mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-09-11 20:37:35 +00:00
Compare commits
20 Commits
master
...
gitlab-rel
Author | SHA1 | Date | |
---|---|---|---|
|
740c346b3b | ||
|
c9116e2a52 | ||
|
91248bdd32 | ||
|
64ecd514f2 | ||
|
8aabdd8714 | ||
|
1bf31c91b6 | ||
|
bf5326ec87 | ||
|
6e1e081d90 | ||
|
8b58416003 | ||
|
24f2d91800 | ||
|
783b761745 | ||
|
559d9b4db0 | ||
|
787a14ed2b | ||
|
d0c055ccb8 | ||
|
72935bdbb6 | ||
|
0df51e24dd | ||
|
4b003498a3 | ||
|
23b2576ded | ||
|
3f653626c8 | ||
|
052510ae1a |
122
.github/workflows/canary.yml
vendored
122
.github/workflows/canary.yml
vendored
@@ -24,6 +24,54 @@ env:
|
||||
RELEASE: 1
|
||||
|
||||
jobs:
|
||||
tag:
|
||||
name: Create tag
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Install GitLabCli
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
|
||||
chmod +x gli
|
||||
mv gli $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create GitLab tag
|
||||
run: gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateTag "Canary-${{ steps.version_info.outputs.build_version }}|master"
|
||||
|
||||
- name: Create release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: |
|
||||
# Canary builds:
|
||||
|
||||
These builds are experimental and may sometimes not work, use [regular builds](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/latest) instead if that sounds like something you don't want to deal with.
|
||||
|
||||
| Platform | Artifact |
|
||||
|--|--|
|
||||
| Windows 64-bit | [Canary Windows Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
|
||||
| Windows ARM 64-bit | [Canary Windows ARM Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_arm64.zip) |
|
||||
| Linux 64-bit | [Canary Linux Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
|
||||
| Linux ARM 64-bit | [Canary Linux ARM Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
|
||||
| macOS | [Canary macOS Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
|
||||
|
||||
**[Full Changelog](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})**
|
||||
omitBodyDuringUpdate: true
|
||||
owner: ${{ secrets.RC_OWNER }}
|
||||
repo: ${{ secrets.RC_CANARY_NAME }}
|
||||
token: ${{ secrets.ALT_RELEASE_TOKEN }}
|
||||
|
||||
release:
|
||||
name: Release for ${{ matrix.platform.name }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
@@ -43,6 +91,16 @@ jobs:
|
||||
|
||||
- name: Overwrite csc problem matcher
|
||||
run: echo "::add-matcher::.github/csc.json"
|
||||
|
||||
- name: Install GitLabCli
|
||||
run: |
|
||||
mkdir -p $HOME/.bin
|
||||
gh release download -R GreemDev/GLI -O gli -p 'GitLabCli-linux_x64'
|
||||
chmod +x gli
|
||||
mv gli $HOME/.bin/
|
||||
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
@@ -102,10 +160,10 @@ 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
|
||||
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
@@ -144,7 +202,34 @@ jobs:
|
||||
|
||||
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
|
||||
shell: bash
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: |
|
||||
# Canary builds:
|
||||
|
||||
These builds are experimental and may sometimes not work, use [regular builds](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/latest) instead if that sounds like something you don't want to deal with.
|
||||
|
||||
| Platform | Artifact |
|
||||
|--|--|
|
||||
| Windows 64-bit | [Canary Windows Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
|
||||
| Windows ARM 64-bit | [Canary Windows ARM Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_arm64.zip) |
|
||||
| Linux 64-bit | [Canary Linux Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
|
||||
| Linux ARM 64-bit | [Canary Linux ARM Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
|
||||
| macOS | [Canary macOS Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_CANARY_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
|
||||
|
||||
**[Full Changelog](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})**
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ secrets.RC_OWNER }}
|
||||
repo: ${{ secrets.RC_CANARY_NAME }}
|
||||
token: ${{ secrets.ALT_RELEASE_TOKEN }}
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
@@ -205,15 +290,28 @@ jobs:
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|publish_ava/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz"
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
||||
artifacts: "publish_ava/*.tar.gz"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: ""
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ secrets.RC_OWNER }}
|
||||
repo: ${{ secrets.RC_CANARY_NAME }}
|
||||
token: ${{ secrets.ALT_RELEASE_TOKEN }}
|
||||
|
||||
create_gitlab_release:
|
||||
name: Create GitLab Release
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- tag
|
||||
- macos_release
|
||||
- release
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
@@ -232,18 +330,6 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create tag
|
||||
run: |
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateTag "Canary-${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}"
|
||||
|
||||
- name: Create release
|
||||
run: |
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=CreateReleaseFromGenericPackageFiles "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|main|Canary ${{ steps.version_info.outputs.build_version }}|**Full Changelog:** [${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})"
|
||||
|
||||
- name: Send notification webhook
|
||||
run: |
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=SendUpdateMessage "${{ steps.version_info.outputs.build_version }}|FF4500|${{ secrets.CANARY_DISCORD_WEBHOOK }}|https://avatars.githubusercontent.com/u/192939710?s=200&v=4|false"
|
||||
|
||||
- name: Notify update server of new builds
|
||||
run: |
|
||||
curl 'https://update.ryujinx.app/api/v1/admin/refresh_cache?rc=canary' -X PATCH -H 'accept: */*' -H 'Authorization: ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }}'
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=CreateReleaseFromGenericPackageFiles "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|main|Canary ${{ steps.version_info.outputs.build_version }}|**[Full Changelog](https://git.ryujinx.app/ryubing/ryujinx/-/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }})**"
|
||||
|
85
.github/workflows/release.yml
vendored
85
.github/workflows/release.yml
vendored
@@ -14,6 +14,38 @@ env:
|
||||
RELEASE: 1
|
||||
|
||||
jobs:
|
||||
tag:
|
||||
name: Create tag
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Get version info
|
||||
id: version_info
|
||||
run: |
|
||||
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Create release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: |
|
||||
# Stable builds:
|
||||
| Platform | Artifact |
|
||||
|--|--|
|
||||
| Windows 64-bit | [Stable Windows Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
|
||||
| Windows ARM 64-bit | [Stable Windows ARM Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_arm64.zip) |
|
||||
| Linux 64-bit | [Stable Linux Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
|
||||
| Linux ARM 64-bit | [Stable Linux ARM Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
|
||||
| macOS | [Stable macOS Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
|
||||
|
||||
**[Full Changelog](https://git.ryujinx.app/ryubing/ryujinx/-/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }})**
|
||||
omitBodyDuringUpdate: true
|
||||
owner: ${{ secrets.RC_OWNER }}
|
||||
repo: ${{ secrets.RC_STABLE_NAME }}
|
||||
token: ${{ secrets.ALT_RELEASE_TOKEN }}
|
||||
|
||||
release:
|
||||
name: Release for ${{ matrix.platform.name }}
|
||||
runs-on: ${{ matrix.platform.os }}
|
||||
@@ -96,7 +128,7 @@ jobs:
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
@@ -137,6 +169,30 @@ jobs:
|
||||
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
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: |
|
||||
# Stable builds:
|
||||
| Platform | Artifact |
|
||||
|--|--|
|
||||
| Windows 64-bit | [Stable Windows Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
|
||||
| Windows ARM 64-bit | [Stable Windows ARM Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_arm64.zip) |
|
||||
| Linux 64-bit | [Stable Linux Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
|
||||
| Linux ARM 64-bit | [Stable Linux ARM Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
|
||||
| macOS | [Stable macOS Artifact](https://github.com/${{ secrets.RC_OWNER }}/${{ secrets.RC_STABLE_NAME }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
|
||||
|
||||
**[Full Changelog](https://git.ryujinx.app/ryubing/ryujinx/-/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }})**
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ secrets.RC_OWNER }}
|
||||
repo: ${{ secrets.RC_STABLE_NAME }}
|
||||
token: ${{ secrets.ALT_RELEASE_TOKEN }}
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-24.04
|
||||
@@ -193,11 +249,26 @@ jobs:
|
||||
run: |
|
||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|publish/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz"
|
||||
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "publish/*.tar.gz"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: ""
|
||||
omitBodyDuringUpdate: true
|
||||
allowUpdates: true
|
||||
replacesArtifacts: true
|
||||
owner: ${{ secrets.RC_OWNER }}
|
||||
repo: ${{ secrets.RC_STABLE_NAME }}
|
||||
token: ${{ secrets.ALT_RELEASE_TOKEN }}
|
||||
|
||||
create_gitlab_release:
|
||||
name: Create GitLab Release
|
||||
runs-on: ubuntu-24.04
|
||||
needs:
|
||||
- tag
|
||||
- macos_release
|
||||
- release
|
||||
steps:
|
||||
@@ -223,12 +294,4 @@ jobs:
|
||||
|
||||
- name: Create release
|
||||
run: |
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateReleaseFromGenericPackageFiles "Ryubing|${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}|${{ steps.version_info.outputs.build_version }}|msd:${{ steps.version_info.outputs.build_version }}"
|
||||
|
||||
- name: Send notification webhook
|
||||
run: |
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=SendUpdateMessage "${{ steps.version_info.outputs.build_version }}|32cd32|${{ secrets.STABLE_DISCORD_WEBHOOK }}|https://avatars.githubusercontent.com/u/192939710?s=200&v=4|false"
|
||||
|
||||
- name: Notify update server of new builds
|
||||
run: |
|
||||
curl 'https://update.ryujinx.app/api/v1/admin/refresh_cache?rc=stable' -X PATCH -H 'accept: */*' -H 'Authorization: ${{ secrets.UPDATE_SERVER_ADMIN_TOKEN }}'
|
||||
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=CreateReleaseFromGenericPackageFiles "Ryubing|${{ steps.version_info.outputs.build_version }}|${{ steps.version_info.outputs.git_short_hash }}|${{ steps.version_info.outputs.build_version }}|**[Full Changelog](https://git.ryujinx.app/ryubing/ryujinx/-/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }})**"
|
||||
|
18
BuildAndPushLibraries.sh
Normal file
18
BuildAndPushLibraries.sh
Normal file
@@ -0,0 +1,18 @@
|
||||
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
|
49
CHANGELOG.md
49
CHANGELOG.md
@@ -2,17 +2,20 @@
|
||||
|
||||
All updates to this Ryujinx branch will be documented in this file.
|
||||
|
||||
## [1.3.2](<https://git.ryujinx.app/ryubing/ryujinx/-/releases/1.3.2>) - 2025-06-09
|
||||
|
||||
## [1.3.1](<https://git.ryujinx.app/ryubing/ryujinx/-/releases/1.3.1>) - 2025-04-23
|
||||
A list of notable changes can be found on the release linked in the version number above.
|
||||
|
||||
## [1.2.86](<https://github.com/Ryubing/Stable-Releases/releases/tag/1.2.86>) - 2025-03-13
|
||||
A list of notable changes can be found on the release linked in the version number above.
|
||||
|
||||
## [1.2.82](<https://web.archive.org/web/20250312010534/https://github.com/Ryubing/Ryujinx/releases/tag/1.2.82>) - 2025-02-16
|
||||
A list of notable changes can be found on the release linked in the version number above.
|
||||
|
||||
## [1.2.80-81](<https://web.archive.org/web/20250302064257/https://github.com/Ryubing/Ryujinx/releases/tag/1.2.81>) - 2025-01-22
|
||||
A list of notable changes can be found on the release linked in the version number above.
|
||||
|
||||
## [1.2.78](<https://web.archive.org/web/20250301174537/https://github.com/Ryubing/Ryujinx/releases/tag/1.2.78>) - 2024-12-19
|
||||
A list of notable changes can be found on the release linked in the version number above.
|
||||
|
||||
## [1.2.73-1.2.76](<https://web.archive.org/web/20250209202612/https://github.com/Ryubing/Ryujinx/releases/tag/1.2.76>) - 2024-11-19
|
||||
A list of notable changes can be found on the release linked in the version number above.
|
||||
@@ -21,8 +24,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://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>)
|
||||
## [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>)
|
||||
### HLE:
|
||||
- Add DebugMouse HID device.
|
||||
- Fixes "Clock Tower Rewind" crashing while loading.
|
||||
@@ -32,7 +35,7 @@ PRs [#163](<https://web.archive.org/web/20241123015123/https://github.com/GreemD
|
||||
### misc:
|
||||
- Update macOS distribution .icns.
|
||||
|
||||
## [1.2.69](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.69>) - 2024-11-01
|
||||
## [1.2.69](<https://github.com/GreemDev/Ryujinx/releases/tag/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 +45,8 @@ PRs [#163](<https://web.archive.org/web/20241123015123/https://github.com/GreemD
|
||||
- Replace "" with `string.Empty`.
|
||||
- Code cleanups & simplifications.
|
||||
|
||||
## [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>)
|
||||
## [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>)
|
||||
|
||||
### GUI:
|
||||
- Set UseFloatingWatermark to false when watermark is empty
|
||||
@@ -54,8 +57,8 @@ PRs [#36](<https://web.archive.org/web/20250306215917/https://github.com/Ryubing
|
||||
- Fix homebrew loading.
|
||||
|
||||
|
||||
## [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)~~
|
||||
## [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)
|
||||
### 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 +74,14 @@ PRs [#92](https://web.archive.org/web/20241118052724/https://github.com/GreemDev
|
||||
|
||||
## 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://web.archive.org/web/20241126203614/https://github.com/GreemDev/Ryujinx/pull/42)
|
||||
PRs [#60](https://github.com/GreemDev/Ryujinx/pull/60), [#42](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 +107,7 @@ PRs ~~[#60](https://github.com/GreemDev/Ryujinx/pull/60)~~, [#42](https://web.ar
|
||||
- Code cleanup.
|
||||
|
||||
## 1.2.44 - 2024-10-25
|
||||
PR [#59](https://web.archive.org/web/20241125060420/https://github.com/GreemDev/Ryujinx/pull/59)
|
||||
PR [#59](https://github.com/GreemDev/Ryujinx/pull/59)
|
||||
### GUI:
|
||||
- Add descriptions for "ignoring applet" translated into other languages.
|
||||
|
||||
@@ -117,9 +120,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: [archive of github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9](https://web.archive.org/web/20241122193401/https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9)
|
||||
Init function: https://github.com/MutantAura/Ryujinx/commit/9cef4ceba40d66492ff775af793ff70e6e7551a9
|
||||
|
||||
Shader counter: ~~https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357~~ Original commit has been lost
|
||||
Shader counter: https://github.com/MutantAura/Ryujinx/commit/67b873645fd593e83d042a77bf7ab12e5ec97357
|
||||
|
||||
Thanks MutantAura :D
|
||||
### GUI:
|
||||
@@ -127,14 +130,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 +151,30 @@ Thanks Вова С!
|
||||
- Should prevent crashing on config loads in some circumstances.
|
||||
|
||||
## 1.2.38 - 2024-10-23
|
||||
PR [#51](https://web.archive.org/web/20241127022413/https://github.com/GreemDev/Ryujinx/pull/51)
|
||||
PR [#51](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://web.archive.org/web/20241123010103/https://github.com/GreemDev/Ryujinx/pull/37)
|
||||
PR [#37](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://web.archive.org/web/20241127010942/https://github.com/GreemDev/Ryujinx/pull/32)
|
||||
PR [#32](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://web.archive.org/web/20241125093029/https://github.com/GreemDev/Ryujinx/pull/29)
|
||||
PR [#29](https://github.com/GreemDev/Ryujinx/pull/29)
|
||||
### GUI:
|
||||
- Fix duplicate controller names when 2 controllers of the same type are connected.
|
||||
### INPUT:
|
||||
@@ -248,7 +251,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://web.archive.org/web/20241127004005/https://github.com/GreemDev/Ryujinx/pull/12)).
|
||||
- Autoload DLC/Updates from dir ([#12](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.
|
||||
- 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.6.1.70" />
|
||||
<PackageVersion Include="DynamicData" Version="9.4.1" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
@@ -40,13 +40,11 @@
|
||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.116" />
|
||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.20.0-alpha.107" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||
<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="Gommon" Version="2.7.1.1" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.11.1" />
|
||||
<PackageVersion Include="Sep" Version="0.6.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
|
14
README.md
14
README.md
@@ -7,8 +7,8 @@
|
||||
|
||||
# Ryujinx
|
||||
|
||||
[](https://update.ryujinx.app/latest/stable)
|
||||
[](https://update.ryujinx.app/latest/canary)
|
||||
[](https://github.com/Ryubing/Stable-Releases/releases/latest)
|
||||
[](https://github.com/Ryubing/Canary-Releases/releases/latest)
|
||||
<br>
|
||||
<a href="https://discord.gg/PEuzjrFXUA">
|
||||
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryubing&logo=discord&logoColor=white" alt="Discord">
|
||||
@@ -31,7 +31,7 @@
|
||||
<br>
|
||||
This is not a Ryujinx revival project. This is not a Phoenix project.
|
||||
<br>
|
||||
Guides and documentation can be found on the <a href="https://git.ryujinx.app/groups/ryubing/-/wikis/home">Wiki tab</a>.
|
||||
Guides and documentation can be found on the <a href="https://git.ryujinx.app/ryubing/ryujinx/-/wikis/home">Wiki tab</a>.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -49,13 +49,13 @@ Stable builds are made every so often, based on the `master` branch, that then g
|
||||
These stable builds exist so that the end user can get a more **enjoyable and stable experience**.
|
||||
They are released every month or so, to ensure consistent updates, while not being an annoying amount of individual updates to download over the course of that month.
|
||||
|
||||
You can find the stable releases [here](https://git.ryujinx.app/ryubing/ryujinx/-/releases).
|
||||
You can find the latest stable release [here](https://github.com/Ryubing/Stable-Releases/releases/latest).
|
||||
|
||||
Canary builds are compiled automatically for each commit on the `master` branch.
|
||||
While we strive to ensure optimal stability and performance prior to pushing an update, these builds **may be unstable or completely broken**.
|
||||
These canary builds are only recommended for experienced users.
|
||||
|
||||
You can find the canary releases [here](https://git.ryujinx.app/ryubing/canary/-/releases).
|
||||
You can find the latest canary release [here](https://github.com/Ryubing/Canary-Releases/releases/latest).
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -111,7 +111,7 @@ See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY
|
||||
|
||||
## Credits
|
||||
|
||||
- [LibHac](https://git.ryujinx.app/ryubing/libhac) is used for our file-system.
|
||||
- [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system.
|
||||
- [AmiiboAPI](https://www.amiiboapi.com) is used in our Amiibo emulation.
|
||||
- [ldn_mitm](https://github.com/spacemeowx2/ldn_mitm) is used for one of our available multiplayer modes.
|
||||
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
|
||||
- [ShellLink](https://github.com/securifybv/ShellLink) is used for Windows shortcut generation.
|
||||
|
@@ -77,8 +77,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Gene
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
@@ -86,9 +84,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
.github\workflows\canary.yml = .github\workflows\canary.yml
|
||||
Directory.Packages.props = Directory.Packages.props
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
nuget.config = nuget.config
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
7355
assets/locales.json
7355
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 -n --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||
appimagetool --comp zstd --mksquashfs-opt -Xcompression-level --mksquashfs-opt 21 \
|
||||
-u "$UFLAG" \
|
||||
AppDir "$OUTDIR"/Ryujinx.AppImage
|
||||
|
||||
|
@@ -33,29 +33,23 @@ echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
||||
echo "Running bundle fix up python script"
|
||||
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
|
||||
|
||||
# Resign all dyplib files as ad-hoc after changing them
|
||||
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec codesign --force --sign - {} \;
|
||||
|
||||
# Now sign it
|
||||
echo "Starting signing process"
|
||||
if ! [ -x "$(command -v codesign)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v rcodesign)" ];
|
||||
then
|
||||
echo "Cannot find rcodesign on your system, please install rcodesign and ensure it is in your search path."
|
||||
echo "Cannot find rcodesign on your system, please install rcodesign."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# cargo install apple-codesign
|
||||
echo "Using rcodesign for ad-hoc signing"
|
||||
|
||||
echo "Resigning all frameworks dylib files as ad-hoc"
|
||||
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec rcodesign sign {} \;
|
||||
|
||||
echo "Signing app bundle as ad-hoc"
|
||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
||||
else
|
||||
echo "Using codesign for ad-hoc signing"
|
||||
|
||||
echo "Resigning all frameworks dylib files as ad-hoc"
|
||||
find "$APP_BUNDLE_DIRECTORY/Contents/Frameworks" -type f -name "*.dylib" -exec codesign --force --sign - {} \;
|
||||
|
||||
echo "Signing app bundle as ad-hoc"
|
||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$APP_BUNDLE_DIRECTORY"
|
||||
fi
|
||||
|
@@ -20,18 +20,6 @@ SOURCE_REVISION_ID=$6
|
||||
CONFIGURATION=$7
|
||||
CANARY=$8
|
||||
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
echo "Clearing xattr on all dot undercsore files"
|
||||
find "$BASE_DIR" -type f -name "._*" -exec sh -c '
|
||||
for f; do
|
||||
dir=$(dirname "$f")
|
||||
base=$(basename "$f")
|
||||
orig="$dir/${base#._}"
|
||||
[ -f "$orig" ] && xattr -c "$orig" || true
|
||||
done
|
||||
' sh {} +
|
||||
fi
|
||||
|
||||
if [ "$CANARY" == "1" ]; then
|
||||
RELEASE_TAR_FILE_NAME=ryujinx-canary-$VERSION-macos_universal.app.tar
|
||||
elif [ "$VERSION" == "1.1.0" ]; then
|
||||
|
@@ -20,18 +20,6 @@ SOURCE_REVISION_ID=$6
|
||||
CONFIGURATION=$7
|
||||
CANARY=$8
|
||||
|
||||
if [[ "$(uname)" == "Darwin" ]]; then
|
||||
echo "Clearing xattr on all dot undercsore files"
|
||||
find "$BASE_DIR" -type f -name "._*" -exec sh -c '
|
||||
for f; do
|
||||
dir=$(dirname "$f")
|
||||
base=$(basename "$f")
|
||||
orig="$dir/${base#._}"
|
||||
[ -f "$orig" ] && xattr -c "$orig" || true
|
||||
done
|
||||
' sh {} +
|
||||
fi
|
||||
|
||||
if [ "$CANARY" == "1" ]; then
|
||||
RELEASE_TAR_FILE_NAME=nogui-ryujinx-canary-$VERSION-macos_universal.tar
|
||||
elif [ "$VERSION" == "1.1.0" ]; then
|
||||
|
@@ -188,8 +188,6 @@
|
||||
01003DD00BFEE000,"Airheart - Tales of broken Wings",,playable,2021-02-26 15:20:27
|
||||
01007F100DE52000,"Akane",nvdec,playable,2022-07-21 00:12:18
|
||||
01009A800F0C8000,"Akash: Path of the Five",gpu;nvdec,ingame,2020-12-14 22:33:12
|
||||
01009E8012976000,"AKIBA'S TRIP: Hellbound & Debriefed",,playable,2025-07-30 23:22:47
|
||||
0100D74019A0E000,"AKIBA'S TRIP: Undead & Undressed Director's Cut",,playable,2025-07-31 13:58:42
|
||||
010053100B0EA000,"Akihabara - Feel the Rhythm Remixed",,playable,2021-02-22 14:39:35
|
||||
0100D4C00EE0C000,"Akuarium",slow,playable,2020-12-12 23:43:36
|
||||
010026E00FEBE000,"Akuto: Showdown",,playable,2020-08-04 19:43:27
|
||||
@@ -978,7 +976,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;slow,menus,2024-08-03 05:25:47
|
||||
010029D00E740000,"DOOM 3",crash,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 +1095,6 @@
|
||||
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
|
||||
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
|
||||
@@ -1128,7 +1125,6 @@
|
||||
0100034012606000,"Family Mysteries: Poisonous Promises",audio;crash,menus,2021-11-26 12:35:06
|
||||
010017C012726000,"Fantasy Friends",,playable,2022-10-17 19:42:39
|
||||
0100767008502000,"FANTASY HERO ~unsigned legacy~",,playable,2022-07-26 12:28:52
|
||||
0100755017EE0000,"FANTASY LIFE i: The Girl Who Steals Time",gpu;crash;vulkan-backend-bug,ingame,2025-06-08 20:41:00
|
||||
0100944003820000,"Fantasy Strike",online,playable,2021-02-27 01:59:18
|
||||
01000E2012F6E000,"Fantasy Tavern Sextet -Vol.1 New World Days-",gpu;crash;Needs Update,ingame,2022-12-05 16:48:00
|
||||
01005C10136CA000,"Fantasy Tavern Sextet -Vol.2 Adventurer's Days-",gpu;slow;crash,ingame,2021-11-06 02:57:29
|
||||
@@ -1243,8 +1239,6 @@
|
||||
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
|
||||
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
|
||||
010038A007AA4000,"FruitFall Crush",,playable,2020-10-20 11:33:33
|
||||
@@ -1440,7 +1434,6 @@
|
||||
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
|
||||
@@ -1450,7 +1443,6 @@
|
||||
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
|
||||
@@ -1525,7 +1517,6 @@
|
||||
010095C016C14000,"Iridium",,playable,2022-08-05 23:19:53
|
||||
0100AD300B786000,"Iris School of Wizardry -Vinculum Hearts-",,playable,2022-12-05 13:11:15
|
||||
0100945012168000,"Iris.Fall",nvdec,playable,2022-10-18 13:40:22
|
||||
010059801B736000,"IronFall: Invasion",,playable,2025-07-30 11:42:30
|
||||
01005270118D6000,"Iron Wings",slow,ingame,2022-08-07 08:32:57
|
||||
01004DB003E6A000,"IRONCAST",,playable,2021-01-13 13:54:29
|
||||
0100E5700CD56000,"Irony Curtain: From Matryoshka with Love",,playable,2021-06-04 20:12:37
|
||||
@@ -1889,7 +1880,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
|
||||
@@ -2265,7 +2256,6 @@
|
||||
010086F0064CE000,"Poi: Explorer Edition",nvdec,playable,2021-01-21 19:32:00
|
||||
0100EB6012FD2000,"Poison Control",,playable,2021-05-16 14:01:54
|
||||
010072400E04A000,"Pokémon Café ReMix",,playable,2021-08-17 20:00:04
|
||||
010008c01e742000,"Pokémon Friends",crash;services,menus,2025-07-24 13:32:00
|
||||
01003D200BAA2000,"Pokémon Mystery Dungeon™: Rescue Team DX",mac-bug,playable,2024-01-21 00:16:32
|
||||
01008DB008C2C000,"Pokémon Shield + Pokémon Shield Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-12 07:20:22
|
||||
0100ABF008968000,"Pokémon Sword + Pokémon Sword Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-26 15:40:37
|
||||
@@ -2314,7 +2304,6 @@
|
||||
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
|
||||
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
|
||||
@@ -2446,7 +2435,6 @@
|
||||
0100E9C010EA8000,"Rise of Insanity",,playable,2020-08-30 15:42:14
|
||||
01006BA00E652000,"Rise: Race The Future",,playable,2021-02-27 13:29:06
|
||||
010020C012F48000,"Rising Hell",,playable,2022-10-31 13:54:02
|
||||
0100D1801A0F4000,"Risk of Rain Returns",,playable,2025-06-28 04:24:04
|
||||
010076D00E4BA000,"Risk of Rain 2",online-broken,playable,2024-03-04 17:01:05
|
||||
0100E8300A67A000,"RISK® Global Domination",nvdec;online-broken,playable,2022-08-01 18:53:28
|
||||
010042500FABA000,"Ritual: Crown of Horns",,playable,2021-01-26 16:01:47
|
||||
@@ -2580,7 +2568,6 @@
|
||||
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
|
||||
@@ -2758,7 +2745,6 @@
|
||||
01005D701264A000,"SpyHack",,playable,2021-04-15 10:53:51
|
||||
010077B00E046000,"Spyro™ Reignited Trilogy",nvdec;UE4,playable,2022-09-11 18:38:33
|
||||
0100085012A0E000,"Squeakers",,playable,2020-12-13 12:13:05
|
||||
0100E1D01EB2E000,"Squeakross: Home Squeak Home",,playable,2025-06-16 02:02:00
|
||||
010009300D31C000,"Squidgies Takeover",,playable,2020-07-20 22:28:08
|
||||
0100FCD0102EC000,"Squidlit",,playable,2020-08-06 12:38:32
|
||||
0100EBF00E702000,"STAR OCEAN First Departure R",nvdec,playable,2021-07-05 19:29:16
|
||||
@@ -2778,7 +2764,7 @@
|
||||
0100E6B0115FC000,"Star99",online,menus,2021-11-26 14:18:51
|
||||
01002100137BA000,"Stardash",,playable,2021-01-21 16:31:19
|
||||
0100E65002BB8000,"Stardew Valley",online-broken;ldn-untested,playable,2024-02-14 03:11:19
|
||||
01002CC003FE6000,"Starlink: Battle for Atlas™ Digital Edition",,playable,2025-07-30 12:09:37
|
||||
01002CC003FE6000,"Starlink: Battle for Atlas™ Digital Edition",services-horizon;crash;Needs Update,nothing,2024-05-05 17:25:11
|
||||
010098E010FDA000,"Starlit Adventures Golden Stars",,playable,2020-11-21 12:14:43
|
||||
01001BB00AC26000,"STARSHIP AVENGER Operation: Take Back Earth",,playable,2021-01-12 15:52:55
|
||||
010000700A572000,"State of Anarchy: Master of Mayhem",nvdec,playable,2021-01-12 19:00:05
|
||||
@@ -2979,7 +2965,6 @@
|
||||
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
|
||||
@@ -2987,7 +2972,6 @@
|
||||
0100C2E0129A6000,"The Executioner",nvdec,playable,2021-01-23 00:31:28
|
||||
01006050114D4000,"The Experiment: Escape Room",gpu,ingame,2022-09-30 13:20:35
|
||||
0100B5900DFB2000,"The Eyes of Ara",,playable,2022-09-16 14:44:06
|
||||
0100BA5013E52000,"The Falconeer: Warrior Edition",,playable,2025-07-30 12:04:50
|
||||
01002DD00AF9E000,"The Fall",gpu,ingame,2020-05-31 23:31:16
|
||||
01003E5002320000,"The Fall Part 2: Unbound",,playable,2021-11-06 02:18:08
|
||||
0100CDC00789E000,"The Final Station",nvdec,playable,2022-08-22 15:54:39
|
||||
@@ -3031,7 +3015,6 @@
|
||||
01009B101044C000,"The Legend of Heroes: Trails of Cold Steel III Demo",demo;nvdec,playable,2021-04-23 01:07:32
|
||||
0100D3C010DE8000,"The Legend of Heroes: Trails of Cold Steel IV",nvdec,playable,2021-04-23 14:01:05
|
||||
01005E5013862000,"THE LEGEND OF HEROES: ZERO NO KISEKI KAI [英雄傳說 零之軌跡:改]",crash,nothing,2021-09-30 14:41:07
|
||||
01009C901ACEE000,"The Legend of Nayuta: Boundless Trails",,ingame,2025-06-12 15:47
|
||||
01008CF01BAAC000,"The Legend of Zelda Echoes of Wisdom",nvdec;ASTC;intel-vendor-bug,playable,2024-10-01 14:11:01
|
||||
0100509005AF2000,"The Legend of Zelda: Breath of the Wild Demo",demo,ingame,2022-12-24 05:02:58
|
||||
01007EF00011E000,"The Legend of Zelda™: Breath of the Wild",gpu;amd-vendor-bug;mac-bug,ingame,2024-09-23 19:35:46
|
||||
@@ -3210,7 +3193,6 @@
|
||||
010000400F582000,"TT Isle of Man Ride on the Edge 2",gpu;nvdec;online-broken,ingame,2022-09-30 22:13:05
|
||||
0100752011628000,"TTV2",,playable,2020-11-27 13:21:36
|
||||
0100AFE00452E000,"Tumblestone",,playable,2021-01-07 17:49:20
|
||||
0100D1A01D7BA000,"Turbo Overkill",,playable,2025-07-30 12:08:57
|
||||
010085500D5F6000,"Turok",gpu,ingame,2021-06-04 13:16:24
|
||||
0100CDC00D8D6000,"Turok 2: Seeds of Evil",gpu;vulkan,ingame,2022-09-12 17:50:05
|
||||
010004B0130C8000,"Turrican Flashback",audout,playable,2021-08-30 10:07:56
|
||||
@@ -3234,8 +3216,6 @@
|
||||
0100592005164000,"UNBOX: Newbie's Adventure",UE4,playable,2022-08-29 13:12:56
|
||||
01002D900C5E4000,"Uncanny Valley",nvdec,playable,2021-06-04 13:28:45
|
||||
010076F011F54000,"Undead & Beyond",nvdec,playable,2022-10-04 09:11:18
|
||||
01009B700D0B8000,"Undead Horde",,playable,2025-07-30 12:05:05
|
||||
0100FC301A878000,"Undead Horde 2: Necropolis",,playable,2025-07-30 12:06:07
|
||||
01008F3013E4E000,"Under Leaves",,playable,2021-05-22 18:13:58
|
||||
010080B00AD66000,"Undertale",,playable,2022-08-31 17:31:46
|
||||
01008F80049C6000,"Unepic",,playable,2024-01-15 17:03:00
|
||||
|
|
12
nuget.config
12
nuget.config
@@ -4,20 +4,18 @@
|
||||
<packageSources>
|
||||
<clear />
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||
<!-- Only needed when using pre-release versions of Ryujinx.LibHac. -->
|
||||
<add key="LibHacAlpha" value="https://git.ryujinx.app/api/v4/projects/17/packages/nuget/index.json" />
|
||||
<add key="Ryujinx.UpdateClient" value="https://git.ryujinx.app/api/v4/projects/71/packages/nuget/index.json" />
|
||||
<add key="RyubingPkgs" value="https://git.ryujinx.app/api/v4/projects/1/packages/nuget/index.json" />
|
||||
</packageSources>
|
||||
|
||||
<!-- Define mappings by adding package patterns beneath the target source. -->
|
||||
<!-- Ryujinx.LibHac packages will be restored from LibHacAlpha,
|
||||
everything else from nuget.org. -->
|
||||
<packageSourceMapping>
|
||||
<!-- key value for <packageSource> should match key values from <packageSources> element -->
|
||||
<!-- These are defined and .NET still yells about multiple package sources with no mappings. Not sure what to do, this is in the docs lol -->
|
||||
<packageSource key="nuget.org">
|
||||
<package pattern="*" />
|
||||
</packageSource>
|
||||
<packageSource key="Ryujinx.UpdateClient">
|
||||
<package pattern="Ryujinx.UpdateClient" />
|
||||
<package pattern="Ryujinx.Systems.Update.Common" />
|
||||
</packageSource>
|
||||
<packageSource key="LibHacAlpha">
|
||||
<package pattern="Ryujinx.LibHac" />
|
||||
</packageSource>
|
||||
|
@@ -143,12 +143,6 @@ 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)
|
||||
@@ -163,24 +157,12 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
||||
{
|
||||
if (context.IsSingleStep)
|
||||
{
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
target = context.ZeroExtend32(OperandType.I64, target);
|
||||
}
|
||||
|
||||
context.Return(target);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitTableBranch(context, target, isJump: false);
|
||||
}
|
||||
EmitTableBranch(context, target, isJump: false);
|
||||
}
|
||||
|
||||
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
||||
{
|
||||
if (isReturn || context.IsSingleStep)
|
||||
if (isReturn)
|
||||
{
|
||||
if (target.Type == OperandType.I32)
|
||||
{
|
||||
|
@@ -3,7 +3,6 @@ using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
@@ -201,11 +200,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
ExecutionContext context = GetContext();
|
||||
|
||||
// If debugging, we'll handle interrupts outside
|
||||
if (!Optimizations.EnableDebugging)
|
||||
{
|
||||
context.CheckInterrupt();
|
||||
}
|
||||
context.CheckInterrupt();
|
||||
|
||||
Statistics.ResumeTimer();
|
||||
|
||||
|
@@ -12,7 +12,6 @@ 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,5 +1,4 @@
|
||||
using ARMeilleure.Memory;
|
||||
using System.Threading;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
@@ -11,7 +10,7 @@ namespace ARMeilleure.State
|
||||
|
||||
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
||||
|
||||
internal bool Interrupted { get; private set; }
|
||||
private bool _interrupted;
|
||||
|
||||
private readonly ICounter _counter;
|
||||
|
||||
@@ -66,8 +65,6 @@ namespace ARMeilleure.State
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
{
|
||||
get
|
||||
@@ -93,19 +90,14 @@ 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)
|
||||
{
|
||||
@@ -113,7 +105,6 @@ namespace ARMeilleure.State
|
||||
_counter = counter;
|
||||
_interruptCallback = interruptCallback;
|
||||
_breakCallback = breakCallback;
|
||||
_stepCallback = stepCallback;
|
||||
_supervisorCallback = supervisorCallback;
|
||||
_undefinedCallback = undefinedCallback;
|
||||
|
||||
@@ -136,9 +127,9 @@ namespace ARMeilleure.State
|
||||
|
||||
internal void CheckInterrupt()
|
||||
{
|
||||
if (Interrupted)
|
||||
if (_interrupted)
|
||||
{
|
||||
Interrupted = false;
|
||||
_interrupted = false;
|
||||
|
||||
_interruptCallback?.Invoke(this);
|
||||
}
|
||||
@@ -148,37 +139,16 @@ namespace ARMeilleure.State
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
Interrupted = true;
|
||||
}
|
||||
|
||||
public void StepHandler()
|
||||
{
|
||||
_stepCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
public void RequestDebugStep()
|
||||
{
|
||||
Interlocked.Exchange(ref ShouldStep, 1);
|
||||
RequestInterrupt();
|
||||
_interrupted = true;
|
||||
}
|
||||
|
||||
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,12 +22,6 @@ 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();
|
||||
@@ -45,11 +39,6 @@ namespace ARMeilleure.State
|
||||
|
||||
public ulong GetPc()
|
||||
{
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
return GetStorage().DebugPrecisePc;
|
||||
}
|
||||
|
||||
// TODO: More precise tracking of PC value.
|
||||
return GetStorage().DispatchAddress;
|
||||
}
|
||||
@@ -279,11 +268,6 @@ 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,7 +52,6 @@ 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 = [];
|
||||
@@ -67,8 +66,7 @@ namespace ARMeilleure.Translation
|
||||
ulong entryAddress,
|
||||
bool highCq,
|
||||
bool hasPtc,
|
||||
Aarch32Mode mode,
|
||||
bool isSingleStep)
|
||||
Aarch32Mode mode)
|
||||
{
|
||||
Memory = memory;
|
||||
CountTable = countTable;
|
||||
@@ -78,7 +76,6 @@ 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 = 7009; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 7008; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
@@ -193,7 +193,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
_infosStream.Seek(0L, SeekOrigin.Begin);
|
||||
bool foundBadFunction = false;
|
||||
|
||||
for (int index = 0; index < _infosStream.Length / Unsafe.SizeOf<InfoEntry>(); index++)
|
||||
for (int index = 0; index < GetEntriesCount(); index++)
|
||||
{
|
||||
InfoEntry infoEntry = DeserializeStructure<InfoEntry>(_infosStream);
|
||||
foreach (ulong address in blacklist)
|
||||
@@ -303,13 +303,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
return false;
|
||||
}
|
||||
|
||||
if (outerHeader.DebuggerMode != Optimizations.EnableDebugging)
|
||||
{
|
||||
InvalidateCompressedStream(compressedStream);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nint intPtr = nint.Zero;
|
||||
|
||||
try
|
||||
@@ -486,7 +479,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
MemoryManagerMode = GetMemoryManagerMode(),
|
||||
OSPlatform = GetOSPlatform(),
|
||||
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
||||
DebuggerMode = Optimizations.EnableDebugging,
|
||||
|
||||
UncompressedStreamSize =
|
||||
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||
@@ -1076,7 +1068,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return osPlatform;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 87*/)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
|
||||
private struct OuterHeader
|
||||
{
|
||||
public ulong Magic;
|
||||
@@ -1088,7 +1080,6 @@ namespace ARMeilleure.Translation.PTC
|
||||
public byte MemoryManagerMode;
|
||||
public uint OSPlatform;
|
||||
public uint Architecture;
|
||||
public bool DebuggerMode;
|
||||
|
||||
public long UncompressedStreamSize;
|
||||
|
||||
|
@@ -119,25 +119,7 @@ namespace ARMeilleure.Translation
|
||||
|
||||
NativeInterface.RegisterThread(context, Memory, this);
|
||||
|
||||
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)
|
||||
if (Optimizations.UseUnmanagedDispatchLoop)
|
||||
{
|
||||
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
||||
}
|
||||
@@ -193,7 +175,7 @@ namespace ARMeilleure.Translation
|
||||
return nextAddr;
|
||||
}
|
||||
|
||||
private ulong Step(State.ExecutionContext context, ulong address)
|
||||
public ulong Step(State.ExecutionContext context, ulong address)
|
||||
{
|
||||
TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
|
||||
|
||||
@@ -204,8 +186,6 @@ namespace ARMeilleure.Translation
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
|
||||
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
||||
{
|
||||
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
||||
@@ -249,8 +229,7 @@ namespace ARMeilleure.Translation
|
||||
address,
|
||||
highCq,
|
||||
_ptc.State != PtcState.Disabled,
|
||||
mode: Aarch32Mode.User,
|
||||
isSingleStep: singleStep);
|
||||
mode: Aarch32Mode.User);
|
||||
|
||||
Logger.StartPass(PassName.Decoding);
|
||||
|
||||
@@ -388,13 +367,9 @@ namespace ARMeilleure.Translation
|
||||
|
||||
if (block.Exit)
|
||||
{
|
||||
// Return to managed rather than tail call.
|
||||
bool useReturns = Optimizations.EnableDebugging;
|
||||
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
EmitDebugPrecisePcUpdate(context, block.Address);
|
||||
}
|
||||
// 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;
|
||||
|
||||
InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
|
||||
}
|
||||
@@ -418,11 +393,6 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
}
|
||||
|
||||
if (Optimizations.EnableDebugging)
|
||||
{
|
||||
EmitDebugPrecisePcUpdate(context, opCode.Address);
|
||||
}
|
||||
|
||||
Operand lblPredicateSkip = default;
|
||||
|
||||
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
||||
@@ -519,14 +489,6 @@ 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)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||
|
||||
return 0;
|
||||
return coefficients[index];
|
||||
}
|
||||
|
||||
return coefficients[index];
|
||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@@ -26,15 +26,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
ReadOnlySpan<float> inputBuffer,
|
||||
uint sampleCount)
|
||||
{
|
||||
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 a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -67,15 +64,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
uint sampleCount,
|
||||
float volume)
|
||||
{
|
||||
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 a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -113,15 +107,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
float volume,
|
||||
float ramp)
|
||||
{
|
||||
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 a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
|
||||
float mixState = 0f;
|
||||
|
||||
@@ -166,16 +157,13 @@ 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(numeratorSpan[0], FixedPointPrecisionForParameter);
|
||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
||||
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 b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
||||
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -213,25 +201,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
uint sampleCount,
|
||||
float volume)
|
||||
{
|
||||
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 a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
||||
|
||||
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
||||
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
||||
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], 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 b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
||||
|
||||
for (int i = 0; i < sampleCount; i++)
|
||||
{
|
||||
@@ -279,24 +261,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
float volume,
|
||||
float ramp)
|
||||
{
|
||||
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 a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
||||
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
||||
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
||||
|
||||
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
||||
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
||||
|
||||
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
||||
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
||||
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], 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 b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
||||
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
||||
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
||||
|
||||
float mixState = 0f;
|
||||
|
||||
|
@@ -39,14 +39,12 @@ 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 waveBufferSpan[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
@@ -29,12 +28,10 @@ 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 + inputSpan[i]);
|
||||
Input[i] = (ushort)(bufferOffset + parameter.Input[i]);
|
||||
}
|
||||
|
||||
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
||||
|
@@ -42,14 +42,11 @@ 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 + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,12 +171,10 @@ 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++)
|
||||
{
|
||||
lastSamplesSpan[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
||||
statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -52,14 +52,12 @@ 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 waveBufferSpan[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(2);
|
||||
}
|
||||
|
@@ -42,14 +42,11 @@ 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 + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
}
|
||||
|
||||
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
||||
|
@@ -42,15 +42,14 @@ 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 (lastSamplesSpan[i] != 0)
|
||||
if (state.LastSamples[i] != 0)
|
||||
{
|
||||
depopBuffer[OutputBufferIndices[i]] += lastSamplesSpan[i];
|
||||
depopBuffer[OutputBufferIndices[i]] += state.LastSamples[i];
|
||||
|
||||
lastSamplesSpan[i] = 0;
|
||||
state.LastSamples[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -34,12 +34,10 @@ 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 + inputSpan[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + sink.Parameter.Input[i]);
|
||||
}
|
||||
|
||||
if (sink.UpsamplerState != null)
|
||||
|
@@ -37,14 +37,11 @@ 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 + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -48,14 +48,11 @@ 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 + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,11 +150,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||
{
|
||||
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
|
||||
|
||||
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);
|
||||
statistics.InputMax[channelIndex] = Math.Max(statistics.InputMax[channelIndex], sampleInputMax);
|
||||
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], compressionGain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -79,10 +79,6 @@ 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]);
|
||||
@@ -91,13 +87,15 @@ 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)
|
||||
{
|
||||
lastSamplesSpan[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
||||
state.LastSamples[i] = ProcessMixRampGrouped(outputBuffer, inputBuffer, volume0, volume1, (int)context.SampleCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastSamplesSpan[i] = 0;
|
||||
state.LastSamples[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -42,12 +42,10 @@ 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 waveBufferSpan[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
@@ -42,12 +42,10 @@ 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 waveBufferSpan[i];
|
||||
ref Server.Voice.WaveBuffer voiceWaveBuffer = ref serverState.WaveBuffers[i];
|
||||
|
||||
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||
}
|
||||
|
@@ -65,14 +65,11 @@ 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 + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
}
|
||||
|
||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
||||
|
@@ -63,14 +63,11 @@ 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 + inputSpan[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
||||
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||
}
|
||||
|
||||
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
||||
|
@@ -74,7 +74,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
{
|
||||
int tempBufferIndex = 0;
|
||||
|
||||
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) != DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||
if (!info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||
{
|
||||
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
||||
tempBufferIndex += pitchMaxLength;
|
||||
@@ -208,7 +208,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
break;
|
||||
}
|
||||
|
||||
if ((info.DecodingBehaviour & DecodingBehaviour.PlayedSampleCountResetWhenLooping) == DecodingBehaviour.PlayedSampleCountResetWhenLooping)
|
||||
if (info.DecodingBehaviour.HasFlag(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 & DecodingBehaviour.SkipPitchAndSampleRateConversion) == DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
||||
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||
{
|
||||
for (int j = 0; j < y; j++)
|
||||
{
|
||||
|
@@ -41,12 +41,11 @@ 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;
|
||||
resultSpan[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||
result[i] = Sinc(x) * BlackmanWindow(x / FilterBankLength + 0.5f);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -79,9 +78,6 @@ 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)
|
||||
@@ -92,15 +88,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
||||
while (curIdx < stopIdx)
|
||||
{
|
||||
result += Vector.Dot(
|
||||
new Vector<float>(bankSpan[curIdx..(curIdx + Vector<float>.Count)]),
|
||||
new Vector<float>(historySpan[curIdx..(curIdx + Vector<float>.Count)]));
|
||||
new Vector<float>(bank.AsSpan().Slice(curIdx, Vector<float>.Count)),
|
||||
new Vector<float>(state.History.AsSpan().Slice(curIdx, Vector<float>.Count)));
|
||||
curIdx += Vector<float>.Count;
|
||||
}
|
||||
}
|
||||
|
||||
while (curIdx < FilterBankLength)
|
||||
{
|
||||
result += bankSpan[curIdx] * historySpan[curIdx];
|
||||
result += bank[curIdx] * state.History[curIdx];
|
||||
curIdx++;
|
||||
}
|
||||
|
||||
|
@@ -141,20 +141,18 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
||||
|
||||
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
||||
|
||||
if (supportsOptimizedPath && biquadFiltersSpan[0].Enable && biquadFiltersSpan[1].Enable)
|
||||
if (supportsOptimizedPath && voiceState.BiquadFilters[0].Enable && voiceState.BiquadFilters[1].Enable)
|
||||
{
|
||||
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
||||
Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory);
|
||||
|
||||
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, biquadFiltersSpan, stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
||||
_commandBuffer.GenerateMultiTapBiquadFilter(baseIndex, voiceState.BiquadFilters.AsSpan(), stateMemory, bufferOffset, bufferOffset, voiceState.BiquadFilterNeedInitialization, nodeId);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < biquadFiltersSpan.Length; i++)
|
||||
for (int i = 0; i < voiceState.BiquadFilters.Length; i++)
|
||||
{
|
||||
ref BiquadFilterParameter filter = ref biquadFiltersSpan[i];
|
||||
ref BiquadFilterParameter filter = ref voiceState.BiquadFilters[i];
|
||||
|
||||
if (filter.Enable)
|
||||
{
|
||||
@@ -313,15 +311,12 @@ 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(channelResourceIdsSpan[channelIndex]);
|
||||
Memory<VoiceUpdateState> dspStateMemory = _voiceContext.GetUpdateStateForDsp(voiceState.ChannelResourceIds[channelIndex]);
|
||||
|
||||
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(channelResourceIdsSpan[channelIndex]);
|
||||
ref VoiceChannelResource channelResource = ref _voiceContext.GetChannelResource(voiceState.ChannelResourceIds[channelIndex]);
|
||||
|
||||
PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm;
|
||||
|
||||
@@ -481,7 +476,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++)
|
||||
{
|
||||
voiceState.BiquadFilterNeedInitialization[i] = biquadFiltersSpan[i].Enable;
|
||||
voiceState.BiquadFilterNeedInitialization[i] = voiceState.BiquadFilters[i].Enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -531,19 +526,15 @@ 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 (volumesSpan[i] != 0.0f)
|
||||
if (effect.Parameter.Volumes[i] != 0.0f)
|
||||
{
|
||||
_commandBuffer.GenerateMix(
|
||||
(uint)bufferOffset + inputSpan[i],
|
||||
(uint)bufferOffset + outputSpan[i],
|
||||
(uint)bufferOffset + effect.Parameter.Input[i],
|
||||
(uint)bufferOffset + effect.Parameter.Output[i],
|
||||
nodeId,
|
||||
volumesSpan[i]);
|
||||
effect.Parameter.Volumes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -563,10 +554,6 @@ 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;
|
||||
@@ -584,8 +571,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_commandBuffer.GenerateAuxEffect(
|
||||
bufferOffset,
|
||||
inputSpan[i],
|
||||
outputSpan[i],
|
||||
effect.Parameter.Input[i],
|
||||
effect.Parameter.Output[i],
|
||||
ref effect.State,
|
||||
effect.IsEnabled,
|
||||
effect.Parameter.BufferStorageSize,
|
||||
@@ -632,9 +619,6 @@ 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)
|
||||
{
|
||||
@@ -655,8 +639,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
(int)bufferOffset,
|
||||
ref parameter,
|
||||
effect.State.Slice(i, 1),
|
||||
inputSpan[i],
|
||||
outputSpan[i],
|
||||
effect.Parameter.Input[i],
|
||||
effect.Parameter.Output[i],
|
||||
needInitialization,
|
||||
nodeId);
|
||||
}
|
||||
@@ -665,8 +649,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
{
|
||||
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
||||
{
|
||||
uint inputBufferIndex = bufferOffset + inputSpan[i];
|
||||
uint outputBufferIndex = bufferOffset + outputSpan[i];
|
||||
uint inputBufferIndex = bufferOffset + effect.Parameter.Input[i];
|
||||
uint outputBufferIndex = bufferOffset + effect.Parameter.Output[i];
|
||||
|
||||
// If the input and output isn't the same, generate a command.
|
||||
if (inputBufferIndex != outputBufferIndex)
|
||||
@@ -717,8 +701,6 @@ 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--)
|
||||
{
|
||||
@@ -737,7 +719,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
||||
|
||||
_commandBuffer.GenerateCaptureEffect(
|
||||
bufferOffset,
|
||||
inputSpan[i],
|
||||
effect.Parameter.Input[i],
|
||||
effect.State.SendBufferInfo,
|
||||
effect.IsEnabled,
|
||||
effect.Parameter.BufferStorageSize,
|
||||
|
@@ -218,8 +218,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
|
||||
/// <returns>True if any biquad filter is enabled.</returns>
|
||||
public bool IsBiquadFilterEnabled()
|
||||
{
|
||||
Span<BiquadFilterParameter> biquadFiltersSpan = _biquadFilters.AsSpan();
|
||||
return biquadFiltersSpan[0].Enable || biquadFiltersSpan[1].Enable;
|
||||
return _biquadFilters[0].Enable || _biquadFilters[1].Enable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -162,11 +162,9 @@ 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 = channelResourceIdsSpan[channelResourceIndex];
|
||||
int channelId = parameter.ChannelResourceIds[channelResourceIndex];
|
||||
|
||||
Debug.Assert(channelId >= 0 && channelId < context.GetCount());
|
||||
|
||||
|
@@ -126,9 +126,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
_sortedVoices.Span[i] = i;
|
||||
}
|
||||
|
||||
Span<int> sortedVoicesTemp = _sortedVoices[..(int)_voiceCount].Span;
|
||||
int[] sortedVoicesTemp = _sortedVoices[..(int)GetCount()].ToArray();
|
||||
|
||||
sortedVoicesTemp.Sort((a, b) =>
|
||||
Array.Sort(sortedVoicesTemp, (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.CopyTo(_sortedVoices.Span);
|
||||
sortedVoicesTemp.AsSpan().CopyTo(_sortedVoices.Span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -219,17 +219,15 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
/// </summary>
|
||||
private void InitializeWaveBuffers()
|
||||
{
|
||||
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,13 +446,10 @@ 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 waveBuffersSpan[i], ref pWaveBuffersSpan[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
|
||||
UpdateWaveBuffer(errorInfos.AsSpan(i * 2, 2), ref WaveBuffers[i], ref parameter.WaveBuffers[i], parameter.SampleFormat, voiceUpdateState.IsWaveBufferValid[i], mapper, ref behaviourContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,11 +534,9 @@ 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 = channelResourceIdsSpan[i];
|
||||
int channelResourceId = ChannelResourceIds[i];
|
||||
|
||||
ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId);
|
||||
|
||||
@@ -566,12 +559,10 @@ 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++)
|
||||
{
|
||||
waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
||||
WaveBuffers[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
||||
|
||||
for (int j = 0; j < channelCount; j++)
|
||||
{
|
||||
@@ -600,18 +591,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
FlushWaveBufferCount = 0;
|
||||
}
|
||||
|
||||
Span<WaveBuffer> waveBuffersSpan;
|
||||
|
||||
switch (PlayState)
|
||||
{
|
||||
case PlayState.Started:
|
||||
waveBuffersSpan = WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
ref WaveBuffer waveBuffer = ref waveBuffersSpan[i];
|
||||
ref WaveBuffer wavebuffer = ref WaveBuffers[i];
|
||||
|
||||
if (!waveBuffer.IsSendToAudioProcessor)
|
||||
if (!wavebuffer.IsSendToAudioProcessor)
|
||||
{
|
||||
for (int y = 0; y < ChannelsCount; y++)
|
||||
{
|
||||
@@ -620,7 +607,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true;
|
||||
}
|
||||
|
||||
waveBuffer.IsSendToAudioProcessor = true;
|
||||
wavebuffer.IsSendToAudioProcessor = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,13 +626,11 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
||||
return false;
|
||||
|
||||
case PlayState.Stopping:
|
||||
waveBuffersSpan = WaveBuffers.AsSpan();
|
||||
|
||||
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||
{
|
||||
ref WaveBuffer waveBuffer = ref waveBuffersSpan[i];
|
||||
ref WaveBuffer wavebuffer = ref WaveBuffers[i];
|
||||
|
||||
waveBuffer.IsSendToAudioProcessor = true;
|
||||
wavebuffer.IsSendToAudioProcessor = true;
|
||||
|
||||
for (int j = 0; j < ChannelsCount; j++)
|
||||
{
|
||||
@@ -717,11 +702,9 @@ 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(channelResourceIdsSpan[i]);
|
||||
voiceUpdateStates[i] = context.GetUpdateStateForDsp(ChannelResourceIds[i]);
|
||||
}
|
||||
|
||||
return UpdateParametersForCommandGeneration(voiceUpdateStates);
|
||||
|
@@ -33,7 +33,7 @@ namespace Ryujinx.BuildValidationTasks
|
||||
LocalesJson json;
|
||||
|
||||
if (isGitRunner && data.Contains("\r\n"))
|
||||
throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, rebuild locally to fix...");
|
||||
throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, build locally to fix...");
|
||||
|
||||
try
|
||||
{
|
||||
@@ -86,7 +86,7 @@ namespace Ryujinx.BuildValidationTasks
|
||||
}
|
||||
|
||||
if (isGitRunner && encounteredIssue)
|
||||
throw new JsonException("1 or more locales are invalid! Rebuild locally to fix...");
|
||||
throw new JsonException("1 or more locales are invalid!");
|
||||
|
||||
string jsonString = JsonSerializer.Serialize(json, _jsonOptions);
|
||||
|
||||
@@ -102,7 +102,6 @@ namespace Ryujinx.BuildValidationTasks
|
||||
|
||||
struct LocalesJson
|
||||
{
|
||||
public Dictionary<string, string> Info { get; set; }
|
||||
public List<string> Languages { get; set; }
|
||||
public List<LocalesEntry> Locales { get; set; }
|
||||
}
|
||||
|
@@ -10,18 +10,8 @@
|
||||
<Exec WorkingDirectory="$(ProjectDir)bin\Debug\$(TargetFramework)\"
|
||||
Command="dotnet Ryujinx.BuildValidationTasks.dll "$(ProjectDir)..\..\\""
|
||||
ConsoleToMsBuild="true"
|
||||
Condition="'$(RuntimeIdentifier)' == ''"
|
||||
IgnoreExitCode="true">
|
||||
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
|
||||
<Output TaskParameter="ExitCode" PropertyName="BuildExitCode"/>
|
||||
</Exec>
|
||||
|
||||
<PropertyGroup Condition=" '$(OutputOfExec.IndexOf(Unhandled exception))' != '-1'">
|
||||
<ErrorOutput>$(OutputOfExec.Substring($(OutputOfExec.IndexOf("Unhandled exception"))))</ErrorOutput>
|
||||
<ErrorOutput>$(ErrorOutput.Substring(0, $(ErrorOutput.IndexOf(';'))))</ErrorOutput>
|
||||
</PropertyGroup>
|
||||
|
||||
<Error Text="$(ErrorOutput)" Condition=" '$(BuildExitCode)' != '0'"/>
|
||||
Condition="'$(RuntimeIdentifier)' == ''"
|
||||
/>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
</Project>
|
@@ -14,13 +14,12 @@ 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, T parent = null)
|
||||
public void Add(T node)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(node);
|
||||
|
||||
Insert(node, parent);
|
||||
Insert(node);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -77,11 +76,9 @@ namespace Ryujinx.Common.Collections
|
||||
/// Inserts a new node into the tree.
|
||||
/// </summary>
|
||||
/// <param name="node">Node to be inserted</param>
|
||||
/// <param name="parent">Node to be inserted under</param>
|
||||
private void Insert(T node, T parent = null)
|
||||
private void Insert(T node)
|
||||
{
|
||||
T newNode = parent != null ? InsertWithParent(node, parent) : BSTInsert(node);
|
||||
|
||||
T newNode = BSTInsert(node);
|
||||
RestoreBalanceAfterInsertion(newNode);
|
||||
}
|
||||
|
||||
@@ -125,77 +122,10 @@ 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++;
|
||||
@@ -229,7 +159,7 @@ namespace Ryujinx.Common.Collections
|
||||
}
|
||||
else
|
||||
{
|
||||
T element = nodeToDelete.Successor;
|
||||
T element = Minimum(RightOf(nodeToDelete));
|
||||
|
||||
child = RightOf(element);
|
||||
parent = ParentOf(element);
|
||||
@@ -257,9 +187,6 @@ 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)
|
||||
{
|
||||
@@ -314,11 +241,6 @@ 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,7 +9,8 @@ namespace Ryujinx.Common.Collections
|
||||
public T Left;
|
||||
public T Right;
|
||||
public T Parent;
|
||||
public T Predecessor;
|
||||
public T Successor;
|
||||
|
||||
public T Predecessor => IntrusiveRedBlackTreeImpl<T>.PredecessorOf((T)this);
|
||||
public T Successor => IntrusiveRedBlackTreeImpl<T>.SuccessorOf((T)this);
|
||||
}
|
||||
}
|
||||
|
@@ -109,7 +109,7 @@ namespace Ryujinx.Common.Collections
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
Node<TKey, TValue> successor = node.Successor;
|
||||
Node<TKey, TValue> successor = SuccessorOf(node);
|
||||
|
||||
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 = node.Predecessor;
|
||||
Node<TKey, TValue> predecessor = PredecessorOf(node);
|
||||
|
||||
return predecessor != null ? predecessor.Key : default;
|
||||
}
|
||||
@@ -136,10 +136,11 @@ namespace Ryujinx.Common.Collections
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the nodes in the dictionary as key/value pairs into a list.
|
||||
/// Adds all the nodes in the dictionary as key/value pairs into <paramref name="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 = [];
|
||||
@@ -169,7 +170,7 @@ namespace Ryujinx.Common.Collections
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all the nodes in the dictionary into a list.
|
||||
/// Adds all the nodes in the dictionary into <paramref name="list"/>.
|
||||
/// </summary>
|
||||
/// <returns>A list of all KeyValuePairs sorted by Key Order</returns>
|
||||
public List<KeyValuePair<TKey, TValue>> AsList()
|
||||
@@ -283,7 +284,7 @@ namespace Ryujinx.Common.Collections
|
||||
}
|
||||
|
||||
Node<TKey, TValue> newNode = new(key, value, parent);
|
||||
if (parent == null)
|
||||
if (newNode.Parent == null)
|
||||
{
|
||||
Root = newNode;
|
||||
}
|
||||
|
@@ -13,7 +13,6 @@ namespace Ryujinx.Common.Logging
|
||||
Cpu,
|
||||
Emulation,
|
||||
FFmpeg,
|
||||
GdbStub,
|
||||
Font,
|
||||
Gpu,
|
||||
Hid,
|
||||
|
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common.Memory
|
||||
{
|
||||
/// <summary>
|
||||
@@ -19,10 +17,5 @@ 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,7 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -11,126 +10,11 @@ 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 <see cref="ArrayPooling"/>.
|
||||
/// accessor, with memory allocated from <seealso cref="ArrayPool{T}.Shared"/>.
|
||||
/// </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;
|
||||
|
||||
@@ -141,7 +25,7 @@ namespace Ryujinx.Common.Memory
|
||||
private MemoryOwner(int length)
|
||||
{
|
||||
_length = length;
|
||||
_array = ArrayPooling.Get(length);
|
||||
_array = ArrayPool<T>.Shared.Rent(length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -240,7 +124,7 @@ namespace Ryujinx.Common.Memory
|
||||
|
||||
if (array is not null)
|
||||
{
|
||||
ArrayPooling.Return(array);
|
||||
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||
@@ -43,13 +42,10 @@ 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 threadIdsSpan[i], threadId, threadId);
|
||||
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, threadId);
|
||||
|
||||
if (compare == threadId)
|
||||
{
|
||||
@@ -61,11 +57,11 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
||||
for (int i = 0; i < MapSize; i++)
|
||||
{
|
||||
int compare = Interlocked.CompareExchange(ref threadIdsSpan[i], threadId, 0);
|
||||
int compare = Interlocked.CompareExchange(ref ThreadIds[i], threadId, 0);
|
||||
|
||||
if (compare == 0)
|
||||
{
|
||||
structsSpan[i] = initial;
|
||||
Structs[i] = initial;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@@ -2,18 +2,8 @@ namespace Ryujinx.Common
|
||||
{
|
||||
public static class SharedConstants
|
||||
{
|
||||
public const string DefaultLanPlayHost = "ldn.ryujinx.app";
|
||||
public const string DefaultLanPlayHost = "ryuldn.vudjun.com";
|
||||
public const short LanPlayPort = 30456;
|
||||
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";
|
||||
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
||||
}
|
||||
}
|
||||
|
@@ -93,7 +93,6 @@ namespace Ryujinx.Common
|
||||
//The Pokémon Franchise
|
||||
"0100f4300bf2c000", // New Pokémon Snap
|
||||
"0100000011d90000", // Pokémon Brilliant Diamond
|
||||
"010008c01e742000", // Pokémon Friends
|
||||
"01001f5010dfa000", // Pokémon Legends: Arceus
|
||||
"01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX
|
||||
"0100a3d008c5c000", // Pokémon Scarlet
|
||||
@@ -134,6 +133,7 @@ namespace Ryujinx.Common
|
||||
"0100c1f0051b6000", // Donkey Kong Country: Tropical Freeze
|
||||
"0100ed000d390000", // Dr. Kawashima's Brain Training
|
||||
"010067b017588000", // Endless Ocean Luminous
|
||||
"0100d2f00d5c0000", // Nintendo Switch Sports
|
||||
"01006b5012b32000", // Part Time UFO
|
||||
"0100704000B3A000", // Snipperclips
|
||||
"01006a800016e000", // Super Smash Bros. Ultimate
|
||||
@@ -169,8 +169,6 @@ namespace Ryujinx.Common
|
||||
"010056e00853a000", // A Hat in Time
|
||||
"0100fd1014726000", // Baldurs Gate: Dark Alliance
|
||||
"01008c2019598000", // Bluey: The Video Game
|
||||
"010096f00ff22000", // Borderlands 2: Game of the Year Edition
|
||||
"010007400ff24000", // Borderlands: The Pre-Sequel Ultimate Edition
|
||||
"0100c6800b934000", // Brawlhalla
|
||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
||||
"0100744001588000", // Cars 3: Driven to Win
|
||||
@@ -182,7 +180,6 @@ 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
|
||||
@@ -197,7 +194,6 @@ namespace Ryujinx.Common
|
||||
"01008d100d43e000", // Saints Row IV
|
||||
"0100de600beee000", // Saints Row: The Third - The Full Package
|
||||
"01001180021fa000", // Shovel Knight: Specter of Torment
|
||||
"0100e1D01eb2e000", // Squeakross: Home Squeak Home
|
||||
"0100e65002bb8000", // Stardew Valley
|
||||
"0100d7a01b7a2000", // Star Wars: Bounty Hunter
|
||||
"0100800015926000", // Suika Game
|
||||
|
@@ -1,10 +0,0 @@
|
||||
namespace Ryujinx.Cpu.AppleHv.Arm
|
||||
{
|
||||
enum ExceptionLevel : uint
|
||||
{
|
||||
PstateMask = 0xfffffff0,
|
||||
EL1h = 0b0101,
|
||||
El1t = 0b0100,
|
||||
EL0 = 0b0000,
|
||||
}
|
||||
}
|
@@ -11,18 +11,7 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
class HvExecutionContext : IExecutionContext
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ulong Pc
|
||||
{
|
||||
get
|
||||
{
|
||||
uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
|
||||
if (currentEl == (uint)ExceptionLevel.EL1h)
|
||||
{
|
||||
return _impl.ElrEl1;
|
||||
}
|
||||
return _impl.Pc;
|
||||
}
|
||||
}
|
||||
public ulong Pc => _impl.ElrEl1;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public long TpidrEl0
|
||||
@@ -59,9 +48,6 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
set => _impl.Fpsr = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsAarch32
|
||||
{
|
||||
@@ -81,7 +67,6 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
private readonly ICounter _counter;
|
||||
private readonly IHvExecutionContext _shadowContext;
|
||||
private IHvExecutionContext _impl;
|
||||
private int _shouldStep;
|
||||
|
||||
private readonly ExceptionCallbacks _exceptionCallbacks;
|
||||
|
||||
@@ -118,11 +103,6 @@ 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);
|
||||
@@ -147,30 +127,6 @@ 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()
|
||||
{
|
||||
@@ -186,22 +142,6 @@ 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;
|
||||
@@ -269,20 +209,6 @@ 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}.");
|
||||
}
|
||||
@@ -293,7 +219,10 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
// TODO: Invalidate only the range that was modified?
|
||||
return HvAddressSpace.KernelRegionTlbiEretAddress;
|
||||
}
|
||||
return HvAddressSpace.KernelRegionEretAddress;
|
||||
else
|
||||
{
|
||||
return HvAddressSpace.KernelRegionEretAddress;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DataAbort(MemoryTracking tracking, ulong vcpu, uint esr)
|
||||
|
@@ -18,8 +18,6 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
private readonly ulong[] _x;
|
||||
private readonly V128[] _v;
|
||||
|
||||
@@ -48,14 +46,5 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
_v[index] = value;
|
||||
}
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
}
|
||||
|
||||
public bool GetAndClearInterruptRequested()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ using ARMeilleure.State;
|
||||
using Ryujinx.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu.AppleHv
|
||||
{
|
||||
@@ -14,8 +13,6 @@ 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
|
||||
@@ -138,7 +135,6 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
}
|
||||
|
||||
private readonly ulong _vcpu;
|
||||
private int _interruptRequested;
|
||||
|
||||
public HvExecutionContextVcpu(ulong vcpu)
|
||||
{
|
||||
@@ -184,16 +180,8 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
|
||||
public void RequestInterrupt()
|
||||
{
|
||||
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;
|
||||
ulong vcpu = _vcpu;
|
||||
HvApi.hv_vcpus_exit(ref vcpu, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,7 +15,6 @@ 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);
|
||||
@@ -40,8 +39,5 @@ namespace Ryujinx.Cpu.AppleHv
|
||||
SetV(i, context.GetV(i));
|
||||
}
|
||||
}
|
||||
|
||||
void RequestInterrupt();
|
||||
bool GetAndClearInterruptRequested();
|
||||
}
|
||||
}
|
||||
|
@@ -29,11 +29,6 @@ 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>
|
||||
@@ -52,19 +47,16 @@ 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,6 +1,5 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu
|
||||
{
|
||||
@@ -47,11 +46,6 @@ 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>
|
||||
@@ -114,23 +108,5 @@ 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,6 +1,5 @@
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
||||
|
||||
namespace Ryujinx.Cpu.Jit
|
||||
{
|
||||
@@ -54,13 +53,6 @@ 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;
|
||||
|
||||
@@ -73,7 +65,6 @@ namespace Ryujinx.Cpu.Jit
|
||||
counter,
|
||||
InterruptHandler,
|
||||
BreakHandler,
|
||||
StepHandler,
|
||||
SupervisorCallHandler,
|
||||
UndefinedHandler);
|
||||
|
||||
@@ -102,11 +93,6 @@ 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);
|
||||
@@ -123,16 +109,6 @@ 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,8 +1,6 @@
|
||||
using ARMeilleure;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Cpu.LightningJit.State
|
||||
{
|
||||
@@ -53,8 +51,6 @@ namespace Ryujinx.Cpu.LightningJit.State
|
||||
}
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
public ulong ThreadUid { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
{
|
||||
@@ -81,20 +77,15 @@ 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;
|
||||
|
||||
@@ -126,17 +117,6 @@ 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,8 +81,16 @@ namespace Ryujinx.Graphics.Device
|
||||
if (index < Size)
|
||||
{
|
||||
uint alignedOffset = index * RegisterSize;
|
||||
|
||||
return _readCallbacks[index]?.Invoke() ?? GetRefUnchecked<int>(alignedOffset);
|
||||
|
||||
Func<int> readCallback = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_readCallbacks), (nint)index);
|
||||
if (readCallback != null)
|
||||
{
|
||||
return readCallback();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetRefUnchecked<int>(alignedOffset);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -97,9 +105,9 @@ namespace Ryujinx.Graphics.Device
|
||||
uint alignedOffset = index * RegisterSize;
|
||||
DebugWrite(alignedOffset, data);
|
||||
|
||||
SetIntAlignedUncheck(index, data);
|
||||
GetRefIntAlignedUncheck(index) = data;
|
||||
|
||||
_writeCallbacks[index]?.Invoke(data);
|
||||
Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (nint)index)?.Invoke(data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +120,11 @@ namespace Ryujinx.Graphics.Device
|
||||
uint alignedOffset = index * RegisterSize;
|
||||
DebugWrite(alignedOffset, data);
|
||||
|
||||
changed = SetIntAlignedUncheckChanged(index, data);
|
||||
ref int storage = ref GetRefIntAlignedUncheck(index);
|
||||
changed = storage != data;
|
||||
storage = data;
|
||||
|
||||
_writeCallbacks[index]?.Invoke(data);
|
||||
Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_writeCallbacks), (nint)index)?.Invoke(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -152,24 +162,5 @@ 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,14 +219,13 @@ 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++)
|
||||
{
|
||||
enableSpan[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1);
|
||||
enable[i] = new Boolean32((uint)(arg0 >> (i + 8)) & 1);
|
||||
}
|
||||
|
||||
_processor.ThreedClass.UpdateBlendEnable(enableSpan);
|
||||
_processor.ThreedClass.UpdateBlendEnable(ref enable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -237,14 +236,13 @@ 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++)
|
||||
{
|
||||
masksSpan[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
||||
masksSpan[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
||||
masks[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
||||
masks[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
||||
|
||||
if (i != 3)
|
||||
{
|
||||
@@ -252,7 +250,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
||||
}
|
||||
}
|
||||
|
||||
_processor.ThreedClass.UpdateColorMasks(masksSpan);
|
||||
_processor.ThreedClass.UpdateColorMasks(ref masks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@@ -75,12 +75,10 @@ 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 = blendUcodeConstantsSpan[i];
|
||||
RgbHalf constant2 = _state.State.BlendUcodeConstants[i];
|
||||
|
||||
if ((Half)constant.R != constant2.UnpackR() ||
|
||||
(Half)constant.G != constant2.UnpackG() ||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Gpu.Memory;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -77,11 +76,9 @@ 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)
|
||||
{
|
||||
Span<Vector4<int>> vertexStridesSpan = _data.VertexStrides.AsSpan();
|
||||
|
||||
if (vertexStridesSpan[index].X != stride)
|
||||
if (_data.VertexStrides[index].X != stride)
|
||||
{
|
||||
vertexStridesSpan[index].X = stride;
|
||||
_data.VertexStrides[index].X = stride;
|
||||
MarkDirty(VertexInfoBuffer.VertexStridesOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
||||
}
|
||||
|
||||
@@ -89,7 +86,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||
{
|
||||
int value = c < componentCount ? 1 : 0;
|
||||
|
||||
ref int currentValue = ref GetElementRef(ref vertexStridesSpan[index], c);
|
||||
ref int currentValue = ref GetElementRef(ref _data.VertexStrides[index], c);
|
||||
|
||||
if (currentValue != value)
|
||||
{
|
||||
@@ -107,17 +104,15 @@ 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)
|
||||
{
|
||||
Span<Vector4<int>> vertexOffsetsSpan = _data.VertexOffsets.AsSpan();
|
||||
|
||||
if (vertexOffsetsSpan[index].X != offset)
|
||||
if (_data.VertexOffsets[index].X != offset)
|
||||
{
|
||||
vertexOffsetsSpan[index].X = offset;
|
||||
_data.VertexOffsets[index].X = offset;
|
||||
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
||||
}
|
||||
|
||||
if (vertexOffsetsSpan[index].Y != divisor)
|
||||
if (_data.VertexOffsets[index].Y != divisor)
|
||||
{
|
||||
vertexOffsetsSpan[index].Y = divisor;
|
||||
_data.VertexOffsets[index].Y = divisor;
|
||||
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>() + sizeof(int), sizeof(int));
|
||||
}
|
||||
}
|
||||
|
@@ -125,14 +125,9 @@ 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 = vertexAttribStateSpan[index];
|
||||
VertexAttribState vertexAttrib = _state.State.VertexAttribState[index];
|
||||
|
||||
if (!FormatTable.TryGetSingleComponentAttribFormat(vertexAttrib.UnpackFormat(), out Format format, out int componentsCount))
|
||||
{
|
||||
@@ -158,9 +153,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
||||
|
||||
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
||||
|
||||
GpuVa endAddress = vertexBufferEndAddressSpan[bufferIndex];
|
||||
VertexBufferState vertexBuffer = vertexBufferStateSpan[bufferIndex];
|
||||
bool instanced = vertexBufferInstancedSpan[bufferIndex];
|
||||
GpuVa endAddress = _state.State.VertexBufferEndAddress[bufferIndex];
|
||||
VertexBufferState vertexBuffer = _state.State.VertexBufferState[bufferIndex];
|
||||
bool instanced = _state.State.VertexBufferInstanced[bufferIndex];
|
||||
|
||||
ulong address = vertexBuffer.Address.Pack();
|
||||
|
||||
|
@@ -821,8 +821,6 @@ 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;
|
||||
@@ -833,9 +831,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
bool fullClear = screenScissorState.X == 0 && screenScissorState.Y == 0;
|
||||
|
||||
if (fullClear && clearAffectedByScissor && scissorStateSpan[0].Enable)
|
||||
if (fullClear && clearAffectedByScissor && _state.State.ScissorState[0].Enable)
|
||||
{
|
||||
ref ScissorState scissorState = ref scissorStateSpan[0];
|
||||
ref ScissorState scissorState = ref _state.State.ScissorState[0];
|
||||
|
||||
fullClear = scissorState.X1 == screenScissorState.X &&
|
||||
scissorState.Y1 == screenScissorState.Y &&
|
||||
@@ -894,9 +892,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
int scissorW = screenScissorState.Width;
|
||||
int scissorH = screenScissorState.Height;
|
||||
|
||||
if (clearAffectedByScissor && scissorStateSpan[0].Enable)
|
||||
if (clearAffectedByScissor && _state.State.ScissorState[0].Enable)
|
||||
{
|
||||
ref ScissorState scissorState = ref scissorStateSpan[0];
|
||||
ref ScissorState scissorState = ref _state.State.ScissorState[0];
|
||||
|
||||
scissorX = Math.Max(scissorX, scissorState.X1);
|
||||
scissorY = Math.Max(scissorY, scissorState.Y1);
|
||||
|
@@ -3,7 +3,6 @@ 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
|
||||
{
|
||||
@@ -215,11 +214,10 @@ 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(ReadOnlySpan<VertexAttribState> state)
|
||||
public void SetAttributeTypes(ref Array32<VertexAttribState> state)
|
||||
{
|
||||
bool changed = false;
|
||||
// ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
||||
Span<AttributeType> attributeTypesSpan = _graphics.AttributeTypes.AsSpan();
|
||||
ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
||||
bool mayConvertVtgToCompute = ShaderCache.MayConvertVtgToCompute(ref _context.Capabilities);
|
||||
bool supportsScaledFormats = _context.Capabilities.SupportsScaledVertexFormats && !mayConvertVtgToCompute;
|
||||
|
||||
@@ -263,9 +261,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
}
|
||||
}
|
||||
|
||||
if (attributeTypesSpan[location] != value)
|
||||
if (attributeTypes[location] != value)
|
||||
{
|
||||
attributeTypesSpan[location] = value;
|
||||
attributeTypes[location] = value;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -281,12 +279,10 @@ 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, ReadOnlySpan<RtColorState> state)
|
||||
public void SetFragmentOutputTypes(RtControl rtControl, ref Array8<RtColorState> state)
|
||||
{
|
||||
bool changed = false;
|
||||
int count = rtControl.UnpackCount();
|
||||
|
||||
Span<AttributeType> fragmentOutputTypesSpan = _graphics.FragmentOutputTypes.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||
{
|
||||
@@ -300,9 +296,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
|
||||
|
||||
if (type != fragmentOutputTypesSpan[index])
|
||||
if (type != _graphics.FragmentOutputTypes[index])
|
||||
{
|
||||
fragmentOutputTypesSpan[index] = type;
|
||||
_graphics.FragmentOutputTypes[index] = type;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
@@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
if (index < BlockSize)
|
||||
{
|
||||
int groupIndex = _registerToGroupMapping[index];
|
||||
int groupIndex = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_registerToGroupMapping), (nint)index);
|
||||
if (groupIndex != 0)
|
||||
{
|
||||
groupIndex--;
|
||||
|
@@ -423,11 +423,9 @@ 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 = tfBufferStateSpan[index];
|
||||
TfBufferState tfb = _state.State.TfBufferState[index];
|
||||
|
||||
if (!tfb.Enable)
|
||||
{
|
||||
@@ -468,10 +466,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
MemoryManager memoryManager = _channel.MemoryManager;
|
||||
RtControl rtControl = _state.State.RtControl;
|
||||
|
||||
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;
|
||||
bool useControl = updateFlags.HasFlag(RenderTargetUpdateFlags.UseControl);
|
||||
bool layered = updateFlags.HasFlag(RenderTargetUpdateFlags.Layered);
|
||||
bool singleColor = updateFlags.HasFlag(RenderTargetUpdateFlags.SingleColor);
|
||||
bool discard = updateFlags.HasFlag(RenderTargetUpdateFlags.DiscardClip);
|
||||
|
||||
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
|
||||
|
||||
@@ -489,13 +487,11 @@ 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 = rtColorStateSpan[rtIndex];
|
||||
RtColorState colorState = _state.State.RtColorState[rtIndex];
|
||||
|
||||
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
|
||||
{
|
||||
@@ -543,7 +539,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
Image.Texture depthStencil = null;
|
||||
|
||||
if (dsEnable && (updateFlags & RenderTargetUpdateFlags.UpdateDepthStencil) == RenderTargetUpdateFlags.UpdateDepthStencil)
|
||||
if (dsEnable && updateFlags.HasFlag(RenderTargetUpdateFlags.UpdateDepthStencil))
|
||||
{
|
||||
RtDepthStencilState dsState = _state.State.RtDepthStencilState;
|
||||
Size3D dsSize = _state.State.RtDepthStencilSize;
|
||||
@@ -603,7 +599,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
public void UpdateRenderTargetSpecialization()
|
||||
{
|
||||
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, _state.State.RtColorState.AsSpan());
|
||||
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, ref _state.State.RtColorState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -628,11 +624,10 @@ 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 = scissorStateSpan[index];
|
||||
ScissorState scissor = _state.State.ScissorState[index];
|
||||
|
||||
bool enable = scissor.Enable && (scissor.X1 != MinX ||
|
||||
scissor.Y1 != MinY ||
|
||||
@@ -736,8 +731,6 @@ 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++)
|
||||
{
|
||||
@@ -752,8 +745,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
continue;
|
||||
}
|
||||
|
||||
ref ViewportTransform transform = ref viewportTransformSpan[index];
|
||||
ref ViewportExtents extents = ref viewportExtentsSpan[index];
|
||||
ref ViewportTransform transform = ref _state.State.ViewportTransform[index];
|
||||
ref ViewportExtents extents = ref _state.State.ViewportExtents[index];
|
||||
|
||||
float scaleX = MathF.Abs(transform.ScaleX);
|
||||
float scaleY = transform.ScaleY;
|
||||
@@ -975,11 +968,10 @@ 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 = vertexAttribStateSpan[index];
|
||||
VertexAttribState vertexAttrib = _state.State.VertexAttribState[index];
|
||||
|
||||
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
||||
|
||||
@@ -1023,7 +1015,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
_pipeline.SetVertexAttribs(vertexAttribs);
|
||||
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
||||
_currentSpecState.SetAttributeTypes(_state.State.VertexAttribState.AsSpan());
|
||||
_currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1121,25 +1113,20 @@ 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 = vertexBufferStateSpan[index];
|
||||
VertexBufferState vertexBuffer = _state.State.VertexBufferState[index];
|
||||
|
||||
if (!vertexBuffer.UnpackEnable())
|
||||
{
|
||||
vertexBuffersSpan[index] = new BufferPipelineDescriptor(false, 0, 0);
|
||||
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(false, 0, 0);
|
||||
_channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
GpuVa endAddress = vertexBufferEndAddressSpan[index];
|
||||
GpuVa endAddress = _state.State.VertexBufferEndAddress[index];
|
||||
|
||||
ulong address = vertexBuffer.Address.Pack();
|
||||
|
||||
@@ -1150,7 +1137,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
int stride = vertexBuffer.UnpackStride();
|
||||
|
||||
bool instanced = vertexBufferInstancedSpan[index];
|
||||
bool instanced = _state.State.VertexBufferInstanced[index];
|
||||
|
||||
int divisor = instanced ? vertexBuffer.Divisor : 0;
|
||||
|
||||
@@ -1197,7 +1184,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
size = Math.Min(vbSize, (ulong)((firstInstance + drawFirstVertex + drawVertexCount) * stride));
|
||||
}
|
||||
|
||||
vertexBuffersSpan[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
||||
_pipeline.VertexBuffers[index] = new BufferPipelineDescriptor(_channel.MemoryManager.IsMapped(address), stride, divisor);
|
||||
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
||||
}
|
||||
|
||||
@@ -1250,12 +1237,10 @@ 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 = rtColorMaskSpan[rtColorMaskShared ? 0 : index];
|
||||
RtColorMask colorMask = _state.State.RtColorMask[rtColorMaskShared ? 0 : index];
|
||||
|
||||
uint componentMask;
|
||||
|
||||
@@ -1265,7 +1250,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
|
||||
|
||||
componentMasks[index] = componentMask;
|
||||
colorWriteMaskSpan[index] = componentMask;
|
||||
_pipeline.ColorWriteMask[index] = componentMask;
|
||||
}
|
||||
|
||||
_context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
|
||||
@@ -1297,14 +1282,10 @@ 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 = blendEnableSpan[index];
|
||||
BlendState blend = blendStateSpan[index];
|
||||
bool enable = _state.State.BlendEnable[index];
|
||||
BlendState blend = _state.State.BlendState[index];
|
||||
|
||||
BlendDescriptor descriptor = new(
|
||||
enable,
|
||||
@@ -1325,7 +1306,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
dualSourceBlendEnabled = true;
|
||||
}
|
||||
|
||||
blendDescriptorsSpan[index] = descriptor;
|
||||
_pipeline.BlendDescriptors[index] = descriptor;
|
||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||
}
|
||||
}
|
||||
@@ -1352,12 +1333,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
dualSourceBlendEnabled = true;
|
||||
}
|
||||
|
||||
Span<BlendDescriptor> blendDescriptorsSpan = _pipeline.BlendDescriptors.AsSpan();
|
||||
|
||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||
{
|
||||
blendDescriptorsSpan[index] = descriptor;
|
||||
_pipeline.BlendDescriptors[index] = descriptor;
|
||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||
}
|
||||
}
|
||||
@@ -1443,13 +1422,12 @@ 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 = shaderStateSpan[index];
|
||||
ShaderState shader = _state.State.ShaderState[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>(Span<T> lhs, Span<T> rhs) where T : unmanaged
|
||||
private static bool UnsafeEquals32Byte<T>(ref T lhs, ref T rhs) where T : unmanaged
|
||||
{
|
||||
if (Vector256.IsHardwareAccelerated)
|
||||
{
|
||||
return Vector256.EqualsAll(
|
||||
Unsafe.As<Span<T>, ReadOnlySpan<Vector256<uint>>>(ref lhs)[0],
|
||||
Unsafe.As<Span<T>, ReadOnlySpan<Vector256<uint>>>(ref rhs)[0]
|
||||
Unsafe.As<T, Vector256<uint>>(ref lhs),
|
||||
Unsafe.As<T, Vector256<uint>>(ref rhs)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
ref Vector128<uint> lhsVec = ref Unsafe.As<T, Vector128<uint>>(ref lhs);
|
||||
ref Vector128<uint> rhsVec = ref Unsafe.As<T, Vector128<uint>>(ref rhs);
|
||||
|
||||
return Vector128.EqualsAll(lhsVec[0], rhsVec[0]) &&
|
||||
Vector128.EqualsAll(lhsVec[1], rhsVec[1]);
|
||||
return Vector128.EqualsAll(lhsVec, rhsVec) &&
|
||||
Vector128.EqualsAll(Unsafe.Add(ref lhsVec, 1), Unsafe.Add(ref 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(Span<Boolean32> enable)
|
||||
public void UpdateBlendEnable(ref Array8<Boolean32> enable)
|
||||
{
|
||||
SetMmeShadowRamControlMode shadow = ShadowMode;
|
||||
Span<Boolean32> state = _state.State.BlendEnable.AsSpan();
|
||||
ref Array8<Boolean32> state = ref _state.State.BlendEnable;
|
||||
|
||||
if (shadow.IsReplay())
|
||||
{
|
||||
state.CopyTo(enable);
|
||||
enable = _state.ShadowState.BlendEnable;
|
||||
}
|
||||
|
||||
if (!UnsafeEquals32Byte(enable, state))
|
||||
if (!UnsafeEquals32Byte(ref enable, ref state))
|
||||
{
|
||||
enable.CopyTo(state);
|
||||
state = enable;
|
||||
|
||||
_stateUpdater.ForceDirty(StateUpdater.BlendStateIndex);
|
||||
}
|
||||
|
||||
if (shadow.IsTrack())
|
||||
{
|
||||
enable.CopyTo(state);
|
||||
_state.ShadowState.BlendEnable = enable;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(Span<RtColorMask> masks)
|
||||
public void UpdateColorMasks(ref Array8<RtColorMask> masks)
|
||||
{
|
||||
SetMmeShadowRamControlMode shadow = ShadowMode;
|
||||
Span<RtColorMask> state = _state.State.RtColorMask.AsSpan();
|
||||
ref Array8<RtColorMask> state = ref _state.State.RtColorMask;
|
||||
|
||||
if (shadow.IsReplay())
|
||||
{
|
||||
state.CopyTo(masks);
|
||||
masks = _state.ShadowState.RtColorMask;
|
||||
}
|
||||
|
||||
if (!UnsafeEquals32Byte(masks, state))
|
||||
if (!UnsafeEquals32Byte(ref masks, ref state))
|
||||
{
|
||||
masks.CopyTo(state);
|
||||
state = masks;
|
||||
|
||||
_stateUpdater.ForceDirty(StateUpdater.RtColorMaskIndex);
|
||||
}
|
||||
|
||||
if (shadow.IsTrack())
|
||||
{
|
||||
masks.CopyTo(state);
|
||||
_state.ShadowState.RtColorMask = masks;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 : INonOverlappingRange, ISyncActionHandler, IDisposable
|
||||
class Buffer : IRange, 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; private set; }
|
||||
public ulong Size { get; }
|
||||
|
||||
/// <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;
|
||||
private BufferModifiedRangeList _modifiedRanges = null;
|
||||
|
||||
/// <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;
|
||||
private BufferPreFlush _preFlush = null;
|
||||
|
||||
/// <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,
|
||||
RangeItem<Buffer>[] baseBuffers)
|
||||
IEnumerable<Buffer> baseBuffers = null)
|
||||
{
|
||||
_context = context;
|
||||
_physicalMemory = physicalMemory;
|
||||
@@ -126,22 +126,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
_useGranular = size > GranularBufferThreshold;
|
||||
|
||||
List<IRegionHandle> baseHandles = null;
|
||||
IEnumerable<IRegionHandle> baseHandles = null;
|
||||
|
||||
if (baseBuffers.Length != 0)
|
||||
if (baseBuffers != null)
|
||||
{
|
||||
baseHandles = new List<IRegionHandle>();
|
||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
||||
baseHandles = baseBuffers.SelectMany(buffer =>
|
||||
{
|
||||
if (item.Value._useGranular)
|
||||
if (buffer._useGranular)
|
||||
{
|
||||
baseHandles.AddRange((item.Value._memoryTrackingGranular.GetHandles()));
|
||||
return buffer._memoryTrackingGranular.GetHandles();
|
||||
}
|
||||
else
|
||||
{
|
||||
baseHandles.Add(item.Value._memoryTracking);
|
||||
return Enumerable.Repeat(buffer._memoryTracking, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (_useGranular)
|
||||
@@ -172,9 +171,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_memoryTracking.RegisterPreciseAction(PreciseAction);
|
||||
}
|
||||
|
||||
_externalFlushDelegate = ExternalFlush;
|
||||
_loadDelegate = LoadRegion;
|
||||
_modifiedDelegate = RegionModified;
|
||||
_externalFlushDelegate = new RegionSignal(ExternalFlush);
|
||||
_loadDelegate = new Action<ulong, ulong>(LoadRegion);
|
||||
_modifiedDelegate = new Action<ulong, ulong>(RegionModified);
|
||||
|
||||
_virtualDependenciesLock = new ReaderWriterLockSlim();
|
||||
}
|
||||
@@ -248,11 +247,6 @@ 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>
|
||||
@@ -441,7 +435,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="from">The buffer to inherit from</param>
|
||||
public void InheritModifiedRanges(Buffer from)
|
||||
{
|
||||
if (from._modifiedRanges is { HasRanges: true })
|
||||
if (from._modifiedRanges != null && from._modifiedRanges.HasRanges)
|
||||
{
|
||||
if (from._syncActionRegistered && !_syncActionRegistered)
|
||||
{
|
||||
@@ -449,7 +443,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
_syncActionRegistered = true;
|
||||
}
|
||||
|
||||
void RegisterRangeAction(ulong address, ulong size)
|
||||
void registerRangeAction(ulong address, ulong size)
|
||||
{
|
||||
if (_useGranular)
|
||||
{
|
||||
@@ -463,7 +457,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
EnsureRangeList();
|
||||
|
||||
_modifiedRanges.InheritRanges(from._modifiedRanges, RegisterRangeAction);
|
||||
_modifiedRanges.InheritRanges(from._modifiedRanges, registerRangeAction);
|
||||
}
|
||||
|
||||
if (from._dirtyStart != ulong.MaxValue)
|
||||
@@ -505,7 +499,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
// Cut off the start.
|
||||
|
||||
_dirtyStart = end < _dirtyEnd ? end : ulong.MaxValue;
|
||||
if (end < _dirtyEnd)
|
||||
{
|
||||
_dirtyStart = end;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dirtyStart = ulong.MaxValue;
|
||||
}
|
||||
}
|
||||
else if (end >= _dirtyEnd)
|
||||
{
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Memory.Range;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -57,7 +56,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, RangeItem<Buffer>[] baseBuffers)
|
||||
public BufferBackingState(GpuContext context, Buffer parent, BufferStage stage, IEnumerable<Buffer> baseBuffers = null)
|
||||
{
|
||||
_size = (int)parent.Size;
|
||||
_systemMemoryType = context.Capabilities.MemoryType;
|
||||
@@ -73,7 +72,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
BufferStage storageFlags = stage & BufferStage.StorageMask;
|
||||
|
||||
if (parent.Size > DeviceLocalSizeThreshold && baseBuffers.Length == 0)
|
||||
if (parent.Size > DeviceLocalSizeThreshold && baseBuffers == null)
|
||||
{
|
||||
_desiredType = BufferBackingType.DeviceMemory;
|
||||
}
|
||||
@@ -101,11 +100,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// TODO: Might be nice to force atomic access to be device local for any stage.
|
||||
}
|
||||
|
||||
if (baseBuffers.Length != 0)
|
||||
if (baseBuffers != null)
|
||||
{
|
||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
||||
foreach (Buffer buffer in baseBuffers)
|
||||
{
|
||||
CombineState(item.Value.BackingState);
|
||||
CombineState(buffer.BackingState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ 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
|
||||
@@ -38,9 +39,11 @@ 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 NonOverlappingRangeList<Buffer> _buffers;
|
||||
private readonly RangeList<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;
|
||||
@@ -61,6 +64,8 @@ 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.
|
||||
@@ -74,21 +79,24 @@ 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);
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
lock (_buffers)
|
||||
{
|
||||
overlaps[i].Value.Unmapped(subRange.Address, subRange.Size);
|
||||
overlapCount = _buffers.FindOverlaps(subRange.Address, subRange.Size, ref overlaps);
|
||||
}
|
||||
|
||||
_buffers.Lock.ExitReadLock();
|
||||
for (int i = 0; i < overlapCount; i++)
|
||||
{
|
||||
overlaps[i].Unmapped(subRange.Address, subRange.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +137,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 || size == 0)
|
||||
if (gpuVa == 0)
|
||||
{
|
||||
return new MultiRange(MemoryManager.PteUnmapped, size);
|
||||
}
|
||||
@@ -328,7 +336,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
ulong alignedEndAddress = (endAddress + alignmentMask) & ~alignmentMask;
|
||||
ulong alignedSize = alignedEndAddress - alignedAddress;
|
||||
|
||||
Buffer buffer = _buffers.FindOverlap(alignedAddress, alignedSize).Value;
|
||||
Buffer buffer = _buffers.FindFirstOverlap(alignedAddress, alignedSize);
|
||||
BufferRange bufferRange = buffer.GetRange(alignedAddress, alignedSize, false);
|
||||
|
||||
alignedSubRanges[i] = new MemoryRange(alignedAddress, alignedSize);
|
||||
@@ -395,7 +403,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (subRange.Address != MemoryManager.PteUnmapped)
|
||||
{
|
||||
Buffer buffer = _buffers.FindOverlap(subRange.Address, subRange.Size).Value;
|
||||
Buffer buffer = _buffers.FindFirstOverlap(subRange.Address, subRange.Size);
|
||||
|
||||
virtualBuffer.AddPhysicalDependency(buffer, subRange.Address, dstOffset, subRange.Size);
|
||||
physicalBuffers.Add(buffer);
|
||||
@@ -487,12 +495,10 @@ 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 newBuffer = null;
|
||||
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
Buffer[] overlaps = _bufferOverlaps;
|
||||
int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
|
||||
if (overlaps.Length != 0)
|
||||
if (overlapsCount != 0)
|
||||
{
|
||||
// The buffer already exists. We can just return the existing buffer
|
||||
// if the buffer we need is fully contained inside the overlapping buffer.
|
||||
@@ -501,8 +507,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
// old buffer(s) to the new buffer.
|
||||
|
||||
ulong endAddress = address + size;
|
||||
Buffer overlap0 = overlaps[0];
|
||||
|
||||
if (overlaps[0].Address > address || overlaps[0].EndAddress < endAddress)
|
||||
if (overlap0.Address > address || overlap0.EndAddress < endAddress)
|
||||
{
|
||||
bool anySparseCompatible = false;
|
||||
|
||||
@@ -515,60 +522,53 @@ 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 (overlaps.Length == 1 &&
|
||||
address >= overlaps[0].Address &&
|
||||
endAddress - overlaps[0].EndAddress <= BufferAlignmentSize * 2)
|
||||
if (overlapsCount == 1 &&
|
||||
address >= overlap0.Address &&
|
||||
endAddress - overlap0.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 = overlaps[0].Value.Size;
|
||||
ulong existingSize = overlap0.Size;
|
||||
ulong growthSize = (existingSize + Math.Min(existingSize >> 1, MaxDynamicGrowthSize)) & ~BufferAlignmentMask;
|
||||
|
||||
size = Math.Max(size, growthSize);
|
||||
endAddress = address + size;
|
||||
|
||||
overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
||||
}
|
||||
|
||||
address = Math.Min(address, overlaps[0].Address);
|
||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
{
|
||||
anySparseCompatible |= overlaps[i].Value.SparseCompatible;
|
||||
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
}
|
||||
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
Buffer buffer = overlaps[index];
|
||||
|
||||
anySparseCompatible |= buffer.SparseCompatible;
|
||||
|
||||
address = Math.Min(address, buffer.Address);
|
||||
endAddress = Math.Max(endAddress, buffer.EndAddress);
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
_buffers.Remove(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
|
||||
|
||||
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
ulong newSize = endAddress - address;
|
||||
|
||||
newBuffer = CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlapsArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlaps, overlapsCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
// No overlap, just create a new buffer.
|
||||
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false, []);
|
||||
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible: false);
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
_buffers.Add(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (newBuffer is not null)
|
||||
{
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
|
||||
_buffers.Add(newBuffer);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
}
|
||||
ShrinkOverlapsBufferIfNeeded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -582,75 +582,72 @@ 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 (overlaps.Length != 0)
|
||||
if (overlapsCount != 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 (overlaps[0].Address > address ||
|
||||
overlaps[0].EndAddress < endAddress ||
|
||||
(overlaps[0].Address & (alignment - 1)) != 0 ||
|
||||
(!overlaps[0].Value.SparseCompatible && sparseAligned))
|
||||
if (overlap0.Address > address ||
|
||||
overlap0.EndAddress < endAddress ||
|
||||
(overlap0.Address & (alignment - 1)) != 0 ||
|
||||
(!overlap0.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.
|
||||
|
||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
||||
int oldOverlapCount;
|
||||
|
||||
int oldOverlapsCount;
|
||||
|
||||
do
|
||||
{
|
||||
address = Math.Min(address, overlaps[0].Address);
|
||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
Buffer buffer = overlaps[index];
|
||||
|
||||
address = Math.Min(address, buffer.Address);
|
||||
endAddress = Math.Max(endAddress, buffer.EndAddress);
|
||||
}
|
||||
|
||||
address &= ~(alignment - 1);
|
||||
|
||||
oldOverlapCount = overlaps.Length;
|
||||
overlaps = _buffers.FindOverlapsAsSpan(address, endAddress - address);
|
||||
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]);
|
||||
}
|
||||
}
|
||||
while (oldOverlapCount != overlaps.Length);
|
||||
|
||||
ulong newSize = endAddress - address;
|
||||
|
||||
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();
|
||||
|
||||
CreateBufferAligned(address, newSize, stage, sparseAligned, overlaps, overlapsCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
|
||||
// No overlap, just create a new buffer.
|
||||
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseAligned, []);
|
||||
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseAligned);
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
_buffers.Add(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if (newBuffer is not null)
|
||||
{
|
||||
_buffers.Lock.EnterWriteLock();
|
||||
|
||||
_buffers.Add(newBuffer);
|
||||
|
||||
_buffers.Lock.ExitWriteLock();
|
||||
}
|
||||
ShrinkOverlapsBufferIfNeeded();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -663,13 +660,19 @@ 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>
|
||||
private Buffer CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, RangeItem<Buffer>[] overlaps)
|
||||
/// <param name="overlapsCount">Total of overlaps</param>
|
||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, bool sparseCompatible, Buffer[] overlaps, int overlapsCount)
|
||||
{
|
||||
Buffer newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps);
|
||||
Buffer newBuffer = new(_context, _physicalMemory, address, size, stage, sparseCompatible, overlaps.Take(overlapsCount));
|
||||
|
||||
for (int index = 0; index < overlaps.Length; index++)
|
||||
lock (_buffers)
|
||||
{
|
||||
Buffer buffer = overlaps[index].Value;
|
||||
_buffers.Add(newBuffer);
|
||||
}
|
||||
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
Buffer buffer = overlaps[index];
|
||||
|
||||
int dstOffset = (int)(buffer.Address - newBuffer.Address);
|
||||
|
||||
@@ -685,8 +688,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
NotifyBuffersModified?.Invoke();
|
||||
|
||||
RecreateMultiRangeBuffers(address, size);
|
||||
|
||||
return newBuffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -717,6 +718,17 @@ 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>
|
||||
@@ -897,7 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
MemoryRange subRange = range.GetSubRange(i);
|
||||
|
||||
Buffer subBuffer = _buffers.FindOverlap(subRange.Address, subRange.Size).Value;
|
||||
Buffer subBuffer = _buffers.FindFirstOverlap(subRange.Address, subRange.Size);
|
||||
|
||||
subBuffer.SynchronizeMemory(subRange.Address, subRange.Size);
|
||||
|
||||
@@ -945,7 +957,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
buffer = _buffers.FindOverlap(address, size).Value;
|
||||
buffer = _buffers.FindFirstOverlap(address, size);
|
||||
|
||||
buffer.CopyFromDependantVirtualBuffers();
|
||||
buffer.SynchronizeMemory(address, size);
|
||||
@@ -957,7 +969,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = _buffers.FindOverlapFast(address, 1).Value;
|
||||
buffer = _buffers.FindFirstOverlap(address, 1);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
@@ -995,7 +1007,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
Buffer buffer = _buffers.FindOverlap(address, size).Value;
|
||||
Buffer buffer = _buffers.FindFirstOverlap(address, size);
|
||||
|
||||
if (copyBackVirtual)
|
||||
{
|
||||
|
@@ -258,7 +258,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
RecordStorageAlignment(_cpStorageBuffers, index, gpuVa);
|
||||
|
||||
gpuVa = BitUtils.AlignDown(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
|
||||
gpuVa = BitUtils.AlignDown<ulong>(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(gpuVa, (ulong)_context.Capabilities.StorageBufferOffsetAlignment);
|
||||
gpuVa = BitUtils.AlignDown<ulong>(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 & BufferUsageFlags.Write) == BufferUsageFlags.Write;
|
||||
bool isWrite = bounds.Flags.HasFlag(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 & BufferUsageFlags.Write) == BufferUsageFlags.Write;
|
||||
bool isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
|
||||
BufferRange range = isStorage
|
||||
? bufferCache.GetBufferRangeAligned(bounds.Range, BufferStageUtils.ComputeStorage(bounds.Flags), isWrite)
|
||||
: bufferCache.GetBufferRange(bounds.Range, BufferStage.Compute);
|
||||
@@ -817,6 +817,7 @@ 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)]
|
||||
@@ -865,6 +866,7 @@ 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,
|
||||
@@ -887,6 +889,7 @@ 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,
|
||||
@@ -909,6 +912,7 @@ 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,24 +1,25 @@
|
||||
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 : INonOverlappingRange
|
||||
class BufferModifiedRange : IRange
|
||||
{
|
||||
/// <summary>
|
||||
/// Start address of the range in guest memory.
|
||||
/// </summary>
|
||||
public ulong Address { get; internal set; }
|
||||
public ulong Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of the range in bytes.
|
||||
/// </summary>
|
||||
public ulong Size { get; internal set; }
|
||||
public ulong Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// End address of the range in guest memory.
|
||||
@@ -60,17 +61,12 @@ 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 : NonOverlappingRangeList<BufferModifiedRange>
|
||||
class BufferModifiedRangeList : RangeList<BufferModifiedRange>
|
||||
{
|
||||
private const int BackingInitialSize = 8;
|
||||
|
||||
@@ -81,6 +77,8 @@ 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>
|
||||
@@ -88,10 +86,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
get
|
||||
{
|
||||
Lock.EnterReadLock();
|
||||
bool result = Count > 0;
|
||||
Lock.ExitReadLock();
|
||||
return result;
|
||||
lock (_lock)
|
||||
{
|
||||
return Count > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,32 +114,33 @@ 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)
|
||||
{
|
||||
// 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++)
|
||||
lock (_lock)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
// 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();
|
||||
|
||||
if (overlap.Address > address)
|
||||
int count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
// The start of the remaining region is uncovered by this overlap. Call the action for it.
|
||||
action(address, 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if ((long)size > 0)
|
||||
{
|
||||
// If there is any region left after removing the overlaps, signal it.
|
||||
action(address, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,93 +152,51 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="size">Size of the modified region in bytes</param>
|
||||
public void SignalModified(ulong address, ulong size)
|
||||
{
|
||||
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)
|
||||
// Must lock, as this can affect flushes from the background thread.
|
||||
lock (_lock)
|
||||
{
|
||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
// We may overlap with some existing modified regions. They must be cut into by the new entry.
|
||||
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
|
||||
if (first == last)
|
||||
{
|
||||
if (first.Address == address && first.EndAddress == endAddress)
|
||||
int count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
|
||||
ulong endAddress = address + size;
|
||||
ulong syncNumber = _context.SyncNumber;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
first.Value.SyncNumber = syncNumber;
|
||||
first.Value.Parent = this;
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
// The overlaps must be removed or split.
|
||||
|
||||
if (first.Address < address)
|
||||
{
|
||||
first.Value.Size = address - first.Address;
|
||||
Update(first);
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
if (first.EndAddress > endAddress)
|
||||
if (overlap.Address == address && overlap.Size == size)
|
||||
{
|
||||
Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
|
||||
first.Value.SyncNumber, first.Value.Parent));
|
||||
// Region already exists. Just update the existing sync number.
|
||||
overlap.SyncNumber = syncNumber;
|
||||
overlap.Parent = this;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first.EndAddress > endAddress)
|
||||
|
||||
Remove(overlap);
|
||||
|
||||
if (overlap.Address < address && overlap.EndAddress > address)
|
||||
{
|
||||
first.Value.Size = first.EndAddress - endAddress;
|
||||
first.Value.Address = endAddress;
|
||||
Update(first);
|
||||
// A split item must be created behind this overlap.
|
||||
|
||||
Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber, overlap.Parent));
|
||||
}
|
||||
else
|
||||
|
||||
if (overlap.Address < endAddress && overlap.EndAddress > endAddress)
|
||||
{
|
||||
Remove(first.Value);
|
||||
// A split item must be created after this overlap.
|
||||
|
||||
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber, overlap.Parent));
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
@@ -251,20 +208,25 @@ 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)
|
||||
{
|
||||
Lock.EnterReadLock();
|
||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
|
||||
// Range list must be consistent for this operation.
|
||||
lock (_lock)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
if (overlap.SyncNumber == syncNumber)
|
||||
{
|
||||
rangeAction(overlap.Address, overlap.Size);
|
||||
}
|
||||
}
|
||||
|
||||
Lock.ExitReadLock();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -275,14 +237,19 @@ 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)
|
||||
{
|
||||
// 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();
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < overlaps.Length; i++)
|
||||
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||
|
||||
// Range list must be consistent for this operation.
|
||||
lock (_lock)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
rangeAction(overlap.Address, overlap.Size);
|
||||
}
|
||||
}
|
||||
@@ -295,11 +262,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)
|
||||
{
|
||||
Lock.EnterReadLock();
|
||||
RangeItem<BufferModifiedRange> first = FindOverlapFast(address, size);
|
||||
bool result = first is not null;
|
||||
Lock.ExitReadLock();
|
||||
return result;
|
||||
// Range list must be consistent for this operation.
|
||||
lock (_lock)
|
||||
{
|
||||
return FindOverlapsNonOverlapping(address, size, ref ThreadStaticArray<BufferModifiedRange>.Get()) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -331,35 +298,38 @@ 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(
|
||||
RangeItem<BufferModifiedRange>[] overlaps,
|
||||
BufferModifiedRange[] overlaps,
|
||||
int rangeCount,
|
||||
long highestDiff,
|
||||
ulong currentSync,
|
||||
ulong address,
|
||||
ulong endAddress)
|
||||
{
|
||||
if (_migrationTarget == null)
|
||||
lock (_lock)
|
||||
{
|
||||
ulong waitSync = currentSync + (ulong)highestDiff;
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
if (_migrationTarget == null)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
ulong waitSync = currentSync + (ulong)highestDiff;
|
||||
|
||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||
|
||||
if (diff <= highestDiff)
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
{
|
||||
ulong clampAddress = Math.Max(address, overlap.Address);
|
||||
ulong clampEnd = Math.Min(endAddress, overlap.EndAddress);
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
ClearPart(overlap, clampAddress, clampEnd);
|
||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||
|
||||
RangeActionWithMigration(clampAddress, clampEnd - clampAddress, waitSync, _flushAction);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -383,24 +353,31 @@ 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
|
||||
if (_migrationTarget != null)
|
||||
lock (_lock)
|
||||
{
|
||||
_migrationTarget!.WaitForAndFlushRanges(address, size);
|
||||
if (_migrationTarget != null)
|
||||
{
|
||||
rangeCount = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeCount = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||
}
|
||||
}
|
||||
|
||||
if (rangeCount == -1)
|
||||
{
|
||||
_migrationTarget.WaitForAndFlushRanges(address, size);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
else if (rangeCount == 0)
|
||||
{
|
||||
Lock.ExitWriteLock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -411,7 +388,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
{
|
||||
BufferModifiedRange overlap = overlaps[i].Value;
|
||||
BufferModifiedRange overlap = overlaps[i];
|
||||
|
||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||
|
||||
@@ -423,17 +400,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (highestDiff == long.MinValue)
|
||||
{
|
||||
Lock.ExitWriteLock();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the syncpoint.
|
||||
_context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
|
||||
|
||||
RemoveRangesAndFlush(overlaps.ToArray(), rangeCount, highestDiff, currentSync, address, endAddress);
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -446,40 +419,42 @@ 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)
|
||||
{
|
||||
ranges.Lock.EnterReadLock();
|
||||
BufferModifiedRange[] inheritRanges = ranges.ToArray();
|
||||
ranges.Lock.ExitReadLock();
|
||||
BufferModifiedRange[] inheritRanges;
|
||||
|
||||
// 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)
|
||||
lock (ranges._lock)
|
||||
{
|
||||
// Create a new migration.
|
||||
_source = new BufferMigration([span], this, _context.SyncNumber);
|
||||
inheritRanges = ranges.ToArray();
|
||||
|
||||
_context.RegisterBufferMigration(_source);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
@@ -498,18 +473,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// </summary>
|
||||
public void SelfMigration()
|
||||
{
|
||||
BufferMigrationSpan span = new(_parent, _parent.GetSnapshotDisposeAction(),
|
||||
_parent.GetSnapshotFlushAction(), _source);
|
||||
BufferMigration migration = new([span], this, _context.SyncNumber);
|
||||
lock (_lock)
|
||||
{
|
||||
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);
|
||||
|
||||
Lock.EnterWriteLock();
|
||||
_source = migration;
|
||||
Lock.ExitWriteLock();
|
||||
_source = migration;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -518,13 +493,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="migration">The migration to remove</param>
|
||||
public void RemoveMigration(BufferMigration migration)
|
||||
{
|
||||
Lock.EnterWriteLock();
|
||||
if (_source == migration)
|
||||
lock (_lock)
|
||||
{
|
||||
_source = null;
|
||||
if (_source == migration)
|
||||
{
|
||||
_source = null;
|
||||
}
|
||||
}
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
}
|
||||
|
||||
private void ClearPart(BufferModifiedRange overlap, ulong address, ulong endAddress)
|
||||
@@ -551,79 +526,33 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="size">Size to clear</param>
|
||||
public void Clear(ulong address, ulong size)
|
||||
{
|
||||
ulong endAddress = address + size;
|
||||
Lock.EnterWriteLock();
|
||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlapsAsNodes(address, size);
|
||||
|
||||
if (first is null)
|
||||
lock (_lock)
|
||||
{
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
// This function can be called from any thread, so it cannot use the arrays for background or foreground.
|
||||
BufferModifiedRange[] toClear = new BufferModifiedRange[1];
|
||||
|
||||
if (first == last)
|
||||
{
|
||||
if (first.Address < address)
|
||||
int rangeCount = FindOverlapsNonOverlapping(address, size, ref toClear);
|
||||
|
||||
ulong endAddress = address + size;
|
||||
|
||||
for (int i = 0; i < rangeCount; i++)
|
||||
{
|
||||
first.Value.Size = address - first.Address;
|
||||
Update(first);
|
||||
BufferModifiedRange overlap = toClear[i];
|
||||
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
|
||||
first.Value.SyncNumber, first.Value.Parent));
|
||||
}
|
||||
ClearPart(overlap, address, endAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first.EndAddress > endAddress)
|
||||
{
|
||||
first.Value.Size = first.EndAddress - endAddress;
|
||||
first.Value.Address = endAddress;
|
||||
Update(first);
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(first.Value);
|
||||
}
|
||||
}
|
||||
|
||||
Lock.ExitWriteLock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BufferModifiedRange buffPre = null;
|
||||
BufferModifiedRange buffPost = null;
|
||||
bool extendsPost = false;
|
||||
bool extendsPre = false;
|
||||
|
||||
if (first.Address < address)
|
||||
/// <summary>
|
||||
/// Clear all modified ranges.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
buffPre = new BufferModifiedRange(first.Address, address - first.Address,
|
||||
first.Value.SyncNumber, first.Value.Parent);
|
||||
extendsPre = true;
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
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,5 +1,4 @@
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Graphics.Gpu.Memory
|
||||
@@ -8,7 +7,6 @@ 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,
|
||||
@@ -54,7 +52,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static BufferStage FromUsage(BufferUsageFlags flags)
|
||||
{
|
||||
if ((flags & BufferUsageFlags.Write) == BufferUsageFlags.Write)
|
||||
if (flags.HasFlag(BufferUsageFlags.Write))
|
||||
{
|
||||
return BufferStage.StorageWrite;
|
||||
}
|
||||
@@ -67,7 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static BufferStage FromUsage(TextureUsageFlags flags)
|
||||
{
|
||||
if ((flags & TextureUsageFlags.ImageStore) == TextureUsageFlags.ImageStore)
|
||||
if (flags.HasFlag(TextureUsageFlags.ImageStore))
|
||||
{
|
||||
return BufferStage.StorageWrite;
|
||||
}
|
||||
|
@@ -690,8 +690,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
if (_pageTable[l0] == null)
|
||||
{
|
||||
_pageTable[l0] = new ulong[PtLvl1Size];
|
||||
|
||||
Array.Fill(_pageTable[l0], PteUnmapped);
|
||||
|
||||
for (ulong index = 0; index < PtLvl1Size; index++)
|
||||
{
|
||||
_pageTable[l0][index] = PteUnmapped;
|
||||
}
|
||||
}
|
||||
|
||||
_pageTable[l0][l1] = pte;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -105,11 +104,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="scale">Scale value</param>
|
||||
public void UpdateRenderScale(int index, float scale)
|
||||
{
|
||||
Span<Vector4<float>> renderScaleSpan = _data.RenderScale.AsSpan();
|
||||
|
||||
if (renderScaleSpan[1 + index].X != scale)
|
||||
if (_data.RenderScale[1 + index].X != scale)
|
||||
{
|
||||
renderScaleSpan[1 + index].X = scale;
|
||||
_data.RenderScale[1 + index].X = scale;
|
||||
DirtyRenderScale(1 + index, 1);
|
||||
}
|
||||
}
|
||||
@@ -136,13 +133,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="isBgra">True if the format is BGRA< false otherwise</param>
|
||||
public void SetRenderTargetIsBgra(int index, bool isBgra)
|
||||
{
|
||||
Span<Vector4<int>> fragmentIsBgraSpan = _data.FragmentIsBgra.AsSpan();
|
||||
|
||||
bool isBgraChanged = fragmentIsBgraSpan[index].X != 0 != isBgra;
|
||||
bool isBgraChanged = _data.FragmentIsBgra[index].X != 0 != isBgra;
|
||||
|
||||
if (isBgraChanged)
|
||||
{
|
||||
fragmentIsBgraSpan[index].X = isBgra ? 1 : 0;
|
||||
_data.FragmentIsBgra[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 class VirtualRange : INonOverlappingRange
|
||||
private readonly struct VirtualRange : IRange
|
||||
{
|
||||
/// <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; private set; }
|
||||
public ulong Size { get; }
|
||||
|
||||
/// <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; private set; }
|
||||
public MultiRange Range { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new virtual memory range.
|
||||
@@ -60,14 +60,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
return Address < address + size && address < EndAddress;
|
||||
}
|
||||
|
||||
public INonOverlappingRange Split(ulong splitAddress)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private readonly NonOverlappingRangeList<VirtualRange> _virtualRanges;
|
||||
private readonly RangeList<VirtualRange> _virtualRanges;
|
||||
private VirtualRange[] _virtualRangeOverlaps;
|
||||
private readonly ConcurrentQueue<VirtualRange> _deferredUnmaps;
|
||||
private int _hasDeferredUnmaps;
|
||||
|
||||
@@ -79,6 +75,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
_memoryManager = memoryManager;
|
||||
_virtualRanges = [];
|
||||
_virtualRangeOverlaps = new VirtualRange[BufferCache.OverlapsBufferInitialCapacity];
|
||||
_deferredUnmaps = new ConcurrentQueue<VirtualRange>();
|
||||
}
|
||||
|
||||
@@ -109,11 +106,19 @@ 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))
|
||||
{
|
||||
_virtualRanges.RemoveRange(unmappedRange.Address, unmappedRange.Size);
|
||||
overlapsCount = _virtualRanges.FindOverlapsNonOverlapping(unmappedRange.Address, unmappedRange.Size, ref overlaps);
|
||||
|
||||
for (int index = 0; index < overlapsCount; index++)
|
||||
{
|
||||
_virtualRanges.Remove(overlaps[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,22 +126,27 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
ulong originalVa = gpuVa;
|
||||
|
||||
_virtualRanges.Lock.EnterWriteLock();
|
||||
(RangeItem<VirtualRange> first, RangeItem<VirtualRange> last) = _virtualRanges.FindOverlapsAsNodes(gpuVa, size);
|
||||
|
||||
if (first is not null)
|
||||
overlapsCount = _virtualRanges.FindOverlapsNonOverlapping(gpuVa, size, ref overlaps);
|
||||
|
||||
if (overlapsCount != 0)
|
||||
{
|
||||
// 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 (first.Address > gpuVa || first.EndAddress < endAddress)
|
||||
if (overlap0.Address > gpuVa || overlap0.EndAddress < endAddress)
|
||||
{
|
||||
gpuVa = Math.Min(gpuVa, first.Address);
|
||||
endAddress = Math.Max(endAddress, last.EndAddress);
|
||||
|
||||
_virtualRanges.RemoveRange(first, last);
|
||||
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);
|
||||
}
|
||||
|
||||
ulong newSize = endAddress - gpuVa;
|
||||
MultiRange newRange = _memoryManager.GetPhysicalRegions(gpuVa, newSize);
|
||||
@@ -147,8 +157,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
found = first.Value.Range.Count == 1 || IsSparseAligned(first.Value.Range);
|
||||
range = first.Value.Range.Slice(gpuVa - first.Address, size);
|
||||
found = overlap0.Range.Count == 1 || IsSparseAligned(overlap0.Range);
|
||||
range = overlap0.Range.Slice(gpuVa - overlap0.Address, size);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -160,7 +170,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
_virtualRanges.Add(virtualRange);
|
||||
}
|
||||
_virtualRanges.Lock.ExitWriteLock();
|
||||
|
||||
ShrinkOverlapsBufferIfNeeded();
|
||||
|
||||
// If the range is not properly aligned for sparse mapping,
|
||||
// let's just force it to a single range.
|
||||
@@ -210,5 +221,16 @@ 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,6 +1,5 @@
|
||||
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;
|
||||
@@ -259,25 +258,21 @@ 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 = rtColorStateSpan[rtIndex];
|
||||
var colorState = state.RtColorState[rtIndex];
|
||||
|
||||
if (index >= count || colorState.Format == 0 || colorState.WidthOrStride == 0)
|
||||
{
|
||||
attachmentEnableSpan[index] = false;
|
||||
attachmentFormatsSpan[index] = Format.R8G8B8A8Unorm;
|
||||
pipeline.AttachmentEnable[index] = false;
|
||||
pipeline.AttachmentFormats[index] = Format.R8G8B8A8Unorm;
|
||||
}
|
||||
else
|
||||
{
|
||||
attachmentEnableSpan[index] = true;
|
||||
attachmentFormatsSpan[index] = colorState.Format.Convert().Format;
|
||||
pipeline.AttachmentEnable[index] = true;
|
||||
pipeline.AttachmentFormats[index] = colorState.Format.Convert().Format;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -585,18 +580,15 @@ 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 = tfStateSpan[i];
|
||||
var tf = state.TfState[i];
|
||||
|
||||
descs[i] = new TransformFeedbackDescriptor(
|
||||
tf.BufferIndex,
|
||||
tf.Stride,
|
||||
tf.VaryingsCount,
|
||||
ref tfVaryingLocationsSpan[i]);
|
||||
ref state.TfVaryingLocations[i]);
|
||||
}
|
||||
|
||||
return descs;
|
||||
|
@@ -580,13 +580,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
|
||||
if (ShaderCache.MayConvertVtgToCompute(ref channel.Capabilities) && !vertexAsCompute)
|
||||
{
|
||||
Span<AttributeType> attributeTypesSpan = graphicsState.AttributeTypes.AsSpan();
|
||||
Span<AttributeType> gAttributeTypesSpan = GraphicsState.AttributeTypes.AsSpan();
|
||||
|
||||
for (int index = 0; index < attributeTypesSpan.Length; index++)
|
||||
for (int index = 0; index < graphicsState.AttributeTypes.Length; index++)
|
||||
{
|
||||
AttributeType lType = FilterAttributeType(channel, attributeTypesSpan[index]);
|
||||
AttributeType rType = FilterAttributeType(channel, gAttributeTypesSpan[index]);
|
||||
AttributeType lType = FilterAttributeType(channel, graphicsState.AttributeTypes[index]);
|
||||
AttributeType rType = FilterAttributeType(channel, GraphicsState.AttributeTypes[index]);
|
||||
|
||||
if (lType != rType)
|
||||
{
|
||||
@@ -732,8 +729,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||
|
||||
Span<uint> constantBufferUseSpan = ConstantBufferUse.AsSpan();
|
||||
|
||||
while (constantBufferUsePerStageMask != 0)
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||
@@ -742,7 +737,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
? channel.BufferManager.GetComputeUniformBufferUseMask()
|
||||
: channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
|
||||
|
||||
if (constantBufferUseSpan[index] != useMask)
|
||||
if (ConstantBufferUse[index] != useMask)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -806,7 +801,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
{
|
||||
if (specializationState != null)
|
||||
{
|
||||
if ((specializationState.Value.QueriedFlags & QueriedTextureStateFlags.CoordNormalized) == QueriedTextureStateFlags.CoordNormalized &&
|
||||
if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
|
||||
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
||||
{
|
||||
return false;
|
||||
@@ -882,12 +877,10 @@ 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 constantBufferUseSpan[index]);
|
||||
dataReader.Read(ref specState.ConstantBufferUse[index]);
|
||||
constantBufferUsePerStageMask &= ~(1 << index);
|
||||
}
|
||||
|
||||
@@ -986,13 +979,11 @@ 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 constantBufferUseSpan[index]);
|
||||
dataWriter.Write(ref ConstantBufferUse[index]);
|
||||
constantBufferUsePerStageMask &= ~(1 << index);
|
||||
}
|
||||
|
||||
|
@@ -92,24 +92,20 @@ 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, scalingLists4x4Span[index]);
|
||||
WriteScalingList(ref writer, pictureInfo.ScalingLists4x4[index]);
|
||||
}
|
||||
|
||||
if (pictureInfo.Transform8x8ModeFlag)
|
||||
{
|
||||
Span<Array64<byte>> scalingLists8x8Span = pictureInfo.ScalingLists8x8.AsSpan();
|
||||
|
||||
for (int index = 0; index < 2; index++)
|
||||
{
|
||||
writer.WriteBit(true);
|
||||
|
||||
WriteScalingList(ref writer, scalingLists8x8Span[index]);
|
||||
WriteScalingList(ref writer, pictureInfo.ScalingLists8x8[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,11 +144,9 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
||||
|
||||
int lastScale = 8;
|
||||
|
||||
Span<byte> listSpan = list.AsSpan();
|
||||
|
||||
for (int index = 0; index < listSpan.Length; index++)
|
||||
for (int index = 0; index < list.Length; index++)
|
||||
{
|
||||
byte value = listSpan[scan[index]];
|
||||
byte value = list[scan[index]];
|
||||
|
||||
int deltaScale = value - lastScale;
|
||||
|
||||
|
@@ -21,67 +21,49 @@ 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 tx8x8ProbSpan2[j]);
|
||||
r.DiffUpdateProb(ref txProbs.Tx8x8Prob[i][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 tx16x16ProbSpan2[j]);
|
||||
r.DiffUpdateProb(ref txProbs.Tx16x16Prob[i][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 tx32x32ProbSpan2[j]);
|
||||
r.DiffUpdateProb(ref txProbs.Tx32x32Prob[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadSwitchableInterpProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
||||
{
|
||||
Span<Array2<byte>> switchableInterpProbSpan1 = fc.SwitchableInterpProb.AsSpan();
|
||||
|
||||
for (int i = 0; i < Constants.SwitchableFilterContexts; ++i)
|
||||
for (int j = 0; j < Constants.SwitchableFilterContexts; ++j)
|
||||
{
|
||||
Span<byte> switchableInterpProbSpan2 = switchableInterpProbSpan1[i].AsSpan();
|
||||
|
||||
for (int j = 0; j < Constants.SwitchableFilters - 1; ++j)
|
||||
for (int i = 0; i < Constants.SwitchableFilters - 1; ++i)
|
||||
{
|
||||
r.DiffUpdateProb(ref switchableInterpProbSpan2[j]);
|
||||
r.DiffUpdateProb(ref fc.SwitchableInterpProb[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 interModeProbSpan2[j]);
|
||||
r.DiffUpdateProb(ref fc.InterModeProb[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,43 +72,30 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
r.UpdateMvProbs(ctx.Joints.AsSpan(), EntropyMv.Joints - 1);
|
||||
|
||||
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);
|
||||
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<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(class0FpSpan2[j].AsSpan(), EntropyMv.FpSize - 1);
|
||||
r.UpdateMvProbs(ctx.Class0Fp[i][j].AsSpan(), EntropyMv.FpSize - 1);
|
||||
}
|
||||
|
||||
r.UpdateMvProbs(fpSpan[i].AsSpan(), 3);
|
||||
r.UpdateMvProbs(ctx.Fp[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 class0HpSpan[i], 1), 1);
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref hpSpan[i], 1), 1);
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Class0Hp[i], 1), 1);
|
||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Hp[i], 1), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -782,16 +751,10 @@ 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 = refFrameSpan[refr];
|
||||
ref RefBuffer refBuf = ref frameRefsSpan[frame - Constants.LastFrame];
|
||||
int frame = mi.RefFrame[refr];
|
||||
ref RefBuffer refBuf = ref cm.FrameRefs[frame - Constants.LastFrame];
|
||||
ref ScaleFactors sf = ref refBuf.Sf;
|
||||
ref Surface refFrameBuf = ref refBuf.Buf;
|
||||
|
||||
@@ -804,13 +767,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);
|
||||
blockRefsSpan[refr] = new Ptr<RefBuffer>(ref refBuf);
|
||||
xd.BlockRefs[refr] = new Ptr<RefBuffer>(ref refBuf);
|
||||
|
||||
if (sbType < BlockSize.Block8X8)
|
||||
{
|
||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
ref Buf2D dstBuf = ref pd.Dst;
|
||||
int num4X4W = pd.N4W;
|
||||
int num4X4H = pd.N4H;
|
||||
@@ -848,10 +811,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
else
|
||||
{
|
||||
Mv mv = mvSpan[refr];
|
||||
Mv mv = mi.Mv[refr];
|
||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
ref Buf2D dstBuf = ref pd.Dst;
|
||||
int num4X4W = pd.N4W;
|
||||
int num4X4H = pd.N4H;
|
||||
@@ -884,14 +847,12 @@ 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++)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -931,7 +892,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(xd.Plane.AsSpan(), ref xd.CurBuf, miRow, miCol);
|
||||
ReconInter.SetupDstPlanes(ref xd.Plane, ref xd.CurBuf, miRow, miCol);
|
||||
return ref xd.Mi[0].Value;
|
||||
}
|
||||
|
||||
@@ -972,11 +933,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
if (!mi.IsInterBlock())
|
||||
{
|
||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||
|
||||
for (int plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
int plane;
|
||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
||||
int num4X4W = pd.N4W;
|
||||
int num4X4H = pd.N4H;
|
||||
@@ -1007,13 +967,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Reconstruction
|
||||
if (mi.Skip == 0)
|
||||
{
|
||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
||||
|
||||
int eobtotal = 0;
|
||||
int plane;
|
||||
|
||||
for (int plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||
{
|
||||
ref MacroBlockDPlane pd = ref planeSpan[plane];
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
||||
int num4X4W = pd.N4W;
|
||||
int num4X4H = pd.N4H;
|
||||
@@ -1200,30 +1159,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
}
|
||||
|
||||
private static void ReadCoefProbsCommon(ReadOnlySpan<Array2<Array6<Array6<Array3<byte>>>>> coefProbs1,
|
||||
private static void ReadCoefProbsCommon(ref Array2<Array2<Array6<Array6<Array3<byte>>>>> coefProbs,
|
||||
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 coefProbs5[m]);
|
||||
r.DiffUpdateProb(ref coefProbs[i][j][k][l][m]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1234,13 +1185,10 @@ 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(coefProbsSpan[txSize].AsSpan(), ref r, txSize);
|
||||
ReadCoefProbsCommon(ref fc.CoefProbs[txSize], ref r, txSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1259,14 +1207,11 @@ 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)
|
||||
{
|
||||
refDeltasSpan[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||
lf.RefDeltas[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1274,7 +1219,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (rb.ReadBit() != 0)
|
||||
{
|
||||
modeDeltasSpan[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||
lf.ModeDeltas[i] = (sbyte)rb.ReadSignedLiteral(6);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1322,8 +1267,6 @@ 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,
|
||||
@@ -1333,21 +1276,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
cm.UseHighBitDepth,
|
||||
Surface.DecBorderInPixels,
|
||||
cm.ByteAlignment,
|
||||
new Ptr<VpxCodecFrameBuffer>(ref frameBuffsSpan[cm.NewFbIdx].RawFrameBuffer),
|
||||
new Ptr<VpxCodecFrameBuffer>(ref pool.FrameBufs[cm.NewFbIdx].RawFrameBuffer),
|
||||
FrameBuffers.GetFrameBuffer,
|
||||
pool.CbPriv) != 0)
|
||||
{
|
||||
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
private static bool ValidRefFrameImgFmt(
|
||||
@@ -1368,15 +1311,13 @@ 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 (frameRefsSpan[i].Idx != RefBuffer.InvalidIdx)
|
||||
if (cm.FrameRefs[i].Idx != RefBuffer.InvalidIdx)
|
||||
{
|
||||
ref Surface buf = ref frameRefsSpan[i].Buf;
|
||||
ref Surface buf = ref cm.FrameRefs[i].Buf;
|
||||
width = buf.YCropWidth;
|
||||
height = buf.YCropHeight;
|
||||
found = true;
|
||||
@@ -1401,7 +1342,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// has valid dimensions.
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
||||
hasValidRefFrame |=
|
||||
refFrame.Idx != RefBuffer.InvalidIdx &&
|
||||
ScaleFactors.ValidRefFrameSize(refFrame.Buf.YCropWidth, refFrame.Buf.YCropHeight, width,
|
||||
@@ -1415,7 +1356,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
||||
if (refFrame.Idx == RefBuffer.InvalidIdx ||
|
||||
!ValidRefFrameImgFmt(
|
||||
(BitDepth)refFrame.Buf.BitDepth,
|
||||
@@ -1432,8 +1373,6 @@ 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,
|
||||
@@ -1444,21 +1383,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
cm.UseHighBitDepth,
|
||||
Surface.DecBorderInPixels,
|
||||
cm.ByteAlignment,
|
||||
new Ptr<VpxCodecFrameBuffer>(ref frameBuffsSpan[cm.NewFbIdx].RawFrameBuffer),
|
||||
new Ptr<VpxCodecFrameBuffer>(ref pool.FrameBufs[cm.NewFbIdx].RawFrameBuffer),
|
||||
FrameBuffers.GetFrameBuffer,
|
||||
pool.CbPriv) != 0)
|
||||
{
|
||||
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
// Reads the next tile returning its size and adjusting '*data' accordingly
|
||||
@@ -1498,7 +1437,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
private static void GetTileBuffers(ref Vp9Common cm, ArrayPtr<byte> data, int tileCols,
|
||||
Span<TileBuffer> tileBuffers)
|
||||
ref Array64<TileBuffer> tileBuffers)
|
||||
{
|
||||
for (int c = 0; c < tileCols; ++c)
|
||||
{
|
||||
@@ -1514,16 +1453,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ArrayPtr<byte> data,
|
||||
int tileCols,
|
||||
int tileRows,
|
||||
Span<Array64<TileBuffer>> tileBuffers1)
|
||||
ref Array4<Array64<TileBuffer>> tileBuffers)
|
||||
{
|
||||
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 tileBuffers2[c];
|
||||
ref TileBuffer buf = ref tileBuffers[r][c];
|
||||
GetTileBuffer(isLast, ref cm.Error, ref data, ref buf);
|
||||
}
|
||||
}
|
||||
@@ -1547,20 +1484,15 @@ 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, tileBuffers1);
|
||||
GetTileBuffers(ref cm, data, tileCols, tileRows, ref tileBuffers);
|
||||
// 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 tileBuffers2[tileCol];
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[(tileCols * tileRow) + tileCol];
|
||||
ref TileBuffer buf = ref tileBuffers[tileRow][tileCol];
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[(tileCols * tileRow) + tileCol];
|
||||
tileData.Xd = cm.Mb;
|
||||
tileData.Xd.Corrupted = false;
|
||||
tileData.Xd.Counts = cm.Counts;
|
||||
@@ -1580,7 +1512,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
||||
{
|
||||
int col = tileCol;
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[(tileCols * tileRow) + col];
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[(tileCols * tileRow) + col];
|
||||
tile.SetCol(ref cm, col);
|
||||
tileData.Xd.LeftContext = new Array3<Array16<sbyte>>();
|
||||
tileData.Xd.LeftSegContext = new Array8<sbyte>();
|
||||
@@ -1599,11 +1531,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
// Get last tile data.
|
||||
return tileWorkerDataSpan[(tileCols * tileRows) - 1].BitReader.FindEnd();
|
||||
return cm.TileWorkerData[(tileCols * tileRows) - 1].BitReader.FindEnd();
|
||||
}
|
||||
|
||||
private static bool DecodeTileCol(ref TileWorkerData tileData, ref Vp9Common cm,
|
||||
Span<TileBuffer> tileBuffers)
|
||||
ref Array64<TileBuffer> tileBuffers)
|
||||
{
|
||||
ref TileInfo tile = ref tileData.Xd.Tile;
|
||||
int finalCol = (1 << cm.Log2TileCols) - 1;
|
||||
@@ -1661,12 +1593,10 @@ 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 tileWorkerDataSpan[n + totalTiles];
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
||||
|
||||
tileData.Xd = cm.Mb;
|
||||
tileData.Xd.Counts = new Ptr<Vp9BackwardUpdates>(ref tileData.Counts);
|
||||
@@ -1674,17 +1604,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
Array64<TileBuffer> tileBuffers = new();
|
||||
Span<TileBuffer> tileBuffersSpan = tileBuffers.AsSpan();
|
||||
|
||||
GetTileBuffers(ref cm, data, tileCols, tileBuffersSpan);
|
||||
GetTileBuffers(ref cm, data, tileCols, ref tileBuffers);
|
||||
|
||||
tileBuffersSpan[..tileCols].Sort(CompareTileBuffers);
|
||||
tileBuffers.AsSpan()[..tileCols].Sort(CompareTileBuffers);
|
||||
|
||||
if (numWorkers == tileCols)
|
||||
{
|
||||
TileBuffer largest = tileBuffersSpan[0];
|
||||
tileBuffersSpan[1..].CopyTo(tileBuffersSpan[..^1]);
|
||||
tileBuffersSpan[tileCols - 1] = largest;
|
||||
TileBuffer largest = tileBuffers[0];
|
||||
Span<TileBuffer> buffers = tileBuffers.AsSpan();
|
||||
buffers[1..].CopyTo(buffers[..(tileBuffers.Length - 1)]);
|
||||
tileBuffers[tileCols - 1] = largest;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1695,9 +1625,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// larger tile implies it is more difficult to decode.
|
||||
while (start < end)
|
||||
{
|
||||
tmp = tileBuffersSpan[start];
|
||||
tileBuffersSpan[start] = tileBuffersSpan[end];
|
||||
tileBuffersSpan[end] = tmp;
|
||||
tmp = tileBuffers[start];
|
||||
tileBuffers[start] = tileBuffers[end];
|
||||
tileBuffers[end] = tmp;
|
||||
start += 2;
|
||||
end -= 2;
|
||||
}
|
||||
@@ -1710,7 +1640,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
for (n = 0; n < numWorkers; ++n)
|
||||
{
|
||||
int count = baseVal + ((remain + n) / numWorkers);
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[n + totalTiles];
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
||||
|
||||
tileData.BufStart = bufStart;
|
||||
tileData.BufEnd = bufStart + count - 1;
|
||||
@@ -1724,7 +1654,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
ref TileWorkerData tileData = ref cmPtr.Value.TileWorkerData[n + totalTiles];
|
||||
|
||||
if (!DecodeTileCol(ref tileData, ref cmPtr.Value, tileBuffers.AsSpan()))
|
||||
if (!DecodeTileCol(ref tileData, ref cmPtr.Value, ref tileBuffers))
|
||||
{
|
||||
cmPtr.Value.Mb.Corrupted = true;
|
||||
}
|
||||
@@ -1734,14 +1664,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (bitReaderEnd.IsNull)
|
||||
{
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[n - 1 + totalTiles];
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n - 1 + totalTiles];
|
||||
bitReaderEnd = tileData.DataEnd;
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 0; n < numWorkers; ++n)
|
||||
{
|
||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[n + totalTiles];
|
||||
ref TileWorkerData tileData = ref cm.TileWorkerData[n + totalTiles];
|
||||
AccumulateFrameCounts(ref cm.Counts.Value, ref tileData.Counts);
|
||||
}
|
||||
|
||||
@@ -1775,7 +1705,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (cm.FrameType == FrameType.KeyFrame && cm.CurrentVideoFrame > 0)
|
||||
{
|
||||
Span<RefCntBuffer> frameBuffs = cm.BufferPool.Value.FrameBufs.AsSpan();
|
||||
ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
|
||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||
|
||||
for (int i = 0; i < Constants.FrameBuffers; ++i)
|
||||
@@ -1785,11 +1715,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
continue;
|
||||
}
|
||||
|
||||
frameBuffs[i].RefCount = 0;
|
||||
if (frameBuffs[i].Released == 0)
|
||||
frameBufs[i].RefCount = 0;
|
||||
if (frameBufs[i].Released == 0)
|
||||
{
|
||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBuffs[i].RawFrameBuffer);
|
||||
frameBuffs[i].Released = 1;
|
||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[i].RawFrameBuffer);
|
||||
frameBufs[i].Released = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1812,7 +1742,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
readSyncCode2 == SyncCode2;
|
||||
}
|
||||
|
||||
private static void RefCntFb(Span<RefCntBuffer> bufs, ref int idx, int newIdx)
|
||||
private static void RefCntFb(ref Array12<RefCntBuffer> bufs, ref int idx, int newIdx)
|
||||
{
|
||||
int refIndex = idx;
|
||||
|
||||
@@ -1831,15 +1761,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
ref Vp9Common cm = ref pbi.Common;
|
||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||
Span<RefCntBuffer> frameBuffs = pool.FrameBufs.AsSpan();
|
||||
ref Array12<RefCntBuffer> frameBufs = ref pool.FrameBufs;
|
||||
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");
|
||||
@@ -1855,14 +1783,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
if (cm.ShowExistingFrame != 0)
|
||||
{
|
||||
// Show an existing frame directly.
|
||||
int frameToShow = refFrameSpan[rb.ReadLiteral(3)];
|
||||
if (frameToShow < 0 || frameBuffs[frameToShow].RefCount < 1)
|
||||
int frameToShow = cm.RefFrameMap[rb.ReadLiteral(3)];
|
||||
if (frameToShow < 0 || frameBufs[frameToShow].RefCount < 1)
|
||||
{
|
||||
cm.Error.InternalError(CodecErr.UnsupBitstream,
|
||||
$"Buffer {frameToShow} does not contain a decoded frame");
|
||||
}
|
||||
|
||||
RefCntFb(frameBuffs, ref cm.NewFbIdx, frameToShow);
|
||||
RefCntFb(ref frameBufs, ref cm.NewFbIdx, frameToShow);
|
||||
pbi.RefreshFrameFlags = 0;
|
||||
cm.Lf.FilterLevel = 0;
|
||||
cm.ShowFrame = 1;
|
||||
@@ -1884,18 +1812,16 @@ 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)
|
||||
{
|
||||
frameRefsSpan[i].Idx = RefBuffer.InvalidIdx;
|
||||
frameRefsSpan[i].Buf = default;
|
||||
cm.FrameRefs[i].Idx = RefBuffer.InvalidIdx;
|
||||
cm.FrameRefs[i].Buf = default;
|
||||
}
|
||||
|
||||
SetupFrameSize(allocator, ref cm, ref rb);
|
||||
if (pbi.NeedResync != 0)
|
||||
{
|
||||
refFrameSpan.Fill(-1);
|
||||
cm.RefFrameMap.AsSpan().Fill(-1);
|
||||
FlushAllFbOnKey(ref cm);
|
||||
pbi.NeedResync = 0;
|
||||
}
|
||||
@@ -1934,25 +1860,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
SetupFrameSize(allocator, ref cm, ref rb);
|
||||
if (pbi.NeedResync != 0)
|
||||
{
|
||||
refFrameSpan.Fill(-1);
|
||||
cm.RefFrameMap.AsSpan().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 = refFrameSpan[refr];
|
||||
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
||||
int idx = cm.RefFrameMap[refr];
|
||||
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
||||
refFrame.Idx = idx;
|
||||
refFrame.Buf = frameBuffs[idx].Buf;
|
||||
refFrameSignBiasSpan[Constants.LastFrame + i] = (sbyte)rb.ReadBit();
|
||||
refFrame.Buf = frameBufs[idx].Buf;
|
||||
cm.RefFrameSignBias[Constants.LastFrame + i] = (sbyte)rb.ReadBit();
|
||||
}
|
||||
|
||||
SetupFrameSizeWithRefs(allocator, ref cm, ref rb);
|
||||
@@ -1962,7 +1885,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||
{
|
||||
ref RefBuffer refBuf = ref frameRefsSpan[i];
|
||||
ref RefBuffer refBuf = ref cm.FrameRefs[i];
|
||||
refBuf.Sf.SetupScaleFactorsForFrame(
|
||||
refBuf.Buf.YCropWidth,
|
||||
refBuf.Buf.YCropHeight,
|
||||
@@ -2003,25 +1926,23 @@ 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)
|
||||
{
|
||||
nextRefFrameMapSpan[refIndex] = cm.NewFbIdx;
|
||||
++frameBuffs[cm.NewFbIdx].RefCount;
|
||||
cm.NextRefFrameMap[refIndex] = cm.NewFbIdx;
|
||||
++frameBufs[cm.NewFbIdx].RefCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextRefFrameMapSpan[refIndex] = cm.RefFrameMap[refIndex];
|
||||
cm.NextRefFrameMap[refIndex] = cm.RefFrameMap[refIndex];
|
||||
}
|
||||
|
||||
// Current thread holds the reference frame.
|
||||
if (cm.RefFrameMap[refIndex] >= 0)
|
||||
{
|
||||
++frameBuffs[cm.RefFrameMap[refIndex]].RefCount;
|
||||
++frameBufs[cm.RefFrameMap[refIndex]].RefCount;
|
||||
}
|
||||
|
||||
++refIndex;
|
||||
@@ -2029,11 +1950,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
for (; refIndex < Constants.RefFrames; ++refIndex)
|
||||
{
|
||||
nextRefFrameMapSpan[refIndex] = refFrameSpan[refIndex];
|
||||
cm.NextRefFrameMap[refIndex] = cm.RefFrameMap[refIndex];
|
||||
// Current thread holds the reference frame.
|
||||
if (refFrameSpan[refIndex] >= 0)
|
||||
if (cm.RefFrameMap[refIndex] >= 0)
|
||||
{
|
||||
++frameBuffs[refFrameSpan[refIndex]].RefCount;
|
||||
++frameBufs[cm.RefFrameMap[refIndex]].RefCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2080,11 +2001,9 @@ 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 skipProbSpan[k]);
|
||||
r.DiffUpdateProb(ref fc.SkipProb[k]);
|
||||
}
|
||||
|
||||
if (!cm.FrameIsIntraOnly())
|
||||
@@ -2095,12 +2014,10 @@ 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 intraInterProbSpan[i]);
|
||||
r.DiffUpdateProb(ref fc.IntraInterProb[i]);
|
||||
}
|
||||
|
||||
cm.ReferenceMode = cm.ReadFrameReferenceMode(ref r);
|
||||
@@ -2110,28 +2027,20 @@ 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 yModeProbSpan2[i]);
|
||||
r.DiffUpdateProb(ref fc.YModeProb[j][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 partitionProbSpan2[i]);
|
||||
r.DiffUpdateProb(ref fc.PartitionProb[j][i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2189,9 +2098,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
xd.SetupBlockPlanes(cm.SubsamplingX, cm.SubsamplingY);
|
||||
|
||||
Span<Vp9EntropyProbs> frameContextsSpan = cm.FrameContexts.AsSpan();
|
||||
|
||||
cm.Fc = new Ptr<Vp9EntropyProbs>(ref frameContextsSpan[(int)cm.FrameContextIdx]);
|
||||
cm.Fc = new Ptr<Vp9EntropyProbs>(ref cm.FrameContexts[(int)cm.FrameContextIdx]);
|
||||
|
||||
xd.Corrupted = false;
|
||||
newFb.Corrupted = ReadCompressedHeader(ref pbi, data, firstPartitionSize) ? 1 : 0;
|
||||
@@ -2260,7 +2167,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Non frame parallel update frame context here.
|
||||
if (cm.RefreshFrameContext != 0 && contextUpdated == 0)
|
||||
{
|
||||
frameContextsSpan[(int)cm.FrameContextIdx] = cm.Fc.Value;
|
||||
cm.FrameContexts[(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, ReadOnlySpan<byte> segTreeProbs)
|
||||
private static int ReadSegmentId(ref Reader r, ref Array7<byte> segTreeProbs)
|
||||
{
|
||||
return r.ReadTree(Luts.SegmentTree, segTreeProbs);
|
||||
return r.ReadTree(Luts.SegmentTree, segTreeProbs.AsSpan());
|
||||
}
|
||||
|
||||
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, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||
segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
||||
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(cm.Fc.Value.SegPredProb.AsSpan(), ref xd);
|
||||
byte predProb = Segmentation.GetPredProbSegId(ref cm.Fc.Value.SegPredProb, ref xd);
|
||||
mi.SegIdPredicted = (sbyte)r.Read(predProb);
|
||||
segmentId = mi.SegIdPredicted != 0
|
||||
? predictedSegmentId
|
||||
: ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||
: ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
||||
}
|
||||
else
|
||||
{
|
||||
segmentId = ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
||||
segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
||||
}
|
||||
|
||||
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
|
||||
@@ -272,12 +272,10 @@ 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(bitsSpan[i]) << i;
|
||||
d |= r.Read(fc.Bits[mvcomp][i]) << i;
|
||||
}
|
||||
|
||||
mag = Constants.Class0Size << ((int)mvClass + 2);
|
||||
@@ -345,7 +343,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ref MacroBlockD xd,
|
||||
ref Reader r,
|
||||
int segmentId,
|
||||
Span<sbyte> refFrame)
|
||||
ref Array2<sbyte> refFrame)
|
||||
{
|
||||
ref Vp9EntropyProbs fc = ref cm.Fc.Value;
|
||||
|
||||
@@ -420,25 +418,23 @@ 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)
|
||||
{
|
||||
bmiSpan[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
mi.Bmi[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
|
||||
}
|
||||
|
||||
mi.Mode = bmiSpan[3].Mode;
|
||||
mi.Mode = mi.Bmi[3].Mode;
|
||||
break;
|
||||
case BlockSize.Block4X8:
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
case BlockSize.Block8X4:
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]);
|
||||
@@ -451,19 +447,29 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// modes in GetPredContextSwitchableInterp()
|
||||
mi.InterpFilter = Constants.SwitchableFilters;
|
||||
|
||||
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
||||
|
||||
refFrameSpan[0] = Constants.IntraFrame;
|
||||
refFrameSpan[1] = Constants.None;
|
||||
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();
|
||||
}
|
||||
|
||||
private static bool Assign(
|
||||
ref Vp9Common cm,
|
||||
ref MacroBlockD xd,
|
||||
PredictionMode mode,
|
||||
Span<Mv> mv,
|
||||
Span<Mv> refMv,
|
||||
Span<Mv> nearNearestMv,
|
||||
ref Array2<Mv> mv,
|
||||
ref Array2<Mv> refMv,
|
||||
ref Array2<Mv> nearNearestMv,
|
||||
int isCompound,
|
||||
bool allowHp,
|
||||
ref Reader r)
|
||||
@@ -485,12 +491,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
case PredictionMode.NearMv:
|
||||
case PredictionMode.NearestMv:
|
||||
{
|
||||
nearNearestMv.CopyTo(mv);
|
||||
CopyPair(ref mv, ref nearNearestMv);
|
||||
break;
|
||||
}
|
||||
case PredictionMode.ZeroMv:
|
||||
{
|
||||
mv.Clear();
|
||||
ZeroPair(ref mv);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -553,29 +559,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
private static bool IsDiffRefFrameAddEb(
|
||||
ref ModeInfo mbmi,
|
||||
sbyte refFrame,
|
||||
Span<sbyte> refSignBias,
|
||||
ref Array4<sbyte> refSignBias,
|
||||
ref int refmvCount,
|
||||
Span<Mv> mvRefList,
|
||||
bool earlyBreak)
|
||||
{
|
||||
if (mbmi.IsInterBlock())
|
||||
{
|
||||
Span<sbyte> refFrameSpan = mbmi.RefFrame.AsSpan();
|
||||
Span<Mv> mvSpan = mbmi.Mv.AsSpan();
|
||||
|
||||
if (refFrameSpan[0] != refFrame)
|
||||
if (mbmi.RefFrame[0] != refFrame)
|
||||
{
|
||||
if (AddRefListEb(mbmi.ScaleMv(0, refFrame, refSignBias), ref refmvCount, mvRefList,
|
||||
if (AddRefListEb(mbmi.ScaleMv(0, refFrame, ref refSignBias), ref refmvCount, mvRefList,
|
||||
earlyBreak))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mbmi.HasSecondRef() && refFrameSpan[1] != refFrame &&
|
||||
Unsafe.As<Mv, int>(ref mvSpan[1]) != Unsafe.As<Mv, int>(ref mvSpan[0]))
|
||||
if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame &&
|
||||
Unsafe.As<Mv, int>(ref mbmi.Mv[1]) != Unsafe.As<Mv, int>(ref mbmi.Mv[0]))
|
||||
{
|
||||
if (AddRefListEb(mbmi.ScaleMv(1, refFrame, refSignBias), ref refmvCount, mvRefList,
|
||||
if (AddRefListEb(mbmi.ScaleMv(1, refFrame, ref refSignBias), ref refmvCount, mvRefList,
|
||||
earlyBreak))
|
||||
{
|
||||
return true;
|
||||
@@ -600,7 +603,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
int block,
|
||||
int isSub8X8)
|
||||
{
|
||||
Span<sbyte> refSignBias = cm.RefFrameSignBias.AsSpan();
|
||||
ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias;
|
||||
int i, refmvCount = 0;
|
||||
bool differentRefFound = false;
|
||||
Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs
|
||||
@@ -613,7 +616,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
// Blank the reference vector list
|
||||
mvRefList[..Constants.MaxMvRefCandidates].Clear();
|
||||
|
||||
|
||||
i = 0;
|
||||
if (isSub8X8 != 0)
|
||||
{
|
||||
@@ -627,9 +630,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||
differentRefFound = true;
|
||||
|
||||
Span<sbyte> refFrameSpan = candidateMi.RefFrame.AsSpan();
|
||||
|
||||
if (refFrameSpan[0] == refFrame)
|
||||
if (candidateMi.RefFrame[0] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount,
|
||||
mvRefList, earlyBreak))
|
||||
@@ -637,7 +638,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
else if (refFrameSpan[1] == refFrame)
|
||||
else if (candidateMi.RefFrame[1] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount,
|
||||
mvRefList, earlyBreak))
|
||||
@@ -659,20 +660,17 @@ 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 (refFrameSpan[0] == refFrame)
|
||||
if (candidate.RefFrame[0] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(mvSpan[0], ref refmvCount, mvRefList, earlyBreak))
|
||||
if (AddRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
else if (refFrameSpan[1] == refFrame)
|
||||
else if (candidate.RefFrame[1] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(mvSpan[1], ref refmvCount, mvRefList, earlyBreak))
|
||||
if (AddRefListEb(candidate.Mv[1], ref refmvCount, mvRefList, earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
@@ -683,19 +681,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Check the last frame's mode and mv info.
|
||||
if (!prevFrameMvs.IsNull)
|
||||
{
|
||||
Span<sbyte> refFrameSpan = prevFrameMvs.Value.RefFrame.AsSpan();
|
||||
Span<Mv> mvSpan = prevFrameMvs.Value.Mv.AsSpan();
|
||||
|
||||
if (refFrameSpan[0] == refFrame)
|
||||
if (prevFrameMvs.Value.RefFrame[0] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(mvSpan[0], ref refmvCount, mvRefList, earlyBreak))
|
||||
if (AddRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
else if (refFrameSpan[1] == refFrame)
|
||||
else if (prevFrameMvs.Value.RefFrame[1] == refFrame)
|
||||
{
|
||||
if (AddRefListEb(mvSpan[1], ref refmvCount, mvRefList, earlyBreak))
|
||||
if (AddRefListEb(prevFrameMvs.Value.Mv[1], ref refmvCount, mvRefList, earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
}
|
||||
@@ -715,7 +710,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, refSignBias, ref refmvCount, mvRefList,
|
||||
if (IsDiffRefFrameAddEb(ref candidate, refFrame, ref refSignBias, ref refmvCount, mvRefList,
|
||||
earlyBreak))
|
||||
{
|
||||
goto Done;
|
||||
@@ -727,13 +722,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Since we still don't have a candidate we'll try the last frame.
|
||||
if (!prevFrameMvs.IsNull)
|
||||
{
|
||||
Span<sbyte> refFrameSpan = prevFrameMvs.Value.RefFrame.AsSpan();
|
||||
Span<Mv> mvSpan = prevFrameMvs.Value.Mv.AsSpan();
|
||||
|
||||
if (refFrameSpan[0] != refFrame && refFrameSpan[0] > Constants.IntraFrame)
|
||||
if (prevFrameMvs.Value.RefFrame[0] != refFrame && prevFrameMvs.Value.RefFrame[0] > Constants.IntraFrame)
|
||||
{
|
||||
Mv mv = mvSpan[0];
|
||||
if (refSignBias[refFrameSpan[0]] != refSignBias[refFrame])
|
||||
Mv mv = prevFrameMvs.Value.Mv[0];
|
||||
if (refSignBias[prevFrameMvs.Value.RefFrame[0]] != refSignBias[refFrame])
|
||||
{
|
||||
mv.Row *= -1;
|
||||
mv.Col *= -1;
|
||||
@@ -745,13 +737,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
}
|
||||
|
||||
if (refFrameSpan[1] > Constants.IntraFrame &&
|
||||
refFrameSpan[1] != refFrame &&
|
||||
Unsafe.As<Mv, int>(ref mvSpan[1]) !=
|
||||
Unsafe.As<Mv, int>(ref mvSpan[0]))
|
||||
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]))
|
||||
{
|
||||
Mv mv = mvSpan[1];
|
||||
if (refSignBias[refFrameSpan[1]] != refSignBias[refFrame])
|
||||
Mv mv = prevFrameMvs.Value.Mv[1];
|
||||
if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame])
|
||||
{
|
||||
mv.Row *= -1;
|
||||
mv.Col *= -1;
|
||||
@@ -797,7 +789,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
|
||||
ref ModeInfo mi = ref xd.Mi[0].Value;
|
||||
Span<BModeInfo> bmi = mi.Bmi.AsSpan();
|
||||
ref Array4<BModeInfo> bmi = ref mi.Bmi;
|
||||
int refmvCount;
|
||||
|
||||
Debug.Assert(Constants.MaxMvRefCandidates == 2);
|
||||
@@ -892,12 +884,11 @@ 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, mi.RefFrame.AsSpan());
|
||||
ReadRefFrames(ref cm, ref xd, ref r, mi.SegmentId, ref mi.RefFrame);
|
||||
isCompound = mi.HasSecondRef() ? 1 : 0;
|
||||
interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
|
||||
|
||||
@@ -929,17 +920,16 @@ 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 = refFrameSpan[refr];
|
||||
sbyte frame = mi.RefFrame[refr];
|
||||
int refmvCount;
|
||||
|
||||
refmvCount = DecFindRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol,
|
||||
-1, 0);
|
||||
|
||||
DecFindBestRefs(allowHp, tmpMvs, ref bestRefMvsSpan[refr], refmvCount);
|
||||
DecFindBestRefs(allowHp, tmpMvs, ref bestRefMvs[refr], refmvCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -955,12 +945,10 @@ 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 bestSub8X8Span[1]) = InvalidMv;
|
||||
Unsafe.As<Mv, uint>(ref bestSub8X8[1]) = InvalidMv;
|
||||
for (idy = 0; idy < 2; idy += num4X4H)
|
||||
{
|
||||
for (idx = 0; idx < 2; idx += num4X4W)
|
||||
@@ -973,11 +961,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 bestSub8X8Span[refr]);
|
||||
ref bestSub8X8[refr]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Assign(ref cm, ref xd, bMode, bmiSpan[j].Mv.AsSpan(), bestRefMvs.AsSpan(), bestSub8X8.AsSpan(),
|
||||
if (!Assign(ref cm, ref xd, bMode, ref mi.Bmi[j].Mv, ref bestRefMvs, ref bestSub8X8,
|
||||
isCompound, allowHp, ref r))
|
||||
{
|
||||
xd.Corrupted |= true;
|
||||
@@ -986,22 +974,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
if (num4X4H == 2)
|
||||
{
|
||||
bmiSpan[j + 2] = bmiSpan[j];
|
||||
mi.Bmi[j + 2] = mi.Bmi[j];
|
||||
}
|
||||
|
||||
if (num4X4W == 2)
|
||||
{
|
||||
bmiSpan[j + 1] = bmiSpan[j];
|
||||
mi.Bmi[j + 1] = mi.Bmi[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mi.Mode = bMode;
|
||||
bmiSpan[3].Mv.AsSpan().CopyTo(mi.Mv.AsSpan());
|
||||
|
||||
CopyPair(ref mi.Mv, ref mi.Bmi[3].Mv);
|
||||
}
|
||||
else
|
||||
{
|
||||
xd.Corrupted |= !Assign(ref cm, ref xd, mi.Mode, mi.Mv.AsSpan(), bestRefMvs.AsSpan(), bestRefMvs.AsSpan(),
|
||||
xd.Corrupted |= !Assign(ref cm, ref xd, mi.Mode, ref mi.Mv, ref bestRefMvs, ref bestRefMvs,
|
||||
isCompound, allowHp, ref r);
|
||||
}
|
||||
}
|
||||
@@ -1093,42 +1082,33 @@ 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);
|
||||
refFrameSpan[0] = Constants.IntraFrame;
|
||||
refFrameSpan[1] = Constants.None;
|
||||
mi.Value.RefFrame[0] = Constants.IntraFrame;
|
||||
mi.Value.RefFrame[1] = Constants.None;
|
||||
|
||||
Span<BModeInfo> bmiSpan;
|
||||
switch (bsize)
|
||||
{
|
||||
case BlockSize.Block4X4:
|
||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
bmiSpan[i].Mode =
|
||||
mi.Value.Bmi[i].Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i));
|
||||
}
|
||||
|
||||
mi.Value.Mode = bmiSpan[3].Mode;
|
||||
mi.Value.Mode = mi.Value.Bmi[3].Mode;
|
||||
break;
|
||||
case BlockSize.Block4X8:
|
||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||
|
||||
bmiSpan[0].Mode = bmiSpan[2].Mode =
|
||||
mi.Value.Bmi[0].Mode = mi.Value.Bmi[2].Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
||||
bmiSpan[1].Mode = bmiSpan[3].Mode = mi.Value.Mode =
|
||||
mi.Value.Bmi[1].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 1));
|
||||
break;
|
||||
case BlockSize.Block8X4:
|
||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
||||
|
||||
bmiSpan[0].Mode = bmiSpan[1].Mode =
|
||||
mi.Value.Bmi[0].Mode = mi.Value.Bmi[1].Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
||||
bmiSpan[2].Mode = bmiSpan[3].Mode = mi.Value.Mode =
|
||||
mi.Value.Bmi[2].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
|
||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 2));
|
||||
break;
|
||||
default:
|
||||
@@ -1139,6 +1119,12 @@ 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,
|
||||
@@ -1165,8 +1151,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
for (int w = 0; w < xMis; ++w)
|
||||
{
|
||||
ref MvRef mv = ref frameMvs[w];
|
||||
mi.RefFrame.AsSpan().CopyTo(mv.RefFrame.AsSpan());
|
||||
mi.Mv.AsSpan().CopyTo(mv.Mv.AsSpan());
|
||||
CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame);
|
||||
CopyPair(ref mv.Mv, ref mi.Mv);
|
||||
}
|
||||
|
||||
frameMvs = frameMvs.Slice(cm.MiCols);
|
||||
|
@@ -89,10 +89,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
cm.Lf.RefDeltas = pictureInfo.RefDeltas;
|
||||
cm.Lf.ModeDeltas = pictureInfo.ModeDeltas;
|
||||
|
||||
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.FrameRefs[0].Buf = (Surface)pictureInfo.LastReference;
|
||||
cm.FrameRefs[1].Buf = (Surface)pictureInfo.GoldenReference;
|
||||
cm.FrameRefs[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,
|
||||
ReadOnlySpan<short> dq,
|
||||
ref Array2<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;
|
||||
ReadOnlySpan<Array6<Array3<byte>>> coefProbs = fc.CoefProbs[(int)txSize][(int)type][refr].AsSpan();
|
||||
ref Array6<Array6<Array3<byte>>> coefProbs = ref fc.CoefProbs[(int)txSize][(int)type][refr];
|
||||
Span<byte> tokenCache = stackalloc byte[32 * 32];
|
||||
ReadOnlySpan<byte> bandTranslate = Luts.GetBandTranslate(txSize);
|
||||
int dqShift = txSize == TxSize.Tx32X32 ? 1 : 0;
|
||||
@@ -56,26 +56,23 @@ 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..];
|
||||
ReadOnlySpan<byte> prob = coefProbs[band][ctx].AsSpan();
|
||||
ref Array3<byte> prob = ref coefProbs[band][ctx];
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++eobBranchSpan[band][ctx];
|
||||
++counts.EobBranch[(int)txSize][(int)type][refr][band][ctx];
|
||||
}
|
||||
|
||||
if (r.ReadBool(prob[EobContextNode], ref value, ref count, ref range) == 0)
|
||||
{
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++coefSpan[band][ctx][Constants.EobModelToken];
|
||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.EobModelToken];
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -85,7 +82,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++coefSpan[band][ctx][Constants.ZeroToken];
|
||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.ZeroToken];
|
||||
}
|
||||
|
||||
dqv = dq[1];
|
||||
@@ -102,7 +99,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ctx = GetCoefContext(nb, tokenCache, c);
|
||||
band = bandTranslate[0];
|
||||
bandTranslate = bandTranslate[1..];
|
||||
prob = coefProbs[band][ctx].AsSpan();
|
||||
prob = ref coefProbs[band][ctx];
|
||||
}
|
||||
|
||||
if (r.ReadBool(prob[OneContextNode], ref value, ref count, ref range) != 0)
|
||||
@@ -110,7 +107,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ReadOnlySpan<byte> p = Luts.Pareto8Full[prob[Constants.PivotNode] - 1];
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++coefSpan[band][ctx][Constants.TwoToken];
|
||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.TwoToken];
|
||||
}
|
||||
|
||||
if (r.ReadBool(p[0], ref value, ref count, ref range) != 0)
|
||||
@@ -178,7 +175,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
if (!xd.Counts.IsNull)
|
||||
{
|
||||
++coefSpan[band][ctx][Constants.OneToken];
|
||||
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.OneToken];
|
||||
}
|
||||
|
||||
tokenCache[scan[c]] = 1;
|
||||
@@ -235,7 +232,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];
|
||||
Span<short> dequant = pd.SegDequant[segId].AsSpan();
|
||||
ref Array2<short> dequant = ref pd.SegDequant[segId];
|
||||
int eob;
|
||||
Span<sbyte> a = pd.AboveContext.AsSpan()[x..];
|
||||
Span<sbyte> l = pd.LeftContext.AsSpan()[y..];
|
||||
@@ -253,7 +250,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
GetPlaneType(plane),
|
||||
pd.DqCoeff.AsSpan(),
|
||||
txSize,
|
||||
dequant,
|
||||
ref dequant,
|
||||
ctx,
|
||||
sc.Scan,
|
||||
sc.Neighbors,
|
||||
@@ -269,7 +266,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
GetPlaneType(plane),
|
||||
pd.DqCoeff.AsSpan(),
|
||||
txSize,
|
||||
dequant,
|
||||
ref dequant,
|
||||
ctx,
|
||||
sc.Scan,
|
||||
sc.Neighbors,
|
||||
@@ -286,7 +283,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
GetPlaneType(plane),
|
||||
pd.DqCoeff.AsSpan(),
|
||||
txSize,
|
||||
dequant,
|
||||
ref dequant,
|
||||
ctx,
|
||||
sc.Scan,
|
||||
sc.Neighbors,
|
||||
@@ -306,7 +303,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
GetPlaneType(plane),
|
||||
pd.DqCoeff.AsSpan(),
|
||||
txSize,
|
||||
dequant,
|
||||
ref dequant,
|
||||
ctx,
|
||||
sc.Scan,
|
||||
sc.Neighbors,
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
@@ -130,7 +129,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
byte* srcX = &src[xQ4 >> SubpelBits];
|
||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -165,7 +164,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
byte* srcX = &src[xQ4 >> SubpelBits];
|
||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -276,7 +275,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -311,7 +310,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -620,7 +619,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
ushort* srcX = &src[xQ4 >> SubpelBits];
|
||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -656,7 +655,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int x = 0; x < w; ++x)
|
||||
{
|
||||
ushort* srcX = &src[xQ4 >> SubpelBits];
|
||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
||||
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -693,7 +692,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
@@ -729,7 +728,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
||||
for (int y = 0; y < h; ++y)
|
||||
{
|
||||
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
||||
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||
int sum = 0;
|
||||
for (int k = 0; k < SubpelTaps; ++k)
|
||||
{
|
||||
|
@@ -304,40 +304,31 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
internal static void TxCountsToBranchCounts32X32(ReadOnlySpan<uint> txCount32X32P,
|
||||
ReadOnlySpan<Array2<uint>> ct32X32P)
|
||||
ref Array3<Array2<uint>> ct32X32P)
|
||||
{
|
||||
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] +
|
||||
ct32X32P[0][0] = txCount32X32P[(int)TxSize.Tx4X4];
|
||||
ct32X32P[0][1] = txCount32X32P[(int)TxSize.Tx8X8] + txCount32X32P[(int)TxSize.Tx16X16] +
|
||||
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];
|
||||
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];
|
||||
}
|
||||
|
||||
internal static void TxCountsToBranchCounts16X16(ReadOnlySpan<uint> txCount16X16P,
|
||||
ReadOnlySpan<Array2<uint>> ct16X16P)
|
||||
ref Array2<Array2<uint>> ct16X16P)
|
||||
{
|
||||
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];
|
||||
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];
|
||||
}
|
||||
|
||||
internal static void TxCountsToBranchCounts8X8(ReadOnlySpan<uint> txCount8X8P,
|
||||
ReadOnlySpan<Array2<uint>> ct8X8P)
|
||||
ref Array1<Array2<uint>> ct8X8P)
|
||||
{
|
||||
Span<uint> ct8X8PSpan = ct8X8P[0].AsSpan();
|
||||
|
||||
ct8X8PSpan[0] = txCount8X8P[(int)TxSize.Tx4X4];
|
||||
ct8X8PSpan[1] = txCount8X8P[(int)TxSize.Tx8X8];
|
||||
ct8X8P[0][0] = txCount8X8P[(int)TxSize.Tx4X4];
|
||||
ct8X8P[0][1] = txCount8X8P[(int)TxSize.Tx8X8];
|
||||
}
|
||||
|
||||
public static unsafe void SetupPastIndependence(ref Vp9Common cm)
|
||||
|
@@ -378,11 +378,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
int index = shiftY;
|
||||
|
||||
Span<byte> lflYSpan = lfm.LflY.AsSpan();
|
||||
|
||||
for (int i = 0; i < bh; i++)
|
||||
{
|
||||
MemoryMarshal.CreateSpan(ref lflYSpan[index], 64 - index)[..bw].Fill((byte)filterLevel);
|
||||
MemoryMarshal.CreateSpan(ref lfm.LflY[index], 64 - index)[..bw].Fill((byte)filterLevel);
|
||||
index += 8;
|
||||
}
|
||||
|
||||
@@ -446,30 +444,25 @@ 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.
|
||||
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];
|
||||
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];
|
||||
|
||||
// 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.
|
||||
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);
|
||||
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);
|
||||
|
||||
// We do some special edge handling.
|
||||
if (miRow + Constants.MiBlockSize > cm.MiRows)
|
||||
@@ -483,10 +476,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Remove values completely outside our border.
|
||||
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||
{
|
||||
leftYSpan[i] &= maskY;
|
||||
aboveYSpan[i] &= maskY;
|
||||
leftUvSpan[i] &= maskUv;
|
||||
aboveUvSpan[i] &= maskUv;
|
||||
lfm.LeftY[i] &= maskY;
|
||||
lfm.AboveY[i] &= maskY;
|
||||
lfm.LeftUv[i] &= maskUv;
|
||||
lfm.AboveUv[i] &= maskUv;
|
||||
}
|
||||
|
||||
lfm.Int4X4Y &= maskY;
|
||||
@@ -496,14 +489,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// apply the shorter one instead.
|
||||
if (rows == 1)
|
||||
{
|
||||
aboveUvSpan[(int)TxSize.Tx8X8] |= aboveUvSpan[(int)TxSize.Tx16X16];
|
||||
aboveUvSpan[(int)TxSize.Tx16X16] = 0;
|
||||
lfm.AboveUv[(int)TxSize.Tx8X8] |= lfm.AboveUv[(int)TxSize.Tx16X16];
|
||||
lfm.AboveUv[(int)TxSize.Tx16X16] = 0;
|
||||
}
|
||||
|
||||
if (rows == 5)
|
||||
{
|
||||
aboveUvSpan[(int)TxSize.Tx8X8] |= (ushort)(aboveUvSpan[(int)TxSize.Tx16X16] & 0xff00);
|
||||
aboveUvSpan[(int)TxSize.Tx16X16] &= (ushort)~(aboveUvSpan[(int)TxSize.Tx16X16] & 0xff00);
|
||||
lfm.AboveUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.AboveUv[(int)TxSize.Tx16X16] & 0xff00);
|
||||
lfm.AboveUv[(int)TxSize.Tx16X16] &= (ushort)~(lfm.AboveUv[(int)TxSize.Tx16X16] & 0xff00);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,10 +516,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Remove the bits outside the image edge.
|
||||
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||
{
|
||||
leftYSpan[i] &= maskY;
|
||||
aboveYSpan[i] &= maskY;
|
||||
leftUvSpan[i] &= maskUv;
|
||||
aboveUvSpan[i] &= maskUv;
|
||||
lfm.LeftY[i] &= maskY;
|
||||
lfm.AboveY[i] &= maskY;
|
||||
lfm.LeftUv[i] &= maskUv;
|
||||
lfm.AboveUv[i] &= maskUv;
|
||||
}
|
||||
|
||||
lfm.Int4X4Y &= maskY;
|
||||
@@ -536,14 +529,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// apply the shorter one instead.
|
||||
if (columns == 1)
|
||||
{
|
||||
leftUvSpan[(int)TxSize.Tx8X8] |= leftUvSpan[(int)TxSize.Tx16X16];
|
||||
leftUvSpan[(int)TxSize.Tx16X16] = 0;
|
||||
lfm.LeftUv[(int)TxSize.Tx8X8] |= lfm.LeftUv[(int)TxSize.Tx16X16];
|
||||
lfm.LeftUv[(int)TxSize.Tx16X16] = 0;
|
||||
}
|
||||
|
||||
if (columns == 5)
|
||||
{
|
||||
leftUvSpan[(int)TxSize.Tx8X8] |= (ushort)(leftUvSpan[(int)TxSize.Tx16X16] & 0xcccc);
|
||||
leftUvSpan[(int)TxSize.Tx16X16] &= (ushort)~(leftUvSpan[(int)TxSize.Tx16X16] & 0xcccc);
|
||||
lfm.LeftUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.LeftUv[(int)TxSize.Tx16X16] & 0xcccc);
|
||||
lfm.LeftUv[(int)TxSize.Tx16X16] &= (ushort)~(lfm.LeftUv[(int)TxSize.Tx16X16] & 0xcccc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,28 +546,28 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||
{
|
||||
leftYSpan[i] &= 0xfefefefefefefefeUL;
|
||||
leftUvSpan[i] &= 0xeeee;
|
||||
lfm.LeftY[i] &= 0xfefefefefefefefeUL;
|
||||
lfm.LeftUv[i] &= 0xeeee;
|
||||
}
|
||||
}
|
||||
|
||||
// Assert if we try to apply 2 different loop filters at the same position.
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
public static unsafe void ResetLfm(ref Vp9Common cm)
|
||||
@@ -590,8 +583,6 @@ 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++)
|
||||
{
|
||||
@@ -611,8 +602,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
blockInsideLimit = 1;
|
||||
}
|
||||
|
||||
lFThrSpan[lvl].Lim.AsSpan().Fill((byte)blockInsideLimit);
|
||||
lFThrSpan[lvl].Mblim.AsSpan().Fill((byte)((2 * (lvl + 2)) + blockInsideLimit));
|
||||
lfi.Lfthr[lvl].Lim.AsSpan().Fill((byte)blockInsideLimit);
|
||||
lfi.Lfthr[lvl].Mblim.AsSpan().Fill((byte)((2 * (lvl + 2)) + blockInsideLimit));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,11 +625,6 @@ 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;
|
||||
@@ -653,24 +639,20 @@ 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>(lvlSpan[segId].AsSpan()).Fill((byte)lvlSeg);
|
||||
MemoryMarshal.Cast<Array2<byte>, byte>(lfi.Lvl[segId].AsSpan()).Fill((byte)lvlSeg);
|
||||
}
|
||||
else
|
||||
{
|
||||
int refr, mode;
|
||||
int intraLvl = lvlSeg + (intraFrameRefDelta * scale);
|
||||
lvlSpan[segId][Constants.IntraFrame][0] = (byte)Math.Clamp(intraLvl, 0, MaxLoopFilter);
|
||||
|
||||
Span<Array2<byte>> lvlSpan2 = lvlSpan[segId].AsSpan();
|
||||
int intraLvl = lvlSeg + (lf.RefDeltas[Constants.IntraFrame] * scale);
|
||||
lfi.Lvl[segId][Constants.IntraFrame][0] = (byte)Math.Clamp(intraLvl, 0, MaxLoopFilter);
|
||||
|
||||
for (refr = Constants.LastFrame; refr < Constants.MaxRefFrames; ++refr)
|
||||
{
|
||||
Span<byte> lvlSpan3 = lvlSpan2[refr].AsSpan();
|
||||
|
||||
for (mode = 0; mode < MaxModeLfDeltas; ++mode)
|
||||
{
|
||||
int interLvl = lvlSeg + (refDeltasSpan[refr] * scale) + (modeDeltasSpan[mode] * scale);
|
||||
lvlSpan3[mode] = (byte)Math.Clamp(interLvl, 0, MaxLoopFilter);
|
||||
int interLvl = lvlSeg + (lf.RefDeltas[refr] * scale) + (lf.ModeDeltas[mode] * scale);
|
||||
lfi.Lvl[segId][refr][mode] = (byte)Math.Clamp(interLvl, 0, MaxLoopFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -829,32 +811,18 @@ 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, mblim0Span[0], lim0Span[0],
|
||||
hevThr0Span[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical16Dual(ss[0], pitch, lfis[0].Mblim[0], lfis[0].Lim[0],
|
||||
lfis[0].HevThr[0], bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -865,26 +833,24 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfVertical8Dual(
|
||||
ss[0],
|
||||
pitch,
|
||||
mblim0Span[0],
|
||||
lim0Span[0],
|
||||
hevThr0Span[0],
|
||||
mblim1Span[0],
|
||||
lim1Span[0],
|
||||
hevThr1Span[0],
|
||||
lfis[0].Mblim[0],
|
||||
lfis[0].Lim[0],
|
||||
lfis[0].HevThr[0],
|
||||
lfis[1].Mblim[0],
|
||||
lfis[1].Lim[0],
|
||||
lfis[1].HevThr[0],
|
||||
bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -895,26 +861,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfVertical4Dual(
|
||||
ss[0],
|
||||
pitch,
|
||||
mblim0Span[0],
|
||||
lim0Span[0],
|
||||
hevThr0Span[0],
|
||||
mblim1Span[0],
|
||||
lim1Span[0],
|
||||
hevThr1Span[0],
|
||||
lfis[0].Mblim[0],
|
||||
lfis[0].Lim[0],
|
||||
lfis[0].HevThr[0],
|
||||
lfis[1].Mblim[0],
|
||||
lfis[1].Lim[0],
|
||||
lfis[1].HevThr[0],
|
||||
bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -925,26 +884,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfVertical4Dual(
|
||||
ss[0].Slice(4),
|
||||
pitch,
|
||||
mblim0Span[0],
|
||||
lim0Span[0],
|
||||
hevThr0Span[0],
|
||||
mblim1Span[0],
|
||||
lim1Span[0],
|
||||
hevThr1Span[0],
|
||||
lfis[0].Mblim[0],
|
||||
lfis[0].Lim[0],
|
||||
lfis[0].HevThr[0],
|
||||
lfis[1].Mblim[0],
|
||||
lfis[1].Lim[0],
|
||||
lfis[1].HevThr[0],
|
||||
bd);
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1134,22 +1086,18 @@ 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, mblimSpan[0], limSpan[0],
|
||||
hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal16Dual(s, pitch, lfi.Mblim[0], lfi.Lim[0],
|
||||
lfi.HevThr[0], bd);
|
||||
count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal16(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||
LoopFilterScalar.HighBdLpfHorizontal16(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
||||
bd);
|
||||
}
|
||||
}
|
||||
@@ -1159,20 +1107,16 @@ 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,
|
||||
mblimSpan[0],
|
||||
limSpan[0],
|
||||
hevThrSpan[0],
|
||||
nMblimSpan[0],
|
||||
nLimSpan[0],
|
||||
nHevThrSpan[0],
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
lfin.Mblim[0],
|
||||
lfin.Lim[0],
|
||||
lfin.HevThr[0],
|
||||
bd);
|
||||
|
||||
if ((mask4X4Int & 3) == 3)
|
||||
@@ -1180,36 +1124,36 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||
s.Slice(4 * pitch),
|
||||
pitch,
|
||||
mblimSpan[0],
|
||||
limSpan[0],
|
||||
hevThrSpan[0],
|
||||
nMblimSpan[0],
|
||||
nLimSpan[0],
|
||||
nHevThrSpan[0],
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
lfin.Mblim[0],
|
||||
lfin.Lim[0],
|
||||
lfin.HevThr[0],
|
||||
bd);
|
||||
}
|
||||
else if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||
limSpan[0], hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
}
|
||||
else if ((mask4X4Int & 2) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, nMblimSpan[0],
|
||||
nLimSpan[0], nHevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, lfin.Mblim[0],
|
||||
lfin.Lim[0], lfin.HevThr[0], bd);
|
||||
}
|
||||
|
||||
count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal8(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||
LoopFilterScalar.HighBdLpfHorizontal8(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
||||
bd);
|
||||
|
||||
if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||
limSpan[0], hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1219,20 +1163,16 @@ 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,
|
||||
mblimSpan[0],
|
||||
limSpan[0],
|
||||
hevThrSpan[0],
|
||||
nMblimSpan[0],
|
||||
nLimSpan[0],
|
||||
nHevThrSpan[0],
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
lfin.Mblim[0],
|
||||
lfin.Lim[0],
|
||||
lfin.HevThr[0],
|
||||
bd);
|
||||
|
||||
if ((mask4X4Int & 3) == 3)
|
||||
@@ -1240,43 +1180,43 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||
s.Slice(4 * pitch),
|
||||
pitch,
|
||||
mblimSpan[0],
|
||||
limSpan[0],
|
||||
hevThrSpan[0],
|
||||
nMblimSpan[0],
|
||||
nLimSpan[0],
|
||||
nHevThrSpan[0],
|
||||
lfi.Mblim[0],
|
||||
lfi.Lim[0],
|
||||
lfi.HevThr[0],
|
||||
lfin.Mblim[0],
|
||||
lfin.Lim[0],
|
||||
lfin.HevThr[0],
|
||||
bd);
|
||||
}
|
||||
else if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||
limSpan[0], hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
}
|
||||
else if ((mask4X4Int & 2) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, nMblimSpan[0],
|
||||
nLimSpan[0], nHevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, lfin.Mblim[0],
|
||||
lfin.Lim[0], lfin.HevThr[0], bd);
|
||||
}
|
||||
|
||||
count = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0],
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0],
|
||||
bd);
|
||||
|
||||
if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
||||
limSpan[0], hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0], limSpan[0],
|
||||
hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0], lfi.Lim[0],
|
||||
lfi.HevThr[0], bd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1351,30 +1291,26 @@ 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, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical16(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
}
|
||||
else if ((mask8X8 & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical8(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical8(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
}
|
||||
else if ((mask4X4 & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical4(s, pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical4(s, pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mask4X4Int & 1) != 0)
|
||||
{
|
||||
LoopFilterScalar.HighBdLpfVertical4(s.Slice(4), pitch, mblimSpan[0], limSpan[0], hevThrSpan[0], bd);
|
||||
LoopFilterScalar.HighBdLpfVertical4(s.Slice(4), pitch, lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||
}
|
||||
|
||||
s = s.Slice(8);
|
||||
@@ -1619,10 +1555,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
ref Buf2D dst = ref plane.Dst;
|
||||
ArrayPtr<byte> dst0 = dst.Buf;
|
||||
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 mask16X16 = lfm.LeftY[(int)TxSize.Tx16X16];
|
||||
ulong mask8X8 = lfm.LeftY[(int)TxSize.Tx8X8];
|
||||
ulong mask4X4 = lfm.LeftY[(int)TxSize.Tx4X4];
|
||||
ulong mask4X4Int = lfm.Int4X4Y;
|
||||
|
||||
Debug.Assert(plane.SubsamplingX == 0 && plane.SubsamplingY == 0);
|
||||
@@ -1669,10 +1604,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
// Horizontal pass
|
||||
dst.Buf = dst0;
|
||||
Span<ulong> aboveYSpan = lfm.AboveY.AsSpan();
|
||||
mask16X16 = aboveYSpan[(int)TxSize.Tx16X16];
|
||||
mask8X8 = aboveYSpan[(int)TxSize.Tx8X8];
|
||||
mask4X4 = aboveYSpan[(int)TxSize.Tx4X4];
|
||||
mask16X16 = lfm.AboveY[(int)TxSize.Tx16X16];
|
||||
mask8X8 = lfm.AboveY[(int)TxSize.Tx8X8];
|
||||
mask4X4 = lfm.AboveY[(int)TxSize.Tx4X4];
|
||||
mask4X4Int = lfm.Int4X4Y;
|
||||
|
||||
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r++)
|
||||
@@ -1735,12 +1669,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
ArrayPtr<byte> dst0 = dst.Buf;
|
||||
|
||||
Span<byte> lflUv = stackalloc byte[16];
|
||||
Span<byte> lflY = lfm.LflY.AsSpan();
|
||||
|
||||
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 mask16X16 = lfm.LeftUv[(int)TxSize.Tx16X16];
|
||||
ushort mask8X8 = lfm.LeftUv[(int)TxSize.Tx8X8];
|
||||
ushort mask4X4 = lfm.LeftUv[(int)TxSize.Tx4X4];
|
||||
ushort mask4X4Int = lfm.Int4X4Uv;
|
||||
|
||||
Debug.Assert(plane.SubsamplingX == 1 && plane.SubsamplingY == 1);
|
||||
@@ -1750,8 +1682,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
{
|
||||
for (int c = 0; c < Constants.MiBlockSize >> 1; c++)
|
||||
{
|
||||
lflUv[(r << 1) + c] = lflY[(r << 3) + (c << 1)];
|
||||
lflUv[((r + 2) << 1) + c] = lflY[((r + 2) << 3) + (c << 1)];
|
||||
lflUv[(r << 1) + c] = lfm.LflY[(r << 3) + (c << 1)];
|
||||
lflUv[((r + 2) << 1) + c] = lfm.LflY[((r + 2) << 3) + (c << 1)];
|
||||
}
|
||||
|
||||
if (cm.UseHighBitDepth)
|
||||
@@ -1793,10 +1725,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
// Horizontal pass
|
||||
dst.Buf = dst0;
|
||||
Span<ushort> aboveUvSpan = lfm.AboveUv.AsSpan();
|
||||
mask16X16 = aboveUvSpan[(int)TxSize.Tx16X16];
|
||||
mask8X8 = aboveUvSpan[(int)TxSize.Tx8X8];
|
||||
mask4X4 = aboveUvSpan[(int)TxSize.Tx4X4];
|
||||
mask16X16 = lfm.AboveUv[(int)TxSize.Tx16X16];
|
||||
mask8X8 = lfm.AboveUv[(int)TxSize.Tx8X8];
|
||||
mask4X4 = lfm.AboveUv[(int)TxSize.Tx4X4];
|
||||
mask4X4Int = lfm.Int4X4Uv;
|
||||
|
||||
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r += 2)
|
||||
@@ -1875,17 +1806,16 @@ 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 (planesSpan[1].SubsamplingY == 1 && planesSpan[1].SubsamplingX == 1)
|
||||
else if (planes[1].SubsamplingY == 1 && planes[1].SubsamplingX == 1)
|
||||
{
|
||||
path = LfPath.LfPath420;
|
||||
}
|
||||
else if (planesSpan[1].SubsamplingY == 0 && planesSpan[1].SubsamplingX == 0)
|
||||
else if (planes[1].SubsamplingY == 0 && planes[1].SubsamplingX == 0)
|
||||
{
|
||||
path = LfPath.LfPath444;
|
||||
}
|
||||
@@ -1907,23 +1837,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
|
||||
lfSync.SyncRead(r, c);
|
||||
|
||||
ReconInter.SetupDstPlanes(planesSpan, ref frameBuffer, miRow, miCol);
|
||||
ReconInter.SetupDstPlanes(ref planes, ref frameBuffer, miRow, miCol);
|
||||
|
||||
AdjustMask(ref cm, miRow, miCol, ref lfm[0]);
|
||||
|
||||
FilterBlockPlaneSs00(ref cm, ref planesSpan[0], miRow, ref lfm[0]);
|
||||
FilterBlockPlaneSs00(ref cm, ref planes[0], miRow, ref lfm[0]);
|
||||
for (plane = 1; plane < numPlanes; ++plane)
|
||||
{
|
||||
switch (path)
|
||||
{
|
||||
case LfPath.LfPath420:
|
||||
FilterBlockPlaneSs11(ref cm, ref planesSpan[plane], miRow, ref lfm[0]);
|
||||
FilterBlockPlaneSs11(ref cm, ref planes[plane], miRow, ref lfm[0]);
|
||||
break;
|
||||
case LfPath.LfPath444:
|
||||
FilterBlockPlaneSs00(ref cm, ref planesSpan[plane], miRow, ref lfm[0]);
|
||||
FilterBlockPlaneSs00(ref cm, ref planes[plane], miRow, ref lfm[0]);
|
||||
break;
|
||||
case LfPath.LfPathSlow:
|
||||
FilterBlockPlaneNon420(ref cm, ref planesSpan[plane], mi.Slice(miCol), miRow,
|
||||
FilterBlockPlaneNon420(ref cm, ref planes[plane], mi.Slice(miCol), miRow,
|
||||
miCol);
|
||||
break;
|
||||
}
|
||||
|
@@ -270,16 +270,17 @@ 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();
|
||||
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;
|
||||
Array8<short> output = new()
|
||||
{
|
||||
[0] = e0,
|
||||
[1] = e1,
|
||||
[2] = e2,
|
||||
[3] = e3,
|
||||
[4] = e4,
|
||||
[5] = e5,
|
||||
[6] = e6,
|
||||
[7] = e7
|
||||
};
|
||||
|
||||
return output;
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
@@ -110,17 +109,15 @@ 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];
|
||||
|
||||
Span<sbyte> compVarRefSpan = cm.CompVarRef.AsSpan();
|
||||
|
||||
if (vrfa == vrfl && compVarRefSpan[1] == vrfa)
|
||||
if (vrfa == vrfl && cm.CompVarRef[1] == vrfa)
|
||||
{
|
||||
predContext = 0;
|
||||
}
|
||||
else if (lSg && aSg)
|
||||
{
|
||||
// Single/Single
|
||||
if ((vrfa == cm.CompFixedRef && vrfl == compVarRefSpan[0]) ||
|
||||
(vrfl == cm.CompFixedRef && vrfa == compVarRefSpan[0]))
|
||||
if ((vrfa == cm.CompFixedRef && vrfl == cm.CompVarRef[0]) ||
|
||||
(vrfl == cm.CompFixedRef && vrfa == cm.CompVarRef[0]))
|
||||
{
|
||||
predContext = 4;
|
||||
}
|
||||
@@ -138,11 +135,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Single/Comp
|
||||
sbyte vrfc = lSg ? vrfa : vrfl;
|
||||
sbyte rfs = aSg ? vrfa : vrfl;
|
||||
if (vrfc == compVarRefSpan[1] && rfs != compVarRefSpan[1])
|
||||
if (vrfc == cm.CompVarRef[1] && rfs != cm.CompVarRef[1])
|
||||
{
|
||||
predContext = 1;
|
||||
}
|
||||
else if (rfs == compVarRefSpan[1] && vrfc != compVarRefSpan[1])
|
||||
else if (rfs == cm.CompVarRef[1] && vrfc != cm.CompVarRef[1])
|
||||
{
|
||||
predContext = 2;
|
||||
}
|
||||
@@ -215,15 +212,14 @@ 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 * (refFrameSpan[0] == Constants.LastFrame ? 1 : 0);
|
||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.LastFrame ? 1 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 1 + (refFrameSpan[0] == Constants.LastFrame ||
|
||||
refFrameSpan[1] == Constants.LastFrame
|
||||
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
|
||||
edgeMi.RefFrame[1] == Constants.LastFrame
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
@@ -233,12 +229,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Inter/Inter
|
||||
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
||||
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
||||
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];
|
||||
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];
|
||||
|
||||
if (aboveHasSecond && leftHasSecond)
|
||||
{
|
||||
@@ -287,10 +281,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
else
|
||||
{
|
||||
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
||||
|
||||
predContext = 1 + (refFrameSpan[0] == Constants.LastFrame ||
|
||||
refFrameSpan[1] == Constants.LastFrame
|
||||
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
|
||||
edgeMi.RefFrame[1] == Constants.LastFrame
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
@@ -329,22 +321,21 @@ 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 (refFrameSpan[0] == Constants.LastFrame)
|
||||
if (edgeMi.RefFrame[0] == Constants.LastFrame)
|
||||
{
|
||||
predContext = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 4 * (refFrameSpan[0] == Constants.GoldenFrame ? 1 : 0);
|
||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 1 + (2 * (refFrameSpan[0] == Constants.GoldenFrame ||
|
||||
refFrameSpan[1] == Constants.GoldenFrame
|
||||
predContext = 1 + (2 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
|
||||
edgeMi.RefFrame[1] == Constants.GoldenFrame
|
||||
? 1
|
||||
: 0));
|
||||
}
|
||||
@@ -354,12 +345,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
// Inter/Inter
|
||||
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
||||
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
||||
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];
|
||||
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];
|
||||
|
||||
if (aboveHasSecond && leftHasSecond)
|
||||
{
|
||||
@@ -418,20 +407,19 @@ 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() || (refFrameSpan[0] == Constants.LastFrame && !edgeMi.HasSecondRef()))
|
||||
if (!edgeMi.IsInterBlock() || (edgeMi.RefFrame[0] == Constants.LastFrame && !edgeMi.HasSecondRef()))
|
||||
{
|
||||
predContext = 2;
|
||||
}
|
||||
else if (!edgeMi.HasSecondRef())
|
||||
{
|
||||
predContext = 4 * (refFrameSpan[0] == Constants.GoldenFrame ? 1 : 0);
|
||||
predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
predContext = 3 * (refFrameSpan[0] == Constants.GoldenFrame ||
|
||||
refFrameSpan[1] == Constants.GoldenFrame
|
||||
predContext = 3 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
|
||||
edgeMi.RefFrame[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, ReadOnlySpan<uint> ct, uint countSat, uint maxUpdateFactor)
|
||||
public static byte MergeProbs(byte preProb, ref Array2<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, ReadOnlySpan<uint> ct)
|
||||
public static byte ModeMvMergeProbs(byte preProb, ref Array2<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)], ct.AsSpan());
|
||||
probs[(int)(i >> 1)] = ModeMvMergeProbs(preProbs[(int)(i >> 1)], ref ct);
|
||||
return leftCount + rightCount;
|
||||
}
|
||||
|
||||
|
@@ -164,7 +164,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
||||
}
|
||||
|
||||
public static void SetupDstPlanes(
|
||||
Span<MacroBlockDPlane> planes,
|
||||
ref Array3<MacroBlockDPlane> planes,
|
||||
ref Surface src,
|
||||
int miRow,
|
||||
int miCol)
|
||||
@@ -205,11 +205,9 @@ 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 planeSpan[i];
|
||||
ref MacroBlockDPlane pd = ref xd.Plane[i];
|
||||
SetupPredPlanes(ref pd.Pre[idx], buffers[i], strides[i], miRow, miCol, sf, pd.SubsamplingX,
|
||||
pd.SubsamplingY);
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
@@ -29,16 +28,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
ModeRefDeltaEnabled = true;
|
||||
ModeRefDeltaUpdate = true;
|
||||
|
||||
Span<sbyte> refDeltasSpan = RefDeltas.AsSpan();
|
||||
Span<sbyte> modeDeltasSpan = ModeDeltas.AsSpan();
|
||||
|
||||
refDeltasSpan[Constants.IntraFrame] = 1;
|
||||
refDeltasSpan[Constants.LastFrame] = 0;
|
||||
refDeltasSpan[Constants.GoldenFrame] = -1;
|
||||
refDeltasSpan[Constants.AltRefFrame] = -1;
|
||||
modeDeltasSpan[0] = 0;
|
||||
modeDeltasSpan[1] = 0;
|
||||
RefDeltas[Constants.IntraFrame] = 1;
|
||||
RefDeltas[Constants.LastFrame] = 0;
|
||||
RefDeltas[Constants.GoldenFrame] = -1;
|
||||
RefDeltas[Constants.AltRefFrame] = -1;
|
||||
ModeDeltas[0] = 0;
|
||||
ModeDeltas[1] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,6 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||
{
|
||||
@@ -148,12 +147,10 @@ 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++)
|
||||
{
|
||||
planeSpan[i].SubsamplingX = i != 0 ? ssX : 0;
|
||||
planeSpan[i].SubsamplingY = i != 0 ? ssY : 0;
|
||||
Plane[i].SubsamplingX = i != 0 ? ssX : 0;
|
||||
Plane[i].SubsamplingY = i != 0 ? ssY : 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,16 +158,12 @@ 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 planeSpan[i];
|
||||
pd.AboveContext = aboveContextSpan[i].Slice(aboveIdx >> pd.SubsamplingX);
|
||||
pd.LeftContext = new ArrayPtr<sbyte>(ref leftContextSpan[i][leftIdx >> pd.SubsamplingY],
|
||||
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],
|
||||
16 - (leftIdx >> pd.SubsamplingY));
|
||||
}
|
||||
}
|
||||
@@ -189,11 +182,9 @@ 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 planeSpan[i];
|
||||
ref MacroBlockDPlane pd = ref Plane[i];
|
||||
MemoryUtil.Fill(pd.AboveContext.ToPointer(), (sbyte)0, pd.N4W);
|
||||
MemoryUtil.Fill(pd.LeftContext.ToPointer(), (sbyte)0, pd.N4H);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user