mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-09-10 11:55:16 +00:00
Compare commits
63 Commits
Canary-1.3
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
b000f91dad | ||
|
a60b2a0ba3 | ||
|
4c9b48b754 | ||
|
3bd7d5904e | ||
|
23eb9a3043 | ||
|
931ec44406 | ||
|
d68efa98ba | ||
|
ded76801d1 | ||
|
6084df7473 | ||
|
f3953c6039 | ||
|
91f5247e7f | ||
|
5658402c6b | ||
|
1b2c93e188 | ||
|
9e599ff325 | ||
|
7a5f430b59 | ||
|
1e340ce2f3 | ||
|
dbb4e63e1e | ||
|
d00ab52fa2 | ||
|
959af3613d | ||
|
3309fb2351 | ||
|
e1e8628a6f | ||
|
3969191605 | ||
|
07c7b39053 | ||
|
053efaa414 | ||
|
56e6339553 | ||
|
042362ee2b | ||
|
7347ee2212 | ||
|
01a9b636af | ||
|
6e47d8548c | ||
|
da340f5615 | ||
|
be249f7bdc | ||
|
462c93e1ff | ||
|
573a6f32fe | ||
|
7846f58cad | ||
|
0203065fed | ||
|
7319a2dafc | ||
|
f992735656 | ||
|
48b9f2ab93 | ||
|
50ab108ee1 | ||
|
d499449f57 | ||
|
cd3c614021 | ||
|
5fa82bb1f5 | ||
|
234cb99325 | ||
|
ab7914f235 | ||
|
3df6b7c0f5 | ||
|
37e81481c4 | ||
|
4d8b799763 | ||
|
cb786b7147 | ||
|
2a308f50c0 | ||
|
b51c5cead6 | ||
|
461c1f5342 | ||
|
cfea61b3a0 | ||
|
ae2e9a73ab | ||
|
c6f22318a7 | ||
|
dd5e1b99b1 | ||
|
c863ffd353 | ||
|
d6d089b81b | ||
|
c482b7a1c0 | ||
|
01e1cd4d5a | ||
|
bb06eb751b | ||
|
5613d3f35d | ||
|
54d4d184f4 | ||
|
d22756f1bd |
84
.github/workflows/canary.yml
vendored
84
.github/workflows/canary.yml
vendored
@@ -102,51 +102,49 @@ jobs:
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
popd
|
||||
|
||||
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz"
|
||||
shell: bash
|
||||
|
||||
# If anyone wants to look into why appimagetool randomly errors with exit code 8, that would be cool
|
||||
|
||||
# - name: Build AppImage (Linux)
|
||||
# if: matrix.platform.os == 'ubuntu-latest'
|
||||
# run: |
|
||||
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
# PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
#
|
||||
# sudo apt install -y zsync desktop-file-utils appstream
|
||||
#
|
||||
# mkdir -p tools
|
||||
# export PATH="$PATH:$(readlink -f tools)"
|
||||
#
|
||||
# # Setup appimagetool
|
||||
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
# chmod +x tools/appimagetool
|
||||
# chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
#
|
||||
# # Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
# ARCH_NAME=x64
|
||||
# export ARCH=x86_64
|
||||
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
# ARCH_NAME=arm64
|
||||
# export ARCH=aarch64
|
||||
# else
|
||||
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
# exit 1
|
||||
# fi
|
||||
#
|
||||
# export UFLAG="gh-releases-zsync|${{ secrets.RC_OWNER }}${{ secrets.RC_CANARY_NAME }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
# BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||
#
|
||||
# pushd publish_appimage
|
||||
# mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
# mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
# popd
|
||||
#
|
||||
# gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage"
|
||||
# gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
|
||||
# shell: bash
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
|
||||
sudo apt install -y zsync desktop-file-utils appstream
|
||||
|
||||
mkdir -p tools
|
||||
export PATH="$PATH:$(readlink -f tools)"
|
||||
|
||||
# Setup appimagetool
|
||||
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x tools/appimagetool
|
||||
chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
ARCH_NAME=x64
|
||||
export ARCH=x86_64
|
||||
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
ARCH_NAME=arm64
|
||||
export ARCH=aarch64
|
||||
else
|
||||
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export UFLAG="gh-releases-zsync|${{ secrets.RC_OWNER }}${{ secrets.RC_CANARY_NAME }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
pushd publish_appimage
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
popd
|
||||
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage"
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
|
||||
shell: bash
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
|
80
.github/workflows/release.yml
vendored
80
.github/workflows/release.yml
vendored
@@ -96,48 +96,46 @@ jobs:
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
|
||||
sudo apt install -y zsync desktop-file-utils appstream
|
||||
|
||||
mkdir -p tools
|
||||
export PATH="$PATH:$(readlink -f tools)"
|
||||
|
||||
# Setup appimagetool
|
||||
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x tools/appimagetool
|
||||
chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
ARCH_NAME=x64
|
||||
export ARCH=x86_64
|
||||
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
ARCH_NAME=arm64
|
||||
export ARCH=aarch64
|
||||
else
|
||||
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
pushd publish_appimage
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
popd
|
||||
|
||||
# If anyone wants to look into why appimagetool randomly errors with exit code 8, that would be cool
|
||||
|
||||
# - name: Build AppImage (Linux)
|
||||
# if: matrix.platform.os == 'ubuntu-latest'
|
||||
# run: |
|
||||
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
# PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
#
|
||||
# sudo apt install -y zsync desktop-file-utils appstream
|
||||
#
|
||||
# mkdir -p tools
|
||||
# export PATH="$PATH:$(readlink -f tools)"
|
||||
#
|
||||
# # Setup appimagetool
|
||||
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
# chmod +x tools/appimagetool
|
||||
# chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
#
|
||||
# # Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
# ARCH_NAME=x64
|
||||
# export ARCH=x86_64
|
||||
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
# ARCH_NAME=arm64
|
||||
# export ARCH=aarch64
|
||||
# else
|
||||
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
# exit 1
|
||||
# fi
|
||||
#
|
||||
# export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
# BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||
#
|
||||
# pushd publish_appimage
|
||||
# mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
# mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
# popd
|
||||
#
|
||||
# gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage"
|
||||
# gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
|
||||
# shell: bash
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage"
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
|
||||
shell: bash
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
|
@@ -1,18 +0,0 @@
|
||||
function pub {
|
||||
dotnet publish -c release
|
||||
}
|
||||
|
||||
function package {
|
||||
cd src/$1
|
||||
pub
|
||||
mv bin/Release/$1.1.0.0.nupkg ../../pkgs/$1.1.0.0.nupkg
|
||||
cd ../../
|
||||
}
|
||||
|
||||
rm -rf pkgs
|
||||
mkdir pkgs
|
||||
|
||||
package ARMeilleure
|
||||
package Ryujinx.Memory
|
||||
|
||||
dotnet nuget push pkgs/*.nupkg --source RyubingPkgs
|
40
CHANGELOG.md
40
CHANGELOG.md
@@ -21,8 +21,8 @@ Additionally, 1.2.74 & 75 were fixes for uploading Windows build artifacts.
|
||||
|
||||
1.2.76 fixes a rare crash on startup.
|
||||
|
||||
## [1.2.72](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.72>) - 2024-11-03
|
||||
PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://github.com/GreemDev/Ryujinx/pull/164>), [#139](<https://github.com/GreemDev/Ryujinx/pull/139>)
|
||||
## [1.2.72](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.72>) - 2024-11-03
|
||||
PRs [#163](<https://web.archive.org/web/20241123015123/https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://web.archive.org/web/20250307192526/https://github.com/Ryubing/Ryujinx/pull/164>), [#139](<https://web.archive.org/web/20250306123457/https://github.com/Ryubing/Ryujinx/pull/139>)
|
||||
### HLE:
|
||||
- Add DebugMouse HID device.
|
||||
- Fixes "Clock Tower Rewind" crashing while loading.
|
||||
@@ -32,7 +32,7 @@ PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://gith
|
||||
### misc:
|
||||
- Update macOS distribution .icns.
|
||||
|
||||
## [1.2.69](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.69>) - 2024-11-01
|
||||
## [1.2.69](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.69>) - 2024-11-01
|
||||
### Infra:
|
||||
- Compile the native libraries into the Ryujinx executable.
|
||||
- Remove `libarmeilleure-jitsupport.dylib` from Windows & Linux releases (dylibs are macOS-only)
|
||||
@@ -42,8 +42,8 @@ PRs [#163](<https://github.com/GreemDev/Ryujinx/pull/163>), [#164](<https://gith
|
||||
- Replace "" with `string.Empty`.
|
||||
- Code cleanups & simplifications.
|
||||
|
||||
## [1.2.67](<https://github.com/GreemDev/Ryujinx/releases/tag/1.2.67>) - 2024-11-01
|
||||
PRs [#36](<https://github.com/GreemDev/Ryujinx/pull/36>), [#135](<https://github.com/GreemDev/Ryujinx/pull/135>)
|
||||
## [1.2.67](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.67>) - 2024-11-01
|
||||
PRs [#36](<https://web.archive.org/web/20250306215917/https://github.com/Ryubing/Ryujinx/pull/36>), [#135](<https://web.archive.org/web/20241122135125/https://github.com/GreemDev/Ryujinx/pull/135>)
|
||||
|
||||
### GUI:
|
||||
- Set UseFloatingWatermark to false when watermark is empty
|
||||
@@ -54,8 +54,8 @@ PRs [#36](<https://github.com/GreemDev/Ryujinx/pull/36>), [#135](<https://github
|
||||
- Fix homebrew loading.
|
||||
|
||||
|
||||
## [1.2.64](https://github.com/GreemDev/Ryujinx/releases/tag/1.2.64) - 2024-10-30
|
||||
PRs [#92](https://github.com/GreemDev/Ryujinx/pull/92), [#96](https://github.com/GreemDev/Ryujinx/pull/96), [#97](https://github.com/GreemDev/Ryujinx/pull/97), [#101](https://github.com/GreemDev/Ryujinx/pull/101), [#103](https://github.com/GreemDev/Ryujinx/pull/103)
|
||||
## [1.2.64](https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.64) - 2024-10-30
|
||||
PRs [#92](https://web.archive.org/web/20241118052724/https://github.com/GreemDev/Ryujinx/pull/92), ~~[#96](https://github.com/GreemDev/Ryujinx/pull/96)~~, ~~[#97](https://github.com/GreemDev/Ryujinx/pull/97)~~, [#101](https://web.archive.org/web/20250306223605/https://github.com/Ryubing/Ryujinx/pull/101), ~~[#103](https://github.com/GreemDev/Ryujinx/pull/103)~~
|
||||
### GUI:
|
||||
- Option to show classic-style title bar. Requires restart of emulator to take effect.
|
||||
- This is only relevant on Windows. Other Operating Systems default to this being on and not being changeable, because the custom (current) title bar only works on Windows in the first place.
|
||||
@@ -71,14 +71,14 @@ PRs [#92](https://github.com/GreemDev/Ryujinx/pull/92), [#96](https://github.com
|
||||
|
||||
## 1.2.59 - 2024-10-27
|
||||
|
||||
PRs [#88](https://github.com/GreemDev/Ryujinx/pull/88), [#87](https://github.com/GreemDev/Ryujinx/pull/87)
|
||||
PRs ~~[#88](https://github.com/GreemDev/Ryujinx/pull/88), [#87](https://github.com/GreemDev/Ryujinx/pull/87)~~
|
||||
### i18n:
|
||||
- fr_FR:
|
||||
- Add missing translations for new features & fix a couple wrong ones.
|
||||
- Fix Ignore Missing Services / Ignore Applet tooltip.
|
||||
|
||||
## 1.2.57 - 2024-10-27
|
||||
PRs [#60](https://github.com/GreemDev/Ryujinx/pull/60), [#42](https://github.com/GreemDev/Ryujinx/pull/42)
|
||||
PRs ~~[#60](https://github.com/GreemDev/Ryujinx/pull/60)~~, [#42](https://web.archive.org/web/20241126203614/https://github.com/GreemDev/Ryujinx/pull/42)
|
||||
### GUI:
|
||||
- Automatically remove invalid DLC & updates as part of autoload.
|
||||
- Added Thai translation for Ignore Applet hover tooltip.
|
||||
@@ -104,7 +104,7 @@ PRs [#60](https://github.com/GreemDev/Ryujinx/pull/60), [#42](https://github.com
|
||||
- Code cleanup.
|
||||
|
||||
## 1.2.44 - 2024-10-25
|
||||
PR [#59](https://github.com/GreemDev/Ryujinx/pull/59)
|
||||
PR [#59](https://web.archive.org/web/20241125060420/https://github.com/GreemDev/Ryujinx/pull/59)
|
||||
### GUI:
|
||||
- Add descriptions for "ignoring applet" translated into other languages.
|
||||
|
||||
@@ -117,9 +117,9 @@ NOTE: The translation isn't referenced in the code yet, it will be in the next u
|
||||
## 1.2.42 - 2024-10-24
|
||||
Sources:
|
||||
|
||||
Init function: https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9
|
||||
Init function: [archive of github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9](https://web.archive.org/web/20241122193401/https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9)
|
||||
|
||||
Shader counter: https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357
|
||||
Shader counter: ~~https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357~~ Original commit has been lost
|
||||
|
||||
Thanks MutantAura :D
|
||||
### GUI:
|
||||
@@ -127,14 +127,14 @@ Thanks MutantAura :D
|
||||
- Remove graphics backend / GPU name event logic in favor of a single init function.
|
||||
|
||||
## 1.2.41 - 2024-10-24
|
||||
PR [#54](https://github.com/GreemDev/Ryujinx/pull/54)
|
||||
PR ~~[#54](https://github.com/GreemDev/Ryujinx/pull/54)~~
|
||||
|
||||
Thanks Whitescatz!
|
||||
### i18n:
|
||||
- th_TH (Thai): Added missing translations, reduce transliterated words, fix grammar.
|
||||
|
||||
## 1.2.40 - 2024-10-23
|
||||
PR [#40](https://github.com/GreemDev/Ryujinx/pull/40)
|
||||
PR ~~[#40](https://github.com/GreemDev/Ryujinx/pull/40)~~
|
||||
|
||||
Thanks Вова С!
|
||||
### GUI:
|
||||
@@ -148,30 +148,30 @@ Thanks Вова С!
|
||||
- Should prevent crashing on config loads in some circumstances.
|
||||
|
||||
## 1.2.38 - 2024-10-23
|
||||
PR [#51](https://github.com/GreemDev/Ryujinx/pull/51)
|
||||
PR [#51](https://web.archive.org/web/20241127022413/https://github.com/GreemDev/Ryujinx/pull/51)
|
||||
### i18n:
|
||||
- zh_CH (Simplified Chinese): Add some missing translations.
|
||||
|
||||
## 1.2.37 - 2024-10-23
|
||||
PR [#37](https://github.com/GreemDev/Ryujinx/pull/37)
|
||||
PR [#37](https://web.archive.org/web/20241123010103/https://github.com/GreemDev/Ryujinx/pull/37)
|
||||
|
||||
Thanks Last Breath!
|
||||
### GUI:
|
||||
- Set the default controller to the Pro Controller.
|
||||
|
||||
## 1.2.36 - 2024-10-21
|
||||
PR [#30](https://github.com/GreemDev/Ryujinx/pull/30)
|
||||
PR ~~[#30](https://github.com/GreemDev/Ryujinx/pull/30)~~
|
||||
### GUI:
|
||||
- Fix repeated dialog popup notifying you of new updates when there aren't any, while having a bundled update inside an XCI and an external update file.
|
||||
|
||||
## 1.2.35 - 2024-10-21
|
||||
PR [#32](https://github.com/GreemDev/Ryujinx/pull/32)
|
||||
PR [#32](https://web.archive.org/web/20241127010942/https://github.com/GreemDev/Ryujinx/pull/32)
|
||||
### GUI:
|
||||
- Replace "expand DRAM" option with a DRAM size dropdown.
|
||||
- Allows for using mods which require a ridiculous amount of memory to allocate from.
|
||||
|
||||
## 1.2.34 - 2024-10-21
|
||||
PR [#29](https://github.com/GreemDev/Ryujinx/pull/29)
|
||||
PR [#29](https://web.archive.org/web/20241125093029/https://github.com/GreemDev/Ryujinx/pull/29)
|
||||
### GUI:
|
||||
- Fix duplicate controller names when 2 controllers of the same type are connected.
|
||||
### INPUT:
|
||||
@@ -248,7 +248,7 @@ Added Low-power PPTC mode strings to the translation files.
|
||||
## 1.2.1-1.2.19 - 2024-10-08 - 2024-10-11
|
||||
### GUI/INFRA/MISC:
|
||||
- Remove GTK UI.
|
||||
- Autoload DLC/Updates from dir ([#12](https://github.com/GreemDev/Ryujinx/pull/12)).
|
||||
- Autoload DLC/Updates from dir ([#12](https://web.archive.org/web/20241127004005/https://github.com/GreemDev/Ryujinx/pull/12)).
|
||||
- Changed executable icon to rainbow logo.
|
||||
- Extract Data > Logo now also extracts the square thumbnail you see for the game in the UI.
|
||||
- The "use random UUID hack" checkbox in the Amiibo screen now remembers its last state when you reopen the window in a given session.
|
||||
|
@@ -19,8 +19,8 @@
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
||||
<PackageVersion Include="DynamicData" Version="9.4.1" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
@@ -42,11 +42,11 @@
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.116" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.29" />
|
||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.29" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.1.1" />
|
||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
|
||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.44" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.2.1" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.6.0" />
|
||||
<PackageVersion Include="Sep" Version="0.11.1" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
|
4370
assets/locales.json
4370
assets/locales.json
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ chmod +x AppDir/AppRun AppDir/usr/bin/Ryujinx*
|
||||
|
||||
mkdir -p "$OUTDIR"
|
||||
|
||||
appimagetool --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||
appimagetool -n --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||
-u "$UFLAG" \
|
||||
AppDir "$OUTDIR"/Ryujinx.AppImage
|
||||
|
||||
|
@@ -978,7 +978,7 @@
|
||||
0100416004C00000,"DOOM",gpu;slow;nvdec;online-broken,ingame,2024-09-23 15:40:07
|
||||
010018900DD00000,"DOOM (1993)",nvdec;online-broken,menus,2022-09-06 13:32:19
|
||||
01008CB01E52E000,"DOOM + DOOM II",opengl;ldn-untested;LAN,playable,2024-09-12 07:06:01
|
||||
010029D00E740000,"DOOM 3",crash,menus,2024-08-03 05:25:47
|
||||
010029D00E740000,"DOOM 3",crash;slow,menus,2024-08-03 05:25:47
|
||||
01005D700E742000,"DOOM 64",nvdec;vulkan,playable,2020-10-13 23:47:28
|
||||
0100D4F00DD02000,"DOOM II (Classic)",nvdec;online,playable,2021-06-03 20:10:01
|
||||
0100B1A00D8CE000,"DOOM® Eternal",gpu;slow;nvdec;online-broken,ingame,2024-08-28 15:57:17
|
||||
@@ -1097,7 +1097,7 @@
|
||||
0100F9600E746000,"ESP Ra.De. Psi",audio;slow,ingame,2024-03-07 15:05:08
|
||||
010073000FE18000,"Esports powerful pro yakyuu 2020",gpu;crash;Needs More Attention,ingame,2024-04-29 05:34:14
|
||||
01004F9012FD8000,"Estranged: The Departure",nvdec;UE4,playable,2022-10-24 10:37:58
|
||||
010018f01e0a0000,"Eternights",,playable,2025-07-30 12:10:24
|
||||
010018F01E0A0000,"Eternights",,playable,2025-07-30 12:10:24
|
||||
0100CB900B498000,"Eternum Ex",,playable,2021-01-13 20:28:32
|
||||
010092501EB2C000,"Europa (Demo)",gpu;crash;UE4,ingame,2024-04-23 10:47:12
|
||||
01007BE0160D6000,"EVE ghost enemies",gpu,ingame,2023-01-14 03:13:30
|
||||
@@ -1243,7 +1243,7 @@
|
||||
010003F00BD48000,"Friday the 13th: Killer Puzzle",,playable,2021-01-28 01:33:38
|
||||
010092A00C4B6000,"Friday the 13th: The Game Ultimate Slasher Edition",nvdec;online-broken;UE4,playable,2022-09-06 17:33:27
|
||||
0100F200178F4000,"FRONT MISSION 1st: Remake",,playable,2023-06-09 07:44:24
|
||||
0100c4e018a24000,"FRONT MISSION 2: Remake",,playable,2025-07-30 12:11:23
|
||||
0100C4E018A24000,"FRONT MISSION 2: Remake",,playable,2025-07-30 12:11:23
|
||||
01007E6019872000,"FRONT MISSION 3: Remake",,playable,2025-07-30 12:12:02
|
||||
0100861012474000,"Frontline Zed",,playable,2020-10-03 12:55:59
|
||||
0100B5300B49A000,"Frost",,playable,2022-07-27 12:00:36
|
||||
@@ -1440,6 +1440,7 @@
|
||||
0100C2700E338000,"Heroland",,playable,2020-08-05 15:35:39
|
||||
01007AC00E012000,"HexaGravity",,playable,2021-05-28 13:47:48
|
||||
01004E800F03C000,"Hidden",slow,ingame,2022-10-05 10:56:53
|
||||
0100C1101EE5A000,"High on Life",,menus,2025-08-26 19:11:00
|
||||
0100F6A00A684000,"Higurashi no Naku Koro ni Hō",audio,ingame,2021-09-18 14:40:28
|
||||
0100F8D0129F4000,"Himehibi 1 gakki - Princess Days",crash,nothing,2021-11-03 08:34:19
|
||||
0100F3D008436000,"Hiragana Pixel Party",,playable,2021-01-14 08:36:50
|
||||
@@ -1449,6 +1450,7 @@
|
||||
0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35
|
||||
0100F7E00C70E000,"Hogwarts Legacy",UE4;slow,ingame,2024-09-03 19:53:58
|
||||
0100633007D48000,"Hollow Knight",nvdec,playable,2023-01-16 15:44:56
|
||||
010013C00E930000,"Hollow Knight: Silksong",,playable,2025-09-04 17:23:22
|
||||
0100F2100061E800,"Hollow0",UE4;gpu,ingame,2021-03-03 23:42:56
|
||||
0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56
|
||||
010071B00C904000,"HoPiKo",,playable,2021-01-13 20:12:38
|
||||
@@ -1887,7 +1889,7 @@
|
||||
010097800EA20000,"Monster Energy Supercross - The Official Videogame 3",UE4;audout;nvdec;online,playable,2021-06-14 12:37:54
|
||||
0100E9900ED74000,"Monster Farm",32-bit;nvdec,playable,2021-05-05 19:29:13
|
||||
0100770008DD8000,"Monster Hunter Generations Ultimate™",32-bit;online-broken;ldn-works,playable,2024-03-18 14:35:36
|
||||
0100B04011742000,"Monster Hunter Rise",gpu;slow;crash;nvdec;online-broken;Needs Update;ldn-works,ingame,2024-08-24 11:04:59
|
||||
0100B04011742000,"MONSTER HUNTER RISE",gpu;slow;crash;nvdec;online-broken;Needs Update;ldn-works,ingame,2024-08-24 11:04:59
|
||||
010093A01305C000,"Monster Hunter Rise Demo",online-broken;ldn-works;demo,playable,2022-10-18 23:04:17
|
||||
0100E21011446000,"Monster Hunter Stories 2: Wings of Ruin",services,ingame,2022-07-10 19:27:30
|
||||
010042501329E000,"MONSTER HUNTER STORIES 2: WINGS OF RUIN Trial Version",demo,playable,2022-11-13 22:20:26
|
||||
@@ -2312,7 +2314,7 @@
|
||||
010077B00BDD8000,"Professional Farmer: Nintendo Switch™ Edition",slow,playable,2020-12-16 13:38:19
|
||||
010018300C83A000,"Professor Lupo and his Horrible Pets",,playable,2020-06-12 00:08:45
|
||||
0100D1F0132F6000,"Professor Lupo: Ocean",,playable,2021-04-14 16:33:33
|
||||
0100c3a017834000,"Prodeus",,playable,2025-07-30 12:07:52
|
||||
0100C3A017834000,"Prodeus",,playable,2025-07-30 12:07:52
|
||||
0100BBD00976C000,"Project Highrise: Architect's Edition",,playable,2022-08-10 17:19:12
|
||||
0100ACE00DAB6000,"Project Nimbus: Complete Edition",nvdec;UE4;vulkan-backend-bug,playable,2022-08-10 17:35:43
|
||||
01002980140F6000,"Project TRIANGLE STRATEGY™ Debut Demo",UE4;demo,playable,2022-10-24 21:40:27
|
||||
@@ -2578,6 +2580,7 @@
|
||||
0100C610154CA000,"Shadowrun: Hong Kong - Extended Edition",gpu;Needs Update,ingame,2022-10-04 20:53:09
|
||||
010000000EEF0000,"Shadows 2: Perfidia",,playable,2020-08-07 12:43:46
|
||||
0100AD700CBBE000,"Shadows of Adam",,playable,2021-01-11 13:35:58
|
||||
010037A01F96C000,"Shadows of the Damned: Hella Remastered",,playable,2025-09-05 11:34:32
|
||||
01002A800C064000,"Shadowverse Champions Battle",,playable,2022-10-02 22:59:29
|
||||
01003B90136DA000,"Shadowverse: Champion's Battle",crash,nothing,2023-03-06 00:31:50
|
||||
0100820013612000,"Shady Part of Me",,playable,2022-10-20 11:31:55
|
||||
@@ -2976,6 +2979,7 @@
|
||||
0100EBA01548E000,"The Cruel King and the Great Hero",gpu;services,ingame,2022-12-02 07:02:08
|
||||
010051800E922000,"The Dark Crystal: Age of Resistance Tactics",,playable,2020-08-11 13:43:41
|
||||
01003DE00918E000,"The Darkside Detective",,playable,2020-06-03 22:16:18
|
||||
010032B015D66000,"The DioField Chronicle",,playable,2025-09-05 11:35:50
|
||||
01000A10041EA000,"The Elder Scrolls V: Skyrim",gpu;crash,ingame,2024-07-14 03:21:31
|
||||
01004A9006B84000,"The End Is Nigh",,playable,2020-06-01 11:26:45
|
||||
0100CA100489C000,"The Escapists 2",nvdec,playable,2020-09-24 12:31:31
|
||||
|
|
@@ -143,6 +143,12 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
||||
{
|
||||
if (context.IsSingleStep)
|
||||
{
|
||||
context.Return(Const(immediate));
|
||||
return;
|
||||
}
|
||||
|
||||
bool isRecursive = immediate == context.EntryAddress;
|
||||
|
||||
if (isRecursive)
|
||||
@@ -157,12 +163,24 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
||||
{
|
||||
EmitTableBranch(context, target, isJump: false);
|
||||
if (context.IsSingleStep)
|
||||
{
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
target = context.ZeroExtend32(OperandType.I64, target);
|
||||
}
|
||||
|
||||
context.Return(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitTableBranch(context, target, isJump: false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
||||
{
|
||||
if (isReturn)
|
||||
if (isReturn || context.IsSingleStep)
|
||||
{
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
|
@@ -3,6 +3,7 @@ using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
@@ -200,7 +201,11 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
ExecutionContext context = GetContext();
|
||||
|
||||
context.CheckInterrupt();
|
||||
// If debugging, we'll handle interrupts outside
|
||||
if (!Optimizations.EnableDebugging)
|
||||
{
|
||||
context.CheckInterrupt();
|
||||
}
|
||||
|
||||
Statistics.ResumeTimer();
|
||||
|
||||
|
@@ -12,6 +12,7 @@ namespace ARMeilleure
|
||||
|
||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||
public static bool UseUnmanagedDispatchLoop { get; set; } = true;
|
||||
public static bool EnableDebugging { get; set; } = false;
|
||||
|
||||
public static bool UseAdvSimdIfAvailable { get; set; } = true;
|
||||
public static bool UseArm64AesIfAvailable { get; set; } = true;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using ARMeilleure.Memory;
|
||||
using System.Threading;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
@@ -10,7 +11,7 @@ namespace ARMeilleure.State
|
||||
|
||||
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
||||
|
||||
private bool _interrupted;
|
||||
internal bool Interrupted { get; private set; }
|
||||
|
||||
private readonly ICounter _counter;
|
||||
|
||||
@@ -65,6 +66,8 @@ namespace ARMeilleure.State
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
{
|
||||
get
|
||||
@@ -90,14 +93,19 @@ namespace ARMeilleure.State
|
||||
|
||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||
private readonly ExceptionCallback _breakCallback;
|
||||
private readonly ExceptionCallbackNoArgs _stepCallback;
|
||||
private readonly ExceptionCallback _supervisorCallback;
|
||||
private readonly ExceptionCallback _undefinedCallback;
|
||||
|
||||
internal int ShouldStep;
|
||||
public ulong DebugPc { get; set; }
|
||||
|
||||
public ExecutionContext(
|
||||
IJitMemoryAllocator allocator,
|
||||
ICounter counter,
|
||||
ExceptionCallbackNoArgs interruptCallback = null,
|
||||
ExceptionCallback breakCallback = null,
|
||||
ExceptionCallbackNoArgs stepCallback = null,
|
||||
ExceptionCallback supervisorCallback = null,
|
||||
ExceptionCallback undefinedCallback = null)
|
||||
{
|
||||
@@ -105,6 +113,7 @@ namespace ARMeilleure.State
|
||||
_counter = counter;
|
||||
_interruptCallback = interruptCallback;
|
||||
_breakCallback = breakCallback;
|
||||
_stepCallback = stepCallback;
|
||||
_supervisorCallback = supervisorCallback;
|
||||
_undefinedCallback = undefinedCallback;
|
||||
|
||||
@@ -127,9 +136,9 @@ namespace ARMeilleure.State
|
||||
|
||||
internal void CheckInterrupt()
|
||||
{
|
||||
if (_interrupted)
|
||||
if (Interrupted)
|
||||
{
|
||||
_interrupted = false;
|
||||
Interrupted = false;
|
||||
|
||||
_interruptCallback?.Invoke(this);
|
||||
}
|
||||
@@ -139,16 +148,37 @@ namespace ARMeilleure.State
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
_interrupted = true;
|
||||
Interrupted = true;
|
||||
}
|
||||
|
||||
public void StepHandler()
|
||||
{
|
||||
_stepCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
Interlocked.Exchange(ref ShouldStep, 1);
|
||||
RequestInterrupt();
|
||||
}
|
||||
|
||||
internal void OnBreak(ulong address, int imm)
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
DebugPc = Pc;
|
||||
}
|
||||
|
||||
_breakCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
internal void OnSupervisorCall(ulong address, int imm)
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
DebugPc = Pc;
|
||||
}
|
||||
|
||||
_supervisorCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,12 @@ namespace ARMeilleure.State
|
||||
public ulong ExclusiveValueHigh;
|
||||
public int Running;
|
||||
public long Tpidr2El0;
|
||||
|
||||
/// <summary>
|
||||
/// Precise PC value used for debugging.
|
||||
/// This will only be set when Optimizations.EnableDebugging is true.
|
||||
/// </summary>
|
||||
public ulong DebugPrecisePc;
|
||||
}
|
||||
|
||||
private static NativeCtxStorage _dummyStorage = new();
|
||||
@@ -39,6 +45,11 @@ namespace ARMeilleure.State
|
||||
|
||||
public ulong GetPc()
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
return GetStorage().DebugPrecisePc;
|
||||
}
|
||||
|
||||
// TODO: More precise tracking of PC value.
|
||||
return GetStorage().DispatchAddress;
|
||||
}
|
||||
@@ -268,6 +279,11 @@ namespace ARMeilleure.State
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
||||
}
|
||||
|
||||
public static int GetDebugPrecisePcOffset()
|
||||
{
|
||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.DebugPrecisePc);
|
||||
}
|
||||
|
||||
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
|
||||
{
|
||||
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref target);
|
||||
|
@@ -52,6 +52,7 @@ namespace ARMeilleure.Translation
|
||||
public bool HighCq { get; }
|
||||
public bool HasPtc { get; }
|
||||
public Aarch32Mode Mode { get; }
|
||||
public bool IsSingleStep { get; }
|
||||
|
||||
private int _ifThenBlockStateIndex = 0;
|
||||
private Condition[] _ifThenBlockState = [];
|
||||
@@ -66,7 +67,8 @@ namespace ARMeilleure.Translation
|
||||
ulong entryAddress,
|
||||
bool highCq,
|
||||
bool hasPtc,
|
||||
Aarch32Mode mode)
|
||||
Aarch32Mode mode,
|
||||
bool isSingleStep)
|
||||
{
|
||||
Memory = memory;
|
||||
CountTable = countTable;
|
||||
@@ -76,6 +78,7 @@ namespace ARMeilleure.Translation
|
||||
HighCq = highCq;
|
||||
HasPtc = hasPtc;
|
||||
Mode = mode;
|
||||
IsSingleStep = isSingleStep;
|
||||
|
||||
_labels = new Dictionary<ulong, Operand>();
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 7008; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 7009; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
@@ -303,6 +303,13 @@ namespace ARMeilleure.Translation.PTC
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outerHeader.DebuggerMode != Optimizations.EnableDebugging)
|
||||
{
|
||||
InvalidateCompressedStream(compressedStream);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nint intPtr = nint.Zero;
|
||||
|
||||
try
|
||||
@@ -479,6 +486,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
MemoryManagerMode = GetMemoryManagerMode(),
|
||||
OSPlatform = GetOSPlatform(),
|
||||
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
||||
DebuggerMode = Optimizations.EnableDebugging,
|
||||
|
||||
UncompressedStreamSize =
|
||||
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||
@@ -1068,7 +1076,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return osPlatform;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 87*/)]
|
||||
private struct OuterHeader
|
||||
{
|
||||
public ulong Magic;
|
||||
@@ -1080,6 +1088,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
public byte MemoryManagerMode;
|
||||
public uint OSPlatform;
|
||||
public uint Architecture;
|
||||
public bool DebuggerMode;
|
||||
|
||||
public long UncompressedStreamSize;
|
||||
|
||||
|
@@ -119,7 +119,25 @@ namespace ARMeilleure.Translation
|
||||
|
||||
NativeInterface.RegisterThread(context, Memory, this);
|
||||
|
||||
if (Optimizations.UseUnmanagedDispatchLoop)
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
context.DebugPc = address;
|
||||
do
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1)
|
||||
{
|
||||
context.DebugPc = Step(context, context.DebugPc);
|
||||
context.StepHandler();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.DebugPc = ExecuteSingle(context, context.DebugPc);
|
||||
}
|
||||
context.CheckInterrupt();
|
||||
}
|
||||
while (context.Running && context.DebugPc != 0);
|
||||
}
|
||||
else if (Optimizations.UseUnmanagedDispatchLoop)
|
||||
{
|
||||
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
||||
}
|
||||
@@ -175,7 +193,7 @@ namespace ARMeilleure.Translation
|
||||
return nextAddr;
|
||||
}
|
||||
|
||||
public ulong Step(State.ExecutionContext context, ulong address)
|
||||
private ulong Step(State.ExecutionContext context, ulong address)
|
||||
{
|
||||
TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
|
||||
|
||||
@@ -186,6 +204,8 @@ namespace ARMeilleure.Translation
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
||||
{
|
||||
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
||||
@@ -229,7 +249,8 @@ namespace ARMeilleure.Translation
|
||||
address,
|
||||
highCq,
|
||||
_ptc.State != PtcState.Disabled,
|
||||
mode: Aarch32Mode.User);
|
||||
mode: Aarch32Mode.User,
|
||||
isSingleStep: singleStep);
|
||||
|
||||
Logger.StartPass(PassName.Decoding);
|
||||
|
||||
@@ -367,9 +388,13 @@ namespace ARMeilleure.Translation
|
||||
|
||||
if (block.Exit)
|
||||
{
|
||||
// Left option here as it may be useful if we need to return to managed rather than tail call in
|
||||
// future. (eg. for debug)
|
||||
bool useReturns = false;
|
||||
// Return to managed rather than tail call.
|
||||
bool useReturns = Optimizations.EnableDebugging;
|
||||
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
EmitDebugPrecisePcUpdate(context, block.Address);
|
||||
}
|
||||
|
||||
InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
|
||||
}
|
||||
@@ -393,6 +418,11 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
EmitDebugPrecisePcUpdate(context, opCode.Address);
|
||||
}
|
||||
|
||||
Operand lblPredicateSkip = default;
|
||||
|
||||
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
||||
@@ -489,6 +519,14 @@ namespace ARMeilleure.Translation
|
||||
context.MarkLabel(lblExit);
|
||||
}
|
||||
|
||||
internal static void EmitDebugPrecisePcUpdate(EmitterContext context, ulong address)
|
||||
{
|
||||
long debugPrecisePcOffs = NativeContext.GetDebugPrecisePcOffset();
|
||||
|
||||
Operand debugPrecisePcAddr = context.Add(context.LoadArgument(OperandType.I64, 0), Const(debugPrecisePcOffs));
|
||||
context.Store(debugPrecisePcAddr, Const(address));
|
||||
}
|
||||
|
||||
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
||||
{
|
||||
ulong[] overlapAddresses = [];
|
||||
|
@@ -81,14 +81,14 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
|
||||
{
|
||||
if ((uint)index < (uint)coefficients.Length)
|
||||
if ((uint)index >= (uint)coefficients.Length)
|
||||
{
|
||||
return coefficients[index];
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||
|
||||
return 0;
|
||||
return coefficients[index];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@@ -26,12 +26,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
ReadOnlySpan<float> inputBuffer,
|
||||
uint sampleCount)
|
||||
{
|
||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -64,12 +67,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
uint sampleCount,
|
||||
float volume)
|
||||
{
|
||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -107,12 +113,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
float volume,
|
||||
float ramp)
|
||||
{
|
||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
|
||||
float mixState = 0f;
|
||||
|
||||
@@ -157,13 +166,16 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
BiquadFilterParameter parameter = parameters[stageIndex];
|
||||
|
||||
ref BiquadFilterState state = ref states[stageIndex];
|
||||
|
||||
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
||||
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
||||
|
||||
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -201,19 +213,25 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
uint sampleCount,
|
||||
float volume)
|
||||
{
|
||||
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
|
||||
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
|
||||
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
|
||||
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
|
||||
|
||||
|
||||
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
|
||||
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
|
||||
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
||||
|
||||
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
||||
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
||||
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
||||
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -261,19 +279,24 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
float volume,
|
||||
float ramp)
|
||||
{
|
||||
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
||||
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
|
||||
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
|
||||
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
|
||||
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
|
||||
|
||||
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
|
||||
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
|
||||
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
||||
|
||||
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
||||
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
||||
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
||||
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
||||
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
||||
|
||||
float mixState = 0f;
|
||||
|
||||
|
@@ -39,12 +39,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
OutputBufferIndex = outputBufferIndex;
|
||||
SampleRate = serverState.SampleRate;
|
||||
Pitch = serverState.Pitch;
|
||||
|
||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||
|
||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
@@ -28,10 +29,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
Input = new ushort[Constants.ChannelCountMax];
|
||||
InputCount = parameter.InputCount;
|
||||
|
||||
Span<byte> inputSpan = parameter.Input.AsSpan();
|
||||
|
||||
for (int i = 0; i < InputCount; i++)
|
||||
{
|
||||
Input[i] = (ushort)(bufferOffset + parameter.Input[i]);
|
||||
Input[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
}
|
||||
|
||||
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
||||
|
@@ -42,11 +42,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,10 +174,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
|
||||
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
|
||||
|
||||
Span<float> lastSamplesSpan = statistics.LastSamples.AsSpan();
|
||||
|
||||
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
||||
{
|
||||
statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
||||
lastSamplesSpan[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -52,12 +52,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
OutputBufferIndex = (ushort)(channelIndex + outputBufferIndex);
|
||||
SampleRate = serverState.SampleRate;
|
||||
Pitch = serverState.Pitch;
|
||||
|
||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||
|
||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(2);
|
||||
}
|
||||
|
@@ -42,11 +42,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
|
||||
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
||||
|
@@ -42,14 +42,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
ref VoiceUpdateState state = ref State.Span[0];
|
||||
|
||||
Span<float> depopBuffer = DepopBuffer.Span;
|
||||
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
||||
|
||||
for (int i = 0; i < MixBufferCount; i++)
|
||||
{
|
||||
if (state.LastSamples[i] != 0)
|
||||
if (lastSamplesSpan[i] != 0)
|
||||
{
|
||||
depopBuffer[OutputBufferIndices[i]] += state.LastSamples[i];
|
||||
depopBuffer[OutputBufferIndices[i]] += lastSamplesSpan[i];
|
||||
|
||||
state.LastSamples[i] = 0;
|
||||
lastSamplesSpan[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,10 +34,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
SessionId = sessionId;
|
||||
InputCount = sink.Parameter.InputCount;
|
||||
InputBufferIndices = new ushort[InputCount];
|
||||
|
||||
Span<byte> inputSpan = sink.Parameter.Input.AsSpan();
|
||||
|
||||
for (int i = 0; i < Math.Min(InputCount, Constants.ChannelCountMax); i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + sink.Parameter.Input[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
}
|
||||
|
||||
if (sink.UpsamplerState != null)
|
||||
|
@@ -37,11 +37,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -48,11 +48,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = _parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = _parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,8 +153,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
|
||||
|
||||
statistics.InputMax[channelIndex] = Math.Max(statistics.InputMax[channelIndex], sampleInputMax);
|
||||
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], compressionGain);
|
||||
Span<float> inputMaxSpan = statistics.InputMax.AsSpan();
|
||||
Span<float> compressionGainMinSpan = statistics.CompressionGainMin.AsSpan();
|
||||
|
||||
inputMaxSpan[channelIndex] = Math.Max(inputMaxSpan[channelIndex], sampleInputMax);
|
||||
compressionGainMinSpan[channelIndex] = Math.Min(compressionGainMinSpan[channelIndex], compressionGain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -79,6 +79,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
public void Process(CommandList context)
|
||||
{
|
||||
ref VoiceUpdateState state = ref State.Span[0];
|
||||
|
||||
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
||||
|
||||
for (int i = 0; i < MixBufferCount; i++)
|
||||
{
|
||||
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]);
|
||||
@@ -87,15 +91,13 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
float volume0 = Volume0[i];
|
||||
float volume1 = Volume1[i];
|
||||
|
||||
ref VoiceUpdateState state = ref State.Span[0];
|
||||
|
||||
if (volume0 != 0 || volume1 != 0)
|
||||
{
|
||||
state.LastSamples[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
||||
lastSamplesSpan[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LastSamples[i] = 0;
|
||||
lastSamplesSpan[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -42,10 +42,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
Pitch = serverState.Pitch;
|
||||
|
||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||
|
||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
@@ -42,10 +42,12 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
Pitch = serverState.Pitch;
|
||||
|
||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||
|
||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref waveBufferSpan[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
@@ -65,11 +65,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
|
||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
||||
|
@@ -63,11 +63,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
|
||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<byte> inputSpan = Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = Parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||
{
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
}
|
||||
|
||||
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
||||
|
@@ -74,7 +74,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
{
|
||||
int tempBufferIndex = 0;
|
||||
|
||||
if (!info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) != DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||
{
|
||||
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
||||
tempBufferIndex += pitchMaxLength;
|
||||
@@ -208,7 +208,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
break;
|
||||
}
|
||||
|
||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.PlayedSampleCountResetWhenLooping))
|
||||
if ((info.DecodingBehaviour & DecodingBehaviour.PlayedSampleCountResetWhenLooping) == DecodingBehaviour.PlayedSampleCountResetWhenLooping)
|
||||
{
|
||||
playedSampleCount = 0;
|
||||
}
|
||||
@@ -222,7 +222,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
|
||||
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputBuffer[i..]);
|
||||
|
||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) == DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||
{
|
||||
for (int j = 0; j < y; j++)
|
||||
{
|
||||
|
@@ -41,11 +41,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
}
|
||||
|
||||
Array20<float> result = new();
|
||||
Span<float> resultSpan = result.AsSpan();
|
||||
|
||||
for (int i = 0; i < FilterBankLength; i++)
|
||||
{
|
||||
float x = (Bank0CenterIndex - i) + offset;
|
||||
result[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||
resultSpan[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -78,6 +79,9 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
|
||||
Debug.Assert(state.History.Length == HistoryLength);
|
||||
Debug.Assert(bank.Length == FilterBankLength);
|
||||
|
||||
Span<float> bankSpan = bank.AsSpan();
|
||||
Span<float> historySpan = state.History.AsSpan();
|
||||
|
||||
int curIdx = 0;
|
||||
if (Vector.IsHardwareAccelerated)
|
||||
@@ -88,15 +92,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
while (curIdx < stopIdx)
|
||||
{
|
||||
result += Vector.Dot(
|
||||
new Vector<float>(bank.AsSpan().Slice(curIdx, Vector<float>.Count)),
|
||||
new Vector<float>(state.History.AsSpan().Slice(curIdx, Vector<float>.Count)));
|
||||
new Vector<float>(bankSpan[curIdx..(curIdx + Vector<float>.Count)]),
|
||||
new Vector<float>(historySpan[curIdx..(curIdx + Vector<float>.Count)]));
|
||||
curIdx += Vector<float>.Count;
|
||||
}
|
||||
}
|
||||
|
||||
while (curIdx < FilterBankLength)
|
||||
{
|
||||
result += bank[curIdx] * state.History[curIdx];
|
||||
result += bankSpan[curIdx] * historySpan[curIdx];
|
||||
curIdx++;
|
||||
}
|
||||
|
||||
|
@@ -141,18 +141,20 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
||||
|
||||
if (supportsOptimizedPath && voiceState.BiquadFilters[0].Enable && voiceState.BiquadFilters[1].Enable)
|
||||
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
||||
|
||||
if (supportsOptimizedPath && biquadFiltersSpan[0].Enable && biquadFiltersSpan[1].Enable)
|
||||
{
|
||||
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
||||
Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory);
|
||||
|
||||
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, voiceState.BiquadFilters.AsSpan(), stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
||||
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, biquadFiltersSpan, stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < voiceState.BiquadFilters.Length; i++)
|
||||
for (int i = 0; i < biquadFiltersSpan.Length; i++)
|
||||
{
|
||||
ref BiquadFilterParameter filter = ref voiceState.BiquadFilters[i];
|
||||
ref BiquadFilterParameter filter = ref biquadFiltersSpan[i];
|
||||
|
||||
if (filter.Enable)
|
||||
{
|
||||
@@ -311,12 +313,15 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
int nodeId = voiceState.NodeId;
|
||||
uint channelsCount = voiceState.ChannelsCount;
|
||||
|
||||
Span<int> channelResourceIdsSpan = voiceState.ChannelResourceIds.AsSpan();
|
||||
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
||||
|
||||
for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++)
|
||||
{
|
||||
Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(voiceState.ChannelResourceIds[channelIndex]);
|
||||
Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(channelResourceIdsSpan[channelIndex]);
|
||||
|
||||
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(voiceState.ChannelResourceIds[channelIndex]);
|
||||
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(channelResourceIdsSpan[channelIndex]);
|
||||
|
||||
PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm;
|
||||
|
||||
@@ -476,7 +481,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++)
|
||||
{
|
||||
voiceState.BiquadFilterNeedInitialization[i] = voiceState.BiquadFilters[i].Enable;
|
||||
voiceState.BiquadFilterNeedInitialization[i] = biquadFiltersSpan[i].Enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -526,15 +531,19 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
if (effect.IsEnabled)
|
||||
{
|
||||
Span<float> volumesSpan = effect.Parameter.Volumes.AsSpan();
|
||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||
|
||||
for (int i = 0; i < effect.Parameter.MixesCount; i++)
|
||||
{
|
||||
if (effect.Parameter.Volumes[i] != 0.0f)
|
||||
if (volumesSpan[i] != 0.0f)
|
||||
{
|
||||
_commandBuffer.GenerateMix(
|
||||
(uint)bufferOffset + effect.Parameter.Input[i],
|
||||
(uint)bufferOffset + effect.Parameter.Output[i],
|
||||
(uint)bufferOffset + inputSpan[i],
|
||||
(uint)bufferOffset + outputSpan[i],
|
||||
nodeId,
|
||||
effect.Parameter.Volumes[i]);
|
||||
volumesSpan[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,6 +563,10 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
int i = 0;
|
||||
uint writeOffset = 0;
|
||||
|
||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||
|
||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||
{
|
||||
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
||||
@@ -571,8 +584,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_commandBuffer.GenerateAuxEffect(
|
||||
bufferOffset,
|
||||
effect.Parameter.Input[i],
|
||||
effect.Parameter.Output[i],
|
||||
inputSpan[i],
|
||||
outputSpan[i],
|
||||
ref effect.State,
|
||||
effect.IsEnabled,
|
||||
effect.Parameter.BufferStorageSize,
|
||||
@@ -619,6 +632,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
private void GenerateBiquadFilterEffect(uint bufferOffset, BiquadFilterEffect effect, int nodeId)
|
||||
{
|
||||
Debug.Assert(effect.Type == EffectType.BiquadFilter);
|
||||
|
||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
||||
|
||||
if (effect.IsEnabled)
|
||||
{
|
||||
@@ -639,8 +655,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
(int)bufferOffset,
|
||||
ref parameter,
|
||||
effect.State.Slice(i, 1),
|
||||
effect.Parameter.Input[i],
|
||||
effect.Parameter.Output[i],
|
||||
inputSpan[i],
|
||||
outputSpan[i],
|
||||
needInitialization,
|
||||
nodeId);
|
||||
}
|
||||
@@ -649,8 +665,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
||||
{
|
||||
uint inputBufferIndex = bufferOffset + effect.Parameter.Input[i];
|
||||
uint outputBufferIndex = bufferOffset + effect.Parameter.Output[i];
|
||||
uint inputBufferIndex = bufferOffset + inputSpan[i];
|
||||
uint outputBufferIndex = bufferOffset + outputSpan[i];
|
||||
|
||||
// If the input and output isn't the same, generate a command.
|
||||
if (inputBufferIndex != outputBufferIndex)
|
||||
@@ -701,6 +717,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
int i = 0;
|
||||
uint writeOffset = 0;
|
||||
|
||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
||||
|
||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||
{
|
||||
@@ -719,7 +737,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_commandBuffer.GenerateCaptureEffect(
|
||||
bufferOffset,
|
||||
effect.Parameter.Input[i],
|
||||
inputSpan[i],
|
||||
effect.State.SendBufferInfo,
|
||||
effect.IsEnabled,
|
||||
effect.Parameter.BufferStorageSize,
|
||||
|
@@ -218,7 +218,8 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
|
||||
/// <returns>True if any biquad filter is enabled.</returns>
|
||||
public bool IsBiquadFilterEnabled()
|
||||
{
|
||||
return _biquadFilters[0].Enable || _biquadFilters[1].Enable;
|
||||
Span<BiquadFilterParameter> biquadFiltersSpan = _biquadFilters.AsSpan();
|
||||
return biquadFiltersSpan[0].Enable || biquadFiltersSpan[1].Enable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -162,9 +162,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
ref VoiceState currentVoiceState = ref context.GetState(i);
|
||||
|
||||
Span<int> channelResourceIdsSpan = parameter.ChannelResourceIds.AsSpan();
|
||||
|
||||
for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++)
|
||||
{
|
||||
int channelId = parameter.ChannelResourceIds[channelResourceIndex];
|
||||
int channelId = channelResourceIdsSpan[channelResourceIndex];
|
||||
|
||||
Debug.Assert(channelId >= 0 && channelId < context.GetCount());
|
||||
|
||||
|
@@ -126,9 +126,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
_sortedVoices.Span[i] = i;
|
||||
}
|
||||
|
||||
int[] sortedVoicesTemp = _sortedVoices[..(int)GetCount()].ToArray();
|
||||
Span<int> sortedVoicesTemp = _sortedVoices[..(int)_voiceCount].Span;
|
||||
|
||||
Array.Sort(sortedVoicesTemp, (a, b) =>
|
||||
sortedVoicesTemp.Sort((a, b) =>
|
||||
{
|
||||
ref VoiceState aState = ref GetState(a);
|
||||
ref VoiceState bState = ref GetState(b);
|
||||
@@ -143,7 +143,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
return result;
|
||||
});
|
||||
|
||||
sortedVoicesTemp.AsSpan().CopyTo(_sortedVoices.Span);
|
||||
// sortedVoicesTemp.CopyTo(_sortedVoices.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -219,15 +219,17 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
/// </summary>
|
||||
private void InitializeWaveBuffers()
|
||||
{
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||
{
|
||||
WaveBuffers[i].StartSampleOffset = 0;
|
||||
WaveBuffers[i].EndSampleOffset = 0;
|
||||
WaveBuffers[i].ShouldLoop = false;
|
||||
WaveBuffers[i].IsEndOfStream = false;
|
||||
WaveBuffers[i].BufferAddressInfo.Setup(0, 0);
|
||||
WaveBuffers[i].ContextAddressInfo.Setup(0, 0);
|
||||
WaveBuffers[i].IsSendToAudioProcessor = true;
|
||||
waveBuffersSpan[i].StartSampleOffset = 0;
|
||||
waveBuffersSpan[i].EndSampleOffset = 0;
|
||||
waveBuffersSpan[i].ShouldLoop = false;
|
||||
waveBuffersSpan[i].IsEndOfStream = false;
|
||||
waveBuffersSpan[i].BufferAddressInfo.Setup(0, 0);
|
||||
waveBuffersSpan[i].ContextAddressInfo.Setup(0, 0);
|
||||
waveBuffersSpan[i].IsSendToAudioProcessor = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,10 +448,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
}
|
||||
|
||||
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0];
|
||||
|
||||
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||
Span<WaveBufferInternal> pWaveBuffersSpan = parameter.WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.VoiceWaveBufferCount; i++)
|
||||
{
|
||||
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref WaveBuffers[i], ref parameter.WaveBuffers[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
|
||||
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,9 +539,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
/// <param name="context">The voice context.</param>
|
||||
private void ResetResources(VoiceContext context)
|
||||
{
|
||||
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
|
||||
|
||||
for (int i = 0; i < ChannelsCount; i++)
|
||||
{
|
||||
int channelResourceId = ChannelResourceIds[i];
|
||||
int channelResourceId = channelResourceIdsSpan[i];
|
||||
|
||||
ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId);
|
||||
|
||||
@@ -559,10 +566,12 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
private void FlushWaveBuffers(uint waveBufferCount, Memory<VoiceUpdateState>[] voiceUpdateStates, uint channelCount)
|
||||
{
|
||||
uint waveBufferIndex = WaveBuffersIndex;
|
||||
|
||||
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < waveBufferCount; i++)
|
||||
{
|
||||
WaveBuffers[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
||||
waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
||||
|
||||
for (int j = 0; j < channelCount; j++)
|
||||
{
|
||||
@@ -591,14 +600,18 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
FlushWaveBufferCount = 0;
|
||||
}
|
||||
|
||||
Span<WaveBuffer> waveBuffersSpan;
|
||||
|
||||
switch (PlayState)
|
||||
{
|
||||
case PlayState.Started:
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
waveBuffersSpan = WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||
{
|
||||
ref WaveBuffer wavebuffer = ref WaveBuffers[i];
|
||||
ref WaveBuffer waveBuffer = ref waveBuffersSpan[i];
|
||||
|
||||
if (!wavebuffer.IsSendToAudioProcessor)
|
||||
if (!waveBuffer.IsSendToAudioProcessor)
|
||||
{
|
||||
for (int y = 0; y < ChannelsCount; y++)
|
||||
{
|
||||
@@ -607,7 +620,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true;
|
||||
}
|
||||
|
||||
wavebuffer.IsSendToAudioProcessor = true;
|
||||
waveBuffer.IsSendToAudioProcessor = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,11 +639,13 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
return false;
|
||||
|
||||
case PlayState.Stopping:
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
waveBuffersSpan = WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||
{
|
||||
ref WaveBuffer wavebuffer = ref WaveBuffers[i];
|
||||
ref WaveBuffer waveBuffer = ref waveBuffersSpan[i];
|
||||
|
||||
wavebuffer.IsSendToAudioProcessor = true;
|
||||
waveBuffer.IsSendToAudioProcessor = true;
|
||||
|
||||
for (int j = 0; j < ChannelsCount; j++)
|
||||
{
|
||||
@@ -702,9 +717,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
|
||||
Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax];
|
||||
|
||||
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
|
||||
|
||||
for (int i = 0; i < ChannelsCount; i++)
|
||||
{
|
||||
voiceUpdateStates[i] = context.GetUpdateStateForDsp(ChannelResourceIds[i]);
|
||||
voiceUpdateStates[i] = context.GetUpdateStateForDsp(channelResourceIdsSpan[i]);
|
||||
}
|
||||
|
||||
return UpdateParametersForCommandGeneration(voiceUpdateStates);
|
||||
|
@@ -14,12 +14,13 @@ namespace Ryujinx.Common.Collections
|
||||
/// Adds a new node into the tree.
|
||||
/// </summary>
|
||||
/// <param name="node">Node to be added</param>
|
||||
/// <param name="parent">Node to be added under</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="node"/> is null</exception>
|
||||
public void Add(T node)
|
||||
public void Add(T node, T parent = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(node);
|
||||
|
||||
Insert(node);
|
||||
Insert(node, parent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,9 +77,11 @@ namespace Ryujinx.Common.Collections
|
||||
/// Inserts a new node into the tree.
|
||||
/// </summary>
|
||||
/// <param name="node">Node to be inserted</param>
|
||||
private void Insert(T node)
|
||||
/// <param name="parent">Node to be inserted under</param>
|
||||
private void Insert(T node, T parent = null)
|
||||
{
|
||||
T newNode = BSTInsert(node);
|
||||
T newNode = parent != null ? InsertWithParent(node, parent) : BSTInsert(node);
|
||||
|
||||
RestoreBalanceAfterInsertion(newNode);
|
||||
}
|
||||
|
||||
@@ -122,10 +125,77 @@ namespace Ryujinx.Common.Collections
|
||||
else if (newNode.CompareTo(parent) < 0)
|
||||
{
|
||||
parent.Left = newNode;
|
||||
|
||||
newNode.Successor = parent;
|
||||
|
||||
if (parent.Predecessor != null)
|
||||
{
|
||||
newNode.Predecessor = parent.Predecessor;
|
||||
newNode.Predecessor.Successor = newNode;
|
||||
}
|
||||
|
||||
parent.Predecessor = newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.Right = newNode;
|
||||
|
||||
newNode.Predecessor = parent;
|
||||
|
||||
if (parent.Successor != null)
|
||||
{
|
||||
newNode.Successor = parent.Successor;
|
||||
newNode.Successor.Predecessor = newNode;
|
||||
}
|
||||
|
||||
parent.Successor = newNode;
|
||||
}
|
||||
Count++;
|
||||
return newNode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insertion Mechanism for a Binary Search Tree (BST).
|
||||
/// <br></br>
|
||||
/// Inserts a new node directly under a parent node
|
||||
/// where all children in the left subtree are less than <paramref name="newNode"/>,
|
||||
/// and all children in the right subtree are greater than <paramref name="newNode"/>.
|
||||
/// </summary>
|
||||
/// <param name="newNode">Node to be inserted</param>
|
||||
/// <param name="parent">Node to be inserted under</param>
|
||||
/// <returns>The inserted Node</returns>
|
||||
private T InsertWithParent(T newNode, T parent)
|
||||
{
|
||||
newNode.Parent = parent;
|
||||
|
||||
if (newNode.CompareTo(parent) < 0)
|
||||
{
|
||||
parent.Left = newNode;
|
||||
|
||||
newNode.Successor = parent;
|
||||
|
||||
if (parent.Predecessor != null)
|
||||
{
|
||||
newNode.Predecessor = parent.Predecessor;
|
||||
parent.Predecessor = newNode;
|
||||
newNode.Predecessor.Successor = newNode;
|
||||
}
|
||||
|
||||
parent.Predecessor = newNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.Right = newNode;
|
||||
|
||||
newNode.Predecessor = parent;
|
||||
|
||||
if (parent.Successor != null)
|
||||
{
|
||||
newNode.Successor = parent.Successor;
|
||||
newNode.Successor.Predecessor = newNode;
|
||||
}
|
||||
|
||||
parent.Successor = newNode;
|
||||
}
|
||||
|
||||
Count++;
|
||||
@@ -159,7 +229,7 @@ namespace Ryujinx.Common.Collections
|
||||
}
|
||||
else
|
||||
{
|
||||
T element = Minimum(RightOf(nodeToDelete));
|
||||
T element = nodeToDelete.Successor;
|
||||
|
||||
child = RightOf(element);
|
||||
parent = ParentOf(element);
|
||||
@@ -187,6 +257,9 @@ namespace Ryujinx.Common.Collections
|
||||
element.Left = old.Left;
|
||||
element.Right = old.Right;
|
||||
element.Parent = old.Parent;
|
||||
element.Predecessor = old.Predecessor;
|
||||
if (element.Predecessor != null)
|
||||
element.Predecessor.Successor = element;
|
||||
|
||||
if (ParentOf(old) == null)
|
||||
{
|
||||
@@ -241,6 +314,11 @@ namespace Ryujinx.Common.Collections
|
||||
{
|
||||
RestoreBalanceAfterRemoval(child);
|
||||
}
|
||||
|
||||
if (old.Successor != null)
|
||||
old.Successor.Predecessor = old.Predecessor;
|
||||
if (old.Predecessor != null)
|
||||
old.Predecessor.Successor = old.Successor;
|
||||
|
||||
return old;
|
||||
}
|
||||
|
@@ -9,8 +9,7 @@ namespace Ryujinx.Common.Collections
|
||||
public T Left;
|
||||
public T Right;
|
||||
public T Parent;
|
||||
|
||||
public T Predecessor => IntrusiveRedBlackTreeImpl<T>.PredecessorOf((T)this);
|
||||
public T Successor => IntrusiveRedBlackTreeImpl<T>.SuccessorOf((T)this);
|
||||
public T Predecessor;
|
||||
public T Successor;
|
||||
}
|
||||
}
|
||||
|
@@ -109,7 +109,7 @@ namespace Ryujinx.Common.Collections
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
Node<TKey, TValue> successor = SuccessorOf(node);
|
||||
Node<TKey, TValue> successor = node.Successor;
|
||||
|
||||
return successor != null ? successor.Key : default;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ namespace Ryujinx.Common.Collections
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
Node<TKey, TValue> predecessor = PredecessorOf(node);
|
||||
Node<TKey, TValue> predecessor = node.Predecessor;
|
||||
|
||||
return predecessor != null ? predecessor.Key : default;
|
||||
}
|
||||
@@ -136,11 +136,10 @@ namespace Ryujinx.Common.Collections
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the nodes in the dictionary as key/value pairs into <paramref name="list"/>.
|
||||
/// Adds all the nodes in the dictionary as key/value pairs into a list.
|
||||
/// <br></br>
|
||||
/// The key/value pairs will be added in Level Order.
|
||||
/// </summary>
|
||||
/// <param name="list">List to add the tree pairs into</param>
|
||||
public List<KeyValuePair<TKey, TValue>> AsLevelOrderList()
|
||||
{
|
||||
List<KeyValuePair<TKey, TValue>> list = [];
|
||||
@@ -170,7 +169,7 @@ namespace Ryujinx.Common.Collections
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the nodes in the dictionary into <paramref name="list"/>.
|
||||
/// Adds all the nodes in the dictionary into a list.
|
||||
/// </summary>
|
||||
/// <returns>A list of all KeyValuePairs sorted by Key Order</returns>
|
||||
public List<KeyValuePair<TKey, TValue>> AsList()
|
||||
@@ -284,7 +283,7 @@ namespace Ryujinx.Common.Collections
|
||||
}
|
||||
|
||||
Node<TKey, TValue> newNode = new(key, value, parent);
|
||||
if (newNode.Parent == null)
|
||||
if (parent == null)
|
||||
{
|
||||
Root = newNode;
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ namespace Ryujinx.Common.Logging
|
||||
Cpu,
|
||||
Emulation,
|
||||
FFmpeg,
|
||||
GdbStub,
|
||||
Font,
|
||||
Gpu,
|
||||
Hid,
|
||||
|
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common.Memory
|
||||
{
|
||||
/// <summary>
|
||||
@@ -17,5 +19,10 @@ namespace Ryujinx.Common.Memory
|
||||
/// Number of elements on the array.
|
||||
/// </summary>
|
||||
int Length { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of elements on the array.
|
||||
/// </summary>
|
||||
public Span<T> AsSpan();
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -10,11 +11,126 @@ namespace Ryujinx.Common.Memory
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
|
||||
/// accessor, with memory allocated from <seealso cref="ArrayPool{T}.Shared"/>.
|
||||
/// accessor, with memory allocated from <see cref="ArrayPooling"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of item to store.</typeparam>
|
||||
public sealed class MemoryOwner<T> : IMemoryOwner<T>
|
||||
{
|
||||
private static class ArrayPooling
|
||||
{
|
||||
public class Holder(T[]? array = null) : IComparable<Holder>, IComparable<int>
|
||||
{
|
||||
public int SkipCount;
|
||||
public readonly T[]? Array = array;
|
||||
|
||||
public int CompareTo(Holder? other)
|
||||
{
|
||||
return Array!.Length.CompareTo(other!.Array!.Length);
|
||||
}
|
||||
|
||||
public int CompareTo(int other)
|
||||
{
|
||||
int self = Array!.Length;
|
||||
|
||||
if (self < other)
|
||||
{
|
||||
SkipCount++;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self > other * 4)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
private static int _maxCacheCount = 50;
|
||||
|
||||
private const int MaxSkipCount = 50;
|
||||
|
||||
static readonly List<Holder> _pool = new();
|
||||
|
||||
// ReSharper disable once StaticMemberInGenericType
|
||||
static readonly Lock _lock = new();
|
||||
|
||||
private static int BinarySearch(List<Holder> list, int size)
|
||||
{
|
||||
int min = 0;
|
||||
int max = list.Count-1;
|
||||
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int comparison = list[mid].CompareTo(size);
|
||||
if (comparison == 0)
|
||||
{
|
||||
return mid;
|
||||
}
|
||||
if (comparison < 0)
|
||||
{
|
||||
min = mid+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
max = mid-1;
|
||||
}
|
||||
}
|
||||
return ~min;
|
||||
}
|
||||
|
||||
public static T[] Get(int minimumSize)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
int index = BinarySearch(_pool, minimumSize);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
Holder holder = _pool[index];
|
||||
|
||||
_pool.Remove(holder);
|
||||
return holder.Array!;
|
||||
}
|
||||
|
||||
return new T[minimumSize];
|
||||
}
|
||||
}
|
||||
|
||||
public static void Return(T[] array)
|
||||
{
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
Holder holder = new(array);
|
||||
int i = _pool.BinarySearch(holder);
|
||||
if (i < 0)
|
||||
{
|
||||
_pool.Insert(~i, holder);
|
||||
}
|
||||
|
||||
if (_pool.Count >= _maxCacheCount)
|
||||
{
|
||||
for (int index = 0; index < _pool.Count; index++)
|
||||
{
|
||||
Holder h = _pool[index];
|
||||
|
||||
if (h.SkipCount >= MaxSkipCount)
|
||||
{
|
||||
_pool.Remove(h);
|
||||
index--;
|
||||
}
|
||||
}
|
||||
|
||||
_maxCacheCount = _pool.Count * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly int _length;
|
||||
private T[]? _array;
|
||||
|
||||
@@ -25,7 +141,7 @@ namespace Ryujinx.Common.Memory
|
||||
private MemoryOwner(int length)
|
||||
{
|
||||
_length = length;
|
||||
_array = ArrayPool<T>.Shared.Rent(length);
|
||||
_array = ArrayPooling.Get(length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -124,7 +240,7 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
if (array is not null)
|
||||
{
|
||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
|
||||
ArrayPooling.Return(array);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||
@@ -42,10 +43,13 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
public int GetOrReserve(int threadId, T initial)
|
||||
{
|
||||
// Try get a match first.
|
||||
|
||||
Span<int> threadIdsSpan = ThreadIds.AsSpan();
|
||||
Span<T> structsSpan = Structs.AsSpan();
|
||||
|
||||
for (int i = 0; i < MapSize; i++)
|
||||
{
|
||||
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, threadId);
|
||||
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, threadId);
|
||||
|
||||
if (compare == threadId)
|
||||
{
|
||||
@@ -57,11 +61,11 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
||||
for (int i = 0; i < MapSize; i++)
|
||||
{
|
||||
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, 0);
|
||||
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, 0);
|
||||
|
||||
if (compare == 0)
|
||||
{
|
||||
Structs[i] = initial;
|
||||
structsSpan[i] = initial;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@@ -2,8 +2,18 @@ namespace Ryujinx.Common
|
||||
{
|
||||
public static class SharedConstants
|
||||
{
|
||||
public const string DefaultLanPlayHost = "ryuldn.vudjun.com";
|
||||
public const string DefaultLanPlayHost = "ldn.ryujinx.app";
|
||||
public const short LanPlayPort = 30456;
|
||||
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
||||
public const string DefaultLanPlayWebHost = DefaultLanPlayHost;
|
||||
|
||||
public const string AmiiboTagsUrl = "https://raw.githubusercontent.com/Ryubing/Nfc/refs/heads/main/tags.json";
|
||||
|
||||
public const string FaqWikiUrl = "https://git.ryujinx.app/ryubing/ryujinx/-/wikis/FAQ-&-Troubleshooting";
|
||||
|
||||
public const string SetupGuideWikiUrl =
|
||||
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Setup-&-Configuration-Guide";
|
||||
|
||||
public const string MultiplayerWikiUrl =
|
||||
"https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Multiplayer-(LDN-Local-Wireless)-Guide";
|
||||
}
|
||||
}
|
||||
|
@@ -182,6 +182,7 @@ namespace Ryujinx.Common
|
||||
"01001cc01b2d4000", // Goat Simulator 3
|
||||
"01003620068ea000", // Hand of Fate 2
|
||||
"0100f7e00c70e000", // Hogwarts Legacy
|
||||
"010013c00e930000", // Hollow Knight: Silksong
|
||||
"010085500130a000", // Lego City: Undercover
|
||||
"010073c01af34000", // LEGO Horizon Adventures
|
||||
"0100d71004694000", // Minecraft
|
||||
|
10
src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs
Normal file
10
src/Ryujinx.Cpu/AppleHv/Arm/ExceptionLevel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Ryujinx.Cpu.AppleHv.Arm
|
||||
{
|
||||
enum ExceptionLevel : uint
|
||||
{
|
||||
PstateMask = 0xfffffff0,
|
||||
EL1h = 0b0101,
|
||||
El1t = 0b0100,
|
||||
EL0 = 0b0000,
|
||||
}
|
||||
}
|
@@ -11,7 +11,18 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
class HvExecutionContext : IExecutionContext
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ulong Pc => _impl.ElrEl1;
|
||||
public ulong Pc
|
||||
{
|
||||
get
|
||||
{
|
||||
uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
|
||||
if (currentEl == (uint)ExceptionLevel.EL1h)
|
||||
{
|
||||
return _impl.ElrEl1;
|
||||
}
|
||||
return _impl.Pc;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long TpidrEl0
|
||||
@@ -48,6 +59,9 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
set => _impl.Fpsr = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsAarch32
|
||||
{
|
||||
@@ -67,6 +81,7 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
private readonly ICounter _counter;
|
||||
private readonly IHvExecutionContext _shadowContext;
|
||||
private IHvExecutionContext _impl;
|
||||
private int _shouldStep;
|
||||
|
||||
private readonly ExceptionCallbacks _exceptionCallbacks;
|
||||
|
||||
@@ -103,6 +118,11 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
_exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
private void StepHandler()
|
||||
{
|
||||
_exceptionCallbacks.StepCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
private void SupervisorCallHandler(ulong address, int imm)
|
||||
{
|
||||
_exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
|
||||
@@ -127,6 +147,30 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
Interlocked.Exchange(ref _shouldStep, 1);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong DebugPc
|
||||
{
|
||||
get => Pc;
|
||||
set
|
||||
{
|
||||
uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
|
||||
if (currentEl == (uint)ExceptionLevel.EL1h)
|
||||
{
|
||||
_impl.ElrEl1 = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_impl.Pc = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void StopRunning()
|
||||
{
|
||||
@@ -142,6 +186,22 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
|
||||
while (Running)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref _shouldStep, 0, 1) == 1)
|
||||
{
|
||||
uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
|
||||
if (currentEl == (uint)ExceptionLevel.EL1h)
|
||||
{
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, out ulong spsr).ThrowOnError();
|
||||
spsr |= (1 << 21);
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu.Handle, HvSysReg.SPSR_EL1, spsr);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pstate |= (1 << 21);
|
||||
}
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpu.Handle, HvSysReg.MDSCR_EL1, 1);
|
||||
}
|
||||
|
||||
HvApi.hv_vcpu_run(vcpu.Handle).ThrowOnError();
|
||||
|
||||
HvExitReason reason = vcpu.ExitInfo->Reason;
|
||||
@@ -209,6 +269,20 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
SupervisorCallHandler(elr - 4UL, id);
|
||||
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
||||
break;
|
||||
case ExceptionClass.SoftwareStepLowerEl:
|
||||
HvApi.hv_vcpu_get_sys_reg(vcpuHandle, HvSysReg.SPSR_EL1, out ulong spsr).ThrowOnError();
|
||||
spsr &= ~((ulong)(1 << 21));
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.SPSR_EL1, spsr).ThrowOnError();
|
||||
HvApi.hv_vcpu_set_sys_reg(vcpuHandle, HvSysReg.MDSCR_EL1, 0);
|
||||
ReturnToPool(vcpu);
|
||||
StepHandler();
|
||||
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
||||
break;
|
||||
case ExceptionClass.BrkAarch64:
|
||||
ReturnToPool(vcpu);
|
||||
BreakHandler(elr, (ushort)esr);
|
||||
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Unhandled guest exception {ec}.");
|
||||
}
|
||||
@@ -219,10 +293,7 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
// TODO: Invalidate only the range that was modified?
|
||||
return HvAddressSpace.KernelRegionTlbiEretAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HvAddressSpace.KernelRegionEretAddress;
|
||||
}
|
||||
return HvAddressSpace.KernelRegionEretAddress;
|
||||
}
|
||||
|
||||
private static void DataAbort(MemoryTracking tracking, ulong vcpu, uint esr)
|
||||
|
@@ -18,6 +18,8 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
private readonly ulong[] _x;
|
||||
private readonly V128[] _v;
|
||||
|
||||
@@ -46,5 +48,14 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
_v[index] = value;
|
||||
}
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
}
|
||||
|
||||
public bool GetAndClearInterruptRequested()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ using ARMeilleure.State;
|
||||
using Ryujinx.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
@@ -13,6 +14,8 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
private static readonly SetSimdFpReg _setSimdFpReg;
|
||||
private static readonly nint _setSimdFpRegNativePtr;
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
static HvExecutionContextVcpu()
|
||||
{
|
||||
// .NET does not support passing vectors by value, so we need to pass a pointer and use a native
|
||||
@@ -135,6 +138,7 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
}
|
||||
|
||||
private readonly ulong _vcpu;
|
||||
private int _interruptRequested;
|
||||
|
||||
public HvExecutionContextVcpu(ulong vcpu)
|
||||
{
|
||||
@@ -180,8 +184,16 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
ulong vcpu = _vcpu;
|
||||
HvApi.hv_vcpus_exit(ref vcpu, 1);
|
||||
if (Interlocked.Exchange(ref _interruptRequested, 1) == 0)
|
||||
{
|
||||
ulong vcpu = _vcpu;
|
||||
HvApi.hv_vcpus_exit(ref vcpu, 1);
|
||||
}
|
||||
}
|
||||
|
||||
public bool GetAndClearInterruptRequested()
|
||||
{
|
||||
return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
|
||||
uint Fpcr { get; set; }
|
||||
uint Fpsr { get; set; }
|
||||
ulong ThreadUid { get; set; }
|
||||
|
||||
ulong GetX(int index);
|
||||
void SetX(int index, ulong value);
|
||||
@@ -39,5 +40,8 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
SetV(i, context.GetV(i));
|
||||
}
|
||||
}
|
||||
|
||||
void RequestInterrupt();
|
||||
bool GetAndClearInterruptRequested();
|
||||
}
|
||||
}
|
||||
|
@@ -29,6 +29,11 @@ namespace Ryujinx.Cpu
|
||||
/// </summary>
|
||||
public readonly ExceptionCallback BreakCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CPU software interrupts caused by single-stepping.
|
||||
/// </summary>
|
||||
public readonly ExceptionCallbackNoArgs StepCallback;
|
||||
|
||||
/// <summary>
|
||||
/// Handler for CPU software interrupts caused by the Arm SVC instruction.
|
||||
/// </summary>
|
||||
@@ -47,16 +52,19 @@ namespace Ryujinx.Cpu
|
||||
/// </remarks>
|
||||
/// <param name="interruptCallback">Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/></param>
|
||||
/// <param name="breakCallback">Handler for CPU software interrupts caused by the Arm BRK instruction</param>
|
||||
/// <param name="stepCallback">Handler for CPU software interrupts caused by single-stepping</param>
|
||||
/// <param name="supervisorCallback">Handler for CPU software interrupts caused by the Arm SVC instruction</param>
|
||||
/// <param name="undefinedCallback">Handler for CPU software interrupts caused by any undefined Arm instruction</param>
|
||||
public ExceptionCallbacks(
|
||||
ExceptionCallbackNoArgs interruptCallback = null,
|
||||
ExceptionCallback breakCallback = null,
|
||||
ExceptionCallbackNoArgs stepCallback = null,
|
||||
ExceptionCallback supervisorCallback = null,
|
||||
ExceptionCallback undefinedCallback = null)
|
||||
{
|
||||
InterruptCallback = interruptCallback;
|
||||
BreakCallback = breakCallback;
|
||||
StepCallback = stepCallback;
|
||||
SupervisorCallback = supervisorCallback;
|
||||
UndefinedCallback = undefinedCallback;
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
@@ -46,6 +47,11 @@ namespace Ryujinx.Cpu
|
||||
/// </summary>
|
||||
bool IsAarch32 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Thread UID.
|
||||
/// </summary>
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whenever the CPU is still running code.
|
||||
/// </summary>
|
||||
@@ -108,5 +114,23 @@ namespace Ryujinx.Cpu
|
||||
/// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead.
|
||||
/// </remarks>
|
||||
void StopRunning();
|
||||
|
||||
/// <summary>
|
||||
/// Requests the thread to stop running temporarily and call <see cref="ExceptionCallbacks.InterruptCallback"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The thread might not pause immediately.
|
||||
/// One must not assume that guest code is no longer being executed by the thread after calling this function.
|
||||
/// After single stepping, the thread should call call <see cref="ExceptionCallbacks.StepCallback"/>.
|
||||
/// </remarks>
|
||||
void RequestDebugStep();
|
||||
|
||||
/// <summary>
|
||||
/// Current Program Counter (for debugging).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// PC register for the debugger. Must not be accessed while the thread isn't stopped for debugging.
|
||||
/// </remarks>
|
||||
ulong DebugPc { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
||||
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
@@ -53,6 +54,13 @@ namespace Ryujinx.Cpu.Jit
|
||||
set => _impl.IsAarch32 = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong ThreadUid
|
||||
{
|
||||
get => _impl.ThreadUid;
|
||||
set => _impl.ThreadUid = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Running => _impl.Running;
|
||||
|
||||
@@ -65,6 +73,7 @@ namespace Ryujinx.Cpu.Jit
|
||||
counter,
|
||||
InterruptHandler,
|
||||
BreakHandler,
|
||||
StepHandler,
|
||||
SupervisorCallHandler,
|
||||
UndefinedHandler);
|
||||
|
||||
@@ -93,6 +102,11 @@ namespace Ryujinx.Cpu.Jit
|
||||
_exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
|
||||
}
|
||||
|
||||
private void StepHandler(ExecutionContext context)
|
||||
{
|
||||
_exceptionCallbacks.StepCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
private void SupervisorCallHandler(ExecutionContext context, ulong address, int imm)
|
||||
{
|
||||
_exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
|
||||
@@ -109,6 +123,16 @@ namespace Ryujinx.Cpu.Jit
|
||||
_impl.RequestInterrupt();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RequestDebugStep() => _impl.RequestDebugStep();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong DebugPc
|
||||
{
|
||||
get => _impl.DebugPc;
|
||||
set => _impl.DebugPc = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void StopRunning()
|
||||
{
|
||||
|
@@ -1,6 +1,8 @@
|
||||
using ARMeilleure;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu.LightningJit.State
|
||||
{
|
||||
@@ -51,6 +53,8 @@ namespace Ryujinx.Cpu.LightningJit.State
|
||||
}
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
{
|
||||
@@ -77,15 +81,20 @@ namespace Ryujinx.Cpu.LightningJit.State
|
||||
|
||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||
private readonly ExceptionCallback _breakCallback;
|
||||
private readonly ExceptionCallbackNoArgs _stepCallback;
|
||||
private readonly ExceptionCallback _supervisorCallback;
|
||||
private readonly ExceptionCallback _undefinedCallback;
|
||||
|
||||
internal int ShouldStep;
|
||||
public ulong DebugPc { get; set; }
|
||||
|
||||
public ExecutionContext(IJitMemoryAllocator allocator, ICounter counter, ExceptionCallbacks exceptionCallbacks)
|
||||
{
|
||||
_nativeContext = new NativeContext(allocator);
|
||||
_counter = counter;
|
||||
_interruptCallback = exceptionCallbacks.InterruptCallback;
|
||||
_breakCallback = exceptionCallbacks.BreakCallback;
|
||||
_stepCallback = exceptionCallbacks.StepCallback;
|
||||
_supervisorCallback = exceptionCallbacks.SupervisorCallback;
|
||||
_undefinedCallback = exceptionCallbacks.UndefinedCallback;
|
||||
|
||||
@@ -117,6 +126,17 @@ namespace Ryujinx.Cpu.LightningJit.State
|
||||
_interrupted = true;
|
||||
}
|
||||
|
||||
public void StepHandler()
|
||||
{
|
||||
_stepCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
Interlocked.Exchange(ref ShouldStep, 1);
|
||||
RequestInterrupt();
|
||||
}
|
||||
|
||||
internal void OnBreak(ulong address, int imm)
|
||||
{
|
||||
_breakCallback?.Invoke(this, address, imm);
|
||||
|
@@ -81,16 +81,8 @@ namespace Ryujinx.Graphics.Device
|
||||
if (index < Size)
|
||||
{
|
||||
uint alignedOffset = index * RegisterSize;
|
||||
|
||||
Func<int> readCallback = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_readCallbacks), (nint)index);
|
||||
if (readCallback != null)
|
||||
{
|
||||
return readCallback();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetRefUnchecked<int>(alignedOffset);
|
||||
}
|
||||
|
||||
return _readCallbacks[index]?.Invoke() ?? GetRefUnchecked<int>(alignedOffset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -105,9 +97,9 @@ namespace Ryujinx.Graphics.Device
|
||||
uint alignedOffset = index * RegisterSize;
|
||||
DebugWrite(alignedOffset, data);
|
||||
|
||||
GetRefIntAlignedUncheck(index) = data;
|
||||
SetIntAlignedUncheck(index, data);
|
||||
|
||||
Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (nint)index)?.Invoke(data);
|
||||
_writeCallbacks[index]?.Invoke(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,11 +112,9 @@ namespace Ryujinx.Graphics.Device
|
||||
uint alignedOffset = index * RegisterSize;
|
||||
DebugWrite(alignedOffset, data);
|
||||
|
||||
ref int storage = ref GetRefIntAlignedUncheck(index);
|
||||
changed = storage != data;
|
||||
storage = data;
|
||||
changed = SetIntAlignedUncheckChanged(index, data);
|
||||
|
||||
Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (nint)index)?.Invoke(data);
|
||||
_writeCallbacks[index]?.Invoke(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -162,5 +152,24 @@ namespace Ryujinx.Graphics.Device
|
||||
{
|
||||
return ref Unsafe.Add(ref Unsafe.As<TState, int>(ref State), (nint)index);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void SetIntAlignedUncheck(ulong index, int data)
|
||||
{
|
||||
Unsafe.Add(ref Unsafe.As<TState, int>(ref State), (nint)index) = data;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool SetIntAlignedUncheckChanged(ulong index, int data)
|
||||
{
|
||||
ref int val = ref Unsafe.Add(ref Unsafe.As<TState, int>(ref State), (nint)index);
|
||||
if (val == data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
val = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -219,13 +219,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
state.Write(LogicOpOffset, 0);
|
||||
|
||||
Array8<Boolean32> enable = new();
|
||||
Span<Boolean32> enableSpan = enable.AsSpan();
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
enable[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1);
|
||||
enableSpan[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1);
|
||||
}
|
||||
|
||||
_processor.ThreedClass.UpdateBlendEnable(ref enable);
|
||||
_processor.ThreedClass.UpdateBlendEnable(enableSpan);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -236,13 +237,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
private void UpdateColorMasks(IDeviceState state, int arg0)
|
||||
{
|
||||
Array8<RtColorMask> masks = new();
|
||||
Span<RtColorMask> masksSpan = masks.AsSpan();
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
masks[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
||||
masks[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
||||
masksSpan[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
||||
masksSpan[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
||||
|
||||
if (i != 3)
|
||||
{
|
||||
@@ -250,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
}
|
||||
}
|
||||
|
||||
_processor.ThreedClass.UpdateColorMasks(ref masks);
|
||||
_processor.ThreedClass.UpdateColorMasks(masksSpan);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -75,10 +75,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender
|
||||
{
|
||||
bool constantsMatch = true;
|
||||
|
||||
Span<RgbHalf> blendUcodeConstantsSpan = _state.State.BlendUcodeConstants.AsSpan();
|
||||
|
||||
for (int i = 0; i < entry.Constants.Length; i++)
|
||||
{
|
||||
RgbFloat constant = entry.Constants[i];
|
||||
RgbHalf constant2 = _state.State.BlendUcodeConstants[i];
|
||||
RgbHalf constant2 = blendUcodeConstantsSpan[i];
|
||||
|
||||
if ((Half)constant.R != constant2.UnpackR() ||
|
||||
(Half)constant.G != constant2.UnpackG() ||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -76,9 +77,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||
/// <param name="componentCount">Number of components that the format has</param>
|
||||
public void SetVertexStride(int index, int stride, int componentCount)
|
||||
{
|
||||
if (_data.VertexStrides[index].X != stride)
|
||||
Span<Vector4<int>> vertexStridesSpan = _data.VertexStrides.AsSpan();
|
||||
|
||||
if (vertexStridesSpan[index].X != stride)
|
||||
{
|
||||
_data.VertexStrides[index].X = stride;
|
||||
vertexStridesSpan[index].X = stride;
|
||||
MarkDirty(VertexInfoBuffer.VertexStridesOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
||||
}
|
||||
|
||||
@@ -86,7 +89,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||
{
|
||||
int value = c < componentCount ? 1 : 0;
|
||||
|
||||
ref int currentValue = ref GetElementRef(ref _data.VertexStrides[index], c);
|
||||
ref int currentValue = ref GetElementRef(ref vertexStridesSpan[index], c);
|
||||
|
||||
if (currentValue != value)
|
||||
{
|
||||
@@ -104,15 +107,17 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||
/// <param name="divisor">If the draw is instanced, should have the vertex divisor value, otherwise should be zero</param>
|
||||
public void SetVertexOffset(int index, int offset, int divisor)
|
||||
{
|
||||
if (_data.VertexOffsets[index].X != offset)
|
||||
Span<Vector4<int>> vertexOffsetsSpan = _data.VertexOffsets.AsSpan();
|
||||
|
||||
if (vertexOffsetsSpan[index].X != offset)
|
||||
{
|
||||
_data.VertexOffsets[index].X = offset;
|
||||
vertexOffsetsSpan[index].X = offset;
|
||||
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
||||
}
|
||||
|
||||
if (_data.VertexOffsets[index].Y != divisor)
|
||||
if (vertexOffsetsSpan[index].Y != divisor)
|
||||
{
|
||||
_data.VertexOffsets[index].Y = divisor;
|
||||
vertexOffsetsSpan[index].Y = divisor;
|
||||
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>() + sizeof(int), sizeof(int));
|
||||
}
|
||||
}
|
||||
|
@@ -125,9 +125,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||
_vacContext.VertexInfoBufferUpdater.SetVertexCounts(_count, _instanceCount, _firstVertex, _firstInstance);
|
||||
_vacContext.VertexInfoBufferUpdater.SetGeometryCounts(primitivesCount);
|
||||
|
||||
Span<VertexAttribState> vertexAttribStateSpan = _state.State.VertexAttribState.AsSpan();
|
||||
Span<GpuVa> vertexBufferEndAddressSpan = _state.State.VertexBufferEndAddress.AsSpan();
|
||||
Span<VertexBufferState> vertexBufferStateSpan = _state.State.VertexBufferState.AsSpan();
|
||||
Span<Boolean32> vertexBufferInstancedSpan = _state.State.VertexBufferInstanced.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
||||
{
|
||||
VertexAttribState vertexAttrib = _state.State.VertexAttribState[index];
|
||||
VertexAttribState vertexAttrib = vertexAttribStateSpan[index];
|
||||
|
||||
if (!FormatTable.TryGetSingleComponentAttribFormat(vertexAttrib.UnpackFormat(), out Format format, out int componentsCount))
|
||||
{
|
||||
@@ -153,9 +158,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||
|
||||
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
||||
|
||||
GpuVa endAddress = _state.State.VertexBufferEndAddress[bufferIndex];
|
||||
VertexBufferState vertexBuffer = _state.State.VertexBufferState[bufferIndex];
|
||||
bool instanced = _state.State.VertexBufferInstanced[bufferIndex];
|
||||
GpuVa endAddress = vertexBufferEndAddressSpan[bufferIndex];
|
||||
VertexBufferState vertexBuffer = vertexBufferStateSpan[bufferIndex];
|
||||
bool instanced = vertexBufferInstancedSpan[bufferIndex];
|
||||
|
||||
ulong address = vertexBuffer.Address.Pack();
|
||||
|
||||
|
@@ -821,6 +821,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
// on the screen scissor state, then we need to force only one texture to be bound to avoid
|
||||
// host clipping.
|
||||
ScreenScissorState screenScissorState = _state.State.ScreenScissorState;
|
||||
|
||||
Span<ScissorState> scissorStateSpan = _state.State.ScissorState.AsSpan();
|
||||
|
||||
bool clearAffectedByStencilMask = (_state.State.ClearFlags & 1) != 0;
|
||||
bool clearAffectedByScissor = (_state.State.ClearFlags & 0x100) != 0;
|
||||
@@ -831,9 +833,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
bool fullClear = screenScissorState.X == 0 && screenScissorState.Y == 0;
|
||||
|
||||
if (fullClear && clearAffectedByScissor && _state.State.ScissorState[0].Enable)
|
||||
if (fullClear && clearAffectedByScissor && scissorStateSpan[0].Enable)
|
||||
{
|
||||
ref ScissorState scissorState = ref _state.State.ScissorState[0];
|
||||
ref ScissorState scissorState = ref scissorStateSpan[0];
|
||||
|
||||
fullClear = scissorState.X1 == screenScissorState.X &&
|
||||
scissorState.Y1 == screenScissorState.Y &&
|
||||
@@ -892,9 +894,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
int scissorW = screenScissorState.Width;
|
||||
int scissorH = screenScissorState.Height;
|
||||
|
||||
if (clearAffectedByScissor && _state.State.ScissorState[0].Enable)
|
||||
if (clearAffectedByScissor && scissorStateSpan[0].Enable)
|
||||
{
|
||||
ref ScissorState scissorState = ref _state.State.ScissorState[0];
|
||||
ref ScissorState scissorState = ref scissorStateSpan[0];
|
||||
|
||||
scissorX = Math.Max(scissorX, scissorState.X1);
|
||||
scissorY = Math.Max(scissorY, scissorState.Y1);
|
||||
|
@@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
@@ -214,10 +215,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// Updates the type of the vertex attributes consumed by the shader.
|
||||
/// </summary>
|
||||
/// <param name="state">The new state</param>
|
||||
public void SetAttributeTypes(ref Array32<VertexAttribState> state)
|
||||
public void SetAttributeTypes(ReadOnlySpan<VertexAttribState> state)
|
||||
{
|
||||
bool changed = false;
|
||||
ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
||||
// ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
||||
Span<AttributeType> attributeTypesSpan = _graphics.AttributeTypes.AsSpan();
|
||||
bool mayConvertVtgToCompute = ShaderCache.MayConvertVtgToCompute(ref _context.Capabilities);
|
||||
bool supportsScaledFormats = _context.Capabilities.SupportsScaledVertexFormats && !mayConvertVtgToCompute;
|
||||
|
||||
@@ -261,9 +263,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
}
|
||||
}
|
||||
|
||||
if (attributeTypes[location] != value)
|
||||
if (attributeTypesSpan[location] != value)
|
||||
{
|
||||
attributeTypes[location] = value;
|
||||
attributeTypesSpan[location] = value;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -279,10 +281,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
/// <param name="rtControl">The render target control register</param>
|
||||
/// <param name="state">The color attachment state</param>
|
||||
public void SetFragmentOutputTypes(RtControl rtControl, ref Array8<RtColorState> state)
|
||||
public void SetFragmentOutputTypes(RtControl rtControl, ReadOnlySpan<RtColorState> state)
|
||||
{
|
||||
bool changed = false;
|
||||
int count = rtControl.UnpackCount();
|
||||
|
||||
Span<AttributeType> fragmentOutputTypesSpan = _graphics.FragmentOutputTypes.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||
{
|
||||
@@ -296,9 +300,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
|
||||
|
||||
if (type != _graphics.FragmentOutputTypes[index])
|
||||
if (type != fragmentOutputTypesSpan[index])
|
||||
{
|
||||
_graphics.FragmentOutputTypes[index] = type;
|
||||
fragmentOutputTypesSpan[index] = type;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
@@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
if (index < BlockSize)
|
||||
{
|
||||
int groupIndex = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_registerToGroupMapping), (nint)index);
|
||||
int groupIndex = _registerToGroupMapping[index];
|
||||
if (groupIndex != 0)
|
||||
{
|
||||
groupIndex--;
|
||||
|
@@ -423,9 +423,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
private void UpdateTfBufferState()
|
||||
{
|
||||
Span<TfBufferState> tfBufferStateSpan = _state.State.TfBufferState.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||
{
|
||||
TfBufferState tfb = _state.State.TfBufferState[index];
|
||||
TfBufferState tfb = tfBufferStateSpan[index];
|
||||
|
||||
if (!tfb.Enable)
|
||||
{
|
||||
@@ -466,10 +468,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
MemoryManager memoryManager = _channel.MemoryManager;
|
||||
RtControl rtControl = _state.State.RtControl;
|
||||
|
||||
bool useControl = updateFlags.HasFlag(RenderTargetUpdateFlags.UseControl);
|
||||
bool layered = updateFlags.HasFlag(RenderTargetUpdateFlags.Layered);
|
||||
bool singleColor = updateFlags.HasFlag(RenderTargetUpdateFlags.SingleColor);
|
||||
bool discard = updateFlags.HasFlag(RenderTargetUpdateFlags.DiscardClip);
|
||||
bool useControl = (updateFlags & RenderTargetUpdateFlags.UseControl) == RenderTargetUpdateFlags.UseControl;
|
||||
bool layered = (updateFlags & RenderTargetUpdateFlags.Layered) == RenderTargetUpdateFlags.Layered;
|
||||
bool singleColor = (updateFlags & RenderTargetUpdateFlags.SingleColor) == RenderTargetUpdateFlags.SingleColor;
|
||||
bool discard = (updateFlags & RenderTargetUpdateFlags.DiscardClip) == RenderTargetUpdateFlags.DiscardClip;
|
||||
|
||||
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
|
||||
|
||||
@@ -487,11 +489,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
bool changedScale = false;
|
||||
uint rtNoAlphaMask = 0;
|
||||
|
||||
Span<RtColorState> rtColorStateSpan = _state.State.RtColorState.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||
{
|
||||
int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : index;
|
||||
|
||||
RtColorState colorState = _state.State.RtColorState[rtIndex];
|
||||
RtColorState colorState = rtColorStateSpan[rtIndex];
|
||||
|
||||
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
|
||||
{
|
||||
@@ -539,7 +543,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
Image.Texture depthStencil = null;
|
||||
|
||||
if (dsEnable && updateFlags.HasFlag(RenderTargetUpdateFlags.UpdateDepthStencil))
|
||||
if (dsEnable && (updateFlags & RenderTargetUpdateFlags.UpdateDepthStencil) == RenderTargetUpdateFlags.UpdateDepthStencil)
|
||||
{
|
||||
RtDepthStencilState dsState = _state.State.RtDepthStencilState;
|
||||
Size3D dsSize = _state.State.RtDepthStencilSize;
|
||||
@@ -599,7 +603,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
public void UpdateRenderTargetSpecialization()
|
||||
{
|
||||
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, ref _state.State.RtColorState);
|
||||
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, _state.State.RtColorState.AsSpan());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -624,10 +628,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
const int MaxH = 0xffff;
|
||||
|
||||
Span<Rectangle<int>> regions = stackalloc Rectangle<int>[Constants.TotalViewports];
|
||||
|
||||
Span<ScissorState> scissorStateSpan = _state.State.ScissorState.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalViewports; index++)
|
||||
{
|
||||
ScissorState scissor = _state.State.ScissorState[index];
|
||||
ScissorState scissor = scissorStateSpan[index];
|
||||
|
||||
bool enable = scissor.Enable && (scissor.X1 != MinX ||
|
||||
scissor.Y1 != MinY ||
|
||||
@@ -731,6 +736,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
UpdateDepthMode();
|
||||
|
||||
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
||||
Span<ViewportTransform> viewportTransformSpan = _state.State.ViewportTransform.AsSpan();
|
||||
Span<ViewportExtents> viewportExtentsSpan = _state.State.ViewportExtents.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalViewports; index++)
|
||||
{
|
||||
@@ -745,8 +752,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
continue;
|
||||
}
|
||||
|
||||
ref ViewportTransform transform = ref _state.State.ViewportTransform[index];
|
||||
ref ViewportExtents extents = ref _state.State.ViewportExtents[index];
|
||||
ref ViewportTransform transform = ref viewportTransformSpan[index];
|
||||
ref ViewportExtents extents = ref viewportExtentsSpan[index];
|
||||
|
||||
float scaleX = MathF.Abs(transform.ScaleX);
|
||||
float scaleY = transform.ScaleY;
|
||||
@@ -968,10 +975,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
uint vbEnableMask = _vbEnableMask;
|
||||
|
||||
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
|
||||
|
||||
Span<VertexAttribState> vertexAttribStateSpan = _state.State.VertexAttribState.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
||||
{
|
||||
VertexAttribState vertexAttrib = _state.State.VertexAttribState[index];
|
||||
VertexAttribState vertexAttrib = vertexAttribStateSpan[index];
|
||||
|
||||
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
||||
|
||||
@@ -1015,7 +1023,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_pipeline.SetVertexAttribs(vertexAttribs);
|
||||
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
||||
_currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
|
||||
_currentSpecState.SetAttributeTypes(_state.State.VertexAttribState.AsSpan());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1113,20 +1121,25 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
int drawFirstVertex = _drawState.DrawFirstVertex;
|
||||
int drawVertexCount = _drawState.DrawVertexCount;
|
||||
uint vbEnableMask = 0;
|
||||
|
||||
Span<VertexBufferState> vertexBufferStateSpan = _state.State.VertexBufferState.AsSpan();
|
||||
Span<BufferPipelineDescriptor> vertexBuffersSpan = _pipeline.VertexBuffers.AsSpan();
|
||||
Span<GpuVa> vertexBufferEndAddressSpan = _state.State.VertexBufferEndAddress.AsSpan();
|
||||
Span<Boolean32> vertexBufferInstancedSpan = _state.State.VertexBufferInstanced.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||
{
|
||||
VertexBufferState vertexBuffer = _state.State.VertexBufferState[index];
|
||||
VertexBufferState vertexBuffer = vertexBufferStateSpan[index];
|
||||
|
||||
if (!vertexBuffer.UnpackEnable())
|
||||
{
|
||||
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(false, 0, 0);
|
||||
vertexBuffersSpan[index] = new BufferPipelineDescriptor(false, 0, 0);
|
||||
_channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
GpuVa endAddress = _state.State.VertexBufferEndAddress[index];
|
||||
GpuVa endAddress = vertexBufferEndAddressSpan[index];
|
||||
|
||||
ulong address = vertexBuffer.Address.Pack();
|
||||
|
||||
@@ -1137,7 +1150,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
int stride = vertexBuffer.UnpackStride();
|
||||
|
||||
bool instanced = _state.State.VertexBufferInstanced[index];
|
||||
bool instanced = vertexBufferInstancedSpan[index];
|
||||
|
||||
int divisor = instanced ? vertexBuffer.Divisor : 0;
|
||||
|
||||
@@ -1184,7 +1197,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
size = Math.Min(vbSize, (ulong)((firstInstance + drawFirstVertex + drawVertexCount) * stride));
|
||||
}
|
||||
|
||||
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
||||
vertexBuffersSpan[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
||||
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
||||
}
|
||||
|
||||
@@ -1237,10 +1250,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
bool rtColorMaskShared = _state.State.RtColorMaskShared;
|
||||
|
||||
Span<uint> componentMasks = stackalloc uint[Constants.TotalRenderTargets];
|
||||
Span<RtColorMask> rtColorMaskSpan = _state.State.RtColorMask.AsSpan();
|
||||
Span<uint> colorWriteMaskSpan = _pipeline.ColorWriteMask.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||
{
|
||||
RtColorMask colorMask = _state.State.RtColorMask[rtColorMaskShared ? 0 : index];
|
||||
RtColorMask colorMask = rtColorMaskSpan[rtColorMaskShared ? 0 : index];
|
||||
|
||||
uint componentMask;
|
||||
|
||||
@@ -1250,7 +1265,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
|
||||
|
||||
componentMasks[index] = componentMask;
|
||||
_pipeline.ColorWriteMask[index] = componentMask;
|
||||
colorWriteMaskSpan[index] = componentMask;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
|
||||
@@ -1282,10 +1297,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
if (blendIndependent)
|
||||
{
|
||||
Span<Boolean32> blendEnableSpan = _state.State.BlendEnable.AsSpan();
|
||||
Span<BlendState> blendStateSpan = _state.State.BlendState.AsSpan();
|
||||
Span<BlendDescriptor> blendDescriptorsSpan = _pipeline.BlendDescriptors.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||
{
|
||||
bool enable = _state.State.BlendEnable[index];
|
||||
BlendState blend = _state.State.BlendState[index];
|
||||
bool enable = blendEnableSpan[index];
|
||||
BlendState blend = blendStateSpan[index];
|
||||
|
||||
BlendDescriptor descriptor = new(
|
||||
enable,
|
||||
@@ -1306,7 +1325,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
dualSourceBlendEnabled = true;
|
||||
}
|
||||
|
||||
_pipeline.BlendDescriptors[index] = descriptor;
|
||||
blendDescriptorsSpan[index] = descriptor;
|
||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||
}
|
||||
}
|
||||
@@ -1333,10 +1352,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
dualSourceBlendEnabled = true;
|
||||
}
|
||||
|
||||
Span<BlendDescriptor> blendDescriptorsSpan = _pipeline.BlendDescriptors.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||
{
|
||||
_pipeline.BlendDescriptors[index] = descriptor;
|
||||
blendDescriptorsSpan[index] = descriptor;
|
||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||
}
|
||||
}
|
||||
@@ -1422,12 +1443,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
ShaderAddresses addresses = new();
|
||||
Span<ulong> addressesSpan = addresses.AsSpan();
|
||||
Span<ShaderState> shaderStateSpan = _state.State.ShaderState.AsSpan();
|
||||
|
||||
ulong baseAddress = _state.State.ShaderBaseAddress.Pack();
|
||||
|
||||
for (int index = 0; index < 6; index++)
|
||||
{
|
||||
ShaderState shader = _state.State.ShaderState[index];
|
||||
ShaderState shader = shaderStateSpan[index];
|
||||
if (!shader.UnpackEnable() && index != 1)
|
||||
{
|
||||
continue;
|
||||
|
@@ -242,22 +242,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// <param name="rhs">Second struct</param>
|
||||
/// <returns>True if equal, false otherwise</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static bool UnsafeEquals32Byte<T>(ref T lhs, ref T rhs) where T : unmanaged
|
||||
private static bool UnsafeEquals32Byte<T>(Span<T> lhs, Span<T> rhs) where T : unmanaged
|
||||
{
|
||||
if (Vector256.IsHardwareAccelerated)
|
||||
{
|
||||
return Vector256.EqualsAll(
|
||||
Unsafe.As<T, Vector256<uint>>(ref lhs),
|
||||
Unsafe.As<T, Vector256<uint>>(ref rhs)
|
||||
Unsafe.As<Span<T>, ReadOnlySpan<Vector256<uint>>>(ref lhs)[0],
|
||||
Unsafe.As<Span<T>, ReadOnlySpan<Vector256<uint>>>(ref rhs)[0]
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref Vector128<uint> lhsVec = ref Unsafe.As<T, Vector128<uint>>(ref lhs);
|
||||
ref Vector128<uint> rhsVec = ref Unsafe.As<T, Vector128<uint>>(ref rhs);
|
||||
ReadOnlySpan<Vector128<uint>> lhsVec = Unsafe.As<Span<T>, ReadOnlySpan<Vector128<uint>>>(ref lhs);
|
||||
ReadOnlySpan<Vector128<uint>> rhsVec = Unsafe.As<Span<T>, ReadOnlySpan<Vector128<uint>>>(ref rhs);
|
||||
|
||||
return Vector128.EqualsAll(lhsVec, rhsVec) &&
|
||||
Vector128.EqualsAll(Unsafe.Add(ref lhsVec, 1), Unsafe.Add(ref rhsVec, 1));
|
||||
return Vector128.EqualsAll(lhsVec[0], rhsVec[0]) &&
|
||||
Vector128.EqualsAll(lhsVec[1], rhsVec[1]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,26 +265,26 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// Updates blend enable. Respects current shadow mode.
|
||||
/// </summary>
|
||||
/// <param name="masks">Blend enable</param>
|
||||
public void UpdateBlendEnable(ref Array8<Boolean32> enable)
|
||||
public void UpdateBlendEnable(Span<Boolean32> enable)
|
||||
{
|
||||
SetMmeShadowRamControlMode shadow = ShadowMode;
|
||||
ref Array8<Boolean32> state = ref _state.State.BlendEnable;
|
||||
Span<Boolean32> state = _state.State.BlendEnable.AsSpan();
|
||||
|
||||
if (shadow.IsReplay())
|
||||
{
|
||||
enable = _state.ShadowState.BlendEnable;
|
||||
state.CopyTo(enable);
|
||||
}
|
||||
|
||||
if (!UnsafeEquals32Byte(ref enable, ref state))
|
||||
if (!UnsafeEquals32Byte(enable, state))
|
||||
{
|
||||
state = enable;
|
||||
enable.CopyTo(state);
|
||||
|
||||
_stateUpdater.ForceDirty(StateUpdater.BlendStateIndex);
|
||||
}
|
||||
|
||||
if (shadow.IsTrack())
|
||||
{
|
||||
_state.ShadowState.BlendEnable = enable;
|
||||
enable.CopyTo(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,26 +292,26 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// Updates color masks. Respects current shadow mode.
|
||||
/// </summary>
|
||||
/// <param name="masks">Color masks</param>
|
||||
public void UpdateColorMasks(ref Array8<RtColorMask> masks)
|
||||
public void UpdateColorMasks(Span<RtColorMask> masks)
|
||||
{
|
||||
SetMmeShadowRamControlMode shadow = ShadowMode;
|
||||
ref Array8<RtColorMask> state = ref _state.State.RtColorMask;
|
||||
Span<RtColorMask> state = _state.State.RtColorMask.AsSpan();
|
||||
|
||||
if (shadow.IsReplay())
|
||||
{
|
||||
masks = _state.ShadowState.RtColorMask;
|
||||
state.CopyTo(masks);
|
||||
}
|
||||
|
||||
if (!UnsafeEquals32Byte(ref masks, ref state))
|
||||
if (!UnsafeEquals32Byte(masks, state))
|
||||
{
|
||||
state = masks;
|
||||
masks.CopyTo(state);
|
||||
|
||||
_stateUpdater.ForceDirty(StateUpdater.RtColorMaskIndex);
|
||||
}
|
||||
|
||||
if (shadow.IsTrack())
|
||||
{
|
||||
_state.ShadowState.RtColorMask = masks;
|
||||
masks.CopyTo(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Buffer, used to store vertex and index data, uniform and storage buffers, and others.
|
||||
/// </summary>
|
||||
class Buffer : IRange, ISyncActionHandler, IDisposable
|
||||
class Buffer : INonOverlappingRange, ISyncActionHandler, IDisposable
|
||||
{
|
||||
private const ulong GranularBufferThreshold = 4096;
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Size of the buffer in bytes.
|
||||
/// </summary>
|
||||
public ulong Size { get; }
|
||||
public ulong Size { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// End address of the buffer in guest memory.
|
||||
@@ -60,13 +60,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <remarks>
|
||||
/// This is null until at least one modification occurs.
|
||||
/// </remarks>
|
||||
private BufferModifiedRangeList _modifiedRanges = null;
|
||||
private BufferModifiedRangeList _modifiedRanges;
|
||||
|
||||
/// <summary>
|
||||
/// A structure that is used to flush buffer data back to a host mapped buffer for cached readback.
|
||||
/// Only used if the buffer data is explicitly owned by device local memory.
|
||||
/// </summary>
|
||||
private BufferPreFlush _preFlush = null;
|
||||
private BufferPreFlush _preFlush;
|
||||
|
||||
/// <summary>
|
||||
/// Usage tracking state that determines what type of backing the buffer should use.
|
||||
@@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong size,
|
||||
BufferStage stage,
|
||||
bool sparseCompatible,
|
||||
IEnumerable<Buffer> baseBuffers = null)
|
||||
RangeItem<Buffer>[] baseBuffers)
|
||||
{
|
||||
_context = context;
|
||||
_physicalMemory = physicalMemory;
|
||||
@@ -126,21 +126,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
_useGranular = size > GranularBufferThreshold;
|
||||
|
||||
IEnumerable<IRegionHandle> baseHandles = null;
|
||||
List<IRegionHandle> baseHandles = null;
|
||||
|
||||
if (baseBuffers != null)
|
||||
if (baseBuffers.Length != 0)
|
||||
{
|
||||
baseHandles = baseBuffers.SelectMany(buffer =>
|
||||
baseHandles = new List<IRegionHandle>();
|
||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
||||
{
|
||||
if (buffer._useGranular)
|
||||
if (item.Value._useGranular)
|
||||
{
|
||||
return buffer._memoryTrackingGranular.GetHandles();
|
||||
baseHandles.AddRange((item.Value._memoryTrackingGranular.GetHandles()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Enumerable.Repeat(buffer._memoryTracking, 1);
|
||||
baseHandles.Add(item.Value._memoryTracking);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (_useGranular)
|
||||
@@ -171,9 +172,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_memoryTracking.RegisterPreciseAction(PreciseAction);
|
||||
}
|
||||
|
||||
_externalFlushDelegate = new RegionSignal(ExternalFlush);
|
||||
_loadDelegate = new Action<ulong, ulong>(LoadRegion);
|
||||
_modifiedDelegate = new Action<ulong, ulong>(RegionModified);
|
||||
_externalFlushDelegate = ExternalFlush;
|
||||
_loadDelegate = LoadRegion;
|
||||
_modifiedDelegate = RegionModified;
|
||||
|
||||
_virtualDependenciesLock = new ReaderWriterLockSlim();
|
||||
}
|
||||
@@ -247,6 +248,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
return Address < address + size && address < EndAddress;
|
||||
}
|
||||
|
||||
public INonOverlappingRange Split(ulong splitAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given range is fully contained in the buffer.
|
||||
/// </summary>
|
||||
@@ -435,7 +441,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="from">The buffer to inherit from</param>
|
||||
public void InheritModifiedRanges(Buffer from)
|
||||
{
|
||||
if (from._modifiedRanges != null && from._modifiedRanges.HasRanges)
|
||||
if (from._modifiedRanges is { HasRanges: true })
|
||||
{
|
||||
if (from._syncActionRegistered && !_syncActionRegistered)
|
||||
{
|
||||
@@ -443,7 +449,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_syncActionRegistered = true;
|
||||
}
|
||||
|
||||
void registerRangeAction(ulong address, ulong size)
|
||||
void RegisterRangeAction(ulong address, ulong size)
|
||||
{
|
||||
if (_useGranular)
|
||||
{
|
||||
@@ -457,7 +463,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
EnsureRangeList();
|
||||
|
||||
_modifiedRanges.InheritRanges(from._modifiedRanges, registerRangeAction);
|
||||
_modifiedRanges.InheritRanges(from._modifiedRanges, RegisterRangeAction);
|
||||
}
|
||||
|
||||
if (from._dirtyStart != ulong.MaxValue)
|
||||
@@ -499,14 +505,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
// Cut off the start.
|
||||
|
||||
if (end < _dirtyEnd)
|
||||
{
|
||||
_dirtyStart = end;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dirtyStart = ulong.MaxValue;
|
||||
}
|
||||
_dirtyStart = end < _dirtyEnd ? end : ulong.MaxValue;
|
||||
}
|
||||
else if (end >= _dirtyEnd)
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -56,7 +57,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="parent">Parent buffer</param>
|
||||
/// <param name="stage">Initial buffer stage</param>
|
||||
/// <param name="baseBuffers">Buffers to inherit state from</param>
|
||||
public BufferBackingState(GpuContext context, Buffer parent, BufferStage stage, IEnumerable<Buffer> baseBuffers = null)
|
||||
public BufferBackingState(GpuContext context, Buffer parent, BufferStage stage, RangeItem<Buffer>[] baseBuffers)
|
||||
{
|
||||
_size = (int)parent.Size;
|
||||
_systemMemoryType = context.Capabilities.MemoryType;
|
||||
@@ -72,7 +73,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
BufferStage storageFlags = stage & BufferStage.StorageMask;
|
||||
|
||||
if (parent.Size > DeviceLocalSizeThreshold && baseBuffers == null)
|
||||
if (parent.Size > DeviceLocalSizeThreshold && baseBuffers.Length == 0)
|
||||
{
|
||||
_desiredType = BufferBackingType.DeviceMemory;
|
||||
}
|
||||
@@ -100,11 +101,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// TODO: Might be nice to force atomic access to be device local for any stage.
|
||||
}
|
||||
|
||||
if (baseBuffers != null)
|
||||
if (baseBuffers.Length != 0)
|
||||
{
|
||||
foreach (Buffer buffer in baseBuffers)
|
||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
||||
{
|
||||
CombineState(buffer.BackingState);
|
||||
CombineState(item.Value.BackingState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
@@ -39,11 +38,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// Only modified from the GPU thread. Must lock for add/remove.
|
||||
/// Must lock for any access from other threads.
|
||||
/// </remarks>
|
||||
private readonly RangeList<Buffer> _buffers;
|
||||
private readonly NonOverlappingRangeList<Buffer> _buffers;
|
||||
private readonly MultiRangeList<MultiRangeBuffer> _multiRangeBuffers;
|
||||
|
||||
private Buffer[] _bufferOverlaps;
|
||||
|
||||
private readonly Dictionary<ulong, BufferCacheEntry> _dirtyCache;
|
||||
private readonly Dictionary<ulong, BufferCacheEntry> _modifiedCache;
|
||||
private bool _pruneCaches;
|
||||
@@ -64,8 +61,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_buffers = [];
|
||||
_multiRangeBuffers = [];
|
||||
|
||||
_bufferOverlaps = new Buffer[OverlapsBufferInitialCapacity];
|
||||
|
||||
_dirtyCache = new Dictionary<ulong, BufferCacheEntry>();
|
||||
|
||||
// There are a lot more entries on the modified cache, so it is separate from the one for ForceDirty.
|
||||
@@ -79,24 +74,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="e">Event arguments</param>
|
||||
public void MemoryUnmappedHandler(object sender, UnmapEventArgs e)
|
||||
{
|
||||
Buffer[] overlaps = new Buffer[10];
|
||||
int overlapCount;
|
||||
|
||||
MultiRange range = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size);
|
||||
|
||||
for (int index = 0; index < range.Count; index++)
|
||||
{
|
||||
MemoryRange subRange = range.GetSubRange(index);
|
||||
|
||||
_buffers.Lock.EnterReadLock();
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(subRange.Address, subRange.Size);
|
||||
|
||||
lock (_buffers)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
overlapCount = _buffers.FindOverlaps(subRange.Address, subRange.Size, ref overlaps);
|
||||
overlaps[i].Value.Unmapped(subRange.Address, subRange.Size);
|
||||
}
|
||||
|
||||
for (int i = 0; i < overlapCount; i++)
|
||||
{
|
||||
overlaps[i].Unmapped(subRange.Address, subRange.Size);
|
||||
}
|
||||
_buffers.Lock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +129,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <returns>Physical ranges of the buffer, after address translation</returns>
|
||||
public MultiRange TranslateAndCreateMultiBuffers(MemoryManager memoryManager, ulong gpuVa, ulong size, BufferStage stage)
|
||||
{
|
||||
if (gpuVa == 0)
|
||||
if (gpuVa == 0 || size == 0)
|
||||
{
|
||||
return new MultiRange(MemoryManager.PteUnmapped, size);
|
||||
}
|
||||
@@ -336,7 +328,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong alignedEndAddress = (endAddress + alignmentMask) & ~alignmentMask;
|
||||
ulong alignedSize = alignedEndAddress - alignedAddress;
|
||||
|
||||
Buffer buffer = _buffers.FindFirstOverlap(alignedAddress, alignedSize);
|
||||
Buffer buffer = _buffers.FindOverlap(alignedAddress, alignedSize).Value;
|
||||
BufferRange bufferRange = buffer.GetRange(alignedAddress, alignedSize, false);
|
||||
|
||||
alignedSubRanges[i] = new MemoryRange(alignedAddress, alignedSize);
|
||||
@@ -403,7 +395,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (subRange.Address != MemoryManager.PteUnmapped)
|
||||
{
|
||||
Buffer buffer = _buffers.FindFirstOverlap(subRange.Address, subRange.Size);
|
||||
Buffer buffer = _buffers.FindOverlap(subRange.Address, subRange.Size).Value;
|
||||
|
||||
virtualBuffer.AddPhysicalDependency(buffer, subRange.Address, dstOffset, subRange.Size);
|
||||
physicalBuffers.Add(buffer);
|
||||
@@ -495,10 +487,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="stage">The type of usage that created the buffer</param>
|
||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage)
|
||||
{
|
||||
Buffer[] overlaps = _bufferOverlaps;
|
||||
int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
Buffer newBuffer = null;
|
||||
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
|
||||
if (overlapsCount != 0)
|
||||
if (overlaps.Length != 0)
|
||||
{
|
||||
// The buffer already exists. We can just return the existing buffer
|
||||
// if the buffer we need is fully contained inside the overlapping buffer.
|
||||
@@ -507,9 +501,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// old buffer(s) to the new buffer.
|
||||
|
||||
ulong endAddress = address + size;
|
||||
Buffer overlap0 = overlaps[0];
|
||||
|
||||
if (overlap0.Address > address || overlap0.EndAddress < endAddress)
|
||||
if (overlaps[0].Address > address || overlaps[0].EndAddress < endAddress)
|
||||
{
|
||||
bool anySparseCompatible = false;
|
||||
|
||||
@@ -522,53 +515,60 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// sequential memory.
|
||||
// Allowing for 2 pages (rather than just one) is necessary to catch cases where the
|
||||
// range crosses a page, and after alignment, ends having a size of 2 pages.
|
||||
if (overlapsCount == 1 &&
|
||||
address >= overlap0.Address &&
|
||||
endAddress - overlap0.EndAddress <= BufferAlignmentSize * 2)
|
||||
if (overlaps.Length == 1 &&
|
||||
address >= overlaps[0].Address &&
|
||||
endAddress - overlaps[0].EndAddress <= BufferAlignmentSize * 2)
|
||||
{
|
||||
// Try to grow the buffer by 1.5x of its current size.
|
||||
// This improves performance in the cases where the buffer is resized often by small amounts.
|
||||
ulong existingSize = overlap0.Size;
|
||||
ulong existingSize = overlaps[0].Value.Size;
|
||||
ulong growthSize = (existingSize + Math.Min(existingSize >> 1, MaxDynamicGrowthSize)) & ~BufferAlignmentMask;
|
||||
|
||||
size = Math.Max(size, growthSize);
|
||||
endAddress = address + size;
|
||||
|
||||
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
}
|
||||
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
|
||||
address = Math.Min(address, overlaps[0].Address);
|
||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
Buffer buffer = overlaps[index];
|
||||
|
||||
anySparseCompatible |= buffer.SparseCompatible;
|
||||
|
||||
address = Math.Min(address, buffer.Address);
|
||||
endAddress = Math.Max(endAddress, buffer.EndAddress);
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
_buffers.Remove(buffer);
|
||||
}
|
||||
anySparseCompatible |= overlaps[i].Value.SparseCompatible;
|
||||
}
|
||||
|
||||
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
|
||||
|
||||
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
ulong newSize = endAddress - address;
|
||||
|
||||
CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlaps, overlapsCount);
|
||||
newBuffer = CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlapsArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
// No overlap, just create a new buffer.
|
||||
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false);
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
_buffers.Add(buffer);
|
||||
}
|
||||
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false, []);
|
||||
}
|
||||
|
||||
ShrinkOverlapsBufferIfNeeded();
|
||||
if (newBuffer is not null)
|
||||
{
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
|
||||
_buffers.Add(newBuffer);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -582,72 +582,75 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="alignment">Alignment of the start address of the buffer</param>
|
||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, ulong alignment)
|
||||
{
|
||||
Buffer[] overlaps = _bufferOverlaps;
|
||||
int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
bool sparseAligned = alignment >= SparseBufferAlignmentSize;
|
||||
Buffer newBuffer = null;
|
||||
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
|
||||
if (overlapsCount != 0)
|
||||
if (overlaps.Length != 0)
|
||||
{
|
||||
// If the buffer already exists, make sure if covers the entire range,
|
||||
// and make sure it is properly aligned, otherwise sparse mapping may fail.
|
||||
|
||||
ulong endAddress = address + size;
|
||||
Buffer overlap0 = overlaps[0];
|
||||
|
||||
if (overlap0.Address > address ||
|
||||
overlap0.EndAddress < endAddress ||
|
||||
(overlap0.Address & (alignment - 1)) != 0 ||
|
||||
(!overlap0.SparseCompatible && sparseAligned))
|
||||
if (overlaps[0].Address > address ||
|
||||
overlaps[0].EndAddress < endAddress ||
|
||||
(overlaps[0].Address & (alignment - 1)) != 0 ||
|
||||
(!overlaps[0].Value.SparseCompatible && sparseAligned))
|
||||
{
|
||||
// We need to make sure the new buffer is properly aligned.
|
||||
// However, after the range is aligned, it is possible that it
|
||||
// overlaps more buffers, so try again after each extension
|
||||
// and ensure we cover all overlaps.
|
||||
|
||||
int oldOverlapsCount;
|
||||
|
||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
||||
int oldOverlapCount;
|
||||
|
||||
do
|
||||
{
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
Buffer buffer = overlaps[index];
|
||||
|
||||
address = Math.Min(address, buffer.Address);
|
||||
endAddress = Math.Max(endAddress, buffer.EndAddress);
|
||||
}
|
||||
address = Math.Min(address, overlaps[0].Address);
|
||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
||||
|
||||
address &= ~(alignment - 1);
|
||||
|
||||
oldOverlapsCount = overlapsCount;
|
||||
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, endAddress - address, ref overlaps);
|
||||
}
|
||||
while (oldOverlapsCount != overlapsCount);
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
_buffers.Remove(overlaps[index]);
|
||||
}
|
||||
oldOverlapCount = overlaps.Length;
|
||||
overlaps = _buffers.FindOverlapsAsSpan(address, endAddress - address);
|
||||
}
|
||||
while (oldOverlapCount != overlaps.Length);
|
||||
|
||||
ulong newSize = endAddress - address;
|
||||
|
||||
CreateBufferAligned(address, newSize, stage, sparseAligned, overlaps, overlapsCount);
|
||||
|
||||
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
|
||||
|
||||
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
newBuffer = CreateBufferAligned(address, newSize, stage, sparseAligned, overlapsArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
// No overlap, just create a new buffer.
|
||||
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseAligned);
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
_buffers.Add(buffer);
|
||||
}
|
||||
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseAligned, []);
|
||||
}
|
||||
|
||||
ShrinkOverlapsBufferIfNeeded();
|
||||
if (newBuffer is not null)
|
||||
{
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
|
||||
_buffers.Add(newBuffer);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -660,19 +663,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="stage">The type of usage that created the buffer</param>
|
||||
/// <param name="sparseCompatible">Indicates if the buffer can be used in a sparse buffer mapping</param>
|
||||
/// <param name="overlaps">Buffers overlapping the range</param>
|
||||
/// <param name="overlapsCount">Total of overlaps</param>
|
||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, Buffer[] overlaps, int overlapsCount)
|
||||
private Buffer CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, RangeItem<Buffer>[] overlaps)
|
||||
{
|
||||
Buffer newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps.Take(overlapsCount));
|
||||
Buffer newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps);
|
||||
|
||||
lock (_buffers)
|
||||
for (int index = 0; index < overlaps.Length; index++)
|
||||
{
|
||||
_buffers.Add(newBuffer);
|
||||
}
|
||||
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
Buffer buffer = overlaps[index];
|
||||
Buffer buffer = overlaps[index].Value;
|
||||
|
||||
int dstOffset = (int)(buffer.Address - newBuffer.Address);
|
||||
|
||||
@@ -688,6 +685,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
NotifyBuffersModified?.Invoke();
|
||||
|
||||
RecreateMultiRangeBuffers(address, size);
|
||||
|
||||
return newBuffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -718,17 +717,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes the temporary buffer used for range list intersection results, if it has grown too much.
|
||||
/// </summary>
|
||||
private void ShrinkOverlapsBufferIfNeeded()
|
||||
{
|
||||
if (_bufferOverlaps.Length > OverlapsBufferMaxCapacity)
|
||||
{
|
||||
Array.Resize(ref _bufferOverlaps, OverlapsBufferMaxCapacity);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy a buffer data from a given address to another.
|
||||
/// </summary>
|
||||
@@ -909,7 +897,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
MemoryRange subRange = range.GetSubRange(i);
|
||||
|
||||
Buffer subBuffer = _buffers.FindFirstOverlap(subRange.Address, subRange.Size);
|
||||
Buffer subBuffer = _buffers.FindOverlap(subRange.Address, subRange.Size).Value;
|
||||
|
||||
subBuffer.SynchronizeMemory(subRange.Address, subRange.Size);
|
||||
|
||||
@@ -957,7 +945,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
buffer = _buffers.FindFirstOverlap(address, size);
|
||||
buffer = _buffers.FindOverlap(address, size).Value;
|
||||
|
||||
buffer.CopyFromDependantVirtualBuffers();
|
||||
buffer.SynchronizeMemory(address, size);
|
||||
@@ -969,7 +957,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = _buffers.FindFirstOverlap(address, 1);
|
||||
buffer = _buffers.FindOverlapFast(address, 1).Value;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
@@ -1007,7 +995,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
Buffer buffer = _buffers.FindFirstOverlap(address, size);
|
||||
Buffer buffer = _buffers.FindOverlap(address, size).Value;
|
||||
|
||||
if (copyBackVirtual)
|
||||
{
|
||||
|
@@ -258,7 +258,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
RecordStorageAlignment(_cpStorageBuffers, index, gpuVa);
|
||||
|
||||
gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
|
||||
|
||||
MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size, BufferStageUtils.ComputeStorage(flags));
|
||||
|
||||
@@ -282,7 +282,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
RecordStorageAlignment(buffers, index, gpuVa);
|
||||
|
||||
gpuVa = BitUtils.AlignDown<ulong>(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
|
||||
|
||||
MultiRange range = _channel.MemoryManager.Physical.BufferCache.TranslateAndCreateMultiBuffers(_channel.MemoryManager, gpuVa, size, BufferStageUtils.GraphicsStorage(stage, flags));
|
||||
|
||||
@@ -761,7 +761,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (!bounds.IsUnmapped)
|
||||
{
|
||||
bool isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
|
||||
bool isWrite = (bounds.Flags & BufferUsageFlags.Write) == BufferUsageFlags.Write;
|
||||
BufferRange range = isStorage
|
||||
? bufferCache.GetBufferRangeAligned(bounds.Range, bufferStage | BufferStageUtils.FromUsage(bounds.Flags), isWrite)
|
||||
: bufferCache.GetBufferRange(bounds.Range, bufferStage);
|
||||
@@ -798,7 +798,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (!bounds.IsUnmapped)
|
||||
{
|
||||
bool isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
|
||||
bool isWrite = (bounds.Flags & BufferUsageFlags.Write) == BufferUsageFlags.Write;
|
||||
BufferRange range = isStorage
|
||||
? bufferCache.GetBufferRangeAligned(bounds.Range, BufferStageUtils.ComputeStorage(bounds.Flags), isWrite)
|
||||
: bufferCache.GetBufferRange(bounds.Range, BufferStage.Compute);
|
||||
@@ -817,7 +817,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// Bind respective buffer bindings on the host API.
|
||||
/// </summary>
|
||||
/// <param name="ranges">Host buffers to bind, with their offsets and sizes</param>
|
||||
/// <param name="first">First binding point</param>
|
||||
/// <param name="count">Number of bindings</param>
|
||||
/// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -866,7 +865,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="texture">Buffer texture</param>
|
||||
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
||||
/// <param name="bindingInfo">Binding info for the buffer texture</param>
|
||||
/// <param name="format">Format of the buffer texture</param>
|
||||
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
||||
public void SetBufferTextureStorage(
|
||||
ShaderStage stage,
|
||||
@@ -889,7 +887,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
||||
/// <param name="bindingInfo">Binding info for the buffer texture</param>
|
||||
/// <param name="index">Index of the binding on the array</param>
|
||||
/// <param name="format">Format of the buffer texture</param>
|
||||
public void SetBufferTextureStorage(
|
||||
ShaderStage stage,
|
||||
ITextureArray array,
|
||||
@@ -912,7 +909,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
|
||||
/// <param name="bindingInfo">Binding info for the buffer texture</param>
|
||||
/// <param name="index">Index of the binding on the array</param>
|
||||
/// <param name="format">Format of the buffer texture</param>
|
||||
public void SetBufferTextureStorage(
|
||||
ShaderStage stage,
|
||||
IImageArray array,
|
||||
|
@@ -1,25 +1,24 @@
|
||||
using Ryujinx.Common.Pools;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
/// <summary>
|
||||
/// A range within a buffer that has been modified by the GPU.
|
||||
/// </summary>
|
||||
class BufferModifiedRange : IRange
|
||||
class BufferModifiedRange : INonOverlappingRange
|
||||
{
|
||||
/// <summary>
|
||||
/// Start address of the range in guest memory.
|
||||
/// </summary>
|
||||
public ulong Address { get; }
|
||||
public ulong Address { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the range in bytes.
|
||||
/// </summary>
|
||||
public ulong Size { get; }
|
||||
public ulong Size { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// End address of the range in guest memory.
|
||||
@@ -61,12 +60,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
return Address < address + size && address < EndAddress;
|
||||
}
|
||||
|
||||
public INonOverlappingRange Split(ulong splitAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A structure used to track GPU modified ranges within a buffer.
|
||||
/// </summary>
|
||||
class BufferModifiedRangeList : RangeList<BufferModifiedRange>
|
||||
class BufferModifiedRangeList : NonOverlappingRangeList<BufferModifiedRange>
|
||||
{
|
||||
private const int BackingInitialSize = 8;
|
||||
|
||||
@@ -77,8 +81,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private BufferMigration _source;
|
||||
private BufferModifiedRangeList _migrationTarget;
|
||||
|
||||
private readonly Lock _lock = new();
|
||||
|
||||
/// <summary>
|
||||
/// Whether the modified range list has any entries or not.
|
||||
/// </summary>
|
||||
@@ -86,10 +88,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return Count > 0;
|
||||
}
|
||||
Lock.EnterReadLock();
|
||||
bool result = Count > 0;
|
||||
Lock.ExitReadLock();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,33 +116,32 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="action">Action to perform for each remaining sub-range of the input range</param>
|
||||
public void ExcludeModifiedRegions(ulong address, ulong size, Action<ulong, ulong> action)
|
||||
{
|
||||
lock (_lock)
|
||||
// Slices a given region using the modified regions in the list. Calls the action for the new slices.
|
||||
Lock.EnterReadLock();
|
||||
|
||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
// Slices a given region using the modified regions in the list. Calls the action for the new slices.
|
||||
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
|
||||
int count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
if (overlap.Address > address)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
if (overlap.Address > address)
|
||||
{
|
||||
// The start of the remaining region is uncovered by this overlap. Call the action for it.
|
||||
action(address, overlap.Address - address);
|
||||
}
|
||||
|
||||
// Remaining region is after this overlap.
|
||||
size -= overlap.EndAddress - address;
|
||||
address = overlap.EndAddress;
|
||||
// The start of the remaining region is uncovered by this overlap. Call the action for it.
|
||||
action(address, overlap.Address - address);
|
||||
}
|
||||
|
||||
if ((long)size > 0)
|
||||
{
|
||||
// If there is any region left after removing the overlaps, signal it.
|
||||
action(address, size);
|
||||
}
|
||||
// Remaining region is after this overlap.
|
||||
size -= overlap.EndAddress - address;
|
||||
address = overlap.EndAddress;
|
||||
}
|
||||
|
||||
Lock.ExitReadLock();
|
||||
|
||||
if ((long)size > 0)
|
||||
{
|
||||
// If there is any region left after removing the overlaps, signal it.
|
||||
action(address, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,51 +153,93 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="size">Size of the modified region in bytes</param>
|
||||
public void SignalModified(ulong address, ulong size)
|
||||
{
|
||||
// Must lock, as this can affect flushes from the background thread.
|
||||
lock (_lock)
|
||||
ulong endAddress = address + size;
|
||||
ulong syncNumber = _context.SyncNumber;
|
||||
// We may overlap with some existing modified regions. They must be cut into by the new entry.
|
||||
Lock.EnterWriteLock();
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlapsAsNodes(address, size);
|
||||
|
||||
if (first is null)
|
||||
{
|
||||
// We may overlap with some existing modified regions. They must be cut into by the new entry.
|
||||
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
|
||||
int count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
|
||||
ulong endAddress = address + size;
|
||||
ulong syncNumber = _context.SyncNumber;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
if (first == last)
|
||||
{
|
||||
if (first.Address == address && first.EndAddress == endAddress)
|
||||
{
|
||||
// The overlaps must be removed or split.
|
||||
first.Value.SyncNumber = syncNumber;
|
||||
first.Value.Parent = this;
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
if (first.Address < address)
|
||||
{
|
||||
first.Value.Size = address - first.Address;
|
||||
Update(first);
|
||||
|
||||
if (overlap.Address == address && overlap.Size == size)
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
// Region already exists. Just update the existing sync number.
|
||||
overlap.SyncNumber = syncNumber;
|
||||
overlap.Parent = this;
|
||||
|
||||
return;
|
||||
Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
|
||||
first.Value.SyncNumber, first.Value.Parent));
|
||||
}
|
||||
|
||||
Remove(overlap);
|
||||
|
||||
if (overlap.Address < address && overlap.EndAddress > address)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
// A split item must be created behind this overlap.
|
||||
|
||||
Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber, overlap.Parent));
|
||||
first.Value.Size = first.EndAddress - endAddress;
|
||||
first.Value.Address = endAddress;
|
||||
Update(first);
|
||||
}
|
||||
|
||||
if (overlap.Address < endAddress && overlap.EndAddress > endAddress)
|
||||
else
|
||||
{
|
||||
// A split item must be created after this overlap.
|
||||
|
||||
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber, overlap.Parent));
|
||||
Remove(first.Value);
|
||||
}
|
||||
}
|
||||
|
||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
||||
Lock.ExitWriteLock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
BufferModifiedRange buffPre = null;
|
||||
BufferModifiedRange buffPost = null;
|
||||
bool extendsPost = false;
|
||||
bool extendsPre = false;
|
||||
|
||||
if (first.Address < address)
|
||||
{
|
||||
buffPre = new BufferModifiedRange(first.Address, address - first.Address,
|
||||
first.Value.SyncNumber, first.Value.Parent);
|
||||
extendsPre = true;
|
||||
}
|
||||
|
||||
if (last.EndAddress > endAddress)
|
||||
{
|
||||
buffPost = new BufferModifiedRange(endAddress, last.EndAddress - endAddress,
|
||||
last.Value.SyncNumber, last.Value.Parent);
|
||||
extendsPost = true;
|
||||
}
|
||||
|
||||
RemoveRange(first, last);
|
||||
|
||||
if (extendsPre)
|
||||
{
|
||||
Add(buffPre);
|
||||
}
|
||||
|
||||
if (extendsPost)
|
||||
{
|
||||
Add(buffPost);
|
||||
}
|
||||
|
||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -208,25 +251,20 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="rangeAction">The action to call for each modified range</param>
|
||||
public void GetRangesAtSync(ulong address, ulong size, ulong syncNumber, Action<ulong, ulong> rangeAction)
|
||||
{
|
||||
int count = 0;
|
||||
Lock.EnterReadLock();
|
||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
||||
|
||||
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
|
||||
// Range list must be consistent for this operation.
|
||||
lock (_lock)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
|
||||
if (overlap.SyncNumber == syncNumber)
|
||||
{
|
||||
rangeAction(overlap.Address, overlap.Size);
|
||||
}
|
||||
}
|
||||
|
||||
Lock.ExitReadLock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -237,19 +275,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="rangeAction">The action to call for each modified range</param>
|
||||
public void GetRanges(ulong address, ulong size, Action<ulong, ulong> rangeAction)
|
||||
{
|
||||
int count = 0;
|
||||
// We use the non-span method here because keeping the lock will cause a deadlock.
|
||||
Lock.EnterReadLock();
|
||||
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size);
|
||||
Lock.ExitReadLock();
|
||||
|
||||
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
|
||||
// Range list must be consistent for this operation.
|
||||
lock (_lock)
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
rangeAction(overlap.Address, overlap.Size);
|
||||
}
|
||||
}
|
||||
@@ -262,11 +295,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <returns>True if a range exists in the specified region, false otherwise</returns>
|
||||
public bool HasRange(ulong address, ulong size)
|
||||
{
|
||||
// Range list must be consistent for this operation.
|
||||
lock (_lock)
|
||||
{
|
||||
return FindOverlapsNonOverlapping(address, size, ref ThreadStaticArray<BufferModifiedRange>.Get()) > 0;
|
||||
}
|
||||
Lock.EnterReadLock();
|
||||
RangeItem<BufferModifiedRange> first = FindOverlapFast(address, size);
|
||||
bool result = first is not null;
|
||||
Lock.ExitReadLock();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -298,38 +331,35 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="address">The start address of the flush range</param>
|
||||
/// <param name="endAddress">The end address of the flush range</param>
|
||||
private void RemoveRangesAndFlush(
|
||||
BufferModifiedRange[] overlaps,
|
||||
RangeItem<BufferModifiedRange>[] overlaps,
|
||||
int rangeCount,
|
||||
long highestDiff,
|
||||
ulong currentSync,
|
||||
ulong address,
|
||||
ulong endAddress)
|
||||
{
|
||||
lock (_lock)
|
||||
if (_migrationTarget == null)
|
||||
{
|
||||
if (_migrationTarget == null)
|
||||
ulong waitSync = currentSync + (ulong)highestDiff;
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
{
|
||||
ulong waitSync = currentSync + (ulong)highestDiff;
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||
|
||||
if (diff <= highestDiff)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
ulong clampAddress = Math.Max(address, overlap.Address);
|
||||
ulong clampEnd = Math.Min(endAddress, overlap.EndAddress);
|
||||
|
||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||
ClearPart(overlap, clampAddress, clampEnd);
|
||||
|
||||
if (diff <= highestDiff)
|
||||
{
|
||||
ulong clampAddress = Math.Max(address, overlap.Address);
|
||||
ulong clampEnd = Math.Min(endAddress, overlap.EndAddress);
|
||||
|
||||
ClearPart(overlap, clampAddress, clampEnd);
|
||||
|
||||
RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, _flushAction);
|
||||
}
|
||||
RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, _flushAction);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// There is a migration target to call instead. This can't be changed after set so accessing it outside the lock is fine.
|
||||
@@ -353,31 +383,24 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong endAddress = address + size;
|
||||
ulong currentSync = _context.SyncNumber;
|
||||
|
||||
int rangeCount = 0;
|
||||
|
||||
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
|
||||
// Range list must be consistent for this operation
|
||||
lock (_lock)
|
||||
if (_migrationTarget != null)
|
||||
{
|
||||
if (_migrationTarget != null)
|
||||
{
|
||||
rangeCount = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeCount = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
}
|
||||
}
|
||||
|
||||
if (rangeCount == -1)
|
||||
{
|
||||
_migrationTarget.WaitForAndFlushRanges(address, size);
|
||||
_migrationTarget!.WaitForAndFlushRanges(address, size);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (rangeCount == 0)
|
||||
|
||||
Lock.EnterWriteLock();
|
||||
// We use the non-span method here because the array is partially modified by the code, which would invalidate a span.
|
||||
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size);
|
||||
|
||||
int rangeCount = overlaps.Length;
|
||||
|
||||
if (rangeCount == 0)
|
||||
{
|
||||
Lock.ExitWriteLock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -388,7 +411,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
|
||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||
|
||||
@@ -400,13 +423,17 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (highestDiff == long.MinValue)
|
||||
{
|
||||
Lock.ExitWriteLock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the syncpoint.
|
||||
_context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
|
||||
|
||||
RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
|
||||
RemoveRangesAndFlush(overlaps.ToArray(), rangeCount, highestDiff, currentSync, address, endAddress);
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -419,42 +446,40 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="registerRangeAction">The action to call for each modified range</param>
|
||||
public void InheritRanges(BufferModifiedRangeList ranges, Action<ulong, ulong> registerRangeAction)
|
||||
{
|
||||
BufferModifiedRange[] inheritRanges;
|
||||
ranges.Lock.EnterReadLock();
|
||||
BufferModifiedRange[] inheritRanges = ranges.ToArray();
|
||||
ranges.Lock.ExitReadLock();
|
||||
|
||||
lock (ranges._lock)
|
||||
// Copy over the migration from the previous range list
|
||||
|
||||
BufferMigration oldMigration = ranges._source;
|
||||
|
||||
BufferMigrationSpan span = new(ranges._parent, ranges._flushAction, oldMigration);
|
||||
ranges._parent.IncrementReferenceCount();
|
||||
|
||||
if (_source == null)
|
||||
{
|
||||
inheritRanges = ranges.ToArray();
|
||||
// Create a new migration.
|
||||
_source = new BufferMigration([span], this, _context.SyncNumber);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
// Copy over the migration from the previous range list
|
||||
|
||||
BufferMigration oldMigration = ranges._source;
|
||||
|
||||
BufferMigrationSpan span = new(ranges._parent, ranges._flushAction, oldMigration);
|
||||
ranges._parent.IncrementReferenceCount();
|
||||
|
||||
if (_source == null)
|
||||
{
|
||||
// Create a new migration.
|
||||
_source = new BufferMigration([span], this, _context.SyncNumber);
|
||||
|
||||
_context.RegisterBufferMigration(_source);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Extend the migration
|
||||
_source.AddSpanToEnd(span);
|
||||
}
|
||||
|
||||
ranges._migrationTarget = this;
|
||||
|
||||
foreach (BufferModifiedRange range in inheritRanges)
|
||||
{
|
||||
Add(range);
|
||||
}
|
||||
}
|
||||
_context.RegisterBufferMigration(_source);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Extend the migration
|
||||
_source.AddSpanToEnd(span);
|
||||
}
|
||||
|
||||
ranges._migrationTarget = this;
|
||||
|
||||
Lock.EnterWriteLock();
|
||||
|
||||
foreach (BufferModifiedRange range in inheritRanges)
|
||||
{
|
||||
Add(range);
|
||||
}
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
|
||||
ulong currentSync = _context.SyncNumber;
|
||||
foreach (BufferModifiedRange range in inheritRanges)
|
||||
@@ -473,18 +498,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// </summary>
|
||||
public void SelfMigration()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
BufferMigrationSpan span = new(_parent, _parent.GetSnapshotDisposeAction(), _parent.GetSnapshotFlushAction(), _source);
|
||||
BufferMigration migration = new([span], this, _context.SyncNumber);
|
||||
BufferMigrationSpan span = new(_parent, _parent.GetSnapshotDisposeAction(),
|
||||
_parent.GetSnapshotFlushAction(), _source);
|
||||
BufferMigration migration = new([span], this, _context.SyncNumber);
|
||||
|
||||
// Migration target is used to redirect flush actions to the latest range list,
|
||||
// so we don't need to set it here. (this range list is still the latest)
|
||||
// Migration target is used to redirect flush actions to the latest range list,
|
||||
// so we don't need to set it here. (this range list is still the latest)
|
||||
|
||||
_context.RegisterBufferMigration(migration);
|
||||
_context.RegisterBufferMigration(migration);
|
||||
|
||||
_source = migration;
|
||||
}
|
||||
Lock.EnterWriteLock();
|
||||
_source = migration;
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -493,13 +518,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="migration">The migration to remove</param>
|
||||
public void RemoveMigration(BufferMigration migration)
|
||||
{
|
||||
lock (_lock)
|
||||
Lock.EnterWriteLock();
|
||||
if (_source == migration)
|
||||
{
|
||||
if (_source == migration)
|
||||
{
|
||||
_source = null;
|
||||
}
|
||||
_source = null;
|
||||
}
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
private void ClearPart(BufferModifiedRange overlap, ulong address, ulong endAddress)
|
||||
@@ -526,33 +551,79 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="size">Size to clear</param>
|
||||
public void Clear(ulong address, ulong size)
|
||||
{
|
||||
lock (_lock)
|
||||
ulong endAddress = address + size;
|
||||
Lock.EnterWriteLock();
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlapsAsNodes(address, size);
|
||||
|
||||
if (first is null)
|
||||
{
|
||||
// This function can be called from any thread, so it cannot use the arrays for background or foreground.
|
||||
BufferModifiedRange[] toClear = new BufferModifiedRange[1];
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
|
||||
int rangeCount = FindOverlapsNonOverlapping(address, size, ref toClear);
|
||||
|
||||
ulong endAddress = address + size;
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
if (first == last)
|
||||
{
|
||||
if (first.Address < address)
|
||||
{
|
||||
BufferModifiedRange overlap = toClear[i];
|
||||
first.Value.Size = address - first.Address;
|
||||
Update(first);
|
||||
|
||||
ClearPart(overlap, address, endAddress);
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
|
||||
first.Value.SyncNumber, first.Value.Parent));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
first.Value.Size = first.EndAddress - endAddress;
|
||||
first.Value.Address = endAddress;
|
||||
Update(first);
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(first.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all modified ranges.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
Count = 0;
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
|
||||
BufferModifiedRange buffPre = null;
|
||||
BufferModifiedRange buffPost = null;
|
||||
bool extendsPost = false;
|
||||
bool extendsPre = false;
|
||||
|
||||
if (first.Address < address)
|
||||
{
|
||||
buffPre = new BufferModifiedRange(first.Address, address - first.Address,
|
||||
first.Value.SyncNumber, first.Value.Parent);
|
||||
extendsPre = true;
|
||||
}
|
||||
|
||||
if (last.EndAddress > endAddress)
|
||||
{
|
||||
buffPost = new BufferModifiedRange(endAddress, last.EndAddress - endAddress,
|
||||
last.Value.SyncNumber, last.Value.Parent);
|
||||
extendsPost = true;
|
||||
}
|
||||
|
||||
RemoveRange(first, last);
|
||||
|
||||
if (extendsPre)
|
||||
{
|
||||
Add(buffPre);
|
||||
}
|
||||
|
||||
if (extendsPost)
|
||||
{
|
||||
Add(buffPost);
|
||||
}
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
@@ -7,6 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// Pipeline stages that can modify buffer data, as well as flags indicating storage usage.
|
||||
/// Must match ShaderStage for the shader stages, though anything after that can be in any order.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
internal enum BufferStage : byte
|
||||
{
|
||||
Compute,
|
||||
@@ -52,7 +54,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static BufferStage FromUsage(BufferUsageFlags flags)
|
||||
{
|
||||
if (flags.HasFlag(BufferUsageFlags.Write))
|
||||
if ((flags & BufferUsageFlags.Write) == BufferUsageFlags.Write)
|
||||
{
|
||||
return BufferStage.StorageWrite;
|
||||
}
|
||||
@@ -65,7 +67,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static BufferStage FromUsage(TextureUsageFlags flags)
|
||||
{
|
||||
if (flags.HasFlag(TextureUsageFlags.ImageStore))
|
||||
if ((flags & TextureUsageFlags.ImageStore) == TextureUsageFlags.ImageStore)
|
||||
{
|
||||
return BufferStage.StorageWrite;
|
||||
}
|
||||
|
@@ -690,11 +690,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
if (_pageTable[l0] == null)
|
||||
{
|
||||
_pageTable[l0] = new ulong[PtLvl1Size];
|
||||
|
||||
for (ulong index = 0; index < PtLvl1Size; index++)
|
||||
{
|
||||
_pageTable[l0][index] = PteUnmapped;
|
||||
}
|
||||
|
||||
Array.Fill(_pageTable[l0], PteUnmapped);
|
||||
}
|
||||
|
||||
_pageTable[l0][l1] = pte;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -104,9 +105,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="scale">Scale value</param>
|
||||
public void UpdateRenderScale(int index, float scale)
|
||||
{
|
||||
if (_data.RenderScale[1 + index].X != scale)
|
||||
Span<Vector4<float>> renderScaleSpan = _data.RenderScale.AsSpan();
|
||||
|
||||
if (renderScaleSpan[1 + index].X != scale)
|
||||
{
|
||||
_data.RenderScale[1 + index].X = scale;
|
||||
renderScaleSpan[1 + index].X = scale;
|
||||
DirtyRenderScale(1 + index, 1);
|
||||
}
|
||||
}
|
||||
@@ -133,11 +136,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="isBgra">True if the format is BGRA< false otherwise</param>
|
||||
public void SetRenderTargetIsBgra(int index, bool isBgra)
|
||||
{
|
||||
bool isBgraChanged = _data.FragmentIsBgra[index].X != 0 != isBgra;
|
||||
Span<Vector4<int>> fragmentIsBgraSpan = _data.FragmentIsBgra.AsSpan();
|
||||
|
||||
bool isBgraChanged = fragmentIsBgraSpan[index].X != 0 != isBgra;
|
||||
|
||||
if (isBgraChanged)
|
||||
{
|
||||
_data.FragmentIsBgra[index].X = isBgra ? 1 : 0;
|
||||
fragmentIsBgraSpan[index].X = isBgra ? 1 : 0;
|
||||
DirtyFragmentIsBgra(index, 1);
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Represents a GPU virtual memory range.
|
||||
/// </summary>
|
||||
private readonly struct VirtualRange : IRange
|
||||
private class VirtualRange : INonOverlappingRange
|
||||
{
|
||||
/// <summary>
|
||||
/// GPU virtual address where the range starts.
|
||||
@@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Size of the range in bytes.
|
||||
/// </summary>
|
||||
public ulong Size { get; }
|
||||
public ulong Size { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// GPU virtual address where the range ends.
|
||||
@@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <summary>
|
||||
/// Physical regions where the GPU virtual region is mapped.
|
||||
/// </summary>
|
||||
public MultiRange Range { get; }
|
||||
public MultiRange Range { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new virtual memory range.
|
||||
@@ -60,10 +60,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
return Address < address + size && address < EndAddress;
|
||||
}
|
||||
|
||||
public INonOverlappingRange Split(ulong splitAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly RangeList<VirtualRange> _virtualRanges;
|
||||
private VirtualRange[] _virtualRangeOverlaps;
|
||||
private readonly NonOverlappingRangeList<VirtualRange> _virtualRanges;
|
||||
private readonly ConcurrentQueue<VirtualRange> _deferredUnmaps;
|
||||
private int _hasDeferredUnmaps;
|
||||
|
||||
@@ -75,7 +79,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
_memoryManager = memoryManager;
|
||||
_virtualRanges = [];
|
||||
_virtualRangeOverlaps = new VirtualRange[BufferCache.OverlapsBufferInitialCapacity];
|
||||
_deferredUnmaps = new ConcurrentQueue<VirtualRange>();
|
||||
}
|
||||
|
||||
@@ -106,19 +109,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <returns>True if the range already existed, false if a new one was created and added</returns>
|
||||
public bool TryGetOrAddRange(ulong gpuVa, ulong size, out MultiRange range)
|
||||
{
|
||||
VirtualRange[] overlaps = _virtualRangeOverlaps;
|
||||
int overlapsCount;
|
||||
|
||||
if (Interlocked.Exchange(ref _hasDeferredUnmaps, 0) != 0)
|
||||
{
|
||||
while (_deferredUnmaps.TryDequeue(out VirtualRange unmappedRange))
|
||||
{
|
||||
overlapsCount = _virtualRanges.FindOverlapsNonOverlapping(unmappedRange.Address, unmappedRange.Size, ref overlaps);
|
||||
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
_virtualRanges.Remove(overlaps[index]);
|
||||
}
|
||||
_virtualRanges.RemoveRange(unmappedRange.Address, unmappedRange.Size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,27 +121,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
ulong originalVa = gpuVa;
|
||||
|
||||
overlapsCount = _virtualRanges.FindOverlapsNonOverlapping(gpuVa, size, ref overlaps);
|
||||
|
||||
if (overlapsCount != 0)
|
||||
_virtualRanges.Lock.EnterWriteLock();
|
||||
(RangeItem<VirtualRange> first, RangeItem<VirtualRange> last) = _virtualRanges.FindOverlapsAsNodes(gpuVa, size);
|
||||
|
||||
if (first is not null)
|
||||
{
|
||||
// The virtual range already exists. We just need to check if our range fits inside
|
||||
// the existing one, and if not, we must extend the existing one.
|
||||
|
||||
ulong endAddress = gpuVa + size;
|
||||
VirtualRange overlap0 = overlaps[0];
|
||||
|
||||
if (overlap0.Address > gpuVa || overlap0.EndAddress < endAddress)
|
||||
if (first.Address > gpuVa || first.EndAddress < endAddress)
|
||||
{
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
VirtualRange virtualRange = overlaps[index];
|
||||
|
||||
gpuVa = Math.Min(gpuVa, virtualRange.Address);
|
||||
endAddress = Math.Max(endAddress, virtualRange.EndAddress);
|
||||
|
||||
_virtualRanges.Remove(virtualRange);
|
||||
}
|
||||
gpuVa = Math.Min(gpuVa, first.Address);
|
||||
endAddress = Math.Max(endAddress, last.EndAddress);
|
||||
|
||||
_virtualRanges.RemoveRange(first, last);
|
||||
|
||||
ulong newSize = endAddress - gpuVa;
|
||||
MultiRange newRange = _memoryManager.GetPhysicalRegions(gpuVa, newSize);
|
||||
@@ -157,8 +147,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
found = overlap0.Range.Count == 1 || IsSparseAligned(overlap0.Range);
|
||||
range = overlap0.Range.Slice(gpuVa - overlap0.Address, size);
|
||||
found = first.Value.Range.Count == 1 || IsSparseAligned(first.Value.Range);
|
||||
range = first.Value.Range.Slice(gpuVa - first.Address, size);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -170,8 +160,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
_virtualRanges.Add(virtualRange);
|
||||
}
|
||||
|
||||
ShrinkOverlapsBufferIfNeeded();
|
||||
_virtualRanges.Lock.ExitWriteLock();
|
||||
|
||||
// If the range is not properly aligned for sparse mapping,
|
||||
// let's just force it to a single range.
|
||||
@@ -221,16 +210,5 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resizes the temporary buffer used for range list intersection results, if it has grown too much.
|
||||
/// </summary>
|
||||
private void ShrinkOverlapsBufferIfNeeded()
|
||||
{
|
||||
if (_virtualRangeOverlaps.Length > BufferCache.OverlapsBufferMaxCapacity)
|
||||
{
|
||||
Array.Resize(ref _virtualRangeOverlaps, BufferCache.OverlapsBufferMaxCapacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||
@@ -258,21 +259,25 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
int count = rtControl.UnpackCount();
|
||||
|
||||
Span<RtColorState> rtColorStateSpan = state.RtColorState.AsSpan();
|
||||
Span<bool> attachmentEnableSpan = pipeline.AttachmentEnable.AsSpan();
|
||||
Span<Format> attachmentFormatsSpan = pipeline.AttachmentFormats.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||
{
|
||||
int rtIndex = rtControl.UnpackPermutationIndex(index);
|
||||
|
||||
var colorState = state.RtColorState[rtIndex];
|
||||
var colorState = rtColorStateSpan[rtIndex];
|
||||
|
||||
if (index >= count || colorState.Format == 0 || colorState.WidthOrStride == 0)
|
||||
{
|
||||
pipeline.AttachmentEnable[index] = false;
|
||||
pipeline.AttachmentFormats[index] = Format.R8G8B8A8Unorm;
|
||||
attachmentEnableSpan[index] = false;
|
||||
attachmentFormatsSpan[index] = Format.R8G8B8A8Unorm;
|
||||
}
|
||||
else
|
||||
{
|
||||
pipeline.AttachmentEnable[index] = true;
|
||||
pipeline.AttachmentFormats[index] = colorState.Format.Convert().Format;
|
||||
attachmentEnableSpan[index] = true;
|
||||
attachmentFormatsSpan[index] = colorState.Format.Convert().Format;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,15 +585,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
TransformFeedbackDescriptor[] descs = new TransformFeedbackDescriptor[Constants.TotalTransformFeedbackBuffers];
|
||||
|
||||
Span<TfState> tfStateSpan = state.TfState.AsSpan();
|
||||
Span<Array32<uint>> tfVaryingLocationsSpan = state.TfVaryingLocations.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.TotalTransformFeedbackBuffers; i++)
|
||||
{
|
||||
var tf = state.TfState[i];
|
||||
var tf = tfStateSpan[i];
|
||||
|
||||
descs[i] = new TransformFeedbackDescriptor(
|
||||
tf.BufferIndex,
|
||||
tf.Stride,
|
||||
tf.VaryingsCount,
|
||||
ref state.TfVaryingLocations[i]);
|
||||
ref tfVaryingLocationsSpan[i]);
|
||||
}
|
||||
|
||||
return descs;
|
||||
|
@@ -580,10 +580,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
if (ShaderCache.MayConvertVtgToCompute(ref channel.Capabilities) && !vertexAsCompute)
|
||||
{
|
||||
for (int index = 0; index < graphicsState.AttributeTypes.Length; index++)
|
||||
Span<AttributeType> attributeTypesSpan = graphicsState.AttributeTypes.AsSpan();
|
||||
Span<AttributeType> gAttributeTypesSpan = GraphicsState.AttributeTypes.AsSpan();
|
||||
|
||||
for (int index = 0; index < attributeTypesSpan.Length; index++)
|
||||
{
|
||||
AttributeType lType = FilterAttributeType(channel, graphicsState.AttributeTypes[index]);
|
||||
AttributeType rType = FilterAttributeType(channel, GraphicsState.AttributeTypes[index]);
|
||||
AttributeType lType = FilterAttributeType(channel, attributeTypesSpan[index]);
|
||||
AttributeType rType = FilterAttributeType(channel, gAttributeTypesSpan[index]);
|
||||
|
||||
if (lType != rType)
|
||||
{
|
||||
@@ -729,6 +732,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||
|
||||
Span<uint> constantBufferUseSpan = ConstantBufferUse.AsSpan();
|
||||
|
||||
while (constantBufferUsePerStageMask != 0)
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||
@@ -737,7 +742,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
? channel.BufferManager.GetComputeUniformBufferUseMask()
|
||||
: channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
|
||||
|
||||
if (ConstantBufferUse[index] != useMask)
|
||||
if (constantBufferUseSpan[index] != useMask)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -801,7 +806,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
if (specializationState != null)
|
||||
{
|
||||
if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
|
||||
if ((specializationState.Value.QueriedFlags & QueriedTextureStateFlags.CoordNormalized) == QueriedTextureStateFlags.CoordNormalized &&
|
||||
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
||||
{
|
||||
return false;
|
||||
@@ -877,10 +882,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
|
||||
|
||||
Span<uint> constantBufferUseSpan = specState.ConstantBufferUse.AsSpan();
|
||||
|
||||
while (constantBufferUsePerStageMask != 0)
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||
dataReader.Read(ref specState.ConstantBufferUse[index]);
|
||||
dataReader.Read(ref constantBufferUseSpan[index]);
|
||||
constantBufferUsePerStageMask &= ~(1 << index);
|
||||
}
|
||||
|
||||
@@ -979,11 +986,13 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
dataWriter.Write(ref _constantBufferUsePerStage);
|
||||
|
||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||
|
||||
Span<uint> constantBufferUseSpan = ConstantBufferUse.AsSpan();
|
||||
|
||||
while (constantBufferUsePerStageMask != 0)
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||
dataWriter.Write(ref ConstantBufferUse[index]);
|
||||
dataWriter.Write(ref constantBufferUseSpan[index]);
|
||||
constantBufferUsePerStageMask &= ~(1 << index);
|
||||
}
|
||||
|
||||
|
@@ -92,20 +92,24 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
||||
|
||||
if (pictureInfo.ScalingMatrixPresent)
|
||||
{
|
||||
Span<Array16<byte>> scalingLists4x4Span = pictureInfo.ScalingLists4x4.AsSpan();
|
||||
|
||||
for (int index = 0; index < 6; index++)
|
||||
{
|
||||
writer.WriteBit(true);
|
||||
|
||||
WriteScalingList(ref writer, pictureInfo.ScalingLists4x4[index]);
|
||||
WriteScalingList(ref writer, scalingLists4x4Span[index]);
|
||||
}
|
||||
|
||||
if (pictureInfo.Transform8x8ModeFlag)
|
||||
{
|
||||
Span<Array64<byte>> scalingLists8x8Span = pictureInfo.ScalingLists8x8.AsSpan();
|
||||
|
||||
for (int index = 0; index < 2; index++)
|
||||
{
|
||||
writer.WriteBit(true);
|
||||
|
||||
WriteScalingList(ref writer, pictureInfo.ScalingLists8x8[index]);
|
||||
WriteScalingList(ref writer, scalingLists8x8Span[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,9 +148,11 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
||||
|
||||
int lastScale = 8;
|
||||
|
||||
for (int index = 0; index < list.Length; index++)
|
||||
Span<byte> listSpan = list.AsSpan();
|
||||
|
||||
for (int index = 0; index < listSpan.Length; index++)
|
||||
{
|
||||
byte value = list[scan[index]];
|
||||
byte value = listSpan[scan[index]];
|
||||
|
||||
int deltaScale = value - lastScale;
|
||||
|
||||
|
@@ -21,49 +21,67 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
private static void ReadTxModeProbs(ref Vp9EntropyProbs txProbs, ref Reader r)
|
||||
{
|
||||
Span<Array1<byte>> tx8x8ProbSpan1 = txProbs.Tx8x8Prob.AsSpan();
|
||||
Span<Array2<byte>> tx16x16ProbSpan1 = txProbs.Tx16x16Prob.AsSpan();
|
||||
Span<Array3<byte>> tx32x32ProbSpan1 = txProbs.Tx32x32Prob.AsSpan();
|
||||
|
||||
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||
{
|
||||
Span<byte> tx8x8ProbSpan2 = tx8x8ProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < (int)TxSize.TxSizes - 3; ++j)
|
||||
{
|
||||
r.DiffUpdateProb(ref txProbs.Tx8x8Prob[i][j]);
|
||||
r.DiffUpdateProb(ref tx8x8ProbSpan2[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||
{
|
||||
Span<byte> tx16x16ProbSpan2 = tx16x16ProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < (int)TxSize.TxSizes - 2; ++j)
|
||||
{
|
||||
r.DiffUpdateProb(ref txProbs.Tx16x16Prob[i][j]);
|
||||
r.DiffUpdateProb(ref tx16x16ProbSpan2[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||
{
|
||||
Span<byte> tx32x32ProbSpan2 = tx32x32ProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < (int)TxSize.TxSizes - 1; ++j)
|
||||
{
|
||||
r.DiffUpdateProb(ref txProbs.Tx32x32Prob[i][j]);
|
||||
r.DiffUpdateProb(ref tx32x32ProbSpan2[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadSwitchableInterpProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
||||
{
|
||||
for (int j = 0; j < Constants.SwitchableFilterContexts; ++j)
|
||||
Span<Array2<byte>> switchableInterpProbSpan1 = fc.SwitchableInterpProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.SwitchableFilterContexts; ++i)
|
||||
{
|
||||
for (int i = 0; i < Constants.SwitchableFilters - 1; ++i)
|
||||
Span<byte> switchableInterpProbSpan2 = switchableInterpProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < Constants.SwitchableFilters - 1; ++j)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.SwitchableInterpProb[j][i]);
|
||||
r.DiffUpdateProb(ref switchableInterpProbSpan2[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadInterModeProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
||||
{
|
||||
Span<Array3<byte>> interModeProbSpan1 = fc.InterModeProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.InterModeContexts; ++i)
|
||||
{
|
||||
Span<byte> interModeProbSpan2 = interModeProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < Constants.InterModes - 1; ++j)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.InterModeProb[i][j]);
|
||||
r.DiffUpdateProb(ref interModeProbSpan2[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,30 +90,43 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
r.UpdateMvProbs(ctx.Joints.AsSpan(), EntropyMv.Joints - 1);
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Sign[i], 1), 1);
|
||||
r.UpdateMvProbs(ctx.Classes[i].AsSpan(), EntropyMv.Classes - 1);
|
||||
r.UpdateMvProbs(ctx.Class0[i].AsSpan(), EntropyMv.Class0Size - 1);
|
||||
r.UpdateMvProbs(ctx.Bits[i].AsSpan(), EntropyMv.OffsetBits);
|
||||
}
|
||||
Span<byte> signSpan = ctx.Sign.AsSpan();
|
||||
Span<Array10<byte>> classesSpan = ctx.Classes.AsSpan();
|
||||
Span<Array1<byte>> class0Span = ctx.Class0.AsSpan();
|
||||
Span<Array10<byte>> bitsSpan = ctx.Bits.AsSpan();
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref signSpan[i], 1), 1);
|
||||
r.UpdateMvProbs(classesSpan[i].AsSpan(), EntropyMv.Classes - 1);
|
||||
r.UpdateMvProbs(class0Span[i].AsSpan(), EntropyMv.Class0Size - 1);
|
||||
r.UpdateMvProbs(bitsSpan[i].AsSpan(), EntropyMv.OffsetBits);
|
||||
}
|
||||
|
||||
Span<Array2<Array3<byte>>> class0FpSpan1 = ctx.Class0Fp.AsSpan();
|
||||
Span<Array3<byte>> fpSpan = ctx.Fp.AsSpan();
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
Span<Array3<byte>> class0FpSpan2 = class0FpSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < EntropyMv.Class0Size; ++j)
|
||||
{
|
||||
r.UpdateMvProbs(ctx.Class0Fp[i][j].AsSpan(), EntropyMv.FpSize - 1);
|
||||
r.UpdateMvProbs(class0FpSpan2[j].AsSpan(), EntropyMv.FpSize - 1);
|
||||
}
|
||||
|
||||
r.UpdateMvProbs(ctx.Fp[i].AsSpan(), 3);
|
||||
r.UpdateMvProbs(fpSpan[i].AsSpan(), 3);
|
||||
}
|
||||
|
||||
if (allowHp)
|
||||
{
|
||||
Span<byte> class0HpSpan = ctx.Class0Hp.AsSpan();
|
||||
Span<byte> hpSpan = ctx.Hp.AsSpan();
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Class0Hp[i], 1), 1);
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Hp[i], 1), 1);
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref class0HpSpan[i], 1), 1);
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref hpSpan[i], 1), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -751,10 +782,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
int refr;
|
||||
bool isScaled;
|
||||
|
||||
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
||||
Span<Mv> mvSpan = mi.Mv.AsSpan();
|
||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||
Span<Ptr<RefBuffer>> blockRefsSpan = xd.BlockRefs.AsSpan();
|
||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||
|
||||
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||
{
|
||||
int frame = mi.RefFrame[refr];
|
||||
ref RefBuffer refBuf = ref cm.FrameRefs[frame - Constants.LastFrame];
|
||||
int frame = refFrameSpan[refr];
|
||||
ref RefBuffer refBuf = ref frameRefsSpan[frame - Constants.LastFrame];
|
||||
ref ScaleFactors sf = ref refBuf.Sf;
|
||||
ref Surface refFrameBuf = ref refBuf.Buf;
|
||||
|
||||
@@ -767,13 +804,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
isScaled = sf.IsScaled();
|
||||
ReconInter.SetupPrePlanes(ref xd, refr, ref refFrameBuf, miRow, miCol,
|
||||
isScaled ? new Ptr<ScaleFactors>(ref sf) : Ptr<ScaleFactors>.Null);
|
||||
xd.BlockRefs[refr] = new Ptr<RefBuffer>(ref refBuf);
|
||||
blockRefsSpan[refr] = new Ptr<RefBuffer>(ref refBuf);
|
||||
|
||||
if (sbType < BlockSize.Block8X8)
|
||||
{
|
||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||
ref Buf2D dstBuf = ref pd.Dst;
|
||||
int num4X4W = pd.N4W;
|
||||
int num4X4H = pd.N4H;
|
||||
@@ -811,10 +848,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
else
|
||||
{
|
||||
Mv mv = mi.Mv[refr];
|
||||
Mv mv = mvSpan[refr];
|
||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||
ref Buf2D dstBuf = ref pd.Dst;
|
||||
int num4X4W = pd.N4W;
|
||||
int num4X4H = pd.N4H;
|
||||
@@ -847,12 +884,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
private static void SetPlaneN4(ref MacroBlockD xd, int bw, int bh, int bwl, int bhl)
|
||||
{
|
||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||
{
|
||||
xd.Plane[i].N4W = (ushort)((bw << 1) >> xd.Plane[i].SubsamplingX);
|
||||
xd.Plane[i].N4H = (ushort)((bh << 1) >> xd.Plane[i].SubsamplingY);
|
||||
xd.Plane[i].N4Wl = (byte)(bwl - xd.Plane[i].SubsamplingX);
|
||||
xd.Plane[i].N4Hl = (byte)(bhl - xd.Plane[i].SubsamplingY);
|
||||
planeSpan[i].N4W = (ushort)((bw << 1) >> planeSpan[i].SubsamplingX);
|
||||
planeSpan[i].N4H = (ushort)((bh << 1) >> planeSpan[i].SubsamplingY);
|
||||
planeSpan[i].N4Wl = (byte)(bwl - planeSpan[i].SubsamplingX);
|
||||
planeSpan[i].N4Hl = (byte)(bhl - planeSpan[i].SubsamplingY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -892,7 +931,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// as they are always compared to values that are in 1/8th pel units
|
||||
xd.SetMiRowCol(ref tile, miRow, bh, miCol, bw, cm.MiRows, cm.MiCols);
|
||||
|
||||
ReconInter.SetupDstPlanes(ref xd.Plane, ref xd.CurBuf, miRow, miCol);
|
||||
ReconInter.SetupDstPlanes(xd.Plane.AsSpan(), ref xd.CurBuf, miRow, miCol);
|
||||
return ref xd.Mi[0].Value;
|
||||
}
|
||||
|
||||
@@ -933,10 +972,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
if (!mi.IsInterBlock())
|
||||
{
|
||||
int plane;
|
||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||
|
||||
for (int plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
||||
int num4X4W = pd.N4W;
|
||||
int num4X4H = pd.N4H;
|
||||
@@ -967,12 +1007,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Reconstruction
|
||||
if (mi.Skip == 0)
|
||||
{
|
||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||
|
||||
int eobtotal = 0;
|
||||
int plane;
|
||||
|
||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
for (int plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
||||
int num4X4W = pd.N4W;
|
||||
int num4X4H = pd.N4H;
|
||||
@@ -1159,22 +1200,30 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadCoefProbsCommon(ref Array2<Array2<Array6<Array6<Array3<byte>>>>> coefProbs,
|
||||
private static void ReadCoefProbsCommon(ReadOnlySpan<Array2<Array6<Array6<Array3<byte>>>>> coefProbs1,
|
||||
ref Reader r, int txSize)
|
||||
{
|
||||
if (r.ReadBit() != 0)
|
||||
{
|
||||
for (int i = 0; i < Constants.PlaneTypes; ++i)
|
||||
{
|
||||
Span<Array6<Array6<Array3<byte>>>> coefProbs2 = coefProbs1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < Entropy.RefTypes; ++j)
|
||||
{
|
||||
Span<Array6<Array3<byte>>> coefProbs3 = coefProbs2[j].AsSpan();
|
||||
|
||||
for (int k = 0; k < Entropy.CoefBands; ++k)
|
||||
{
|
||||
Span<Array3<byte>> coefProbs4 = coefProbs3[k].AsSpan();
|
||||
|
||||
for (int l = 0; l < Entropy.BAND_COEFF_CONTEXTS(k); ++l)
|
||||
{
|
||||
Span<byte> coefProbs5 = coefProbs4[l].AsSpan();
|
||||
|
||||
for (int m = 0; m < Entropy.UnconstrainedNodes; ++m)
|
||||
{
|
||||
r.DiffUpdateProb(ref coefProbs[i][j][k][l][m]);
|
||||
r.DiffUpdateProb(ref coefProbs5[m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1185,10 +1234,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
private static void ReadCoefProbs(ref Vp9EntropyProbs fc, TxMode txMode, ref Reader r)
|
||||
{
|
||||
Span<Array2<Array2<Array6<Array6<Array3<byte>>>>>> coefProbsSpan = fc.CoefProbs.AsSpan();
|
||||
|
||||
int maxTxSize = (int)Luts.TxModeToBiggestTxSize[(int)txMode];
|
||||
|
||||
for (int txSize = (int)TxSize.Tx4X4; txSize <= maxTxSize; ++txSize)
|
||||
{
|
||||
ReadCoefProbsCommon(ref fc.CoefProbs[txSize], ref r, txSize);
|
||||
ReadCoefProbsCommon(coefProbsSpan[txSize].AsSpan(), ref r, txSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1207,11 +1259,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
lf.ModeRefDeltaUpdate = rb.ReadBit() != 0;
|
||||
if (lf.ModeRefDeltaUpdate)
|
||||
{
|
||||
Span<sbyte> refDeltasSpan = lf.RefDeltas.AsSpan();
|
||||
Span<sbyte> modeDeltasSpan = lf.ModeDeltas.AsSpan();
|
||||
|
||||
for (int i = 0; i < LoopFilter.MaxRefLfDeltas; i++)
|
||||
{
|
||||
if (rb.ReadBit() != 0)
|
||||
{
|
||||
lf.RefDeltas[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||
refDeltasSpan[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1219,7 +1274,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (rb.ReadBit() != 0)
|
||||
{
|
||||
lf.ModeDeltas[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||
modeDeltasSpan[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1267,6 +1322,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
cm.ResizeContextBuffers(allocator, width, height);
|
||||
SetupRenderSize(ref cm, ref rb);
|
||||
|
||||
Span<RefCntBuffer> frameBuffsSpan = pool.FrameBufs.AsSpan();
|
||||
|
||||
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
||||
allocator,
|
||||
cm.Width,
|
||||
@@ -1276,21 +1333,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
cm.UseHighBitDepth,
|
||||
Surface.DecBorderInPixels,
|
||||
cm.ByteAlignment,
|
||||
new Ptr<VpxCodecFrameBuffer>(ref pool.FrameBufs[cm.NewFbIdx].RawFrameBuffer),
|
||||
new Ptr<VpxCodecFrameBuffer>(ref frameBuffsSpan[cm.NewFbIdx].RawFrameBuffer),
|
||||
FrameBuffers.GetFrameBuffer,
|
||||
pool.CbPriv) != 0)
|
||||
{
|
||||
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
||||
}
|
||||
|
||||
pool.FrameBufs[cm.NewFbIdx].Released = 0;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
||||
frameBuffsSpan[cm.NewFbIdx].Released = 0;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
||||
}
|
||||
|
||||
private static bool ValidRefFrameImgFmt(
|
||||
@@ -1311,13 +1368,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
bool hasValidRefFrame = false;
|
||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
if (rb.ReadBit() != 0)
|
||||
{
|
||||
if (cm.FrameRefs[i].Idx != RefBuffer.InvalidIdx)
|
||||
if (frameRefsSpan[i].Idx != RefBuffer.InvalidIdx)
|
||||
{
|
||||
ref Surface buf = ref cm.FrameRefs[i].Buf;
|
||||
ref Surface buf = ref frameRefsSpan[i].Buf;
|
||||
width = buf.YCropWidth;
|
||||
height = buf.YCropHeight;
|
||||
found = true;
|
||||
@@ -1342,7 +1401,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// has valid dimensions.
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
||||
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||
hasValidRefFrame |=
|
||||
refFrame.Idx != RefBuffer.InvalidIdx &&
|
||||
ScaleFactors.ValidRefFrameSize(refFrame.Buf.YCropWidth, refFrame.Buf.YCropHeight, width,
|
||||
@@ -1356,7 +1415,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
||||
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||
if (refFrame.Idx == RefBuffer.InvalidIdx ||
|
||||
!ValidRefFrameImgFmt(
|
||||
(BitDepth)refFrame.Buf.BitDepth,
|
||||
@@ -1373,6 +1432,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
cm.ResizeContextBuffers(allocator, width, height);
|
||||
SetupRenderSize(ref cm, ref rb);
|
||||
|
||||
Span<RefCntBuffer> frameBuffsSpan = pool.FrameBufs.AsSpan();
|
||||
|
||||
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
||||
allocator,
|
||||
@@ -1383,21 +1444,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
cm.UseHighBitDepth,
|
||||
Surface.DecBorderInPixels,
|
||||
cm.ByteAlignment,
|
||||
new Ptr<VpxCodecFrameBuffer>(ref pool.FrameBufs[cm.NewFbIdx].RawFrameBuffer),
|
||||
new Ptr<VpxCodecFrameBuffer>(ref frameBuffsSpan[cm.NewFbIdx].RawFrameBuffer),
|
||||
FrameBuffers.GetFrameBuffer,
|
||||
pool.CbPriv) != 0)
|
||||
{
|
||||
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
||||
}
|
||||
|
||||
pool.FrameBufs[cm.NewFbIdx].Released = 0;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
||||
pool.FrameBufs[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
||||
frameBuffsSpan[cm.NewFbIdx].Released = 0;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
||||
frameBuffsSpan[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
||||
}
|
||||
|
||||
// Reads the next tile returning its size and adjusting '*data' accordingly
|
||||
@@ -1437,7 +1498,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
private static void GetTileBuffers(ref Vp9Common cm, ArrayPtr<byte> data, int tileCols,
|
||||
ref Array64<TileBuffer> tileBuffers)
|
||||
Span<TileBuffer> tileBuffers)
|
||||
{
|
||||
for (int c = 0; c < tileCols; ++c)
|
||||
{
|
||||
@@ -1453,14 +1514,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ArrayPtr<byte> data,
|
||||
int tileCols,
|
||||
int tileRows,
|
||||
ref Array4<Array64<TileBuffer>> tileBuffers)
|
||||
Span<Array64<TileBuffer>> tileBuffers1)
|
||||
{
|
||||
for (int r = 0; r < tileRows; ++r)
|
||||
{
|
||||
Span<TileBuffer> tileBuffers2 = tileBuffers1[r].AsSpan();
|
||||
|
||||
for (int c = 0; c < tileCols; ++c)
|
||||
{
|
||||
bool isLast = r == tileRows - 1 && c == tileCols - 1;
|
||||
ref TileBuffer buf = ref tileBuffers[r][c];
|
||||
ref TileBuffer buf = ref tileBuffers2[c];
|
||||
GetTileBuffer(isLast, ref cm.Error, ref data, ref buf);
|
||||
}
|
||||
}
|
||||
@@ -1484,15 +1547,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
MemoryUtil.Fill(cm.AboveSegContext.ToPointer(), (sbyte)0, alignedCols);
|
||||
|
||||
LoopFilter.ResetLfm(ref cm);
|
||||
|
||||
Span<Array64<TileBuffer>> tileBuffers1 = tileBuffers.AsSpan();
|
||||
Span<TileWorkerData> tileWorkerDataSpan = cm.TileWorkerData.AsSpan();
|
||||
|
||||
GetTileBuffers(ref cm, data, tileCols, tileRows, ref tileBuffers);
|
||||
GetTileBuffers(ref cm, data, tileCols, tileRows, tileBuffers1);
|
||||
// Load all tile information into tile_data.
|
||||
for (tileRow = 0; tileRow < tileRows; ++tileRow)
|
||||
{
|
||||
Span<TileBuffer> tileBuffers2 = tileBuffers1[tileRow].AsSpan();
|
||||
|
||||
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
||||
{
|
||||
ref TileBuffer buf = ref tileBuffers[tileRow][tileCol];
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[(tileCols * tileRow) + tileCol];
|
||||
ref TileBuffer buf = ref tileBuffers2[tileCol];
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[(tileCols * tileRow) + tileCol];
|
||||
tileData.Xd = cm.Mb;
|
||||
tileData.Xd.Corrupted = false;
|
||||
tileData.Xd.Counts = cm.Counts;
|
||||
@@ -1512,7 +1580,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
||||
{
|
||||
int col = tileCol;
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[(tileCols * tileRow) + col];
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[(tileCols * tileRow) + col];
|
||||
tile.SetCol(ref cm, col);
|
||||
tileData.Xd.LeftContext = new Array3<Array16<sbyte>>();
|
||||
tileData.Xd.LeftSegContext = new Array8<sbyte>();
|
||||
@@ -1531,11 +1599,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
// Get last tile data.
|
||||
return cm.TileWorkerData[(tileCols * tileRows) - 1].BitReader.FindEnd();
|
||||
return tileWorkerDataSpan[(tileCols * tileRows) - 1].BitReader.FindEnd();
|
||||
}
|
||||
|
||||
private static bool DecodeTileCol(ref TileWorkerData tileData, ref Vp9Common cm,
|
||||
ref Array64<TileBuffer> tileBuffers)
|
||||
Span<TileBuffer> tileBuffers)
|
||||
{
|
||||
ref TileInfo tile = ref tileData.Xd.Tile;
|
||||
int finalCol = (1 << cm.Log2TileCols) - 1;
|
||||
@@ -1593,10 +1661,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
cm.AboveContext.AsSpan().Clear();
|
||||
cm.AboveSegContext.AsSpan().Clear();
|
||||
|
||||
Span<TileWorkerData> tileWorkerDataSpan = cm.TileWorkerData.AsSpan();
|
||||
|
||||
for (n = 0; n < numWorkers; ++n)
|
||||
{
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[n + totalTiles];
|
||||
|
||||
tileData.Xd = cm.Mb;
|
||||
tileData.Xd.Counts = new Ptr<Vp9BackwardUpdates>(ref tileData.Counts);
|
||||
@@ -1604,17 +1674,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
Array64<TileBuffer> tileBuffers = new();
|
||||
Span<TileBuffer> tileBuffersSpan = tileBuffers.AsSpan();
|
||||
|
||||
GetTileBuffers(ref cm, data, tileCols, ref tileBuffers);
|
||||
GetTileBuffers(ref cm, data, tileCols, tileBuffersSpan);
|
||||
|
||||
tileBuffers.AsSpan()[..tileCols].Sort(CompareTileBuffers);
|
||||
tileBuffersSpan[..tileCols].Sort(CompareTileBuffers);
|
||||
|
||||
if (numWorkers == tileCols)
|
||||
{
|
||||
TileBuffer largest = tileBuffers[0];
|
||||
Span<TileBuffer> buffers = tileBuffers.AsSpan();
|
||||
buffers[1..].CopyTo(buffers[..(tileBuffers.Length - 1)]);
|
||||
tileBuffers[tileCols - 1] = largest;
|
||||
TileBuffer largest = tileBuffersSpan[0];
|
||||
tileBuffersSpan[1..].CopyTo(tileBuffersSpan[..^1]);
|
||||
tileBuffersSpan[tileCols - 1] = largest;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1625,9 +1695,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// larger tile implies it is more difficult to decode.
|
||||
while (start < end)
|
||||
{
|
||||
tmp = tileBuffers[start];
|
||||
tileBuffers[start] = tileBuffers[end];
|
||||
tileBuffers[end] = tmp;
|
||||
tmp = tileBuffersSpan[start];
|
||||
tileBuffersSpan[start] = tileBuffersSpan[end];
|
||||
tileBuffersSpan[end] = tmp;
|
||||
start += 2;
|
||||
end -= 2;
|
||||
}
|
||||
@@ -1640,7 +1710,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
for (n = 0; n < numWorkers; ++n)
|
||||
{
|
||||
int count = baseVal + ((remain + n) / numWorkers);
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[n + totalTiles];
|
||||
|
||||
tileData.BufStart = bufStart;
|
||||
tileData.BufEnd = bufStart + count - 1;
|
||||
@@ -1654,7 +1724,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
ref TileWorkerData tileData = ref cmPtr.Value.TileWorkerData[n + totalTiles];
|
||||
|
||||
if (!DecodeTileCol(ref tileData, ref cmPtr.Value, ref tileBuffers))
|
||||
if (!DecodeTileCol(ref tileData, ref cmPtr.Value, tileBuffers.AsSpan()))
|
||||
{
|
||||
cmPtr.Value.Mb.Corrupted = true;
|
||||
}
|
||||
@@ -1664,14 +1734,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (bitReaderEnd.IsNull)
|
||||
{
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n - 1 + totalTiles];
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[n - 1 + totalTiles];
|
||||
bitReaderEnd = tileData.DataEnd;
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 0; n < numWorkers; ++n)
|
||||
{
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[n + totalTiles];
|
||||
AccumulateFrameCounts(ref cm.Counts.Value, ref tileData.Counts);
|
||||
}
|
||||
|
||||
@@ -1705,7 +1775,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (cm.FrameType == FrameType.KeyFrame && cm.CurrentVideoFrame > 0)
|
||||
{
|
||||
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
|
||||
Span<RefCntBuffer> frameBuffs = cm.BufferPool.Value.FrameBufs.AsSpan();
|
||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||
|
||||
for (int i = 0; i < Constants.FrameBuffers; ++i)
|
||||
@@ -1715,11 +1785,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
continue;
|
||||
}
|
||||
|
||||
frameBufs[i].RefCount = 0;
|
||||
if (frameBufs[i].Released == 0)
|
||||
frameBuffs[i].RefCount = 0;
|
||||
if (frameBuffs[i].Released == 0)
|
||||
{
|
||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[i].RawFrameBuffer);
|
||||
frameBufs[i].Released = 1;
|
||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBuffs[i].RawFrameBuffer);
|
||||
frameBuffs[i].Released = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1742,7 +1812,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
readSyncCode2 == SyncCode2;
|
||||
}
|
||||
|
||||
private static void RefCntFb(ref Array12<RefCntBuffer> bufs, ref int idx, int newIdx)
|
||||
private static void RefCntFb(Span<RefCntBuffer> bufs, ref int idx, int newIdx)
|
||||
{
|
||||
int refIndex = idx;
|
||||
|
||||
@@ -1761,13 +1831,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
ref Vp9Common cm = ref pbi.Common;
|
||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||
ref Array12<RefCntBuffer> frameBufs = ref pool.FrameBufs;
|
||||
Span<RefCntBuffer> frameBuffs = pool.FrameBufs.AsSpan();
|
||||
int mask, refIndex = 0;
|
||||
ulong sz;
|
||||
|
||||
cm.LastFrameType = cm.FrameType;
|
||||
cm.LastIntraOnly = cm.IntraOnly;
|
||||
|
||||
Span<int> refFrameSpan = cm.RefFrameMap.AsSpan();
|
||||
|
||||
if (rb.ReadLiteral(2) != FrameMarker)
|
||||
{
|
||||
cm.Error.InternalError(CodecErr.UnsupBitstream, "Invalid frame marker");
|
||||
@@ -1783,14 +1855,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
if (cm.ShowExistingFrame != 0)
|
||||
{
|
||||
// Show an existing frame directly.
|
||||
int frameToShow = cm.RefFrameMap[rb.ReadLiteral(3)];
|
||||
if (frameToShow < 0 || frameBufs[frameToShow].RefCount < 1)
|
||||
int frameToShow = refFrameSpan[rb.ReadLiteral(3)];
|
||||
if (frameToShow < 0 || frameBuffs[frameToShow].RefCount < 1)
|
||||
{
|
||||
cm.Error.InternalError(CodecErr.UnsupBitstream,
|
||||
$"Buffer {frameToShow} does not contain a decoded frame");
|
||||
}
|
||||
|
||||
RefCntFb(ref frameBufs, ref cm.NewFbIdx, frameToShow);
|
||||
RefCntFb(frameBuffs, ref cm.NewFbIdx, frameToShow);
|
||||
pbi.RefreshFrameFlags = 0;
|
||||
cm.Lf.FilterLevel = 0;
|
||||
cm.ShowFrame = 1;
|
||||
@@ -1812,16 +1884,18 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
cm.ReadBitdepthColorspaceSampling(ref rb);
|
||||
pbi.RefreshFrameFlags = (1 << Constants.RefFrames) - 1;
|
||||
|
||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
cm.FrameRefs[i].Idx = RefBuffer.InvalidIdx;
|
||||
cm.FrameRefs[i].Buf = default;
|
||||
frameRefsSpan[i].Idx = RefBuffer.InvalidIdx;
|
||||
frameRefsSpan[i].Buf = default;
|
||||
}
|
||||
|
||||
SetupFrameSize(allocator, ref cm, ref rb);
|
||||
if (pbi.NeedResync != 0)
|
||||
{
|
||||
cm.RefFrameMap.AsSpan().Fill(-1);
|
||||
refFrameSpan.Fill(-1);
|
||||
FlushAllFbOnKey(ref cm);
|
||||
pbi.NeedResync = 0;
|
||||
}
|
||||
@@ -1860,22 +1934,25 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
SetupFrameSize(allocator, ref cm, ref rb);
|
||||
if (pbi.NeedResync != 0)
|
||||
{
|
||||
cm.RefFrameMap.AsSpan().Fill(-1);
|
||||
refFrameSpan.Fill(-1);
|
||||
pbi.NeedResync = 0;
|
||||
}
|
||||
}
|
||||
else if (pbi.NeedResync != 1)
|
||||
{
|
||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||
Span<sbyte> refFrameSignBiasSpan = cm.RefFrameSignBias.AsSpan();
|
||||
|
||||
/* Skip if need resync */
|
||||
pbi.RefreshFrameFlags = rb.ReadLiteral(Constants.RefFrames);
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
int refr = rb.ReadLiteral(Constants.RefFramesLog2);
|
||||
int idx = cm.RefFrameMap[refr];
|
||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
||||
int idx = refFrameSpan[refr];
|
||||
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||
refFrame.Idx = idx;
|
||||
refFrame.Buf = frameBufs[idx].Buf;
|
||||
cm.RefFrameSignBias[Constants.LastFrame + i] = (sbyte)rb.ReadBit();
|
||||
refFrame.Buf = frameBuffs[idx].Buf;
|
||||
refFrameSignBiasSpan[Constants.LastFrame + i] = (sbyte)rb.ReadBit();
|
||||
}
|
||||
|
||||
SetupFrameSizeWithRefs(allocator, ref cm, ref rb);
|
||||
@@ -1885,7 +1962,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
ref RefBuffer refBuf = ref cm.FrameRefs[i];
|
||||
ref RefBuffer refBuf = ref frameRefsSpan[i];
|
||||
refBuf.Sf.SetupScaleFactorsForFrame(
|
||||
refBuf.Buf.YCropWidth,
|
||||
refBuf.Buf.YCropHeight,
|
||||
@@ -1926,23 +2003,25 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// below, forcing the use of context 0 for those frame types.
|
||||
cm.FrameContextIdx = (uint)rb.ReadLiteral(Constants.FrameContextsLog2);
|
||||
|
||||
Span<int> nextRefFrameMapSpan = cm.NextRefFrameMap.AsSpan();
|
||||
|
||||
// Generate next_ref_frame_map.
|
||||
for (mask = pbi.RefreshFrameFlags; mask != 0; mask >>= 1)
|
||||
{
|
||||
if ((mask & 1) != 0)
|
||||
{
|
||||
cm.NextRefFrameMap[refIndex] = cm.NewFbIdx;
|
||||
++frameBufs[cm.NewFbIdx].RefCount;
|
||||
nextRefFrameMapSpan[refIndex] = cm.NewFbIdx;
|
||||
++frameBuffs[cm.NewFbIdx].RefCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
cm.NextRefFrameMap[refIndex] = cm.RefFrameMap[refIndex];
|
||||
nextRefFrameMapSpan[refIndex] = cm.RefFrameMap[refIndex];
|
||||
}
|
||||
|
||||
// Current thread holds the reference frame.
|
||||
if (cm.RefFrameMap[refIndex] >= 0)
|
||||
{
|
||||
++frameBufs[cm.RefFrameMap[refIndex]].RefCount;
|
||||
++frameBuffs[cm.RefFrameMap[refIndex]].RefCount;
|
||||
}
|
||||
|
||||
++refIndex;
|
||||
@@ -1950,11 +2029,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
for (; refIndex < Constants.RefFrames; ++refIndex)
|
||||
{
|
||||
cm.NextRefFrameMap[refIndex] = cm.RefFrameMap[refIndex];
|
||||
nextRefFrameMapSpan[refIndex] = refFrameSpan[refIndex];
|
||||
// Current thread holds the reference frame.
|
||||
if (cm.RefFrameMap[refIndex] >= 0)
|
||||
if (refFrameSpan[refIndex] >= 0)
|
||||
{
|
||||
++frameBufs[cm.RefFrameMap[refIndex]].RefCount;
|
||||
++frameBuffs[refFrameSpan[refIndex]].RefCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2001,9 +2080,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
ReadCoefProbs(ref fc, cm.TxMode, ref r);
|
||||
|
||||
Span<byte> skipProbSpan = fc.SkipProb.AsSpan();
|
||||
|
||||
for (int k = 0; k < Constants.SkipContexts; ++k)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.SkipProb[k]);
|
||||
r.DiffUpdateProb(ref skipProbSpan[k]);
|
||||
}
|
||||
|
||||
if (!cm.FrameIsIntraOnly())
|
||||
@@ -2014,10 +2095,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
ReadSwitchableInterpProbs(ref fc, ref r);
|
||||
}
|
||||
|
||||
Span<byte> intraInterProbSpan = fc.IntraInterProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.IntraInterContexts; i++)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.IntraInterProb[i]);
|
||||
r.DiffUpdateProb(ref intraInterProbSpan[i]);
|
||||
}
|
||||
|
||||
cm.ReferenceMode = cm.ReadFrameReferenceMode(ref r);
|
||||
@@ -2027,20 +2110,28 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
cm.ReadFrameReferenceModeProbs(ref r);
|
||||
|
||||
Span<Array9<byte>> yModeProbSpan1 = fc.YModeProb.AsSpan();
|
||||
|
||||
for (int j = 0; j < EntropyMode.BlockSizeGroups; j++)
|
||||
{
|
||||
Span<byte> yModeProbSpan2 = yModeProbSpan1[j].AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.IntraModes - 1; ++i)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.YModeProb[j][i]);
|
||||
r.DiffUpdateProb(ref yModeProbSpan2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Span<Array3<byte>> partitionProbSpan1 = fc.PartitionProb.AsSpan();
|
||||
|
||||
for (int j = 0; j < Constants.PartitionContexts; ++j)
|
||||
{
|
||||
Span<byte> partitionProbSpan2 = partitionProbSpan1[j].AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.PartitionTypes - 1; ++i)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.PartitionProb[j][i]);
|
||||
r.DiffUpdateProb(ref partitionProbSpan2[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2098,7 +2189,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
xd.SetupBlockPlanes(cm.SubsamplingX, cm.SubsamplingY);
|
||||
|
||||
cm.Fc = new Ptr<Vp9EntropyProbs>(ref cm.FrameContexts[(int)cm.FrameContextIdx]);
|
||||
Span<Vp9EntropyProbs> frameContextsSpan = cm.FrameContexts.AsSpan();
|
||||
|
||||
cm.Fc = new Ptr<Vp9EntropyProbs>(ref frameContextsSpan[(int)cm.FrameContextIdx]);
|
||||
|
||||
xd.Corrupted = false;
|
||||
newFb.Corrupted = ReadCompressedHeader(ref pbi, data, firstPartitionSize) ? 1 : 0;
|
||||
@@ -2167,7 +2260,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Non frame parallel update frame context here.
|
||||
if (cm.RefreshFrameContext != 0 && contextUpdated == 0)
|
||||
{
|
||||
cm.FrameContexts[(int)cm.FrameContextIdx] = cm.Fc.Value;
|
||||
frameContextsSpan[(int)cm.FrameContextIdx] = cm.Fc.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -50,9 +50,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
return PredictionMode.NearestMv + mode;
|
||||
}
|
||||
|
||||
private static int ReadSegmentId(ref Reader r, ref Array7<byte> segTreeProbs)
|
||||
private static int ReadSegmentId(ref Reader r, ReadOnlySpan<byte> segTreeProbs)
|
||||
{
|
||||
return r.ReadTree(Luts.SegmentTree, segTreeProbs.AsSpan());
|
||||
return r.ReadTree(Luts.SegmentTree, segTreeProbs);
|
||||
}
|
||||
|
||||
private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx)
|
||||
@@ -187,7 +187,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
return 0;
|
||||
}
|
||||
|
||||
segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
||||
segmentId = ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
|
||||
return segmentId;
|
||||
}
|
||||
@@ -223,15 +223,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
if (seg.TemporalUpdate)
|
||||
{
|
||||
byte predProb = Segmentation.GetPredProbSegId(ref cm.Fc.Value.SegPredProb, ref xd);
|
||||
byte predProb = Segmentation.GetPredProbSegId(cm.Fc.Value.SegPredProb.AsSpan(), ref xd);
|
||||
mi.SegIdPredicted = (sbyte)r.Read(predProb);
|
||||
segmentId = mi.SegIdPredicted != 0
|
||||
? predictedSegmentId
|
||||
: ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
||||
: ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||
}
|
||||
else
|
||||
{
|
||||
segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
||||
segmentId = ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||
}
|
||||
|
||||
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
|
||||
@@ -272,10 +272,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
int n = (int)mvClass + Constants.Class0Bits - 1; // Number of bits
|
||||
|
||||
Span<byte> bitsSpan = fc.Bits[mvcomp].AsSpan();
|
||||
|
||||
d = 0;
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
d |= r.Read(fc.Bits[mvcomp][i]) << i;
|
||||
d |= r.Read(bitsSpan[i]) << i;
|
||||
}
|
||||
|
||||
mag = Constants.Class0Size << ((int)mvClass + 2);
|
||||
@@ -343,7 +345,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ref MacroBlockD xd,
|
||||
ref Reader r,
|
||||
int segmentId,
|
||||
ref Array2<sbyte> refFrame)
|
||||
Span<sbyte> refFrame)
|
||||
{
|
||||
ref Vp9EntropyProbs fc = ref cm.Fc.Value;
|
||||
|
||||
@@ -418,23 +420,25 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
BlockSize bsize = mi.SbType;
|
||||
|
||||
Span<BModeInfo> bmiSpan = mi.Bmi.AsSpan();
|
||||
|
||||
switch (bsize)
|
||||
{
|
||||
case BlockSize.Block4X4:
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
mi.Bmi[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
bmiSpan[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
}
|
||||
|
||||
mi.Mode = mi.Bmi[3].Mode;
|
||||
mi.Mode = bmiSpan[3].Mode;
|
||||
break;
|
||||
case BlockSize.Block4X8:
|
||||
mi.Bmi[0].Mode = mi.Bmi[2].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
mi.Bmi[1].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
bmiSpan[0].Mode = bmiSpan[2].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
bmiSpan[1].Mode = bmiSpan[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
break;
|
||||
case BlockSize.Block8X4:
|
||||
mi.Bmi[0].Mode = mi.Bmi[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
mi.Bmi[2].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
bmiSpan[0].Mode = bmiSpan[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
bmiSpan[2].Mode = bmiSpan[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
break;
|
||||
default:
|
||||
mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]);
|
||||
@@ -447,29 +451,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// modes in GetPredContextSwitchableInterp()
|
||||
mi.InterpFilter = Constants.SwitchableFilters;
|
||||
|
||||
mi.RefFrame[0] = Constants.IntraFrame;
|
||||
mi.RefFrame[1] = Constants.None;
|
||||
}
|
||||
|
||||
private static void CopyPair(ref Array2<Mv> dst, ref Array2<Mv> src)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
}
|
||||
|
||||
private static void ZeroPair(ref Array2<Mv> dst)
|
||||
{
|
||||
dst[0] = new Mv();
|
||||
dst[1] = new Mv();
|
||||
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
||||
|
||||
refFrameSpan[0] = Constants.IntraFrame;
|
||||
refFrameSpan[1] = Constants.None;
|
||||
}
|
||||
|
||||
private static bool Assign(
|
||||
ref Vp9Common cm,
|
||||
ref MacroBlockD xd,
|
||||
PredictionMode mode,
|
||||
ref Array2<Mv> mv,
|
||||
ref Array2<Mv> refMv,
|
||||
ref Array2<Mv> nearNearestMv,
|
||||
Span<Mv> mv,
|
||||
Span<Mv> refMv,
|
||||
Span<Mv> nearNearestMv,
|
||||
int isCompound,
|
||||
bool allowHp,
|
||||
ref Reader r)
|
||||
@@ -491,12 +485,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
case PredictionMode.NearMv:
|
||||
case PredictionMode.NearestMv:
|
||||
{
|
||||
CopyPair(ref mv, ref nearNearestMv);
|
||||
nearNearestMv.CopyTo(mv);
|
||||
break;
|
||||
}
|
||||
case PredictionMode.ZeroMv:
|
||||
{
|
||||
ZeroPair(ref mv);
|
||||
mv.Clear();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -559,26 +553,29 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
private static bool IsDiffRefFrameAddEb(
|
||||
ref ModeInfo mbmi,
|
||||
sbyte refFrame,
|
||||
ref Array4<sbyte> refSignBias,
|
||||
Span<sbyte> refSignBias,
|
||||
ref int refmvCount,
|
||||
Span<Mv> mvRefList,
|
||||
bool earlyBreak)
|
||||
{
|
||||
if (mbmi.IsInterBlock())
|
||||
{
|
||||
if (mbmi.RefFrame[0] != refFrame)
|
||||
Span<sbyte> refFrameSpan = mbmi.RefFrame.AsSpan();
|
||||
Span<Mv> mvSpan = mbmi.Mv.AsSpan();
|
||||
|
||||
if (refFrameSpan[0] != refFrame)
|
||||
{
|
||||
if (AddRefListEb(mbmi.ScaleMv(0, refFrame, ref refSignBias), ref refmvCount, mvRefList,
|
||||
if (AddRefListEb(mbmi.ScaleMv(0, refFrame, refSignBias), ref refmvCount, mvRefList,
|
||||
earlyBreak))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame &&
|
||||
Unsafe.As<Mv, int>(ref mbmi.Mv[1]) != Unsafe.As<Mv, int>(ref mbmi.Mv[0]))
|
||||
if (mbmi.HasSecondRef() && refFrameSpan[1] != refFrame &&
|
||||
Unsafe.As<Mv, int>(ref mvSpan[1]) != Unsafe.As<Mv, int>(ref mvSpan[0]))
|
||||
{
|
||||
if (AddRefListEb(mbmi.ScaleMv(1, refFrame, ref refSignBias), ref refmvCount, mvRefList,
|
||||
if (AddRefListEb(mbmi.ScaleMv(1, refFrame, refSignBias), ref refmvCount, mvRefList,
|
||||
earlyBreak))
|
||||
{
|
||||
return true;
|
||||
@@ -603,7 +600,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
int block,
|
||||
int isSub8X8)
|
||||
{
|
||||
ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias;
|
||||
Span<sbyte> refSignBias = cm.RefFrameSignBias.AsSpan();
|
||||
int i, refmvCount = 0;
|
||||
bool differentRefFound = false;
|
||||
Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs
|
||||
@@ -616,7 +613,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
// Blank the reference vector list
|
||||
mvRefList[..Constants.MaxMvRefCandidates].Clear();
|
||||
|
||||
|
||||
i = 0;
|
||||
if (isSub8X8 != 0)
|
||||
{
|
||||
@@ -630,7 +627,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||
differentRefFound = true;
|
||||
|
||||
if (candidateMi.RefFrame[0] == refFrame)
|
||||
Span<sbyte> refFrameSpan = candidateMi.RefFrame.AsSpan();
|
||||
|
||||
if (refFrameSpan[0] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount,
|
||||
mvRefList, earlyBreak))
|
||||
@@ -638,7 +637,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
else if (candidateMi.RefFrame[1] == refFrame)
|
||||
else if (refFrameSpan[1] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount,
|
||||
mvRefList, earlyBreak))
|
||||
@@ -660,17 +659,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||
differentRefFound = true;
|
||||
|
||||
Span<sbyte> refFrameSpan = candidate.RefFrame.AsSpan();
|
||||
Span<Mv> mvSpan = candidate.Mv.AsSpan();
|
||||
|
||||
if (candidate.RefFrame[0] == refFrame)
|
||||
if (refFrameSpan[0] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak))
|
||||
if (AddRefListEb(mvSpan[0], ref refmvCount, mvRefList, earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
else if (candidate.RefFrame[1] == refFrame)
|
||||
else if (refFrameSpan[1] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(candidate.Mv[1], ref refmvCount, mvRefList, earlyBreak))
|
||||
if (AddRefListEb(mvSpan[1], ref refmvCount, mvRefList, earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
@@ -681,16 +683,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Check the last frame's mode and mv info.
|
||||
if (!prevFrameMvs.IsNull)
|
||||
{
|
||||
if (prevFrameMvs.Value.RefFrame[0] == refFrame)
|
||||
Span<sbyte> refFrameSpan = prevFrameMvs.Value.RefFrame.AsSpan();
|
||||
Span<Mv> mvSpan = prevFrameMvs.Value.Mv.AsSpan();
|
||||
|
||||
if (refFrameSpan[0] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak))
|
||||
if (AddRefListEb(mvSpan[0], ref refmvCount, mvRefList, earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
else if (prevFrameMvs.Value.RefFrame[1] == refFrame)
|
||||
else if (refFrameSpan[1] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(prevFrameMvs.Value.Mv[1], ref refmvCount, mvRefList, earlyBreak))
|
||||
if (AddRefListEb(mvSpan[1], ref refmvCount, mvRefList, earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
@@ -710,7 +715,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||
|
||||
// If the candidate is Intra we don't want to consider its mv.
|
||||
if (IsDiffRefFrameAddEb(ref candidate, refFrame, ref refSignBias, ref refmvCount, mvRefList,
|
||||
if (IsDiffRefFrameAddEb(ref candidate, refFrame, refSignBias, ref refmvCount, mvRefList,
|
||||
earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
@@ -722,10 +727,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Since we still don't have a candidate we'll try the last frame.
|
||||
if (!prevFrameMvs.IsNull)
|
||||
{
|
||||
if (prevFrameMvs.Value.RefFrame[0] != refFrame && prevFrameMvs.Value.RefFrame[0] > Constants.IntraFrame)
|
||||
Span<sbyte> refFrameSpan = prevFrameMvs.Value.RefFrame.AsSpan();
|
||||
Span<Mv> mvSpan = prevFrameMvs.Value.Mv.AsSpan();
|
||||
|
||||
if (refFrameSpan[0] != refFrame && refFrameSpan[0] > Constants.IntraFrame)
|
||||
{
|
||||
Mv mv = prevFrameMvs.Value.Mv[0];
|
||||
if (refSignBias[prevFrameMvs.Value.RefFrame[0]] != refSignBias[refFrame])
|
||||
Mv mv = mvSpan[0];
|
||||
if (refSignBias[refFrameSpan[0]] != refSignBias[refFrame])
|
||||
{
|
||||
mv.Row *= -1;
|
||||
mv.Col *= -1;
|
||||
@@ -737,13 +745,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
}
|
||||
|
||||
if (prevFrameMvs.Value.RefFrame[1] > Constants.IntraFrame &&
|
||||
prevFrameMvs.Value.RefFrame[1] != refFrame &&
|
||||
Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[1]) !=
|
||||
Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[0]))
|
||||
if (refFrameSpan[1] > Constants.IntraFrame &&
|
||||
refFrameSpan[1] != refFrame &&
|
||||
Unsafe.As<Mv, int>(ref mvSpan[1]) !=
|
||||
Unsafe.As<Mv, int>(ref mvSpan[0]))
|
||||
{
|
||||
Mv mv = prevFrameMvs.Value.Mv[1];
|
||||
if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame])
|
||||
Mv mv = mvSpan[1];
|
||||
if (refSignBias[refFrameSpan[1]] != refSignBias[refFrame])
|
||||
{
|
||||
mv.Row *= -1;
|
||||
mv.Col *= -1;
|
||||
@@ -789,7 +797,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
|
||||
ref ModeInfo mi = ref xd.Mi[0].Value;
|
||||
ref Array4<BModeInfo> bmi = ref mi.Bmi;
|
||||
Span<BModeInfo> bmi = mi.Bmi.AsSpan();
|
||||
int refmvCount;
|
||||
|
||||
Debug.Assert(Constants.MaxMvRefCandidates == 2);
|
||||
@@ -884,11 +892,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
BlockSize bsize = mi.SbType;
|
||||
bool allowHp = cm.AllowHighPrecisionMv;
|
||||
Array2<Mv> bestRefMvs = new();
|
||||
Span<Mv> bestRefMvsSpan = bestRefMvs.AsSpan();
|
||||
int refr, isCompound;
|
||||
byte interModeCtx;
|
||||
Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize];
|
||||
|
||||
ReadRefFrames(ref cm, ref xd, ref r, mi.SegmentId, ref mi.RefFrame);
|
||||
ReadRefFrames(ref cm, ref xd, ref r, mi.SegmentId, mi.RefFrame.AsSpan());
|
||||
isCompound = mi.HasSecondRef() ? 1 : 0;
|
||||
interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
|
||||
|
||||
@@ -920,16 +929,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
if (mi.Mode != PredictionMode.ZeroMv)
|
||||
{
|
||||
Span<Mv> tmpMvs = stackalloc Mv[Constants.MaxMvRefCandidates];
|
||||
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
||||
|
||||
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||
{
|
||||
sbyte frame = mi.RefFrame[refr];
|
||||
sbyte frame = refFrameSpan[refr];
|
||||
int refmvCount;
|
||||
|
||||
refmvCount = DecFindRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol,
|
||||
-1, 0);
|
||||
|
||||
DecFindBestRefs(allowHp, tmpMvs, ref bestRefMvs[refr], refmvCount);
|
||||
DecFindBestRefs(allowHp, tmpMvs, ref bestRefMvsSpan[refr], refmvCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -945,10 +955,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
int idx, idy;
|
||||
PredictionMode bMode = 0;
|
||||
Array2<Mv> bestSub8X8 = new();
|
||||
Span<Mv> bestSub8X8Span = bestSub8X8.AsSpan();
|
||||
Span<BModeInfo> bmiSpan = mi.Bmi.AsSpan();
|
||||
const uint InvalidMv = 0x80008000;
|
||||
// Initialize the 2nd element as even though it won't be used meaningfully
|
||||
// if isCompound is false.
|
||||
Unsafe.As<Mv, uint>(ref bestSub8X8[1]) = InvalidMv;
|
||||
Unsafe.As<Mv, uint>(ref bestSub8X8Span[1]) = InvalidMv;
|
||||
for (idy = 0; idy < 2; idy += num4X4H)
|
||||
{
|
||||
for (idx = 0; idx < 2; idx += num4X4W)
|
||||
@@ -961,11 +973,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||
{
|
||||
AppendSub8X8ForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol,
|
||||
ref bestSub8X8[refr]);
|
||||
ref bestSub8X8Span[refr]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Assign(ref cm, ref xd, bMode, ref mi.Bmi[j].Mv, ref bestRefMvs, ref bestSub8X8,
|
||||
if (!Assign(ref cm, ref xd, bMode, bmiSpan[j].Mv.AsSpan(), bestRefMvs.AsSpan(), bestSub8X8.AsSpan(),
|
||||
isCompound, allowHp, ref r))
|
||||
{
|
||||
xd.Corrupted |= true;
|
||||
@@ -974,23 +986,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
if (num4X4H == 2)
|
||||
{
|
||||
mi.Bmi[j + 2] = mi.Bmi[j];
|
||||
bmiSpan[j + 2] = bmiSpan[j];
|
||||
}
|
||||
|
||||
if (num4X4W == 2)
|
||||
{
|
||||
mi.Bmi[j + 1] = mi.Bmi[j];
|
||||
bmiSpan[j + 1] = bmiSpan[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mi.Mode = bMode;
|
||||
|
||||
CopyPair(ref mi.Mv, ref mi.Bmi[3].Mv);
|
||||
bmiSpan[3].Mv.AsSpan().CopyTo(mi.Mv.AsSpan());
|
||||
}
|
||||
else
|
||||
{
|
||||
xd.Corrupted |= !Assign(ref cm, ref xd, mi.Mode, ref mi.Mv, ref bestRefMvs, ref bestRefMvs,
|
||||
xd.Corrupted |= !Assign(ref cm, ref xd, mi.Mode, mi.Mv.AsSpan(), bestRefMvs.AsSpan(), bestRefMvs.AsSpan(),
|
||||
isCompound, allowHp, ref r);
|
||||
}
|
||||
}
|
||||
@@ -1082,33 +1093,42 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
int miOffset = (miRow * cm.MiCols) + miCol;
|
||||
|
||||
Span<sbyte> refFrameSpan = mi.Value.RefFrame.AsSpan();
|
||||
|
||||
mi.Value.SegmentId = (sbyte)ReadIntraSegmentId(ref cm, miOffset, xMis, yMis, ref r);
|
||||
mi.Value.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r);
|
||||
mi.Value.TxSize = ReadTxSize(ref cm, ref xd, true, ref r);
|
||||
mi.Value.RefFrame[0] = Constants.IntraFrame;
|
||||
mi.Value.RefFrame[1] = Constants.None;
|
||||
refFrameSpan[0] = Constants.IntraFrame;
|
||||
refFrameSpan[1] = Constants.None;
|
||||
|
||||
Span<BModeInfo> bmiSpan;
|
||||
switch (bsize)
|
||||
{
|
||||
case BlockSize.Block4X4:
|
||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
mi.Value.Bmi[i].Mode =
|
||||
bmiSpan[i].Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i));
|
||||
}
|
||||
|
||||
mi.Value.Mode = mi.Value.Bmi[3].Mode;
|
||||
mi.Value.Mode = bmiSpan[3].Mode;
|
||||
break;
|
||||
case BlockSize.Block4X8:
|
||||
mi.Value.Bmi[0].Mode = mi.Value.Bmi[2].Mode =
|
||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||
|
||||
bmiSpan[0].Mode = bmiSpan[2].Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
||||
mi.Value.Bmi[1].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
|
||||
bmiSpan[1].Mode = bmiSpan[3].Mode = mi.Value.Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 1));
|
||||
break;
|
||||
case BlockSize.Block8X4:
|
||||
mi.Value.Bmi[0].Mode = mi.Value.Bmi[1].Mode =
|
||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||
|
||||
bmiSpan[0].Mode = bmiSpan[1].Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
||||
mi.Value.Bmi[2].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
|
||||
bmiSpan[2].Mode = bmiSpan[3].Mode = mi.Value.Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 2));
|
||||
break;
|
||||
default:
|
||||
@@ -1119,12 +1139,6 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
mi.Value.UvMode = ReadIntraMode(ref r, cm.Fc.Value.KfUvModeProb[(int)mi.Value.Mode].AsSpan());
|
||||
}
|
||||
|
||||
private static void CopyRefFramePair(ref Array2<sbyte> dst, ref Array2<sbyte> src)
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
}
|
||||
|
||||
public static void ReadModeInfo(
|
||||
ref TileWorkerData twd,
|
||||
ref Vp9Common cm,
|
||||
@@ -1151,8 +1165,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
for (int w = 0; w < xMis; ++w)
|
||||
{
|
||||
ref MvRef mv = ref frameMvs[w];
|
||||
CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame);
|
||||
CopyPair(ref mv.Mv, ref mi.Mv);
|
||||
mi.RefFrame.AsSpan().CopyTo(mv.RefFrame.AsSpan());
|
||||
mi.Mv.AsSpan().CopyTo(mv.Mv.AsSpan());
|
||||
}
|
||||
|
||||
frameMvs = frameMvs.Slice(cm.MiCols);
|
||||
|
@@ -89,9 +89,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
cm.Lf.RefDeltas = pictureInfo.RefDeltas;
|
||||
cm.Lf.ModeDeltas = pictureInfo.ModeDeltas;
|
||||
|
||||
cm.FrameRefs[0].Buf = (Surface)pictureInfo.LastReference;
|
||||
cm.FrameRefs[1].Buf = (Surface)pictureInfo.GoldenReference;
|
||||
cm.FrameRefs[2].Buf = (Surface)pictureInfo.AltReference;
|
||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||
frameRefsSpan[0].Buf = (Surface)pictureInfo.LastReference;
|
||||
frameRefsSpan[1].Buf = (Surface)pictureInfo.GoldenReference;
|
||||
frameRefsSpan[2].Buf = (Surface)pictureInfo.AltReference;
|
||||
cm.Mb.CurBuf = (Surface)output;
|
||||
|
||||
cm.Mb.SetupBlockPlanes(1, 1);
|
||||
|
@@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
PlaneType type,
|
||||
Span<int> dqcoeff,
|
||||
TxSize txSize,
|
||||
ref Array2<short> dq,
|
||||
ReadOnlySpan<short> dq,
|
||||
int ctx,
|
||||
ReadOnlySpan<short> scan,
|
||||
ReadOnlySpan<short> nb,
|
||||
@@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ref Vp9EntropyProbs fc = ref xd.Fc.Value;
|
||||
int refr = xd.Mi[0].Value.IsInterBlock() ? 1 : 0;
|
||||
int band, c = 0;
|
||||
ref Array6<Array6<Array3<byte>>> coefProbs = ref fc.CoefProbs[(int)txSize][(int)type][refr];
|
||||
ReadOnlySpan<Array6<Array3<byte>>> coefProbs = fc.CoefProbs[(int)txSize][(int)type][refr].AsSpan();
|
||||
Span<byte> tokenCache = stackalloc byte[32 * 32];
|
||||
ReadOnlySpan<byte> bandTranslate = Luts.GetBandTranslate(txSize);
|
||||
int dqShift = txSize == TxSize.Tx32X32 ? 1 : 0;
|
||||
@@ -56,23 +56,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ulong value = r.Value;
|
||||
uint range = r.Range;
|
||||
int count = r.Count;
|
||||
|
||||
ReadOnlySpan<Array6<Array4<uint>>> coefSpan = counts.Coef[(int)txSize][(int)type][refr].AsSpan();
|
||||
ReadOnlySpan<Array6<uint>> eobBranchSpan = counts.EobBranch[(int)txSize][(int)type][refr].AsSpan();
|
||||
|
||||
while (c < maxEob)
|
||||
{
|
||||
int val = -1;
|
||||
band = bandTranslate[0];
|
||||
bandTranslate = bandTranslate[1..];
|
||||
ref Array3<byte> prob = ref coefProbs[band][ctx];
|
||||
ReadOnlySpan<byte> prob = coefProbs[band][ctx].AsSpan();
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++counts.EobBranch[(int)txSize][(int)type][refr][band][ctx];
|
||||
++eobBranchSpan[band][ctx];
|
||||
}
|
||||
|
||||
if (r.ReadBool(prob[EobContextNode], ref value, ref count, ref range) == 0)
|
||||
{
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.EobModelToken];
|
||||
++coefSpan[band][ctx][Constants.EobModelToken];
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -82,7 +85,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.ZeroToken];
|
||||
++coefSpan[band][ctx][Constants.ZeroToken];
|
||||
}
|
||||
|
||||
dqv = dq[1];
|
||||
@@ -99,7 +102,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ctx = GetCoefContext(nb, tokenCache, c);
|
||||
band = bandTranslate[0];
|
||||
bandTranslate = bandTranslate[1..];
|
||||
prob = ref coefProbs[band][ctx];
|
||||
prob = coefProbs[band][ctx].AsSpan();
|
||||
}
|
||||
|
||||
if (r.ReadBool(prob[OneContextNode], ref value, ref count, ref range) != 0)
|
||||
@@ -107,7 +110,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ReadOnlySpan<byte> p = Luts.Pareto8Full[prob[Constants.PivotNode] - 1];
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.TwoToken];
|
||||
++coefSpan[band][ctx][Constants.TwoToken];
|
||||
}
|
||||
|
||||
if (r.ReadBool(p[0], ref value, ref count, ref range) != 0)
|
||||
@@ -175,7 +178,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.OneToken];
|
||||
++coefSpan[band][ctx][Constants.OneToken];
|
||||
}
|
||||
|
||||
tokenCache[scan[c]] = 1;
|
||||
@@ -232,7 +235,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ref Reader r = ref twd.BitReader;
|
||||
ref MacroBlockD xd = ref twd.Xd;
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
ref Array2<short> dequant = ref pd.SegDequant[segId];
|
||||
Span<short> dequant = pd.SegDequant[segId].AsSpan();
|
||||
int eob;
|
||||
Span<sbyte> a = pd.AboveContext.AsSpan()[x..];
|
||||
Span<sbyte> l = pd.LeftContext.AsSpan()[y..];
|
||||
@@ -250,7 +253,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
GetPlaneType(plane),
|
||||
pd.DqCoeff.AsSpan(),
|
||||
txSize,
|
||||
ref dequant,
|
||||
dequant,
|
||||
ctx,
|
||||
sc.Scan,
|
||||
sc.Neighbors,
|
||||
@@ -266,7 +269,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
GetPlaneType(plane),
|
||||
pd.DqCoeff.AsSpan(),
|
||||
txSize,
|
||||
ref dequant,
|
||||
dequant,
|
||||
ctx,
|
||||
sc.Scan,
|
||||
sc.Neighbors,
|
||||
@@ -283,7 +286,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
GetPlaneType(plane),
|
||||
pd.DqCoeff.AsSpan(),
|
||||
txSize,
|
||||
ref dequant,
|
||||
dequant,
|
||||
ctx,
|
||||
sc.Scan,
|
||||
sc.Neighbors,
|
||||
@@ -303,7 +306,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
GetPlaneType(plane),
|
||||
pd.DqCoeff.AsSpan(),
|
||||
txSize,
|
||||
ref dequant,
|
||||
dequant,
|
||||
ctx,
|
||||
sc.Scan,
|
||||
sc.Neighbors,
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
@@ -129,7 +130,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
byte* srcX = &src[xQ4 >> SubpelBits];
|
||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -164,7 +165,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
byte* srcX = &src[xQ4 >> SubpelBits];
|
||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -275,7 +276,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -310,7 +311,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -619,7 +620,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
ushort* srcX = &src[xQ4 >> SubpelBits];
|
||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -655,7 +656,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
ushort* srcX = &src[xQ4 >> SubpelBits];
|
||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -692,7 +693,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -728,7 +729,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
|
@@ -304,31 +304,40 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
internal static void TxCountsToBranchCounts32X32(ReadOnlySpan<uint> txCount32X32P,
|
||||
ref Array3<Array2<uint>> ct32X32P)
|
||||
ReadOnlySpan<Array2<uint>> ct32X32P)
|
||||
{
|
||||
ct32X32P[0][0] = txCount32X32P[(int)TxSize.Tx4X4];
|
||||
ct32X32P[0][1] = txCount32X32P[(int)TxSize.Tx8X8] + txCount32X32P[(int)TxSize.Tx16X16] +
|
||||
Span<uint> ct32X32PSpan0 = ct32X32P[0].AsSpan();
|
||||
Span<uint> ct32X32PSpan1 = ct32X32P[1].AsSpan();
|
||||
Span<uint> ct32X32PSpan2 = ct32X32P[2].AsSpan();
|
||||
|
||||
ct32X32PSpan0[0] = txCount32X32P[(int)TxSize.Tx4X4];
|
||||
ct32X32PSpan0[1] = txCount32X32P[(int)TxSize.Tx8X8] + txCount32X32P[(int)TxSize.Tx16X16] +
|
||||
txCount32X32P[(int)TxSize.Tx32X32];
|
||||
ct32X32P[1][0] = txCount32X32P[(int)TxSize.Tx8X8];
|
||||
ct32X32P[1][1] = txCount32X32P[(int)TxSize.Tx16X16] + txCount32X32P[(int)TxSize.Tx32X32];
|
||||
ct32X32P[2][0] = txCount32X32P[(int)TxSize.Tx16X16];
|
||||
ct32X32P[2][1] = txCount32X32P[(int)TxSize.Tx32X32];
|
||||
ct32X32PSpan1[0] = txCount32X32P[(int)TxSize.Tx8X8];
|
||||
ct32X32PSpan1[1] = txCount32X32P[(int)TxSize.Tx16X16] + txCount32X32P[(int)TxSize.Tx32X32];
|
||||
ct32X32PSpan2[0] = txCount32X32P[(int)TxSize.Tx16X16];
|
||||
ct32X32PSpan2[1] = txCount32X32P[(int)TxSize.Tx32X32];
|
||||
}
|
||||
|
||||
internal static void TxCountsToBranchCounts16X16(ReadOnlySpan<uint> txCount16X16P,
|
||||
ref Array2<Array2<uint>> ct16X16P)
|
||||
ReadOnlySpan<Array2<uint>> ct16X16P)
|
||||
{
|
||||
ct16X16P[0][0] = txCount16X16P[(int)TxSize.Tx4X4];
|
||||
ct16X16P[0][1] = txCount16X16P[(int)TxSize.Tx8X8] + txCount16X16P[(int)TxSize.Tx16X16];
|
||||
ct16X16P[1][0] = txCount16X16P[(int)TxSize.Tx8X8];
|
||||
ct16X16P[1][1] = txCount16X16P[(int)TxSize.Tx16X16];
|
||||
Span<uint> ct16X16PSpan0 = ct16X16P[0].AsSpan();
|
||||
Span<uint> ct16X16PSpan1 = ct16X16P[1].AsSpan();
|
||||
|
||||
ct16X16PSpan0[0] = txCount16X16P[(int)TxSize.Tx4X4];
|
||||
ct16X16PSpan0[1] = txCount16X16P[(int)TxSize.Tx8X8] + txCount16X16P[(int)TxSize.Tx16X16];
|
||||
ct16X16PSpan1[0] = txCount16X16P[(int)TxSize.Tx8X8];
|
||||
ct16X16PSpan1[1] = txCount16X16P[(int)TxSize.Tx16X16];
|
||||
}
|
||||
|
||||
internal static void TxCountsToBranchCounts8X8(ReadOnlySpan<uint> txCount8X8P,
|
||||
ref Array1<Array2<uint>> ct8X8P)
|
||||
ReadOnlySpan<Array2<uint>> ct8X8P)
|
||||
{
|
||||
ct8X8P[0][0] = txCount8X8P[(int)TxSize.Tx4X4];
|
||||
ct8X8P[0][1] = txCount8X8P[(int)TxSize.Tx8X8];
|
||||
Span<uint> ct8X8PSpan = ct8X8P[0].AsSpan();
|
||||
|
||||
ct8X8PSpan[0] = txCount8X8P[(int)TxSize.Tx4X4];
|
||||
ct8X8PSpan[1] = txCount8X8P[(int)TxSize.Tx8X8];
|
||||
}
|
||||
|
||||
public static unsafe void SetupPastIndependence(ref Vp9Common cm)
|
||||
|
@@ -378,9 +378,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
int index = shiftY;
|
||||
|
||||
Span<byte> lflYSpan = lfm.LflY.AsSpan();
|
||||
|
||||
for (int i = 0; i < bh; i++)
|
||||
{
|
||||
MemoryMarshal.CreateSpan(ref lfm.LflY[index], 64 - index)[..bw].Fill((byte)filterLevel);
|
||||
MemoryMarshal.CreateSpan(ref lflYSpan[index], 64 - index)[..bw].Fill((byte)filterLevel);
|
||||
index += 8;
|
||||
}
|
||||
|
||||
@@ -444,25 +446,30 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
const ulong AboveBorder = 0x000000ff000000ffUL;
|
||||
const ushort LeftBorderUv = 0x1111;
|
||||
const ushort AboveBorderUv = 0x000f;
|
||||
|
||||
Span<ulong> leftYSpan = lfm.LeftY.AsSpan();
|
||||
Span<ulong> aboveYSpan = lfm.AboveY.AsSpan();
|
||||
Span<ushort> leftUvSpan = lfm.LeftUv.AsSpan();
|
||||
Span<ushort> aboveUvSpan = lfm.AboveUv.AsSpan();
|
||||
|
||||
// The largest loopfilter we have is 16x16 so we use the 16x16 mask
|
||||
// for 32x32 transforms also.
|
||||
lfm.LeftY[(int)TxSize.Tx16X16] |= lfm.LeftY[(int)TxSize.Tx32X32];
|
||||
lfm.AboveY[(int)TxSize.Tx16X16] |= lfm.AboveY[(int)TxSize.Tx32X32];
|
||||
lfm.LeftUv[(int)TxSize.Tx16X16] |= lfm.LeftUv[(int)TxSize.Tx32X32];
|
||||
lfm.AboveUv[(int)TxSize.Tx16X16] |= lfm.AboveUv[(int)TxSize.Tx32X32];
|
||||
leftYSpan[(int)TxSize.Tx16X16] |= leftYSpan[(int)TxSize.Tx32X32];
|
||||
aboveYSpan[(int)TxSize.Tx16X16] |= aboveYSpan[(int)TxSize.Tx32X32];
|
||||
leftUvSpan[(int)TxSize.Tx16X16] |= leftUvSpan[(int)TxSize.Tx32X32];
|
||||
aboveUvSpan[(int)TxSize.Tx16X16] |= aboveUvSpan[(int)TxSize.Tx32X32];
|
||||
|
||||
// We do at least 8 tap filter on every 32x32 even if the transform size
|
||||
// is 4x4. So if the 4x4 is set on a border pixel add it to the 8x8 and
|
||||
// remove it from the 4x4.
|
||||
lfm.LeftY[(int)TxSize.Tx8X8] |= lfm.LeftY[(int)TxSize.Tx4X4] & LeftBorder;
|
||||
lfm.LeftY[(int)TxSize.Tx4X4] &= ~LeftBorder;
|
||||
lfm.AboveY[(int)TxSize.Tx8X8] |= lfm.AboveY[(int)TxSize.Tx4X4] & AboveBorder;
|
||||
lfm.AboveY[(int)TxSize.Tx4X4] &= ~AboveBorder;
|
||||
lfm.LeftUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.LeftUv[(int)TxSize.Tx4X4] & LeftBorderUv);
|
||||
lfm.LeftUv[(int)TxSize.Tx4X4] &= unchecked((ushort)~LeftBorderUv);
|
||||
lfm.AboveUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.AboveUv[(int)TxSize.Tx4X4] & AboveBorderUv);
|
||||
lfm.AboveUv[(int)TxSize.Tx4X4] &= unchecked((ushort)~AboveBorderUv);
|
||||
leftYSpan[(int)TxSize.Tx8X8] |= leftYSpan[(int)TxSize.Tx4X4] & LeftBorder;
|
||||
leftYSpan[(int)TxSize.Tx4X4] &= ~LeftBorder;
|
||||
aboveYSpan[(int)TxSize.Tx8X8] |= aboveYSpan[(int)TxSize.Tx4X4] & AboveBorder;
|
||||
aboveYSpan[(int)TxSize.Tx4X4] &= ~AboveBorder;
|
||||
leftUvSpan[(int)TxSize.Tx8X8] |= (ushort)(leftUvSpan[(int)TxSize.Tx4X4] & LeftBorderUv);
|
||||
leftUvSpan[(int)TxSize.Tx4X4] &= unchecked((ushort)~LeftBorderUv);
|
||||
aboveUvSpan[(int)TxSize.Tx8X8] |= (ushort)(aboveUvSpan[(int)TxSize.Tx4X4] & AboveBorderUv);
|
||||
aboveUvSpan[(int)TxSize.Tx4X4] &= unchecked((ushort)~AboveBorderUv);
|
||||
|
||||
// We do some special edge handling.
|
||||
if (miRow + Constants.MiBlockSize > cm.MiRows)
|
||||
@@ -476,10 +483,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Remove values completely outside our border.
|
||||
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||
{
|
||||
lfm.LeftY[i] &= maskY;
|
||||
lfm.AboveY[i] &= maskY;
|
||||
lfm.LeftUv[i] &= maskUv;
|
||||
lfm.AboveUv[i] &= maskUv;
|
||||
leftYSpan[i] &= maskY;
|
||||
aboveYSpan[i] &= maskY;
|
||||
leftUvSpan[i] &= maskUv;
|
||||
aboveUvSpan[i] &= maskUv;
|
||||
}
|
||||
|
||||
lfm.Int4X4Y &= maskY;
|
||||
@@ -489,14 +496,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// apply the shorter one instead.
|
||||
if (rows == 1)
|
||||
{
|
||||
lfm.AboveUv[(int)TxSize.Tx8X8] |= lfm.AboveUv[(int)TxSize.Tx16X16];
|
||||
lfm.AboveUv[(int)TxSize.Tx16X16] = 0;
|
||||
aboveUvSpan[(int)TxSize.Tx8X8] |= aboveUvSpan[(int)TxSize.Tx16X16];
|
||||
aboveUvSpan[(int)TxSize.Tx16X16] = 0;
|
||||
}
|
||||
|
||||
if (rows == 5)
|
||||
{
|
||||
lfm.AboveUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.AboveUv[(int)TxSize.Tx16X16] & 0xff00);
|
||||
lfm.AboveUv[(int)TxSize.Tx16X16] &= (ushort)~(lfm.AboveUv[(int)TxSize.Tx16X16] & 0xff00);
|
||||
aboveUvSpan[(int)TxSize.Tx8X8] |= (ushort)(aboveUvSpan[(int)TxSize.Tx16X16] & 0xff00);
|
||||
aboveUvSpan[(int)TxSize.Tx16X16] &= (ushort)~(aboveUvSpan[(int)TxSize.Tx16X16] & 0xff00);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,10 +523,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Remove the bits outside the image edge.
|
||||
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||
{
|
||||
lfm.LeftY[i] &= maskY;
|
||||
lfm.AboveY[i] &= maskY;
|
||||
lfm.LeftUv[i] &= maskUv;
|
||||
lfm.AboveUv[i] &= maskUv;
|
||||
leftYSpan[i] &= maskY;
|
||||
aboveYSpan[i] &= maskY;
|
||||
leftUvSpan[i] &= maskUv;
|
||||
aboveUvSpan[i] &= maskUv;
|
||||
}
|
||||
|
||||
lfm.Int4X4Y &= maskY;
|
||||
@@ -529,14 +536,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// apply the shorter one instead.
|
||||
if (columns == 1)
|
||||
{
|
||||
lfm.LeftUv[(int)TxSize.Tx8X8] |= lfm.LeftUv[(int)TxSize.Tx16X16];
|
||||
lfm.LeftUv[(int)TxSize.Tx16X16] = 0;
|
||||
leftUvSpan[(int)TxSize.Tx8X8] |= leftUvSpan[(int)TxSize.Tx16X16];
|
||||
leftUvSpan[(int)TxSize.Tx16X16] = 0;
|
||||
}
|
||||
|
||||
if (columns == 5)
|
||||
{
|
||||
lfm.LeftUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.LeftUv[(int)TxSize.Tx16X16] & 0xcccc);
|
||||
lfm.LeftUv[(int)TxSize.Tx16X16] &= (ushort)~(lfm.LeftUv[(int)TxSize.Tx16X16] & 0xcccc);
|
||||
leftUvSpan[(int)TxSize.Tx8X8] |= (ushort)(leftUvSpan[(int)TxSize.Tx16X16] & 0xcccc);
|
||||
leftUvSpan[(int)TxSize.Tx16X16] &= (ushort)~(leftUvSpan[(int)TxSize.Tx16X16] & 0xcccc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,28 +553,28 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||
{
|
||||
lfm.LeftY[i] &= 0xfefefefefefefefeUL;
|
||||
lfm.LeftUv[i] &= 0xeeee;
|
||||
leftYSpan[i] &= 0xfefefefefefefefeUL;
|
||||
leftUvSpan[i] &= 0xeeee;
|
||||
}
|
||||
}
|
||||
|
||||
// Assert if we try to apply 2 different loop filters at the same position.
|
||||
Debug.Assert((lfm.LeftY[(int)TxSize.Tx16X16] & lfm.LeftY[(int)TxSize.Tx8X8]) == 0);
|
||||
Debug.Assert((lfm.LeftY[(int)TxSize.Tx16X16] & lfm.LeftY[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.LeftY[(int)TxSize.Tx8X8] & lfm.LeftY[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.Int4X4Y & lfm.LeftY[(int)TxSize.Tx16X16]) == 0);
|
||||
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx16X16] & lfm.LeftUv[(int)TxSize.Tx8X8]) == 0);
|
||||
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx16X16] & lfm.LeftUv[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx8X8] & lfm.LeftUv[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.Int4X4Uv & lfm.LeftUv[(int)TxSize.Tx16X16]) == 0);
|
||||
Debug.Assert((lfm.AboveY[(int)TxSize.Tx16X16] & lfm.AboveY[(int)TxSize.Tx8X8]) == 0);
|
||||
Debug.Assert((lfm.AboveY[(int)TxSize.Tx16X16] & lfm.AboveY[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.AboveY[(int)TxSize.Tx8X8] & lfm.AboveY[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.Int4X4Y & lfm.AboveY[(int)TxSize.Tx16X16]) == 0);
|
||||
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx16X16] & lfm.AboveUv[(int)TxSize.Tx8X8]) == 0);
|
||||
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx16X16] & lfm.AboveUv[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx8X8] & lfm.AboveUv[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.Int4X4Uv & lfm.AboveUv[(int)TxSize.Tx16X16]) == 0);
|
||||
Debug.Assert((leftYSpan[(int)TxSize.Tx16X16] & leftYSpan[(int)TxSize.Tx8X8]) == 0);
|
||||
Debug.Assert((leftYSpan[(int)TxSize.Tx16X16] & leftYSpan[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((leftYSpan[(int)TxSize.Tx8X8] & leftYSpan[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.Int4X4Y & leftYSpan[(int)TxSize.Tx16X16]) == 0);
|
||||
Debug.Assert((leftUvSpan[(int)TxSize.Tx16X16] & leftUvSpan[(int)TxSize.Tx8X8]) == 0);
|
||||
Debug.Assert((leftUvSpan[(int)TxSize.Tx16X16] & leftUvSpan[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((leftUvSpan[(int)TxSize.Tx8X8] & leftUvSpan[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.Int4X4Uv & leftUvSpan[(int)TxSize.Tx16X16]) == 0);
|
||||
Debug.Assert((aboveYSpan[(int)TxSize.Tx16X16] & aboveYSpan[(int)TxSize.Tx8X8]) == 0);
|
||||
Debug.Assert((aboveYSpan[(int)TxSize.Tx16X16] & aboveYSpan[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((aboveYSpan[(int)TxSize.Tx8X8] & aboveYSpan[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.Int4X4Y & aboveYSpan[(int)TxSize.Tx16X16]) == 0);
|
||||
Debug.Assert((aboveUvSpan[(int)TxSize.Tx16X16] & aboveUvSpan[(int)TxSize.Tx8X8]) == 0);
|
||||
Debug.Assert((aboveUvSpan[(int)TxSize.Tx16X16] & aboveUvSpan[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((aboveUvSpan[(int)TxSize.Tx8X8] & aboveUvSpan[(int)TxSize.Tx4X4]) == 0);
|
||||
Debug.Assert((lfm.Int4X4Uv & aboveUvSpan[(int)TxSize.Tx16X16]) == 0);
|
||||
}
|
||||
|
||||
public static unsafe void ResetLfm(ref Vp9Common cm)
|
||||
@@ -583,6 +590,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
int lvl;
|
||||
|
||||
Span<LoopFilterThresh> lFThrSpan = lfi.Lfthr.AsSpan();
|
||||
|
||||
// For each possible value for the loop filter fill out limits
|
||||
for (lvl = 0; lvl <= MaxLoopFilter; lvl++)
|
||||
{
|
||||
@@ -602,8 +611,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
blockInsideLimit = 1;
|
||||
}
|
||||
|
||||
lfi.Lfthr[lvl].Lim.AsSpan().Fill((byte)blockInsideLimit);
|
||||
lfi.Lfthr[lvl].Mblim.AsSpan().Fill((byte)((2 * (lvl + 2)) + blockInsideLimit));
|
||||
lFThrSpan[lvl].Lim.AsSpan().Fill((byte)blockInsideLimit);
|
||||
lFThrSpan[lvl].Mblim.AsSpan().Fill((byte)((2 * (lvl + 2)) + blockInsideLimit));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -625,6 +634,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
lf.LastSharpnessLevel = lf.SharpnessLevel;
|
||||
}
|
||||
|
||||
Span<Array4<Array2<byte>>> lvlSpan = lfi.Lvl.AsSpan();
|
||||
Span<sbyte> refDeltasSpan = lf.RefDeltas.AsSpan();
|
||||
Span<sbyte> modeDeltasSpan = lf.ModeDeltas.AsSpan();
|
||||
sbyte intraFrameRefDelta = refDeltasSpan[Constants.IntraFrame];
|
||||
|
||||
for (segId = 0; segId < Constants.MaxSegments; segId++)
|
||||
{
|
||||
int lvlSeg = defaultFiltLvl;
|
||||
@@ -639,20 +653,24 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
// We could get rid of this if we assume that deltas are set to
|
||||
// zero when not in use; encoder always uses deltas
|
||||
MemoryMarshal.Cast<Array2<byte>, byte>(lfi.Lvl[segId].AsSpan()).Fill((byte)lvlSeg);
|
||||
MemoryMarshal.Cast<Array2<byte>, byte>(lvlSpan[segId].AsSpan()).Fill((byte)lvlSeg);
|
||||
}
|
||||
else
|
||||
{
|
||||
int refr, mode;
|
||||
int intraLvl = lvlSeg + (lf.RefDeltas[Constants.IntraFrame] * scale);
|
||||
lfi.Lvl[segId][Constants.IntraFrame][0] = (byte)Math.Clamp(intraLvl, 0, MaxLoopFilter);
|
||||
int intraLvl = lvlSeg + (intraFrameRefDelta * scale);
|
||||
lvlSpan[segId][Constants.IntraFrame][0] = (byte)Math.Clamp(intraLvl, 0, MaxLoopFilter);
|
||||
|
||||
Span<Array2<byte>> lvlSpan2 = lvlSpan[segId].AsSpan();
|
||||
|
||||
for (refr = Constants.LastFrame; refr < Constants.MaxRefFrames; ++refr)
|
||||
{
|
||||
Span<byte> lvlSpan3 = lvlSpan2[refr].AsSpan();
|
||||
|
||||
for (mode = 0; mode < MaxModeLfDeltas; ++mode)
|
||||
{
|
||||
int interLvl = lvlSeg + (lf.RefDeltas[refr] * scale) + (lf.ModeDeltas[mode] * scale);
|
||||
lfi.Lvl[segId][refr][mode] = (byte)Math.Clamp(interLvl, 0, MaxLoopFilter);
|
||||
int interLvl = lvlSeg + (refDeltasSpan[refr] * scale) + (modeDeltasSpan[mode] * scale);
|
||||
lvlSpan3[mode] = (byte)Math.Clamp(interLvl, 0, MaxLoopFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -811,18 +829,32 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
lfis[1] = lfthr[lfl[lflForward]];
|
||||
ss[1] = ss[0].Slice(8 * pitch);
|
||||
|
||||
Span<byte> mblim0Span = lfis[0].Mblim.AsSpan();
|
||||
Span<byte> lim0Span = lfis[0].Lim.AsSpan();
|
||||
Span<byte> hevThr0Span = lfis[0].HevThr.AsSpan();
|
||||
Span<byte> mblim1Span = lfis[1].Mblim.AsSpan();
|
||||
Span<byte> lim1Span = lfis[1].Lim.AsSpan();
|
||||
Span<byte> hevThr1Span = lfis[1].HevThr.AsSpan();
|
||||
|
||||
if ((mask16X16 & dualOne) != 0)
|
||||
{
|
||||
if ((mask16X16 & dualOne) == dualOne)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical16Dual(ss[0], pitch, lfis[0].Mblim[0], lfis[0].Lim[0],
|
||||
lfis[0].HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical16Dual(ss[0], pitch, mblim0Span[0], lim0Span[0],
|
||||
hevThr0Span[0], bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref LoopFilterThresh lfi = ref lfis[(mask16X16 & 1) == 0 ? 1 : 0];
|
||||
LoopFilterScalar.HighBdLpfVertical16(ss[(mask16X16 & 1) == 0 ? 1 : 0], pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
if ((mask16X16 & 1) == 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical16(ss[1], pitch, mblim1Span[0],
|
||||
lim1Span[0], hevThr1Span[0], bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical16(ss[0], pitch, mblim0Span[0],
|
||||
lim0Span[0], hevThr0Span[0], bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -833,24 +865,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfVertical8Dual(
|
||||
ss[0],
|
||||
pitch,
|
||||
lfis[0].Mblim[0],
|
||||
lfis[0].Lim[0],
|
||||
lfis[0].HevThr[0],
|
||||
lfis[1].Mblim[0],
|
||||
lfis[1].Lim[0],
|
||||
lfis[1].HevThr[0],
|
||||
mblim0Span[0],
|
||||
lim0Span[0],
|
||||
hevThr0Span[0],
|
||||
mblim1Span[0],
|
||||
lim1Span[0],
|
||||
hevThr1Span[0],
|
||||
bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref LoopFilterThresh lfi = ref lfis[(mask8X8 & 1) == 0 ? 1 : 0];
|
||||
LoopFilterScalar.HighBdLpfVertical8(
|
||||
ss[(mask8X8 & 1) == 0 ? 1 : 0],
|
||||
pitch,
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
bd);
|
||||
if ((mask8X8 & 1) == 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical8(ss[1], pitch, mblim1Span[0],
|
||||
lim1Span[0], hevThr1Span[0], bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical8(ss[0], pitch, mblim0Span[0],
|
||||
lim0Span[0], hevThr0Span[0], bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -861,19 +895,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfVertical4Dual(
|
||||
ss[0],
|
||||
pitch,
|
||||
lfis[0].Mblim[0],
|
||||
lfis[0].Lim[0],
|
||||
lfis[0].HevThr[0],
|
||||
lfis[1].Mblim[0],
|
||||
lfis[1].Lim[0],
|
||||
lfis[1].HevThr[0],
|
||||
mblim0Span[0],
|
||||
lim0Span[0],
|
||||
hevThr0Span[0],
|
||||
mblim1Span[0],
|
||||
lim1Span[0],
|
||||
hevThr1Span[0],
|
||||
bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref LoopFilterThresh lfi = ref lfis[(mask4X4 & 1) == 0 ? 1 : 0];
|
||||
LoopFilterScalar.HighBdLpfVertical4(ss[(mask4X4 & 1) == 0 ? 1 : 0], pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
if ((mask4X4 & 1) == 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical4(ss[1], pitch, mblim1Span[0],
|
||||
lim1Span[0], hevThr1Span[0], bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical4(ss[0], pitch, mblim0Span[0],
|
||||
lim0Span[0], hevThr0Span[0], bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,19 +925,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfVertical4Dual(
|
||||
ss[0].Slice(4),
|
||||
pitch,
|
||||
lfis[0].Mblim[0],
|
||||
lfis[0].Lim[0],
|
||||
lfis[0].HevThr[0],
|
||||
lfis[1].Mblim[0],
|
||||
lfis[1].Lim[0],
|
||||
lfis[1].HevThr[0],
|
||||
mblim0Span[0],
|
||||
lim0Span[0],
|
||||
hevThr0Span[0],
|
||||
mblim1Span[0],
|
||||
lim1Span[0],
|
||||
hevThr1Span[0],
|
||||
bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref LoopFilterThresh lfi = ref lfis[(mask4X4Int & 1) == 0 ? 1 : 0];
|
||||
LoopFilterScalar.HighBdLpfVertical4(ss[(mask4X4Int & 1) == 0 ? 1 : 0].Slice(4), pitch,
|
||||
lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
if ((mask4X4Int & 1) == 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical4(ss[1].Slice(4), pitch, mblim1Span[0],
|
||||
lim1Span[0], hevThr1Span[0], bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical4(ss[0].Slice(4), pitch, mblim0Span[0],
|
||||
lim0Span[0], hevThr0Span[0], bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1086,18 +1134,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
if ((mask & 1) != 0)
|
||||
{
|
||||
LoopFilterThresh lfi = lfthr[lfl[0]];
|
||||
|
||||
Span<byte> mblimSpan = lfi.Mblim.AsSpan();
|
||||
Span<byte> limSpan = lfi.Lim.AsSpan();
|
||||
Span<byte> hevThrSpan = lfi.HevThr.AsSpan();
|
||||
|
||||
if ((mask16X16 & 1) != 0)
|
||||
{
|
||||
if ((mask16X16 & 3) == 3)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal16Dual(s, pitch, lfi.Mblim[0], lfi.Lim[0],
|
||||
lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal16Dual(s, pitch, mblimSpan[0], limSpan[0],
|
||||
hevThrSpan[0], bd);
|
||||
count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal16(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
||||
LoopFilterScalar.HighBdLpfHorizontal16(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||
bd);
|
||||
}
|
||||
}
|
||||
@@ -1107,16 +1159,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
// Next block's thresholds.
|
||||
LoopFilterThresh lfin = lfthr[lfl[1]];
|
||||
|
||||
Span<byte> nMblimSpan = lfin.Mblim.AsSpan();
|
||||
Span<byte> nLimSpan = lfin.Lim.AsSpan();
|
||||
Span<byte> nHevThrSpan = lfin.HevThr.AsSpan();
|
||||
|
||||
LoopFilterScalar.HighBdLpfHorizontal8Dual(
|
||||
s,
|
||||
pitch,
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
lfin.Mblim[0],
|
||||
lfin.Lim[0],
|
||||
lfin.HevThr[0],
|
||||
mblimSpan[0],
|
||||
limSpan[0],
|
||||
hevThrSpan[0],
|
||||
nMblimSpan[0],
|
||||
nLimSpan[0],
|
||||
nHevThrSpan[0],
|
||||
bd);
|
||||
|
||||
if ((mask4X4Int & 3) == 3)
|
||||
@@ -1124,36 +1180,36 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||
s.Slice(4 * pitch),
|
||||
pitch,
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
lfin.Mblim[0],
|
||||
lfin.Lim[0],
|
||||
lfin.HevThr[0],
|
||||
mblimSpan[0],
|
||||
limSpan[0],
|
||||
hevThrSpan[0],
|
||||
nMblimSpan[0],
|
||||
nLimSpan[0],
|
||||
nHevThrSpan[0],
|
||||
bd);
|
||||
}
|
||||
else if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||
limSpan[0], hevThrSpan[0], bd);
|
||||
}
|
||||
else if ((mask4X4Int & 2) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, lfin.Mblim[0],
|
||||
lfin.Lim[0], lfin.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, nMblimSpan[0],
|
||||
nLimSpan[0], nHevThrSpan[0], bd);
|
||||
}
|
||||
|
||||
count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal8(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
||||
LoopFilterScalar.HighBdLpfHorizontal8(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||
bd);
|
||||
|
||||
if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||
limSpan[0], hevThrSpan[0], bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1163,16 +1219,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
// Next block's thresholds.
|
||||
LoopFilterThresh lfin = lfthr[lfl[1]];
|
||||
|
||||
Span<byte> nMblimSpan = lfin.Mblim.AsSpan();
|
||||
Span<byte> nLimSpan = lfin.Lim.AsSpan();
|
||||
Span<byte> nHevThrSpan = lfin.HevThr.AsSpan();
|
||||
|
||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||
s,
|
||||
pitch,
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
lfin.Mblim[0],
|
||||
lfin.Lim[0],
|
||||
lfin.HevThr[0],
|
||||
mblimSpan[0],
|
||||
limSpan[0],
|
||||
hevThrSpan[0],
|
||||
nMblimSpan[0],
|
||||
nLimSpan[0],
|
||||
nHevThrSpan[0],
|
||||
bd);
|
||||
|
||||
if ((mask4X4Int & 3) == 3)
|
||||
@@ -1180,43 +1240,43 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||
s.Slice(4 * pitch),
|
||||
pitch,
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
lfin.Mblim[0],
|
||||
lfin.Lim[0],
|
||||
lfin.HevThr[0],
|
||||
mblimSpan[0],
|
||||
limSpan[0],
|
||||
hevThrSpan[0],
|
||||
nMblimSpan[0],
|
||||
nLimSpan[0],
|
||||
nHevThrSpan[0],
|
||||
bd);
|
||||
}
|
||||
else if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||
limSpan[0], hevThrSpan[0], bd);
|
||||
}
|
||||
else if ((mask4X4Int & 2) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, lfin.Mblim[0],
|
||||
lfin.Lim[0], lfin.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, nMblimSpan[0],
|
||||
nLimSpan[0], nHevThrSpan[0], bd);
|
||||
}
|
||||
|
||||
count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||
bd);
|
||||
|
||||
if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||
limSpan[0], hevThrSpan[0], bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0], lfi.Lim[0],
|
||||
lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0], limSpan[0],
|
||||
hevThrSpan[0], bd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,26 +1351,30 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
for (uint mask = mask16X16 | mask8X8 | mask4X4 | mask4X4Int; mask != 0; mask >>= 1)
|
||||
{
|
||||
LoopFilterThresh lfi = lfthr[lfl[0]];
|
||||
|
||||
Span<byte> mblimSpan = lfi.Mblim.AsSpan();
|
||||
Span<byte> limSpan = lfi.Lim.AsSpan();
|
||||
Span<byte> hevThrSpan = lfi.HevThr.AsSpan();
|
||||
|
||||
if ((mask & 1) != 0)
|
||||
{
|
||||
if ((mask16X16 & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical16(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical16(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||
}
|
||||
else if ((mask8X8 & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical8(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical8(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||
}
|
||||
else if ((mask4X4 & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical4(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical4(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical4(s.Slice(4), pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical4(s.Slice(4), pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||
}
|
||||
|
||||
s = s.Slice(8);
|
||||
@@ -1555,9 +1619,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
ref Buf2D dst = ref plane.Dst;
|
||||
ArrayPtr<byte> dst0 = dst.Buf;
|
||||
ulong mask16X16 = lfm.LeftY[(int)TxSize.Tx16X16];
|
||||
ulong mask8X8 = lfm.LeftY[(int)TxSize.Tx8X8];
|
||||
ulong mask4X4 = lfm.LeftY[(int)TxSize.Tx4X4];
|
||||
Span<ulong> leftYSpan = lfm.LeftY.AsSpan();
|
||||
ulong mask16X16 = leftYSpan[(int)TxSize.Tx16X16];
|
||||
ulong mask8X8 = leftYSpan[(int)TxSize.Tx8X8];
|
||||
ulong mask4X4 = leftYSpan[(int)TxSize.Tx4X4];
|
||||
ulong mask4X4Int = lfm.Int4X4Y;
|
||||
|
||||
Debug.Assert(plane.SubsamplingX == 0 && plane.SubsamplingY == 0);
|
||||
@@ -1604,9 +1669,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
// Horizontal pass
|
||||
dst.Buf = dst0;
|
||||
mask16X16 = lfm.AboveY[(int)TxSize.Tx16X16];
|
||||
mask8X8 = lfm.AboveY[(int)TxSize.Tx8X8];
|
||||
mask4X4 = lfm.AboveY[(int)TxSize.Tx4X4];
|
||||
Span<ulong> aboveYSpan = lfm.AboveY.AsSpan();
|
||||
mask16X16 = aboveYSpan[(int)TxSize.Tx16X16];
|
||||
mask8X8 = aboveYSpan[(int)TxSize.Tx8X8];
|
||||
mask4X4 = aboveYSpan[(int)TxSize.Tx4X4];
|
||||
mask4X4Int = lfm.Int4X4Y;
|
||||
|
||||
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r++)
|
||||
@@ -1669,10 +1735,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ArrayPtr<byte> dst0 = dst.Buf;
|
||||
|
||||
Span<byte> lflUv = stackalloc byte[16];
|
||||
Span<byte> lflY = lfm.LflY.AsSpan();
|
||||
|
||||
ushort mask16X16 = lfm.LeftUv[(int)TxSize.Tx16X16];
|
||||
ushort mask8X8 = lfm.LeftUv[(int)TxSize.Tx8X8];
|
||||
ushort mask4X4 = lfm.LeftUv[(int)TxSize.Tx4X4];
|
||||
Span<ushort> leftUvSpan = lfm.LeftUv.AsSpan();
|
||||
ushort mask16X16 = leftUvSpan[(int)TxSize.Tx16X16];
|
||||
ushort mask8X8 = leftUvSpan[(int)TxSize.Tx8X8];
|
||||
ushort mask4X4 = leftUvSpan[(int)TxSize.Tx4X4];
|
||||
ushort mask4X4Int = lfm.Int4X4Uv;
|
||||
|
||||
Debug.Assert(plane.SubsamplingX == 1 && plane.SubsamplingY == 1);
|
||||
@@ -1682,8 +1750,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
for (int c = 0; c < Constants.MiBlockSize >> 1; c++)
|
||||
{
|
||||
lflUv[(r << 1) + c] = lfm.LflY[(r << 3) + (c << 1)];
|
||||
lflUv[((r + 2) << 1) + c] = lfm.LflY[((r + 2) << 3) + (c << 1)];
|
||||
lflUv[(r << 1) + c] = lflY[(r << 3) + (c << 1)];
|
||||
lflUv[((r + 2) << 1) + c] = lflY[((r + 2) << 3) + (c << 1)];
|
||||
}
|
||||
|
||||
if (cm.UseHighBitDepth)
|
||||
@@ -1725,9 +1793,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
// Horizontal pass
|
||||
dst.Buf = dst0;
|
||||
mask16X16 = lfm.AboveUv[(int)TxSize.Tx16X16];
|
||||
mask8X8 = lfm.AboveUv[(int)TxSize.Tx8X8];
|
||||
mask4X4 = lfm.AboveUv[(int)TxSize.Tx4X4];
|
||||
Span<ushort> aboveUvSpan = lfm.AboveUv.AsSpan();
|
||||
mask16X16 = aboveUvSpan[(int)TxSize.Tx16X16];
|
||||
mask8X8 = aboveUvSpan[(int)TxSize.Tx8X8];
|
||||
mask4X4 = aboveUvSpan[(int)TxSize.Tx4X4];
|
||||
mask4X4Int = lfm.Int4X4Uv;
|
||||
|
||||
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r += 2)
|
||||
@@ -1806,16 +1875,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
int sbCols = TileInfo.MiColsAlignedToSb(cm.MiCols) >> Constants.MiBlockSizeLog2;
|
||||
LfPath path;
|
||||
int miRow, miCol;
|
||||
Span<MacroBlockDPlane> planesSpan = planes.AsSpan();
|
||||
|
||||
if (yOnly)
|
||||
{
|
||||
path = LfPath.LfPath444;
|
||||
}
|
||||
else if (planes[1].SubsamplingY == 1 && planes[1].SubsamplingX == 1)
|
||||
else if (planesSpan[1].SubsamplingY == 1 && planesSpan[1].SubsamplingX == 1)
|
||||
{
|
||||
path = LfPath.LfPath420;
|
||||
}
|
||||
else if (planes[1].SubsamplingY == 0 && planes[1].SubsamplingX == 0)
|
||||
else if (planesSpan[1].SubsamplingY == 0 && planesSpan[1].SubsamplingX == 0)
|
||||
{
|
||||
path = LfPath.LfPath444;
|
||||
}
|
||||
@@ -1837,23 +1907,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
lfSync.SyncRead(r, c);
|
||||
|
||||
ReconInter.SetupDstPlanes(ref planes, ref frameBuffer, miRow, miCol);
|
||||
ReconInter.SetupDstPlanes(planesSpan, ref frameBuffer, miRow, miCol);
|
||||
|
||||
AdjustMask(ref cm, miRow, miCol, ref lfm[0]);
|
||||
|
||||
FilterBlockPlaneSs00(ref cm, ref planes[0], miRow, ref lfm[0]);
|
||||
FilterBlockPlaneSs00(ref cm, ref planesSpan[0], miRow, ref lfm[0]);
|
||||
for (plane = 1; plane < numPlanes; ++plane)
|
||||
{
|
||||
switch (path)
|
||||
{
|
||||
case LfPath.LfPath420:
|
||||
FilterBlockPlaneSs11(ref cm, ref planes[plane], miRow, ref lfm[0]);
|
||||
FilterBlockPlaneSs11(ref cm, ref planesSpan[plane], miRow, ref lfm[0]);
|
||||
break;
|
||||
case LfPath.LfPath444:
|
||||
FilterBlockPlaneSs00(ref cm, ref planes[plane], miRow, ref lfm[0]);
|
||||
FilterBlockPlaneSs00(ref cm, ref planesSpan[plane], miRow, ref lfm[0]);
|
||||
break;
|
||||
case LfPath.LfPathSlow:
|
||||
FilterBlockPlaneNon420(ref cm, ref planes[plane], mi.Slice(miCol), miRow,
|
||||
FilterBlockPlaneNon420(ref cm, ref planesSpan[plane], mi.Slice(miCol), miRow,
|
||||
miCol);
|
||||
break;
|
||||
}
|
||||
|
@@ -270,17 +270,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
private static Array8<short> NewArray8Short(short e0, short e1, short e2, short e3, short e4, short e5, short e6, short e7)
|
||||
{
|
||||
Array8<short> output = new()
|
||||
{
|
||||
[0] = e0,
|
||||
[1] = e1,
|
||||
[2] = e2,
|
||||
[3] = e3,
|
||||
[4] = e4,
|
||||
[5] = e5,
|
||||
[6] = e6,
|
||||
[7] = e7
|
||||
};
|
||||
Array8<short> output = new();
|
||||
Span<short> outputSpan = output.AsSpan();
|
||||
outputSpan[0] = e0;
|
||||
outputSpan[1] = e1;
|
||||
outputSpan[2] = e2;
|
||||
outputSpan[3] = e3;
|
||||
outputSpan[4] = e4;
|
||||
outputSpan[5] = e5;
|
||||
outputSpan[6] = e6;
|
||||
outputSpan[7] = e7;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
@@ -109,15 +110,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
sbyte vrfa = aSg ? xd.AboveMi.Value.RefFrame[0] : xd.AboveMi.Value.RefFrame[varRefIdx];
|
||||
sbyte vrfl = lSg ? xd.LeftMi.Value.RefFrame[0] : xd.LeftMi.Value.RefFrame[varRefIdx];
|
||||
|
||||
if (vrfa == vrfl && cm.CompVarRef[1] == vrfa)
|
||||
Span<sbyte> compVarRefSpan = cm.CompVarRef.AsSpan();
|
||||
|
||||
if (vrfa == vrfl && compVarRefSpan[1] == vrfa)
|
||||
{
|
||||
predContext = 0;
|
||||
}
|
||||
else if (lSg && aSg)
|
||||
{
|
||||
// Single/Single
|
||||
if ((vrfa == cm.CompFixedRef && vrfl == cm.CompVarRef[0]) ||
|
||||
(vrfl == cm.CompFixedRef && vrfa == cm.CompVarRef[0]))
|
||||
if ((vrfa == cm.CompFixedRef && vrfl == compVarRefSpan[0]) ||
|
||||
(vrfl == cm.CompFixedRef && vrfa == compVarRefSpan[0]))
|
||||
{
|
||||
predContext = 4;
|
||||
}
|
||||
@@ -135,11 +138,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Single/Comp
|
||||
sbyte vrfc = lSg ? vrfa : vrfl;
|
||||
sbyte rfs = aSg ? vrfa : vrfl;
|
||||
if (vrfc == cm.CompVarRef[1] && rfs != cm.CompVarRef[1])
|
||||
if (vrfc == compVarRefSpan[1] && rfs != compVarRefSpan[1])
|
||||
{
|
||||
predContext = 1;
|
||||
}
|
||||
else if (rfs == cm.CompVarRef[1] && vrfc != cm.CompVarRef[1])
|
||||
else if (rfs == compVarRefSpan[1] && vrfc != compVarRefSpan[1])
|
||||
{
|
||||
predContext = 2;
|
||||
}
|
||||
@@ -212,14 +215,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
// Intra/Inter or Inter/Intra
|
||||
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
||||
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||
if (!edgeMi.HasSecondRef())
|
||||
{
|
||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.LastFrame ? 1 : 0);
|
||||
predContext = 4 * (refFrameSpan[0] == Constants.LastFrame ? 1 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
|
||||
edgeMi.RefFrame[1] == Constants.LastFrame
|
||||
predContext = 1 + (refFrameSpan[0] == Constants.LastFrame ||
|
||||
refFrameSpan[1] == Constants.LastFrame
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
@@ -229,10 +233,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Inter/Inter
|
||||
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
||||
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
||||
sbyte above0 = xd.AboveMi.Value.RefFrame[0];
|
||||
sbyte above1 = xd.AboveMi.Value.RefFrame[1];
|
||||
sbyte left0 = xd.LeftMi.Value.RefFrame[0];
|
||||
sbyte left1 = xd.LeftMi.Value.RefFrame[1];
|
||||
Span<sbyte> aRefFrameSpan = xd.AboveMi.Value.RefFrame.AsSpan();
|
||||
sbyte above0 = aRefFrameSpan[0];
|
||||
sbyte above1 = aRefFrameSpan[1];
|
||||
Span<sbyte> lRefFrameSpan = xd.LeftMi.Value.RefFrame.AsSpan();
|
||||
sbyte left0 = lRefFrameSpan[0];
|
||||
sbyte left1 = lRefFrameSpan[1];
|
||||
|
||||
if (aboveHasSecond && leftHasSecond)
|
||||
{
|
||||
@@ -281,8 +287,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
|
||||
edgeMi.RefFrame[1] == Constants.LastFrame
|
||||
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||
|
||||
predContext = 1 + (refFrameSpan[0] == Constants.LastFrame ||
|
||||
refFrameSpan[1] == Constants.LastFrame
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
@@ -321,21 +329,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
// Intra/Inter or Inter/Intra
|
||||
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
||||
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||
if (!edgeMi.HasSecondRef())
|
||||
{
|
||||
if (edgeMi.RefFrame[0] == Constants.LastFrame)
|
||||
if (refFrameSpan[0] == Constants.LastFrame)
|
||||
{
|
||||
predContext = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
|
||||
predContext = 4 * (refFrameSpan[0] == Constants.GoldenFrame ? 1 : 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 1 + (2 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
|
||||
edgeMi.RefFrame[1] == Constants.GoldenFrame
|
||||
predContext = 1 + (2 * (refFrameSpan[0] == Constants.GoldenFrame ||
|
||||
refFrameSpan[1] == Constants.GoldenFrame
|
||||
? 1
|
||||
: 0));
|
||||
}
|
||||
@@ -345,10 +354,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Inter/Inter
|
||||
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
||||
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
||||
sbyte above0 = xd.AboveMi.Value.RefFrame[0];
|
||||
sbyte above1 = xd.AboveMi.Value.RefFrame[1];
|
||||
sbyte left0 = xd.LeftMi.Value.RefFrame[0];
|
||||
sbyte left1 = xd.LeftMi.Value.RefFrame[1];
|
||||
Span<sbyte> aRefFrameSpan = xd.AboveMi.Value.RefFrame.AsSpan();
|
||||
sbyte above0 = aRefFrameSpan[0];
|
||||
sbyte above1 = aRefFrameSpan[1];
|
||||
Span<sbyte> lRefFrameSpan = xd.LeftMi.Value.RefFrame.AsSpan();
|
||||
sbyte left0 = lRefFrameSpan[0];
|
||||
sbyte left1 = lRefFrameSpan[1];
|
||||
|
||||
if (aboveHasSecond && leftHasSecond)
|
||||
{
|
||||
@@ -407,19 +418,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
// One edge available
|
||||
ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
|
||||
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||
|
||||
if (!edgeMi.IsInterBlock() || (edgeMi.RefFrame[0] == Constants.LastFrame && !edgeMi.HasSecondRef()))
|
||||
if (!edgeMi.IsInterBlock() || (refFrameSpan[0] == Constants.LastFrame && !edgeMi.HasSecondRef()))
|
||||
{
|
||||
predContext = 2;
|
||||
}
|
||||
else if (!edgeMi.HasSecondRef())
|
||||
{
|
||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
|
||||
predContext = 4 * (refFrameSpan[0] == Constants.GoldenFrame ? 1 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 3 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
|
||||
edgeMi.RefFrame[1] == Constants.GoldenFrame
|
||||
predContext = 3 * (refFrameSpan[0] == Constants.GoldenFrame ||
|
||||
refFrameSpan[1] == Constants.GoldenFrame
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
return (byte)BitUtils.RoundPowerOfTwo((prob1 * (256 - factor)) + (prob2 * factor), 8);
|
||||
}
|
||||
|
||||
public static byte MergeProbs(byte preProb, ref Array2<uint> ct, uint countSat, uint maxUpdateFactor)
|
||||
public static byte MergeProbs(byte preProb, ReadOnlySpan<uint> ct, uint countSat, uint maxUpdateFactor)
|
||||
{
|
||||
byte prob = GetBinaryProb(ct[0], ct[1]);
|
||||
uint count = Math.Min(ct[0] + ct[1], countSat);
|
||||
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
private const int ModeMvCountSat = 20;
|
||||
|
||||
public static byte ModeMvMergeProbs(byte preProb, ref Array2<uint> ct)
|
||||
public static byte ModeMvMergeProbs(byte preProb, ReadOnlySpan<uint> ct)
|
||||
{
|
||||
uint den = ct[0] + ct[1];
|
||||
if (den == 0)
|
||||
@@ -81,7 +81,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
Array2<uint> ct = new();
|
||||
ct[0] = leftCount;
|
||||
ct[1] = rightCount;
|
||||
probs[(int)(i >> 1)] = ModeMvMergeProbs(preProbs[(int)(i >> 1)], ref ct);
|
||||
probs[(int)(i >> 1)] = ModeMvMergeProbs(preProbs[(int)(i >> 1)], ct.AsSpan());
|
||||
return leftCount + rightCount;
|
||||
}
|
||||
|
||||
|
@@ -164,7 +164,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
public static void SetupDstPlanes(
|
||||
ref Array3<MacroBlockDPlane> planes,
|
||||
Span<MacroBlockDPlane> planes,
|
||||
ref Surface src,
|
||||
int miRow,
|
||||
int miCol)
|
||||
@@ -205,9 +205,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
strides[1] = src.UvStride;
|
||||
strides[2] = src.UvStride;
|
||||
|
||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[i];
|
||||
ref MacroBlockDPlane pd = ref planeSpan[i];
|
||||
SetupPredPlanes(ref pd.Pre[idx], buffers[i], strides[i], miRow, miCol, sf, pd.SubsamplingX,
|
||||
pd.SubsamplingY);
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
@@ -28,13 +29,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
ModeRefDeltaEnabled = true;
|
||||
ModeRefDeltaUpdate = true;
|
||||
|
||||
Span<sbyte> refDeltasSpan = RefDeltas.AsSpan();
|
||||
Span<sbyte> modeDeltasSpan = ModeDeltas.AsSpan();
|
||||
|
||||
RefDeltas[Constants.IntraFrame] = 1;
|
||||
RefDeltas[Constants.LastFrame] = 0;
|
||||
RefDeltas[Constants.GoldenFrame] = -1;
|
||||
RefDeltas[Constants.AltRefFrame] = -1;
|
||||
ModeDeltas[0] = 0;
|
||||
ModeDeltas[1] = 0;
|
||||
refDeltasSpan[Constants.IntraFrame] = 1;
|
||||
refDeltasSpan[Constants.LastFrame] = 0;
|
||||
refDeltasSpan[Constants.GoldenFrame] = -1;
|
||||
refDeltasSpan[Constants.AltRefFrame] = -1;
|
||||
modeDeltasSpan[0] = 0;
|
||||
modeDeltasSpan[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
@@ -147,10 +148,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
public void SetupBlockPlanes(int ssX, int ssY)
|
||||
{
|
||||
Span<MacroBlockDPlane> planeSpan = Plane.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||
{
|
||||
Plane[i].SubsamplingX = i != 0 ? ssX : 0;
|
||||
Plane[i].SubsamplingY = i != 0 ? ssY : 0;
|
||||
planeSpan[i].SubsamplingX = i != 0 ? ssX : 0;
|
||||
planeSpan[i].SubsamplingY = i != 0 ? ssY : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,12 +161,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
int aboveIdx = miCol * 2;
|
||||
int leftIdx = (miRow * 2) & 15;
|
||||
|
||||
Span<MacroBlockDPlane> planeSpan = Plane.AsSpan();
|
||||
Span<ArrayPtr<sbyte>> aboveContextSpan = AboveContext.AsSpan();
|
||||
Span<Array16<sbyte>> leftContextSpan = LeftContext.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref Plane[i];
|
||||
pd.AboveContext = AboveContext[i].Slice(aboveIdx >> pd.SubsamplingX);
|
||||
pd.LeftContext = new ArrayPtr<sbyte>(ref LeftContext[i][leftIdx >> pd.SubsamplingY],
|
||||
ref MacroBlockDPlane pd = ref planeSpan[i];
|
||||
pd.AboveContext = aboveContextSpan[i].Slice(aboveIdx >> pd.SubsamplingX);
|
||||
pd.LeftContext = new ArrayPtr<sbyte>(ref leftContextSpan[i][leftIdx >> pd.SubsamplingY],
|
||||
16 - (leftIdx >> pd.SubsamplingY));
|
||||
}
|
||||
}
|
||||
@@ -182,9 +189,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
public unsafe void DecResetSkipContext()
|
||||
{
|
||||
Span<MacroBlockDPlane> planeSpan = Plane.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref Plane[i];
|
||||
ref MacroBlockDPlane pd = ref planeSpan[i];
|
||||
MemoryUtil.Fill(pd.AboveContext.ToPointer(), (sbyte)0, pd.N4W);
|
||||
MemoryUtil.Fill(pd.LeftContext.ToPointer(), (sbyte)0, pd.N4H);
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
@@ -65,36 +66,41 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
public Mv MvPredQ4(int idx)
|
||||
{
|
||||
Span<BModeInfo> bmiSpan = Bmi.AsSpan();
|
||||
|
||||
Mv res = new()
|
||||
{
|
||||
Row = (short)ReconInter.RoundMvCompQ4(
|
||||
Bmi[0].Mv[idx].Row + Bmi[1].Mv[idx].Row +
|
||||
Bmi[2].Mv[idx].Row + Bmi[3].Mv[idx].Row),
|
||||
bmiSpan[0].Mv[idx].Row + bmiSpan[1].Mv[idx].Row +
|
||||
bmiSpan[2].Mv[idx].Row + bmiSpan[3].Mv[idx].Row),
|
||||
Col = (short)ReconInter.RoundMvCompQ4(
|
||||
Bmi[0].Mv[idx].Col + Bmi[1].Mv[idx].Col +
|
||||
Bmi[2].Mv[idx].Col + Bmi[3].Mv[idx].Col)
|
||||
bmiSpan[0].Mv[idx].Col + bmiSpan[1].Mv[idx].Col +
|
||||
bmiSpan[2].Mv[idx].Col + bmiSpan[3].Mv[idx].Col)
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
public Mv MvPredQ2(int idx, int block0, int block1)
|
||||
{
|
||||
Span<BModeInfo> bmiSpan = Bmi.AsSpan();
|
||||
|
||||
Mv res = new()
|
||||
{
|
||||
Row = (short)ReconInter.RoundMvCompQ2(
|
||||
Bmi[block0].Mv[idx].Row +
|
||||
Bmi[block1].Mv[idx].Row),
|
||||
bmiSpan[block0].Mv[idx].Row +
|
||||
bmiSpan[block1].Mv[idx].Row),
|
||||
Col = (short)ReconInter.RoundMvCompQ2(
|
||||
Bmi[block0].Mv[idx].Col +
|
||||
Bmi[block1].Mv[idx].Col)
|
||||
bmiSpan[block0].Mv[idx].Col +
|
||||
bmiSpan[block1].Mv[idx].Col)
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
// Performs mv sign inversion if indicated by the reference frame combination.
|
||||
public Mv ScaleMv(int refr, sbyte thisRefFrame, ref Array4<sbyte> refSignBias)
|
||||
public Mv ScaleMv(int refr, sbyte thisRefFrame, Span<sbyte> refSignBias)
|
||||
{
|
||||
Mv mv = Mv[refr];
|
||||
|
||||
if (refSignBias[RefFrame[refr]] != refSignBias[thisRefFrame])
|
||||
{
|
||||
mv.Row *= -1;
|
||||
|
@@ -99,10 +99,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
}
|
||||
else
|
||||
{
|
||||
Span<Array2<uint>> bitsSpan = counts.Bits[comp].AsSpan();
|
||||
|
||||
int b = c + Constants.Class0Bits - 1; // Number of bits
|
||||
for (int i = 0; i < b; ++i)
|
||||
{
|
||||
counts.Bits[comp][i][(d >> i) & 1] += (uint)incr;
|
||||
bitsSpan[i][(d >> i) & 1] += (uint)incr;
|
||||
}
|
||||
|
||||
counts.Fp[comp][f] += (uint)incr;
|
||||
|
@@ -29,7 +29,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
public Array8<uint> FeatureMask;
|
||||
public int AqAvOffset;
|
||||
|
||||
public static byte GetPredProbSegId(ref Array3<byte> segPredProbs, ref MacroBlockD xd)
|
||||
public static byte GetPredProbSegId(ReadOnlySpan<byte> segPredProbs, ref MacroBlockD xd)
|
||||
{
|
||||
return segPredProbs[xd.GetPredContextSegId()];
|
||||
}
|
||||
@@ -105,9 +105,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
UpdateMap = rb.ReadBit() != 0;
|
||||
if (UpdateMap)
|
||||
{
|
||||
Span<byte> segTreeProbSpan = fc.SegTreeProb.AsSpan();
|
||||
Span<byte> segPredProbSpan = fc.SegPredProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < SegTreeProbs; i++)
|
||||
{
|
||||
fc.SegTreeProb[i] = rb.ReadBit() != 0
|
||||
segTreeProbSpan[i] = rb.ReadBit() != 0
|
||||
? (byte)rb.ReadLiteral(8)
|
||||
: (byte)Prob.MaxProb;
|
||||
}
|
||||
@@ -117,7 +120,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
for (int i = 0; i < PredictionProbs; i++)
|
||||
{
|
||||
fc.SegPredProb[i] = rb.ReadBit() != 0
|
||||
segPredProbSpan[i] = rb.ReadBit() != 0
|
||||
? (byte)rb.ReadLiteral(8)
|
||||
: (byte)Prob.MaxProb;
|
||||
}
|
||||
@@ -126,7 +129,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
for (int i = 0; i < PredictionProbs; i++)
|
||||
{
|
||||
fc.SegPredProb[i] = Prob.MaxProb;
|
||||
segPredProbSpan[i] = Prob.MaxProb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -155,9 +155,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
public bool CompoundReferenceAllowed()
|
||||
{
|
||||
Span<sbyte> refFrameSignBiasSpan = RefFrameSignBias.AsSpan();
|
||||
|
||||
for (int i = 1; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
if (RefFrameSignBias[i + 1] != RefFrameSignBias[1])
|
||||
if (refFrameSignBiasSpan[i + 1] != refFrameSignBiasSpan[1])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -173,13 +175,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
public readonly int GetFreeFb()
|
||||
{
|
||||
ref Array12<RefCntBuffer> frameBufs = ref BufferPool.Value.FrameBufs;
|
||||
Span<RefCntBuffer> frameBuffs = BufferPool.Value.FrameBufs.AsSpan();
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < Constants.FrameBuffers; ++i)
|
||||
{
|
||||
if (frameBufs[i].RefCount == 0)
|
||||
if (frameBuffs[i].RefCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -187,7 +189,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
if (i != Constants.FrameBuffers)
|
||||
{
|
||||
frameBufs[i].RefCount = 1;
|
||||
frameBuffs[i].RefCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -240,25 +242,29 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
private void AllocSegMap(MemoryAllocator allocator, int segMapSize)
|
||||
{
|
||||
Span<ArrayPtr<byte>> segMapArraySpan = SegMapArray.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
|
||||
{
|
||||
SegMapArray[i] = allocator.Allocate<byte>(segMapSize);
|
||||
segMapArraySpan[i] = allocator.Allocate<byte>(segMapSize);
|
||||
}
|
||||
|
||||
// Init the index.
|
||||
SegMapIdx = 0;
|
||||
PrevSegMapIdx = 1;
|
||||
|
||||
CurrentFrameSegMap = SegMapArray[SegMapIdx];
|
||||
LastFrameSegMap = SegMapArray[PrevSegMapIdx];
|
||||
CurrentFrameSegMap = segMapArraySpan[SegMapIdx];
|
||||
LastFrameSegMap = segMapArraySpan[PrevSegMapIdx];
|
||||
}
|
||||
|
||||
private void FreeSegMap(MemoryAllocator allocator)
|
||||
{
|
||||
Span<ArrayPtr<byte>> segMapArraySpan = SegMapArray.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.NumPingPongBuffers; ++i)
|
||||
{
|
||||
allocator.Free(SegMapArray[i]);
|
||||
SegMapArray[i] = ArrayPtr<byte>.Null;
|
||||
allocator.Free(segMapArraySpan[i]);
|
||||
segMapArraySpan[i] = ArrayPtr<byte>.Null;
|
||||
}
|
||||
|
||||
CurrentFrameSegMap = ArrayPtr<byte>.Null;
|
||||
@@ -366,18 +372,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
internal void InitMacroBlockD(ref MacroBlockD xd, ArrayPtr<int> dqcoeff)
|
||||
{
|
||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||
Span<ArrayPtr<sbyte>> aboveContextSpan = xd.AboveContext.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
||||
{
|
||||
xd.Plane[i].DqCoeff = dqcoeff;
|
||||
xd.AboveContext[i] = AboveContext.Slice(i * 2 * TileInfo.MiColsAlignedToSb(MiCols));
|
||||
planeSpan[i].DqCoeff = dqcoeff;
|
||||
aboveContextSpan[i] = AboveContext.Slice(i * 2 * TileInfo.MiColsAlignedToSb(MiCols));
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
MemoryUtil.Copy(ref xd.Plane[i].SegDequant, ref YDequant);
|
||||
MemoryUtil.Copy(ref planeSpan[i].SegDequant, ref YDequant);
|
||||
}
|
||||
else
|
||||
{
|
||||
MemoryUtil.Copy(ref xd.Plane[i].SegDequant, ref UvDequant);
|
||||
MemoryUtil.Copy(ref planeSpan[i].SegDequant, ref UvDequant);
|
||||
}
|
||||
|
||||
xd.Fc = new Ptr<Vp9EntropyProbs>(ref Fc.Value);
|
||||
@@ -395,32 +404,43 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
// Build y/uv dequant values based on segmentation.
|
||||
if (Seg.Enabled)
|
||||
{
|
||||
Span<Array2<short>> yDequantSpan1 = YDequant.AsSpan();
|
||||
Span<Array2<short>> uvDequantSpan1 = UvDequant.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.MaxSegments; ++i)
|
||||
{
|
||||
Span<short> yDequantSpan2 = yDequantSpan1[i].AsSpan();
|
||||
Span<short> uvDequantSpan2 = uvDequantSpan1[i].AsSpan();
|
||||
|
||||
int qindex = Seg.GetQIndex(i, BaseQindex);
|
||||
YDequant[i][0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
||||
YDequant[i][1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
||||
UvDequant[i][0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
||||
UvDequant[i][1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
||||
yDequantSpan2[0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
||||
yDequantSpan2[1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
||||
uvDequantSpan2[0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
||||
uvDequantSpan2[1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Span<short> yDequantSpan = YDequant[0].AsSpan();
|
||||
Span<short> uvDequantSpan = UvDequant[0].AsSpan();
|
||||
|
||||
int qindex = BaseQindex;
|
||||
// When segmentation is disabled, only the first value is used. The
|
||||
// remaining are don't cares.
|
||||
YDequant[0][0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
||||
YDequant[0][1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
||||
UvDequant[0][0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
||||
UvDequant[0][1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
||||
yDequantSpan[0] = QuantCommon.DcQuant(qindex, YDcDeltaQ, BitDepth);
|
||||
yDequantSpan[1] = QuantCommon.AcQuant(qindex, 0, BitDepth);
|
||||
uvDequantSpan[0] = QuantCommon.DcQuant(qindex, UvDcDeltaQ, BitDepth);
|
||||
uvDequantSpan[1] = QuantCommon.AcQuant(qindex, UvAcDeltaQ, BitDepth);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetupScaleFactors()
|
||||
{
|
||||
Span<RefBuffer> frameRefsSpan = FrameRefs.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
ref RefBuffer refBuf = ref FrameRefs[i];
|
||||
ref RefBuffer refBuf = ref frameRefsSpan[i];
|
||||
refBuf.Sf.SetupScaleFactorsForFrame(refBuf.Buf.Width, refBuf.Buf.Height, Width, Height);
|
||||
}
|
||||
}
|
||||
@@ -431,26 +451,34 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
if (ReferenceMode == ReferenceMode.Select)
|
||||
{
|
||||
Span<byte> compInterProbSpan = fc.CompInterProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.CompInterContexts; ++i)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.CompInterProb[i]);
|
||||
r.DiffUpdateProb(ref compInterProbSpan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (ReferenceMode != ReferenceMode.Compound)
|
||||
{
|
||||
Span<Array2<byte>> singleRefProbSpan1 = fc.SingleRefProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.RefContexts; ++i)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.SingleRefProb[i][0]);
|
||||
r.DiffUpdateProb(ref fc.SingleRefProb[i][1]);
|
||||
Span<byte> singleRefProbSpan2 = singleRefProbSpan1[i].AsSpan();
|
||||
|
||||
r.DiffUpdateProb(ref singleRefProbSpan2[0]);
|
||||
r.DiffUpdateProb(ref singleRefProbSpan2[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (ReferenceMode != ReferenceMode.Single)
|
||||
{
|
||||
Span<byte> compRefProbSpan = fc.CompRefProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.RefContexts; ++i)
|
||||
{
|
||||
r.DiffUpdateProb(ref fc.CompRefProb[i]);
|
||||
r.DiffUpdateProb(ref compRefProbSpan[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -469,99 +497,124 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
public void SetupCompoundReferenceMode()
|
||||
{
|
||||
if (RefFrameSignBias[Constants.LastFrame] == RefFrameSignBias[Constants.GoldenFrame])
|
||||
Span<sbyte> refFrameSignBiasSpan = RefFrameSignBias.AsSpan();
|
||||
Span<sbyte> compVarRefSpan = CompVarRef.AsSpan();
|
||||
|
||||
if (refFrameSignBiasSpan[Constants.LastFrame] == refFrameSignBiasSpan[Constants.GoldenFrame])
|
||||
{
|
||||
CompFixedRef = Constants.AltRefFrame;
|
||||
CompVarRef[0] = Constants.LastFrame;
|
||||
CompVarRef[1] = Constants.GoldenFrame;
|
||||
compVarRefSpan[0] = Constants.LastFrame;
|
||||
compVarRefSpan[1] = Constants.GoldenFrame;
|
||||
}
|
||||
else if (RefFrameSignBias[Constants.LastFrame] == RefFrameSignBias[Constants.AltRefFrame])
|
||||
else if (refFrameSignBiasSpan[Constants.LastFrame] == refFrameSignBiasSpan[Constants.AltRefFrame])
|
||||
{
|
||||
CompFixedRef = Constants.GoldenFrame;
|
||||
CompVarRef[0] = Constants.LastFrame;
|
||||
CompVarRef[1] = Constants.AltRefFrame;
|
||||
compVarRefSpan[0] = Constants.LastFrame;
|
||||
compVarRefSpan[1] = Constants.AltRefFrame;
|
||||
}
|
||||
else
|
||||
{
|
||||
CompFixedRef = Constants.LastFrame;
|
||||
CompVarRef[0] = Constants.GoldenFrame;
|
||||
CompVarRef[1] = Constants.AltRefFrame;
|
||||
compVarRefSpan[0] = Constants.GoldenFrame;
|
||||
compVarRefSpan[1] = Constants.AltRefFrame;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly void InitMvProbs()
|
||||
{
|
||||
Fc.Value.Joints[0] = 32;
|
||||
Fc.Value.Joints[1] = 64;
|
||||
Fc.Value.Joints[2] = 96;
|
||||
Span<byte> jointsSpan = Fc.Value.Joints.AsSpan();
|
||||
Span<byte> signSpan = Fc.Value.Sign.AsSpan();
|
||||
Span<Array10<byte>> classesSpan = Fc.Value.Classes.AsSpan();
|
||||
Span<byte> classes0Span = classesSpan[0].AsSpan();
|
||||
Span<byte> classes1Span = classesSpan[1].AsSpan();
|
||||
Span<Array1<byte>> class0Span = Fc.Value.Class0.AsSpan();
|
||||
Span<Array10<byte>> bitsSpan = Fc.Value.Bits.AsSpan();
|
||||
Span<byte> bits0Span = bitsSpan[0].AsSpan();
|
||||
Span<byte> bits1Span = bitsSpan[1].AsSpan();
|
||||
Span<Array2<Array3<byte>>> class0FpSpan = Fc.Value.Class0Fp.AsSpan();
|
||||
Span<Array3<byte>> class0Fp0Span = class0FpSpan[0].AsSpan();
|
||||
Span<Array3<byte>> class0Fp1Span = class0FpSpan[1].AsSpan();
|
||||
Span<byte> class0Fp00Span = class0Fp0Span[0].AsSpan();
|
||||
Span<byte> class0Fp01Span = class0Fp0Span[1].AsSpan();
|
||||
Span<byte> class0Fp10Span = class0Fp1Span[0].AsSpan();
|
||||
Span<byte> class0Fp11Span = class0Fp1Span[1].AsSpan();
|
||||
Span<Array3<byte>> fpSpan = Fc.Value.Fp.AsSpan();
|
||||
Span<byte> fp0Span = fpSpan[0].AsSpan();
|
||||
Span<byte> fp1Span = fpSpan[1].AsSpan();
|
||||
Span<byte> class0HpSpan = Fc.Value.Class0Hp.AsSpan();
|
||||
Span<byte> hpSpan = Fc.Value.Hp.AsSpan();
|
||||
|
||||
jointsSpan[0] = 32;
|
||||
jointsSpan[1] = 64;
|
||||
jointsSpan[2] = 96;
|
||||
|
||||
Fc.Value.Sign[0] = 128;
|
||||
Fc.Value.Classes[0][0] = 224;
|
||||
Fc.Value.Classes[0][1] = 144;
|
||||
Fc.Value.Classes[0][2] = 192;
|
||||
Fc.Value.Classes[0][3] = 168;
|
||||
Fc.Value.Classes[0][4] = 192;
|
||||
Fc.Value.Classes[0][5] = 176;
|
||||
Fc.Value.Classes[0][6] = 192;
|
||||
Fc.Value.Classes[0][7] = 198;
|
||||
Fc.Value.Classes[0][8] = 198;
|
||||
Fc.Value.Classes[0][9] = 245;
|
||||
Fc.Value.Class0[0][0] = 216;
|
||||
Fc.Value.Bits[0][0] = 136;
|
||||
Fc.Value.Bits[0][1] = 140;
|
||||
Fc.Value.Bits[0][2] = 148;
|
||||
Fc.Value.Bits[0][3] = 160;
|
||||
Fc.Value.Bits[0][4] = 176;
|
||||
Fc.Value.Bits[0][5] = 192;
|
||||
Fc.Value.Bits[0][6] = 224;
|
||||
Fc.Value.Bits[0][7] = 234;
|
||||
Fc.Value.Bits[0][8] = 234;
|
||||
Fc.Value.Bits[0][9] = 240;
|
||||
Fc.Value.Class0Fp[0][0][0] = 128;
|
||||
Fc.Value.Class0Fp[0][0][1] = 128;
|
||||
Fc.Value.Class0Fp[0][0][2] = 64;
|
||||
Fc.Value.Class0Fp[0][1][0] = 96;
|
||||
Fc.Value.Class0Fp[0][1][1] = 112;
|
||||
Fc.Value.Class0Fp[0][1][2] = 64;
|
||||
Fc.Value.Fp[0][0] = 64;
|
||||
Fc.Value.Fp[0][1] = 96;
|
||||
Fc.Value.Fp[0][2] = 64;
|
||||
Fc.Value.Class0Hp[0] = 160;
|
||||
Fc.Value.Hp[0] = 128;
|
||||
signSpan[0] = 128;
|
||||
classes0Span[0] = 224;
|
||||
classes0Span[1] = 144;
|
||||
classes0Span[2] = 192;
|
||||
classes0Span[3] = 168;
|
||||
classes0Span[4] = 192;
|
||||
classes0Span[5] = 176;
|
||||
classes0Span[6] = 192;
|
||||
classes0Span[7] = 198;
|
||||
classes0Span[8] = 198;
|
||||
classes0Span[9] = 245;
|
||||
class0Span[0][0] = 216;
|
||||
bits0Span[0] = 136;
|
||||
bits0Span[1] = 140;
|
||||
bits0Span[2] = 148;
|
||||
bits0Span[3] = 160;
|
||||
bits0Span[4] = 176;
|
||||
bits0Span[5] = 192;
|
||||
bits0Span[6] = 224;
|
||||
bits0Span[7] = 234;
|
||||
bits0Span[8] = 234;
|
||||
bits0Span[9] = 240;
|
||||
class0Fp00Span[0] = 128;
|
||||
class0Fp00Span[1] = 128;
|
||||
class0Fp00Span[2] = 64;
|
||||
class0Fp01Span[0] = 96;
|
||||
class0Fp01Span[1] = 112;
|
||||
class0Fp01Span[2] = 64;
|
||||
fp0Span[0] = 64;
|
||||
fp0Span[1] = 96;
|
||||
fp0Span[2] = 64;
|
||||
class0HpSpan[0] = 160;
|
||||
hpSpan[0] = 128;
|
||||
|
||||
Fc.Value.Sign[1] = 128;
|
||||
Fc.Value.Classes[1][0] = 216;
|
||||
Fc.Value.Classes[1][1] = 128;
|
||||
Fc.Value.Classes[1][2] = 176;
|
||||
Fc.Value.Classes[1][3] = 160;
|
||||
Fc.Value.Classes[1][4] = 176;
|
||||
Fc.Value.Classes[1][5] = 176;
|
||||
Fc.Value.Classes[1][6] = 192;
|
||||
Fc.Value.Classes[1][7] = 198;
|
||||
Fc.Value.Classes[1][8] = 198;
|
||||
Fc.Value.Classes[1][9] = 208;
|
||||
Fc.Value.Class0[1][0] = 208;
|
||||
Fc.Value.Bits[1][0] = 136;
|
||||
Fc.Value.Bits[1][1] = 140;
|
||||
Fc.Value.Bits[1][2] = 148;
|
||||
Fc.Value.Bits[1][3] = 160;
|
||||
Fc.Value.Bits[1][4] = 176;
|
||||
Fc.Value.Bits[1][5] = 192;
|
||||
Fc.Value.Bits[1][6] = 224;
|
||||
Fc.Value.Bits[1][7] = 234;
|
||||
Fc.Value.Bits[1][8] = 234;
|
||||
Fc.Value.Bits[1][9] = 240;
|
||||
Fc.Value.Class0Fp[1][0][0] = 128;
|
||||
Fc.Value.Class0Fp[1][0][1] = 128;
|
||||
Fc.Value.Class0Fp[1][0][2] = 64;
|
||||
Fc.Value.Class0Fp[1][1][0] = 96;
|
||||
Fc.Value.Class0Fp[1][1][1] = 112;
|
||||
Fc.Value.Class0Fp[1][1][2] = 64;
|
||||
Fc.Value.Fp[1][0] = 64;
|
||||
Fc.Value.Fp[1][1] = 96;
|
||||
Fc.Value.Fp[1][2] = 64;
|
||||
Fc.Value.Class0Hp[1] = 160;
|
||||
Fc.Value.Hp[1] = 128;
|
||||
signSpan[1] = 128;
|
||||
classes1Span[0] = 216;
|
||||
classes1Span[1] = 128;
|
||||
classes1Span[2] = 176;
|
||||
classes1Span[3] = 160;
|
||||
classes1Span[4] = 176;
|
||||
classes1Span[5] = 176;
|
||||
classes1Span[6] = 192;
|
||||
classes1Span[7] = 198;
|
||||
classes1Span[8] = 198;
|
||||
classes1Span[9] = 208;
|
||||
class0Span[1][0] = 208;
|
||||
bits1Span[0] = 136;
|
||||
bits1Span[1] = 140;
|
||||
bits1Span[2] = 148;
|
||||
bits1Span[3] = 160;
|
||||
bits1Span[4] = 176;
|
||||
bits1Span[5] = 192;
|
||||
bits1Span[6] = 224;
|
||||
bits1Span[7] = 234;
|
||||
bits1Span[8] = 234;
|
||||
bits1Span[9] = 240;
|
||||
class0Fp10Span[0] = 128;
|
||||
class0Fp10Span[1] = 128;
|
||||
class0Fp10Span[2] = 64;
|
||||
class0Fp11Span[0] = 96;
|
||||
class0Fp11Span[1] = 112;
|
||||
class0Fp11Span[2] = 64;
|
||||
fp1Span[0] = 64;
|
||||
fp1Span[1] = 96;
|
||||
fp1Span[2] = 64;
|
||||
class0HpSpan[1] = 160;
|
||||
hpSpan[1] = 128;
|
||||
}
|
||||
|
||||
public void AdaptMvProbs(bool allowHp)
|
||||
@@ -576,41 +629,74 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
counts.Joints.AsSpan(),
|
||||
fc.Joints.AsSpan());
|
||||
|
||||
Span<byte> fSignSpan = fc.Sign.AsSpan();
|
||||
Span<byte> pSignSpan = preFc.Sign.AsSpan();
|
||||
Span<Array2<uint>> cSignSpan = counts.Sign.AsSpan();
|
||||
Span<Array10<byte>> fClassesSpan = fc.Classes.AsSpan();
|
||||
Span<Array10<byte>> pClassesSpan = preFc.Classes.AsSpan();
|
||||
Span<Array11<uint>> cClassesSpan = counts.Classes.AsSpan();
|
||||
Span<Array1<byte>> fClass0Span = fc.Class0.AsSpan();
|
||||
Span<Array1<byte>> pClass0Span = preFc.Class0.AsSpan();
|
||||
Span<Array2<uint>> cClass0Span = counts.Class0.AsSpan();
|
||||
Span<Array10<byte>> fBitsSpan1 = fc.Bits.AsSpan();
|
||||
Span<Array10<byte>> pBitsSpan1 = preFc.Bits.AsSpan();
|
||||
Span<Array10<Array2<uint>>> cBitsSpan1 = counts.Bits.AsSpan();
|
||||
Span<Array2<Array3<byte>>> fClass0FpSpan1 = fc.Class0Fp.AsSpan();
|
||||
Span<Array2<Array3<byte>>> pClass0FpSpan1 = preFc.Class0Fp.AsSpan();
|
||||
Span<Array2<Array4<uint>>> cClass0FpSpan1 = counts.Class0Fp.AsSpan();
|
||||
Span<Array3<byte>> fFpSpan = fc.Fp.AsSpan();
|
||||
Span<Array3<byte>> pFpSpan = preFc.Fp.AsSpan();
|
||||
Span<Array4<uint>> cFpSpan = counts.Fp.AsSpan();
|
||||
Span<byte> fClass0HpSpan = fc.Class0Hp.AsSpan();
|
||||
Span<byte> pClass0HpSpan = preFc.Class0Hp.AsSpan();
|
||||
Span<Array2<uint>> cClass0HpSpan = counts.Class0Hp.AsSpan();
|
||||
Span<byte> fHpSpan = fc.Hp.AsSpan();
|
||||
Span<byte> pHpSpan = preFc.Hp.AsSpan();
|
||||
Span<Array2<uint>> cHpSpan = counts.Hp.AsSpan();
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
fc.Sign[i] = Prob.ModeMvMergeProbs(preFc.Sign[i], ref counts.Sign[i]);
|
||||
fSignSpan[i] = Prob.ModeMvMergeProbs(pSignSpan[i], cSignSpan[i].AsSpan());
|
||||
Prob.VpxTreeMergeProbs(
|
||||
EntropyMv.ClassTree,
|
||||
preFc.Classes[i].AsSpan(),
|
||||
counts.Classes[i].AsSpan(),
|
||||
fc.Classes[i].AsSpan());
|
||||
pClassesSpan[i].AsSpan(),
|
||||
cClassesSpan[i].AsSpan(),
|
||||
fClassesSpan[i].AsSpan());
|
||||
Prob.VpxTreeMergeProbs(
|
||||
EntropyMv.Class0Tree,
|
||||
preFc.Class0[i].AsSpan(),
|
||||
counts.Class0[i].AsSpan(),
|
||||
fc.Class0[i].AsSpan());
|
||||
pClass0Span[i].AsSpan(),
|
||||
cClass0Span[i].AsSpan(),
|
||||
fClass0Span[i].AsSpan());
|
||||
|
||||
Span<byte> fBitsSpan2 = fBitsSpan1[i].AsSpan();
|
||||
Span<byte> pBitsSpan2 = pBitsSpan1[i].AsSpan();
|
||||
Span<Array2<uint>> cBitsSpan2 = cBitsSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < EntropyMv.OffsetBits; ++j)
|
||||
{
|
||||
fc.Bits[i][j] = Prob.ModeMvMergeProbs(preFc.Bits[i][j], ref counts.Bits[i][j]);
|
||||
fBitsSpan2[j] = Prob.ModeMvMergeProbs(pBitsSpan2[j], cBitsSpan2[j].AsSpan());
|
||||
}
|
||||
|
||||
Span<Array3<byte>> fClass0FpSpan2 = fClass0FpSpan1[i].AsSpan();
|
||||
Span<Array3<byte>> pClass0FpSpan2 = pClass0FpSpan1[i].AsSpan();
|
||||
Span<Array4<uint>> cClass0FpSpan2 = cClass0FpSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < EntropyMv.Class0Size; ++j)
|
||||
{
|
||||
Prob.VpxTreeMergeProbs(
|
||||
EntropyMv.FpTree,
|
||||
preFc.Class0Fp[i][j].AsSpan(),
|
||||
counts.Class0Fp[i][j].AsSpan(),
|
||||
fc.Class0Fp[i][j].AsSpan());
|
||||
pClass0FpSpan2[j].AsSpan(),
|
||||
cClass0FpSpan2[j].AsSpan(),
|
||||
fClass0FpSpan2[j].AsSpan());
|
||||
}
|
||||
|
||||
Prob.VpxTreeMergeProbs(EntropyMv.FpTree, preFc.Fp[i].AsSpan(), counts.Fp[i].AsSpan(),
|
||||
fc.Fp[i].AsSpan());
|
||||
Prob.VpxTreeMergeProbs(EntropyMv.FpTree, pFpSpan[i].AsSpan(), cFpSpan[i].AsSpan(),
|
||||
fFpSpan[i].AsSpan());
|
||||
|
||||
if (allowHp)
|
||||
{
|
||||
fc.Class0Hp[i] = Prob.ModeMvMergeProbs(preFc.Class0Hp[i], ref counts.Class0Hp[i]);
|
||||
fc.Hp[i] = Prob.ModeMvMergeProbs(preFc.Hp[i], ref counts.Hp[i]);
|
||||
fClass0HpSpan[i] = Prob.ModeMvMergeProbs(pClass0HpSpan[i], cClass0HpSpan[i].AsSpan());
|
||||
fHpSpan[i] = Prob.ModeMvMergeProbs(pHpSpan[i], cHpSpan[i].AsSpan());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -769,75 +855,115 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
|
||||
ref Vp9BackwardUpdates counts = ref Counts.Value;
|
||||
|
||||
Span<byte> fIntraInterProbSpan = fc.IntraInterProb.AsSpan();
|
||||
Span<byte> pIntraInterProbSpan = preFc.IntraInterProb.AsSpan();
|
||||
Span<Array2<uint>> cIntraInterSpan = counts.IntraInter.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.IntraInterContexts; i++)
|
||||
{
|
||||
fc.IntraInterProb[i] = Prob.ModeMvMergeProbs(preFc.IntraInterProb[i], ref counts.IntraInter[i]);
|
||||
fIntraInterProbSpan[i] = Prob.ModeMvMergeProbs(pIntraInterProbSpan[i], cIntraInterSpan[i].AsSpan());
|
||||
}
|
||||
|
||||
Span<byte> fCompInterProbSpan = fc.CompInterProb.AsSpan();
|
||||
Span<byte> pCompInterProbSpan = preFc.CompInterProb.AsSpan();
|
||||
Span<Array2<uint>> cCompInterSpan = counts.CompInter.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.CompInterContexts; i++)
|
||||
{
|
||||
fc.CompInterProb[i] = Prob.ModeMvMergeProbs(preFc.CompInterProb[i], ref counts.CompInter[i]);
|
||||
fCompInterProbSpan[i] = Prob.ModeMvMergeProbs(pCompInterProbSpan[i], cCompInterSpan[i].AsSpan());
|
||||
}
|
||||
|
||||
Span<byte> fCompRefProbSpan = fc.CompRefProb.AsSpan();
|
||||
Span<byte> pCompRefProbSpan = preFc.CompRefProb.AsSpan();
|
||||
Span<Array2<uint>> cCompRefSpan = counts.CompRef.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.RefContexts; i++)
|
||||
{
|
||||
fc.CompRefProb[i] = Prob.ModeMvMergeProbs(preFc.CompRefProb[i], ref counts.CompRef[i]);
|
||||
fCompRefProbSpan[i] = Prob.ModeMvMergeProbs(pCompRefProbSpan[i], cCompRefSpan[i].AsSpan());
|
||||
}
|
||||
|
||||
Span<Array2<byte>> fSingleRefProbSpan1 = fc.SingleRefProb.AsSpan();
|
||||
Span<Array2<byte>> pSingleRefProbSpan1 = preFc.SingleRefProb.AsSpan();
|
||||
Span<Array2<Array2<uint>>> cSingleRefSpan1 = counts.SingleRef.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.RefContexts; i++)
|
||||
{
|
||||
Span<byte> fSingleRefProbSpan2 = fSingleRefProbSpan1[i].AsSpan();
|
||||
Span<byte> pSingleRefProbSpan2 = pSingleRefProbSpan1[i].AsSpan();
|
||||
Span<Array2<uint>> cSingleRefSpan2 = cSingleRefSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
fc.SingleRefProb[i][j] =
|
||||
Prob.ModeMvMergeProbs(preFc.SingleRefProb[i][j], ref counts.SingleRef[i][j]);
|
||||
fSingleRefProbSpan2[j] =
|
||||
Prob.ModeMvMergeProbs(pSingleRefProbSpan2[j], cSingleRefSpan2[j].AsSpan());
|
||||
}
|
||||
}
|
||||
|
||||
Span<Array3<byte>> fInterModeProbSpan = fc.InterModeProb.AsSpan();
|
||||
Span<Array3<byte>> pInterModeProbSpan = preFc.InterModeProb.AsSpan();
|
||||
Span<Array4<uint>> cInterModeSpan = counts.InterMode.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.InterModeContexts; i++)
|
||||
{
|
||||
Prob.VpxTreeMergeProbs(
|
||||
EntropyMode.InterModeTree,
|
||||
preFc.InterModeProb[i].AsSpan(),
|
||||
counts.InterMode[i].AsSpan(),
|
||||
fc.InterModeProb[i].AsSpan());
|
||||
pInterModeProbSpan[i].AsSpan(),
|
||||
cInterModeSpan[i].AsSpan(),
|
||||
fInterModeProbSpan[i].AsSpan());
|
||||
}
|
||||
|
||||
Span<Array9<byte>> fYModeProbSpan = fc.YModeProb.AsSpan();
|
||||
Span<Array9<byte>> pYModeProbSpan = preFc.YModeProb.AsSpan();
|
||||
Span<Array10<uint>> cYModeSpan = counts.YMode.AsSpan();
|
||||
|
||||
for (int i = 0; i < EntropyMode.BlockSizeGroups; i++)
|
||||
{
|
||||
Prob.VpxTreeMergeProbs(
|
||||
EntropyMode.IntraModeTree,
|
||||
preFc.YModeProb[i].AsSpan(),
|
||||
counts.YMode[i].AsSpan(),
|
||||
fc.YModeProb[i].AsSpan());
|
||||
pYModeProbSpan[i].AsSpan(),
|
||||
cYModeSpan[i].AsSpan(),
|
||||
fYModeProbSpan[i].AsSpan());
|
||||
}
|
||||
|
||||
Span<Array9<byte>> fUvModeProbSpan = fc.UvModeProb.AsSpan();
|
||||
Span<Array9<byte>> pUvModeProbSpan = preFc.UvModeProb.AsSpan();
|
||||
Span<Array10<uint>> cUvModeSpan = counts.UvMode.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.IntraModes; ++i)
|
||||
{
|
||||
Prob.VpxTreeMergeProbs(
|
||||
EntropyMode.IntraModeTree,
|
||||
preFc.UvModeProb[i].AsSpan(),
|
||||
counts.UvMode[i].AsSpan(),
|
||||
fc.UvModeProb[i].AsSpan());
|
||||
pUvModeProbSpan[i].AsSpan(),
|
||||
cUvModeSpan[i].AsSpan(),
|
||||
fUvModeProbSpan[i].AsSpan());
|
||||
}
|
||||
|
||||
Span<Array3<byte>> fPartitionProbSpan = fc.PartitionProb.AsSpan();
|
||||
Span<Array3<byte>> pPartitionProbSpan = preFc.PartitionProb.AsSpan();
|
||||
Span<Array4<uint>> cPartitionSpan = counts.Partition.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.PartitionContexts; i++)
|
||||
{
|
||||
Prob.VpxTreeMergeProbs(
|
||||
EntropyMode.PartitionTree,
|
||||
preFc.PartitionProb[i].AsSpan(),
|
||||
counts.Partition[i].AsSpan(),
|
||||
fc.PartitionProb[i].AsSpan());
|
||||
pPartitionProbSpan[i].AsSpan(),
|
||||
cPartitionSpan[i].AsSpan(),
|
||||
fPartitionProbSpan[i].AsSpan());
|
||||
}
|
||||
|
||||
if (InterpFilter == Constants.Switchable)
|
||||
{
|
||||
Span<Array2<byte>> fSwitchableInterpProbSpan = fc.SwitchableInterpProb.AsSpan();
|
||||
Span<Array2<byte>> pSwitchableInterpProbSpan = preFc.SwitchableInterpProb.AsSpan();
|
||||
Span<Array3<uint>> cSwitchableInterpSpan = counts.SwitchableInterp.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.SwitchableFilterContexts; i++)
|
||||
{
|
||||
Prob.VpxTreeMergeProbs(
|
||||
EntropyMode.SwitchableInterpTree,
|
||||
preFc.SwitchableInterpProb[i].AsSpan(),
|
||||
counts.SwitchableInterp[i].AsSpan(),
|
||||
fc.SwitchableInterpProb[i].AsSpan());
|
||||
pSwitchableInterpProbSpan[i].AsSpan(),
|
||||
cSwitchableInterpSpan[i].AsSpan(),
|
||||
fSwitchableInterpProbSpan[i].AsSpan());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,34 +972,62 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
Array1<Array2<uint>> branchCt8X8P = new();
|
||||
Array2<Array2<uint>> branchCt16X16P = new();
|
||||
Array3<Array2<uint>> branchCt32X32P = new();
|
||||
|
||||
Span<Array2<uint>> branchCt8X8PSpan = branchCt8X8P.AsSpan();
|
||||
Span<Array2<uint>> branchCt16X16PSpan = branchCt16X16P.AsSpan();
|
||||
Span<Array2<uint>> branchCt32X32PSpan = branchCt32X32P.AsSpan();
|
||||
|
||||
Span<Array2<uint>> tx8x8Span = counts.Tx8x8.AsSpan();
|
||||
Span<Array2<uint>> tx16x16Span = counts.Tx8x8.AsSpan();
|
||||
Span<Array2<uint>> tx32x32Span = counts.Tx8x8.AsSpan();
|
||||
|
||||
//There is no need for a Span2, as there is only ever 1 iteration
|
||||
Span<Array1<byte>> fTx8x8ProbSpan = fc.Tx8x8Prob.AsSpan();
|
||||
Span<Array1<byte>> pTx8x8ProbSpan = preFc.Tx8x8Prob.AsSpan();
|
||||
|
||||
Span<Array2<byte>> fTx16x16ProbSpan1 = fc.Tx16x16Prob.AsSpan();
|
||||
Span<Array2<byte>> pTx16x16ProbSpan1 = preFc.Tx16x16Prob.AsSpan();
|
||||
|
||||
Span<Array3<byte>> fTx32x32ProbSpan1 = fc.Tx32x32Prob.AsSpan();
|
||||
Span<Array3<byte>> pTx32x32ProbSpan1 = preFc.Tx32x32Prob.AsSpan();
|
||||
|
||||
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||
{
|
||||
EntropyMode.TxCountsToBranchCounts8X8(counts.Tx8x8[i].AsSpan(), ref branchCt8X8P);
|
||||
EntropyMode.TxCountsToBranchCounts8X8(tx8x8Span[i].AsSpan(), branchCt8X8P.AsSpan());
|
||||
for (int j = 0; j < (int)TxSize.TxSizes - 3; ++j)
|
||||
{
|
||||
fc.Tx8x8Prob[i][j] = Prob.ModeMvMergeProbs(preFc.Tx8x8Prob[i][j], ref branchCt8X8P[j]);
|
||||
fTx8x8ProbSpan[i][j] = Prob.ModeMvMergeProbs(pTx8x8ProbSpan[i][j], branchCt8X8PSpan[j].AsSpan());
|
||||
}
|
||||
|
||||
Span<byte> fTx16x16ProbSpan2 = fTx16x16ProbSpan1[i].AsSpan();
|
||||
Span<byte> pTx16x16ProbSpan2 = pTx16x16ProbSpan1[i].AsSpan();
|
||||
|
||||
EntropyMode.TxCountsToBranchCounts16X16(counts.Tx16x16[i].AsSpan(), ref branchCt16X16P);
|
||||
EntropyMode.TxCountsToBranchCounts16X16(tx16x16Span[i].AsSpan(), branchCt16X16P.AsSpan());
|
||||
for (int j = 0; j < (int)TxSize.TxSizes - 2; ++j)
|
||||
{
|
||||
fc.Tx16x16Prob[i][j] =
|
||||
Prob.ModeMvMergeProbs(preFc.Tx16x16Prob[i][j], ref branchCt16X16P[j]);
|
||||
fTx16x16ProbSpan2[j] =
|
||||
Prob.ModeMvMergeProbs(pTx16x16ProbSpan2[j], branchCt16X16PSpan[j].AsSpan());
|
||||
}
|
||||
|
||||
Span<byte> fTx32x32ProbSpan2 = fTx32x32ProbSpan1[i].AsSpan();
|
||||
Span<byte> pTx32x32ProbSpan2 = pTx32x32ProbSpan1[i].AsSpan();
|
||||
|
||||
EntropyMode.TxCountsToBranchCounts32X32(counts.Tx32x32[i].AsSpan(), ref branchCt32X32P);
|
||||
EntropyMode.TxCountsToBranchCounts32X32(tx32x32Span[i].AsSpan(), branchCt32X32P.AsSpan());
|
||||
for (int j = 0; j < (int)TxSize.TxSizes - 1; ++j)
|
||||
{
|
||||
fc.Tx32x32Prob[i][j] =
|
||||
Prob.ModeMvMergeProbs(preFc.Tx32x32Prob[i][j], ref branchCt32X32P[j]);
|
||||
fTx32x32ProbSpan2[j] =
|
||||
Prob.ModeMvMergeProbs(pTx32x32ProbSpan2[j], branchCt32X32PSpan[j].AsSpan());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Span<byte> fSkipProbSpan = fc.SkipProb.AsSpan();
|
||||
Span<byte> pSkipProbSpan = preFc.SkipProb.AsSpan();
|
||||
Span<Array2<uint>> cSkipSpan = counts.Skip.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.SkipContexts; ++i)
|
||||
{
|
||||
fc.SkipProb[i] = Prob.ModeMvMergeProbs(preFc.SkipProb[i], ref counts.Skip[i]);
|
||||
fSkipProbSpan[i] = Prob.ModeMvMergeProbs(pSkipProbSpan[i], cSkipSpan[i].AsSpan());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -916,13 +1070,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
ref MvRef mv = ref PrevFrameMvs[i];
|
||||
|
||||
mv.Mv[0].Row = mvs[i].Mvs[0].Row;
|
||||
mv.Mv[0].Col = mvs[i].Mvs[0].Col;
|
||||
mv.Mv[1].Row = mvs[i].Mvs[1].Row;
|
||||
mv.Mv[1].Col = mvs[i].Mvs[1].Col;
|
||||
Span<Mv> mvSpan = mv.Mv.AsSpan();
|
||||
Span<Vp9Mv> mvsSpan = mvs[i].Mvs.AsSpan();
|
||||
|
||||
mv.RefFrame[0] = (sbyte)mvs[i].RefFrames[0];
|
||||
mv.RefFrame[1] = (sbyte)mvs[i].RefFrames[1];
|
||||
mvSpan[0].Row = mvsSpan[0].Row;
|
||||
mvSpan[0].Col = mvsSpan[0].Col;
|
||||
mvSpan[1].Row = mvsSpan[1].Row;
|
||||
mvSpan[1].Col = mvsSpan[1].Col;
|
||||
|
||||
Span<sbyte> refFrameSpan = mv.RefFrame.AsSpan();
|
||||
Span<int> refFramesSpan = mvs[i].RefFrames.AsSpan();
|
||||
|
||||
refFrameSpan[0] = (sbyte)refFramesSpan[0];
|
||||
refFrameSpan[1] = (sbyte)refFramesSpan[1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,47 +1097,76 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
for (int i = 0; i < mvs.Length; i++)
|
||||
{
|
||||
ref MvRef mv = ref CurFrameMvs[i];
|
||||
|
||||
Span<Mv> mvSpan = mv.Mv.AsSpan();
|
||||
Span<Vp9Mv> mvsSpan = mvs[i].Mvs.AsSpan();
|
||||
|
||||
mvs[i].Mvs[0].Row = mv.Mv[0].Row;
|
||||
mvs[i].Mvs[0].Col = mv.Mv[0].Col;
|
||||
mvs[i].Mvs[1].Row = mv.Mv[1].Row;
|
||||
mvs[i].Mvs[1].Col = mv.Mv[1].Col;
|
||||
mvsSpan[0].Row = mvSpan[0].Row;
|
||||
mvsSpan[0].Col = mvSpan[0].Col;
|
||||
mvsSpan[1].Row = mvSpan[1].Row;
|
||||
mvsSpan[1].Col = mvSpan[1].Col;
|
||||
|
||||
Span<sbyte> refFrameSpan = mv.RefFrame.AsSpan();
|
||||
Span<int> refFramesSpan = mvs[i].RefFrames.AsSpan();
|
||||
|
||||
mvs[i].RefFrames[0] = mv.RefFrame[0];
|
||||
mvs[i].RefFrames[1] = mv.RefFrame[1];
|
||||
refFramesSpan[0] = refFrameSpan[0];
|
||||
refFramesSpan[1] = refFrameSpan[1];
|
||||
}
|
||||
}
|
||||
|
||||
private void AdaptCoefProbs(byte txSize, uint countSat, uint updateFactor)
|
||||
{
|
||||
ref Vp9EntropyProbs preFc = ref FrameContexts[(int)FrameContextIdx];
|
||||
ref Array2<Array2<Array6<Array6<Array3<byte>>>>> probs = ref Fc.Value.CoefProbs[txSize];
|
||||
ref Array2<Array2<Array6<Array6<Array3<byte>>>>> preProbs = ref preFc.CoefProbs[txSize];
|
||||
ref Array2<Array2<Array6<Array6<Array4<uint>>>>> counts = ref Counts.Value.Coef[txSize];
|
||||
ref Array2<Array2<Array6<Array6<uint>>>> eobCounts = ref Counts.Value.EobBranch[txSize];
|
||||
Span<Array2<Array6<Array6<Array3<byte>>>>> probsSpan1 = Fc.Value.CoefProbs[txSize].AsSpan();
|
||||
Span<Array2<Array6<Array6<Array3<byte>>>>> preProbsSpan1 = preFc.CoefProbs[txSize].AsSpan();
|
||||
Span<Array2<Array6<Array6<Array4<uint>>>>> countsSpan1 = Counts.Value.Coef[txSize].AsSpan();
|
||||
Span<Array2<Array6<Array6<uint>>>> eobCountsSpan1 = Counts.Value.EobBranch[txSize].AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.PlaneTypes; ++i)
|
||||
{
|
||||
Span<Array6<Array6<Array3<byte>>>> probsSpan2 = probsSpan1[i].AsSpan();
|
||||
Span<Array6<Array6<Array3<byte>>>> preProbsSpan2 = preProbsSpan1[i].AsSpan();
|
||||
Span<Array6<Array6<Array4<uint>>>> countsSpan2 = countsSpan1[i].AsSpan();
|
||||
Span<Array6<Array6<uint>>> eobCountsSpan2 = eobCountsSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < Entropy.RefTypes; ++j)
|
||||
{
|
||||
Span<Array6<Array3<byte>>> probsSpan3 = probsSpan2[j].AsSpan();
|
||||
Span<Array6<Array3<byte>>> preProbsSpan3 = preProbsSpan2[j].AsSpan();
|
||||
Span<Array6<Array4<uint>>> countsSpan3 = countsSpan2[j].AsSpan();
|
||||
Span<Array6<uint>> eobCountsSpan3 = eobCountsSpan2[j].AsSpan();
|
||||
|
||||
for (int k = 0; k < Entropy.CoefBands; ++k)
|
||||
{
|
||||
Span<Array3<byte>> probsSpan4 = probsSpan3[k].AsSpan();
|
||||
Span<Array3<byte>> preProbsSpan4 = preProbsSpan3[k].AsSpan();
|
||||
Span<Array4<uint>> countsSpan4 = countsSpan3[k].AsSpan();
|
||||
Span<uint> eobCountsSpan4 = eobCountsSpan3[k].AsSpan();
|
||||
|
||||
for (int l = 0; l < Entropy.BAND_COEFF_CONTEXTS(k); ++l)
|
||||
{
|
||||
int n0 = (int)counts[i][j][k][l][Entropy.ZeroToken];
|
||||
int n1 = (int)counts[i][j][k][l][Entropy.OneToken];
|
||||
int n2 = (int)counts[i][j][k][l][Entropy.TwoToken];
|
||||
int neob = (int)counts[i][j][k][l][Entropy.EobModelToken];
|
||||
Span<byte> probsSpan5 = probsSpan4[l].AsSpan();
|
||||
Span<byte> preProbsSpan5 = preProbsSpan4[l].AsSpan();
|
||||
Span<uint> countsSpan5 = countsSpan4[l].AsSpan();
|
||||
|
||||
int n0 = (int)countsSpan5[Entropy.ZeroToken];
|
||||
int n1 = (int)countsSpan5[Entropy.OneToken];
|
||||
int n2 = (int)countsSpan5[Entropy.TwoToken];
|
||||
int neob = (int)countsSpan5[Entropy.EobModelToken];
|
||||
Array3<Array2<uint>> branchCt = new();
|
||||
branchCt[0][0] = (uint)neob;
|
||||
branchCt[0][1] = (uint)(eobCounts[i][j][k][l] - neob);
|
||||
branchCt[1][0] = (uint)n0;
|
||||
branchCt[1][1] = (uint)(n1 + n2);
|
||||
branchCt[2][0] = (uint)n1;
|
||||
branchCt[2][1] = (uint)n2;
|
||||
Span<Array2<uint>> branchCtSpan = branchCt.AsSpan();
|
||||
Span<uint> branchCt0Span = branchCtSpan[0].AsSpan();
|
||||
Span<uint> branchCt1Span = branchCtSpan[1].AsSpan();
|
||||
Span<uint> branchCt2Span = branchCtSpan[2].AsSpan();
|
||||
branchCt0Span[0] = (uint)neob;
|
||||
branchCt0Span[1] = (uint)(eobCountsSpan4[l] - neob);
|
||||
branchCt1Span[0] = (uint)n0;
|
||||
branchCt1Span[1] = (uint)(n1 + n2);
|
||||
branchCt2Span[0] = (uint)n1;
|
||||
branchCt2Span[1] = (uint)n2;
|
||||
for (int m = 0; m < Entropy.UnconstrainedNodes; ++m)
|
||||
{
|
||||
probs[i][j][k][l][m] = Prob.MergeProbs(preProbs[i][j][k][l][m], ref branchCt[m],
|
||||
probsSpan5[m] = Prob.MergeProbs(preProbsSpan5[m], branchCt[m].AsSpan(),
|
||||
countSat, updateFactor);
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
@@ -16,20 +17,20 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
public int NeedResync; // Wait for key/intra-only frame.
|
||||
public int HoldRefBuf; // Hold the reference buffer.
|
||||
|
||||
private static void DecreaseRefCount(int idx, ref Array12<RefCntBuffer> frameBufs, ref BufferPool pool)
|
||||
private static void DecreaseRefCount(int idx, Span<RefCntBuffer> frameBuffs, ref BufferPool pool)
|
||||
{
|
||||
if (idx >= 0 && frameBufs[idx].RefCount > 0)
|
||||
if (idx >= 0 && frameBuffs[idx].RefCount > 0)
|
||||
{
|
||||
--frameBufs[idx].RefCount;
|
||||
--frameBuffs[idx].RefCount;
|
||||
// A worker may only get a free framebuffer index when calling GetFreeFb.
|
||||
// But the private buffer is not set up until finish decoding header.
|
||||
// So any error happens during decoding header, the frame_bufs will not
|
||||
// have valid priv buffer.
|
||||
if (frameBufs[idx].Released == 0 && frameBufs[idx].RefCount == 0 &&
|
||||
!frameBufs[idx].RawFrameBuffer.Priv.IsNull)
|
||||
if (frameBuffs[idx].Released == 0 && frameBuffs[idx].RefCount == 0 &&
|
||||
!frameBuffs[idx].RawFrameBuffer.Priv.IsNull)
|
||||
{
|
||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[idx].RawFrameBuffer);
|
||||
frameBufs[idx].Released = 1;
|
||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBuffs[idx].RawFrameBuffer);
|
||||
frameBuffs[idx].Released = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,22 +44,32 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
cm.CheckMemError(ref cm.FrameContexts,
|
||||
allocator.Allocate<Vp9EntropyProbs>(Constants.FrameContexts));
|
||||
|
||||
Span<Array10<Array9<byte>>> cKfYModeProbSpan1 = cm.Fc.Value.KfYModeProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < EntropyMode.KfYModeProb.Length; i++)
|
||||
{
|
||||
Span<Array9<byte>> cKfYModeProbSpan2 = cKfYModeProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < EntropyMode.KfYModeProb[i].Length; j++)
|
||||
{
|
||||
Span<byte> cKfYModeProbSpan3 = cKfYModeProbSpan2[j].AsSpan();
|
||||
|
||||
for (int k = 0; k < EntropyMode.KfYModeProb[i][j].Length; k++)
|
||||
{
|
||||
cm.Fc.Value.KfYModeProb[i][j][k] = EntropyMode.KfYModeProb[i][j][k];
|
||||
cKfYModeProbSpan3[k] = EntropyMode.KfYModeProb[i][j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Span<Array9<byte>> cKfUvModeProbSpan1 = cm.Fc.Value.KfUvModeProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < EntropyMode.KfUvModeProb.Length; i++)
|
||||
{
|
||||
Span<byte> cKfUvModeProbSpan2 = cKfUvModeProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < EntropyMode.KfUvModeProb[i].Length; j++)
|
||||
{
|
||||
cm.Fc.Value.KfUvModeProb[i][j] = EntropyMode.KfUvModeProb[i][j];
|
||||
cKfUvModeProbSpan2[j] = EntropyMode.KfUvModeProb[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,12 +99,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
[57, 15, 9], // l split, a not split
|
||||
[12, 3, 3] // a/l both split
|
||||
];
|
||||
|
||||
Span<Array3<byte>> cKfPartitionProbSpan1 = cm.Fc.Value.KfPartitionProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < kfPartitionProbs.Length; i++)
|
||||
{
|
||||
Span<byte> cKfPartitionProbSpan2 = cKfPartitionProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < kfPartitionProbs[i].Length; j++)
|
||||
{
|
||||
cm.Fc.Value.KfPartitionProb[i][j] = kfPartitionProbs[i][j];
|
||||
cKfPartitionProbSpan2[j] = kfPartitionProbs[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +116,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
|
||||
NeedResync = 1;
|
||||
|
||||
Span<int> refFrameMapSpan = cm.RefFrameMap.AsSpan();
|
||||
Span<int> nextRefFrameMapSpan = cm.NextRefFrameMap.AsSpan();
|
||||
|
||||
// Initialize the references to not point to any frame buffers.
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
cm.RefFrameMap[i] = -1;
|
||||
cm.NextRefFrameMap[i] = -1;
|
||||
refFrameMapSpan[i] = -1;
|
||||
nextRefFrameMapSpan[i] = -1;
|
||||
}
|
||||
|
||||
cm.CurrentVideoFrame = 0;
|
||||
@@ -124,30 +142,34 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
int refIndex = 0, mask;
|
||||
ref Vp9Common cm = ref Common;
|
||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
|
||||
Span<RefCntBuffer> frameBufs = cm.BufferPool.Value.FrameBufs.AsSpan();
|
||||
|
||||
Span<int> refFrameMapSpan = cm.RefFrameMap.AsSpan();
|
||||
Span<int> nextRefFrameMapSpan = cm.NextRefFrameMap.AsSpan();
|
||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||
|
||||
for (mask = RefreshFrameFlags; mask != 0; mask >>= 1)
|
||||
{
|
||||
int oldIdx = cm.RefFrameMap[refIndex];
|
||||
int oldIdx = refFrameMapSpan[refIndex];
|
||||
// Current thread releases the holding of reference frame.
|
||||
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
|
||||
DecreaseRefCount(oldIdx, frameBufs, ref pool);
|
||||
|
||||
// Release the reference frame in reference map.
|
||||
if ((mask & 1) != 0)
|
||||
{
|
||||
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
|
||||
DecreaseRefCount(oldIdx, frameBufs, ref pool);
|
||||
}
|
||||
|
||||
cm.RefFrameMap[refIndex] = cm.NextRefFrameMap[refIndex];
|
||||
refFrameMapSpan[refIndex] = nextRefFrameMapSpan[refIndex];
|
||||
++refIndex;
|
||||
}
|
||||
|
||||
// Current thread releases the holding of reference frame.
|
||||
for (; refIndex < Constants.RefFrames && cm.ShowExistingFrame == 0; ++refIndex)
|
||||
{
|
||||
int oldIdx = cm.RefFrameMap[refIndex];
|
||||
DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
|
||||
cm.RefFrameMap[refIndex] = cm.NextRefFrameMap[refIndex];
|
||||
int oldIdx = refFrameMapSpan[refIndex];
|
||||
DecreaseRefCount(oldIdx, frameBufs, ref pool);
|
||||
refFrameMapSpan[refIndex] = nextRefFrameMapSpan[refIndex];
|
||||
}
|
||||
|
||||
HoldRefBuf = 0;
|
||||
@@ -158,7 +180,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
// Invalidate these references until the next frame starts.
|
||||
for (refIndex = 0; refIndex < 3; refIndex++)
|
||||
{
|
||||
cm.FrameRefs[refIndex].Idx = RefBuffer.InvalidIdx;
|
||||
frameRefsSpan[refIndex].Idx = RefBuffer.InvalidIdx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +188,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
ref Vp9Common cm = ref Common;
|
||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
|
||||
Span<RefCntBuffer> frameBufs = cm.BufferPool.Value.FrameBufs.AsSpan();
|
||||
ArrayPtr<byte> source = psource;
|
||||
CodecErr retcode = 0;
|
||||
cm.Error.ErrorCode = CodecErr.Ok;
|
||||
@@ -177,10 +199,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
// We do not know if the missing frame(s) was supposed to update
|
||||
// any of the reference buffers, but we act conservative and
|
||||
// mark only the last buffer as corrupted.
|
||||
|
||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
||||
|
||||
if (cm.FrameRefs[0].Idx > 0)
|
||||
if (frameRefsSpan[0].Idx > 0)
|
||||
{
|
||||
cm.FrameRefs[0].Buf.Corrupted = 1;
|
||||
frameRefsSpan[0].Buf.Corrupted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,8 +303,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
ArrayPtr<byte> dataStart = data;
|
||||
CodecErr res;
|
||||
Array8<uint> frameSizes = new();
|
||||
|
||||
res = Decoder.ParseSuperframeIndex(data, (ulong)data.Length, ref frameSizes, out int frameCount);
|
||||
Span<uint> frameSizesSpan = frameSizes.AsSpan();
|
||||
|
||||
res = Decoder.ParseSuperframeIndex(data, (ulong)data.Length, frameSizesSpan, out int frameCount);
|
||||
if (res != CodecErr.Ok)
|
||||
{
|
||||
return res;
|
||||
@@ -292,7 +317,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
for (int i = 0; i < frameCount; ++i)
|
||||
{
|
||||
ArrayPtr<byte> dataStartCopy = dataStart;
|
||||
uint frameSize = frameSizes[i];
|
||||
uint frameSize = frameSizesSpan[i];
|
||||
if (frameSize > (uint)dataStart.Length)
|
||||
{
|
||||
return CodecErr.CorruptFrame;
|
||||
@@ -343,7 +368,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
return data[0];
|
||||
}
|
||||
|
||||
public static CodecErr ParseSuperframeIndex(ArrayPtr<byte> data, ulong dataSz, ref Array8<uint> sizes, out int count)
|
||||
public static CodecErr ParseSuperframeIndex(ArrayPtr<byte> data, ulong dataSz, Span<uint> sizes, out int count)
|
||||
{
|
||||
// A chunk ending with a byte matching 0xc0 is an invalid chunk unless
|
||||
// it is a super frame index. If the last byte of real video compression
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||
{
|
||||
@@ -33,15 +34,24 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||
public BackwardUpdates(ref Vp9BackwardUpdates counts)
|
||||
{
|
||||
InterModeCounts = new Array7<Array3<Array2<uint>>>();
|
||||
|
||||
Span<Array3<Array2<uint>>> interModeCountsSpan1 = InterModeCounts.AsSpan();
|
||||
Span<Array4<uint>> interModeSpan1 = counts.InterMode.AsSpan();
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
InterModeCounts[i][0][0] = counts.InterMode[i][2];
|
||||
InterModeCounts[i][0][1] = counts.InterMode[i][0] + counts.InterMode[i][1] + counts.InterMode[i][3];
|
||||
InterModeCounts[i][1][0] = counts.InterMode[i][0];
|
||||
InterModeCounts[i][1][1] = counts.InterMode[i][1] + counts.InterMode[i][3];
|
||||
InterModeCounts[i][2][0] = counts.InterMode[i][1];
|
||||
InterModeCounts[i][2][1] = counts.InterMode[i][3];
|
||||
Span<Array2<uint>> interModeCountsSpan2 = interModeCountsSpan1[i].AsSpan();
|
||||
Span<uint> interModeCountsSpan20 = interModeCountsSpan2[0].AsSpan();
|
||||
Span<uint> interModeCountsSpan21 = interModeCountsSpan2[1].AsSpan();
|
||||
Span<uint> interModeCountsSpan22 = interModeCountsSpan2[2].AsSpan();
|
||||
Span<uint> interModeSpan2 = interModeSpan1[i].AsSpan();
|
||||
|
||||
interModeCountsSpan20[0] = interModeSpan2[2];
|
||||
interModeCountsSpan20[1] = interModeSpan2[0] + interModeSpan2[1] + interModeSpan2[3];
|
||||
interModeCountsSpan21[0] = interModeSpan2[0];
|
||||
interModeCountsSpan21[1] = interModeSpan2[1] + interModeSpan2[3];
|
||||
interModeCountsSpan22[0] = interModeSpan2[1];
|
||||
interModeCountsSpan22[1] = interModeSpan2[3];
|
||||
}
|
||||
|
||||
YModeCounts = counts.YMode;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||
{
|
||||
@@ -46,57 +47,98 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||
|
||||
public void Convert(ref Vp9EntropyProbs fc)
|
||||
{
|
||||
Span<Array10<Array9<byte>>> kfYModeProbSpan1 = fc.KfYModeProb.AsSpan();
|
||||
Span<Array10<Array8<byte>>> kfYModeProbE0ToE7Span1 = KfYModeProbE0ToE7.AsSpan();
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
Span<Array9<byte>> kfYModeProbSpan2 = kfYModeProbSpan1[i].AsSpan();
|
||||
Span<Array8<byte>> kfYModeProbE0ToE7Span2 = kfYModeProbE0ToE7Span1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < 10; j++)
|
||||
{
|
||||
Span<byte> kfYModeProbSpan3 = kfYModeProbSpan2[j].AsSpan();
|
||||
Span<byte> kfYModeProbE0ToE7Span3 = kfYModeProbE0ToE7Span2[j].AsSpan();
|
||||
|
||||
for (int k = 0; k < 9; k++)
|
||||
{
|
||||
fc.KfYModeProb[i][j][k] = k < 8 ? KfYModeProbE0ToE7[i][j][k] : KfYModeProbE8[i][j];
|
||||
kfYModeProbSpan3[k] = k < 8 ? kfYModeProbE0ToE7Span3[k] : KfYModeProbE8[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fc.SegTreeProb = SegTreeProbs;
|
||||
fc.SegPredProb = SegPredProbs;
|
||||
|
||||
Span<Array3<byte>> interModeProbSpan1 = fc.InterModeProb.AsSpan();
|
||||
Span<Array4<byte>> gInterModeProbSpan1 = InterModeProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
Span<byte> interModeProbSpan2 = interModeProbSpan1[i].AsSpan();
|
||||
Span<byte> gInterModeProbSpan2 = gInterModeProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
fc.InterModeProb[i][j] = InterModeProb[i][j];
|
||||
interModeProbSpan2[j] = gInterModeProbSpan2[j];
|
||||
}
|
||||
}
|
||||
|
||||
fc.IntraInterProb = IntraInterProb;
|
||||
|
||||
Span<Array9<byte>> kfUvModeProbSpan1 = fc.KfUvModeProb.AsSpan();
|
||||
Span<Array8<byte>> kfUvModeProbE0ToE7Span1 = KfUvModeProbE0ToE7.AsSpan();
|
||||
Span<Array9<byte>> uvModeProbSpan1 = fc.UvModeProb.AsSpan();
|
||||
Span<Array8<byte>> uvModeProbE0ToE7Span1 = UvModeProbE0ToE7.AsSpan();
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
Span<byte> kfUvModeProbSpan2 = kfUvModeProbSpan1[i].AsSpan();
|
||||
Span<byte> kfUvModeProbE0ToE7Span2 = kfUvModeProbE0ToE7Span1[i].AsSpan();
|
||||
Span<byte> uvModeProbSpan2 = uvModeProbSpan1[i].AsSpan();
|
||||
Span<byte> uvModeProbE0ToE7Span2 = uvModeProbE0ToE7Span1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < 9; j++)
|
||||
{
|
||||
fc.KfUvModeProb[i][j] = j < 8 ? KfUvModeProbE0ToE7[i][j] : KfUvModeProbE8[i];
|
||||
fc.UvModeProb[i][j] = j < 8 ? UvModeProbE0ToE7[i][j] : UvModeProbE8[i];
|
||||
kfUvModeProbSpan2[j] = j < 8 ? kfUvModeProbE0ToE7Span2[j] : KfUvModeProbE8[i];
|
||||
uvModeProbSpan2[j] = j < 8 ? uvModeProbE0ToE7Span2[j] : UvModeProbE8[i];
|
||||
}
|
||||
}
|
||||
|
||||
fc.Tx8x8Prob = Tx8x8Prob;
|
||||
fc.Tx16x16Prob = Tx16x16Prob;
|
||||
fc.Tx32x32Prob = Tx32x32Prob;
|
||||
|
||||
Span<Array9<byte>> yModeProbSpan1 = fc.YModeProb.AsSpan();
|
||||
Span<Array8<byte>> yModeProbE0ToE7Span1 = YModeProbE0ToE7.AsSpan();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Span<byte> yModeProbSpan2 = yModeProbSpan1[i].AsSpan();
|
||||
Span<byte> yModeProbE0ToE7Span2 = yModeProbE0ToE7Span1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < 9; j++)
|
||||
{
|
||||
fc.YModeProb[i][j] = j < 8 ? YModeProbE0ToE7[i][j] : YModeProbE8[i];
|
||||
yModeProbSpan2[j] = j < 8 ? yModeProbE0ToE7Span2[j] : YModeProbE8[i];
|
||||
}
|
||||
}
|
||||
|
||||
Span<Array3<byte>> kfPartitionProbSpan1 = fc.KfPartitionProb.AsSpan();
|
||||
Span<Array4<byte>> gKfPartitionProbSpan1 = KfPartitionProb.AsSpan();
|
||||
Span<Array3<byte>> partitionProbSpan1 = fc.PartitionProb.AsSpan();
|
||||
Span<Array4<byte>> gPartitionProbSpan1 = PartitionProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
Span<byte> kfPartitionProbSpan2 = kfPartitionProbSpan1[i].AsSpan();
|
||||
Span<byte> gKfPartitionProbSpan2 = gKfPartitionProbSpan1[i].AsSpan();
|
||||
Span<byte> partitionProbSpan2 = partitionProbSpan1[i].AsSpan();
|
||||
Span<byte> gPartitionProbSpan2 = gPartitionProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
fc.KfPartitionProb[i][j] = KfPartitionProb[i][j];
|
||||
fc.PartitionProb[i][j] = PartitionProb[i][j];
|
||||
kfPartitionProbSpan2[j] = gKfPartitionProbSpan2[j];
|
||||
partitionProbSpan2[j] = gPartitionProbSpan2[j];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,20 +158,38 @@ namespace Ryujinx.Graphics.Nvdec.Types.Vp9
|
||||
fc.Bits = Bits;
|
||||
fc.SingleRefProb = SingleRefProb;
|
||||
fc.CompRefProb = CompRefProb;
|
||||
|
||||
Span<Array2<Array2<Array6<Array6<Array3<byte>>>>>> coefProbsSpan1 = fc.CoefProbs.AsSpan();
|
||||
Span<Array2<Array2<Array6<Array6<Array4<byte>>>>>> gCoefProbsSpan1 = CoefProbs.AsSpan();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Span<Array2<Array6<Array6<Array3<byte>>>>> coefProbsSpan2 = coefProbsSpan1[i].AsSpan();
|
||||
Span<Array2<Array6<Array6<Array4<byte>>>>> gCoefProbsSpan2 = gCoefProbsSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
Span<Array6<Array6<Array3<byte>>>> coefProbsSpan3 = coefProbsSpan2[j].AsSpan();
|
||||
Span<Array6<Array6<Array4<byte>>>> gCoefProbsSpan3 = gCoefProbsSpan2[j].AsSpan();
|
||||
|
||||
for (int k = 0; k < 2; k++)
|
||||
{
|
||||
Span<Array6<Array3<byte>>> coefProbsSpan4 = coefProbsSpan3[k].AsSpan();
|
||||
Span<Array6<Array4<byte>>> gCoefProbsSpan4 = gCoefProbsSpan3[k].AsSpan();
|
||||
|
||||
for (int l = 0; l < 6; l++)
|
||||
{
|
||||
Span<Array3<byte>> coefProbsSpan5 = coefProbsSpan4[l].AsSpan();
|
||||
Span<Array4<byte>> gCoefProbsSpan5 = gCoefProbsSpan4[l].AsSpan();
|
||||
|
||||
for (int m = 0; m < 6; m++)
|
||||
{
|
||||
Span<byte> coefProbsSpan6 = coefProbsSpan5[m].AsSpan();
|
||||
Span<byte> gCoefProbsSpan6 = gCoefProbsSpan5[m].AsSpan();
|
||||
|
||||
for (int n = 0; n < 3; n++)
|
||||
{
|
||||
fc.CoefProbs[i][j][k][l][m][n] = CoefProbs[i][j][k][l][m][n];
|
||||
coefProbsSpan6[n] = gCoefProbsSpan6[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
[Flags]
|
||||
public enum AttributeType : byte
|
||||
{
|
||||
// Generic types.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user