mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-09-13 05:25:06 +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 |
116
.github/workflows/canary.yml
vendored
116
.github/workflows/canary.yml
vendored
@@ -24,6 +24,54 @@ env:
|
|||||||
RELEASE: 1
|
RELEASE: 1
|
||||||
|
|
||||||
jobs:
|
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:
|
release:
|
||||||
name: Release for ${{ matrix.platform.name }}
|
name: Release for ${{ matrix.platform.name }}
|
||||||
runs-on: ${{ matrix.platform.os }}
|
runs-on: ${{ matrix.platform.os }}
|
||||||
@@ -44,6 +92,16 @@ jobs:
|
|||||||
- name: Overwrite csc problem matcher
|
- name: Overwrite csc problem matcher
|
||||||
run: echo "::add-matcher::.github/csc.json"
|
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
|
- name: Get version info
|
||||||
id: version_info
|
id: version_info
|
||||||
run: |
|
run: |
|
||||||
@@ -146,6 +204,33 @@ 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.zsync"
|
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:
|
macos_release:
|
||||||
name: Release MacOS universal
|
name: Release MacOS universal
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
@@ -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
|
./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"
|
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:
|
create_gitlab_release:
|
||||||
name: Create GitLab Release
|
name: Create GitLab Release
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
|
- tag
|
||||||
- macos_release
|
- macos_release
|
||||||
- release
|
- release
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Get version info
|
- name: Get version info
|
||||||
id: version_info
|
id: version_info
|
||||||
run: |
|
run: |
|
||||||
@@ -232,18 +330,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Create release
|
||||||
run: |
|
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 }})"
|
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 }})**"
|
||||||
|
|
||||||
- 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 }}'
|
|
||||||
|
81
.github/workflows/release.yml
vendored
81
.github/workflows/release.yml
vendored
@@ -14,6 +14,38 @@ env:
|
|||||||
RELEASE: 1
|
RELEASE: 1
|
||||||
|
|
||||||
jobs:
|
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:
|
release:
|
||||||
name: Release for ${{ matrix.platform.name }}
|
name: Release for ${{ matrix.platform.name }}
|
||||||
runs-on: ${{ matrix.platform.os }}
|
runs-on: ${{ matrix.platform.os }}
|
||||||
@@ -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"
|
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
|
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:
|
macos_release:
|
||||||
name: Release MacOS universal
|
name: Release MacOS universal
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
@@ -194,10 +250,25 @@ jobs:
|
|||||||
./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
|
./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"
|
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:
|
create_gitlab_release:
|
||||||
name: Create GitLab Release
|
name: Create GitLab Release
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
|
- tag
|
||||||
- macos_release
|
- macos_release
|
||||||
- release
|
- release
|
||||||
steps:
|
steps:
|
||||||
@@ -223,12 +294,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
run: |
|
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 }}"
|
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 }})**"
|
||||||
|
|
||||||
- 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 }}'
|
|
||||||
|
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
|
47
CHANGELOG.md
47
CHANGELOG.md
@@ -2,17 +2,20 @@
|
|||||||
|
|
||||||
All updates to this Ryujinx branch will be documented in this file.
|
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
|
## [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
|
## [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
|
## [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
|
## [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
|
## [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
|
## [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.
|
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.76 fixes a rare crash on startup.
|
||||||
|
|
||||||
## [1.2.72](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.72>) - 2024-11-03
|
## [1.2.72](<https://github.com/GreemDev/Ryujinx/releases/tag/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>)
|
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:
|
### HLE:
|
||||||
- Add DebugMouse HID device.
|
- Add DebugMouse HID device.
|
||||||
- Fixes "Clock Tower Rewind" crashing while loading.
|
- Fixes "Clock Tower Rewind" crashing while loading.
|
||||||
@@ -32,7 +35,7 @@ PRs [#163](<https://web.archive.org/web/20241123015123/https://github.com/GreemD
|
|||||||
### misc:
|
### misc:
|
||||||
- Update macOS distribution .icns.
|
- 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:
|
### Infra:
|
||||||
- Compile the native libraries into the Ryujinx executable.
|
- Compile the native libraries into the Ryujinx executable.
|
||||||
- Remove `libarmeilleure-jitsupport.dylib` from Windows & Linux releases (dylibs are macOS-only)
|
- 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`.
|
- Replace "" with `string.Empty`.
|
||||||
- Code cleanups & simplifications.
|
- Code cleanups & simplifications.
|
||||||
|
|
||||||
## [1.2.67](<https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.67>) - 2024-11-01
|
## [1.2.67](<https://github.com/GreemDev/Ryujinx/releases/tag/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>)
|
PRs [#36](<https://github.com/GreemDev/Ryujinx/pull/36>), [#135](<https://github.com/GreemDev/Ryujinx/pull/135>)
|
||||||
|
|
||||||
### GUI:
|
### GUI:
|
||||||
- Set UseFloatingWatermark to false when watermark is empty
|
- 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.
|
- Fix homebrew loading.
|
||||||
|
|
||||||
|
|
||||||
## [1.2.64](https://git.ryujinx.app/ryubing/ryujinx/-/tags/1.2.64) - 2024-10-30
|
## [1.2.64](https://github.com/GreemDev/Ryujinx/releases/tag/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)~~
|
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:
|
### GUI:
|
||||||
- Option to show classic-style title bar. Requires restart of emulator to take effect.
|
- 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.
|
- 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
|
## 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:
|
### i18n:
|
||||||
- fr_FR:
|
- fr_FR:
|
||||||
- Add missing translations for new features & fix a couple wrong ones.
|
- Add missing translations for new features & fix a couple wrong ones.
|
||||||
- Fix Ignore Missing Services / Ignore Applet tooltip.
|
- Fix Ignore Missing Services / Ignore Applet tooltip.
|
||||||
|
|
||||||
## 1.2.57 - 2024-10-27
|
## 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:
|
### GUI:
|
||||||
- Automatically remove invalid DLC & updates as part of autoload.
|
- Automatically remove invalid DLC & updates as part of autoload.
|
||||||
- Added Thai translation for Ignore Applet hover tooltip.
|
- 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.
|
- Code cleanup.
|
||||||
|
|
||||||
## 1.2.44 - 2024-10-25
|
## 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:
|
### GUI:
|
||||||
- Add descriptions for "ignoring applet" translated into other languages.
|
- 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
|
## 1.2.42 - 2024-10-24
|
||||||
Sources:
|
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
|
Thanks MutantAura :D
|
||||||
### GUI:
|
### GUI:
|
||||||
@@ -127,14 +130,14 @@ Thanks MutantAura :D
|
|||||||
- Remove graphics backend / GPU name event logic in favor of a single init function.
|
- Remove graphics backend / GPU name event logic in favor of a single init function.
|
||||||
|
|
||||||
## 1.2.41 - 2024-10-24
|
## 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!
|
Thanks Whitescatz!
|
||||||
### i18n:
|
### i18n:
|
||||||
- th_TH (Thai): Added missing translations, reduce transliterated words, fix grammar.
|
- th_TH (Thai): Added missing translations, reduce transliterated words, fix grammar.
|
||||||
|
|
||||||
## 1.2.40 - 2024-10-23
|
## 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 Вова С!
|
Thanks Вова С!
|
||||||
### GUI:
|
### GUI:
|
||||||
@@ -148,30 +151,30 @@ Thanks Вова С!
|
|||||||
- Should prevent crashing on config loads in some circumstances.
|
- Should prevent crashing on config loads in some circumstances.
|
||||||
|
|
||||||
## 1.2.38 - 2024-10-23
|
## 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:
|
### i18n:
|
||||||
- zh_CH (Simplified Chinese): Add some missing translations.
|
- zh_CH (Simplified Chinese): Add some missing translations.
|
||||||
|
|
||||||
## 1.2.37 - 2024-10-23
|
## 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!
|
Thanks Last Breath!
|
||||||
### GUI:
|
### GUI:
|
||||||
- Set the default controller to the Pro Controller.
|
- Set the default controller to the Pro Controller.
|
||||||
|
|
||||||
## 1.2.36 - 2024-10-21
|
## 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:
|
### 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.
|
- 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
|
## 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:
|
### GUI:
|
||||||
- Replace "expand DRAM" option with a DRAM size dropdown.
|
- Replace "expand DRAM" option with a DRAM size dropdown.
|
||||||
- Allows for using mods which require a ridiculous amount of memory to allocate from.
|
- Allows for using mods which require a ridiculous amount of memory to allocate from.
|
||||||
|
|
||||||
## 1.2.34 - 2024-10-21
|
## 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:
|
### GUI:
|
||||||
- Fix duplicate controller names when 2 controllers of the same type are connected.
|
- Fix duplicate controller names when 2 controllers of the same type are connected.
|
||||||
### INPUT:
|
### 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
|
## 1.2.1-1.2.19 - 2024-10-08 - 2024-10-11
|
||||||
### GUI/INFRA/MISC:
|
### GUI/INFRA/MISC:
|
||||||
- Remove GTK UI.
|
- 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.
|
- Changed executable icon to rainbow logo.
|
||||||
- Extract Data > Logo now also extracts the square thumbnail you see for the game in the UI.
|
- 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="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
||||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||||
<PackageVersion Include="DiscordRichPresence" Version="1.6.1.70" />
|
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||||
<PackageVersion Include="DynamicData" Version="9.4.1" />
|
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
||||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||||
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
<PackageVersion Include="Humanizer" Version="2.14.1" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<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.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" />
|
<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.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.SDL2-CS" Version="2.30.0-build32" />
|
||||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
|
<PackageVersion Include="Gommon" Version="2.7.1.1" />
|
||||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.44" />
|
|
||||||
<PackageVersion Include="Gommon" Version="2.7.2.1" />
|
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="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="shaderc.net" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||||
|
12
README.md
12
README.md
@@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
# Ryujinx
|
# Ryujinx
|
||||||
|
|
||||||
[](https://update.ryujinx.app/latest/stable)
|
[](https://github.com/Ryubing/Stable-Releases/releases/latest)
|
||||||
[](https://update.ryujinx.app/latest/canary)
|
[](https://github.com/Ryubing/Canary-Releases/releases/latest)
|
||||||
<br>
|
<br>
|
||||||
<a href="https://discord.gg/PEuzjrFXUA">
|
<a href="https://discord.gg/PEuzjrFXUA">
|
||||||
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryubing&logo=discord&logoColor=white" alt="Discord">
|
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryubing&logo=discord&logoColor=white" alt="Discord">
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
<br>
|
<br>
|
||||||
This is not a Ryujinx revival project. This is not a Phoenix project.
|
This is not a Ryujinx revival project. This is not a Phoenix project.
|
||||||
<br>
|
<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>
|
||||||
|
|
||||||
<p align="center">
|
<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**.
|
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.
|
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.
|
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**.
|
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.
|
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
|
## Documentation
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY
|
|||||||
|
|
||||||
## Credits
|
## 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.
|
- [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.
|
- [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
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
||||||
EndProject
|
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}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
.editorconfig = .editorconfig
|
.editorconfig = .editorconfig
|
||||||
@@ -86,9 +84,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||||||
.github\workflows\canary.yml = .github\workflows\canary.yml
|
.github\workflows\canary.yml = .github\workflows\canary.yml
|
||||||
Directory.Packages.props = Directory.Packages.props
|
Directory.Packages.props = Directory.Packages.props
|
||||||
.github\workflows\release.yml = .github\workflows\release.yml
|
.github\workflows\release.yml = .github\workflows\release.yml
|
||||||
nuget.config = nuget.config
|
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
7351
assets/locales.json
7351
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"
|
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" \
|
-u "$UFLAG" \
|
||||||
AppDir "$OUTDIR"/Ryujinx.AppImage
|
AppDir "$OUTDIR"/Ryujinx.AppImage
|
||||||
|
|
||||||
|
@@ -33,29 +33,23 @@ echo -n "APPL????" > "$APP_BUNDLE_DIRECTORY/Contents/PkgInfo"
|
|||||||
echo "Running bundle fix up python script"
|
echo "Running bundle fix up python script"
|
||||||
python3 bundle_fix_up.py "$APP_BUNDLE_DIRECTORY" MacOS/Ryujinx
|
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
|
# Now sign it
|
||||||
echo "Starting signing process"
|
echo "Starting signing process"
|
||||||
if ! [ -x "$(command -v codesign)" ];
|
if ! [ -x "$(command -v codesign)" ];
|
||||||
then
|
then
|
||||||
if ! [ -x "$(command -v rcodesign)" ];
|
if ! [ -x "$(command -v rcodesign)" ];
|
||||||
then
|
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
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# cargo install apple-codesign
|
||||||
echo "Using rcodesign for ad-hoc signing"
|
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"
|
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
||||||
else
|
else
|
||||||
echo "Using codesign for ad-hoc signing"
|
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"
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$APP_BUNDLE_DIRECTORY"
|
||||||
fi
|
fi
|
||||||
|
@@ -20,18 +20,6 @@ SOURCE_REVISION_ID=$6
|
|||||||
CONFIGURATION=$7
|
CONFIGURATION=$7
|
||||||
CANARY=$8
|
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
|
if [ "$CANARY" == "1" ]; then
|
||||||
RELEASE_TAR_FILE_NAME=ryujinx-canary-$VERSION-macos_universal.app.tar
|
RELEASE_TAR_FILE_NAME=ryujinx-canary-$VERSION-macos_universal.app.tar
|
||||||
elif [ "$VERSION" == "1.1.0" ]; then
|
elif [ "$VERSION" == "1.1.0" ]; then
|
||||||
|
@@ -20,18 +20,6 @@ SOURCE_REVISION_ID=$6
|
|||||||
CONFIGURATION=$7
|
CONFIGURATION=$7
|
||||||
CANARY=$8
|
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
|
if [ "$CANARY" == "1" ]; then
|
||||||
RELEASE_TAR_FILE_NAME=nogui-ryujinx-canary-$VERSION-macos_universal.tar
|
RELEASE_TAR_FILE_NAME=nogui-ryujinx-canary-$VERSION-macos_universal.tar
|
||||||
elif [ "$VERSION" == "1.1.0" ]; then
|
elif [ "$VERSION" == "1.1.0" ]; then
|
||||||
|
@@ -188,8 +188,6 @@
|
|||||||
01003DD00BFEE000,"Airheart - Tales of broken Wings",,playable,2021-02-26 15:20:27
|
01003DD00BFEE000,"Airheart - Tales of broken Wings",,playable,2021-02-26 15:20:27
|
||||||
01007F100DE52000,"Akane",nvdec,playable,2022-07-21 00:12:18
|
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
|
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
|
010053100B0EA000,"Akihabara - Feel the Rhythm Remixed",,playable,2021-02-22 14:39:35
|
||||||
0100D4C00EE0C000,"Akuarium",slow,playable,2020-12-12 23:43:36
|
0100D4C00EE0C000,"Akuarium",slow,playable,2020-12-12 23:43:36
|
||||||
010026E00FEBE000,"Akuto: Showdown",,playable,2020-08-04 19:43:27
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
0100CB900B498000,"Eternum Ex",,playable,2021-01-13 20:28:32
|
||||||
010092501EB2C000,"Europa (Demo)",gpu;crash;UE4,ingame,2024-04-23 10:47:12
|
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
|
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
|
0100034012606000,"Family Mysteries: Poisonous Promises",audio;crash,menus,2021-11-26 12:35:06
|
||||||
010017C012726000,"Fantasy Friends",,playable,2022-10-17 19:42:39
|
010017C012726000,"Fantasy Friends",,playable,2022-10-17 19:42:39
|
||||||
0100767008502000,"FANTASY HERO ~unsigned legacy~",,playable,2022-07-26 12:28:52
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
0100861012474000,"Frontline Zed",,playable,2020-10-03 12:55:59
|
||||||
0100B5300B49A000,"Frost",,playable,2022-07-27 12:00:36
|
0100B5300B49A000,"Frost",,playable,2022-07-27 12:00:36
|
||||||
010038A007AA4000,"FruitFall Crush",,playable,2020-10-20 11:33:33
|
010038A007AA4000,"FruitFall Crush",,playable,2020-10-20 11:33:33
|
||||||
@@ -1440,7 +1434,6 @@
|
|||||||
0100C2700E338000,"Heroland",,playable,2020-08-05 15:35:39
|
0100C2700E338000,"Heroland",,playable,2020-08-05 15:35:39
|
||||||
01007AC00E012000,"HexaGravity",,playable,2021-05-28 13:47:48
|
01007AC00E012000,"HexaGravity",,playable,2021-05-28 13:47:48
|
||||||
01004E800F03C000,"Hidden",slow,ingame,2022-10-05 10:56:53
|
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
|
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
|
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
|
0100F3D008436000,"Hiragana Pixel Party",,playable,2021-01-14 08:36:50
|
||||||
@@ -1450,7 +1443,6 @@
|
|||||||
0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35
|
0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35
|
||||||
0100F7E00C70E000,"Hogwarts Legacy",UE4;slow,ingame,2024-09-03 19:53:58
|
0100F7E00C70E000,"Hogwarts Legacy",UE4;slow,ingame,2024-09-03 19:53:58
|
||||||
0100633007D48000,"Hollow Knight",nvdec,playable,2023-01-16 15:44:56
|
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
|
0100F2100061E800,"Hollow0",UE4;gpu,ingame,2021-03-03 23:42:56
|
||||||
0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56
|
0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56
|
||||||
010071B00C904000,"HoPiKo",,playable,2021-01-13 20:12:38
|
010071B00C904000,"HoPiKo",,playable,2021-01-13 20:12:38
|
||||||
@@ -1525,7 +1517,6 @@
|
|||||||
010095C016C14000,"Iridium",,playable,2022-08-05 23:19:53
|
010095C016C14000,"Iridium",,playable,2022-08-05 23:19:53
|
||||||
0100AD300B786000,"Iris School of Wizardry -Vinculum Hearts-",,playable,2022-12-05 13:11:15
|
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
|
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
|
01005270118D6000,"Iron Wings",slow,ingame,2022-08-07 08:32:57
|
||||||
01004DB003E6A000,"IRONCAST",,playable,2021-01-13 13:54:29
|
01004DB003E6A000,"IRONCAST",,playable,2021-01-13 13:54:29
|
||||||
0100E5700CD56000,"Irony Curtain: From Matryoshka with Love",,playable,2021-06-04 20:12:37
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
010086F0064CE000,"Poi: Explorer Edition",nvdec,playable,2021-01-21 19:32:00
|
||||||
0100EB6012FD2000,"Poison Control",,playable,2021-05-16 14:01:54
|
0100EB6012FD2000,"Poison Control",,playable,2021-05-16 14:01:54
|
||||||
010072400E04A000,"Pokémon Café ReMix",,playable,2021-08-17 20:00:04
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
0100E9C010EA8000,"Rise of Insanity",,playable,2020-08-30 15:42:14
|
||||||
01006BA00E652000,"Rise: Race The Future",,playable,2021-02-27 13:29:06
|
01006BA00E652000,"Rise: Race The Future",,playable,2021-02-27 13:29:06
|
||||||
010020C012F48000,"Rising Hell",,playable,2022-10-31 13:54:02
|
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
|
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
|
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
|
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
|
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
|
010000000EEF0000,"Shadows 2: Perfidia",,playable,2020-08-07 12:43:46
|
||||||
0100AD700CBBE000,"Shadows of Adam",,playable,2021-01-11 13:35:58
|
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
|
01002A800C064000,"Shadowverse Champions Battle",,playable,2022-10-02 22:59:29
|
||||||
01003B90136DA000,"Shadowverse: Champion's Battle",crash,nothing,2023-03-06 00:31:50
|
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
|
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
|
01005D701264A000,"SpyHack",,playable,2021-04-15 10:53:51
|
||||||
010077B00E046000,"Spyro™ Reignited Trilogy",nvdec;UE4,playable,2022-09-11 18:38:33
|
010077B00E046000,"Spyro™ Reignited Trilogy",nvdec;UE4,playable,2022-09-11 18:38:33
|
||||||
0100085012A0E000,"Squeakers",,playable,2020-12-13 12:13:05
|
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
|
010009300D31C000,"Squidgies Takeover",,playable,2020-07-20 22:28:08
|
||||||
0100FCD0102EC000,"Squidlit",,playable,2020-08-06 12:38:32
|
0100FCD0102EC000,"Squidlit",,playable,2020-08-06 12:38:32
|
||||||
0100EBF00E702000,"STAR OCEAN First Departure R",nvdec,playable,2021-07-05 19:29:16
|
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
|
0100E6B0115FC000,"Star99",online,menus,2021-11-26 14:18:51
|
||||||
01002100137BA000,"Stardash",,playable,2021-01-21 16:31:19
|
01002100137BA000,"Stardash",,playable,2021-01-21 16:31:19
|
||||||
0100E65002BB8000,"Stardew Valley",online-broken;ldn-untested,playable,2024-02-14 03:11: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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
01004A9006B84000,"The End Is Nigh",,playable,2020-06-01 11:26:45
|
||||||
0100CA100489C000,"The Escapists 2",nvdec,playable,2020-09-24 12:31:31
|
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
|
0100C2E0129A6000,"The Executioner",nvdec,playable,2021-01-23 00:31:28
|
||||||
01006050114D4000,"The Experiment: Escape Room",gpu,ingame,2022-09-30 13:20:35
|
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
|
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
|
01002DD00AF9E000,"The Fall",gpu,ingame,2020-05-31 23:31:16
|
||||||
01003E5002320000,"The Fall Part 2: Unbound",,playable,2021-11-06 02:18:08
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
0100752011628000,"TTV2",,playable,2020-11-27 13:21:36
|
||||||
0100AFE00452E000,"Tumblestone",,playable,2021-01-07 17:49:20
|
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
|
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
|
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
|
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
|
0100592005164000,"UNBOX: Newbie's Adventure",UE4,playable,2022-08-29 13:12:56
|
||||||
01002D900C5E4000,"Uncanny Valley",nvdec,playable,2021-06-04 13:28:45
|
01002D900C5E4000,"Uncanny Valley",nvdec,playable,2021-06-04 13:28:45
|
||||||
010076F011F54000,"Undead & Beyond",nvdec,playable,2022-10-04 09:11:18
|
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
|
01008F3013E4E000,"Under Leaves",,playable,2021-05-22 18:13:58
|
||||||
010080B00AD66000,"Undertale",,playable,2022-08-31 17:31:46
|
010080B00AD66000,"Undertale",,playable,2022-08-31 17:31:46
|
||||||
01008F80049C6000,"Unepic",,playable,2024-01-15 17:03:00
|
01008F80049C6000,"Unepic",,playable,2024-01-15 17:03:00
|
||||||
|
|
12
nuget.config
12
nuget.config
@@ -4,20 +4,18 @@
|
|||||||
<packageSources>
|
<packageSources>
|
||||||
<clear />
|
<clear />
|
||||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
<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="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>
|
</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>
|
<packageSourceMapping>
|
||||||
<!-- key value for <packageSource> should match key values from <packageSources> element -->
|
<!-- 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">
|
<packageSource key="nuget.org">
|
||||||
<package pattern="*" />
|
<package pattern="*" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
<packageSource key="Ryujinx.UpdateClient">
|
|
||||||
<package pattern="Ryujinx.UpdateClient" />
|
|
||||||
<package pattern="Ryujinx.Systems.Update.Common" />
|
|
||||||
</packageSource>
|
|
||||||
<packageSource key="LibHacAlpha">
|
<packageSource key="LibHacAlpha">
|
||||||
<package pattern="Ryujinx.LibHac" />
|
<package pattern="Ryujinx.LibHac" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
|
@@ -143,12 +143,6 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
public static void EmitCall(ArmEmitterContext context, ulong immediate)
|
||||||
{
|
{
|
||||||
if (context.IsSingleStep)
|
|
||||||
{
|
|
||||||
context.Return(Const(immediate));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isRecursive = immediate == context.EntryAddress;
|
bool isRecursive = immediate == context.EntryAddress;
|
||||||
|
|
||||||
if (isRecursive)
|
if (isRecursive)
|
||||||
@@ -162,25 +156,13 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitVirtualCall(ArmEmitterContext context, Operand target)
|
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)
|
public static void EmitVirtualJump(ArmEmitterContext context, Operand target, bool isReturn)
|
||||||
{
|
{
|
||||||
if (isReturn || context.IsSingleStep)
|
if (isReturn)
|
||||||
{
|
{
|
||||||
if (target.Type == OperandType.I32)
|
if (target.Type == OperandType.I32)
|
||||||
{
|
{
|
||||||
|
@@ -3,7 +3,6 @@ using ARMeilleure.State;
|
|||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
@@ -201,11 +200,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
ExecutionContext context = GetContext();
|
ExecutionContext context = GetContext();
|
||||||
|
|
||||||
// If debugging, we'll handle interrupts outside
|
|
||||||
if (!Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
context.CheckInterrupt();
|
context.CheckInterrupt();
|
||||||
}
|
|
||||||
|
|
||||||
Statistics.ResumeTimer();
|
Statistics.ResumeTimer();
|
||||||
|
|
||||||
|
@@ -12,7 +12,6 @@ namespace ARMeilleure
|
|||||||
|
|
||||||
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
public static bool AllowLcqInFunctionTable { get; set; } = true;
|
||||||
public static bool UseUnmanagedDispatchLoop { 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 UseAdvSimdIfAvailable { get; set; } = true;
|
||||||
public static bool UseArm64AesIfAvailable { get; set; } = true;
|
public static bool UseArm64AesIfAvailable { get; set; } = true;
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
@@ -11,7 +10,7 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
internal nint NativeContextPtr => _nativeContext.BasePtr;
|
||||||
|
|
||||||
internal bool Interrupted { get; private set; }
|
private bool _interrupted;
|
||||||
|
|
||||||
private readonly ICounter _counter;
|
private readonly ICounter _counter;
|
||||||
|
|
||||||
@@ -66,8 +65,6 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public bool IsAarch32 { get; set; }
|
public bool IsAarch32 { get; set; }
|
||||||
|
|
||||||
public ulong ThreadUid { get; set; }
|
|
||||||
|
|
||||||
internal ExecutionMode ExecutionMode
|
internal ExecutionMode ExecutionMode
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -93,19 +90,14 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||||
private readonly ExceptionCallback _breakCallback;
|
private readonly ExceptionCallback _breakCallback;
|
||||||
private readonly ExceptionCallbackNoArgs _stepCallback;
|
|
||||||
private readonly ExceptionCallback _supervisorCallback;
|
private readonly ExceptionCallback _supervisorCallback;
|
||||||
private readonly ExceptionCallback _undefinedCallback;
|
private readonly ExceptionCallback _undefinedCallback;
|
||||||
|
|
||||||
internal int ShouldStep;
|
|
||||||
public ulong DebugPc { get; set; }
|
|
||||||
|
|
||||||
public ExecutionContext(
|
public ExecutionContext(
|
||||||
IJitMemoryAllocator allocator,
|
IJitMemoryAllocator allocator,
|
||||||
ICounter counter,
|
ICounter counter,
|
||||||
ExceptionCallbackNoArgs interruptCallback = null,
|
ExceptionCallbackNoArgs interruptCallback = null,
|
||||||
ExceptionCallback breakCallback = null,
|
ExceptionCallback breakCallback = null,
|
||||||
ExceptionCallbackNoArgs stepCallback = null,
|
|
||||||
ExceptionCallback supervisorCallback = null,
|
ExceptionCallback supervisorCallback = null,
|
||||||
ExceptionCallback undefinedCallback = null)
|
ExceptionCallback undefinedCallback = null)
|
||||||
{
|
{
|
||||||
@@ -113,7 +105,6 @@ namespace ARMeilleure.State
|
|||||||
_counter = counter;
|
_counter = counter;
|
||||||
_interruptCallback = interruptCallback;
|
_interruptCallback = interruptCallback;
|
||||||
_breakCallback = breakCallback;
|
_breakCallback = breakCallback;
|
||||||
_stepCallback = stepCallback;
|
|
||||||
_supervisorCallback = supervisorCallback;
|
_supervisorCallback = supervisorCallback;
|
||||||
_undefinedCallback = undefinedCallback;
|
_undefinedCallback = undefinedCallback;
|
||||||
|
|
||||||
@@ -136,9 +127,9 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
internal void CheckInterrupt()
|
internal void CheckInterrupt()
|
||||||
{
|
{
|
||||||
if (Interrupted)
|
if (_interrupted)
|
||||||
{
|
{
|
||||||
Interrupted = false;
|
_interrupted = false;
|
||||||
|
|
||||||
_interruptCallback?.Invoke(this);
|
_interruptCallback?.Invoke(this);
|
||||||
}
|
}
|
||||||
@@ -148,37 +139,16 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public void RequestInterrupt()
|
public void RequestInterrupt()
|
||||||
{
|
{
|
||||||
Interrupted = true;
|
_interrupted = true;
|
||||||
}
|
|
||||||
|
|
||||||
public void StepHandler()
|
|
||||||
{
|
|
||||||
_stepCallback?.Invoke(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RequestDebugStep()
|
|
||||||
{
|
|
||||||
Interlocked.Exchange(ref ShouldStep, 1);
|
|
||||||
RequestInterrupt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnBreak(ulong address, int imm)
|
internal void OnBreak(ulong address, int imm)
|
||||||
{
|
{
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
DebugPc = Pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
_breakCallback?.Invoke(this, address, imm);
|
_breakCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnSupervisorCall(ulong address, int imm)
|
internal void OnSupervisorCall(ulong address, int imm)
|
||||||
{
|
{
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
DebugPc = Pc;
|
|
||||||
}
|
|
||||||
|
|
||||||
_supervisorCallback?.Invoke(this, address, imm);
|
_supervisorCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,12 +22,6 @@ namespace ARMeilleure.State
|
|||||||
public ulong ExclusiveValueHigh;
|
public ulong ExclusiveValueHigh;
|
||||||
public int Running;
|
public int Running;
|
||||||
public long Tpidr2El0;
|
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();
|
private static NativeCtxStorage _dummyStorage = new();
|
||||||
@@ -45,11 +39,6 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
public ulong GetPc()
|
public ulong GetPc()
|
||||||
{
|
{
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
return GetStorage().DebugPrecisePc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: More precise tracking of PC value.
|
// TODO: More precise tracking of PC value.
|
||||||
return GetStorage().DispatchAddress;
|
return GetStorage().DispatchAddress;
|
||||||
}
|
}
|
||||||
@@ -279,11 +268,6 @@ namespace ARMeilleure.State
|
|||||||
return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running);
|
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)
|
private static int StorageOffset<T>(ref NativeCtxStorage storage, ref T target)
|
||||||
{
|
{
|
||||||
return (int)Unsafe.ByteOffset(ref Unsafe.As<NativeCtxStorage, T>(ref storage), ref 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 HighCq { get; }
|
||||||
public bool HasPtc { get; }
|
public bool HasPtc { get; }
|
||||||
public Aarch32Mode Mode { get; }
|
public Aarch32Mode Mode { get; }
|
||||||
public bool IsSingleStep { get; }
|
|
||||||
|
|
||||||
private int _ifThenBlockStateIndex = 0;
|
private int _ifThenBlockStateIndex = 0;
|
||||||
private Condition[] _ifThenBlockState = [];
|
private Condition[] _ifThenBlockState = [];
|
||||||
@@ -67,8 +66,7 @@ namespace ARMeilleure.Translation
|
|||||||
ulong entryAddress,
|
ulong entryAddress,
|
||||||
bool highCq,
|
bool highCq,
|
||||||
bool hasPtc,
|
bool hasPtc,
|
||||||
Aarch32Mode mode,
|
Aarch32Mode mode)
|
||||||
bool isSingleStep)
|
|
||||||
{
|
{
|
||||||
Memory = memory;
|
Memory = memory;
|
||||||
CountTable = countTable;
|
CountTable = countTable;
|
||||||
@@ -78,7 +76,6 @@ namespace ARMeilleure.Translation
|
|||||||
HighCq = highCq;
|
HighCq = highCq;
|
||||||
HasPtc = hasPtc;
|
HasPtc = hasPtc;
|
||||||
Mode = mode;
|
Mode = mode;
|
||||||
IsSingleStep = isSingleStep;
|
|
||||||
|
|
||||||
_labels = new Dictionary<ulong, Operand>();
|
_labels = new Dictionary<ulong, Operand>();
|
||||||
}
|
}
|
||||||
|
@@ -33,7 +33,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\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 ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
@@ -193,7 +193,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
_infosStream.Seek(0L, SeekOrigin.Begin);
|
_infosStream.Seek(0L, SeekOrigin.Begin);
|
||||||
bool foundBadFunction = false;
|
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);
|
InfoEntry infoEntry = DeserializeStructure<InfoEntry>(_infosStream);
|
||||||
foreach (ulong address in blacklist)
|
foreach (ulong address in blacklist)
|
||||||
@@ -303,13 +303,6 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outerHeader.DebuggerMode != Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
InvalidateCompressedStream(compressedStream);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
nint intPtr = nint.Zero;
|
nint intPtr = nint.Zero;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -486,7 +479,6 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
MemoryManagerMode = GetMemoryManagerMode(),
|
MemoryManagerMode = GetMemoryManagerMode(),
|
||||||
OSPlatform = GetOSPlatform(),
|
OSPlatform = GetOSPlatform(),
|
||||||
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
Architecture = (uint)RuntimeInformation.ProcessArchitecture,
|
||||||
DebuggerMode = Optimizations.EnableDebugging,
|
|
||||||
|
|
||||||
UncompressedStreamSize =
|
UncompressedStreamSize =
|
||||||
(long)Unsafe.SizeOf<InnerHeader>() +
|
(long)Unsafe.SizeOf<InnerHeader>() +
|
||||||
@@ -1076,7 +1068,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
return osPlatform;
|
return osPlatform;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 87*/)]
|
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
|
||||||
private struct OuterHeader
|
private struct OuterHeader
|
||||||
{
|
{
|
||||||
public ulong Magic;
|
public ulong Magic;
|
||||||
@@ -1088,7 +1080,6 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
public byte MemoryManagerMode;
|
public byte MemoryManagerMode;
|
||||||
public uint OSPlatform;
|
public uint OSPlatform;
|
||||||
public uint Architecture;
|
public uint Architecture;
|
||||||
public bool DebuggerMode;
|
|
||||||
|
|
||||||
public long UncompressedStreamSize;
|
public long UncompressedStreamSize;
|
||||||
|
|
||||||
|
@@ -119,25 +119,7 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
NativeInterface.RegisterThread(context, Memory, this);
|
NativeInterface.RegisterThread(context, Memory, this);
|
||||||
|
|
||||||
if (Optimizations.EnableDebugging)
|
if (Optimizations.UseUnmanagedDispatchLoop)
|
||||||
{
|
|
||||||
context.DebugPc = address;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (Interlocked.CompareExchange(ref context.ShouldStep, 0, 1) == 1)
|
|
||||||
{
|
|
||||||
context.DebugPc = Step(context, context.DebugPc);
|
|
||||||
context.StepHandler();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
context.DebugPc = ExecuteSingle(context, context.DebugPc);
|
|
||||||
}
|
|
||||||
context.CheckInterrupt();
|
|
||||||
}
|
|
||||||
while (context.Running && context.DebugPc != 0);
|
|
||||||
}
|
|
||||||
else if (Optimizations.UseUnmanagedDispatchLoop)
|
|
||||||
{
|
{
|
||||||
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
Stubs.DispatchLoop(context.NativeContextPtr, address);
|
||||||
}
|
}
|
||||||
@@ -193,7 +175,7 @@ namespace ARMeilleure.Translation
|
|||||||
return nextAddr;
|
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);
|
TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
|
||||||
|
|
||||||
@@ -204,8 +186,6 @@ namespace ARMeilleure.Translation
|
|||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
|
||||||
{
|
{
|
||||||
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
if (!Functions.TryGetValue(address, out TranslatedFunction func))
|
||||||
@@ -249,8 +229,7 @@ namespace ARMeilleure.Translation
|
|||||||
address,
|
address,
|
||||||
highCq,
|
highCq,
|
||||||
_ptc.State != PtcState.Disabled,
|
_ptc.State != PtcState.Disabled,
|
||||||
mode: Aarch32Mode.User,
|
mode: Aarch32Mode.User);
|
||||||
isSingleStep: singleStep);
|
|
||||||
|
|
||||||
Logger.StartPass(PassName.Decoding);
|
Logger.StartPass(PassName.Decoding);
|
||||||
|
|
||||||
@@ -388,13 +367,9 @@ namespace ARMeilleure.Translation
|
|||||||
|
|
||||||
if (block.Exit)
|
if (block.Exit)
|
||||||
{
|
{
|
||||||
// Return to managed rather than tail call.
|
// Left option here as it may be useful if we need to return to managed rather than tail call in
|
||||||
bool useReturns = Optimizations.EnableDebugging;
|
// future. (eg. for debug)
|
||||||
|
bool useReturns = false;
|
||||||
if (Optimizations.EnableDebugging)
|
|
||||||
{
|
|
||||||
EmitDebugPrecisePcUpdate(context, block.Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
|
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;
|
Operand lblPredicateSkip = default;
|
||||||
|
|
||||||
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
|
||||||
@@ -519,14 +489,6 @@ namespace ARMeilleure.Translation
|
|||||||
context.MarkLabel(lblExit);
|
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)
|
public void InvalidateJitCacheRegion(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
ulong[] overlapAddresses = [];
|
ulong[] overlapAddresses = [];
|
||||||
|
@@ -81,16 +81,16 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
|
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
|
||||||
{
|
{
|
||||||
if ((uint)index >= (uint)coefficients.Length)
|
if ((uint)index < (uint)coefficients.Length)
|
||||||
{
|
{
|
||||||
|
return coefficients[index];
|
||||||
|
}
|
||||||
|
|
||||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return coefficients[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
|
public static int Decode(Span<short> output, ReadOnlySpan<byte> input, int startSampleOffset, int endSampleOffset, int offset, int count, ReadOnlySpan<short> coefficients, ref AdpcmLoopContext loopContext)
|
||||||
{
|
{
|
||||||
|
@@ -26,15 +26,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
ReadOnlySpan<float> inputBuffer,
|
ReadOnlySpan<float> inputBuffer,
|
||||||
uint sampleCount)
|
uint sampleCount)
|
||||||
{
|
{
|
||||||
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||||
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
|
||||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -67,15 +64,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
uint sampleCount,
|
uint sampleCount,
|
||||||
float volume)
|
float volume)
|
||||||
{
|
{
|
||||||
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||||
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
|
||||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -113,15 +107,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
float volume,
|
float volume,
|
||||||
float ramp)
|
float ramp)
|
||||||
{
|
{
|
||||||
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||||
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
|
||||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float mixState = 0f;
|
float mixState = 0f;
|
||||||
|
|
||||||
@@ -167,15 +158,12 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
|
|
||||||
ref BiquadFilterState state = ref states[stageIndex];
|
ref BiquadFilterState state = ref states[stageIndex];
|
||||||
|
|
||||||
Span<short> numeratorSpan = parameter.Numerator.AsSpan();
|
float a0 = FixedPointHelper.ToFloat(parameter.Numerator[0], FixedPointPrecisionForParameter);
|
||||||
Span<short> denominatorSpan = parameter.Denominator.AsSpan();
|
float a1 = FixedPointHelper.ToFloat(parameter.Numerator[1], FixedPointPrecisionForParameter);
|
||||||
|
float a2 = FixedPointHelper.ToFloat(parameter.Numerator[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a0 = FixedPointHelper.ToFloat(numeratorSpan[0], FixedPointPrecisionForParameter);
|
float b1 = FixedPointHelper.ToFloat(parameter.Denominator[0], FixedPointPrecisionForParameter);
|
||||||
float a1 = FixedPointHelper.ToFloat(numeratorSpan[1], FixedPointPrecisionForParameter);
|
float b2 = FixedPointHelper.ToFloat(parameter.Denominator[1], FixedPointPrecisionForParameter);
|
||||||
float a2 = FixedPointHelper.ToFloat(numeratorSpan[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b1 = FixedPointHelper.ToFloat(denominatorSpan[0], FixedPointPrecisionForParameter);
|
|
||||||
float b2 = FixedPointHelper.ToFloat(denominatorSpan[1], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -213,25 +201,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
uint sampleCount,
|
uint sampleCount,
|
||||||
float volume)
|
float volume)
|
||||||
{
|
{
|
||||||
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
|
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
||||||
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
|
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
||||||
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
|
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
||||||
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
|
|
||||||
|
|
||||||
|
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
||||||
|
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
|
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
||||||
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
|
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
||||||
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
|
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
||||||
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
float b21 = FixedPointHelper.ToFloat(parameter1.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 b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
|
||||||
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
for (int i = 0; i < sampleCount; i++)
|
for (int i = 0; i < sampleCount; i++)
|
||||||
{
|
{
|
||||||
@@ -279,24 +261,19 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
float volume,
|
float volume,
|
||||||
float ramp)
|
float ramp)
|
||||||
{
|
{
|
||||||
Span<short> numerator0Span = parameter0.Numerator.AsSpan();
|
float a00 = FixedPointHelper.ToFloat(parameter0.Numerator[0], FixedPointPrecisionForParameter);
|
||||||
Span<short> numerator1Span = parameter1.Numerator.AsSpan();
|
float a10 = FixedPointHelper.ToFloat(parameter0.Numerator[1], FixedPointPrecisionForParameter);
|
||||||
Span<short> denominator0Span = parameter0.Denominator.AsSpan();
|
float a20 = FixedPointHelper.ToFloat(parameter0.Numerator[2], FixedPointPrecisionForParameter);
|
||||||
Span<short> denominator1Span = parameter1.Denominator.AsSpan();
|
|
||||||
|
|
||||||
float a00 = FixedPointHelper.ToFloat(numerator0Span[0], FixedPointPrecisionForParameter);
|
float b10 = FixedPointHelper.ToFloat(parameter0.Denominator[0], FixedPointPrecisionForParameter);
|
||||||
float a10 = FixedPointHelper.ToFloat(numerator0Span[1], FixedPointPrecisionForParameter);
|
float b20 = FixedPointHelper.ToFloat(parameter0.Denominator[1], FixedPointPrecisionForParameter);
|
||||||
float a20 = FixedPointHelper.ToFloat(numerator0Span[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b10 = FixedPointHelper.ToFloat(denominator0Span[0], FixedPointPrecisionForParameter);
|
float a01 = FixedPointHelper.ToFloat(parameter1.Numerator[0], FixedPointPrecisionForParameter);
|
||||||
float b20 = FixedPointHelper.ToFloat(denominator0Span[1], FixedPointPrecisionForParameter);
|
float a11 = FixedPointHelper.ToFloat(parameter1.Numerator[1], FixedPointPrecisionForParameter);
|
||||||
|
float a21 = FixedPointHelper.ToFloat(parameter1.Numerator[2], FixedPointPrecisionForParameter);
|
||||||
|
|
||||||
float a01 = FixedPointHelper.ToFloat(numerator1Span[0], FixedPointPrecisionForParameter);
|
float b11 = FixedPointHelper.ToFloat(parameter1.Denominator[0], FixedPointPrecisionForParameter);
|
||||||
float a11 = FixedPointHelper.ToFloat(numerator1Span[1], FixedPointPrecisionForParameter);
|
float b21 = FixedPointHelper.ToFloat(parameter1.Denominator[1], FixedPointPrecisionForParameter);
|
||||||
float a21 = FixedPointHelper.ToFloat(numerator1Span[2], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float b11 = FixedPointHelper.ToFloat(denominator1Span[0], FixedPointPrecisionForParameter);
|
|
||||||
float b21 = FixedPointHelper.ToFloat(denominator1Span[1], FixedPointPrecisionForParameter);
|
|
||||||
|
|
||||||
float mixState = 0f;
|
float mixState = 0f;
|
||||||
|
|
||||||
|
@@ -40,13 +40,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
SampleRate = serverState.SampleRate;
|
SampleRate = serverState.SampleRate;
|
||||||
Pitch = serverState.Pitch;
|
Pitch = serverState.Pitch;
|
||||||
|
|
||||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
|
||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
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);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
using Ryujinx.Audio.Renderer.Parameter.Sink;
|
||||||
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
using Ryujinx.Audio.Renderer.Server.MemoryPool;
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
namespace Ryujinx.Audio.Renderer.Dsp.Command
|
||||||
@@ -30,11 +29,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
Input = new ushort[Constants.ChannelCountMax];
|
Input = new ushort[Constants.ChannelCountMax];
|
||||||
InputCount = parameter.InputCount;
|
InputCount = parameter.InputCount;
|
||||||
|
|
||||||
Span<byte> inputSpan = parameter.Input.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < InputCount; i++)
|
for (int i = 0; i < InputCount; i++)
|
||||||
{
|
{
|
||||||
Input[i] = (ushort)(bufferOffset + inputSpan[i]);
|
Input[i] = (ushort)(bufferOffset + parameter.Input[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
CircularBuffer = circularBufferAddressInfo.GetReference(true);
|
||||||
|
@@ -43,13 +43,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = 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++)
|
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,11 +172,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
|
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
|
||||||
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
|
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
|
||||||
|
|
||||||
Span<float> lastSamplesSpan = statistics.LastSamples.AsSpan();
|
|
||||||
|
|
||||||
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -53,13 +53,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
SampleRate = serverState.SampleRate;
|
SampleRate = serverState.SampleRate;
|
||||||
Pitch = serverState.Pitch;
|
Pitch = serverState.Pitch;
|
||||||
|
|
||||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
|
||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
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);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(2);
|
||||||
}
|
}
|
||||||
|
@@ -43,13 +43,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = 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++)
|
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
|
||||||
|
@@ -42,15 +42,14 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
ref VoiceUpdateState state = ref State.Span[0];
|
ref VoiceUpdateState state = ref State.Span[0];
|
||||||
|
|
||||||
Span<float> depopBuffer = DepopBuffer.Span;
|
Span<float> depopBuffer = DepopBuffer.Span;
|
||||||
Span<float> lastSamplesSpan = state.LastSamples.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < MixBufferCount; i++)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -35,11 +35,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputCount = sink.Parameter.InputCount;
|
InputCount = sink.Parameter.InputCount;
|
||||||
InputBufferIndices = new ushort[InputCount];
|
InputBufferIndices = new ushort[InputCount];
|
||||||
|
|
||||||
Span<byte> inputSpan = sink.Parameter.Input.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Math.Min(InputCount, Constants.ChannelCountMax); i++)
|
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)
|
if (sink.UpsamplerState != null)
|
||||||
|
@@ -38,13 +38,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = 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++)
|
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -49,13 +49,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = 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++)
|
for (int i = 0; i < _parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[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];
|
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
|
||||||
|
|
||||||
Span<float> inputMaxSpan = statistics.InputMax.AsSpan();
|
statistics.InputMax[channelIndex] = Math.Max(statistics.InputMax[channelIndex], sampleInputMax);
|
||||||
Span<float> compressionGainMinSpan = statistics.CompressionGainMin.AsSpan();
|
statistics.CompressionGainMin[channelIndex] = Math.Min(statistics.CompressionGainMin[channelIndex], compressionGain);
|
||||||
|
|
||||||
inputMaxSpan[channelIndex] = Math.Max(inputMaxSpan[channelIndex], sampleInputMax);
|
|
||||||
compressionGainMinSpan[channelIndex] = Math.Min(compressionGainMinSpan[channelIndex], compressionGain);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -79,10 +79,6 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
public void Process(CommandList context)
|
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++)
|
for (int i = 0; i < MixBufferCount; i++)
|
||||||
{
|
{
|
||||||
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]);
|
ReadOnlySpan<float> inputBuffer = context.GetBuffer(InputBufferIndices[i]);
|
||||||
@@ -91,13 +87,15 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
float volume0 = Volume0[i];
|
float volume0 = Volume0[i];
|
||||||
float volume1 = Volume1[i];
|
float volume1 = Volume1[i];
|
||||||
|
|
||||||
|
ref VoiceUpdateState state = ref State.Span[0];
|
||||||
|
|
||||||
if (volume0 != 0 || volume1 != 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
|
else
|
||||||
{
|
{
|
||||||
lastSamplesSpan[i] = 0;
|
state.LastSamples[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,11 +43,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
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);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
@@ -43,11 +43,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
|
|
||||||
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
WaveBuffers = new WaveBuffer[Constants.VoiceWaveBufferCount];
|
||||||
|
|
||||||
Span<Server.Voice.WaveBuffer> waveBufferSpan = serverState.WaveBuffers.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < WaveBuffers.Length; i++)
|
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);
|
WaveBuffers[i] = voiceWaveBuffer.ToCommon(1);
|
||||||
}
|
}
|
||||||
|
@@ -66,13 +66,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = 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++)
|
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
|
||||||
|
@@ -64,13 +64,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
|
|||||||
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
|
||||||
OutputBufferIndices = 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++)
|
for (int i = 0; i < Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
InputBufferIndices[i] = (ushort)(bufferOffset + inputSpan[i]);
|
InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
|
||||||
OutputBufferIndices[i] = (ushort)(bufferOffset + outputSpan[i]);
|
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
IsLongSizePreDelaySupported = isLongSizePreDelaySupported;
|
||||||
|
@@ -74,7 +74,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
{
|
{
|
||||||
int tempBufferIndex = 0;
|
int tempBufferIndex = 0;
|
||||||
|
|
||||||
if ((info.DecodingBehaviour & DecodingBehaviour.SkipPitchAndSampleRateConversion) != DecodingBehaviour.SkipPitchAndSampleRateConversion)
|
if (!info.DecodingBehaviour.HasFlag(DecodingBehaviour.SkipPitchAndSampleRateConversion))
|
||||||
{
|
{
|
||||||
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
voiceState.Pitch.AsSpan()[..pitchMaxLength].CopyTo(tempBuffer);
|
||||||
tempBufferIndex += pitchMaxLength;
|
tempBufferIndex += pitchMaxLength;
|
||||||
@@ -208,7 +208,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((info.DecodingBehaviour & DecodingBehaviour.PlayedSampleCountResetWhenLooping) == DecodingBehaviour.PlayedSampleCountResetWhenLooping)
|
if (info.DecodingBehaviour.HasFlag(DecodingBehaviour.PlayedSampleCountResetWhenLooping))
|
||||||
{
|
{
|
||||||
playedSampleCount = 0;
|
playedSampleCount = 0;
|
||||||
}
|
}
|
||||||
@@ -222,7 +222,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
|
|
||||||
Span<int> outputSpanInt = MemoryMarshal.Cast<float, int>(outputBuffer[i..]);
|
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++)
|
for (int j = 0; j < y; j++)
|
||||||
{
|
{
|
||||||
|
@@ -41,12 +41,11 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
}
|
}
|
||||||
|
|
||||||
Array20<float> result = new();
|
Array20<float> result = new();
|
||||||
Span<float> resultSpan = result.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < FilterBankLength; i++)
|
for (int i = 0; i < FilterBankLength; i++)
|
||||||
{
|
{
|
||||||
float x = (Bank0CenterIndex - i) + offset;
|
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;
|
return result;
|
||||||
@@ -80,9 +79,6 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
Debug.Assert(state.History.Length == HistoryLength);
|
Debug.Assert(state.History.Length == HistoryLength);
|
||||||
Debug.Assert(bank.Length == FilterBankLength);
|
Debug.Assert(bank.Length == FilterBankLength);
|
||||||
|
|
||||||
Span<float> bankSpan = bank.AsSpan();
|
|
||||||
Span<float> historySpan = state.History.AsSpan();
|
|
||||||
|
|
||||||
int curIdx = 0;
|
int curIdx = 0;
|
||||||
if (Vector.IsHardwareAccelerated)
|
if (Vector.IsHardwareAccelerated)
|
||||||
{
|
{
|
||||||
@@ -92,15 +88,15 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
while (curIdx < stopIdx)
|
while (curIdx < stopIdx)
|
||||||
{
|
{
|
||||||
result += Vector.Dot(
|
result += Vector.Dot(
|
||||||
new Vector<float>(bankSpan[curIdx..(curIdx + Vector<float>.Count)]),
|
new Vector<float>(bank.AsSpan().Slice(curIdx, Vector<float>.Count)),
|
||||||
new Vector<float>(historySpan[curIdx..(curIdx + Vector<float>.Count)]));
|
new Vector<float>(state.History.AsSpan().Slice(curIdx, Vector<float>.Count)));
|
||||||
curIdx += Vector<float>.Count;
|
curIdx += Vector<float>.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (curIdx < FilterBankLength)
|
while (curIdx < FilterBankLength)
|
||||||
{
|
{
|
||||||
result += bankSpan[curIdx] * historySpan[curIdx];
|
result += bank[curIdx] * state.History[curIdx];
|
||||||
curIdx++;
|
curIdx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -141,20 +141,18 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
bool supportsOptimizedPath = _rendererContext.BehaviourContext.UseMultiTapBiquadFilterProcessing();
|
||||||
|
|
||||||
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
if (supportsOptimizedPath && voiceState.BiquadFilters[0].Enable && voiceState.BiquadFilters[1].Enable)
|
||||||
|
|
||||||
if (supportsOptimizedPath && biquadFiltersSpan[0].Enable && biquadFiltersSpan[1].Enable)
|
|
||||||
{
|
{
|
||||||
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
Memory<byte> biquadStateRawMemory = SpanMemoryManager<byte>.Cast(state)[..(Unsafe.SizeOf<BiquadFilterState>() * Constants.VoiceBiquadFilterCount)];
|
||||||
Memory<BiquadFilterState> stateMemory = SpanMemoryManager<BiquadFilterState>.Cast(biquadStateRawMemory);
|
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
|
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)
|
if (filter.Enable)
|
||||||
{
|
{
|
||||||
@@ -314,14 +312,11 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
int nodeId = voiceState.NodeId;
|
int nodeId = voiceState.NodeId;
|
||||||
uint channelsCount = voiceState.ChannelsCount;
|
uint channelsCount = voiceState.ChannelsCount;
|
||||||
|
|
||||||
Span<int> channelResourceIdsSpan = voiceState.ChannelResourceIds.AsSpan();
|
|
||||||
Span<BiquadFilterParameter> biquadFiltersSpan = voiceState.BiquadFilters.AsSpan();
|
|
||||||
|
|
||||||
for (int channelIndex = 0; channelIndex < channelsCount; channelIndex++)
|
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;
|
PerformanceDetailType dataSourceDetailType = PerformanceDetailType.Adpcm;
|
||||||
|
|
||||||
@@ -481,7 +476,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
for (int i = 0; i < voiceState.BiquadFilterNeedInitialization.Length; i++)
|
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)
|
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++)
|
for (int i = 0; i < effect.Parameter.MixesCount; i++)
|
||||||
{
|
{
|
||||||
if (volumesSpan[i] != 0.0f)
|
if (effect.Parameter.Volumes[i] != 0.0f)
|
||||||
{
|
{
|
||||||
_commandBuffer.GenerateMix(
|
_commandBuffer.GenerateMix(
|
||||||
(uint)bufferOffset + inputSpan[i],
|
(uint)bufferOffset + effect.Parameter.Input[i],
|
||||||
(uint)bufferOffset + outputSpan[i],
|
(uint)bufferOffset + effect.Parameter.Output[i],
|
||||||
nodeId,
|
nodeId,
|
||||||
volumesSpan[i]);
|
effect.Parameter.Volumes[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -563,10 +554,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
uint writeOffset = 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--)
|
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||||
{
|
{
|
||||||
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
||||||
@@ -584,8 +571,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
_commandBuffer.GenerateAuxEffect(
|
_commandBuffer.GenerateAuxEffect(
|
||||||
bufferOffset,
|
bufferOffset,
|
||||||
inputSpan[i],
|
effect.Parameter.Input[i],
|
||||||
outputSpan[i],
|
effect.Parameter.Output[i],
|
||||||
ref effect.State,
|
ref effect.State,
|
||||||
effect.IsEnabled,
|
effect.IsEnabled,
|
||||||
effect.Parameter.BufferStorageSize,
|
effect.Parameter.BufferStorageSize,
|
||||||
@@ -633,9 +620,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
Debug.Assert(effect.Type == EffectType.BiquadFilter);
|
Debug.Assert(effect.Type == EffectType.BiquadFilter);
|
||||||
|
|
||||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
|
||||||
Span<byte> outputSpan = effect.Parameter.Output.AsSpan();
|
|
||||||
|
|
||||||
if (effect.IsEnabled)
|
if (effect.IsEnabled)
|
||||||
{
|
{
|
||||||
bool needInitialization = effect.Parameter.Status == UsageState.Invalid ||
|
bool needInitialization = effect.Parameter.Status == UsageState.Invalid ||
|
||||||
@@ -655,8 +639,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
(int)bufferOffset,
|
(int)bufferOffset,
|
||||||
ref parameter,
|
ref parameter,
|
||||||
effect.State.Slice(i, 1),
|
effect.State.Slice(i, 1),
|
||||||
inputSpan[i],
|
effect.Parameter.Input[i],
|
||||||
outputSpan[i],
|
effect.Parameter.Output[i],
|
||||||
needInitialization,
|
needInitialization,
|
||||||
nodeId);
|
nodeId);
|
||||||
}
|
}
|
||||||
@@ -665,8 +649,8 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
for (int i = 0; i < effect.Parameter.ChannelCount; i++)
|
||||||
{
|
{
|
||||||
uint inputBufferIndex = bufferOffset + inputSpan[i];
|
uint inputBufferIndex = bufferOffset + effect.Parameter.Input[i];
|
||||||
uint outputBufferIndex = bufferOffset + outputSpan[i];
|
uint outputBufferIndex = bufferOffset + effect.Parameter.Output[i];
|
||||||
|
|
||||||
// If the input and output isn't the same, generate a command.
|
// If the input and output isn't the same, generate a command.
|
||||||
if (inputBufferIndex != outputBufferIndex)
|
if (inputBufferIndex != outputBufferIndex)
|
||||||
@@ -718,8 +702,6 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
uint writeOffset = 0;
|
uint writeOffset = 0;
|
||||||
|
|
||||||
Span<byte> inputSpan = effect.Parameter.Input.AsSpan();
|
|
||||||
|
|
||||||
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
for (uint channelIndex = effect.Parameter.ChannelCount; channelIndex != 0; channelIndex--)
|
||||||
{
|
{
|
||||||
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
uint newUpdateCount = writeOffset + _commandBuffer.CommandList.SampleCount;
|
||||||
@@ -737,7 +719,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
|
|
||||||
_commandBuffer.GenerateCaptureEffect(
|
_commandBuffer.GenerateCaptureEffect(
|
||||||
bufferOffset,
|
bufferOffset,
|
||||||
inputSpan[i],
|
effect.Parameter.Input[i],
|
||||||
effect.State.SendBufferInfo,
|
effect.State.SendBufferInfo,
|
||||||
effect.IsEnabled,
|
effect.IsEnabled,
|
||||||
effect.Parameter.BufferStorageSize,
|
effect.Parameter.BufferStorageSize,
|
||||||
|
@@ -218,8 +218,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
|
|||||||
/// <returns>True if any biquad filter is enabled.</returns>
|
/// <returns>True if any biquad filter is enabled.</returns>
|
||||||
public bool IsBiquadFilterEnabled()
|
public bool IsBiquadFilterEnabled()
|
||||||
{
|
{
|
||||||
Span<BiquadFilterParameter> biquadFiltersSpan = _biquadFilters.AsSpan();
|
return _biquadFilters[0].Enable || _biquadFilters[1].Enable;
|
||||||
return biquadFiltersSpan[0].Enable || biquadFiltersSpan[1].Enable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -162,11 +162,9 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
ref VoiceState currentVoiceState = ref context.GetState(i);
|
ref VoiceState currentVoiceState = ref context.GetState(i);
|
||||||
|
|
||||||
Span<int> channelResourceIdsSpan = parameter.ChannelResourceIds.AsSpan();
|
|
||||||
|
|
||||||
for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++)
|
for (int channelResourceIndex = 0; channelResourceIndex < parameter.ChannelCount; channelResourceIndex++)
|
||||||
{
|
{
|
||||||
int channelId = channelResourceIdsSpan[channelResourceIndex];
|
int channelId = parameter.ChannelResourceIds[channelResourceIndex];
|
||||||
|
|
||||||
Debug.Assert(channelId >= 0 && channelId < context.GetCount());
|
Debug.Assert(channelId >= 0 && channelId < context.GetCount());
|
||||||
|
|
||||||
|
@@ -126,9 +126,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
_sortedVoices.Span[i] = i;
|
_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 aState = ref GetState(a);
|
||||||
ref VoiceState bState = ref GetState(b);
|
ref VoiceState bState = ref GetState(b);
|
||||||
@@ -143,7 +143,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
// sortedVoicesTemp.CopyTo(_sortedVoices.Span);
|
sortedVoicesTemp.AsSpan().CopyTo(_sortedVoices.Span);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -219,17 +219,15 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeWaveBuffers()
|
private void InitializeWaveBuffers()
|
||||||
{
|
{
|
||||||
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
|
|
||||||
for (int i = 0; i < waveBuffersSpan.Length; i++)
|
|
||||||
{
|
{
|
||||||
waveBuffersSpan[i].StartSampleOffset = 0;
|
WaveBuffers[i].StartSampleOffset = 0;
|
||||||
waveBuffersSpan[i].EndSampleOffset = 0;
|
WaveBuffers[i].EndSampleOffset = 0;
|
||||||
waveBuffersSpan[i].ShouldLoop = false;
|
WaveBuffers[i].ShouldLoop = false;
|
||||||
waveBuffersSpan[i].IsEndOfStream = false;
|
WaveBuffers[i].IsEndOfStream = false;
|
||||||
waveBuffersSpan[i].BufferAddressInfo.Setup(0, 0);
|
WaveBuffers[i].BufferAddressInfo.Setup(0, 0);
|
||||||
waveBuffersSpan[i].ContextAddressInfo.Setup(0, 0);
|
WaveBuffers[i].ContextAddressInfo.Setup(0, 0);
|
||||||
waveBuffersSpan[i].IsSendToAudioProcessor = true;
|
WaveBuffers[i].IsSendToAudioProcessor = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,12 +447,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
|
|
||||||
ref VoiceUpdateState voiceUpdateState = ref voiceUpdateStates[0].Span[0];
|
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++)
|
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>
|
/// <param name="context">The voice context.</param>
|
||||||
private void ResetResources(VoiceContext context)
|
private void ResetResources(VoiceContext context)
|
||||||
{
|
{
|
||||||
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < ChannelsCount; i++)
|
for (int i = 0; i < ChannelsCount; i++)
|
||||||
{
|
{
|
||||||
int channelResourceId = channelResourceIdsSpan[i];
|
int channelResourceId = ChannelResourceIds[i];
|
||||||
|
|
||||||
ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId);
|
ref VoiceChannelResource voiceChannelResource = ref context.GetChannelResource(channelResourceId);
|
||||||
|
|
||||||
@@ -567,11 +560,9 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
{
|
{
|
||||||
uint waveBufferIndex = WaveBuffersIndex;
|
uint waveBufferIndex = WaveBuffersIndex;
|
||||||
|
|
||||||
Span<WaveBuffer> waveBuffersSpan = WaveBuffers.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < waveBufferCount; i++)
|
for (int i = 0; i < waveBufferCount; i++)
|
||||||
{
|
{
|
||||||
waveBuffersSpan[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
WaveBuffers[(int)waveBufferIndex].IsSendToAudioProcessor = true;
|
||||||
|
|
||||||
for (int j = 0; j < channelCount; j++)
|
for (int j = 0; j < channelCount; j++)
|
||||||
{
|
{
|
||||||
@@ -600,18 +591,14 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
FlushWaveBufferCount = 0;
|
FlushWaveBufferCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<WaveBuffer> waveBuffersSpan;
|
|
||||||
|
|
||||||
switch (PlayState)
|
switch (PlayState)
|
||||||
{
|
{
|
||||||
case PlayState.Started:
|
case PlayState.Started:
|
||||||
waveBuffersSpan = WaveBuffers.AsSpan();
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
|
|
||||||
for (int i = 0; i < waveBuffersSpan.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++)
|
for (int y = 0; y < ChannelsCount; y++)
|
||||||
{
|
{
|
||||||
@@ -620,7 +607,7 @@ namespace Ryujinx.Audio.Renderer.Server.Voice
|
|||||||
voiceUpdateStates[y].Span[0].IsWaveBufferValid[i] = true;
|
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;
|
return false;
|
||||||
|
|
||||||
case PlayState.Stopping:
|
case PlayState.Stopping:
|
||||||
waveBuffersSpan = WaveBuffers.AsSpan();
|
for (int i = 0; i < WaveBuffers.Length; i++)
|
||||||
|
|
||||||
for (int i = 0; i < waveBuffersSpan.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++)
|
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];
|
Memory<VoiceUpdateState>[] voiceUpdateStates = new Memory<VoiceUpdateState>[Constants.VoiceChannelCountMax];
|
||||||
|
|
||||||
Span<int> channelResourceIdsSpan = ChannelResourceIds.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < ChannelsCount; i++)
|
for (int i = 0; i < ChannelsCount; i++)
|
||||||
{
|
{
|
||||||
voiceUpdateStates[i] = context.GetUpdateStateForDsp(channelResourceIdsSpan[i]);
|
voiceUpdateStates[i] = context.GetUpdateStateForDsp(ChannelResourceIds[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UpdateParametersForCommandGeneration(voiceUpdateStates);
|
return UpdateParametersForCommandGeneration(voiceUpdateStates);
|
||||||
|
@@ -33,7 +33,7 @@ namespace Ryujinx.BuildValidationTasks
|
|||||||
LocalesJson json;
|
LocalesJson json;
|
||||||
|
|
||||||
if (isGitRunner && data.Contains("\r\n"))
|
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
|
try
|
||||||
{
|
{
|
||||||
@@ -86,7 +86,7 @@ namespace Ryujinx.BuildValidationTasks
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isGitRunner && encounteredIssue)
|
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);
|
string jsonString = JsonSerializer.Serialize(json, _jsonOptions);
|
||||||
|
|
||||||
@@ -102,7 +102,6 @@ namespace Ryujinx.BuildValidationTasks
|
|||||||
|
|
||||||
struct LocalesJson
|
struct LocalesJson
|
||||||
{
|
{
|
||||||
public Dictionary<string, string> Info { get; set; }
|
|
||||||
public List<string> Languages { get; set; }
|
public List<string> Languages { get; set; }
|
||||||
public List<LocalesEntry> Locales { get; set; }
|
public List<LocalesEntry> Locales { get; set; }
|
||||||
}
|
}
|
||||||
|
@@ -11,17 +11,7 @@
|
|||||||
Command="dotnet Ryujinx.BuildValidationTasks.dll "$(ProjectDir)..\..\\""
|
Command="dotnet Ryujinx.BuildValidationTasks.dll "$(ProjectDir)..\..\\""
|
||||||
ConsoleToMsBuild="true"
|
ConsoleToMsBuild="true"
|
||||||
Condition="'$(RuntimeIdentifier)' == ''"
|
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'"/>
|
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@@ -14,13 +14,12 @@ namespace Ryujinx.Common.Collections
|
|||||||
/// Adds a new node into the tree.
|
/// Adds a new node into the tree.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node">Node to be added</param>
|
/// <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>
|
/// <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);
|
ArgumentNullException.ThrowIfNull(node);
|
||||||
|
|
||||||
Insert(node, parent);
|
Insert(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -77,11 +76,9 @@ namespace Ryujinx.Common.Collections
|
|||||||
/// Inserts a new node into the tree.
|
/// Inserts a new node into the tree.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="node">Node to be inserted</param>
|
/// <param name="node">Node to be inserted</param>
|
||||||
/// <param name="parent">Node to be inserted under</param>
|
private void Insert(T node)
|
||||||
private void Insert(T node, T parent = null)
|
|
||||||
{
|
{
|
||||||
T newNode = parent != null ? InsertWithParent(node, parent) : BSTInsert(node);
|
T newNode = BSTInsert(node);
|
||||||
|
|
||||||
RestoreBalanceAfterInsertion(newNode);
|
RestoreBalanceAfterInsertion(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,77 +122,10 @@ namespace Ryujinx.Common.Collections
|
|||||||
else if (newNode.CompareTo(parent) < 0)
|
else if (newNode.CompareTo(parent) < 0)
|
||||||
{
|
{
|
||||||
parent.Left = newNode;
|
parent.Left = newNode;
|
||||||
|
|
||||||
newNode.Successor = parent;
|
|
||||||
|
|
||||||
if (parent.Predecessor != null)
|
|
||||||
{
|
|
||||||
newNode.Predecessor = parent.Predecessor;
|
|
||||||
newNode.Predecessor.Successor = newNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.Predecessor = newNode;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
parent.Right = newNode;
|
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++;
|
Count++;
|
||||||
@@ -229,7 +159,7 @@ namespace Ryujinx.Common.Collections
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
T element = nodeToDelete.Successor;
|
T element = Minimum(RightOf(nodeToDelete));
|
||||||
|
|
||||||
child = RightOf(element);
|
child = RightOf(element);
|
||||||
parent = ParentOf(element);
|
parent = ParentOf(element);
|
||||||
@@ -257,9 +187,6 @@ namespace Ryujinx.Common.Collections
|
|||||||
element.Left = old.Left;
|
element.Left = old.Left;
|
||||||
element.Right = old.Right;
|
element.Right = old.Right;
|
||||||
element.Parent = old.Parent;
|
element.Parent = old.Parent;
|
||||||
element.Predecessor = old.Predecessor;
|
|
||||||
if (element.Predecessor != null)
|
|
||||||
element.Predecessor.Successor = element;
|
|
||||||
|
|
||||||
if (ParentOf(old) == null)
|
if (ParentOf(old) == null)
|
||||||
{
|
{
|
||||||
@@ -315,11 +242,6 @@ namespace Ryujinx.Common.Collections
|
|||||||
RestoreBalanceAfterRemoval(child);
|
RestoreBalanceAfterRemoval(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old.Successor != null)
|
|
||||||
old.Successor.Predecessor = old.Predecessor;
|
|
||||||
if (old.Predecessor != null)
|
|
||||||
old.Predecessor.Successor = old.Successor;
|
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,7 +9,8 @@ namespace Ryujinx.Common.Collections
|
|||||||
public T Left;
|
public T Left;
|
||||||
public T Right;
|
public T Right;
|
||||||
public T Parent;
|
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);
|
Node<TKey, TValue> node = GetNode(key);
|
||||||
if (node != null)
|
if (node != null)
|
||||||
{
|
{
|
||||||
Node<TKey, TValue> successor = node.Successor;
|
Node<TKey, TValue> successor = SuccessorOf(node);
|
||||||
|
|
||||||
return successor != null ? successor.Key : default;
|
return successor != null ? successor.Key : default;
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ namespace Ryujinx.Common.Collections
|
|||||||
Node<TKey, TValue> node = GetNode(key);
|
Node<TKey, TValue> node = GetNode(key);
|
||||||
if (node != null)
|
if (node != null)
|
||||||
{
|
{
|
||||||
Node<TKey, TValue> predecessor = node.Predecessor;
|
Node<TKey, TValue> predecessor = PredecessorOf(node);
|
||||||
|
|
||||||
return predecessor != null ? predecessor.Key : default;
|
return predecessor != null ? predecessor.Key : default;
|
||||||
}
|
}
|
||||||
@@ -136,10 +136,11 @@ namespace Ryujinx.Common.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// <br></br>
|
||||||
/// The key/value pairs will be added in Level Order.
|
/// The key/value pairs will be added in Level Order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="list">List to add the tree pairs into</param>
|
||||||
public List<KeyValuePair<TKey, TValue>> AsLevelOrderList()
|
public List<KeyValuePair<TKey, TValue>> AsLevelOrderList()
|
||||||
{
|
{
|
||||||
List<KeyValuePair<TKey, TValue>> list = [];
|
List<KeyValuePair<TKey, TValue>> list = [];
|
||||||
@@ -169,7 +170,7 @@ namespace Ryujinx.Common.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds all the nodes in the dictionary into a list.
|
/// Adds all the nodes in the dictionary into <paramref name="list"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of all KeyValuePairs sorted by Key Order</returns>
|
/// <returns>A list of all KeyValuePairs sorted by Key Order</returns>
|
||||||
public List<KeyValuePair<TKey, TValue>> AsList()
|
public List<KeyValuePair<TKey, TValue>> AsList()
|
||||||
@@ -283,7 +284,7 @@ namespace Ryujinx.Common.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
Node<TKey, TValue> newNode = new(key, value, parent);
|
Node<TKey, TValue> newNode = new(key, value, parent);
|
||||||
if (parent == null)
|
if (newNode.Parent == null)
|
||||||
{
|
{
|
||||||
Root = newNode;
|
Root = newNode;
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,6 @@ namespace Ryujinx.Common.Logging
|
|||||||
Cpu,
|
Cpu,
|
||||||
Emulation,
|
Emulation,
|
||||||
FFmpeg,
|
FFmpeg,
|
||||||
GdbStub,
|
|
||||||
Font,
|
Font,
|
||||||
Gpu,
|
Gpu,
|
||||||
Hid,
|
Hid,
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Memory
|
namespace Ryujinx.Common.Memory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -19,10 +17,5 @@ namespace Ryujinx.Common.Memory
|
|||||||
/// Number of elements on the array.
|
/// Number of elements on the array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int Length { get; }
|
int Length { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Number of elements on the array.
|
|
||||||
/// </summary>
|
|
||||||
public Span<T> AsSpan();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -11,126 +10,11 @@ namespace Ryujinx.Common.Memory
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
|
/// 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>
|
/// </summary>
|
||||||
/// <typeparam name="T">The type of item to store.</typeparam>
|
/// <typeparam name="T">The type of item to store.</typeparam>
|
||||||
public sealed class MemoryOwner<T> : IMemoryOwner<T>
|
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 readonly int _length;
|
||||||
private T[]? _array;
|
private T[]? _array;
|
||||||
|
|
||||||
@@ -141,7 +25,7 @@ namespace Ryujinx.Common.Memory
|
|||||||
private MemoryOwner(int length)
|
private MemoryOwner(int length)
|
||||||
{
|
{
|
||||||
_length = length;
|
_length = length;
|
||||||
_array = ArrayPooling.Get(length);
|
_array = ArrayPool<T>.Shared.Rent(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -240,7 +124,7 @@ namespace Ryujinx.Common.Memory
|
|||||||
|
|
||||||
if (array is not null)
|
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.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||||
@@ -44,12 +43,9 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||||||
{
|
{
|
||||||
// Try get a match first.
|
// Try get a match first.
|
||||||
|
|
||||||
Span<int> threadIdsSpan = ThreadIds.AsSpan();
|
|
||||||
Span<T> structsSpan = Structs.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < MapSize; i++)
|
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)
|
if (compare == threadId)
|
||||||
{
|
{
|
||||||
@@ -61,11 +57,11 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||||||
|
|
||||||
for (int i = 0; i < MapSize; i++)
|
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)
|
if (compare == 0)
|
||||||
{
|
{
|
||||||
structsSpan[i] = initial;
|
Structs[i] = initial;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,18 +2,8 @@ namespace Ryujinx.Common
|
|||||||
{
|
{
|
||||||
public static class SharedConstants
|
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 short LanPlayPort = 30456;
|
||||||
public const string DefaultLanPlayWebHost = DefaultLanPlayHost;
|
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
||||||
|
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -93,7 +93,6 @@ namespace Ryujinx.Common
|
|||||||
//The Pokémon Franchise
|
//The Pokémon Franchise
|
||||||
"0100f4300bf2c000", // New Pokémon Snap
|
"0100f4300bf2c000", // New Pokémon Snap
|
||||||
"0100000011d90000", // Pokémon Brilliant Diamond
|
"0100000011d90000", // Pokémon Brilliant Diamond
|
||||||
"010008c01e742000", // Pokémon Friends
|
|
||||||
"01001f5010dfa000", // Pokémon Legends: Arceus
|
"01001f5010dfa000", // Pokémon Legends: Arceus
|
||||||
"01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX
|
"01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX
|
||||||
"0100a3d008c5c000", // Pokémon Scarlet
|
"0100a3d008c5c000", // Pokémon Scarlet
|
||||||
@@ -134,6 +133,7 @@ namespace Ryujinx.Common
|
|||||||
"0100c1f0051b6000", // Donkey Kong Country: Tropical Freeze
|
"0100c1f0051b6000", // Donkey Kong Country: Tropical Freeze
|
||||||
"0100ed000d390000", // Dr. Kawashima's Brain Training
|
"0100ed000d390000", // Dr. Kawashima's Brain Training
|
||||||
"010067b017588000", // Endless Ocean Luminous
|
"010067b017588000", // Endless Ocean Luminous
|
||||||
|
"0100d2f00d5c0000", // Nintendo Switch Sports
|
||||||
"01006b5012b32000", // Part Time UFO
|
"01006b5012b32000", // Part Time UFO
|
||||||
"0100704000B3A000", // Snipperclips
|
"0100704000B3A000", // Snipperclips
|
||||||
"01006a800016e000", // Super Smash Bros. Ultimate
|
"01006a800016e000", // Super Smash Bros. Ultimate
|
||||||
@@ -169,8 +169,6 @@ namespace Ryujinx.Common
|
|||||||
"010056e00853a000", // A Hat in Time
|
"010056e00853a000", // A Hat in Time
|
||||||
"0100fd1014726000", // Baldurs Gate: Dark Alliance
|
"0100fd1014726000", // Baldurs Gate: Dark Alliance
|
||||||
"01008c2019598000", // Bluey: The Video Game
|
"01008c2019598000", // Bluey: The Video Game
|
||||||
"010096f00ff22000", // Borderlands 2: Game of the Year Edition
|
|
||||||
"010007400ff24000", // Borderlands: The Pre-Sequel Ultimate Edition
|
|
||||||
"0100c6800b934000", // Brawlhalla
|
"0100c6800b934000", // Brawlhalla
|
||||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
"0100dbf01000a000", // Burnout Paradise Remastered
|
||||||
"0100744001588000", // Cars 3: Driven to Win
|
"0100744001588000", // Cars 3: Driven to Win
|
||||||
@@ -182,7 +180,6 @@ namespace Ryujinx.Common
|
|||||||
"01001cc01b2d4000", // Goat Simulator 3
|
"01001cc01b2d4000", // Goat Simulator 3
|
||||||
"01003620068ea000", // Hand of Fate 2
|
"01003620068ea000", // Hand of Fate 2
|
||||||
"0100f7e00c70e000", // Hogwarts Legacy
|
"0100f7e00c70e000", // Hogwarts Legacy
|
||||||
"010013c00e930000", // Hollow Knight: Silksong
|
|
||||||
"010085500130a000", // Lego City: Undercover
|
"010085500130a000", // Lego City: Undercover
|
||||||
"010073c01af34000", // LEGO Horizon Adventures
|
"010073c01af34000", // LEGO Horizon Adventures
|
||||||
"0100d71004694000", // Minecraft
|
"0100d71004694000", // Minecraft
|
||||||
@@ -197,7 +194,6 @@ namespace Ryujinx.Common
|
|||||||
"01008d100d43e000", // Saints Row IV
|
"01008d100d43e000", // Saints Row IV
|
||||||
"0100de600beee000", // Saints Row: The Third - The Full Package
|
"0100de600beee000", // Saints Row: The Third - The Full Package
|
||||||
"01001180021fa000", // Shovel Knight: Specter of Torment
|
"01001180021fa000", // Shovel Knight: Specter of Torment
|
||||||
"0100e1D01eb2e000", // Squeakross: Home Squeak Home
|
|
||||||
"0100e65002bb8000", // Stardew Valley
|
"0100e65002bb8000", // Stardew Valley
|
||||||
"0100d7a01b7a2000", // Star Wars: Bounty Hunter
|
"0100d7a01b7a2000", // Star Wars: Bounty Hunter
|
||||||
"0100800015926000", // Suika Game
|
"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
|
class HvExecutionContext : IExecutionContext
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ulong Pc
|
public ulong Pc => _impl.ElrEl1;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
uint currentEl = Pstate & ~((uint)ExceptionLevel.PstateMask);
|
|
||||||
if (currentEl == (uint)ExceptionLevel.EL1h)
|
|
||||||
{
|
|
||||||
return _impl.ElrEl1;
|
|
||||||
}
|
|
||||||
return _impl.Pc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public long TpidrEl0
|
public long TpidrEl0
|
||||||
@@ -59,9 +48,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
set => _impl.Fpsr = value;
|
set => _impl.Fpsr = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public ulong ThreadUid { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool IsAarch32
|
public bool IsAarch32
|
||||||
{
|
{
|
||||||
@@ -81,7 +67,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
private readonly ICounter _counter;
|
private readonly ICounter _counter;
|
||||||
private readonly IHvExecutionContext _shadowContext;
|
private readonly IHvExecutionContext _shadowContext;
|
||||||
private IHvExecutionContext _impl;
|
private IHvExecutionContext _impl;
|
||||||
private int _shouldStep;
|
|
||||||
|
|
||||||
private readonly ExceptionCallbacks _exceptionCallbacks;
|
private readonly ExceptionCallbacks _exceptionCallbacks;
|
||||||
|
|
||||||
@@ -118,11 +103,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
_exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
|
_exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StepHandler()
|
|
||||||
{
|
|
||||||
_exceptionCallbacks.StepCallback?.Invoke(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SupervisorCallHandler(ulong address, int imm)
|
private void SupervisorCallHandler(ulong address, int imm)
|
||||||
{
|
{
|
||||||
_exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
|
_exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
|
||||||
@@ -147,30 +127,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
|
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/>
|
/// <inheritdoc/>
|
||||||
public void StopRunning()
|
public void StopRunning()
|
||||||
{
|
{
|
||||||
@@ -186,22 +142,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
|
|
||||||
while (Running)
|
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();
|
HvApi.hv_vcpu_run(vcpu.Handle).ThrowOnError();
|
||||||
|
|
||||||
HvExitReason reason = vcpu.ExitInfo->Reason;
|
HvExitReason reason = vcpu.ExitInfo->Reason;
|
||||||
@@ -269,20 +209,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
SupervisorCallHandler(elr - 4UL, id);
|
SupervisorCallHandler(elr - 4UL, id);
|
||||||
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
vcpu = RentFromPool(memoryManager.AddressSpace, vcpu);
|
||||||
break;
|
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:
|
default:
|
||||||
throw new Exception($"Unhandled guest exception {ec}.");
|
throw new Exception($"Unhandled guest exception {ec}.");
|
||||||
}
|
}
|
||||||
@@ -293,8 +219,11 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
// TODO: Invalidate only the range that was modified?
|
// TODO: Invalidate only the range that was modified?
|
||||||
return HvAddressSpace.KernelRegionTlbiEretAddress;
|
return HvAddressSpace.KernelRegionTlbiEretAddress;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return HvAddressSpace.KernelRegionEretAddress;
|
return HvAddressSpace.KernelRegionEretAddress;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void DataAbort(MemoryTracking tracking, ulong vcpu, uint esr)
|
private static void DataAbort(MemoryTracking tracking, ulong vcpu, uint esr)
|
||||||
{
|
{
|
||||||
|
@@ -18,8 +18,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
|
|
||||||
public bool IsAarch32 { get; set; }
|
public bool IsAarch32 { get; set; }
|
||||||
|
|
||||||
public ulong ThreadUid { get; set; }
|
|
||||||
|
|
||||||
private readonly ulong[] _x;
|
private readonly ulong[] _x;
|
||||||
private readonly V128[] _v;
|
private readonly V128[] _v;
|
||||||
|
|
||||||
@@ -48,14 +46,5 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
{
|
{
|
||||||
_v[index] = value;
|
_v[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RequestInterrupt()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetAndClearInterruptRequested()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,6 @@ using ARMeilleure.State;
|
|||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
@@ -14,8 +13,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
private static readonly SetSimdFpReg _setSimdFpReg;
|
private static readonly SetSimdFpReg _setSimdFpReg;
|
||||||
private static readonly nint _setSimdFpRegNativePtr;
|
private static readonly nint _setSimdFpRegNativePtr;
|
||||||
|
|
||||||
public ulong ThreadUid { get; set; }
|
|
||||||
|
|
||||||
static HvExecutionContextVcpu()
|
static HvExecutionContextVcpu()
|
||||||
{
|
{
|
||||||
// .NET does not support passing vectors by value, so we need to pass a pointer and use a native
|
// .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 readonly ulong _vcpu;
|
||||||
private int _interruptRequested;
|
|
||||||
|
|
||||||
public HvExecutionContextVcpu(ulong vcpu)
|
public HvExecutionContextVcpu(ulong vcpu)
|
||||||
{
|
{
|
||||||
@@ -183,17 +179,9 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void RequestInterrupt()
|
public void RequestInterrupt()
|
||||||
{
|
|
||||||
if (Interlocked.Exchange(ref _interruptRequested, 1) == 0)
|
|
||||||
{
|
{
|
||||||
ulong vcpu = _vcpu;
|
ulong vcpu = _vcpu;
|
||||||
HvApi.hv_vcpus_exit(ref vcpu, 1);
|
HvApi.hv_vcpus_exit(ref vcpu, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool GetAndClearInterruptRequested()
|
|
||||||
{
|
|
||||||
return Interlocked.Exchange(ref _interruptRequested, 0) != 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,6 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
|
|
||||||
uint Fpcr { get; set; }
|
uint Fpcr { get; set; }
|
||||||
uint Fpsr { get; set; }
|
uint Fpsr { get; set; }
|
||||||
ulong ThreadUid { get; set; }
|
|
||||||
|
|
||||||
ulong GetX(int index);
|
ulong GetX(int index);
|
||||||
void SetX(int index, ulong value);
|
void SetX(int index, ulong value);
|
||||||
@@ -40,8 +39,5 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
SetV(i, context.GetV(i));
|
SetV(i, context.GetV(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestInterrupt();
|
|
||||||
bool GetAndClearInterruptRequested();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,11 +29,6 @@ namespace Ryujinx.Cpu
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly ExceptionCallback BreakCallback;
|
public readonly ExceptionCallback BreakCallback;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handler for CPU software interrupts caused by single-stepping.
|
|
||||||
/// </summary>
|
|
||||||
public readonly ExceptionCallbackNoArgs StepCallback;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for CPU software interrupts caused by the Arm SVC instruction.
|
/// Handler for CPU software interrupts caused by the Arm SVC instruction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -52,19 +47,16 @@ namespace Ryujinx.Cpu
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="interruptCallback">Handler for CPU interrupts triggered using <see cref="IExecutionContext.RequestInterrupt"/></param>
|
/// <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="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="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>
|
/// <param name="undefinedCallback">Handler for CPU software interrupts caused by any undefined Arm instruction</param>
|
||||||
public ExceptionCallbacks(
|
public ExceptionCallbacks(
|
||||||
ExceptionCallbackNoArgs interruptCallback = null,
|
ExceptionCallbackNoArgs interruptCallback = null,
|
||||||
ExceptionCallback breakCallback = null,
|
ExceptionCallback breakCallback = null,
|
||||||
ExceptionCallbackNoArgs stepCallback = null,
|
|
||||||
ExceptionCallback supervisorCallback = null,
|
ExceptionCallback supervisorCallback = null,
|
||||||
ExceptionCallback undefinedCallback = null)
|
ExceptionCallback undefinedCallback = null)
|
||||||
{
|
{
|
||||||
InterruptCallback = interruptCallback;
|
InterruptCallback = interruptCallback;
|
||||||
BreakCallback = breakCallback;
|
BreakCallback = breakCallback;
|
||||||
StepCallback = stepCallback;
|
|
||||||
SupervisorCallback = supervisorCallback;
|
SupervisorCallback = supervisorCallback;
|
||||||
UndefinedCallback = undefinedCallback;
|
UndefinedCallback = undefinedCallback;
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu
|
namespace Ryujinx.Cpu
|
||||||
{
|
{
|
||||||
@@ -47,11 +46,6 @@ namespace Ryujinx.Cpu
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsAarch32 { get; set; }
|
bool IsAarch32 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Thread UID.
|
|
||||||
/// </summary>
|
|
||||||
public ulong ThreadUid { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates whenever the CPU is still running code.
|
/// Indicates whenever the CPU is still running code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -114,23 +108,5 @@ namespace Ryujinx.Cpu
|
|||||||
/// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead.
|
/// If you only need to pause the thread temporarily, use <see cref="RequestInterrupt"/> instead.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
void StopRunning();
|
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.Memory;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ExecutionContext = ARMeilleure.State.ExecutionContext;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.Jit
|
namespace Ryujinx.Cpu.Jit
|
||||||
{
|
{
|
||||||
@@ -54,13 +53,6 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
set => _impl.IsAarch32 = value;
|
set => _impl.IsAarch32 = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public ulong ThreadUid
|
|
||||||
{
|
|
||||||
get => _impl.ThreadUid;
|
|
||||||
set => _impl.ThreadUid = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool Running => _impl.Running;
|
public bool Running => _impl.Running;
|
||||||
|
|
||||||
@@ -73,7 +65,6 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
counter,
|
counter,
|
||||||
InterruptHandler,
|
InterruptHandler,
|
||||||
BreakHandler,
|
BreakHandler,
|
||||||
StepHandler,
|
|
||||||
SupervisorCallHandler,
|
SupervisorCallHandler,
|
||||||
UndefinedHandler);
|
UndefinedHandler);
|
||||||
|
|
||||||
@@ -102,11 +93,6 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
_exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
|
_exceptionCallbacks.BreakCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StepHandler(ExecutionContext context)
|
|
||||||
{
|
|
||||||
_exceptionCallbacks.StepCallback?.Invoke(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SupervisorCallHandler(ExecutionContext context, ulong address, int imm)
|
private void SupervisorCallHandler(ExecutionContext context, ulong address, int imm)
|
||||||
{
|
{
|
||||||
_exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
|
_exceptionCallbacks.SupervisorCallback?.Invoke(this, address, imm);
|
||||||
@@ -123,16 +109,6 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
_impl.RequestInterrupt();
|
_impl.RequestInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void RequestDebugStep() => _impl.RequestDebugStep();
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public ulong DebugPc
|
|
||||||
{
|
|
||||||
get => _impl.DebugPc;
|
|
||||||
set => _impl.DebugPc = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void StopRunning()
|
public void StopRunning()
|
||||||
{
|
{
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
using ARMeilleure;
|
|
||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.LightningJit.State
|
namespace Ryujinx.Cpu.LightningJit.State
|
||||||
{
|
{
|
||||||
@@ -54,8 +52,6 @@ namespace Ryujinx.Cpu.LightningJit.State
|
|||||||
|
|
||||||
public bool IsAarch32 { get; set; }
|
public bool IsAarch32 { get; set; }
|
||||||
|
|
||||||
public ulong ThreadUid { get; set; }
|
|
||||||
|
|
||||||
internal ExecutionMode ExecutionMode
|
internal ExecutionMode ExecutionMode
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -81,20 +77,15 @@ namespace Ryujinx.Cpu.LightningJit.State
|
|||||||
|
|
||||||
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||||
private readonly ExceptionCallback _breakCallback;
|
private readonly ExceptionCallback _breakCallback;
|
||||||
private readonly ExceptionCallbackNoArgs _stepCallback;
|
|
||||||
private readonly ExceptionCallback _supervisorCallback;
|
private readonly ExceptionCallback _supervisorCallback;
|
||||||
private readonly ExceptionCallback _undefinedCallback;
|
private readonly ExceptionCallback _undefinedCallback;
|
||||||
|
|
||||||
internal int ShouldStep;
|
|
||||||
public ulong DebugPc { get; set; }
|
|
||||||
|
|
||||||
public ExecutionContext(IJitMemoryAllocator allocator, ICounter counter, ExceptionCallbacks exceptionCallbacks)
|
public ExecutionContext(IJitMemoryAllocator allocator, ICounter counter, ExceptionCallbacks exceptionCallbacks)
|
||||||
{
|
{
|
||||||
_nativeContext = new NativeContext(allocator);
|
_nativeContext = new NativeContext(allocator);
|
||||||
_counter = counter;
|
_counter = counter;
|
||||||
_interruptCallback = exceptionCallbacks.InterruptCallback;
|
_interruptCallback = exceptionCallbacks.InterruptCallback;
|
||||||
_breakCallback = exceptionCallbacks.BreakCallback;
|
_breakCallback = exceptionCallbacks.BreakCallback;
|
||||||
_stepCallback = exceptionCallbacks.StepCallback;
|
|
||||||
_supervisorCallback = exceptionCallbacks.SupervisorCallback;
|
_supervisorCallback = exceptionCallbacks.SupervisorCallback;
|
||||||
_undefinedCallback = exceptionCallbacks.UndefinedCallback;
|
_undefinedCallback = exceptionCallbacks.UndefinedCallback;
|
||||||
|
|
||||||
@@ -126,17 +117,6 @@ namespace Ryujinx.Cpu.LightningJit.State
|
|||||||
_interrupted = true;
|
_interrupted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StepHandler()
|
|
||||||
{
|
|
||||||
_stepCallback?.Invoke(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RequestDebugStep()
|
|
||||||
{
|
|
||||||
Interlocked.Exchange(ref ShouldStep, 1);
|
|
||||||
RequestInterrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void OnBreak(ulong address, int imm)
|
internal void OnBreak(ulong address, int imm)
|
||||||
{
|
{
|
||||||
_breakCallback?.Invoke(this, address, imm);
|
_breakCallback?.Invoke(this, address, imm);
|
||||||
|
@@ -82,7 +82,15 @@ namespace Ryujinx.Graphics.Device
|
|||||||
{
|
{
|
||||||
uint alignedOffset = index * RegisterSize;
|
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;
|
return 0;
|
||||||
@@ -97,9 +105,9 @@ namespace Ryujinx.Graphics.Device
|
|||||||
uint alignedOffset = index * RegisterSize;
|
uint alignedOffset = index * RegisterSize;
|
||||||
DebugWrite(alignedOffset, data);
|
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;
|
uint alignedOffset = index * RegisterSize;
|
||||||
DebugWrite(alignedOffset, data);
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -152,24 +162,5 @@ namespace Ryujinx.Graphics.Device
|
|||||||
{
|
{
|
||||||
return ref Unsafe.Add(ref Unsafe.As<TState, int>(ref State), (nint)index);
|
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);
|
state.Write(LogicOpOffset, 0);
|
||||||
|
|
||||||
Array8<Boolean32> enable = new();
|
Array8<Boolean32> enable = new();
|
||||||
Span<Boolean32> enableSpan = enable.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
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>
|
/// <summary>
|
||||||
@@ -237,14 +236,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
private void UpdateColorMasks(IDeviceState state, int arg0)
|
private void UpdateColorMasks(IDeviceState state, int arg0)
|
||||||
{
|
{
|
||||||
Array8<RtColorMask> masks = new();
|
Array8<RtColorMask> masks = new();
|
||||||
Span<RtColorMask> masksSpan = masks.AsSpan();
|
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
masksSpan[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
masks[index++] = new RtColorMask((uint)arg0 & 0x1fff);
|
||||||
masksSpan[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
masks[index++] = new RtColorMask(((uint)arg0 >> 16) & 0x1fff);
|
||||||
|
|
||||||
if (i != 3)
|
if (i != 3)
|
||||||
{
|
{
|
||||||
@@ -252,7 +250,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_processor.ThreedClass.UpdateColorMasks(masksSpan);
|
_processor.ThreedClass.UpdateColorMasks(ref masks);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@@ -75,12 +75,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.Blender
|
|||||||
{
|
{
|
||||||
bool constantsMatch = true;
|
bool constantsMatch = true;
|
||||||
|
|
||||||
Span<RgbHalf> blendUcodeConstantsSpan = _state.State.BlendUcodeConstants.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < entry.Constants.Length; i++)
|
for (int i = 0; i < entry.Constants.Length; i++)
|
||||||
{
|
{
|
||||||
RgbFloat constant = entry.Constants[i];
|
RgbFloat constant = entry.Constants[i];
|
||||||
RgbHalf constant2 = blendUcodeConstantsSpan[i];
|
RgbHalf constant2 = _state.State.BlendUcodeConstants[i];
|
||||||
|
|
||||||
if ((Half)constant.R != constant2.UnpackR() ||
|
if ((Half)constant.R != constant2.UnpackR() ||
|
||||||
(Half)constant.G != constant2.UnpackG() ||
|
(Half)constant.G != constant2.UnpackG() ||
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Memory;
|
using Ryujinx.Graphics.Gpu.Memory;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
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>
|
/// <param name="componentCount">Number of components that the format has</param>
|
||||||
public void SetVertexStride(int index, int stride, int componentCount)
|
public void SetVertexStride(int index, int stride, int componentCount)
|
||||||
{
|
{
|
||||||
Span<Vector4<int>> vertexStridesSpan = _data.VertexStrides.AsSpan();
|
if (_data.VertexStrides[index].X != stride)
|
||||||
|
|
||||||
if (vertexStridesSpan[index].X != stride)
|
|
||||||
{
|
{
|
||||||
vertexStridesSpan[index].X = stride;
|
_data.VertexStrides[index].X = stride;
|
||||||
MarkDirty(VertexInfoBuffer.VertexStridesOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
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;
|
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)
|
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>
|
/// <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)
|
public void SetVertexOffset(int index, int offset, int divisor)
|
||||||
{
|
{
|
||||||
Span<Vector4<int>> vertexOffsetsSpan = _data.VertexOffsets.AsSpan();
|
if (_data.VertexOffsets[index].X != offset)
|
||||||
|
|
||||||
if (vertexOffsetsSpan[index].X != offset)
|
|
||||||
{
|
{
|
||||||
vertexOffsetsSpan[index].X = offset;
|
_data.VertexOffsets[index].X = offset;
|
||||||
MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf<Vector4<int>>(), sizeof(int));
|
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));
|
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.SetVertexCounts(_count, _instanceCount, _firstVertex, _firstInstance);
|
||||||
_vacContext.VertexInfoBufferUpdater.SetGeometryCounts(primitivesCount);
|
_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++)
|
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))
|
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();
|
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
||||||
|
|
||||||
GpuVa endAddress = vertexBufferEndAddressSpan[bufferIndex];
|
GpuVa endAddress = _state.State.VertexBufferEndAddress[bufferIndex];
|
||||||
VertexBufferState vertexBuffer = vertexBufferStateSpan[bufferIndex];
|
VertexBufferState vertexBuffer = _state.State.VertexBufferState[bufferIndex];
|
||||||
bool instanced = vertexBufferInstancedSpan[bufferIndex];
|
bool instanced = _state.State.VertexBufferInstanced[bufferIndex];
|
||||||
|
|
||||||
ulong address = vertexBuffer.Address.Pack();
|
ulong address = vertexBuffer.Address.Pack();
|
||||||
|
|
||||||
|
@@ -822,8 +822,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
// host clipping.
|
// host clipping.
|
||||||
ScreenScissorState screenScissorState = _state.State.ScreenScissorState;
|
ScreenScissorState screenScissorState = _state.State.ScreenScissorState;
|
||||||
|
|
||||||
Span<ScissorState> scissorStateSpan = _state.State.ScissorState.AsSpan();
|
|
||||||
|
|
||||||
bool clearAffectedByStencilMask = (_state.State.ClearFlags & 1) != 0;
|
bool clearAffectedByStencilMask = (_state.State.ClearFlags & 1) != 0;
|
||||||
bool clearAffectedByScissor = (_state.State.ClearFlags & 0x100) != 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;
|
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 &&
|
fullClear = scissorState.X1 == screenScissorState.X &&
|
||||||
scissorState.Y1 == screenScissorState.Y &&
|
scissorState.Y1 == screenScissorState.Y &&
|
||||||
@@ -894,9 +892,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
int scissorW = screenScissorState.Width;
|
int scissorW = screenScissorState.Width;
|
||||||
int scissorH = screenScissorState.Height;
|
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);
|
scissorX = Math.Max(scissorX, scissorState.X1);
|
||||||
scissorY = Math.Max(scissorY, scissorState.Y1);
|
scissorY = Math.Max(scissorY, scissorState.Y1);
|
||||||
|
@@ -3,7 +3,6 @@ using Ryujinx.Graphics.GAL;
|
|||||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
using Ryujinx.Graphics.Gpu.Shader;
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
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.
|
/// Updates the type of the vertex attributes consumed by the shader.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state">The new state</param>
|
/// <param name="state">The new state</param>
|
||||||
public void SetAttributeTypes(ReadOnlySpan<VertexAttribState> state)
|
public void SetAttributeTypes(ref Array32<VertexAttribState> state)
|
||||||
{
|
{
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
// ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
|
||||||
Span<AttributeType> attributeTypesSpan = _graphics.AttributeTypes.AsSpan();
|
|
||||||
bool mayConvertVtgToCompute = ShaderCache.MayConvertVtgToCompute(ref _context.Capabilities);
|
bool mayConvertVtgToCompute = ShaderCache.MayConvertVtgToCompute(ref _context.Capabilities);
|
||||||
bool supportsScaledFormats = _context.Capabilities.SupportsScaledVertexFormats && !mayConvertVtgToCompute;
|
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;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,13 +279,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="rtControl">The render target control register</param>
|
/// <param name="rtControl">The render target control register</param>
|
||||||
/// <param name="state">The color attachment state</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;
|
bool changed = false;
|
||||||
int count = rtControl.UnpackCount();
|
int count = rtControl.UnpackCount();
|
||||||
|
|
||||||
Span<AttributeType> fragmentOutputTypesSpan = _graphics.FragmentOutputTypes.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
int rtIndex = rtControl.UnpackPermutationIndex(index);
|
int rtIndex = rtControl.UnpackPermutationIndex(index);
|
||||||
@@ -300,9 +296,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
AttributeType type = format.IsInteger() ? (format.IsSint() ? AttributeType.Sint : AttributeType.Uint) : AttributeType.Float;
|
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;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -109,7 +109,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
if (index < BlockSize)
|
if (index < BlockSize)
|
||||||
{
|
{
|
||||||
int groupIndex = _registerToGroupMapping[index];
|
int groupIndex = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(_registerToGroupMapping), (nint)index);
|
||||||
if (groupIndex != 0)
|
if (groupIndex != 0)
|
||||||
{
|
{
|
||||||
groupIndex--;
|
groupIndex--;
|
||||||
|
@@ -423,11 +423,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateTfBufferState()
|
private void UpdateTfBufferState()
|
||||||
{
|
{
|
||||||
Span<TfBufferState> tfBufferStateSpan = _state.State.TfBufferState.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
for (int index = 0; index < Constants.TotalTransformFeedbackBuffers; index++)
|
||||||
{
|
{
|
||||||
TfBufferState tfb = tfBufferStateSpan[index];
|
TfBufferState tfb = _state.State.TfBufferState[index];
|
||||||
|
|
||||||
if (!tfb.Enable)
|
if (!tfb.Enable)
|
||||||
{
|
{
|
||||||
@@ -468,10 +466,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
MemoryManager memoryManager = _channel.MemoryManager;
|
MemoryManager memoryManager = _channel.MemoryManager;
|
||||||
RtControl rtControl = _state.State.RtControl;
|
RtControl rtControl = _state.State.RtControl;
|
||||||
|
|
||||||
bool useControl = (updateFlags & RenderTargetUpdateFlags.UseControl) == RenderTargetUpdateFlags.UseControl;
|
bool useControl = updateFlags.HasFlag(RenderTargetUpdateFlags.UseControl);
|
||||||
bool layered = (updateFlags & RenderTargetUpdateFlags.Layered) == RenderTargetUpdateFlags.Layered;
|
bool layered = updateFlags.HasFlag(RenderTargetUpdateFlags.Layered);
|
||||||
bool singleColor = (updateFlags & RenderTargetUpdateFlags.SingleColor) == RenderTargetUpdateFlags.SingleColor;
|
bool singleColor = updateFlags.HasFlag(RenderTargetUpdateFlags.SingleColor);
|
||||||
bool discard = (updateFlags & RenderTargetUpdateFlags.DiscardClip) == RenderTargetUpdateFlags.DiscardClip;
|
bool discard = updateFlags.HasFlag(RenderTargetUpdateFlags.DiscardClip);
|
||||||
|
|
||||||
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
|
int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
|
||||||
|
|
||||||
@@ -489,13 +487,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
bool changedScale = false;
|
bool changedScale = false;
|
||||||
uint rtNoAlphaMask = 0;
|
uint rtNoAlphaMask = 0;
|
||||||
|
|
||||||
Span<RtColorState> rtColorStateSpan = _state.State.RtColorState.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
int rtIndex = useControl ? rtControl.UnpackPermutationIndex(index) : 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))
|
if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
|
||||||
{
|
{
|
||||||
@@ -543,7 +539,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
Image.Texture depthStencil = null;
|
Image.Texture depthStencil = null;
|
||||||
|
|
||||||
if (dsEnable && (updateFlags & RenderTargetUpdateFlags.UpdateDepthStencil) == RenderTargetUpdateFlags.UpdateDepthStencil)
|
if (dsEnable && updateFlags.HasFlag(RenderTargetUpdateFlags.UpdateDepthStencil))
|
||||||
{
|
{
|
||||||
RtDepthStencilState dsState = _state.State.RtDepthStencilState;
|
RtDepthStencilState dsState = _state.State.RtDepthStencilState;
|
||||||
Size3D dsSize = _state.State.RtDepthStencilSize;
|
Size3D dsSize = _state.State.RtDepthStencilSize;
|
||||||
@@ -603,7 +599,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateRenderTargetSpecialization()
|
public void UpdateRenderTargetSpecialization()
|
||||||
{
|
{
|
||||||
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, _state.State.RtColorState.AsSpan());
|
_currentSpecState.SetFragmentOutputTypes(_state.State.RtControl, ref _state.State.RtColorState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -628,11 +624,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
const int MaxH = 0xffff;
|
const int MaxH = 0xffff;
|
||||||
|
|
||||||
Span<Rectangle<int>> regions = stackalloc Rectangle<int>[Constants.TotalViewports];
|
Span<Rectangle<int>> regions = stackalloc Rectangle<int>[Constants.TotalViewports];
|
||||||
Span<ScissorState> scissorStateSpan = _state.State.ScissorState.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalViewports; index++)
|
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 ||
|
bool enable = scissor.Enable && (scissor.X1 != MinX ||
|
||||||
scissor.Y1 != MinY ||
|
scissor.Y1 != MinY ||
|
||||||
@@ -736,8 +731,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
UpdateDepthMode();
|
UpdateDepthMode();
|
||||||
|
|
||||||
Span<Viewport> viewports = stackalloc Viewport[Constants.TotalViewports];
|
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++)
|
for (int index = 0; index < Constants.TotalViewports; index++)
|
||||||
{
|
{
|
||||||
@@ -752,8 +745,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref ViewportTransform transform = ref viewportTransformSpan[index];
|
ref ViewportTransform transform = ref _state.State.ViewportTransform[index];
|
||||||
ref ViewportExtents extents = ref viewportExtentsSpan[index];
|
ref ViewportExtents extents = ref _state.State.ViewportExtents[index];
|
||||||
|
|
||||||
float scaleX = MathF.Abs(transform.ScaleX);
|
float scaleX = MathF.Abs(transform.ScaleX);
|
||||||
float scaleY = transform.ScaleY;
|
float scaleY = transform.ScaleY;
|
||||||
@@ -975,11 +968,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
uint vbEnableMask = _vbEnableMask;
|
uint vbEnableMask = _vbEnableMask;
|
||||||
|
|
||||||
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
|
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
|
||||||
Span<VertexAttribState> vertexAttribStateSpan = _state.State.VertexAttribState.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
for (int index = 0; index < Constants.TotalVertexAttribs; index++)
|
||||||
{
|
{
|
||||||
VertexAttribState vertexAttrib = vertexAttribStateSpan[index];
|
VertexAttribState vertexAttrib = _state.State.VertexAttribState[index];
|
||||||
|
|
||||||
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
int bufferIndex = vertexAttrib.UnpackBufferIndex();
|
||||||
|
|
||||||
@@ -1023,7 +1015,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
_pipeline.SetVertexAttribs(vertexAttribs);
|
_pipeline.SetVertexAttribs(vertexAttribs);
|
||||||
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
_context.Renderer.Pipeline.SetVertexAttribs(vertexAttribs);
|
||||||
_currentSpecState.SetAttributeTypes(_state.State.VertexAttribState.AsSpan());
|
_currentSpecState.SetAttributeTypes(ref _state.State.VertexAttribState);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1122,24 +1114,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
int drawVertexCount = _drawState.DrawVertexCount;
|
int drawVertexCount = _drawState.DrawVertexCount;
|
||||||
uint vbEnableMask = 0;
|
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++)
|
for (int index = 0; index < Constants.TotalVertexBuffers; index++)
|
||||||
{
|
{
|
||||||
VertexBufferState vertexBuffer = vertexBufferStateSpan[index];
|
VertexBufferState vertexBuffer = _state.State.VertexBufferState[index];
|
||||||
|
|
||||||
if (!vertexBuffer.UnpackEnable())
|
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);
|
_channel.BufferManager.SetVertexBuffer(index, 0, 0, 0, 0);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
GpuVa endAddress = vertexBufferEndAddressSpan[index];
|
GpuVa endAddress = _state.State.VertexBufferEndAddress[index];
|
||||||
|
|
||||||
ulong address = vertexBuffer.Address.Pack();
|
ulong address = vertexBuffer.Address.Pack();
|
||||||
|
|
||||||
@@ -1150,7 +1137,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
int stride = vertexBuffer.UnpackStride();
|
int stride = vertexBuffer.UnpackStride();
|
||||||
|
|
||||||
bool instanced = vertexBufferInstancedSpan[index];
|
bool instanced = _state.State.VertexBufferInstanced[index];
|
||||||
|
|
||||||
int divisor = instanced ? vertexBuffer.Divisor : 0;
|
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));
|
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);
|
_channel.BufferManager.SetVertexBuffer(index, address, size, stride, divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1250,12 +1237,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
bool rtColorMaskShared = _state.State.RtColorMaskShared;
|
bool rtColorMaskShared = _state.State.RtColorMaskShared;
|
||||||
|
|
||||||
Span<uint> componentMasks = stackalloc uint[Constants.TotalRenderTargets];
|
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++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
RtColorMask colorMask = rtColorMaskSpan[rtColorMaskShared ? 0 : index];
|
RtColorMask colorMask = _state.State.RtColorMask[rtColorMaskShared ? 0 : index];
|
||||||
|
|
||||||
uint componentMask;
|
uint componentMask;
|
||||||
|
|
||||||
@@ -1265,7 +1250,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
|
componentMask |= (colorMask.UnpackAlpha() ? 8u : 0u);
|
||||||
|
|
||||||
componentMasks[index] = componentMask;
|
componentMasks[index] = componentMask;
|
||||||
colorWriteMaskSpan[index] = componentMask;
|
_pipeline.ColorWriteMask[index] = componentMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
_context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
|
_context.Renderer.Pipeline.SetRenderTargetColorMasks(componentMasks);
|
||||||
@@ -1297,14 +1282,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
if (blendIndependent)
|
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++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
bool enable = blendEnableSpan[index];
|
bool enable = _state.State.BlendEnable[index];
|
||||||
BlendState blend = blendStateSpan[index];
|
BlendState blend = _state.State.BlendState[index];
|
||||||
|
|
||||||
BlendDescriptor descriptor = new(
|
BlendDescriptor descriptor = new(
|
||||||
enable,
|
enable,
|
||||||
@@ -1325,7 +1306,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
dualSourceBlendEnabled = true;
|
dualSourceBlendEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
blendDescriptorsSpan[index] = descriptor;
|
_pipeline.BlendDescriptors[index] = descriptor;
|
||||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1353,11 +1334,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
dualSourceBlendEnabled = true;
|
dualSourceBlendEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<BlendDescriptor> blendDescriptorsSpan = _pipeline.BlendDescriptors.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
blendDescriptorsSpan[index] = descriptor;
|
_pipeline.BlendDescriptors[index] = descriptor;
|
||||||
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1443,13 +1422,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
|
|
||||||
ShaderAddresses addresses = new();
|
ShaderAddresses addresses = new();
|
||||||
Span<ulong> addressesSpan = addresses.AsSpan();
|
Span<ulong> addressesSpan = addresses.AsSpan();
|
||||||
Span<ShaderState> shaderStateSpan = _state.State.ShaderState.AsSpan();
|
|
||||||
|
|
||||||
ulong baseAddress = _state.State.ShaderBaseAddress.Pack();
|
ulong baseAddress = _state.State.ShaderBaseAddress.Pack();
|
||||||
|
|
||||||
for (int index = 0; index < 6; index++)
|
for (int index = 0; index < 6; index++)
|
||||||
{
|
{
|
||||||
ShaderState shader = shaderStateSpan[index];
|
ShaderState shader = _state.State.ShaderState[index];
|
||||||
if (!shader.UnpackEnable() && index != 1)
|
if (!shader.UnpackEnable() && index != 1)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@@ -242,22 +242,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
|||||||
/// <param name="rhs">Second struct</param>
|
/// <param name="rhs">Second struct</param>
|
||||||
/// <returns>True if equal, false otherwise</returns>
|
/// <returns>True if equal, false otherwise</returns>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[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)
|
if (Vector256.IsHardwareAccelerated)
|
||||||
{
|
{
|
||||||
return Vector256.EqualsAll(
|
return Vector256.EqualsAll(
|
||||||
Unsafe.As<Span<T>, ReadOnlySpan<Vector256<uint>>>(ref lhs)[0],
|
Unsafe.As<T, Vector256<uint>>(ref lhs),
|
||||||
Unsafe.As<Span<T>, ReadOnlySpan<Vector256<uint>>>(ref rhs)[0]
|
Unsafe.As<T, Vector256<uint>>(ref rhs)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ReadOnlySpan<Vector128<uint>> lhsVec = Unsafe.As<Span<T>, ReadOnlySpan<Vector128<uint>>>(ref lhs);
|
ref Vector128<uint> lhsVec = ref Unsafe.As<T, Vector128<uint>>(ref lhs);
|
||||||
ReadOnlySpan<Vector128<uint>> rhsVec = Unsafe.As<Span<T>, ReadOnlySpan<Vector128<uint>>>(ref rhs);
|
ref Vector128<uint> rhsVec = ref Unsafe.As<T, Vector128<uint>>(ref rhs);
|
||||||
|
|
||||||
return Vector128.EqualsAll(lhsVec[0], rhsVec[0]) &&
|
return Vector128.EqualsAll(lhsVec, rhsVec) &&
|
||||||
Vector128.EqualsAll(lhsVec[1], rhsVec[1]);
|
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.
|
/// Updates blend enable. Respects current shadow mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="masks">Blend enable</param>
|
/// <param name="masks">Blend enable</param>
|
||||||
public void UpdateBlendEnable(Span<Boolean32> enable)
|
public void UpdateBlendEnable(ref Array8<Boolean32> enable)
|
||||||
{
|
{
|
||||||
SetMmeShadowRamControlMode shadow = ShadowMode;
|
SetMmeShadowRamControlMode shadow = ShadowMode;
|
||||||
Span<Boolean32> state = _state.State.BlendEnable.AsSpan();
|
ref Array8<Boolean32> state = ref _state.State.BlendEnable;
|
||||||
|
|
||||||
if (shadow.IsReplay())
|
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);
|
_stateUpdater.ForceDirty(StateUpdater.BlendStateIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shadow.IsTrack())
|
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.
|
/// Updates color masks. Respects current shadow mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="masks">Color masks</param>
|
/// <param name="masks">Color masks</param>
|
||||||
public void UpdateColorMasks(Span<RtColorMask> masks)
|
public void UpdateColorMasks(ref Array8<RtColorMask> masks)
|
||||||
{
|
{
|
||||||
SetMmeShadowRamControlMode shadow = ShadowMode;
|
SetMmeShadowRamControlMode shadow = ShadowMode;
|
||||||
Span<RtColorMask> state = _state.State.RtColorMask.AsSpan();
|
ref Array8<RtColorMask> state = ref _state.State.RtColorMask;
|
||||||
|
|
||||||
if (shadow.IsReplay())
|
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);
|
_stateUpdater.ForceDirty(StateUpdater.RtColorMaskIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shadow.IsTrack())
|
if (shadow.IsTrack())
|
||||||
{
|
{
|
||||||
masks.CopyTo(state);
|
_state.ShadowState.RtColorMask = masks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Buffer, used to store vertex and index data, uniform and storage buffers, and others.
|
/// Buffer, used to store vertex and index data, uniform and storage buffers, and others.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class Buffer : INonOverlappingRange, ISyncActionHandler, IDisposable
|
class Buffer : IRange, ISyncActionHandler, IDisposable
|
||||||
{
|
{
|
||||||
private const ulong GranularBufferThreshold = 4096;
|
private const ulong GranularBufferThreshold = 4096;
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Size of the buffer in bytes.
|
/// Size of the buffer in bytes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong Size { get; private set; }
|
public ulong Size { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// End address of the buffer in guest memory.
|
/// End address of the buffer in guest memory.
|
||||||
@@ -60,13 +60,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This is null until at least one modification occurs.
|
/// This is null until at least one modification occurs.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private BufferModifiedRangeList _modifiedRanges;
|
private BufferModifiedRangeList _modifiedRanges = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A structure that is used to flush buffer data back to a host mapped buffer for cached readback.
|
/// 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.
|
/// Only used if the buffer data is explicitly owned by device local memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private BufferPreFlush _preFlush;
|
private BufferPreFlush _preFlush = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Usage tracking state that determines what type of backing the buffer should use.
|
/// Usage tracking state that determines what type of backing the buffer should use.
|
||||||
@@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
ulong size,
|
ulong size,
|
||||||
BufferStage stage,
|
BufferStage stage,
|
||||||
bool sparseCompatible,
|
bool sparseCompatible,
|
||||||
RangeItem<Buffer>[] baseBuffers)
|
IEnumerable<Buffer> baseBuffers = null)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_physicalMemory = physicalMemory;
|
_physicalMemory = physicalMemory;
|
||||||
@@ -126,22 +126,21 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
_useGranular = size > GranularBufferThreshold;
|
_useGranular = size > GranularBufferThreshold;
|
||||||
|
|
||||||
List<IRegionHandle> baseHandles = null;
|
IEnumerable<IRegionHandle> baseHandles = null;
|
||||||
|
|
||||||
if (baseBuffers.Length != 0)
|
if (baseBuffers != null)
|
||||||
{
|
{
|
||||||
baseHandles = new List<IRegionHandle>();
|
baseHandles = baseBuffers.SelectMany(buffer =>
|
||||||
foreach (RangeItem<Buffer> item in baseBuffers)
|
|
||||||
{
|
{
|
||||||
if (item.Value._useGranular)
|
if (buffer._useGranular)
|
||||||
{
|
{
|
||||||
baseHandles.AddRange((item.Value._memoryTrackingGranular.GetHandles()));
|
return buffer._memoryTrackingGranular.GetHandles();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
baseHandles.Add(item.Value._memoryTracking);
|
return Enumerable.Repeat(buffer._memoryTracking, 1);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_useGranular)
|
if (_useGranular)
|
||||||
@@ -172,9 +171,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
_memoryTracking.RegisterPreciseAction(PreciseAction);
|
_memoryTracking.RegisterPreciseAction(PreciseAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
_externalFlushDelegate = ExternalFlush;
|
_externalFlushDelegate = new RegionSignal(ExternalFlush);
|
||||||
_loadDelegate = LoadRegion;
|
_loadDelegate = new Action<ulong, ulong>(LoadRegion);
|
||||||
_modifiedDelegate = RegionModified;
|
_modifiedDelegate = new Action<ulong, ulong>(RegionModified);
|
||||||
|
|
||||||
_virtualDependenciesLock = new ReaderWriterLockSlim();
|
_virtualDependenciesLock = new ReaderWriterLockSlim();
|
||||||
}
|
}
|
||||||
@@ -248,11 +247,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
return Address < address + size && address < EndAddress;
|
return Address < address + size && address < EndAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public INonOverlappingRange Split(ulong splitAddress)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if a given range is fully contained in the buffer.
|
/// Checks if a given range is fully contained in the buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -441,7 +435,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="from">The buffer to inherit from</param>
|
/// <param name="from">The buffer to inherit from</param>
|
||||||
public void InheritModifiedRanges(Buffer from)
|
public void InheritModifiedRanges(Buffer from)
|
||||||
{
|
{
|
||||||
if (from._modifiedRanges is { HasRanges: true })
|
if (from._modifiedRanges != null && from._modifiedRanges.HasRanges)
|
||||||
{
|
{
|
||||||
if (from._syncActionRegistered && !_syncActionRegistered)
|
if (from._syncActionRegistered && !_syncActionRegistered)
|
||||||
{
|
{
|
||||||
@@ -449,7 +443,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
_syncActionRegistered = true;
|
_syncActionRegistered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterRangeAction(ulong address, ulong size)
|
void registerRangeAction(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
if (_useGranular)
|
if (_useGranular)
|
||||||
{
|
{
|
||||||
@@ -463,7 +457,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
EnsureRangeList();
|
EnsureRangeList();
|
||||||
|
|
||||||
_modifiedRanges.InheritRanges(from._modifiedRanges, RegisterRangeAction);
|
_modifiedRanges.InheritRanges(from._modifiedRanges, registerRangeAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from._dirtyStart != ulong.MaxValue)
|
if (from._dirtyStart != ulong.MaxValue)
|
||||||
@@ -505,7 +499,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
// Cut off the start.
|
// Cut off the start.
|
||||||
|
|
||||||
_dirtyStart = end < _dirtyEnd ? end : ulong.MaxValue;
|
if (end < _dirtyEnd)
|
||||||
|
{
|
||||||
|
_dirtyStart = end;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dirtyStart = ulong.MaxValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (end >= _dirtyEnd)
|
else if (end >= _dirtyEnd)
|
||||||
{
|
{
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Memory.Range;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
@@ -57,7 +56,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="parent">Parent buffer</param>
|
/// <param name="parent">Parent buffer</param>
|
||||||
/// <param name="stage">Initial buffer stage</param>
|
/// <param name="stage">Initial buffer stage</param>
|
||||||
/// <param name="baseBuffers">Buffers to inherit state from</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;
|
_size = (int)parent.Size;
|
||||||
_systemMemoryType = context.Capabilities.MemoryType;
|
_systemMemoryType = context.Capabilities.MemoryType;
|
||||||
@@ -73,7 +72,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
BufferStage storageFlags = stage & BufferStage.StorageMask;
|
BufferStage storageFlags = stage & BufferStage.StorageMask;
|
||||||
|
|
||||||
if (parent.Size > DeviceLocalSizeThreshold && baseBuffers.Length == 0)
|
if (parent.Size > DeviceLocalSizeThreshold && baseBuffers == null)
|
||||||
{
|
{
|
||||||
_desiredType = BufferBackingType.DeviceMemory;
|
_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.
|
// 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 Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Memory
|
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.
|
/// Only modified from the GPU thread. Must lock for add/remove.
|
||||||
/// Must lock for any access from other threads.
|
/// Must lock for any access from other threads.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
private readonly NonOverlappingRangeList<Buffer> _buffers;
|
private readonly RangeList<Buffer> _buffers;
|
||||||
private readonly MultiRangeList<MultiRangeBuffer> _multiRangeBuffers;
|
private readonly MultiRangeList<MultiRangeBuffer> _multiRangeBuffers;
|
||||||
|
|
||||||
|
private Buffer[] _bufferOverlaps;
|
||||||
|
|
||||||
private readonly Dictionary<ulong, BufferCacheEntry> _dirtyCache;
|
private readonly Dictionary<ulong, BufferCacheEntry> _dirtyCache;
|
||||||
private readonly Dictionary<ulong, BufferCacheEntry> _modifiedCache;
|
private readonly Dictionary<ulong, BufferCacheEntry> _modifiedCache;
|
||||||
private bool _pruneCaches;
|
private bool _pruneCaches;
|
||||||
@@ -61,6 +64,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
_buffers = [];
|
_buffers = [];
|
||||||
_multiRangeBuffers = [];
|
_multiRangeBuffers = [];
|
||||||
|
|
||||||
|
_bufferOverlaps = new Buffer[OverlapsBufferInitialCapacity];
|
||||||
|
|
||||||
_dirtyCache = new Dictionary<ulong, BufferCacheEntry>();
|
_dirtyCache = new Dictionary<ulong, BufferCacheEntry>();
|
||||||
|
|
||||||
// There are a lot more entries on the modified cache, so it is separate from the one for ForceDirty.
|
// 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>
|
/// <param name="e">Event arguments</param>
|
||||||
public void MemoryUnmappedHandler(object sender, UnmapEventArgs e)
|
public void MemoryUnmappedHandler(object sender, UnmapEventArgs e)
|
||||||
{
|
{
|
||||||
|
Buffer[] overlaps = new Buffer[10];
|
||||||
|
int overlapCount;
|
||||||
|
|
||||||
MultiRange range = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size);
|
MultiRange range = ((MemoryManager)sender).GetPhysicalRegions(e.Address, e.Size);
|
||||||
|
|
||||||
for (int index = 0; index < range.Count; index++)
|
for (int index = 0; index < range.Count; index++)
|
||||||
{
|
{
|
||||||
MemoryRange subRange = range.GetSubRange(index);
|
MemoryRange subRange = range.GetSubRange(index);
|
||||||
|
|
||||||
_buffers.Lock.EnterReadLock();
|
lock (_buffers)
|
||||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(subRange.Address, subRange.Size);
|
|
||||||
|
|
||||||
for (int i = 0; i < overlaps.Length; i++)
|
|
||||||
{
|
{
|
||||||
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>
|
/// <returns>Physical ranges of the buffer, after address translation</returns>
|
||||||
public MultiRange TranslateAndCreateMultiBuffers(MemoryManager memoryManager, ulong gpuVa, ulong size, BufferStage stage)
|
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);
|
return new MultiRange(MemoryManager.PteUnmapped, size);
|
||||||
}
|
}
|
||||||
@@ -328,7 +336,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
ulong alignedEndAddress = (endAddress + alignmentMask) & ~alignmentMask;
|
ulong alignedEndAddress = (endAddress + alignmentMask) & ~alignmentMask;
|
||||||
ulong alignedSize = alignedEndAddress - alignedAddress;
|
ulong alignedSize = alignedEndAddress - alignedAddress;
|
||||||
|
|
||||||
Buffer buffer = _buffers.FindOverlap(alignedAddress, alignedSize).Value;
|
Buffer buffer = _buffers.FindFirstOverlap(alignedAddress, alignedSize);
|
||||||
BufferRange bufferRange = buffer.GetRange(alignedAddress, alignedSize, false);
|
BufferRange bufferRange = buffer.GetRange(alignedAddress, alignedSize, false);
|
||||||
|
|
||||||
alignedSubRanges[i] = new MemoryRange(alignedAddress, alignedSize);
|
alignedSubRanges[i] = new MemoryRange(alignedAddress, alignedSize);
|
||||||
@@ -395,7 +403,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
if (subRange.Address != MemoryManager.PteUnmapped)
|
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);
|
virtualBuffer.AddPhysicalDependency(buffer, subRange.Address, dstOffset, subRange.Size);
|
||||||
physicalBuffers.Add(buffer);
|
physicalBuffers.Add(buffer);
|
||||||
@@ -487,12 +495,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="stage">The type of usage that created the buffer</param>
|
/// <param name="stage">The type of usage that created the buffer</param>
|
||||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage)
|
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage)
|
||||||
{
|
{
|
||||||
Buffer newBuffer = null;
|
Buffer[] overlaps = _bufferOverlaps;
|
||||||
|
int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||||
|
|
||||||
_buffers.Lock.EnterWriteLock();
|
if (overlapsCount != 0)
|
||||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
|
||||||
|
|
||||||
if (overlaps.Length != 0)
|
|
||||||
{
|
{
|
||||||
// The buffer already exists. We can just return the existing buffer
|
// The buffer already exists. We can just return the existing buffer
|
||||||
// if the buffer we need is fully contained inside the overlapping 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.
|
// old buffer(s) to the new buffer.
|
||||||
|
|
||||||
ulong endAddress = address + size;
|
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;
|
bool anySparseCompatible = false;
|
||||||
|
|
||||||
@@ -515,62 +522,55 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
// sequential memory.
|
// sequential memory.
|
||||||
// Allowing for 2 pages (rather than just one) is necessary to catch cases where the
|
// 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.
|
// range crosses a page, and after alignment, ends having a size of 2 pages.
|
||||||
if (overlaps.Length == 1 &&
|
if (overlapsCount == 1 &&
|
||||||
address >= overlaps[0].Address &&
|
address >= overlap0.Address &&
|
||||||
endAddress - overlaps[0].EndAddress <= BufferAlignmentSize * 2)
|
endAddress - overlap0.EndAddress <= BufferAlignmentSize * 2)
|
||||||
{
|
{
|
||||||
// Try to grow the buffer by 1.5x of its current size.
|
// 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.
|
// 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;
|
ulong growthSize = (existingSize + Math.Min(existingSize >> 1, MaxDynamicGrowthSize)) & ~BufferAlignmentMask;
|
||||||
|
|
||||||
size = Math.Max(size, growthSize);
|
size = Math.Max(size, growthSize);
|
||||||
endAddress = address + size;
|
endAddress = address + size;
|
||||||
|
|
||||||
overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
address = Math.Min(address, overlaps[0].Address);
|
for (int index = 0; index < overlapsCount; index++)
|
||||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
|
||||||
|
|
||||||
for (int i = 0; i < overlaps.Length; i++)
|
|
||||||
{
|
{
|
||||||
anySparseCompatible |= overlaps[i].Value.SparseCompatible;
|
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;
|
ulong newSize = endAddress - address;
|
||||||
|
|
||||||
newBuffer = CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlapsArray);
|
CreateBufferAligned(address, newSize, stage, anySparseCompatible, overlaps, overlapsCount);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_buffers.Lock.ExitWriteLock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_buffers.Lock.ExitWriteLock();
|
|
||||||
|
|
||||||
// No overlap, just create a new buffer.
|
// 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);
|
||||||
}
|
|
||||||
|
|
||||||
if (newBuffer is not null)
|
lock (_buffers)
|
||||||
{
|
{
|
||||||
_buffers.Lock.EnterWriteLock();
|
_buffers.Add(buffer);
|
||||||
|
|
||||||
_buffers.Add(newBuffer);
|
|
||||||
|
|
||||||
_buffers.Lock.ExitWriteLock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShrinkOverlapsBufferIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new buffer for the specified range, if needed.
|
/// Creates a new buffer for the specified range, if needed.
|
||||||
/// If a buffer where this range can be fully contained already exists,
|
/// If a buffer where this range can be fully contained already exists,
|
||||||
@@ -582,77 +582,74 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="alignment">Alignment of the start address of the buffer</param>
|
/// <param name="alignment">Alignment of the start address of the buffer</param>
|
||||||
private void CreateBufferAligned(ulong address, ulong size, BufferStage stage, ulong alignment)
|
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;
|
bool sparseAligned = alignment >= SparseBufferAlignmentSize;
|
||||||
Buffer newBuffer = null;
|
|
||||||
|
|
||||||
_buffers.Lock.EnterWriteLock();
|
if (overlapsCount != 0)
|
||||||
Span<RangeItem<Buffer>> overlaps = _buffers.FindOverlapsAsSpan(address, size);
|
|
||||||
|
|
||||||
if (overlaps.Length != 0)
|
|
||||||
{
|
{
|
||||||
// If the buffer already exists, make sure if covers the entire range,
|
// If the buffer already exists, make sure if covers the entire range,
|
||||||
// and make sure it is properly aligned, otherwise sparse mapping may fail.
|
// and make sure it is properly aligned, otherwise sparse mapping may fail.
|
||||||
|
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
|
Buffer overlap0 = overlaps[0];
|
||||||
|
|
||||||
if (overlaps[0].Address > address ||
|
if (overlap0.Address > address ||
|
||||||
overlaps[0].EndAddress < endAddress ||
|
overlap0.EndAddress < endAddress ||
|
||||||
(overlaps[0].Address & (alignment - 1)) != 0 ||
|
(overlap0.Address & (alignment - 1)) != 0 ||
|
||||||
(!overlaps[0].Value.SparseCompatible && sparseAligned))
|
(!overlap0.SparseCompatible && sparseAligned))
|
||||||
{
|
{
|
||||||
// We need to make sure the new buffer is properly aligned.
|
// We need to make sure the new buffer is properly aligned.
|
||||||
// However, after the range is aligned, it is possible that it
|
// However, after the range is aligned, it is possible that it
|
||||||
// overlaps more buffers, so try again after each extension
|
// overlaps more buffers, so try again after each extension
|
||||||
// and ensure we cover all overlaps.
|
// and ensure we cover all overlaps.
|
||||||
|
|
||||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
int oldOverlapsCount;
|
||||||
int oldOverlapCount;
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
address = Math.Min(address, overlaps[0].Address);
|
for (int index = 0; index < overlapsCount; index++)
|
||||||
endAddress = Math.Max(endAddress, overlaps[^1].EndAddress);
|
{
|
||||||
|
Buffer buffer = overlaps[index];
|
||||||
|
|
||||||
|
address = Math.Min(address, buffer.Address);
|
||||||
|
endAddress = Math.Max(endAddress, buffer.EndAddress);
|
||||||
|
}
|
||||||
|
|
||||||
address &= ~(alignment - 1);
|
address &= ~(alignment - 1);
|
||||||
|
|
||||||
oldOverlapCount = overlaps.Length;
|
oldOverlapsCount = overlapsCount;
|
||||||
overlaps = _buffers.FindOverlapsAsSpan(address, endAddress - address);
|
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;
|
ulong newSize = endAddress - address;
|
||||||
|
|
||||||
RangeItem<Buffer>[] overlapsArray = overlaps.ToArray();
|
CreateBufferAligned(address, newSize, stage, sparseAligned, overlaps, overlapsCount);
|
||||||
|
|
||||||
_buffers.RemoveRange(overlaps[0], overlaps[^1]);
|
|
||||||
|
|
||||||
_buffers.Lock.ExitWriteLock();
|
|
||||||
|
|
||||||
newBuffer = CreateBufferAligned(address, newSize, stage, sparseAligned, overlapsArray);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_buffers.Lock.ExitWriteLock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_buffers.Lock.ExitWriteLock();
|
|
||||||
|
|
||||||
// No overlap, just create a new buffer.
|
// No overlap, just create a new buffer.
|
||||||
newBuffer = new(_context, _physicalMemory, address, size, stage, sparseAligned, []);
|
Buffer buffer = new(_context, _physicalMemory, address, size, stage, sparseAligned);
|
||||||
}
|
|
||||||
|
|
||||||
if (newBuffer is not null)
|
lock (_buffers)
|
||||||
{
|
{
|
||||||
_buffers.Lock.EnterWriteLock();
|
_buffers.Add(buffer);
|
||||||
|
|
||||||
_buffers.Add(newBuffer);
|
|
||||||
|
|
||||||
_buffers.Lock.ExitWriteLock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShrinkOverlapsBufferIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new buffer for the specified range, if needed.
|
/// Creates a new buffer for the specified range, if needed.
|
||||||
/// If a buffer where this range can be fully contained already exists,
|
/// If a buffer where this range can be fully contained already exists,
|
||||||
@@ -663,13 +660,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="stage">The type of usage that created the buffer</param>
|
/// <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="sparseCompatible">Indicates if the buffer can be used in a sparse buffer mapping</param>
|
||||||
/// <param name="overlaps">Buffers overlapping the range</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);
|
int dstOffset = (int)(buffer.Address - newBuffer.Address);
|
||||||
|
|
||||||
@@ -685,8 +688,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
NotifyBuffersModified?.Invoke();
|
NotifyBuffersModified?.Invoke();
|
||||||
|
|
||||||
RecreateMultiRangeBuffers(address, size);
|
RecreateMultiRangeBuffers(address, size);
|
||||||
|
|
||||||
return newBuffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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>
|
/// <summary>
|
||||||
/// Copy a buffer data from a given address to another.
|
/// Copy a buffer data from a given address to another.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -897,7 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
MemoryRange subRange = range.GetSubRange(i);
|
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);
|
subBuffer.SynchronizeMemory(subRange.Address, subRange.Size);
|
||||||
|
|
||||||
@@ -945,7 +957,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
if (size != 0)
|
if (size != 0)
|
||||||
{
|
{
|
||||||
buffer = _buffers.FindOverlap(address, size).Value;
|
buffer = _buffers.FindFirstOverlap(address, size);
|
||||||
|
|
||||||
buffer.CopyFromDependantVirtualBuffers();
|
buffer.CopyFromDependantVirtualBuffers();
|
||||||
buffer.SynchronizeMemory(address, size);
|
buffer.SynchronizeMemory(address, size);
|
||||||
@@ -957,7 +969,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
buffer = _buffers.FindOverlapFast(address, 1).Value;
|
buffer = _buffers.FindFirstOverlap(address, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
@@ -995,7 +1007,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
if (size != 0)
|
if (size != 0)
|
||||||
{
|
{
|
||||||
Buffer buffer = _buffers.FindOverlap(address, size).Value;
|
Buffer buffer = _buffers.FindFirstOverlap(address, size);
|
||||||
|
|
||||||
if (copyBackVirtual)
|
if (copyBackVirtual)
|
||||||
{
|
{
|
||||||
|
@@ -258,7 +258,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
RecordStorageAlignment(_cpStorageBuffers, index, gpuVa);
|
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));
|
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);
|
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));
|
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)
|
if (!bounds.IsUnmapped)
|
||||||
{
|
{
|
||||||
bool isWrite = (bounds.Flags & BufferUsageFlags.Write) == BufferUsageFlags.Write;
|
bool isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
|
||||||
BufferRange range = isStorage
|
BufferRange range = isStorage
|
||||||
? bufferCache.GetBufferRangeAligned(bounds.Range, bufferStage | BufferStageUtils.FromUsage(bounds.Flags), isWrite)
|
? bufferCache.GetBufferRangeAligned(bounds.Range, bufferStage | BufferStageUtils.FromUsage(bounds.Flags), isWrite)
|
||||||
: bufferCache.GetBufferRange(bounds.Range, bufferStage);
|
: bufferCache.GetBufferRange(bounds.Range, bufferStage);
|
||||||
@@ -798,7 +798,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
if (!bounds.IsUnmapped)
|
if (!bounds.IsUnmapped)
|
||||||
{
|
{
|
||||||
bool isWrite = (bounds.Flags & BufferUsageFlags.Write) == BufferUsageFlags.Write;
|
bool isWrite = bounds.Flags.HasFlag(BufferUsageFlags.Write);
|
||||||
BufferRange range = isStorage
|
BufferRange range = isStorage
|
||||||
? bufferCache.GetBufferRangeAligned(bounds.Range, BufferStageUtils.ComputeStorage(bounds.Flags), isWrite)
|
? bufferCache.GetBufferRangeAligned(bounds.Range, BufferStageUtils.ComputeStorage(bounds.Flags), isWrite)
|
||||||
: bufferCache.GetBufferRange(bounds.Range, BufferStage.Compute);
|
: bufferCache.GetBufferRange(bounds.Range, BufferStage.Compute);
|
||||||
@@ -817,6 +817,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// Bind respective buffer bindings on the host API.
|
/// Bind respective buffer bindings on the host API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="ranges">Host buffers to bind, with their offsets and sizes</param>
|
/// <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="count">Number of bindings</param>
|
||||||
/// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
|
/// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@@ -865,6 +866,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="texture">Buffer texture</param>
|
/// <param name="texture">Buffer texture</param>
|
||||||
/// <param name="range">Physical ranges of memory where the buffer texture data is located</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="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>
|
/// <param name="isImage">Whether the binding is for an image or a sampler</param>
|
||||||
public void SetBufferTextureStorage(
|
public void SetBufferTextureStorage(
|
||||||
ShaderStage stage,
|
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="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="bindingInfo">Binding info for the buffer texture</param>
|
||||||
/// <param name="index">Index of the binding on the array</param>
|
/// <param name="index">Index of the binding on the array</param>
|
||||||
|
/// <param name="format">Format of the buffer texture</param>
|
||||||
public void SetBufferTextureStorage(
|
public void SetBufferTextureStorage(
|
||||||
ShaderStage stage,
|
ShaderStage stage,
|
||||||
ITextureArray array,
|
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="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="bindingInfo">Binding info for the buffer texture</param>
|
||||||
/// <param name="index">Index of the binding on the array</param>
|
/// <param name="index">Index of the binding on the array</param>
|
||||||
|
/// <param name="format">Format of the buffer texture</param>
|
||||||
public void SetBufferTextureStorage(
|
public void SetBufferTextureStorage(
|
||||||
ShaderStage stage,
|
ShaderStage stage,
|
||||||
IImageArray array,
|
IImageArray array,
|
||||||
|
@@ -1,24 +1,25 @@
|
|||||||
|
using Ryujinx.Common.Pools;
|
||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Memory
|
namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A range within a buffer that has been modified by the GPU.
|
/// A range within a buffer that has been modified by the GPU.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class BufferModifiedRange : INonOverlappingRange
|
class BufferModifiedRange : IRange
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start address of the range in guest memory.
|
/// Start address of the range in guest memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong Address { get; internal set; }
|
public ulong Address { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Size of the range in bytes.
|
/// Size of the range in bytes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong Size { get; internal set; }
|
public ulong Size { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// End address of the range in guest memory.
|
/// End address of the range in guest memory.
|
||||||
@@ -60,17 +61,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
return Address < address + size && address < EndAddress;
|
return Address < address + size && address < EndAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public INonOverlappingRange Split(ulong splitAddress)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A structure used to track GPU modified ranges within a buffer.
|
/// A structure used to track GPU modified ranges within a buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class BufferModifiedRangeList : NonOverlappingRangeList<BufferModifiedRange>
|
class BufferModifiedRangeList : RangeList<BufferModifiedRange>
|
||||||
{
|
{
|
||||||
private const int BackingInitialSize = 8;
|
private const int BackingInitialSize = 8;
|
||||||
|
|
||||||
@@ -81,6 +77,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
private BufferMigration _source;
|
private BufferMigration _source;
|
||||||
private BufferModifiedRangeList _migrationTarget;
|
private BufferModifiedRangeList _migrationTarget;
|
||||||
|
|
||||||
|
private readonly Lock _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the modified range list has any entries or not.
|
/// Whether the modified range list has any entries or not.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -88,10 +86,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
Lock.EnterReadLock();
|
lock (_lock)
|
||||||
bool result = Count > 0;
|
{
|
||||||
Lock.ExitReadLock();
|
return Count > 0;
|
||||||
return result;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,14 +114,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="action">Action to perform for each remaining sub-range of the input range</param>
|
/// <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)
|
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 (_lock)
|
||||||
Lock.EnterReadLock();
|
|
||||||
|
|
||||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
|
||||||
|
|
||||||
for (int i = 0; i < overlaps.Length; i++)
|
|
||||||
{
|
{
|
||||||
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();
|
||||||
|
|
||||||
|
int count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
BufferModifiedRange overlap = overlaps[i];
|
||||||
|
|
||||||
if (overlap.Address > address)
|
if (overlap.Address > address)
|
||||||
{
|
{
|
||||||
@@ -136,14 +136,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
address = overlap.EndAddress;
|
address = overlap.EndAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
Lock.ExitReadLock();
|
|
||||||
|
|
||||||
if ((long)size > 0)
|
if ((long)size > 0)
|
||||||
{
|
{
|
||||||
// If there is any region left after removing the overlaps, signal it.
|
// If there is any region left after removing the overlaps, signal it.
|
||||||
action(address, size);
|
action(address, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signal that a region of the buffer has been modified, and add the new region to the range list.
|
/// Signal that a region of the buffer has been modified, and add the new region to the range list.
|
||||||
@@ -153,93 +152,51 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="size">Size of the modified region in bytes</param>
|
/// <param name="size">Size of the modified region in bytes</param>
|
||||||
public void SignalModified(ulong address, ulong size)
|
public void SignalModified(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
|
// Must lock, as this can affect flushes from the background thread.
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
// We may overlap with some existing modified regions. They must be cut into by the new entry.
|
||||||
|
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||||
|
|
||||||
|
int count = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||||
|
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
ulong syncNumber = _context.SyncNumber;
|
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)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
// The overlaps must be removed or split.
|
||||||
Lock.ExitWriteLock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first == last)
|
BufferModifiedRange overlap = overlaps[i];
|
||||||
{
|
|
||||||
if (first.Address == address && first.EndAddress == endAddress)
|
|
||||||
{
|
|
||||||
first.Value.SyncNumber = syncNumber;
|
|
||||||
first.Value.Parent = this;
|
|
||||||
Lock.ExitWriteLock();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first.Address < address)
|
if (overlap.Address == address && overlap.Size == size)
|
||||||
{
|
{
|
||||||
first.Value.Size = address - first.Address;
|
// Region already exists. Just update the existing sync number.
|
||||||
Update(first);
|
overlap.SyncNumber = syncNumber;
|
||||||
|
overlap.Parent = this;
|
||||||
if (first.EndAddress > endAddress)
|
|
||||||
{
|
|
||||||
Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
|
|
||||||
first.Value.SyncNumber, first.Value.Parent));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (first.EndAddress > endAddress)
|
|
||||||
{
|
|
||||||
first.Value.Size = first.EndAddress - endAddress;
|
|
||||||
first.Value.Address = endAddress;
|
|
||||||
Update(first);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Remove(first.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
|
||||||
Lock.ExitWriteLock();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferModifiedRange buffPre = null;
|
Remove(overlap);
|
||||||
BufferModifiedRange buffPost = null;
|
|
||||||
bool extendsPost = false;
|
|
||||||
bool extendsPre = false;
|
|
||||||
|
|
||||||
if (first.Address < address)
|
if (overlap.Address < address && overlap.EndAddress > address)
|
||||||
{
|
{
|
||||||
buffPre = new BufferModifiedRange(first.Address, address - first.Address,
|
// A split item must be created behind this overlap.
|
||||||
first.Value.SyncNumber, first.Value.Parent);
|
|
||||||
extendsPre = true;
|
Add(new BufferModifiedRange(overlap.Address, address - overlap.Address, overlap.SyncNumber, overlap.Parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last.EndAddress > endAddress)
|
if (overlap.Address < endAddress && overlap.EndAddress > endAddress)
|
||||||
{
|
{
|
||||||
buffPost = new BufferModifiedRange(endAddress, last.EndAddress - endAddress,
|
// A split item must be created after this overlap.
|
||||||
last.Value.SyncNumber, last.Value.Parent);
|
|
||||||
extendsPost = true;
|
Add(new BufferModifiedRange(endAddress, overlap.EndAddress - endAddress, overlap.SyncNumber, overlap.Parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveRange(first, last);
|
|
||||||
|
|
||||||
if (extendsPre)
|
|
||||||
{
|
|
||||||
Add(buffPre);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extendsPost)
|
|
||||||
{
|
|
||||||
Add(buffPost);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
Add(new BufferModifiedRange(address, size, syncNumber, this));
|
||||||
Lock.ExitWriteLock();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -251,20 +208,25 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="rangeAction">The action to call for each modified range</param>
|
/// <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)
|
public void GetRangesAtSync(ulong address, ulong size, ulong syncNumber, Action<ulong, ulong> rangeAction)
|
||||||
{
|
{
|
||||||
Lock.EnterReadLock();
|
int count = 0;
|
||||||
Span<RangeItem<BufferModifiedRange>> overlaps = FindOverlapsAsSpan(address, size);
|
|
||||||
|
|
||||||
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)
|
if (overlap.SyncNumber == syncNumber)
|
||||||
{
|
{
|
||||||
rangeAction(overlap.Address, overlap.Size);
|
rangeAction(overlap.Address, overlap.Size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lock.ExitReadLock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -275,14 +237,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="rangeAction">The action to call for each modified range</param>
|
/// <param name="rangeAction">The action to call for each modified range</param>
|
||||||
public void GetRanges(ulong address, ulong size, Action<ulong, ulong> rangeAction)
|
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.
|
int count = 0;
|
||||||
Lock.EnterReadLock();
|
|
||||||
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size);
|
|
||||||
Lock.ExitReadLock();
|
|
||||||
|
|
||||||
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);
|
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>
|
/// <returns>True if a range exists in the specified region, false otherwise</returns>
|
||||||
public bool HasRange(ulong address, ulong size)
|
public bool HasRange(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
Lock.EnterReadLock();
|
// Range list must be consistent for this operation.
|
||||||
RangeItem<BufferModifiedRange> first = FindOverlapFast(address, size);
|
lock (_lock)
|
||||||
bool result = first is not null;
|
{
|
||||||
Lock.ExitReadLock();
|
return FindOverlapsNonOverlapping(address, size, ref ThreadStaticArray<BufferModifiedRange>.Get()) > 0;
|
||||||
return result;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -331,12 +298,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="address">The start address of the flush range</param>
|
/// <param name="address">The start address of the flush range</param>
|
||||||
/// <param name="endAddress">The end address of the flush range</param>
|
/// <param name="endAddress">The end address of the flush range</param>
|
||||||
private void RemoveRangesAndFlush(
|
private void RemoveRangesAndFlush(
|
||||||
RangeItem<BufferModifiedRange>[] overlaps,
|
BufferModifiedRange[] overlaps,
|
||||||
int rangeCount,
|
int rangeCount,
|
||||||
long highestDiff,
|
long highestDiff,
|
||||||
ulong currentSync,
|
ulong currentSync,
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong endAddress)
|
ulong endAddress)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (_migrationTarget == null)
|
if (_migrationTarget == null)
|
||||||
{
|
{
|
||||||
@@ -344,7 +313,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
for (int i = 0; i < rangeCount; i++)
|
for (int i = 0; i < rangeCount; i++)
|
||||||
{
|
{
|
||||||
BufferModifiedRange overlap = overlaps[i].Value;
|
BufferModifiedRange overlap = overlaps[i];
|
||||||
|
|
||||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||||
|
|
||||||
@@ -361,6 +330,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
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.
|
// 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 endAddress = address + size;
|
||||||
ulong currentSync = _context.SyncNumber;
|
ulong currentSync = _context.SyncNumber;
|
||||||
|
|
||||||
|
int rangeCount = 0;
|
||||||
|
|
||||||
|
ref BufferModifiedRange[] overlaps = ref ThreadStaticArray<BufferModifiedRange>.Get();
|
||||||
|
|
||||||
// Range list must be consistent for this operation
|
// Range list must be consistent for this operation
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
if (_migrationTarget != null)
|
if (_migrationTarget != null)
|
||||||
{
|
{
|
||||||
_migrationTarget!.WaitForAndFlushRanges(address, size);
|
rangeCount = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rangeCount = FindOverlapsNonOverlapping(address, size, ref overlaps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rangeCount == -1)
|
||||||
|
{
|
||||||
|
_migrationTarget.WaitForAndFlushRanges(address, size);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (rangeCount == 0)
|
||||||
Lock.EnterWriteLock();
|
|
||||||
// We use the non-span method here because the array is partially modified by the code, which would invalidate a span.
|
|
||||||
RangeItem<BufferModifiedRange>[] overlaps = FindOverlapsAsArray(address, size);
|
|
||||||
|
|
||||||
int rangeCount = overlaps.Length;
|
|
||||||
|
|
||||||
if (rangeCount == 0)
|
|
||||||
{
|
{
|
||||||
Lock.ExitWriteLock();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,7 +388,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
for (int i = 0; i < rangeCount; i++)
|
for (int i = 0; i < rangeCount; i++)
|
||||||
{
|
{
|
||||||
BufferModifiedRange overlap = overlaps[i].Value;
|
BufferModifiedRange overlap = overlaps[i];
|
||||||
|
|
||||||
long diff = (long)(overlap.SyncNumber - currentSync);
|
long diff = (long)(overlap.SyncNumber - currentSync);
|
||||||
|
|
||||||
@@ -423,17 +400,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
if (highestDiff == long.MinValue)
|
if (highestDiff == long.MinValue)
|
||||||
{
|
{
|
||||||
Lock.ExitWriteLock();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for the syncpoint.
|
// Wait for the syncpoint.
|
||||||
_context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
|
_context.Renderer.WaitSync(currentSync + (ulong)highestDiff);
|
||||||
|
|
||||||
RemoveRangesAndFlush(overlaps.ToArray(), rangeCount, highestDiff, currentSync, address, endAddress);
|
RemoveRangesAndFlush(overlaps, rangeCount, highestDiff, currentSync, address, endAddress);
|
||||||
|
|
||||||
Lock.ExitWriteLock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -446,10 +419,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="registerRangeAction">The action to call for each modified range</param>
|
/// <param name="registerRangeAction">The action to call for each modified range</param>
|
||||||
public void InheritRanges(BufferModifiedRangeList ranges, Action<ulong, ulong> registerRangeAction)
|
public void InheritRanges(BufferModifiedRangeList ranges, Action<ulong, ulong> registerRangeAction)
|
||||||
{
|
{
|
||||||
ranges.Lock.EnterReadLock();
|
BufferModifiedRange[] inheritRanges;
|
||||||
BufferModifiedRange[] inheritRanges = ranges.ToArray();
|
|
||||||
ranges.Lock.ExitReadLock();
|
|
||||||
|
|
||||||
|
lock (ranges._lock)
|
||||||
|
{
|
||||||
|
inheritRanges = ranges.ToArray();
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
// Copy over the migration from the previous range list
|
// Copy over the migration from the previous range list
|
||||||
|
|
||||||
BufferMigration oldMigration = ranges._source;
|
BufferMigration oldMigration = ranges._source;
|
||||||
@@ -472,14 +449,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
ranges._migrationTarget = this;
|
ranges._migrationTarget = this;
|
||||||
|
|
||||||
Lock.EnterWriteLock();
|
|
||||||
|
|
||||||
foreach (BufferModifiedRange range in inheritRanges)
|
foreach (BufferModifiedRange range in inheritRanges)
|
||||||
{
|
{
|
||||||
Add(range);
|
Add(range);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Lock.ExitWriteLock();
|
}
|
||||||
|
|
||||||
ulong currentSync = _context.SyncNumber;
|
ulong currentSync = _context.SyncNumber;
|
||||||
foreach (BufferModifiedRange range in inheritRanges)
|
foreach (BufferModifiedRange range in inheritRanges)
|
||||||
@@ -498,8 +473,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SelfMigration()
|
public void SelfMigration()
|
||||||
{
|
{
|
||||||
BufferMigrationSpan span = new(_parent, _parent.GetSnapshotDisposeAction(),
|
lock (_lock)
|
||||||
_parent.GetSnapshotFlushAction(), _source);
|
{
|
||||||
|
BufferMigrationSpan span = new(_parent, _parent.GetSnapshotDisposeAction(), _parent.GetSnapshotFlushAction(), _source);
|
||||||
BufferMigration migration = new([span], this, _context.SyncNumber);
|
BufferMigration migration = new([span], this, _context.SyncNumber);
|
||||||
|
|
||||||
// Migration target is used to redirect flush actions to the latest range list,
|
// Migration target is used to redirect flush actions to the latest range list,
|
||||||
@@ -507,9 +483,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
_context.RegisterBufferMigration(migration);
|
_context.RegisterBufferMigration(migration);
|
||||||
|
|
||||||
Lock.EnterWriteLock();
|
|
||||||
_source = migration;
|
_source = migration;
|
||||||
Lock.ExitWriteLock();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -518,13 +493,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="migration">The migration to remove</param>
|
/// <param name="migration">The migration to remove</param>
|
||||||
public void RemoveMigration(BufferMigration migration)
|
public void RemoveMigration(BufferMigration migration)
|
||||||
{
|
{
|
||||||
Lock.EnterWriteLock();
|
lock (_lock)
|
||||||
|
{
|
||||||
if (_source == migration)
|
if (_source == migration)
|
||||||
{
|
{
|
||||||
_source = null;
|
_source = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Lock.ExitWriteLock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearPart(BufferModifiedRange overlap, ulong address, ulong endAddress)
|
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>
|
/// <param name="size">Size to clear</param>
|
||||||
public void Clear(ulong address, ulong size)
|
public void Clear(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
// This function can be called from any thread, so it cannot use the arrays for background or foreground.
|
||||||
|
BufferModifiedRange[] toClear = new BufferModifiedRange[1];
|
||||||
|
|
||||||
|
int rangeCount = FindOverlapsNonOverlapping(address, size, ref toClear);
|
||||||
|
|
||||||
ulong endAddress = address + size;
|
ulong endAddress = address + size;
|
||||||
Lock.EnterWriteLock();
|
|
||||||
(RangeItem<BufferModifiedRange> first, RangeItem<BufferModifiedRange> last) = FindOverlapsAsNodes(address, size);
|
|
||||||
|
|
||||||
if (first is null)
|
for (int i = 0; i < rangeCount; i++)
|
||||||
{
|
{
|
||||||
Lock.ExitWriteLock();
|
BufferModifiedRange overlap = toClear[i];
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first == last)
|
ClearPart(overlap, address, endAddress);
|
||||||
{
|
|
||||||
if (first.Address < address)
|
|
||||||
{
|
|
||||||
first.Value.Size = address - first.Address;
|
|
||||||
Update(first);
|
|
||||||
|
|
||||||
if (first.EndAddress > endAddress)
|
|
||||||
{
|
|
||||||
Add(new BufferModifiedRange(endAddress, first.EndAddress - endAddress,
|
|
||||||
first.Value.SyncNumber, first.Value.Parent));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (first.EndAddress > endAddress)
|
|
||||||
{
|
|
||||||
first.Value.Size = first.EndAddress - endAddress;
|
|
||||||
first.Value.Address = endAddress;
|
|
||||||
Update(first);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Remove(first.Value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Lock.ExitWriteLock();
|
/// <summary>
|
||||||
return;
|
/// Clear all modified ranges.
|
||||||
}
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
BufferModifiedRange buffPre = null;
|
|
||||||
BufferModifiedRange buffPost = null;
|
|
||||||
bool extendsPost = false;
|
|
||||||
bool extendsPre = false;
|
|
||||||
|
|
||||||
if (first.Address < address)
|
|
||||||
{
|
{
|
||||||
buffPre = new BufferModifiedRange(first.Address, address - first.Address,
|
lock (_lock)
|
||||||
first.Value.SyncNumber, first.Value.Parent);
|
|
||||||
extendsPre = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last.EndAddress > endAddress)
|
|
||||||
{
|
{
|
||||||
buffPost = new BufferModifiedRange(endAddress, last.EndAddress - endAddress,
|
Count = 0;
|
||||||
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 Ryujinx.Graphics.Shader;
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Memory
|
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.
|
/// 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.
|
/// Must match ShaderStage for the shader stages, though anything after that can be in any order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
|
||||||
internal enum BufferStage : byte
|
internal enum BufferStage : byte
|
||||||
{
|
{
|
||||||
Compute,
|
Compute,
|
||||||
@@ -54,7 +52,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static BufferStage FromUsage(BufferUsageFlags flags)
|
public static BufferStage FromUsage(BufferUsageFlags flags)
|
||||||
{
|
{
|
||||||
if ((flags & BufferUsageFlags.Write) == BufferUsageFlags.Write)
|
if (flags.HasFlag(BufferUsageFlags.Write))
|
||||||
{
|
{
|
||||||
return BufferStage.StorageWrite;
|
return BufferStage.StorageWrite;
|
||||||
}
|
}
|
||||||
@@ -67,7 +65,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static BufferStage FromUsage(TextureUsageFlags flags)
|
public static BufferStage FromUsage(TextureUsageFlags flags)
|
||||||
{
|
{
|
||||||
if ((flags & TextureUsageFlags.ImageStore) == TextureUsageFlags.ImageStore)
|
if (flags.HasFlag(TextureUsageFlags.ImageStore))
|
||||||
{
|
{
|
||||||
return BufferStage.StorageWrite;
|
return BufferStage.StorageWrite;
|
||||||
}
|
}
|
||||||
|
@@ -691,7 +691,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
_pageTable[l0] = new ulong[PtLvl1Size];
|
_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;
|
_pageTable[l0][l1] = pte;
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Shader;
|
using Ryujinx.Graphics.Shader;
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@@ -105,11 +104,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <param name="scale">Scale value</param>
|
/// <param name="scale">Scale value</param>
|
||||||
public void UpdateRenderScale(int index, float scale)
|
public void UpdateRenderScale(int index, float scale)
|
||||||
{
|
{
|
||||||
Span<Vector4<float>> renderScaleSpan = _data.RenderScale.AsSpan();
|
if (_data.RenderScale[1 + index].X != scale)
|
||||||
|
|
||||||
if (renderScaleSpan[1 + index].X != scale)
|
|
||||||
{
|
{
|
||||||
renderScaleSpan[1 + index].X = scale;
|
_data.RenderScale[1 + index].X = scale;
|
||||||
DirtyRenderScale(1 + index, 1);
|
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>
|
/// <param name="isBgra">True if the format is BGRA< false otherwise</param>
|
||||||
public void SetRenderTargetIsBgra(int index, bool isBgra)
|
public void SetRenderTargetIsBgra(int index, bool isBgra)
|
||||||
{
|
{
|
||||||
Span<Vector4<int>> fragmentIsBgraSpan = _data.FragmentIsBgra.AsSpan();
|
bool isBgraChanged = _data.FragmentIsBgra[index].X != 0 != isBgra;
|
||||||
|
|
||||||
bool isBgraChanged = fragmentIsBgraSpan[index].X != 0 != isBgra;
|
|
||||||
|
|
||||||
if (isBgraChanged)
|
if (isBgraChanged)
|
||||||
{
|
{
|
||||||
fragmentIsBgraSpan[index].X = isBgra ? 1 : 0;
|
_data.FragmentIsBgra[index].X = isBgra ? 1 : 0;
|
||||||
DirtyFragmentIsBgra(index, 1);
|
DirtyFragmentIsBgra(index, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,7 +15,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a GPU virtual memory range.
|
/// Represents a GPU virtual memory range.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private class VirtualRange : INonOverlappingRange
|
private readonly struct VirtualRange : IRange
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GPU virtual address where the range starts.
|
/// GPU virtual address where the range starts.
|
||||||
@@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Size of the range in bytes.
|
/// Size of the range in bytes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong Size { get; private set; }
|
public ulong Size { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// GPU virtual address where the range ends.
|
/// GPU virtual address where the range ends.
|
||||||
@@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Physical regions where the GPU virtual region is mapped.
|
/// Physical regions where the GPU virtual region is mapped.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MultiRange Range { get; private set; }
|
public MultiRange Range { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new virtual memory range.
|
/// Creates a new virtual memory range.
|
||||||
@@ -60,14 +60,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
return Address < address + size && address < EndAddress;
|
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 readonly ConcurrentQueue<VirtualRange> _deferredUnmaps;
|
||||||
private int _hasDeferredUnmaps;
|
private int _hasDeferredUnmaps;
|
||||||
|
|
||||||
@@ -79,6 +75,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
{
|
{
|
||||||
_memoryManager = memoryManager;
|
_memoryManager = memoryManager;
|
||||||
_virtualRanges = [];
|
_virtualRanges = [];
|
||||||
|
_virtualRangeOverlaps = new VirtualRange[BufferCache.OverlapsBufferInitialCapacity];
|
||||||
_deferredUnmaps = new ConcurrentQueue<VirtualRange>();
|
_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>
|
/// <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)
|
public bool TryGetOrAddRange(ulong gpuVa, ulong size, out MultiRange range)
|
||||||
{
|
{
|
||||||
|
VirtualRange[] overlaps = _virtualRangeOverlaps;
|
||||||
|
int overlapsCount;
|
||||||
|
|
||||||
if (Interlocked.Exchange(ref _hasDeferredUnmaps, 0) != 0)
|
if (Interlocked.Exchange(ref _hasDeferredUnmaps, 0) != 0)
|
||||||
{
|
{
|
||||||
while (_deferredUnmaps.TryDequeue(out VirtualRange unmappedRange))
|
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;
|
ulong originalVa = gpuVa;
|
||||||
|
|
||||||
_virtualRanges.Lock.EnterWriteLock();
|
overlapsCount = _virtualRanges.FindOverlapsNonOverlapping(gpuVa, size, ref overlaps);
|
||||||
(RangeItem<VirtualRange> first, RangeItem<VirtualRange> last) = _virtualRanges.FindOverlapsAsNodes(gpuVa, size);
|
|
||||||
|
|
||||||
if (first is not null)
|
if (overlapsCount != 0)
|
||||||
{
|
{
|
||||||
// The virtual range already exists. We just need to check if our range fits inside
|
// 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.
|
// the existing one, and if not, we must extend the existing one.
|
||||||
|
|
||||||
ulong endAddress = gpuVa + size;
|
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);
|
for (int index = 0; index < overlapsCount; index++)
|
||||||
endAddress = Math.Max(endAddress, last.EndAddress);
|
{
|
||||||
|
VirtualRange virtualRange = overlaps[index];
|
||||||
|
|
||||||
_virtualRanges.RemoveRange(first, last);
|
gpuVa = Math.Min(gpuVa, virtualRange.Address);
|
||||||
|
endAddress = Math.Max(endAddress, virtualRange.EndAddress);
|
||||||
|
|
||||||
|
_virtualRanges.Remove(virtualRange);
|
||||||
|
}
|
||||||
|
|
||||||
ulong newSize = endAddress - gpuVa;
|
ulong newSize = endAddress - gpuVa;
|
||||||
MultiRange newRange = _memoryManager.GetPhysicalRegions(gpuVa, newSize);
|
MultiRange newRange = _memoryManager.GetPhysicalRegions(gpuVa, newSize);
|
||||||
@@ -147,8 +157,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
found = first.Value.Range.Count == 1 || IsSparseAligned(first.Value.Range);
|
found = overlap0.Range.Count == 1 || IsSparseAligned(overlap0.Range);
|
||||||
range = first.Value.Range.Slice(gpuVa - first.Address, size);
|
range = overlap0.Range.Slice(gpuVa - overlap0.Address, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -160,7 +170,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
_virtualRanges.Add(virtualRange);
|
_virtualRanges.Add(virtualRange);
|
||||||
}
|
}
|
||||||
_virtualRanges.Lock.ExitWriteLock();
|
|
||||||
|
ShrinkOverlapsBufferIfNeeded();
|
||||||
|
|
||||||
// If the range is not properly aligned for sparse mapping,
|
// If the range is not properly aligned for sparse mapping,
|
||||||
// let's just force it to a single range.
|
// let's just force it to a single range.
|
||||||
@@ -210,5 +221,16 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
return true;
|
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.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Memory;
|
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
using Ryujinx.Graphics.Gpu.Engine.Threed;
|
||||||
using Ryujinx.Graphics.Gpu.Engine.Types;
|
using Ryujinx.Graphics.Gpu.Engine.Types;
|
||||||
@@ -259,25 +258,21 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
int count = rtControl.UnpackCount();
|
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++)
|
for (int index = 0; index < Constants.TotalRenderTargets; index++)
|
||||||
{
|
{
|
||||||
int rtIndex = rtControl.UnpackPermutationIndex(index);
|
int rtIndex = rtControl.UnpackPermutationIndex(index);
|
||||||
|
|
||||||
var colorState = rtColorStateSpan[rtIndex];
|
var colorState = state.RtColorState[rtIndex];
|
||||||
|
|
||||||
if (index >= count || colorState.Format == 0 || colorState.WidthOrStride == 0)
|
if (index >= count || colorState.Format == 0 || colorState.WidthOrStride == 0)
|
||||||
{
|
{
|
||||||
attachmentEnableSpan[index] = false;
|
pipeline.AttachmentEnable[index] = false;
|
||||||
attachmentFormatsSpan[index] = Format.R8G8B8A8Unorm;
|
pipeline.AttachmentFormats[index] = Format.R8G8B8A8Unorm;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
attachmentEnableSpan[index] = true;
|
pipeline.AttachmentEnable[index] = true;
|
||||||
attachmentFormatsSpan[index] = colorState.Format.Convert().Format;
|
pipeline.AttachmentFormats[index] = colorState.Format.Convert().Format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,18 +580,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
TransformFeedbackDescriptor[] descs = new TransformFeedbackDescriptor[Constants.TotalTransformFeedbackBuffers];
|
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++)
|
for (int i = 0; i < Constants.TotalTransformFeedbackBuffers; i++)
|
||||||
{
|
{
|
||||||
var tf = tfStateSpan[i];
|
var tf = state.TfState[i];
|
||||||
|
|
||||||
descs[i] = new TransformFeedbackDescriptor(
|
descs[i] = new TransformFeedbackDescriptor(
|
||||||
tf.BufferIndex,
|
tf.BufferIndex,
|
||||||
tf.Stride,
|
tf.Stride,
|
||||||
tf.VaryingsCount,
|
tf.VaryingsCount,
|
||||||
ref tfVaryingLocationsSpan[i]);
|
ref state.TfVaryingLocations[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return descs;
|
return descs;
|
||||||
|
@@ -580,13 +580,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
if (ShaderCache.MayConvertVtgToCompute(ref channel.Capabilities) && !vertexAsCompute)
|
if (ShaderCache.MayConvertVtgToCompute(ref channel.Capabilities) && !vertexAsCompute)
|
||||||
{
|
{
|
||||||
Span<AttributeType> attributeTypesSpan = graphicsState.AttributeTypes.AsSpan();
|
for (int index = 0; index < graphicsState.AttributeTypes.Length; index++)
|
||||||
Span<AttributeType> gAttributeTypesSpan = GraphicsState.AttributeTypes.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < attributeTypesSpan.Length; index++)
|
|
||||||
{
|
{
|
||||||
AttributeType lType = FilterAttributeType(channel, attributeTypesSpan[index]);
|
AttributeType lType = FilterAttributeType(channel, graphicsState.AttributeTypes[index]);
|
||||||
AttributeType rType = FilterAttributeType(channel, gAttributeTypesSpan[index]);
|
AttributeType rType = FilterAttributeType(channel, GraphicsState.AttributeTypes[index]);
|
||||||
|
|
||||||
if (lType != rType)
|
if (lType != rType)
|
||||||
{
|
{
|
||||||
@@ -732,8 +729,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||||
|
|
||||||
Span<uint> constantBufferUseSpan = ConstantBufferUse.AsSpan();
|
|
||||||
|
|
||||||
while (constantBufferUsePerStageMask != 0)
|
while (constantBufferUsePerStageMask != 0)
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||||
@@ -742,7 +737,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
? channel.BufferManager.GetComputeUniformBufferUseMask()
|
? channel.BufferManager.GetComputeUniformBufferUseMask()
|
||||||
: channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
|
: channel.BufferManager.GetGraphicsUniformBufferUseMask(index);
|
||||||
|
|
||||||
if (constantBufferUseSpan[index] != useMask)
|
if (ConstantBufferUse[index] != useMask)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -806,7 +801,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
if (specializationState != null)
|
if (specializationState != null)
|
||||||
{
|
{
|
||||||
if ((specializationState.Value.QueriedFlags & QueriedTextureStateFlags.CoordNormalized) == QueriedTextureStateFlags.CoordNormalized &&
|
if (specializationState.Value.QueriedFlags.HasFlag(QueriedTextureStateFlags.CoordNormalized) &&
|
||||||
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
specializationState.Value.CoordNormalized != descriptor.UnpackTextureCoordNormalized())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -882,12 +877,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
|
int constantBufferUsePerStageMask = specState._constantBufferUsePerStage;
|
||||||
|
|
||||||
Span<uint> constantBufferUseSpan = specState.ConstantBufferUse.AsSpan();
|
|
||||||
|
|
||||||
while (constantBufferUsePerStageMask != 0)
|
while (constantBufferUsePerStageMask != 0)
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||||
dataReader.Read(ref constantBufferUseSpan[index]);
|
dataReader.Read(ref specState.ConstantBufferUse[index]);
|
||||||
constantBufferUsePerStageMask &= ~(1 << index);
|
constantBufferUsePerStageMask &= ~(1 << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -987,12 +980,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
int constantBufferUsePerStageMask = _constantBufferUsePerStage;
|
||||||
|
|
||||||
Span<uint> constantBufferUseSpan = ConstantBufferUse.AsSpan();
|
|
||||||
|
|
||||||
while (constantBufferUsePerStageMask != 0)
|
while (constantBufferUsePerStageMask != 0)
|
||||||
{
|
{
|
||||||
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
int index = BitOperations.TrailingZeroCount(constantBufferUsePerStageMask);
|
||||||
dataWriter.Write(ref constantBufferUseSpan[index]);
|
dataWriter.Write(ref ConstantBufferUse[index]);
|
||||||
constantBufferUsePerStageMask &= ~(1 << index);
|
constantBufferUsePerStageMask &= ~(1 << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -92,24 +92,20 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
|
|||||||
|
|
||||||
if (pictureInfo.ScalingMatrixPresent)
|
if (pictureInfo.ScalingMatrixPresent)
|
||||||
{
|
{
|
||||||
Span<Array16<byte>> scalingLists4x4Span = pictureInfo.ScalingLists4x4.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < 6; index++)
|
for (int index = 0; index < 6; index++)
|
||||||
{
|
{
|
||||||
writer.WriteBit(true);
|
writer.WriteBit(true);
|
||||||
|
|
||||||
WriteScalingList(ref writer, scalingLists4x4Span[index]);
|
WriteScalingList(ref writer, pictureInfo.ScalingLists4x4[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pictureInfo.Transform8x8ModeFlag)
|
if (pictureInfo.Transform8x8ModeFlag)
|
||||||
{
|
{
|
||||||
Span<Array64<byte>> scalingLists8x8Span = pictureInfo.ScalingLists8x8.AsSpan();
|
|
||||||
|
|
||||||
for (int index = 0; index < 2; index++)
|
for (int index = 0; index < 2; index++)
|
||||||
{
|
{
|
||||||
writer.WriteBit(true);
|
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;
|
int lastScale = 8;
|
||||||
|
|
||||||
Span<byte> listSpan = list.AsSpan();
|
for (int index = 0; index < list.Length; index++)
|
||||||
|
|
||||||
for (int index = 0; index < listSpan.Length; index++)
|
|
||||||
{
|
{
|
||||||
byte value = listSpan[scan[index]];
|
byte value = list[scan[index]];
|
||||||
|
|
||||||
int deltaScale = value - lastScale;
|
int deltaScale = value - lastScale;
|
||||||
|
|
||||||
|
@@ -21,67 +21,49 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
private static void ReadTxModeProbs(ref Vp9EntropyProbs txProbs, ref Reader r)
|
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)
|
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||||
{
|
{
|
||||||
Span<byte> tx8x8ProbSpan2 = tx8x8ProbSpan1[i].AsSpan();
|
|
||||||
|
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 3; ++j)
|
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)
|
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||||
{
|
{
|
||||||
Span<byte> tx16x16ProbSpan2 = tx16x16ProbSpan1[i].AsSpan();
|
|
||||||
|
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 2; ++j)
|
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)
|
for (int i = 0; i < EntropyMode.TxSizeContexts; ++i)
|
||||||
{
|
{
|
||||||
Span<byte> tx32x32ProbSpan2 = tx32x32ProbSpan1[i].AsSpan();
|
|
||||||
|
|
||||||
for (int j = 0; j < (int)TxSize.TxSizes - 1; ++j)
|
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)
|
private static void ReadSwitchableInterpProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
||||||
{
|
{
|
||||||
Span<Array2<byte>> switchableInterpProbSpan1 = fc.SwitchableInterpProb.AsSpan();
|
for (int j = 0; j < Constants.SwitchableFilterContexts; ++j)
|
||||||
|
|
||||||
for (int i = 0; i < Constants.SwitchableFilterContexts; ++i)
|
|
||||||
{
|
{
|
||||||
Span<byte> switchableInterpProbSpan2 = switchableInterpProbSpan1[i].AsSpan();
|
for (int i = 0; i < Constants.SwitchableFilters - 1; ++i)
|
||||||
|
|
||||||
for (int j = 0; j < Constants.SwitchableFilters - 1; ++j)
|
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref switchableInterpProbSpan2[j]);
|
r.DiffUpdateProb(ref fc.SwitchableInterpProb[j][i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReadInterModeProbs(ref Vp9EntropyProbs fc, ref Reader r)
|
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)
|
for (int i = 0; i < Constants.InterModeContexts; ++i)
|
||||||
{
|
{
|
||||||
Span<byte> interModeProbSpan2 = interModeProbSpan1[i].AsSpan();
|
|
||||||
|
|
||||||
for (int j = 0; j < Constants.InterModes - 1; ++j)
|
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);
|
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)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref signSpan[i], 1), 1);
|
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Sign[i], 1), 1);
|
||||||
r.UpdateMvProbs(classesSpan[i].AsSpan(), EntropyMv.Classes - 1);
|
r.UpdateMvProbs(ctx.Classes[i].AsSpan(), EntropyMv.Classes - 1);
|
||||||
r.UpdateMvProbs(class0Span[i].AsSpan(), EntropyMv.Class0Size - 1);
|
r.UpdateMvProbs(ctx.Class0[i].AsSpan(), EntropyMv.Class0Size - 1);
|
||||||
r.UpdateMvProbs(bitsSpan[i].AsSpan(), EntropyMv.OffsetBits);
|
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)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
Span<Array3<byte>> class0FpSpan2 = class0FpSpan1[i].AsSpan();
|
|
||||||
|
|
||||||
for (int j = 0; j < EntropyMv.Class0Size; ++j)
|
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)
|
if (allowHp)
|
||||||
{
|
{
|
||||||
Span<byte> class0HpSpan = ctx.Class0Hp.AsSpan();
|
|
||||||
Span<byte> hpSpan = ctx.Hp.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref class0HpSpan[i], 1), 1);
|
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Class0Hp[i], 1), 1);
|
||||||
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref hpSpan[i], 1), 1);
|
r.UpdateMvProbs(MemoryMarshal.CreateSpan(ref ctx.Hp[i], 1), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -782,16 +751,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
int refr;
|
int refr;
|
||||||
bool isScaled;
|
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)
|
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||||
{
|
{
|
||||||
int frame = refFrameSpan[refr];
|
int frame = mi.RefFrame[refr];
|
||||||
ref RefBuffer refBuf = ref frameRefsSpan[frame - Constants.LastFrame];
|
ref RefBuffer refBuf = ref cm.FrameRefs[frame - Constants.LastFrame];
|
||||||
ref ScaleFactors sf = ref refBuf.Sf;
|
ref ScaleFactors sf = ref refBuf.Sf;
|
||||||
ref Surface refFrameBuf = ref refBuf.Buf;
|
ref Surface refFrameBuf = ref refBuf.Buf;
|
||||||
|
|
||||||
@@ -804,13 +767,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
isScaled = sf.IsScaled();
|
isScaled = sf.IsScaled();
|
||||||
ReconInter.SetupPrePlanes(ref xd, refr, ref refFrameBuf, miRow, miCol,
|
ReconInter.SetupPrePlanes(ref xd, refr, ref refFrameBuf, miRow, miCol,
|
||||||
isScaled ? new Ptr<ScaleFactors>(ref sf) : Ptr<ScaleFactors>.Null);
|
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)
|
if (sbType < BlockSize.Block8X8)
|
||||||
{
|
{
|
||||||
for (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];
|
||||||
ref Buf2D dstBuf = ref pd.Dst;
|
ref Buf2D dstBuf = ref pd.Dst;
|
||||||
int num4X4W = pd.N4W;
|
int num4X4W = pd.N4W;
|
||||||
int num4X4H = pd.N4H;
|
int num4X4H = pd.N4H;
|
||||||
@@ -848,10 +811,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Mv mv = mvSpan[refr];
|
Mv mv = mi.Mv[refr];
|
||||||
for (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];
|
||||||
ref Buf2D dstBuf = ref pd.Dst;
|
ref Buf2D dstBuf = ref pd.Dst;
|
||||||
int num4X4W = pd.N4W;
|
int num4X4W = pd.N4W;
|
||||||
int num4X4H = pd.N4H;
|
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)
|
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++)
|
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||||
{
|
{
|
||||||
planeSpan[i].N4W = (ushort)((bw << 1) >> planeSpan[i].SubsamplingX);
|
xd.Plane[i].N4W = (ushort)((bw << 1) >> xd.Plane[i].SubsamplingX);
|
||||||
planeSpan[i].N4H = (ushort)((bh << 1) >> planeSpan[i].SubsamplingY);
|
xd.Plane[i].N4H = (ushort)((bh << 1) >> xd.Plane[i].SubsamplingY);
|
||||||
planeSpan[i].N4Wl = (byte)(bwl - planeSpan[i].SubsamplingX);
|
xd.Plane[i].N4Wl = (byte)(bwl - xd.Plane[i].SubsamplingX);
|
||||||
planeSpan[i].N4Hl = (byte)(bhl - planeSpan[i].SubsamplingY);
|
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
|
// 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);
|
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;
|
return ref xd.Mi[0].Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -972,11 +933,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
if (!mi.IsInterBlock())
|
if (!mi.IsInterBlock())
|
||||||
{
|
{
|
||||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
int plane;
|
||||||
|
for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
|
||||||
for (int 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;
|
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
||||||
int num4X4W = pd.N4W;
|
int num4X4W = pd.N4W;
|
||||||
int num4X4H = pd.N4H;
|
int num4X4H = pd.N4H;
|
||||||
@@ -1007,13 +967,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// Reconstruction
|
// Reconstruction
|
||||||
if (mi.Skip == 0)
|
if (mi.Skip == 0)
|
||||||
{
|
{
|
||||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
|
||||||
|
|
||||||
int eobtotal = 0;
|
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;
|
TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
|
||||||
int num4X4W = pd.N4W;
|
int num4X4W = pd.N4W;
|
||||||
int num4X4H = pd.N4H;
|
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)
|
ref Reader r, int txSize)
|
||||||
{
|
{
|
||||||
if (r.ReadBit() != 0)
|
if (r.ReadBit() != 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < Constants.PlaneTypes; ++i)
|
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)
|
for (int j = 0; j < Entropy.RefTypes; ++j)
|
||||||
{
|
{
|
||||||
Span<Array6<Array3<byte>>> coefProbs3 = coefProbs2[j].AsSpan();
|
|
||||||
|
|
||||||
for (int k = 0; k < Entropy.CoefBands; ++k)
|
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)
|
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)
|
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)
|
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];
|
int maxTxSize = (int)Luts.TxModeToBiggestTxSize[(int)txMode];
|
||||||
|
|
||||||
for (int txSize = (int)TxSize.Tx4X4; txSize <= maxTxSize; ++txSize)
|
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;
|
lf.ModeRefDeltaUpdate = rb.ReadBit() != 0;
|
||||||
if (lf.ModeRefDeltaUpdate)
|
if (lf.ModeRefDeltaUpdate)
|
||||||
{
|
{
|
||||||
Span<sbyte> refDeltasSpan = lf.RefDeltas.AsSpan();
|
|
||||||
Span<sbyte> modeDeltasSpan = lf.ModeDeltas.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < LoopFilter.MaxRefLfDeltas; i++)
|
for (int i = 0; i < LoopFilter.MaxRefLfDeltas; i++)
|
||||||
{
|
{
|
||||||
if (rb.ReadBit() != 0)
|
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)
|
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);
|
cm.ResizeContextBuffers(allocator, width, height);
|
||||||
SetupRenderSize(ref cm, ref rb);
|
SetupRenderSize(ref cm, ref rb);
|
||||||
|
|
||||||
Span<RefCntBuffer> frameBuffsSpan = pool.FrameBufs.AsSpan();
|
|
||||||
|
|
||||||
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
||||||
allocator,
|
allocator,
|
||||||
cm.Width,
|
cm.Width,
|
||||||
@@ -1333,21 +1276,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
cm.UseHighBitDepth,
|
cm.UseHighBitDepth,
|
||||||
Surface.DecBorderInPixels,
|
Surface.DecBorderInPixels,
|
||||||
cm.ByteAlignment,
|
cm.ByteAlignment,
|
||||||
new Ptr<VpxCodecFrameBuffer>(ref frameBuffsSpan[cm.NewFbIdx].RawFrameBuffer),
|
new Ptr<VpxCodecFrameBuffer>(ref pool.FrameBufs[cm.NewFbIdx].RawFrameBuffer),
|
||||||
FrameBuffers.GetFrameBuffer,
|
FrameBuffers.GetFrameBuffer,
|
||||||
pool.CbPriv) != 0)
|
pool.CbPriv) != 0)
|
||||||
{
|
{
|
||||||
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
frameBuffsSpan[cm.NewFbIdx].Released = 0;
|
pool.FrameBufs[cm.NewFbIdx].Released = 0;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
pool.FrameBufs[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
pool.FrameBufs[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
pool.FrameBufs[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
pool.FrameBufs[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
pool.FrameBufs[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool ValidRefFrameImgFmt(
|
private static bool ValidRefFrameImgFmt(
|
||||||
@@ -1368,15 +1311,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
bool hasValidRefFrame = false;
|
bool hasValidRefFrame = false;
|
||||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
if (rb.ReadBit() != 0)
|
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;
|
width = buf.YCropWidth;
|
||||||
height = buf.YCropHeight;
|
height = buf.YCropHeight;
|
||||||
found = true;
|
found = true;
|
||||||
@@ -1401,7 +1342,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// has valid dimensions.
|
// has valid dimensions.
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
||||||
hasValidRefFrame |=
|
hasValidRefFrame |=
|
||||||
refFrame.Idx != RefBuffer.InvalidIdx &&
|
refFrame.Idx != RefBuffer.InvalidIdx &&
|
||||||
ScaleFactors.ValidRefFrameSize(refFrame.Buf.YCropWidth, refFrame.Buf.YCropHeight, width,
|
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)
|
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 ||
|
if (refFrame.Idx == RefBuffer.InvalidIdx ||
|
||||||
!ValidRefFrameImgFmt(
|
!ValidRefFrameImgFmt(
|
||||||
(BitDepth)refFrame.Buf.BitDepth,
|
(BitDepth)refFrame.Buf.BitDepth,
|
||||||
@@ -1433,8 +1374,6 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
cm.ResizeContextBuffers(allocator, width, height);
|
cm.ResizeContextBuffers(allocator, width, height);
|
||||||
SetupRenderSize(ref cm, ref rb);
|
SetupRenderSize(ref cm, ref rb);
|
||||||
|
|
||||||
Span<RefCntBuffer> frameBuffsSpan = pool.FrameBufs.AsSpan();
|
|
||||||
|
|
||||||
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
if (cm.GetFrameNewBuffer().ReallocFrameBuffer(
|
||||||
allocator,
|
allocator,
|
||||||
cm.Width,
|
cm.Width,
|
||||||
@@ -1444,21 +1383,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
cm.UseHighBitDepth,
|
cm.UseHighBitDepth,
|
||||||
Surface.DecBorderInPixels,
|
Surface.DecBorderInPixels,
|
||||||
cm.ByteAlignment,
|
cm.ByteAlignment,
|
||||||
new Ptr<VpxCodecFrameBuffer>(ref frameBuffsSpan[cm.NewFbIdx].RawFrameBuffer),
|
new Ptr<VpxCodecFrameBuffer>(ref pool.FrameBufs[cm.NewFbIdx].RawFrameBuffer),
|
||||||
FrameBuffers.GetFrameBuffer,
|
FrameBuffers.GetFrameBuffer,
|
||||||
pool.CbPriv) != 0)
|
pool.CbPriv) != 0)
|
||||||
{
|
{
|
||||||
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
cm.Error.InternalError(CodecErr.MemError, "Failed to allocate frame buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
frameBuffsSpan[cm.NewFbIdx].Released = 0;
|
pool.FrameBufs[cm.NewFbIdx].Released = 0;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingX = cm.SubsamplingX;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
pool.FrameBufs[cm.NewFbIdx].Buf.SubsamplingY = cm.SubsamplingY;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
pool.FrameBufs[cm.NewFbIdx].Buf.BitDepth = (uint)cm.BitDepth;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
pool.FrameBufs[cm.NewFbIdx].Buf.ColorSpace = cm.ColorSpace;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
pool.FrameBufs[cm.NewFbIdx].Buf.ColorRange = cm.ColorRange;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
pool.FrameBufs[cm.NewFbIdx].Buf.RenderWidth = cm.RenderWidth;
|
||||||
frameBuffsSpan[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
pool.FrameBufs[cm.NewFbIdx].Buf.RenderHeight = cm.RenderHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads the next tile returning its size and adjusting '*data' accordingly
|
// 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,
|
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)
|
for (int c = 0; c < tileCols; ++c)
|
||||||
{
|
{
|
||||||
@@ -1514,16 +1453,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ArrayPtr<byte> data,
|
ArrayPtr<byte> data,
|
||||||
int tileCols,
|
int tileCols,
|
||||||
int tileRows,
|
int tileRows,
|
||||||
Span<Array64<TileBuffer>> tileBuffers1)
|
ref Array4<Array64<TileBuffer>> tileBuffers)
|
||||||
{
|
{
|
||||||
for (int r = 0; r < tileRows; ++r)
|
for (int r = 0; r < tileRows; ++r)
|
||||||
{
|
{
|
||||||
Span<TileBuffer> tileBuffers2 = tileBuffers1[r].AsSpan();
|
|
||||||
|
|
||||||
for (int c = 0; c < tileCols; ++c)
|
for (int c = 0; c < tileCols; ++c)
|
||||||
{
|
{
|
||||||
bool isLast = r == tileRows - 1 && c == tileCols - 1;
|
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);
|
GetTileBuffer(isLast, ref cm.Error, ref data, ref buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1548,19 +1485,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
LoopFilter.ResetLfm(ref cm);
|
LoopFilter.ResetLfm(ref cm);
|
||||||
|
|
||||||
Span<Array64<TileBuffer>> tileBuffers1 = tileBuffers.AsSpan();
|
GetTileBuffers(ref cm, data, tileCols, tileRows, ref tileBuffers);
|
||||||
Span<TileWorkerData> tileWorkerDataSpan = cm.TileWorkerData.AsSpan();
|
|
||||||
|
|
||||||
GetTileBuffers(ref cm, data, tileCols, tileRows, tileBuffers1);
|
|
||||||
// Load all tile information into tile_data.
|
// Load all tile information into tile_data.
|
||||||
for (tileRow = 0; tileRow < tileRows; ++tileRow)
|
for (tileRow = 0; tileRow < tileRows; ++tileRow)
|
||||||
{
|
{
|
||||||
Span<TileBuffer> tileBuffers2 = tileBuffers1[tileRow].AsSpan();
|
|
||||||
|
|
||||||
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
||||||
{
|
{
|
||||||
ref TileBuffer buf = ref tileBuffers2[tileCol];
|
ref TileBuffer buf = ref tileBuffers[tileRow][tileCol];
|
||||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[(tileCols * tileRow) + tileCol];
|
ref TileWorkerData tileData = ref cm.TileWorkerData[(tileCols * tileRow) + tileCol];
|
||||||
tileData.Xd = cm.Mb;
|
tileData.Xd = cm.Mb;
|
||||||
tileData.Xd.Corrupted = false;
|
tileData.Xd.Corrupted = false;
|
||||||
tileData.Xd.Counts = cm.Counts;
|
tileData.Xd.Counts = cm.Counts;
|
||||||
@@ -1580,7 +1512,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
for (tileCol = 0; tileCol < tileCols; ++tileCol)
|
||||||
{
|
{
|
||||||
int col = 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);
|
tile.SetCol(ref cm, col);
|
||||||
tileData.Xd.LeftContext = new Array3<Array16<sbyte>>();
|
tileData.Xd.LeftContext = new Array3<Array16<sbyte>>();
|
||||||
tileData.Xd.LeftSegContext = new Array8<sbyte>();
|
tileData.Xd.LeftSegContext = new Array8<sbyte>();
|
||||||
@@ -1599,11 +1531,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get last tile data.
|
// 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,
|
private static bool DecodeTileCol(ref TileWorkerData tileData, ref Vp9Common cm,
|
||||||
Span<TileBuffer> tileBuffers)
|
ref Array64<TileBuffer> tileBuffers)
|
||||||
{
|
{
|
||||||
ref TileInfo tile = ref tileData.Xd.Tile;
|
ref TileInfo tile = ref tileData.Xd.Tile;
|
||||||
int finalCol = (1 << cm.Log2TileCols) - 1;
|
int finalCol = (1 << cm.Log2TileCols) - 1;
|
||||||
@@ -1662,11 +1594,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
cm.AboveContext.AsSpan().Clear();
|
cm.AboveContext.AsSpan().Clear();
|
||||||
cm.AboveSegContext.AsSpan().Clear();
|
cm.AboveSegContext.AsSpan().Clear();
|
||||||
|
|
||||||
Span<TileWorkerData> tileWorkerDataSpan = cm.TileWorkerData.AsSpan();
|
|
||||||
|
|
||||||
for (n = 0; n < numWorkers; ++n)
|
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 = cm.Mb;
|
||||||
tileData.Xd.Counts = new Ptr<Vp9BackwardUpdates>(ref tileData.Counts);
|
tileData.Xd.Counts = new Ptr<Vp9BackwardUpdates>(ref tileData.Counts);
|
||||||
@@ -1674,17 +1604,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
}
|
}
|
||||||
|
|
||||||
Array64<TileBuffer> tileBuffers = new();
|
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)
|
if (numWorkers == tileCols)
|
||||||
{
|
{
|
||||||
TileBuffer largest = tileBuffersSpan[0];
|
TileBuffer largest = tileBuffers[0];
|
||||||
tileBuffersSpan[1..].CopyTo(tileBuffersSpan[..^1]);
|
Span<TileBuffer> buffers = tileBuffers.AsSpan();
|
||||||
tileBuffersSpan[tileCols - 1] = largest;
|
buffers[1..].CopyTo(buffers[..(tileBuffers.Length - 1)]);
|
||||||
|
tileBuffers[tileCols - 1] = largest;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1695,9 +1625,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// larger tile implies it is more difficult to decode.
|
// larger tile implies it is more difficult to decode.
|
||||||
while (start < end)
|
while (start < end)
|
||||||
{
|
{
|
||||||
tmp = tileBuffersSpan[start];
|
tmp = tileBuffers[start];
|
||||||
tileBuffersSpan[start] = tileBuffersSpan[end];
|
tileBuffers[start] = tileBuffers[end];
|
||||||
tileBuffersSpan[end] = tmp;
|
tileBuffers[end] = tmp;
|
||||||
start += 2;
|
start += 2;
|
||||||
end -= 2;
|
end -= 2;
|
||||||
}
|
}
|
||||||
@@ -1710,7 +1640,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
for (n = 0; n < numWorkers; ++n)
|
for (n = 0; n < numWorkers; ++n)
|
||||||
{
|
{
|
||||||
int count = baseVal + ((remain + n) / numWorkers);
|
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.BufStart = bufStart;
|
||||||
tileData.BufEnd = bufStart + count - 1;
|
tileData.BufEnd = bufStart + count - 1;
|
||||||
@@ -1724,7 +1654,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
ref TileWorkerData tileData = ref cmPtr.Value.TileWorkerData[n + totalTiles];
|
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;
|
cmPtr.Value.Mb.Corrupted = true;
|
||||||
}
|
}
|
||||||
@@ -1734,14 +1664,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
if (bitReaderEnd.IsNull)
|
if (bitReaderEnd.IsNull)
|
||||||
{
|
{
|
||||||
ref TileWorkerData tileData = ref tileWorkerDataSpan[n - 1 + totalTiles];
|
ref TileWorkerData tileData = ref cm.TileWorkerData[n - 1 + totalTiles];
|
||||||
bitReaderEnd = tileData.DataEnd;
|
bitReaderEnd = tileData.DataEnd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (n = 0; n < numWorkers; ++n)
|
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);
|
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)
|
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;
|
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||||
|
|
||||||
for (int i = 0; i < Constants.FrameBuffers; ++i)
|
for (int i = 0; i < Constants.FrameBuffers; ++i)
|
||||||
@@ -1785,11 +1715,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
frameBuffs[i].RefCount = 0;
|
frameBufs[i].RefCount = 0;
|
||||||
if (frameBuffs[i].Released == 0)
|
if (frameBufs[i].Released == 0)
|
||||||
{
|
{
|
||||||
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBuffs[i].RawFrameBuffer);
|
FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[i].RawFrameBuffer);
|
||||||
frameBuffs[i].Released = 1;
|
frameBufs[i].Released = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1812,7 +1742,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
readSyncCode2 == SyncCode2;
|
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;
|
int refIndex = idx;
|
||||||
|
|
||||||
@@ -1831,15 +1761,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
ref Vp9Common cm = ref pbi.Common;
|
ref Vp9Common cm = ref pbi.Common;
|
||||||
ref BufferPool pool = ref cm.BufferPool.Value;
|
ref BufferPool pool = ref cm.BufferPool.Value;
|
||||||
Span<RefCntBuffer> frameBuffs = pool.FrameBufs.AsSpan();
|
ref Array12<RefCntBuffer> frameBufs = ref pool.FrameBufs;
|
||||||
int mask, refIndex = 0;
|
int mask, refIndex = 0;
|
||||||
ulong sz;
|
ulong sz;
|
||||||
|
|
||||||
cm.LastFrameType = cm.FrameType;
|
cm.LastFrameType = cm.FrameType;
|
||||||
cm.LastIntraOnly = cm.IntraOnly;
|
cm.LastIntraOnly = cm.IntraOnly;
|
||||||
|
|
||||||
Span<int> refFrameSpan = cm.RefFrameMap.AsSpan();
|
|
||||||
|
|
||||||
if (rb.ReadLiteral(2) != FrameMarker)
|
if (rb.ReadLiteral(2) != FrameMarker)
|
||||||
{
|
{
|
||||||
cm.Error.InternalError(CodecErr.UnsupBitstream, "Invalid frame marker");
|
cm.Error.InternalError(CodecErr.UnsupBitstream, "Invalid frame marker");
|
||||||
@@ -1855,14 +1783,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
if (cm.ShowExistingFrame != 0)
|
if (cm.ShowExistingFrame != 0)
|
||||||
{
|
{
|
||||||
// Show an existing frame directly.
|
// Show an existing frame directly.
|
||||||
int frameToShow = refFrameSpan[rb.ReadLiteral(3)];
|
int frameToShow = cm.RefFrameMap[rb.ReadLiteral(3)];
|
||||||
if (frameToShow < 0 || frameBuffs[frameToShow].RefCount < 1)
|
if (frameToShow < 0 || frameBufs[frameToShow].RefCount < 1)
|
||||||
{
|
{
|
||||||
cm.Error.InternalError(CodecErr.UnsupBitstream,
|
cm.Error.InternalError(CodecErr.UnsupBitstream,
|
||||||
$"Buffer {frameToShow} does not contain a decoded frame");
|
$"Buffer {frameToShow} does not contain a decoded frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
RefCntFb(frameBuffs, ref cm.NewFbIdx, frameToShow);
|
RefCntFb(ref frameBufs, ref cm.NewFbIdx, frameToShow);
|
||||||
pbi.RefreshFrameFlags = 0;
|
pbi.RefreshFrameFlags = 0;
|
||||||
cm.Lf.FilterLevel = 0;
|
cm.Lf.FilterLevel = 0;
|
||||||
cm.ShowFrame = 1;
|
cm.ShowFrame = 1;
|
||||||
@@ -1884,18 +1812,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
cm.ReadBitdepthColorspaceSampling(ref rb);
|
cm.ReadBitdepthColorspaceSampling(ref rb);
|
||||||
pbi.RefreshFrameFlags = (1 << Constants.RefFrames) - 1;
|
pbi.RefreshFrameFlags = (1 << Constants.RefFrames) - 1;
|
||||||
|
|
||||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
frameRefsSpan[i].Idx = RefBuffer.InvalidIdx;
|
cm.FrameRefs[i].Idx = RefBuffer.InvalidIdx;
|
||||||
frameRefsSpan[i].Buf = default;
|
cm.FrameRefs[i].Buf = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupFrameSize(allocator, ref cm, ref rb);
|
SetupFrameSize(allocator, ref cm, ref rb);
|
||||||
if (pbi.NeedResync != 0)
|
if (pbi.NeedResync != 0)
|
||||||
{
|
{
|
||||||
refFrameSpan.Fill(-1);
|
cm.RefFrameMap.AsSpan().Fill(-1);
|
||||||
FlushAllFbOnKey(ref cm);
|
FlushAllFbOnKey(ref cm);
|
||||||
pbi.NeedResync = 0;
|
pbi.NeedResync = 0;
|
||||||
}
|
}
|
||||||
@@ -1934,25 +1860,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
SetupFrameSize(allocator, ref cm, ref rb);
|
SetupFrameSize(allocator, ref cm, ref rb);
|
||||||
if (pbi.NeedResync != 0)
|
if (pbi.NeedResync != 0)
|
||||||
{
|
{
|
||||||
refFrameSpan.Fill(-1);
|
cm.RefFrameMap.AsSpan().Fill(-1);
|
||||||
pbi.NeedResync = 0;
|
pbi.NeedResync = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pbi.NeedResync != 1)
|
else if (pbi.NeedResync != 1)
|
||||||
{
|
{
|
||||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
|
||||||
Span<sbyte> refFrameSignBiasSpan = cm.RefFrameSignBias.AsSpan();
|
|
||||||
|
|
||||||
/* Skip if need resync */
|
/* Skip if need resync */
|
||||||
pbi.RefreshFrameFlags = rb.ReadLiteral(Constants.RefFrames);
|
pbi.RefreshFrameFlags = rb.ReadLiteral(Constants.RefFrames);
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
||||||
{
|
{
|
||||||
int refr = rb.ReadLiteral(Constants.RefFramesLog2);
|
int refr = rb.ReadLiteral(Constants.RefFramesLog2);
|
||||||
int idx = refFrameSpan[refr];
|
int idx = cm.RefFrameMap[refr];
|
||||||
ref RefBuffer refFrame = ref frameRefsSpan[i];
|
ref RefBuffer refFrame = ref cm.FrameRefs[i];
|
||||||
refFrame.Idx = idx;
|
refFrame.Idx = idx;
|
||||||
refFrame.Buf = frameBuffs[idx].Buf;
|
refFrame.Buf = frameBufs[idx].Buf;
|
||||||
refFrameSignBiasSpan[Constants.LastFrame + i] = (sbyte)rb.ReadBit();
|
cm.RefFrameSignBias[Constants.LastFrame + i] = (sbyte)rb.ReadBit();
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupFrameSizeWithRefs(allocator, ref cm, ref rb);
|
SetupFrameSizeWithRefs(allocator, ref cm, ref rb);
|
||||||
@@ -1962,7 +1885,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
for (int i = 0; i < Constants.RefsPerFrame; ++i)
|
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.Sf.SetupScaleFactorsForFrame(
|
||||||
refBuf.Buf.YCropWidth,
|
refBuf.Buf.YCropWidth,
|
||||||
refBuf.Buf.YCropHeight,
|
refBuf.Buf.YCropHeight,
|
||||||
@@ -2003,25 +1926,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// below, forcing the use of context 0 for those frame types.
|
// below, forcing the use of context 0 for those frame types.
|
||||||
cm.FrameContextIdx = (uint)rb.ReadLiteral(Constants.FrameContextsLog2);
|
cm.FrameContextIdx = (uint)rb.ReadLiteral(Constants.FrameContextsLog2);
|
||||||
|
|
||||||
Span<int> nextRefFrameMapSpan = cm.NextRefFrameMap.AsSpan();
|
|
||||||
|
|
||||||
// Generate next_ref_frame_map.
|
// Generate next_ref_frame_map.
|
||||||
for (mask = pbi.RefreshFrameFlags; mask != 0; mask >>= 1)
|
for (mask = pbi.RefreshFrameFlags; mask != 0; mask >>= 1)
|
||||||
{
|
{
|
||||||
if ((mask & 1) != 0)
|
if ((mask & 1) != 0)
|
||||||
{
|
{
|
||||||
nextRefFrameMapSpan[refIndex] = cm.NewFbIdx;
|
cm.NextRefFrameMap[refIndex] = cm.NewFbIdx;
|
||||||
++frameBuffs[cm.NewFbIdx].RefCount;
|
++frameBufs[cm.NewFbIdx].RefCount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nextRefFrameMapSpan[refIndex] = cm.RefFrameMap[refIndex];
|
cm.NextRefFrameMap[refIndex] = cm.RefFrameMap[refIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current thread holds the reference frame.
|
// Current thread holds the reference frame.
|
||||||
if (cm.RefFrameMap[refIndex] >= 0)
|
if (cm.RefFrameMap[refIndex] >= 0)
|
||||||
{
|
{
|
||||||
++frameBuffs[cm.RefFrameMap[refIndex]].RefCount;
|
++frameBufs[cm.RefFrameMap[refIndex]].RefCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
++refIndex;
|
++refIndex;
|
||||||
@@ -2029,11 +1950,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
for (; refIndex < Constants.RefFrames; ++refIndex)
|
for (; refIndex < Constants.RefFrames; ++refIndex)
|
||||||
{
|
{
|
||||||
nextRefFrameMapSpan[refIndex] = refFrameSpan[refIndex];
|
cm.NextRefFrameMap[refIndex] = cm.RefFrameMap[refIndex];
|
||||||
// Current thread holds the reference frame.
|
// 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);
|
ReadCoefProbs(ref fc, cm.TxMode, ref r);
|
||||||
|
|
||||||
Span<byte> skipProbSpan = fc.SkipProb.AsSpan();
|
|
||||||
|
|
||||||
for (int k = 0; k < Constants.SkipContexts; ++k)
|
for (int k = 0; k < Constants.SkipContexts; ++k)
|
||||||
{
|
{
|
||||||
r.DiffUpdateProb(ref skipProbSpan[k]);
|
r.DiffUpdateProb(ref fc.SkipProb[k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cm.FrameIsIntraOnly())
|
if (!cm.FrameIsIntraOnly())
|
||||||
@@ -2096,11 +2015,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ReadSwitchableInterpProbs(ref fc, ref r);
|
ReadSwitchableInterpProbs(ref fc, ref r);
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<byte> intraInterProbSpan = fc.IntraInterProb.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Constants.IntraInterContexts; i++)
|
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);
|
cm.ReferenceMode = cm.ReadFrameReferenceMode(ref r);
|
||||||
@@ -2111,27 +2028,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
cm.ReadFrameReferenceModeProbs(ref r);
|
cm.ReadFrameReferenceModeProbs(ref r);
|
||||||
|
|
||||||
Span<Array9<byte>> yModeProbSpan1 = fc.YModeProb.AsSpan();
|
|
||||||
|
|
||||||
for (int j = 0; j < EntropyMode.BlockSizeGroups; j++)
|
for (int j = 0; j < EntropyMode.BlockSizeGroups; j++)
|
||||||
{
|
{
|
||||||
Span<byte> yModeProbSpan2 = yModeProbSpan1[j].AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Constants.IntraModes - 1; ++i)
|
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)
|
for (int j = 0; j < Constants.PartitionContexts; ++j)
|
||||||
{
|
{
|
||||||
Span<byte> partitionProbSpan2 = partitionProbSpan1[j].AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Constants.PartitionTypes - 1; ++i)
|
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);
|
xd.SetupBlockPlanes(cm.SubsamplingX, cm.SubsamplingY);
|
||||||
|
|
||||||
Span<Vp9EntropyProbs> frameContextsSpan = cm.FrameContexts.AsSpan();
|
cm.Fc = new Ptr<Vp9EntropyProbs>(ref cm.FrameContexts[(int)cm.FrameContextIdx]);
|
||||||
|
|
||||||
cm.Fc = new Ptr<Vp9EntropyProbs>(ref frameContextsSpan[(int)cm.FrameContextIdx]);
|
|
||||||
|
|
||||||
xd.Corrupted = false;
|
xd.Corrupted = false;
|
||||||
newFb.Corrupted = ReadCompressedHeader(ref pbi, data, firstPartitionSize) ? 1 : 0;
|
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.
|
// Non frame parallel update frame context here.
|
||||||
if (cm.RefreshFrameContext != 0 && contextUpdated == 0)
|
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;
|
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)
|
private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx)
|
||||||
@@ -187,7 +187,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
return 0;
|
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);
|
SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
|
||||||
return segmentId;
|
return segmentId;
|
||||||
}
|
}
|
||||||
@@ -223,15 +223,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
if (seg.TemporalUpdate)
|
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);
|
mi.SegIdPredicted = (sbyte)r.Read(predProb);
|
||||||
segmentId = mi.SegIdPredicted != 0
|
segmentId = mi.SegIdPredicted != 0
|
||||||
? predictedSegmentId
|
? predictedSegmentId
|
||||||
: ReadSegmentId(ref r, cm.Fc.Value.SegTreeProb.AsSpan());
|
: ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
|
||||||
}
|
}
|
||||||
else
|
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);
|
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
|
int n = (int)mvClass + Constants.Class0Bits - 1; // Number of bits
|
||||||
|
|
||||||
Span<byte> bitsSpan = fc.Bits[mvcomp].AsSpan();
|
|
||||||
|
|
||||||
d = 0;
|
d = 0;
|
||||||
for (int i = 0; i < n; ++i)
|
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);
|
mag = Constants.Class0Size << ((int)mvClass + 2);
|
||||||
@@ -345,7 +343,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ref MacroBlockD xd,
|
ref MacroBlockD xd,
|
||||||
ref Reader r,
|
ref Reader r,
|
||||||
int segmentId,
|
int segmentId,
|
||||||
Span<sbyte> refFrame)
|
ref Array2<sbyte> refFrame)
|
||||||
{
|
{
|
||||||
ref Vp9EntropyProbs fc = ref cm.Fc.Value;
|
ref Vp9EntropyProbs fc = ref cm.Fc.Value;
|
||||||
|
|
||||||
@@ -420,25 +418,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
BlockSize bsize = mi.SbType;
|
BlockSize bsize = mi.SbType;
|
||||||
|
|
||||||
Span<BModeInfo> bmiSpan = mi.Bmi.AsSpan();
|
|
||||||
|
|
||||||
switch (bsize)
|
switch (bsize)
|
||||||
{
|
{
|
||||||
case BlockSize.Block4X4:
|
case BlockSize.Block4X4:
|
||||||
for (int i = 0; i < 4; ++i)
|
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;
|
break;
|
||||||
case BlockSize.Block4X8:
|
case BlockSize.Block4X8:
|
||||||
bmiSpan[0].Mode = bmiSpan[2].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);
|
||||||
bmiSpan[1].Mode = bmiSpan[3].Mode = mi.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;
|
break;
|
||||||
case BlockSize.Block8X4:
|
case BlockSize.Block8X4:
|
||||||
bmiSpan[0].Mode = bmiSpan[1].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);
|
||||||
bmiSpan[2].Mode = bmiSpan[3].Mode = mi.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;
|
break;
|
||||||
default:
|
default:
|
||||||
mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]);
|
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()
|
// modes in GetPredContextSwitchableInterp()
|
||||||
mi.InterpFilter = Constants.SwitchableFilters;
|
mi.InterpFilter = Constants.SwitchableFilters;
|
||||||
|
|
||||||
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
mi.RefFrame[0] = Constants.IntraFrame;
|
||||||
|
mi.RefFrame[1] = Constants.None;
|
||||||
|
}
|
||||||
|
|
||||||
refFrameSpan[0] = Constants.IntraFrame;
|
private static void CopyPair(ref Array2<Mv> dst, ref Array2<Mv> src)
|
||||||
refFrameSpan[1] = Constants.None;
|
{
|
||||||
|
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(
|
private static bool Assign(
|
||||||
ref Vp9Common cm,
|
ref Vp9Common cm,
|
||||||
ref MacroBlockD xd,
|
ref MacroBlockD xd,
|
||||||
PredictionMode mode,
|
PredictionMode mode,
|
||||||
Span<Mv> mv,
|
ref Array2<Mv> mv,
|
||||||
Span<Mv> refMv,
|
ref Array2<Mv> refMv,
|
||||||
Span<Mv> nearNearestMv,
|
ref Array2<Mv> nearNearestMv,
|
||||||
int isCompound,
|
int isCompound,
|
||||||
bool allowHp,
|
bool allowHp,
|
||||||
ref Reader r)
|
ref Reader r)
|
||||||
@@ -485,12 +491,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
case PredictionMode.NearMv:
|
case PredictionMode.NearMv:
|
||||||
case PredictionMode.NearestMv:
|
case PredictionMode.NearestMv:
|
||||||
{
|
{
|
||||||
nearNearestMv.CopyTo(mv);
|
CopyPair(ref mv, ref nearNearestMv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PredictionMode.ZeroMv:
|
case PredictionMode.ZeroMv:
|
||||||
{
|
{
|
||||||
mv.Clear();
|
ZeroPair(ref mv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -553,29 +559,26 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
private static bool IsDiffRefFrameAddEb(
|
private static bool IsDiffRefFrameAddEb(
|
||||||
ref ModeInfo mbmi,
|
ref ModeInfo mbmi,
|
||||||
sbyte refFrame,
|
sbyte refFrame,
|
||||||
Span<sbyte> refSignBias,
|
ref Array4<sbyte> refSignBias,
|
||||||
ref int refmvCount,
|
ref int refmvCount,
|
||||||
Span<Mv> mvRefList,
|
Span<Mv> mvRefList,
|
||||||
bool earlyBreak)
|
bool earlyBreak)
|
||||||
{
|
{
|
||||||
if (mbmi.IsInterBlock())
|
if (mbmi.IsInterBlock())
|
||||||
{
|
{
|
||||||
Span<sbyte> refFrameSpan = mbmi.RefFrame.AsSpan();
|
if (mbmi.RefFrame[0] != refFrame)
|
||||||
Span<Mv> mvSpan = mbmi.Mv.AsSpan();
|
|
||||||
|
|
||||||
if (refFrameSpan[0] != refFrame)
|
|
||||||
{
|
{
|
||||||
if (AddRefListEb(mbmi.ScaleMv(0, refFrame, refSignBias), ref refmvCount, mvRefList,
|
if (AddRefListEb(mbmi.ScaleMv(0, refFrame, ref refSignBias), ref refmvCount, mvRefList,
|
||||||
earlyBreak))
|
earlyBreak))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mbmi.HasSecondRef() && refFrameSpan[1] != refFrame &&
|
if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame &&
|
||||||
Unsafe.As<Mv, int>(ref mvSpan[1]) != Unsafe.As<Mv, int>(ref mvSpan[0]))
|
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))
|
earlyBreak))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -600,7 +603,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
int block,
|
int block,
|
||||||
int isSub8X8)
|
int isSub8X8)
|
||||||
{
|
{
|
||||||
Span<sbyte> refSignBias = cm.RefFrameSignBias.AsSpan();
|
ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias;
|
||||||
int i, refmvCount = 0;
|
int i, refmvCount = 0;
|
||||||
bool differentRefFound = false;
|
bool differentRefFound = false;
|
||||||
Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs
|
Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs
|
||||||
@@ -627,9 +630,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||||
differentRefFound = true;
|
differentRefFound = true;
|
||||||
|
|
||||||
Span<sbyte> refFrameSpan = candidateMi.RefFrame.AsSpan();
|
if (candidateMi.RefFrame[0] == refFrame)
|
||||||
|
|
||||||
if (refFrameSpan[0] == refFrame)
|
|
||||||
{
|
{
|
||||||
if (AddRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount,
|
if (AddRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount,
|
||||||
mvRefList, earlyBreak))
|
mvRefList, earlyBreak))
|
||||||
@@ -637,7 +638,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
goto Done;
|
goto Done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (refFrameSpan[1] == refFrame)
|
else if (candidateMi.RefFrame[1] == refFrame)
|
||||||
{
|
{
|
||||||
if (AddRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount,
|
if (AddRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount,
|
||||||
mvRefList, earlyBreak))
|
mvRefList, earlyBreak))
|
||||||
@@ -660,19 +661,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
||||||
differentRefFound = true;
|
differentRefFound = true;
|
||||||
|
|
||||||
Span<sbyte> refFrameSpan = candidate.RefFrame.AsSpan();
|
if (candidate.RefFrame[0] == refFrame)
|
||||||
Span<Mv> mvSpan = candidate.Mv.AsSpan();
|
|
||||||
|
|
||||||
if (refFrameSpan[0] == refFrame)
|
|
||||||
{
|
{
|
||||||
if (AddRefListEb(mvSpan[0], ref refmvCount, mvRefList, earlyBreak))
|
if (AddRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak))
|
||||||
{
|
{
|
||||||
goto Done;
|
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;
|
goto Done;
|
||||||
}
|
}
|
||||||
@@ -683,19 +681,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// Check the last frame's mode and mv info.
|
// Check the last frame's mode and mv info.
|
||||||
if (!prevFrameMvs.IsNull)
|
if (!prevFrameMvs.IsNull)
|
||||||
{
|
{
|
||||||
Span<sbyte> refFrameSpan = prevFrameMvs.Value.RefFrame.AsSpan();
|
if (prevFrameMvs.Value.RefFrame[0] == refFrame)
|
||||||
Span<Mv> mvSpan = prevFrameMvs.Value.Mv.AsSpan();
|
|
||||||
|
|
||||||
if (refFrameSpan[0] == refFrame)
|
|
||||||
{
|
{
|
||||||
if (AddRefListEb(mvSpan[0], ref refmvCount, mvRefList, earlyBreak))
|
if (AddRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak))
|
||||||
{
|
{
|
||||||
goto Done;
|
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;
|
goto Done;
|
||||||
}
|
}
|
||||||
@@ -715,7 +710,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ref ModeInfo candidate = ref xd.Mi[mvRef.Col + (mvRef.Row * xd.MiStride)].Value;
|
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 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))
|
earlyBreak))
|
||||||
{
|
{
|
||||||
goto Done;
|
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.
|
// Since we still don't have a candidate we'll try the last frame.
|
||||||
if (!prevFrameMvs.IsNull)
|
if (!prevFrameMvs.IsNull)
|
||||||
{
|
{
|
||||||
Span<sbyte> refFrameSpan = prevFrameMvs.Value.RefFrame.AsSpan();
|
if (prevFrameMvs.Value.RefFrame[0] != refFrame && prevFrameMvs.Value.RefFrame[0] > Constants.IntraFrame)
|
||||||
Span<Mv> mvSpan = prevFrameMvs.Value.Mv.AsSpan();
|
|
||||||
|
|
||||||
if (refFrameSpan[0] != refFrame && refFrameSpan[0] > Constants.IntraFrame)
|
|
||||||
{
|
{
|
||||||
Mv mv = mvSpan[0];
|
Mv mv = prevFrameMvs.Value.Mv[0];
|
||||||
if (refSignBias[refFrameSpan[0]] != refSignBias[refFrame])
|
if (refSignBias[prevFrameMvs.Value.RefFrame[0]] != refSignBias[refFrame])
|
||||||
{
|
{
|
||||||
mv.Row *= -1;
|
mv.Row *= -1;
|
||||||
mv.Col *= -1;
|
mv.Col *= -1;
|
||||||
@@ -745,13 +737,13 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (refFrameSpan[1] > Constants.IntraFrame &&
|
if (prevFrameMvs.Value.RefFrame[1] > Constants.IntraFrame &&
|
||||||
refFrameSpan[1] != refFrame &&
|
prevFrameMvs.Value.RefFrame[1] != refFrame &&
|
||||||
Unsafe.As<Mv, int>(ref mvSpan[1]) !=
|
Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[1]) !=
|
||||||
Unsafe.As<Mv, int>(ref mvSpan[0]))
|
Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[0]))
|
||||||
{
|
{
|
||||||
Mv mv = mvSpan[1];
|
Mv mv = prevFrameMvs.Value.Mv[1];
|
||||||
if (refSignBias[refFrameSpan[1]] != refSignBias[refFrame])
|
if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame])
|
||||||
{
|
{
|
||||||
mv.Row *= -1;
|
mv.Row *= -1;
|
||||||
mv.Col *= -1;
|
mv.Col *= -1;
|
||||||
@@ -797,7 +789,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
|
Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
|
||||||
ref ModeInfo mi = ref xd.Mi[0].Value;
|
ref ModeInfo mi = ref xd.Mi[0].Value;
|
||||||
Span<BModeInfo> bmi = mi.Bmi.AsSpan();
|
ref Array4<BModeInfo> bmi = ref mi.Bmi;
|
||||||
int refmvCount;
|
int refmvCount;
|
||||||
|
|
||||||
Debug.Assert(Constants.MaxMvRefCandidates == 2);
|
Debug.Assert(Constants.MaxMvRefCandidates == 2);
|
||||||
@@ -892,12 +884,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
BlockSize bsize = mi.SbType;
|
BlockSize bsize = mi.SbType;
|
||||||
bool allowHp = cm.AllowHighPrecisionMv;
|
bool allowHp = cm.AllowHighPrecisionMv;
|
||||||
Array2<Mv> bestRefMvs = new();
|
Array2<Mv> bestRefMvs = new();
|
||||||
Span<Mv> bestRefMvsSpan = bestRefMvs.AsSpan();
|
|
||||||
int refr, isCompound;
|
int refr, isCompound;
|
||||||
byte interModeCtx;
|
byte interModeCtx;
|
||||||
Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize];
|
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;
|
isCompound = mi.HasSecondRef() ? 1 : 0;
|
||||||
interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
|
interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
|
||||||
|
|
||||||
@@ -929,17 +920,16 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
if (mi.Mode != PredictionMode.ZeroMv)
|
if (mi.Mode != PredictionMode.ZeroMv)
|
||||||
{
|
{
|
||||||
Span<Mv> tmpMvs = stackalloc Mv[Constants.MaxMvRefCandidates];
|
Span<Mv> tmpMvs = stackalloc Mv[Constants.MaxMvRefCandidates];
|
||||||
Span<sbyte> refFrameSpan = mi.RefFrame.AsSpan();
|
|
||||||
|
|
||||||
for (refr = 0; refr < 1 + isCompound; ++refr)
|
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||||
{
|
{
|
||||||
sbyte frame = refFrameSpan[refr];
|
sbyte frame = mi.RefFrame[refr];
|
||||||
int refmvCount;
|
int refmvCount;
|
||||||
|
|
||||||
refmvCount = DecFindRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol,
|
refmvCount = DecFindRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol,
|
||||||
-1, 0);
|
-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;
|
int idx, idy;
|
||||||
PredictionMode bMode = 0;
|
PredictionMode bMode = 0;
|
||||||
Array2<Mv> bestSub8X8 = new();
|
Array2<Mv> bestSub8X8 = new();
|
||||||
Span<Mv> bestSub8X8Span = bestSub8X8.AsSpan();
|
|
||||||
Span<BModeInfo> bmiSpan = mi.Bmi.AsSpan();
|
|
||||||
const uint InvalidMv = 0x80008000;
|
const uint InvalidMv = 0x80008000;
|
||||||
// Initialize the 2nd element as even though it won't be used meaningfully
|
// Initialize the 2nd element as even though it won't be used meaningfully
|
||||||
// if isCompound is false.
|
// 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 (idy = 0; idy < 2; idy += num4X4H)
|
||||||
{
|
{
|
||||||
for (idx = 0; idx < 2; idx += num4X4W)
|
for (idx = 0; idx < 2; idx += num4X4W)
|
||||||
@@ -973,11 +961,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
for (refr = 0; refr < 1 + isCompound; ++refr)
|
for (refr = 0; refr < 1 + isCompound; ++refr)
|
||||||
{
|
{
|
||||||
AppendSub8X8ForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol,
|
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))
|
isCompound, allowHp, ref r))
|
||||||
{
|
{
|
||||||
xd.Corrupted |= true;
|
xd.Corrupted |= true;
|
||||||
@@ -986,22 +974,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
if (num4X4H == 2)
|
if (num4X4H == 2)
|
||||||
{
|
{
|
||||||
bmiSpan[j + 2] = bmiSpan[j];
|
mi.Bmi[j + 2] = mi.Bmi[j];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num4X4W == 2)
|
if (num4X4W == 2)
|
||||||
{
|
{
|
||||||
bmiSpan[j + 1] = bmiSpan[j];
|
mi.Bmi[j + 1] = mi.Bmi[j];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mi.Mode = bMode;
|
mi.Mode = bMode;
|
||||||
bmiSpan[3].Mv.AsSpan().CopyTo(mi.Mv.AsSpan());
|
|
||||||
|
CopyPair(ref mi.Mv, ref mi.Bmi[3].Mv);
|
||||||
}
|
}
|
||||||
else
|
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);
|
isCompound, allowHp, ref r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1093,42 +1082,33 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
int miOffset = (miRow * cm.MiCols) + miCol;
|
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.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.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r);
|
||||||
mi.Value.TxSize = ReadTxSize(ref cm, ref xd, true, ref r);
|
mi.Value.TxSize = ReadTxSize(ref cm, ref xd, true, ref r);
|
||||||
refFrameSpan[0] = Constants.IntraFrame;
|
mi.Value.RefFrame[0] = Constants.IntraFrame;
|
||||||
refFrameSpan[1] = Constants.None;
|
mi.Value.RefFrame[1] = Constants.None;
|
||||||
|
|
||||||
Span<BModeInfo> bmiSpan;
|
|
||||||
switch (bsize)
|
switch (bsize)
|
||||||
{
|
{
|
||||||
case BlockSize.Block4X4:
|
case BlockSize.Block4X4:
|
||||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i)
|
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));
|
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;
|
break;
|
||||||
case BlockSize.Block4X8:
|
case BlockSize.Block4X8:
|
||||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
mi.Value.Bmi[0].Mode = mi.Value.Bmi[2].Mode =
|
||||||
|
|
||||||
bmiSpan[0].Mode = bmiSpan[2].Mode =
|
|
||||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
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));
|
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 1));
|
||||||
break;
|
break;
|
||||||
case BlockSize.Block8X4:
|
case BlockSize.Block8X4:
|
||||||
bmiSpan = mi.Value.Bmi.AsSpan();
|
mi.Value.Bmi[0].Mode = mi.Value.Bmi[1].Mode =
|
||||||
|
|
||||||
bmiSpan[0].Mode = bmiSpan[1].Mode =
|
|
||||||
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
|
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));
|
ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 2));
|
||||||
break;
|
break;
|
||||||
default:
|
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());
|
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(
|
public static void ReadModeInfo(
|
||||||
ref TileWorkerData twd,
|
ref TileWorkerData twd,
|
||||||
ref Vp9Common cm,
|
ref Vp9Common cm,
|
||||||
@@ -1165,8 +1151,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
for (int w = 0; w < xMis; ++w)
|
for (int w = 0; w < xMis; ++w)
|
||||||
{
|
{
|
||||||
ref MvRef mv = ref frameMvs[w];
|
ref MvRef mv = ref frameMvs[w];
|
||||||
mi.RefFrame.AsSpan().CopyTo(mv.RefFrame.AsSpan());
|
CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame);
|
||||||
mi.Mv.AsSpan().CopyTo(mv.Mv.AsSpan());
|
CopyPair(ref mv.Mv, ref mi.Mv);
|
||||||
}
|
}
|
||||||
|
|
||||||
frameMvs = frameMvs.Slice(cm.MiCols);
|
frameMvs = frameMvs.Slice(cm.MiCols);
|
||||||
|
@@ -89,10 +89,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
cm.Lf.RefDeltas = pictureInfo.RefDeltas;
|
cm.Lf.RefDeltas = pictureInfo.RefDeltas;
|
||||||
cm.Lf.ModeDeltas = pictureInfo.ModeDeltas;
|
cm.Lf.ModeDeltas = pictureInfo.ModeDeltas;
|
||||||
|
|
||||||
Span<RefBuffer> frameRefsSpan = cm.FrameRefs.AsSpan();
|
cm.FrameRefs[0].Buf = (Surface)pictureInfo.LastReference;
|
||||||
frameRefsSpan[0].Buf = (Surface)pictureInfo.LastReference;
|
cm.FrameRefs[1].Buf = (Surface)pictureInfo.GoldenReference;
|
||||||
frameRefsSpan[1].Buf = (Surface)pictureInfo.GoldenReference;
|
cm.FrameRefs[2].Buf = (Surface)pictureInfo.AltReference;
|
||||||
frameRefsSpan[2].Buf = (Surface)pictureInfo.AltReference;
|
|
||||||
cm.Mb.CurBuf = (Surface)output;
|
cm.Mb.CurBuf = (Surface)output;
|
||||||
|
|
||||||
cm.Mb.SetupBlockPlanes(1, 1);
|
cm.Mb.SetupBlockPlanes(1, 1);
|
||||||
|
@@ -28,7 +28,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
PlaneType type,
|
PlaneType type,
|
||||||
Span<int> dqcoeff,
|
Span<int> dqcoeff,
|
||||||
TxSize txSize,
|
TxSize txSize,
|
||||||
ReadOnlySpan<short> dq,
|
ref Array2<short> dq,
|
||||||
int ctx,
|
int ctx,
|
||||||
ReadOnlySpan<short> scan,
|
ReadOnlySpan<short> scan,
|
||||||
ReadOnlySpan<short> nb,
|
ReadOnlySpan<short> nb,
|
||||||
@@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ref Vp9EntropyProbs fc = ref xd.Fc.Value;
|
ref Vp9EntropyProbs fc = ref xd.Fc.Value;
|
||||||
int refr = xd.Mi[0].Value.IsInterBlock() ? 1 : 0;
|
int refr = xd.Mi[0].Value.IsInterBlock() ? 1 : 0;
|
||||||
int band, c = 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];
|
Span<byte> tokenCache = stackalloc byte[32 * 32];
|
||||||
ReadOnlySpan<byte> bandTranslate = Luts.GetBandTranslate(txSize);
|
ReadOnlySpan<byte> bandTranslate = Luts.GetBandTranslate(txSize);
|
||||||
int dqShift = txSize == TxSize.Tx32X32 ? 1 : 0;
|
int dqShift = txSize == TxSize.Tx32X32 ? 1 : 0;
|
||||||
@@ -57,25 +57,22 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
uint range = r.Range;
|
uint range = r.Range;
|
||||||
int count = r.Count;
|
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)
|
while (c < maxEob)
|
||||||
{
|
{
|
||||||
int val = -1;
|
int val = -1;
|
||||||
band = bandTranslate[0];
|
band = bandTranslate[0];
|
||||||
bandTranslate = bandTranslate[1..];
|
bandTranslate = bandTranslate[1..];
|
||||||
ReadOnlySpan<byte> prob = coefProbs[band][ctx].AsSpan();
|
ref Array3<byte> prob = ref coefProbs[band][ctx];
|
||||||
if (!xd.Counts.IsNull)
|
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 (r.ReadBool(prob[EobContextNode], ref value, ref count, ref range) == 0)
|
||||||
{
|
{
|
||||||
if (!xd.Counts.IsNull)
|
if (!xd.Counts.IsNull)
|
||||||
{
|
{
|
||||||
++coefSpan[band][ctx][Constants.EobModelToken];
|
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.EobModelToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -85,7 +82,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
if (!xd.Counts.IsNull)
|
if (!xd.Counts.IsNull)
|
||||||
{
|
{
|
||||||
++coefSpan[band][ctx][Constants.ZeroToken];
|
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.ZeroToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
dqv = dq[1];
|
dqv = dq[1];
|
||||||
@@ -102,7 +99,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ctx = GetCoefContext(nb, tokenCache, c);
|
ctx = GetCoefContext(nb, tokenCache, c);
|
||||||
band = bandTranslate[0];
|
band = bandTranslate[0];
|
||||||
bandTranslate = bandTranslate[1..];
|
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)
|
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];
|
ReadOnlySpan<byte> p = Luts.Pareto8Full[prob[Constants.PivotNode] - 1];
|
||||||
if (!xd.Counts.IsNull)
|
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)
|
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)
|
if (!xd.Counts.IsNull)
|
||||||
{
|
{
|
||||||
++coefSpan[band][ctx][Constants.OneToken];
|
++counts.Coef[(int)txSize][(int)type][refr][band][ctx][Constants.OneToken];
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenCache[scan[c]] = 1;
|
tokenCache[scan[c]] = 1;
|
||||||
@@ -235,7 +232,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
ref Reader r = ref twd.BitReader;
|
ref Reader r = ref twd.BitReader;
|
||||||
ref MacroBlockD xd = ref twd.Xd;
|
ref MacroBlockD xd = ref twd.Xd;
|
||||||
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
ref MacroBlockDPlane pd = ref xd.Plane[plane];
|
||||||
Span<short> dequant = pd.SegDequant[segId].AsSpan();
|
ref Array2<short> dequant = ref pd.SegDequant[segId];
|
||||||
int eob;
|
int eob;
|
||||||
Span<sbyte> a = pd.AboveContext.AsSpan()[x..];
|
Span<sbyte> a = pd.AboveContext.AsSpan()[x..];
|
||||||
Span<sbyte> l = pd.LeftContext.AsSpan()[y..];
|
Span<sbyte> l = pd.LeftContext.AsSpan()[y..];
|
||||||
@@ -253,7 +250,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
GetPlaneType(plane),
|
GetPlaneType(plane),
|
||||||
pd.DqCoeff.AsSpan(),
|
pd.DqCoeff.AsSpan(),
|
||||||
txSize,
|
txSize,
|
||||||
dequant,
|
ref dequant,
|
||||||
ctx,
|
ctx,
|
||||||
sc.Scan,
|
sc.Scan,
|
||||||
sc.Neighbors,
|
sc.Neighbors,
|
||||||
@@ -269,7 +266,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
GetPlaneType(plane),
|
GetPlaneType(plane),
|
||||||
pd.DqCoeff.AsSpan(),
|
pd.DqCoeff.AsSpan(),
|
||||||
txSize,
|
txSize,
|
||||||
dequant,
|
ref dequant,
|
||||||
ctx,
|
ctx,
|
||||||
sc.Scan,
|
sc.Scan,
|
||||||
sc.Neighbors,
|
sc.Neighbors,
|
||||||
@@ -286,7 +283,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
GetPlaneType(plane),
|
GetPlaneType(plane),
|
||||||
pd.DqCoeff.AsSpan(),
|
pd.DqCoeff.AsSpan(),
|
||||||
txSize,
|
txSize,
|
||||||
dequant,
|
ref dequant,
|
||||||
ctx,
|
ctx,
|
||||||
sc.Scan,
|
sc.Scan,
|
||||||
sc.Neighbors,
|
sc.Neighbors,
|
||||||
@@ -306,7 +303,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
GetPlaneType(plane),
|
GetPlaneType(plane),
|
||||||
pd.DqCoeff.AsSpan(),
|
pd.DqCoeff.AsSpan(),
|
||||||
txSize,
|
txSize,
|
||||||
dequant,
|
ref dequant,
|
||||||
ctx,
|
ctx,
|
||||||
sc.Scan,
|
sc.Scan,
|
||||||
sc.Neighbors,
|
sc.Neighbors,
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Intrinsics;
|
using System.Runtime.Intrinsics;
|
||||||
@@ -130,7 +129,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
|||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
byte* srcX = &src[xQ4 >> SubpelBits];
|
byte* srcX = &src[xQ4 >> SubpelBits];
|
||||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
@@ -165,7 +164,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
|||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
byte* srcX = &src[xQ4 >> SubpelBits];
|
byte* srcX = &src[xQ4 >> SubpelBits];
|
||||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
@@ -276,7 +275,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
|||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
@@ -311,7 +310,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
|||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
byte* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
@@ -620,7 +619,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
|||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
ushort* srcX = &src[xQ4 >> SubpelBits];
|
ushort* srcX = &src[xQ4 >> SubpelBits];
|
||||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
@@ -656,7 +655,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
|||||||
for (int x = 0; x < w; ++x)
|
for (int x = 0; x < w; ++x)
|
||||||
{
|
{
|
||||||
ushort* srcX = &src[xQ4 >> SubpelBits];
|
ushort* srcX = &src[xQ4 >> SubpelBits];
|
||||||
Span<short> xFilter = xFilters[xQ4 & SubpelMask].AsSpan();
|
ref Array8<short> xFilter = ref xFilters[xQ4 & SubpelMask];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
@@ -693,7 +692,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
|||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
@@ -729,7 +728,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Dsp
|
|||||||
for (int y = 0; y < h; ++y)
|
for (int y = 0; y < h; ++y)
|
||||||
{
|
{
|
||||||
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
ushort* srcY = &src[(yQ4 >> SubpelBits) * srcStride];
|
||||||
Span<short> yFilter = yFilters[yQ4 & SubpelMask].AsSpan();
|
ref Array8<short> yFilter = ref yFilters[yQ4 & SubpelMask];
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int k = 0; k < SubpelTaps; ++k)
|
for (int k = 0; k < SubpelTaps; ++k)
|
||||||
{
|
{
|
||||||
|
@@ -304,40 +304,31 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal static void TxCountsToBranchCounts32X32(ReadOnlySpan<uint> txCount32X32P,
|
internal static void TxCountsToBranchCounts32X32(ReadOnlySpan<uint> txCount32X32P,
|
||||||
ReadOnlySpan<Array2<uint>> ct32X32P)
|
ref Array3<Array2<uint>> ct32X32P)
|
||||||
{
|
{
|
||||||
Span<uint> ct32X32PSpan0 = ct32X32P[0].AsSpan();
|
ct32X32P[0][0] = txCount32X32P[(int)TxSize.Tx4X4];
|
||||||
Span<uint> ct32X32PSpan1 = ct32X32P[1].AsSpan();
|
ct32X32P[0][1] = txCount32X32P[(int)TxSize.Tx8X8] + txCount32X32P[(int)TxSize.Tx16X16] +
|
||||||
Span<uint> ct32X32PSpan2 = ct32X32P[2].AsSpan();
|
|
||||||
|
|
||||||
ct32X32PSpan0[0] = txCount32X32P[(int)TxSize.Tx4X4];
|
|
||||||
ct32X32PSpan0[1] = txCount32X32P[(int)TxSize.Tx8X8] + txCount32X32P[(int)TxSize.Tx16X16] +
|
|
||||||
txCount32X32P[(int)TxSize.Tx32X32];
|
txCount32X32P[(int)TxSize.Tx32X32];
|
||||||
ct32X32PSpan1[0] = txCount32X32P[(int)TxSize.Tx8X8];
|
ct32X32P[1][0] = txCount32X32P[(int)TxSize.Tx8X8];
|
||||||
ct32X32PSpan1[1] = txCount32X32P[(int)TxSize.Tx16X16] + txCount32X32P[(int)TxSize.Tx32X32];
|
ct32X32P[1][1] = txCount32X32P[(int)TxSize.Tx16X16] + txCount32X32P[(int)TxSize.Tx32X32];
|
||||||
ct32X32PSpan2[0] = txCount32X32P[(int)TxSize.Tx16X16];
|
ct32X32P[2][0] = txCount32X32P[(int)TxSize.Tx16X16];
|
||||||
ct32X32PSpan2[1] = txCount32X32P[(int)TxSize.Tx32X32];
|
ct32X32P[2][1] = txCount32X32P[(int)TxSize.Tx32X32];
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void TxCountsToBranchCounts16X16(ReadOnlySpan<uint> txCount16X16P,
|
internal static void TxCountsToBranchCounts16X16(ReadOnlySpan<uint> txCount16X16P,
|
||||||
ReadOnlySpan<Array2<uint>> ct16X16P)
|
ref Array2<Array2<uint>> ct16X16P)
|
||||||
{
|
{
|
||||||
Span<uint> ct16X16PSpan0 = ct16X16P[0].AsSpan();
|
ct16X16P[0][0] = txCount16X16P[(int)TxSize.Tx4X4];
|
||||||
Span<uint> ct16X16PSpan1 = ct16X16P[1].AsSpan();
|
ct16X16P[0][1] = txCount16X16P[(int)TxSize.Tx8X8] + txCount16X16P[(int)TxSize.Tx16X16];
|
||||||
|
ct16X16P[1][0] = txCount16X16P[(int)TxSize.Tx8X8];
|
||||||
ct16X16PSpan0[0] = txCount16X16P[(int)TxSize.Tx4X4];
|
ct16X16P[1][1] = txCount16X16P[(int)TxSize.Tx16X16];
|
||||||
ct16X16PSpan0[1] = txCount16X16P[(int)TxSize.Tx8X8] + txCount16X16P[(int)TxSize.Tx16X16];
|
|
||||||
ct16X16PSpan1[0] = txCount16X16P[(int)TxSize.Tx8X8];
|
|
||||||
ct16X16PSpan1[1] = txCount16X16P[(int)TxSize.Tx16X16];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void TxCountsToBranchCounts8X8(ReadOnlySpan<uint> txCount8X8P,
|
internal static void TxCountsToBranchCounts8X8(ReadOnlySpan<uint> txCount8X8P,
|
||||||
ReadOnlySpan<Array2<uint>> ct8X8P)
|
ref Array1<Array2<uint>> ct8X8P)
|
||||||
{
|
{
|
||||||
Span<uint> ct8X8PSpan = ct8X8P[0].AsSpan();
|
ct8X8P[0][0] = txCount8X8P[(int)TxSize.Tx4X4];
|
||||||
|
ct8X8P[0][1] = txCount8X8P[(int)TxSize.Tx8X8];
|
||||||
ct8X8PSpan[0] = txCount8X8P[(int)TxSize.Tx4X4];
|
|
||||||
ct8X8PSpan[1] = txCount8X8P[(int)TxSize.Tx8X8];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe void SetupPastIndependence(ref Vp9Common cm)
|
public static unsafe void SetupPastIndependence(ref Vp9Common cm)
|
||||||
|
@@ -378,11 +378,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
int index = shiftY;
|
int index = shiftY;
|
||||||
|
|
||||||
Span<byte> lflYSpan = lfm.LflY.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < bh; i++)
|
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;
|
index += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,29 +445,24 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
const ushort LeftBorderUv = 0x1111;
|
const ushort LeftBorderUv = 0x1111;
|
||||||
const ushort AboveBorderUv = 0x000f;
|
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
|
// The largest loopfilter we have is 16x16 so we use the 16x16 mask
|
||||||
// for 32x32 transforms also.
|
// for 32x32 transforms also.
|
||||||
leftYSpan[(int)TxSize.Tx16X16] |= leftYSpan[(int)TxSize.Tx32X32];
|
lfm.LeftY[(int)TxSize.Tx16X16] |= lfm.LeftY[(int)TxSize.Tx32X32];
|
||||||
aboveYSpan[(int)TxSize.Tx16X16] |= aboveYSpan[(int)TxSize.Tx32X32];
|
lfm.AboveY[(int)TxSize.Tx16X16] |= lfm.AboveY[(int)TxSize.Tx32X32];
|
||||||
leftUvSpan[(int)TxSize.Tx16X16] |= leftUvSpan[(int)TxSize.Tx32X32];
|
lfm.LeftUv[(int)TxSize.Tx16X16] |= lfm.LeftUv[(int)TxSize.Tx32X32];
|
||||||
aboveUvSpan[(int)TxSize.Tx16X16] |= aboveUvSpan[(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
|
// 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
|
// is 4x4. So if the 4x4 is set on a border pixel add it to the 8x8 and
|
||||||
// remove it from the 4x4.
|
// remove it from the 4x4.
|
||||||
leftYSpan[(int)TxSize.Tx8X8] |= leftYSpan[(int)TxSize.Tx4X4] & LeftBorder;
|
lfm.LeftY[(int)TxSize.Tx8X8] |= lfm.LeftY[(int)TxSize.Tx4X4] & LeftBorder;
|
||||||
leftYSpan[(int)TxSize.Tx4X4] &= ~LeftBorder;
|
lfm.LeftY[(int)TxSize.Tx4X4] &= ~LeftBorder;
|
||||||
aboveYSpan[(int)TxSize.Tx8X8] |= aboveYSpan[(int)TxSize.Tx4X4] & AboveBorder;
|
lfm.AboveY[(int)TxSize.Tx8X8] |= lfm.AboveY[(int)TxSize.Tx4X4] & AboveBorder;
|
||||||
aboveYSpan[(int)TxSize.Tx4X4] &= ~AboveBorder;
|
lfm.AboveY[(int)TxSize.Tx4X4] &= ~AboveBorder;
|
||||||
leftUvSpan[(int)TxSize.Tx8X8] |= (ushort)(leftUvSpan[(int)TxSize.Tx4X4] & LeftBorderUv);
|
lfm.LeftUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.LeftUv[(int)TxSize.Tx4X4] & LeftBorderUv);
|
||||||
leftUvSpan[(int)TxSize.Tx4X4] &= unchecked((ushort)~LeftBorderUv);
|
lfm.LeftUv[(int)TxSize.Tx4X4] &= unchecked((ushort)~LeftBorderUv);
|
||||||
aboveUvSpan[(int)TxSize.Tx8X8] |= (ushort)(aboveUvSpan[(int)TxSize.Tx4X4] & AboveBorderUv);
|
lfm.AboveUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.AboveUv[(int)TxSize.Tx4X4] & AboveBorderUv);
|
||||||
aboveUvSpan[(int)TxSize.Tx4X4] &= unchecked((ushort)~AboveBorderUv);
|
lfm.AboveUv[(int)TxSize.Tx4X4] &= unchecked((ushort)~AboveBorderUv);
|
||||||
|
|
||||||
// We do some special edge handling.
|
// We do some special edge handling.
|
||||||
if (miRow + Constants.MiBlockSize > cm.MiRows)
|
if (miRow + Constants.MiBlockSize > cm.MiRows)
|
||||||
@@ -483,10 +476,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// Remove values completely outside our border.
|
// Remove values completely outside our border.
|
||||||
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||||
{
|
{
|
||||||
leftYSpan[i] &= maskY;
|
lfm.LeftY[i] &= maskY;
|
||||||
aboveYSpan[i] &= maskY;
|
lfm.AboveY[i] &= maskY;
|
||||||
leftUvSpan[i] &= maskUv;
|
lfm.LeftUv[i] &= maskUv;
|
||||||
aboveUvSpan[i] &= maskUv;
|
lfm.AboveUv[i] &= maskUv;
|
||||||
}
|
}
|
||||||
|
|
||||||
lfm.Int4X4Y &= maskY;
|
lfm.Int4X4Y &= maskY;
|
||||||
@@ -496,14 +489,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// apply the shorter one instead.
|
// apply the shorter one instead.
|
||||||
if (rows == 1)
|
if (rows == 1)
|
||||||
{
|
{
|
||||||
aboveUvSpan[(int)TxSize.Tx8X8] |= aboveUvSpan[(int)TxSize.Tx16X16];
|
lfm.AboveUv[(int)TxSize.Tx8X8] |= lfm.AboveUv[(int)TxSize.Tx16X16];
|
||||||
aboveUvSpan[(int)TxSize.Tx16X16] = 0;
|
lfm.AboveUv[(int)TxSize.Tx16X16] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rows == 5)
|
if (rows == 5)
|
||||||
{
|
{
|
||||||
aboveUvSpan[(int)TxSize.Tx8X8] |= (ushort)(aboveUvSpan[(int)TxSize.Tx16X16] & 0xff00);
|
lfm.AboveUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.AboveUv[(int)TxSize.Tx16X16] & 0xff00);
|
||||||
aboveUvSpan[(int)TxSize.Tx16X16] &= (ushort)~(aboveUvSpan[(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.
|
// Remove the bits outside the image edge.
|
||||||
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||||
{
|
{
|
||||||
leftYSpan[i] &= maskY;
|
lfm.LeftY[i] &= maskY;
|
||||||
aboveYSpan[i] &= maskY;
|
lfm.AboveY[i] &= maskY;
|
||||||
leftUvSpan[i] &= maskUv;
|
lfm.LeftUv[i] &= maskUv;
|
||||||
aboveUvSpan[i] &= maskUv;
|
lfm.AboveUv[i] &= maskUv;
|
||||||
}
|
}
|
||||||
|
|
||||||
lfm.Int4X4Y &= maskY;
|
lfm.Int4X4Y &= maskY;
|
||||||
@@ -536,14 +529,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// apply the shorter one instead.
|
// apply the shorter one instead.
|
||||||
if (columns == 1)
|
if (columns == 1)
|
||||||
{
|
{
|
||||||
leftUvSpan[(int)TxSize.Tx8X8] |= leftUvSpan[(int)TxSize.Tx16X16];
|
lfm.LeftUv[(int)TxSize.Tx8X8] |= lfm.LeftUv[(int)TxSize.Tx16X16];
|
||||||
leftUvSpan[(int)TxSize.Tx16X16] = 0;
|
lfm.LeftUv[(int)TxSize.Tx16X16] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (columns == 5)
|
if (columns == 5)
|
||||||
{
|
{
|
||||||
leftUvSpan[(int)TxSize.Tx8X8] |= (ushort)(leftUvSpan[(int)TxSize.Tx16X16] & 0xcccc);
|
lfm.LeftUv[(int)TxSize.Tx8X8] |= (ushort)(lfm.LeftUv[(int)TxSize.Tx16X16] & 0xcccc);
|
||||||
leftUvSpan[(int)TxSize.Tx16X16] &= (ushort)~(leftUvSpan[(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++)
|
for (int i = 0; i < (int)TxSize.Tx32X32; i++)
|
||||||
{
|
{
|
||||||
leftYSpan[i] &= 0xfefefefefefefefeUL;
|
lfm.LeftY[i] &= 0xfefefefefefefefeUL;
|
||||||
leftUvSpan[i] &= 0xeeee;
|
lfm.LeftUv[i] &= 0xeeee;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert if we try to apply 2 different loop filters at the same position.
|
// 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((lfm.LeftY[(int)TxSize.Tx16X16] & lfm.LeftY[(int)TxSize.Tx8X8]) == 0);
|
||||||
Debug.Assert((leftYSpan[(int)TxSize.Tx16X16] & leftYSpan[(int)TxSize.Tx4X4]) == 0);
|
Debug.Assert((lfm.LeftY[(int)TxSize.Tx16X16] & lfm.LeftY[(int)TxSize.Tx4X4]) == 0);
|
||||||
Debug.Assert((leftYSpan[(int)TxSize.Tx8X8] & leftYSpan[(int)TxSize.Tx4X4]) == 0);
|
Debug.Assert((lfm.LeftY[(int)TxSize.Tx8X8] & lfm.LeftY[(int)TxSize.Tx4X4]) == 0);
|
||||||
Debug.Assert((lfm.Int4X4Y & leftYSpan[(int)TxSize.Tx16X16]) == 0);
|
Debug.Assert((lfm.Int4X4Y & lfm.LeftY[(int)TxSize.Tx16X16]) == 0);
|
||||||
Debug.Assert((leftUvSpan[(int)TxSize.Tx16X16] & leftUvSpan[(int)TxSize.Tx8X8]) == 0);
|
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx16X16] & lfm.LeftUv[(int)TxSize.Tx8X8]) == 0);
|
||||||
Debug.Assert((leftUvSpan[(int)TxSize.Tx16X16] & leftUvSpan[(int)TxSize.Tx4X4]) == 0);
|
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx16X16] & lfm.LeftUv[(int)TxSize.Tx4X4]) == 0);
|
||||||
Debug.Assert((leftUvSpan[(int)TxSize.Tx8X8] & leftUvSpan[(int)TxSize.Tx4X4]) == 0);
|
Debug.Assert((lfm.LeftUv[(int)TxSize.Tx8X8] & lfm.LeftUv[(int)TxSize.Tx4X4]) == 0);
|
||||||
Debug.Assert((lfm.Int4X4Uv & leftUvSpan[(int)TxSize.Tx16X16]) == 0);
|
Debug.Assert((lfm.Int4X4Uv & lfm.LeftUv[(int)TxSize.Tx16X16]) == 0);
|
||||||
Debug.Assert((aboveYSpan[(int)TxSize.Tx16X16] & aboveYSpan[(int)TxSize.Tx8X8]) == 0);
|
Debug.Assert((lfm.AboveY[(int)TxSize.Tx16X16] & lfm.AboveY[(int)TxSize.Tx8X8]) == 0);
|
||||||
Debug.Assert((aboveYSpan[(int)TxSize.Tx16X16] & aboveYSpan[(int)TxSize.Tx4X4]) == 0);
|
Debug.Assert((lfm.AboveY[(int)TxSize.Tx16X16] & lfm.AboveY[(int)TxSize.Tx4X4]) == 0);
|
||||||
Debug.Assert((aboveYSpan[(int)TxSize.Tx8X8] & aboveYSpan[(int)TxSize.Tx4X4]) == 0);
|
Debug.Assert((lfm.AboveY[(int)TxSize.Tx8X8] & lfm.AboveY[(int)TxSize.Tx4X4]) == 0);
|
||||||
Debug.Assert((lfm.Int4X4Y & aboveYSpan[(int)TxSize.Tx16X16]) == 0);
|
Debug.Assert((lfm.Int4X4Y & lfm.AboveY[(int)TxSize.Tx16X16]) == 0);
|
||||||
Debug.Assert((aboveUvSpan[(int)TxSize.Tx16X16] & aboveUvSpan[(int)TxSize.Tx8X8]) == 0);
|
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx16X16] & lfm.AboveUv[(int)TxSize.Tx8X8]) == 0);
|
||||||
Debug.Assert((aboveUvSpan[(int)TxSize.Tx16X16] & aboveUvSpan[(int)TxSize.Tx4X4]) == 0);
|
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx16X16] & lfm.AboveUv[(int)TxSize.Tx4X4]) == 0);
|
||||||
Debug.Assert((aboveUvSpan[(int)TxSize.Tx8X8] & aboveUvSpan[(int)TxSize.Tx4X4]) == 0);
|
Debug.Assert((lfm.AboveUv[(int)TxSize.Tx8X8] & lfm.AboveUv[(int)TxSize.Tx4X4]) == 0);
|
||||||
Debug.Assert((lfm.Int4X4Uv & aboveUvSpan[(int)TxSize.Tx16X16]) == 0);
|
Debug.Assert((lfm.Int4X4Uv & lfm.AboveUv[(int)TxSize.Tx16X16]) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe void ResetLfm(ref Vp9Common cm)
|
public static unsafe void ResetLfm(ref Vp9Common cm)
|
||||||
@@ -590,8 +583,6 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
int lvl;
|
int lvl;
|
||||||
|
|
||||||
Span<LoopFilterThresh> lFThrSpan = lfi.Lfthr.AsSpan();
|
|
||||||
|
|
||||||
// For each possible value for the loop filter fill out limits
|
// For each possible value for the loop filter fill out limits
|
||||||
for (lvl = 0; lvl <= MaxLoopFilter; lvl++)
|
for (lvl = 0; lvl <= MaxLoopFilter; lvl++)
|
||||||
{
|
{
|
||||||
@@ -611,8 +602,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
blockInsideLimit = 1;
|
blockInsideLimit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lFThrSpan[lvl].Lim.AsSpan().Fill((byte)blockInsideLimit);
|
lfi.Lfthr[lvl].Lim.AsSpan().Fill((byte)blockInsideLimit);
|
||||||
lFThrSpan[lvl].Mblim.AsSpan().Fill((byte)((2 * (lvl + 2)) + 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;
|
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++)
|
for (segId = 0; segId < Constants.MaxSegments; segId++)
|
||||||
{
|
{
|
||||||
int lvlSeg = defaultFiltLvl;
|
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
|
// We could get rid of this if we assume that deltas are set to
|
||||||
// zero when not in use; encoder always uses deltas
|
// 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
|
else
|
||||||
{
|
{
|
||||||
int refr, mode;
|
int refr, mode;
|
||||||
int intraLvl = lvlSeg + (intraFrameRefDelta * scale);
|
int intraLvl = lvlSeg + (lf.RefDeltas[Constants.IntraFrame] * scale);
|
||||||
lvlSpan[segId][Constants.IntraFrame][0] = (byte)Math.Clamp(intraLvl, 0, MaxLoopFilter);
|
lfi.Lvl[segId][Constants.IntraFrame][0] = (byte)Math.Clamp(intraLvl, 0, MaxLoopFilter);
|
||||||
|
|
||||||
Span<Array2<byte>> lvlSpan2 = lvlSpan[segId].AsSpan();
|
|
||||||
|
|
||||||
for (refr = Constants.LastFrame; refr < Constants.MaxRefFrames; ++refr)
|
for (refr = Constants.LastFrame; refr < Constants.MaxRefFrames; ++refr)
|
||||||
{
|
{
|
||||||
Span<byte> lvlSpan3 = lvlSpan2[refr].AsSpan();
|
|
||||||
|
|
||||||
for (mode = 0; mode < MaxModeLfDeltas; ++mode)
|
for (mode = 0; mode < MaxModeLfDeltas; ++mode)
|
||||||
{
|
{
|
||||||
int interLvl = lvlSeg + (refDeltasSpan[refr] * scale) + (modeDeltasSpan[mode] * scale);
|
int interLvl = lvlSeg + (lf.RefDeltas[refr] * scale) + (lf.ModeDeltas[mode] * scale);
|
||||||
lvlSpan3[mode] = (byte)Math.Clamp(interLvl, 0, MaxLoopFilter);
|
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]];
|
lfis[1] = lfthr[lfl[lflForward]];
|
||||||
ss[1] = ss[0].Slice(8 * pitch);
|
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) != 0)
|
||||||
{
|
{
|
||||||
if ((mask16X16 & dualOne) == dualOne)
|
if ((mask16X16 & dualOne) == dualOne)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfVertical16Dual(ss[0], pitch, mblim0Span[0], lim0Span[0],
|
LoopFilterScalar.HighBdLpfVertical16Dual(ss[0], pitch, lfis[0].Mblim[0], lfis[0].Lim[0],
|
||||||
hevThr0Span[0], bd);
|
lfis[0].HevThr[0], bd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((mask16X16 & 1) == 0)
|
ref LoopFilterThresh lfi = ref lfis[(mask16X16 & 1) == 0 ? 1 : 0];
|
||||||
{
|
LoopFilterScalar.HighBdLpfVertical16(ss[(mask16X16 & 1) == 0 ? 1 : 0], pitch, lfi.Mblim[0],
|
||||||
LoopFilterScalar.HighBdLpfVertical16(ss[1], pitch, mblim1Span[0],
|
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||||
lim1Span[0], hevThr1Span[0], bd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LoopFilterScalar.HighBdLpfVertical16(ss[0], pitch, mblim0Span[0],
|
|
||||||
lim0Span[0], hevThr0Span[0], bd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,26 +833,24 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
LoopFilterScalar.HighBdLpfVertical8Dual(
|
LoopFilterScalar.HighBdLpfVertical8Dual(
|
||||||
ss[0],
|
ss[0],
|
||||||
pitch,
|
pitch,
|
||||||
mblim0Span[0],
|
lfis[0].Mblim[0],
|
||||||
lim0Span[0],
|
lfis[0].Lim[0],
|
||||||
hevThr0Span[0],
|
lfis[0].HevThr[0],
|
||||||
mblim1Span[0],
|
lfis[1].Mblim[0],
|
||||||
lim1Span[0],
|
lfis[1].Lim[0],
|
||||||
hevThr1Span[0],
|
lfis[1].HevThr[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((mask8X8 & 1) == 0)
|
ref LoopFilterThresh lfi = ref lfis[(mask8X8 & 1) == 0 ? 1 : 0];
|
||||||
{
|
LoopFilterScalar.HighBdLpfVertical8(
|
||||||
LoopFilterScalar.HighBdLpfVertical8(ss[1], pitch, mblim1Span[0],
|
ss[(mask8X8 & 1) == 0 ? 1 : 0],
|
||||||
lim1Span[0], hevThr1Span[0], bd);
|
pitch,
|
||||||
}
|
lfi.Mblim[0],
|
||||||
else
|
lfi.Lim[0],
|
||||||
{
|
lfi.HevThr[0],
|
||||||
LoopFilterScalar.HighBdLpfVertical8(ss[0], pitch, mblim0Span[0],
|
bd);
|
||||||
lim0Span[0], hevThr0Span[0], bd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -895,26 +861,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
LoopFilterScalar.HighBdLpfVertical4Dual(
|
LoopFilterScalar.HighBdLpfVertical4Dual(
|
||||||
ss[0],
|
ss[0],
|
||||||
pitch,
|
pitch,
|
||||||
mblim0Span[0],
|
lfis[0].Mblim[0],
|
||||||
lim0Span[0],
|
lfis[0].Lim[0],
|
||||||
hevThr0Span[0],
|
lfis[0].HevThr[0],
|
||||||
mblim1Span[0],
|
lfis[1].Mblim[0],
|
||||||
lim1Span[0],
|
lfis[1].Lim[0],
|
||||||
hevThr1Span[0],
|
lfis[1].HevThr[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((mask4X4 & 1) == 0)
|
ref LoopFilterThresh lfi = ref lfis[(mask4X4 & 1) == 0 ? 1 : 0];
|
||||||
{
|
LoopFilterScalar.HighBdLpfVertical4(ss[(mask4X4 & 1) == 0 ? 1 : 0], pitch, lfi.Mblim[0],
|
||||||
LoopFilterScalar.HighBdLpfVertical4(ss[1], pitch, mblim1Span[0],
|
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||||
lim1Span[0], hevThr1Span[0], bd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LoopFilterScalar.HighBdLpfVertical4(ss[0], pitch, mblim0Span[0],
|
|
||||||
lim0Span[0], hevThr0Span[0], bd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -925,26 +884,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
LoopFilterScalar.HighBdLpfVertical4Dual(
|
LoopFilterScalar.HighBdLpfVertical4Dual(
|
||||||
ss[0].Slice(4),
|
ss[0].Slice(4),
|
||||||
pitch,
|
pitch,
|
||||||
mblim0Span[0],
|
lfis[0].Mblim[0],
|
||||||
lim0Span[0],
|
lfis[0].Lim[0],
|
||||||
hevThr0Span[0],
|
lfis[0].HevThr[0],
|
||||||
mblim1Span[0],
|
lfis[1].Mblim[0],
|
||||||
lim1Span[0],
|
lfis[1].Lim[0],
|
||||||
hevThr1Span[0],
|
lfis[1].HevThr[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((mask4X4Int & 1) == 0)
|
ref LoopFilterThresh lfi = ref lfis[(mask4X4Int & 1) == 0 ? 1 : 0];
|
||||||
{
|
LoopFilterScalar.HighBdLpfVertical4(ss[(mask4X4Int & 1) == 0 ? 1 : 0].Slice(4), pitch,
|
||||||
LoopFilterScalar.HighBdLpfVertical4(ss[1].Slice(4), pitch, mblim1Span[0],
|
lfi.Mblim[0], lfi.Lim[0], lfi.HevThr[0], bd);
|
||||||
lim1Span[0], hevThr1Span[0], bd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LoopFilterScalar.HighBdLpfVertical4(ss[0].Slice(4), pitch, mblim0Span[0],
|
|
||||||
lim0Span[0], hevThr0Span[0], bd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1135,21 +1087,17 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
LoopFilterThresh lfi = lfthr[lfl[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 & 1) != 0)
|
||||||
{
|
{
|
||||||
if ((mask16X16 & 3) == 3)
|
if ((mask16X16 & 3) == 3)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal16Dual(s, pitch, mblimSpan[0], limSpan[0],
|
LoopFilterScalar.HighBdLpfHorizontal16Dual(s, pitch, lfi.Mblim[0], lfi.Lim[0],
|
||||||
hevThrSpan[0], bd);
|
lfi.HevThr[0], bd);
|
||||||
count = 2;
|
count = 2;
|
||||||
}
|
}
|
||||||
else
|
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);
|
bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1160,19 +1108,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// Next block's thresholds.
|
// Next block's thresholds.
|
||||||
LoopFilterThresh lfin = lfthr[lfl[1]];
|
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(
|
LoopFilterScalar.HighBdLpfHorizontal8Dual(
|
||||||
s,
|
s,
|
||||||
pitch,
|
pitch,
|
||||||
mblimSpan[0],
|
lfi.Mblim[0],
|
||||||
limSpan[0],
|
lfi.Lim[0],
|
||||||
hevThrSpan[0],
|
lfi.HevThr[0],
|
||||||
nMblimSpan[0],
|
lfin.Mblim[0],
|
||||||
nLimSpan[0],
|
lfin.Lim[0],
|
||||||
nHevThrSpan[0],
|
lfin.HevThr[0],
|
||||||
bd);
|
bd);
|
||||||
|
|
||||||
if ((mask4X4Int & 3) == 3)
|
if ((mask4X4Int & 3) == 3)
|
||||||
@@ -1180,36 +1124,36 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||||
s.Slice(4 * pitch),
|
s.Slice(4 * pitch),
|
||||||
pitch,
|
pitch,
|
||||||
mblimSpan[0],
|
lfi.Mblim[0],
|
||||||
limSpan[0],
|
lfi.Lim[0],
|
||||||
hevThrSpan[0],
|
lfi.HevThr[0],
|
||||||
nMblimSpan[0],
|
lfin.Mblim[0],
|
||||||
nLimSpan[0],
|
lfin.Lim[0],
|
||||||
nHevThrSpan[0],
|
lfin.HevThr[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else if ((mask4X4Int & 1) != 0)
|
else if ((mask4X4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||||
limSpan[0], hevThrSpan[0], bd);
|
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||||
}
|
}
|
||||||
else if ((mask4X4Int & 2) != 0)
|
else if ((mask4X4Int & 2) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, nMblimSpan[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, lfin.Mblim[0],
|
||||||
nLimSpan[0], nHevThrSpan[0], bd);
|
lfin.Lim[0], lfin.HevThr[0], bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
count = 2;
|
count = 2;
|
||||||
}
|
}
|
||||||
else
|
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);
|
bd);
|
||||||
|
|
||||||
if ((mask4X4Int & 1) != 0)
|
if ((mask4X4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||||
limSpan[0], hevThrSpan[0], bd);
|
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1220,19 +1164,15 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// Next block's thresholds.
|
// Next block's thresholds.
|
||||||
LoopFilterThresh lfin = lfthr[lfl[1]];
|
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(
|
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||||
s,
|
s,
|
||||||
pitch,
|
pitch,
|
||||||
mblimSpan[0],
|
lfi.Mblim[0],
|
||||||
limSpan[0],
|
lfi.Lim[0],
|
||||||
hevThrSpan[0],
|
lfi.HevThr[0],
|
||||||
nMblimSpan[0],
|
lfin.Mblim[0],
|
||||||
nLimSpan[0],
|
lfin.Lim[0],
|
||||||
nHevThrSpan[0],
|
lfin.HevThr[0],
|
||||||
bd);
|
bd);
|
||||||
|
|
||||||
if ((mask4X4Int & 3) == 3)
|
if ((mask4X4Int & 3) == 3)
|
||||||
@@ -1240,43 +1180,43 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
LoopFilterScalar.HighBdLpfHorizontal4Dual(
|
||||||
s.Slice(4 * pitch),
|
s.Slice(4 * pitch),
|
||||||
pitch,
|
pitch,
|
||||||
mblimSpan[0],
|
lfi.Mblim[0],
|
||||||
limSpan[0],
|
lfi.Lim[0],
|
||||||
hevThrSpan[0],
|
lfi.HevThr[0],
|
||||||
nMblimSpan[0],
|
lfin.Mblim[0],
|
||||||
nLimSpan[0],
|
lfin.Lim[0],
|
||||||
nHevThrSpan[0],
|
lfin.HevThr[0],
|
||||||
bd);
|
bd);
|
||||||
}
|
}
|
||||||
else if ((mask4X4Int & 1) != 0)
|
else if ((mask4X4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||||
limSpan[0], hevThrSpan[0], bd);
|
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||||
}
|
}
|
||||||
else if ((mask4X4Int & 2) != 0)
|
else if ((mask4X4Int & 2) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, nMblimSpan[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(8 + (4 * pitch)), pitch, lfin.Mblim[0],
|
||||||
nLimSpan[0], nHevThrSpan[0], bd);
|
lfin.Lim[0], lfin.HevThr[0], bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
count = 2;
|
count = 2;
|
||||||
}
|
}
|
||||||
else
|
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);
|
bd);
|
||||||
|
|
||||||
if ((mask4X4Int & 1) != 0)
|
if ((mask4X4Int & 1) != 0)
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0],
|
||||||
limSpan[0], hevThrSpan[0], bd);
|
lfi.Lim[0], lfi.HevThr[0], bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, mblimSpan[0], limSpan[0],
|
LoopFilterScalar.HighBdLpfHorizontal4(s.Slice(4 * pitch), pitch, lfi.Mblim[0], lfi.Lim[0],
|
||||||
hevThrSpan[0], bd);
|
lfi.HevThr[0], bd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1352,29 +1292,25 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
LoopFilterThresh lfi = lfthr[lfl[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 ((mask & 1) != 0)
|
if ((mask & 1) != 0)
|
||||||
{
|
{
|
||||||
if ((mask16X16 & 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)
|
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)
|
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)
|
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);
|
s = s.Slice(8);
|
||||||
@@ -1619,10 +1555,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
ref Buf2D dst = ref plane.Dst;
|
ref Buf2D dst = ref plane.Dst;
|
||||||
ArrayPtr<byte> dst0 = dst.Buf;
|
ArrayPtr<byte> dst0 = dst.Buf;
|
||||||
Span<ulong> leftYSpan = lfm.LeftY.AsSpan();
|
ulong mask16X16 = lfm.LeftY[(int)TxSize.Tx16X16];
|
||||||
ulong mask16X16 = leftYSpan[(int)TxSize.Tx16X16];
|
ulong mask8X8 = lfm.LeftY[(int)TxSize.Tx8X8];
|
||||||
ulong mask8X8 = leftYSpan[(int)TxSize.Tx8X8];
|
ulong mask4X4 = lfm.LeftY[(int)TxSize.Tx4X4];
|
||||||
ulong mask4X4 = leftYSpan[(int)TxSize.Tx4X4];
|
|
||||||
ulong mask4X4Int = lfm.Int4X4Y;
|
ulong mask4X4Int = lfm.Int4X4Y;
|
||||||
|
|
||||||
Debug.Assert(plane.SubsamplingX == 0 && plane.SubsamplingY == 0);
|
Debug.Assert(plane.SubsamplingX == 0 && plane.SubsamplingY == 0);
|
||||||
@@ -1669,10 +1604,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
// Horizontal pass
|
// Horizontal pass
|
||||||
dst.Buf = dst0;
|
dst.Buf = dst0;
|
||||||
Span<ulong> aboveYSpan = lfm.AboveY.AsSpan();
|
mask16X16 = lfm.AboveY[(int)TxSize.Tx16X16];
|
||||||
mask16X16 = aboveYSpan[(int)TxSize.Tx16X16];
|
mask8X8 = lfm.AboveY[(int)TxSize.Tx8X8];
|
||||||
mask8X8 = aboveYSpan[(int)TxSize.Tx8X8];
|
mask4X4 = lfm.AboveY[(int)TxSize.Tx4X4];
|
||||||
mask4X4 = aboveYSpan[(int)TxSize.Tx4X4];
|
|
||||||
mask4X4Int = lfm.Int4X4Y;
|
mask4X4Int = lfm.Int4X4Y;
|
||||||
|
|
||||||
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r++)
|
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;
|
ArrayPtr<byte> dst0 = dst.Buf;
|
||||||
|
|
||||||
Span<byte> lflUv = stackalloc byte[16];
|
Span<byte> lflUv = stackalloc byte[16];
|
||||||
Span<byte> lflY = lfm.LflY.AsSpan();
|
|
||||||
|
|
||||||
Span<ushort> leftUvSpan = lfm.LeftUv.AsSpan();
|
ushort mask16X16 = lfm.LeftUv[(int)TxSize.Tx16X16];
|
||||||
ushort mask16X16 = leftUvSpan[(int)TxSize.Tx16X16];
|
ushort mask8X8 = lfm.LeftUv[(int)TxSize.Tx8X8];
|
||||||
ushort mask8X8 = leftUvSpan[(int)TxSize.Tx8X8];
|
ushort mask4X4 = lfm.LeftUv[(int)TxSize.Tx4X4];
|
||||||
ushort mask4X4 = leftUvSpan[(int)TxSize.Tx4X4];
|
|
||||||
ushort mask4X4Int = lfm.Int4X4Uv;
|
ushort mask4X4Int = lfm.Int4X4Uv;
|
||||||
|
|
||||||
Debug.Assert(plane.SubsamplingX == 1 && plane.SubsamplingY == 1);
|
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++)
|
for (int c = 0; c < Constants.MiBlockSize >> 1; c++)
|
||||||
{
|
{
|
||||||
lflUv[(r << 1) + c] = lflY[(r << 3) + (c << 1)];
|
lflUv[(r << 1) + c] = lfm.LflY[(r << 3) + (c << 1)];
|
||||||
lflUv[((r + 2) << 1) + c] = lflY[((r + 2) << 3) + (c << 1)];
|
lflUv[((r + 2) << 1) + c] = lfm.LflY[((r + 2) << 3) + (c << 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cm.UseHighBitDepth)
|
if (cm.UseHighBitDepth)
|
||||||
@@ -1793,10 +1725,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
// Horizontal pass
|
// Horizontal pass
|
||||||
dst.Buf = dst0;
|
dst.Buf = dst0;
|
||||||
Span<ushort> aboveUvSpan = lfm.AboveUv.AsSpan();
|
mask16X16 = lfm.AboveUv[(int)TxSize.Tx16X16];
|
||||||
mask16X16 = aboveUvSpan[(int)TxSize.Tx16X16];
|
mask8X8 = lfm.AboveUv[(int)TxSize.Tx8X8];
|
||||||
mask8X8 = aboveUvSpan[(int)TxSize.Tx8X8];
|
mask4X4 = lfm.AboveUv[(int)TxSize.Tx4X4];
|
||||||
mask4X4 = aboveUvSpan[(int)TxSize.Tx4X4];
|
|
||||||
mask4X4Int = lfm.Int4X4Uv;
|
mask4X4Int = lfm.Int4X4Uv;
|
||||||
|
|
||||||
for (int r = 0; r < Constants.MiBlockSize && miRow + r < cm.MiRows; r += 2)
|
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;
|
int sbCols = TileInfo.MiColsAlignedToSb(cm.MiCols) >> Constants.MiBlockSizeLog2;
|
||||||
LfPath path;
|
LfPath path;
|
||||||
int miRow, miCol;
|
int miRow, miCol;
|
||||||
Span<MacroBlockDPlane> planesSpan = planes.AsSpan();
|
|
||||||
|
|
||||||
if (yOnly)
|
if (yOnly)
|
||||||
{
|
{
|
||||||
path = LfPath.LfPath444;
|
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;
|
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;
|
path = LfPath.LfPath444;
|
||||||
}
|
}
|
||||||
@@ -1907,23 +1837,23 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
lfSync.SyncRead(r, c);
|
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]);
|
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)
|
for (plane = 1; plane < numPlanes; ++plane)
|
||||||
{
|
{
|
||||||
switch (path)
|
switch (path)
|
||||||
{
|
{
|
||||||
case LfPath.LfPath420:
|
case LfPath.LfPath420:
|
||||||
FilterBlockPlaneSs11(ref cm, ref planesSpan[plane], miRow, ref lfm[0]);
|
FilterBlockPlaneSs11(ref cm, ref planes[plane], miRow, ref lfm[0]);
|
||||||
break;
|
break;
|
||||||
case LfPath.LfPath444:
|
case LfPath.LfPath444:
|
||||||
FilterBlockPlaneSs00(ref cm, ref planesSpan[plane], miRow, ref lfm[0]);
|
FilterBlockPlaneSs00(ref cm, ref planes[plane], miRow, ref lfm[0]);
|
||||||
break;
|
break;
|
||||||
case LfPath.LfPathSlow:
|
case LfPath.LfPathSlow:
|
||||||
FilterBlockPlaneNon420(ref cm, ref planesSpan[plane], mi.Slice(miCol), miRow,
|
FilterBlockPlaneNon420(ref cm, ref planes[plane], mi.Slice(miCol), miRow,
|
||||||
miCol);
|
miCol);
|
||||||
break;
|
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)
|
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();
|
Array8<short> output = new()
|
||||||
Span<short> outputSpan = output.AsSpan();
|
{
|
||||||
outputSpan[0] = e0;
|
[0] = e0,
|
||||||
outputSpan[1] = e1;
|
[1] = e1,
|
||||||
outputSpan[2] = e2;
|
[2] = e2,
|
||||||
outputSpan[3] = e3;
|
[3] = e3,
|
||||||
outputSpan[4] = e4;
|
[4] = e4,
|
||||||
outputSpan[5] = e5;
|
[5] = e5,
|
||||||
outputSpan[6] = e6;
|
[6] = e6,
|
||||||
outputSpan[7] = e7;
|
[7] = e7
|
||||||
|
};
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
using Ryujinx.Graphics.Nvdec.Vp9.Types;
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9
|
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 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];
|
sbyte vrfl = lSg ? xd.LeftMi.Value.RefFrame[0] : xd.LeftMi.Value.RefFrame[varRefIdx];
|
||||||
|
|
||||||
Span<sbyte> compVarRefSpan = cm.CompVarRef.AsSpan();
|
if (vrfa == vrfl && cm.CompVarRef[1] == vrfa)
|
||||||
|
|
||||||
if (vrfa == vrfl && compVarRefSpan[1] == vrfa)
|
|
||||||
{
|
{
|
||||||
predContext = 0;
|
predContext = 0;
|
||||||
}
|
}
|
||||||
else if (lSg && aSg)
|
else if (lSg && aSg)
|
||||||
{
|
{
|
||||||
// Single/Single
|
// Single/Single
|
||||||
if ((vrfa == cm.CompFixedRef && vrfl == compVarRefSpan[0]) ||
|
if ((vrfa == cm.CompFixedRef && vrfl == cm.CompVarRef[0]) ||
|
||||||
(vrfl == cm.CompFixedRef && vrfa == compVarRefSpan[0]))
|
(vrfl == cm.CompFixedRef && vrfa == cm.CompVarRef[0]))
|
||||||
{
|
{
|
||||||
predContext = 4;
|
predContext = 4;
|
||||||
}
|
}
|
||||||
@@ -138,11 +135,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// Single/Comp
|
// Single/Comp
|
||||||
sbyte vrfc = lSg ? vrfa : vrfl;
|
sbyte vrfc = lSg ? vrfa : vrfl;
|
||||||
sbyte rfs = aSg ? 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;
|
predContext = 1;
|
||||||
}
|
}
|
||||||
else if (rfs == compVarRefSpan[1] && vrfc != compVarRefSpan[1])
|
else if (rfs == cm.CompVarRef[1] && vrfc != cm.CompVarRef[1])
|
||||||
{
|
{
|
||||||
predContext = 2;
|
predContext = 2;
|
||||||
}
|
}
|
||||||
@@ -215,15 +212,14 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
// Intra/Inter or Inter/Intra
|
// Intra/Inter or Inter/Intra
|
||||||
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
||||||
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
|
||||||
if (!edgeMi.HasSecondRef())
|
if (!edgeMi.HasSecondRef())
|
||||||
{
|
{
|
||||||
predContext = 4 * (refFrameSpan[0] == Constants.LastFrame ? 1 : 0);
|
predContext = 4 * (edgeMi.RefFrame[0] == Constants.LastFrame ? 1 : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 1 + (refFrameSpan[0] == Constants.LastFrame ||
|
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
|
||||||
refFrameSpan[1] == Constants.LastFrame
|
edgeMi.RefFrame[1] == Constants.LastFrame
|
||||||
? 1
|
? 1
|
||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
@@ -233,12 +229,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// Inter/Inter
|
// Inter/Inter
|
||||||
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
||||||
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
||||||
Span<sbyte> aRefFrameSpan = xd.AboveMi.Value.RefFrame.AsSpan();
|
sbyte above0 = xd.AboveMi.Value.RefFrame[0];
|
||||||
sbyte above0 = aRefFrameSpan[0];
|
sbyte above1 = xd.AboveMi.Value.RefFrame[1];
|
||||||
sbyte above1 = aRefFrameSpan[1];
|
sbyte left0 = xd.LeftMi.Value.RefFrame[0];
|
||||||
Span<sbyte> lRefFrameSpan = xd.LeftMi.Value.RefFrame.AsSpan();
|
sbyte left1 = xd.LeftMi.Value.RefFrame[1];
|
||||||
sbyte left0 = lRefFrameSpan[0];
|
|
||||||
sbyte left1 = lRefFrameSpan[1];
|
|
||||||
|
|
||||||
if (aboveHasSecond && leftHasSecond)
|
if (aboveHasSecond && leftHasSecond)
|
||||||
{
|
{
|
||||||
@@ -287,10 +281,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
predContext = 1 + (edgeMi.RefFrame[0] == Constants.LastFrame ||
|
||||||
|
edgeMi.RefFrame[1] == Constants.LastFrame
|
||||||
predContext = 1 + (refFrameSpan[0] == Constants.LastFrame ||
|
|
||||||
refFrameSpan[1] == Constants.LastFrame
|
|
||||||
? 1
|
? 1
|
||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
@@ -329,22 +321,21 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
// Intra/Inter or Inter/Intra
|
// Intra/Inter or Inter/Intra
|
||||||
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
ref ModeInfo edgeMi = ref aboveIntra ? ref xd.LeftMi.Value : ref xd.AboveMi.Value;
|
||||||
Span<sbyte> refFrameSpan = edgeMi.RefFrame.AsSpan();
|
|
||||||
if (!edgeMi.HasSecondRef())
|
if (!edgeMi.HasSecondRef())
|
||||||
{
|
{
|
||||||
if (refFrameSpan[0] == Constants.LastFrame)
|
if (edgeMi.RefFrame[0] == Constants.LastFrame)
|
||||||
{
|
{
|
||||||
predContext = 3;
|
predContext = 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 4 * (refFrameSpan[0] == Constants.GoldenFrame ? 1 : 0);
|
predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 1 + (2 * (refFrameSpan[0] == Constants.GoldenFrame ||
|
predContext = 1 + (2 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
|
||||||
refFrameSpan[1] == Constants.GoldenFrame
|
edgeMi.RefFrame[1] == Constants.GoldenFrame
|
||||||
? 1
|
? 1
|
||||||
: 0));
|
: 0));
|
||||||
}
|
}
|
||||||
@@ -354,12 +345,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
// Inter/Inter
|
// Inter/Inter
|
||||||
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
bool aboveHasSecond = xd.AboveMi.Value.HasSecondRef();
|
||||||
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
bool leftHasSecond = xd.LeftMi.Value.HasSecondRef();
|
||||||
Span<sbyte> aRefFrameSpan = xd.AboveMi.Value.RefFrame.AsSpan();
|
sbyte above0 = xd.AboveMi.Value.RefFrame[0];
|
||||||
sbyte above0 = aRefFrameSpan[0];
|
sbyte above1 = xd.AboveMi.Value.RefFrame[1];
|
||||||
sbyte above1 = aRefFrameSpan[1];
|
sbyte left0 = xd.LeftMi.Value.RefFrame[0];
|
||||||
Span<sbyte> lRefFrameSpan = xd.LeftMi.Value.RefFrame.AsSpan();
|
sbyte left1 = xd.LeftMi.Value.RefFrame[1];
|
||||||
sbyte left0 = lRefFrameSpan[0];
|
|
||||||
sbyte left1 = lRefFrameSpan[1];
|
|
||||||
|
|
||||||
if (aboveHasSecond && leftHasSecond)
|
if (aboveHasSecond && leftHasSecond)
|
||||||
{
|
{
|
||||||
@@ -418,20 +407,19 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
// One edge available
|
// One edge available
|
||||||
ref ModeInfo edgeMi = ref !xd.AboveMi.IsNull ? ref xd.AboveMi.Value : ref xd.LeftMi.Value;
|
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;
|
predContext = 2;
|
||||||
}
|
}
|
||||||
else if (!edgeMi.HasSecondRef())
|
else if (!edgeMi.HasSecondRef())
|
||||||
{
|
{
|
||||||
predContext = 4 * (refFrameSpan[0] == Constants.GoldenFrame ? 1 : 0);
|
predContext = 4 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ? 1 : 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
predContext = 3 * (refFrameSpan[0] == Constants.GoldenFrame ||
|
predContext = 3 * (edgeMi.RefFrame[0] == Constants.GoldenFrame ||
|
||||||
refFrameSpan[1] == Constants.GoldenFrame
|
edgeMi.RefFrame[1] == Constants.GoldenFrame
|
||||||
? 1
|
? 1
|
||||||
: 0);
|
: 0);
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
return (byte)BitUtils.RoundPowerOfTwo((prob1 * (256 - factor)) + (prob2 * factor), 8);
|
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]);
|
byte prob = GetBinaryProb(ct[0], ct[1]);
|
||||||
uint count = Math.Min(ct[0] + ct[1], countSat);
|
uint count = Math.Min(ct[0] + ct[1], countSat);
|
||||||
@@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
|
|
||||||
private const int ModeMvCountSat = 20;
|
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];
|
uint den = ct[0] + ct[1];
|
||||||
if (den == 0)
|
if (den == 0)
|
||||||
@@ -81,7 +81,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
Array2<uint> ct = new();
|
Array2<uint> ct = new();
|
||||||
ct[0] = leftCount;
|
ct[0] = leftCount;
|
||||||
ct[1] = rightCount;
|
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;
|
return leftCount + rightCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -164,7 +164,7 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void SetupDstPlanes(
|
public static void SetupDstPlanes(
|
||||||
Span<MacroBlockDPlane> planes,
|
ref Array3<MacroBlockDPlane> planes,
|
||||||
ref Surface src,
|
ref Surface src,
|
||||||
int miRow,
|
int miRow,
|
||||||
int miCol)
|
int miCol)
|
||||||
@@ -205,11 +205,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
strides[1] = src.UvStride;
|
strides[1] = src.UvStride;
|
||||||
strides[2] = src.UvStride;
|
strides[2] = src.UvStride;
|
||||||
|
|
||||||
Span<MacroBlockDPlane> planeSpan = xd.Plane.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
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,
|
SetupPredPlanes(ref pd.Pre[idx], buffers[i], strides[i], miRow, miCol, sf, pd.SubsamplingX,
|
||||||
pd.SubsamplingY);
|
pd.SubsamplingY);
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
@@ -30,15 +29,12 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
ModeRefDeltaEnabled = true;
|
ModeRefDeltaEnabled = true;
|
||||||
ModeRefDeltaUpdate = true;
|
ModeRefDeltaUpdate = true;
|
||||||
|
|
||||||
Span<sbyte> refDeltasSpan = RefDeltas.AsSpan();
|
RefDeltas[Constants.IntraFrame] = 1;
|
||||||
Span<sbyte> modeDeltasSpan = ModeDeltas.AsSpan();
|
RefDeltas[Constants.LastFrame] = 0;
|
||||||
|
RefDeltas[Constants.GoldenFrame] = -1;
|
||||||
refDeltasSpan[Constants.IntraFrame] = 1;
|
RefDeltas[Constants.AltRefFrame] = -1;
|
||||||
refDeltasSpan[Constants.LastFrame] = 0;
|
ModeDeltas[0] = 0;
|
||||||
refDeltasSpan[Constants.GoldenFrame] = -1;
|
ModeDeltas[1] = 0;
|
||||||
refDeltasSpan[Constants.AltRefFrame] = -1;
|
|
||||||
modeDeltasSpan[0] = 0;
|
|
||||||
modeDeltasSpan[1] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
using Ryujinx.Graphics.Nvdec.Vp9.Common;
|
||||||
using Ryujinx.Graphics.Video;
|
using Ryujinx.Graphics.Video;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
||||||
{
|
{
|
||||||
@@ -148,12 +147,10 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
|
|
||||||
public void SetupBlockPlanes(int ssX, int ssY)
|
public void SetupBlockPlanes(int ssX, int ssY)
|
||||||
{
|
{
|
||||||
Span<MacroBlockDPlane> planeSpan = Plane.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
||||||
{
|
{
|
||||||
planeSpan[i].SubsamplingX = i != 0 ? ssX : 0;
|
Plane[i].SubsamplingX = i != 0 ? ssX : 0;
|
||||||
planeSpan[i].SubsamplingY = i != 0 ? ssY : 0;
|
Plane[i].SubsamplingY = i != 0 ? ssY : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,15 +159,11 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
int aboveIdx = miCol * 2;
|
int aboveIdx = miCol * 2;
|
||||||
int leftIdx = (miRow * 2) & 15;
|
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)
|
for (int i = 0; i < Constants.MaxMbPlane; ++i)
|
||||||
{
|
{
|
||||||
ref MacroBlockDPlane pd = ref planeSpan[i];
|
ref MacroBlockDPlane pd = ref Plane[i];
|
||||||
pd.AboveContext = aboveContextSpan[i].Slice(aboveIdx >> pd.SubsamplingX);
|
pd.AboveContext = AboveContext[i].Slice(aboveIdx >> pd.SubsamplingX);
|
||||||
pd.LeftContext = new ArrayPtr<sbyte>(ref leftContextSpan[i][leftIdx >> pd.SubsamplingY],
|
pd.LeftContext = new ArrayPtr<sbyte>(ref LeftContext[i][leftIdx >> pd.SubsamplingY],
|
||||||
16 - (leftIdx >> pd.SubsamplingY));
|
16 - (leftIdx >> pd.SubsamplingY));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,11 +182,9 @@ namespace Ryujinx.Graphics.Nvdec.Vp9.Types
|
|||||||
|
|
||||||
public unsafe void DecResetSkipContext()
|
public unsafe void DecResetSkipContext()
|
||||||
{
|
{
|
||||||
Span<MacroBlockDPlane> planeSpan = Plane.AsSpan();
|
|
||||||
|
|
||||||
for (int i = 0; i < Constants.MaxMbPlane; i++)
|
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.AboveContext.ToPointer(), (sbyte)0, pd.N4W);
|
||||||
MemoryUtil.Fill(pd.LeftContext.ToPointer(), (sbyte)0, pd.N4H);
|
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