Compare commits

..

15 Commits

Author SHA1 Message Date
Mary
5cbdfbc7a4 amadeus: Allow 5.1 sink output (#4894)
* amadeus: Allow 5.1 sink output

Also add a simple Stereo to 5.1 change for device sink.

Tested against NES - Nintendo Switch Online that output stereo on the
audio renderer.

* Remove outdated comment
2023-05-12 00:19:19 +02:00
Nico
e0544dd9c7 UI: Adjust input mapping view (#4866)
* refactor: clean up controller settings ui

- Remove inconsistencies between left and right side
- Use style to set ToggleButton properties (since they are all the same)
- Move topmost controller settings from one line to 2x2 grid for improved clarity
- Properly adjust borders, text widths, etc. to neighboring elements to eliminate misaligned visual lines

* fix: merge issues

* fix: prevent sliders from jumping by giving text block fixed width

* refactor: add more separators and increase margin

* refactor: center deadzone and range descriptions

* refactor: move rumble border top margin to -1 and prevent double border

* refactor: remove margins & double borders + switch profile & input selection

* style: apply suggestions from code review

Co-authored-by: Ac_K <Acoustik666@gmail.com>

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
2023-05-11 21:10:57 +00:00
dependabot[bot]
aa784c3e5e nuget: bump System.IdentityModel.Tokens.Jwt from 6.30.0 to 6.30.1 (#4886)
Bumps [System.IdentityModel.Tokens.Jwt](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet) from 6.30.0 to 6.30.1.
- [Release notes](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/releases)
- [Changelog](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/dev/CHANGELOG.md)
- [Commits](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/compare/6.30.0...6.30.1)

---
updated-dependencies:
- dependency-name: System.IdentityModel.Tokens.Jwt
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-11 21:42:46 +02:00
gdkchan
9205077590 Enable explicit LOD for array textures with depth compare on SPIR-V (#4892) 2023-05-11 21:35:36 +02:00
gdkchan
0ed40c7175 Fix incorrect ASTC endpoint color when using LuminanceDelta mode (#4890) 2023-05-11 20:47:55 +02:00
Mary
40d47b7aa2 amadeus: Fix wrong channel mapping check and an old typo (#4888)
* amadeus: Fix wrong channel mapping check

This was always going to happens, as a result quadratic would break and
move index after the channel count point, effectively breaking
input/output indices.

* amadeus: Fix reverb 3d early delay wrong output index
2023-05-11 20:14:02 +02:00
John
ec0bb74968 Stop SDL from inhibiting sleep. (#4842) 2023-05-11 20:13:01 +02:00
2435043xia
42f7f98666 Fix the issue of unequal check for amiibo file date due to the lack o… (#4832)
* Fix the issue of unequal check for amiibo file date due to the lack of sub-second units in the header, causing slow opening of the amiibo interface.

* Supplement the unrepaired.
2023-05-11 19:10:24 +02:00
riperiperi
95bad6995c GPU: Fix shader cache assuming past shader data was mapped (#4885)
This fixes a potential issue where a shader lookup could match the address of a previous _different_ shader, but that shader is now partially unmapped. This would just crash with an invalid region exception.

To compare a shader in the address cache with one in memory, we get the memory at the location with the previous shader's size. However, it's possible it has been unmapped and then remapped with a smaller size. In this case, we should just get back the mapped portion of the shader, which will then fail the comparison immediately and get to compile/lookup for the new one.

This might fix a random crash in TOTK that was reported by Piplup. I don't know if it does, because I don't have the game yet.
2023-05-11 18:41:34 +02:00
Mary
3d42995822 Attempt to fix release.yml after merge 2023-05-11 17:42:33 +02:00
TSRBerry
9095941fd1 Update release workflow & Add jobs for macOS (#4837)
* Add build config and extra args to create_macos_build.sh

* Use matrix strategy for releases

* Add macOS jobs

Co-authored-by: Mary <thog@protonmail.com>

* Fix wrong version argument

* Fix check for the correct amount of args

* Install latest rcodesign release

Co-authored-by: Mary <thog@protonmail.com>

* Set executable bits for PR builds on linux

---------

Co-authored-by: Mary <thog@protonmail.com>
2023-05-11 17:36:53 +02:00
gdkchan
ba71141bdc Ensure background translation threads exited before disposing JIT (#4874) 2023-05-10 21:46:38 -03:00
gdkchan
0a0675a7f6 Fix missing domain service object dispose (#4879) 2023-05-11 00:29:17 +00:00
Aaron O'Mullan
a7c6e6a8cf fix(mvk): resumeLostDevice (#4800)
Command buffer errors currently trigger an exception "DeviceLost" crashing the process.

Looking at [MKV's code](53a4eb26f2/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm (L392-L408)) we observe that:
- It hard fails if error is:
  ```
   MTLCommandBufferErrorBlacklisted || MTLCommandBufferErrorNotPermitted || MTLCommandBufferErrorDeviceRemoved
   ```
- Otherwise fails conditionally if `config.resumeLostDevice == false` (current default)

For Ryujinx's use-case it's more graceful to resume on those errors rather than crashing the app, the error isn't totally silenced since `mvk` still logs it

Fixes #4704, #4575
2023-05-10 03:31:52 +02:00
Emmanuel Hansen
0bc8151c7e IPC - Refactor Bcat service to use new ipc - Revisit (#4803)
* bcat ipc

* fix hipc buffer flags

* add buffer fixed size flag on generator
2023-05-09 21:46:23 +00:00
52 changed files with 1238 additions and 932 deletions

View File

@@ -18,9 +18,14 @@ on:
- '*.yml'
- 'README.md'
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.1.0"
jobs:
build:
name: ${{ matrix.os }} (${{ matrix.configuration }})
name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
@@ -43,47 +48,106 @@ jobs:
RELEASE_ZIP_OS_NAME: win_x64
fail-fast: false
env:
POWERSHELL_TELEMETRY_OPTOUT: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.1.0"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
global-json-file: global.json
- name: Get git short hash
id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Build
run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER
- name: Test
run: dotnet test --no-build -c "${{ matrix.configuration }}"
- name: Publish Ryujinx
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true
if: github.event_name == 'pull_request'
- name: Publish Ryujinx.Headless.SDL2
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
if: github.event_name == 'pull_request'
- name: Publish Ryujinx.Ava
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true
if: github.event_name == 'pull_request'
- name: Set executable bit
run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest'
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v3
with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish
if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v3
with:
name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_sdl2_headless
if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v3
with:
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
path: publish_ava
if: github.event_name == 'pull_request'
build_macos:
name: MacOS universal (${{ matrix.configuration }})
runs-on: ubuntu-latest
strategy:
matrix:
configuration: [ Debug, Release ]
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Setup LLVM 14
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 14
- name: Install rcodesign
run: |
mkdir -p $HOME/.bin
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
rm apple-codesign.tar.gz
mv rcodesign $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get git short hash
id: git_short_hash
run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Publish macOS
run: |
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Upload Ryujinx.Ava artifact
uses: actions/upload-artifact@v3
with:
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish_ava/*.tar.gz"
if: github.event_name == 'pull_request'

View File

@@ -22,95 +22,15 @@ env:
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "release-channel-master"
jobs:
release:
runs-on: windows-latest
tag:
name: Create tag
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Create output dir
run: "mkdir release_output"
- name: Publish Windows
run: |
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
- name: Packing Windows builds
run: |
pushd publish_windows
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_windows_sdl2_headless
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_windows_ava
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
shell: bash
- name: Publish Linux
run: |
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
- name: Packing Linux builds
run: |
pushd publish_linux
tar --exclude "publish/Ryujinx" --exclude "publish/Ryujinx.sh" -cvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx" "publish/Ryujinx"
python3 ../distribution/misc/add_tar_exec.py ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
gzip -9 < ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
rm ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
popd
pushd publish_linux_sdl2_headless
tar --exclude "publish/Ryujinx.Headless.SDL2" --exclude "publish/Ryujinx.sh" -cvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Headless.SDL2" "publish/Ryujinx.Headless.SDL2"
python3 ../distribution/misc/add_tar_exec.py ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
gzip -9 < ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
rm ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
popd
pushd publish_linux_ava
tar --exclude "publish/Ryujinx.Ava" --exclude "publish/Ryujinx.sh" -cvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar publish
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.Ava" "publish/Ryujinx.Ava"
python3 ../distribution/misc/add_tar_exec.py ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar "publish/Ryujinx.sh" "publish/Ryujinx.sh"
gzip -9 < ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar > ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz
rm ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar
popd
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"
tag: ${{ steps.version_info.outputs.build_version }}
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
allowUpdates: true
removeArtifacts: true
replacesArtifacts: true
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
- name: Create tag
uses: actions/github-script@v5
@@ -123,6 +43,163 @@ jobs:
sha: context.sha
})
release:
name: Release ${{ matrix.OS_NAME }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, windows-latest ]
include:
- os: ubuntu-latest
OS_NAME: Linux x64
DOTNET_RUNTIME_IDENTIFIER: linux-x64
RELEASE_ZIP_OS_NAME: linux_x64
- os: windows-latest
OS_NAME: Windows x64
DOTNET_RUNTIME_IDENTIFIER: win10-x64
RELEASE_ZIP_OS_NAME: win_x64
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
shell: bash
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Create output dir
run: "mkdir release_output"
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true
dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true
- name: Packing Windows builds
if: matrix.os == 'windows-latest'
run: |
pushd publish_gtk
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_sdl2_headless
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
pushd publish_ava
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
popd
shell: bash
- name: Packing Linux builds
if: matrix.os == 'ubuntu-latest'
run: |
pushd publish_gtk
chmod +x publish/Ryujinx.sh publish/Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
pushd publish_sdl2_headless
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
pushd publish_ava
chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
popd
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"
tag: ${{ steps.version_info.outputs.build_version }}
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
omitBodyDuringUpdate: true
allowUpdates: true
replacesArtifacts: true
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
macos_release:
name: Release MacOS universal
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-dotnet@v3
with:
global-json-file: global.json
- name: Setup LLVM 14
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 14
- name: Install rcodesign
run: |
mkdir -p $HOME/.bin
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
rm apple-codesign.tar.gz
mv rcodesign $HOME/.bin/
echo "$HOME/.bin" >> $GITHUB_PATH
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Get version info
id: version_info
run: |
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
- name: Configure for release
run: |
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
shell: bash
- name: Publish macOS
run: |
./distribution/macos/create_macos_build.sh . publish_tmp publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "publish_ava/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }}
body: "For more information about this release please check out the official [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog)."
omitBodyDuringUpdate: true
allowUpdates: true
replacesArtifacts: true
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
token: ${{ secrets.RELEASE_TOKEN }}
flatpak_release:
uses: ./.github/workflows/flatpak.yml
needs: release

View File

@@ -44,7 +44,7 @@
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
<PackageVersion Include="SPB" Version="0.0.4-build28" />
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.30.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.30.1" />
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
<PackageVersion Include="System.Management" Version="7.0.1" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />

View File

@@ -2,8 +2,8 @@
set -e
if [ "$#" -ne 6 ]; then
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID>"
if [ "$#" -lt 7 ]; then
echo "usage <BASE_DIR> <TEMP_DIRECTORY> <OUTPUT_DIRECTORY> <ENTITLEMENTS_FILE_PATH> <VERSION> <SOURCE_REVISION_ID> <CONFIGURATION> <EXTRA_ARGS>"
exit 1
fi
@@ -17,8 +17,16 @@ OUTPUT_DIRECTORY=$(readlink -f "$3")
ENTITLEMENTS_FILE_PATH=$(readlink -f "$4")
VERSION=$5
SOURCE_REVISION_ID=$6
CONFIGURATION=$7
EXTRA_ARGS=$8
if [ "$VERSION" == "1.1.0" ];
then
RELEASE_TAR_FILE_NAME=Ryujinx-$CONFIGURATION-$VERSION+$SOURCE_REVISION_ID-macos_universal.app.tar
else
RELEASE_TAR_FILE_NAME=Ryujinx-$VERSION-macos_universal.app.tar
fi
RELEASE_TAR_FILE_NAME=Ryujinx-$VERSION-macos_universal.app.tar
ARM64_APP_BUNDLE="$TEMP_DIRECTORY/output_arm64/Ryujinx.app"
X64_APP_BUNDLE="$TEMP_DIRECTORY/output_x64/Ryujinx.app"
UNIVERSAL_APP_BUNDLE="$OUTPUT_DIRECTORY/Ryujinx.app"
@@ -27,12 +35,12 @@ EXECUTABLE_SUB_PATH=Contents/MacOS/Ryujinx
rm -rf "$TEMP_DIRECTORY"
mkdir -p "$TEMP_DIRECTORY"
DOTNET_COMMON_ARGS="-p:DebugType=embedded -p:Version=$VERSION -p:SourceRevisionId=$SOURCE_REVISION_ID --self-contained true"
DOTNET_COMMON_ARGS="-p:DebugType=embedded -p:Version=$VERSION -p:SourceRevisionId=$SOURCE_REVISION_ID --self-contained true $EXTRA_ARGS"
dotnet restore
dotnet build -c Release src/Ryujinx.Ava
dotnet publish -c Release -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
dotnet publish -c Release -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
dotnet build -c $CONFIGURATION src/Ryujinx.Ava
dotnet publish -c $CONFIGURATION -r osx-arm64 -o "$TEMP_DIRECTORY/publish_arm64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
dotnet publish -c $CONFIGURATION -r osx-x64 -o "$TEMP_DIRECTORY/publish_x64" $DOTNET_COMMON_ARGS src/Ryujinx.Ava
# Get rid of the support library for ARMeilleure for x64 (that's only for arm64)
rm -rf "$TEMP_DIRECTORY/publish_x64/libarmeilleure-jitsupport.dylib"
@@ -68,7 +76,7 @@ else
LIPO=lipo
fi
# Make it the executable universal
# Make the executable universal
$LIPO "$ARM64_APP_BUNDLE/$EXECUTABLE_SUB_PATH" "$X64_APP_BUNDLE/$EXECUTABLE_SUB_PATH" -output "$UNIVERSAL_APP_BUNDLE/$EXECUTABLE_SUB_PATH" -create
# Patch up the Info.plist to have appropriate version
@@ -87,10 +95,10 @@ then
# NOTE: Currently require https://github.com/indygreg/apple-platform-rs/pull/44 to work on other OSes.
# cargo install --git "https://github.com/marysaka/apple-platform-rs" --branch "fix/adhoc-app-bundle" apple-codesign --bin "rcodesign"
echo "Usign rcodesign for ad-hoc signing"
echo "Using rcodesign for ad-hoc signing"
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$UNIVERSAL_APP_BUNDLE"
else
echo "Usign codesign for ad-hoc signing"
echo "Using codesign for ad-hoc signing"
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$UNIVERSAL_APP_BUNDLE"
fi

View File

@@ -54,6 +54,7 @@ namespace ARMeilleure.Translation
internal TranslatorQueue Queue { get; }
internal IMemoryManager Memory { get; }
private Thread[] _backgroundTranslationThreads;
private volatile int _threadCount;
// FIXME: Remove this once the init logic of the emulator will be redone.
@@ -127,18 +128,22 @@ namespace ARMeilleure.Translation
int unboundedThreadCount = Math.Max(1, (Environment.ProcessorCount - 6) / 3);
int threadCount = Math.Min(4, unboundedThreadCount);
Thread[] backgroundTranslationThreads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++)
{
bool last = i != 0 && i == unboundedThreadCount - 1;
Thread backgroundTranslatorThread = new Thread(BackgroundTranslate)
backgroundTranslationThreads[i] = new Thread(BackgroundTranslate)
{
Name = "CPU.BackgroundTranslatorThread." + i,
Priority = last ? ThreadPriority.Lowest : ThreadPriority.Normal
};
backgroundTranslatorThread.Start();
backgroundTranslationThreads[i].Start();
}
Interlocked.Exchange(ref _backgroundTranslationThreads, backgroundTranslationThreads);
}
Statistics.InitializeTimer();
@@ -162,9 +167,20 @@ namespace ARMeilleure.Translation
if (Interlocked.Decrement(ref _threadCount) == 0)
{
Queue.Dispose();
Thread[] backgroundTranslationThreads = Interlocked.Exchange(ref _backgroundTranslationThreads, null);
if (backgroundTranslationThreads != null)
{
foreach (Thread thread in backgroundTranslationThreads)
{
thread.Join();
}
}
ClearJitCache();
Queue.Dispose();
Stubs.Dispose();
FunctionTable.Dispose();
CountTable.Dispose();

View File

@@ -65,9 +65,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
{
OutputDevices = new IHardwareDevice[Constants.AudioRendererSessionCountMax];
// TODO: Before enabling this, we need up-mixing from stereo to 5.1.
// uint channelCount = GetHardwareChannelCount(deviceDriver);
uint channelCount = 2;
uint channelCount = GetHardwareChannelCount(deviceDriver);
for (int i = 0; i < OutputDevices.Length; i++)
{

View File

@@ -49,8 +49,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
}
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
DataSourceHelper.RemapLegacyChannelEffectMappingToChannelResourceMapping(newEffectChannelMappingSupported, OutputBufferIndices, Parameter.ChannelCount);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]

View File

@@ -67,7 +67,19 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
const int sampleCount = Constants.TargetSampleCount;
short[] outputBuffer = new short[bufferCount * sampleCount];
uint inputCount;
// In case of upmixing to 5.1, we allocate the right amount.
if (bufferCount != channelCount && channelCount == 6)
{
inputCount = (uint)channelCount;
}
else
{
inputCount = bufferCount;
}
short[] outputBuffer = new short[inputCount * sampleCount];
for (int i = 0; i < bufferCount; i++)
{
@@ -79,7 +91,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
}
}
device.AppendBuffer(outputBuffer, InputCount);
device.AppendBuffer(outputBuffer, inputCount);
}
else
{

View File

@@ -66,8 +66,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
// TODO: Update reverb 3d processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices, Parameter.ChannelCount);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -116,7 +116,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
for (int i = 0; i < targetEarlyDelayLineIndicesTable.Length; i++)
{
int earlyDelayIndex = targetEarlyDelayLineIndicesTable[i];
int outputIndex = outputEarlyIndicesTable[i];
int outputIndex = outputEarlyIndicesTable[earlyDelayIndex];
float tempTapOut = state.PreDelayLine.TapUnsafe(state.EarlyDelayTime[earlyDelayIndex], delayLineSampleIndexOffset);

View File

@@ -71,8 +71,8 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
// NOTE: We do the opposite as Nintendo here for now to restore previous behaviour
// TODO: Update reverb processing and remove this to use RemapLegacyChannelEffectMappingToChannelResourceMapping.
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, InputBufferIndices, Parameter.ChannelCount);
DataSourceHelper.RemapChannelResourceMappingToLegacy(newEffectChannelMappingSupported, OutputBufferIndices, Parameter.ChannelCount);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -430,9 +430,9 @@ namespace Ryujinx.Audio.Renderer.Dsp
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void RemapLegacyChannelEffectMappingToChannelResourceMapping(bool isSupported, Span<ushort> bufferIndices)
public static void RemapLegacyChannelEffectMappingToChannelResourceMapping(bool isSupported, Span<ushort> bufferIndices, uint channelCount)
{
if (!isSupported && bufferIndices.Length == 6)
if (!isSupported && channelCount == 6)
{
ushort backLeft = bufferIndices[2];
ushort backRight = bufferIndices[3];
@@ -447,9 +447,9 @@ namespace Ryujinx.Audio.Renderer.Dsp
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void RemapChannelResourceMappingToLegacy(bool isSupported, Span<ushort> bufferIndices)
public static void RemapChannelResourceMappingToLegacy(bool isSupported, Span<ushort> bufferIndices, uint channelCount)
{
if (isSupported && bufferIndices.Length == 6)
if (isSupported && channelCount == 6)
{
ushort frontCenter = bufferIndices[2];
ushort lowFrequency = bufferIndices[3];

View File

@@ -370,7 +370,7 @@ namespace Ryujinx.Ava.UI.ViewModels
if (response.IsSuccessStatusCode)
{
return response.Content.Headers.LastModified != oldLastModified;
return response.Content.Headers.LastModified != new DateTimeOffset(oldLastModified.Ticks - (oldLastModified.Ticks % TimeSpan.TicksPerSecond), TimeSpan.Zero);
}
return false;

View File

@@ -21,35 +21,54 @@
<UserControl.Resources>
<helpers:KeyValueConverter x:Key="Key" />
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="ToggleButton">
<Setter Property="Width" Value="90" />
<Setter Property="Height" Value="27" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</UserControl.Styles>
<StackPanel
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Orientation="Vertical">
<Grid Margin="2,2,2,5" HorizontalAlignment="Stretch">
<Grid Margin="0,2,0,5" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Player selection -->
<Border
Grid.Row="0"
Grid.Column="0"
Margin="0,0,2,0"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
Padding="2,0">
<StackPanel
Padding="2">
<Grid
Margin="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Vertical">
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Margin="0,0,0,4"
HorizontalAlignment="Center"
Margin="5,0,10,0"
Width="90"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsPlayer}" />
<ComboBox
Grid.Column="1"
Name="PlayerIndexBox"
Width="150"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
SelectionChanged="PlayerIndexBox_OnSelectionChanged"
Items="{Binding PlayerIndexes}"
SelectedIndex="{Binding PlayerId}">
@@ -59,103 +78,44 @@
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Border>
<!-- Main Controller Settings -->
<Border
Grid.Column="1"
Margin="0,0,2,0"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
Padding="2,0">
<StackPanel
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Orientation="Vertical">
<TextBlock
Margin="0,0,0,5"
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsInputDevice}" />
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox
Name="DeviceBox"
HorizontalAlignment="Stretch"
Items="{Binding DeviceList}"
SelectedIndex="{Binding Device}" />
<Button
Grid.Column="1"
MinWidth="0"
Margin="5,0,0,0"
VerticalAlignment="Center"
Command="{Binding LoadDevices}">
<ui:SymbolIcon
Symbol="Refresh"
FontSize="15"
Height="20" />
</Button>
</Grid>
</StackPanel>
</Border>
<!-- Profile selection -->
<Border
Grid.Column="2"
Margin="0,0,2,0"
Grid.Row="1"
Grid.Column="0"
Margin="0,-1,0,0"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
Padding="2,0">
Padding="2">
<Grid
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock
Margin="0,0,0,4"
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsControllerType}" />
<ComboBox
Grid.Row="1"
HorizontalAlignment="Stretch"
Items="{Binding Controllers}"
SelectedIndex="{Binding Controller}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Border>
<Border
Grid.Column="3"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
Padding="2,0" >
<StackPanel
Margin="2"
HorizontalAlignment="Center"
Margin="5,0,10,0"
Width="90"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Orientation="Vertical">
<TextBlock
Margin="0,0,0,4"
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsProfile}" />
<StackPanel Orientation="Horizontal">
<ui:ComboBox
Grid.Column="1"
IsEditable="True"
Name="ProfileBox"
Width="100"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
SelectedIndex="0"
Items="{Binding ProfilesList}"
Text="{Binding ProfileName}" />
<Button
Grid.Column="2"
MinWidth="0"
Margin="5,0,0,0"
VerticalAlignment="Center"
@@ -167,6 +127,7 @@
Height="20" />
</Button>
<Button
Grid.Column="3"
MinWidth="0"
Margin="5,0,0,0"
VerticalAlignment="Center"
@@ -178,6 +139,7 @@
Height="20" />
</Button>
<Button
Grid.Column="4"
MinWidth="0"
Margin="5,0,0,0"
VerticalAlignment="Center"
@@ -188,8 +150,85 @@
FontSize="15"
Height="20" />
</Button>
</StackPanel>
</StackPanel>
</Grid>
</Border>
<!-- Input device -->
<Border
Grid.Row="0"
Grid.Column="1"
Margin="-1,0,0,0"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
Padding="2">
<Grid Margin="2" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Margin="5,0,10,0"
Width="90"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsInputDevice}" />
<ComboBox
Grid.Column="1"
Name="DeviceBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Items="{Binding DeviceList}"
SelectedIndex="{Binding Device}" />
<Button
Grid.Column="2"
MinWidth="0"
Margin="5,0,0,0"
VerticalAlignment="Center"
Command="{Binding LoadDevices}">
<ui:SymbolIcon
Symbol="Refresh"
FontSize="15"
Height="20"/>
</Button>
</Grid>
</Border>
<!-- Controler type -->
<Border
Grid.Row="1"
Grid.Column="1"
Margin="-1,-1,0,0"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
Padding="2">
<Grid
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Margin="5,0,10,0"
Width="90"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsControllerType}" />
<ComboBox
Grid.Column="1"
HorizontalAlignment="Stretch"
Items="{Binding Controllers}"
SelectedIndex="{Binding Controller}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Border>
</Grid>
@@ -206,7 +245,7 @@
<!-- Left -->
<Grid
Margin="0,0,10,0"
Margin="0,0,5,0"
Grid.Column="0"
VerticalAlignment="Stretch"
DockPanel.Dock="Left">
@@ -221,7 +260,8 @@
Grid.Row="0"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
IsVisible="{Binding IsLeft}">
IsVisible="{Binding IsLeft}"
MinHeight="90">
<Grid Margin="10" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
@@ -232,7 +272,6 @@
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel
Margin="0,0,0,4"
Grid.Column="0"
Grid.Row="0"
Background="{DynamicResource ThemeDarkColor}"
@@ -243,10 +282,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsTriggerZL}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonZl, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -263,19 +299,15 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsTriggerL}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonL, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
<StackPanel
Margin="0,0,0,4"
Grid.Column="1"
Grid.Row="0"
Grid.Row="1"
Background="{DynamicResource ThemeDarkColor}"
Orientation="Horizontal">
<TextBlock
@@ -284,10 +316,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtonMinus}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonMinus, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -301,7 +330,8 @@
Grid.Row="1"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
IsVisible="{Binding IsLeft}">
IsVisible="{Binding IsLeft}"
Margin="0,5,0,0">
<StackPanel Margin="10" Orientation="Vertical">
<TextBlock
Margin="0,0,0,10"
@@ -320,10 +350,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLStickButton}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.LeftKeyboardStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -339,10 +366,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLStickUp}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.LeftStickUp, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -358,10 +382,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLStickDown}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.LeftStickDown, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -377,10 +398,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLStickLeft}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.LeftStickLeft, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -396,10 +414,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLStickRight}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.LeftStickRight, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -419,10 +434,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLStickButton}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.LeftControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -438,16 +450,13 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLStickStick}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch"
Tag="stick">
<ToggleButton Tag="stick">
<TextBlock
Text="{Binding Configuration.LeftJoystick, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
<Separator Margin="0,8,0,8" Height="1" />
<CheckBox IsChecked="{Binding Configuration.LeftInvertStickX}">
<TextBlock Text="{locale:Locale ControllerSettingsLStickInvertXAxis}" />
</CheckBox>
@@ -457,9 +466,11 @@
<CheckBox IsChecked="{Binding Configuration.LeftRotate90}">
<TextBlock Text="{locale:Locale ControllerSettingsRotate90}" />
</CheckBox>
<Separator Margin="0,4,0,4" Height="1" />
<Separator Margin="0,8,0,8" Height="1" />
<StackPanel Orientation="Vertical">
<TextBlock Text="{locale:Locale ControllerSettingsLStickDeadzone}" />
<TextBlock
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsLStickDeadzone}" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -473,9 +484,12 @@
Value="{Binding Configuration.DeadzoneLeft, Mode=TwoWay}" />
<TextBlock
VerticalAlignment="Center"
Width="25"
Text="{Binding Configuration.DeadzoneLeft, StringFormat=\{0:0.00\}}" />
</StackPanel>
<TextBlock Text="{locale:Locale ControllerSettingsStickRange}" />
<TextBlock
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsStickRange}" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -489,6 +503,7 @@
Value="{Binding Configuration.RangeLeft, Mode=TwoWay}" />
<TextBlock
VerticalAlignment="Center"
Width="25"
Text="{Binding Configuration.RangeLeft, StringFormat=\{0:0.00\}}" />
</StackPanel>
</StackPanel>
@@ -502,7 +517,8 @@
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
VerticalAlignment="Top"
IsVisible="{Binding IsLeft}">
IsVisible="{Binding IsLeft}"
Margin="0,5,0,0">
<StackPanel Margin="10" Orientation="Vertical">
<TextBlock
Margin="0,0,0,10"
@@ -519,8 +535,6 @@
Text="{locale:Locale ControllerSettingsDPadUp}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<TextBlock
Text="{Binding Configuration.DpadUp, Mode=TwoWay, Converter={StaticResource Key}}"
@@ -538,8 +552,6 @@
Text="{locale:Locale ControllerSettingsDPadDown}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<TextBlock
Text="{Binding Configuration.DpadDown, Mode=TwoWay, Converter={StaticResource Key}}"
@@ -557,8 +569,6 @@
Text="{locale:Locale ControllerSettingsDPadLeft}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<TextBlock
Text="{Binding Configuration.DpadLeft, Mode=TwoWay, Converter={StaticResource Key}}"
@@ -576,8 +586,6 @@
Text="{locale:Locale ControllerSettingsDPadRight}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<TextBlock
Text="{Binding Configuration.DpadRight, Mode=TwoWay, Converter={StaticResource Key}}"
@@ -590,11 +598,11 @@
</Grid>
<!-- Triggers And Side Buttons-->
<StackPanel Grid.Column="1" HorizontalAlignment="Stretch">
<StackPanel Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1">
<StackPanel Margin="10" Orientation="Vertical">
BorderThickness="1" MinHeight="90">
<StackPanel Margin="8" Orientation="Vertical">
<TextBlock HorizontalAlignment="Center" Text="{locale:Locale ControllerSettingsTriggerThreshold}" />
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Slider
@@ -604,7 +612,9 @@
IsSnapToTickEnabled="True"
Minimum="0"
Value="{Binding Configuration.TriggerThreshold, Mode=TwoWay}" />
<TextBlock Text="{Binding Configuration.TriggerThreshold, StringFormat=\{0:0.00\}}" />
<TextBlock
Width="25"
Text="{Binding Configuration.TriggerThreshold, StringFormat=\{0:0.00\}}" />
</StackPanel>
<StackPanel
Margin="0,4,0,0"
@@ -619,10 +629,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLeftSR}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.LeftButtonSr, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -641,10 +648,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsLeftSL}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.LeftButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -663,10 +667,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRightSR}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.RightButtonSr, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -685,10 +686,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRightSL}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.RightButtonSl, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -702,14 +700,15 @@
Margin="0,10,0,0"
MaxHeight="250"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"
VerticalAlignment="Stretch"
Source="{Binding Image}" />
<!-- Motion+Rumble -->
<StackPanel Margin="0,10,0,0" Orientation="Vertical" >
<StackPanel Margin="0,10,0,0" Orientation="Vertical" VerticalAlignment="Bottom">
<Border
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
VerticalAlignment="Bottom"
HorizontalAlignment="Stretch"
IsVisible="{Binding IsController}">
<Grid>
@@ -733,7 +732,8 @@
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
HorizontalAlignment="Stretch"
IsVisible="{Binding IsController}">
IsVisible="{Binding IsController}"
Margin="0,-1,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
@@ -756,7 +756,7 @@
<!--Right Controls-->
<Grid
Margin="10,0,0,0"
Margin="5,0,0,0"
Grid.Column="2"
VerticalAlignment="Top"
HorizontalAlignment="Stretch" >
@@ -770,9 +770,9 @@
Grid.Row="0"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
IsVisible="{Binding IsRight}">
<StackPanel Margin="10" Orientation="Vertical">
<Grid HorizontalAlignment="Stretch">
IsVisible="{Binding IsRight}"
MinHeight="90">
<Grid Margin="10" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
@@ -782,7 +782,6 @@
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel
Margin="0,0,0,4"
Grid.Column="1"
Grid.Row="0"
Background="{DynamicResource ThemeDarkColor}"
@@ -793,10 +792,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsTriggerZR}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonZr, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -815,19 +811,15 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsTriggerR}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonR, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
<StackPanel
Margin="0,0,8,4"
Grid.Column="0"
Grid.Row="0"
Grid.Row="1"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Background="{DynamicResource ThemeDarkColor}"
@@ -838,97 +830,39 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtonPlus}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonPlus, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<Border
Grid.Row="1"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
IsVisible="{Binding IsRight}">
IsVisible="{Binding IsRight}"
Margin="0,5,0,0">
<StackPanel Margin="10" Orientation="Vertical">
<TextBlock
Margin="0,0,0,10"
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtons}" />
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!-- Right Buttons X -->
<StackPanel
Margin="0,0,0,4"
Grid.Column="0"
Grid.Row="0"
Background="{DynamicResource ThemeDarkColor}"
Orientation="Horizontal">
<TextBlock
Width="20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtonX}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<TextBlock
Text="{Binding Configuration.ButtonX, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
<!-- Right Buttons Y -->
<StackPanel
Grid.Column="0"
Grid.Row="1"
Background="{DynamicResource ThemeDarkColor}"
Orientation="Horizontal">
<TextBlock
Width="20"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtonY}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<TextBlock
Text="{Binding Configuration.ButtonY, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
<StackPanel Orientation="Vertical">
<!-- Right Buttons A -->
<StackPanel
Margin="0,0,0,4"
Grid.Column="1"
Grid.Row="0"
Background="{DynamicResource ThemeDarkColor}"
Orientation="Horizontal">
<TextBlock
Width="20"
Width="120"
Margin="0,0,10,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtonA}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonA, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -936,26 +870,59 @@
</StackPanel>
<!-- Right Buttons B -->
<StackPanel
Grid.Column="1"
Grid.Row="1"
Margin="0,0,0,4"
Background="{DynamicResource ThemeDarkColor}"
Orientation="Horizontal">
<TextBlock
Width="20"
Width="120"
Margin="0,0,10,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtonB}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonB, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
</Grid>
<!-- Right Buttons X -->
<StackPanel
Margin="0,0,0,4"
Background="{DynamicResource ThemeDarkColor}"
Orientation="Horizontal">
<TextBlock
Width="120"
Margin="0,0,10,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtonX}"
TextAlignment="Center" />
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonX, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
<!-- Right Buttons Y -->
<StackPanel
Margin="0,0,0,4"
Background="{DynamicResource ThemeDarkColor}"
Orientation="Horizontal">
<TextBlock
Width="120"
Margin="0,0,10,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsButtonY}"
TextAlignment="Center" />
<ToggleButton>
<TextBlock
Text="{Binding Configuration.ButtonY, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
</StackPanel>
</StackPanel>
</Border>
<Border
@@ -963,7 +930,8 @@
Padding="10"
BorderBrush="{DynamicResource ThemeControlBorderColor}"
BorderThickness="1"
IsVisible="{Binding IsRight}">
IsVisible="{Binding IsRight}"
Margin="0,5,0,0">
<StackPanel Orientation="Vertical">
<TextBlock
Margin="0,0,0,10"
@@ -982,10 +950,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRStickButton}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.RightKeyboardStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -1001,10 +966,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRStickUp}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.RightStickUp, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -1020,10 +982,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRStickDown}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.RightStickDown, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -1039,10 +998,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRStickLeft}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.RightStickLeft, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -1058,10 +1014,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRStickRight}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.RightStickRight, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -1081,10 +1034,7 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRStickButton}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch">
<ToggleButton>
<TextBlock
Text="{Binding Configuration.RightControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
@@ -1101,16 +1051,13 @@
VerticalAlignment="Center"
Text="{locale:Locale ControllerSettingsRStickStick}"
TextAlignment="Center" />
<ToggleButton
Width="90"
Height="27"
HorizontalAlignment="Stretch"
Tag="stick">
<ToggleButton Tag="stick">
<TextBlock
Text="{Binding Configuration.RightJoystick, Mode=TwoWay, Converter={StaticResource Key}}"
TextAlignment="Center" />
</ToggleButton>
</StackPanel>
<Separator Margin="0,8,0,8" Height="1" />
<CheckBox IsChecked="{Binding Configuration.RightInvertStickX}">
<TextBlock Text="{locale:Locale ControllerSettingsRStickInvertXAxis}" />
</CheckBox>
@@ -1120,9 +1067,11 @@
<CheckBox IsChecked="{Binding Configuration.RightRotate90}">
<TextBlock Text="{locale:Locale ControllerSettingsRotate90}" />
</CheckBox>
<Separator Margin="0,4,0,4" Height="1" />
<Separator Margin="0,8,0,8" Height="1" />
<StackPanel Orientation="Vertical">
<TextBlock Text="{locale:Locale ControllerSettingsRStickDeadzone}" />
<TextBlock
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsRStickDeadzone}" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -1138,9 +1087,12 @@
Value="{Binding Configuration.DeadzoneRight, Mode=TwoWay}" />
<TextBlock
VerticalAlignment="Center"
Width="25"
Text="{Binding Configuration.DeadzoneRight, StringFormat=\{0:0.00\}}" />
</StackPanel>
<TextBlock Text="{locale:Locale ControllerSettingsStickRange}" />
<TextBlock
HorizontalAlignment="Center"
Text="{locale:Locale ControllerSettingsStickRange}" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
@@ -1154,6 +1106,7 @@
Value="{Binding Configuration.RangeRight, Mode=TwoWay}" />
<TextBlock
VerticalAlignment="Center"
Width="25"
Text="{Binding Configuration.RangeRight, StringFormat=\{0:0.00\}}" />
</StackPanel>
</StackPanel>

View File

@@ -591,7 +591,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
return true;
}
ReadOnlySpan<byte> memoryCode = memoryManager.GetSpan(gpuVa, shader.Code.Length);
ReadOnlySpan<byte> memoryCode = memoryManager.GetSpanMapped(gpuVa, shader.Code.Length);
return memoryCode.SequenceEqual(shader.Code);
}

View File

@@ -1442,14 +1442,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
return GetZeroOperationResult(context, texOp, AggregateType.FP32, colorIsVector);
}
// This combination is valid, but not available on GLSL.
// For now, ignore the LOD level and do a normal sample.
// TODO: How to implement it properly?
if (hasLodLevel && isArray && isShadow)
{
hasLodLevel = false;
}
int srcIndex = isBindless ? 1 : 0;
SpvInstruction Src(AggregateType type)

View File

@@ -956,7 +956,7 @@ namespace Ryujinx.Graphics.Texture.Astc
{
Span<uint> val = ReadUintColorValues(2, colorValues, ref colorValuesPosition);
int l0 = (int)((val[0] >> 2) | (val[1] & 0xC0));
int l1 = (int)Math.Max(l0 + (val[1] & 0x3F), 0xFFU);
int l1 = (int)Math.Min(l0 + (val[1] & 0x3F), 0xFFU);
endPoints[0] = new AstcPixel(0xFF, (short)l0, (short)l0, (short)l0);
endPoints[1] = new AstcPixel(0xFF, (short)l1, (short)l1, (short)l1);

View File

@@ -25,6 +25,8 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
config.SemaphoreSupportStyle = MVKVkSemaphoreSupportStyle.MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE;
config.SynchronousQueueSubmits = false;
config.ResumeLostDevice = true;
vkSetMoltenVKConfigurationMVK(IntPtr.Zero, config, configSize);
}
}

View File

@@ -328,7 +328,7 @@ namespace Ryujinx.HLE.HOS
private void StartNewServices()
{
ServiceTable = new ServiceTable();
var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices));
var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices, LibHacHorizonManager.BcatClient));
foreach (var service in services)
{

View File

@@ -1,85 +0,0 @@
using LibHac;
using LibHac.Common;
using Ryujinx.Common;
using Ryujinx.HLE.HOS.Services.Arp;
using Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator;
namespace Ryujinx.HLE.HOS.Services.Bcat
{
[Service("bcat:a", "bcat:a")]
[Service("bcat:m", "bcat:m")]
[Service("bcat:u", "bcat:u")]
[Service("bcat:s", "bcat:s")]
class IServiceCreator : DisposableIpcService
{
private SharedRef<LibHac.Bcat.Impl.Ipc.IServiceCreator> _base;
public IServiceCreator(ServiceCtx context, string serviceName)
{
var applicationClient = context.Device.System.LibHacHorizonManager.ApplicationClient;
applicationClient.Sm.GetService(ref _base, serviceName).ThrowIfFailure();
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_base.Destroy();
}
}
[CommandCmif(0)]
// CreateBcatService(pid) -> object<nn::bcat::detail::ipc::IBcatService>
public ResultCode CreateBcatService(ServiceCtx context)
{
// TODO: Call arp:r GetApplicationLaunchProperty with the pid to get the TitleId.
// Add an instance of nn::bcat::detail::service::core::PassphraseManager.
// Add an instance of nn::bcat::detail::service::ServiceMemoryManager.
// Add an instance of nn::bcat::detail::service::core::TaskManager who load "bcat-sys:/" system save data and open "dc/task.bin".
// If the file don't exist, create a new one (size of 0x800) and write 2 empty struct with a size of 0x400.
MakeObject(context, new IBcatService(ApplicationLaunchProperty.GetByPid(context)));
// NOTE: If the IBcatService is null this error is returned, Doesn't occur in our case.
// return ResultCode.NullObject;
return ResultCode.Success;
}
[CommandCmif(1)]
// CreateDeliveryCacheStorageService(pid) -> object<nn::bcat::detail::ipc::IDeliveryCacheStorageService>
public ResultCode CreateDeliveryCacheStorageService(ServiceCtx context)
{
ulong pid = context.RequestData.ReadUInt64();
using var serv = new SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService>();
Result rc = _base.Get.CreateDeliveryCacheStorageService(ref serv.Ref, pid);
if (rc.IsSuccess())
{
MakeObject(context, new IDeliveryCacheStorageService(context, ref serv.Ref));
}
return (ResultCode)rc.Value;
}
[CommandCmif(2)]
// CreateDeliveryCacheStorageServiceWithApplicationId(nn::ApplicationId) -> object<nn::bcat::detail::ipc::IDeliveryCacheStorageService>
public ResultCode CreateDeliveryCacheStorageServiceWithApplicationId(ServiceCtx context)
{
ApplicationId applicationId = context.RequestData.ReadStruct<ApplicationId>();
using var service = new SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService>();
Result rc = _base.Get.CreateDeliveryCacheStorageServiceWithApplicationId(ref service.Ref, applicationId);
if (rc.IsSuccess())
{
MakeObject(context, new IDeliveryCacheStorageService(context, ref service.Ref));
}
return (ResultCode)rc.Value;
}
}
}

View File

@@ -1,29 +0,0 @@
namespace Ryujinx.HLE.HOS.Services.Bcat
{
enum ResultCode
{
ModuleId = 122,
ErrorCodeShift = 9,
Success = 0,
InvalidArgument = (1 << ErrorCodeShift) | ModuleId,
NotFound = (2 << ErrorCodeShift) | ModuleId,
TargetLocked = (3 << ErrorCodeShift) | ModuleId,
TargetAlreadyMounted = (4 << ErrorCodeShift) | ModuleId,
TargetNotMounted = (5 << ErrorCodeShift) | ModuleId,
AlreadyOpen = (6 << ErrorCodeShift) | ModuleId,
NotOpen = (7 << ErrorCodeShift) | ModuleId,
InternetRequestDenied = (8 << ErrorCodeShift) | ModuleId,
ServiceOpenLimitReached = (9 << ErrorCodeShift) | ModuleId,
SaveDataNotFound = (10 << ErrorCodeShift) | ModuleId,
NetworkServiceAccountNotAvailable = (31 << ErrorCodeShift) | ModuleId,
PassphrasePathNotFound = (80 << ErrorCodeShift) | ModuleId,
DataVerificationFailed = (81 << ErrorCodeShift) | ModuleId,
PermissionDenied = (90 << ErrorCodeShift) | ModuleId,
AllocationFailed = (91 << ErrorCodeShift) | ModuleId,
InvalidOperation = (98 << ErrorCodeShift) | ModuleId,
InvalidDeliveryCacheStorageFile = (204 << ErrorCodeShift) | ModuleId,
StorageOpenLimitReached = (205 << ErrorCodeShift) | ModuleId
}
}

View File

@@ -1,18 +0,0 @@
using Ryujinx.HLE.HOS.Services.Arp;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
class IBcatService : IpcService
{
public IBcatService(ApplicationLaunchProperty applicationLaunchProperty) { }
[CommandCmif(10100)]
// RequestSyncDeliveryCache() -> object<nn::bcat::detail::ipc::IDeliveryCacheProgressService>
public ResultCode RequestSyncDeliveryCache(ServiceCtx context)
{
MakeObject(context, new IDeliveryCacheProgressService(context));
return ResultCode.Success;
}
}
}

View File

@@ -1,65 +0,0 @@
using LibHac;
using LibHac.Bcat;
using LibHac.Common;
using Ryujinx.Common;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
class IDeliveryCacheDirectoryService : DisposableIpcService
{
private SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService> _base;
public IDeliveryCacheDirectoryService(ref SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService> baseService)
{
_base = SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService>.CreateMove(ref baseService);
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_base.Destroy();
}
}
[CommandCmif(0)]
// Open(nn::bcat::DirectoryName)
public ResultCode Open(ServiceCtx context)
{
DirectoryName directoryName = context.RequestData.ReadStruct<DirectoryName>();
Result result = _base.Get.Open(ref directoryName);
return (ResultCode)result.Value;
}
[CommandCmif(1)]
// Read() -> (u32, buffer<nn::bcat::DeliveryCacheDirectoryEntry, 6>)
public ResultCode Read(ServiceCtx context)
{
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _base.Get.Read(out int entriesRead, MemoryMarshal.Cast<byte, DeliveryCacheDirectoryEntry>(region.Memory.Span));
context.ResponseData.Write(entriesRead);
return (ResultCode)result.Value;
}
}
[CommandCmif(2)]
// GetCount() -> u32
public ResultCode GetCount(ServiceCtx context)
{
Result result = _base.Get.GetCount(out int count);
context.ResponseData.Write(count);
return (ResultCode)result.Value;
}
}
}

View File

@@ -1,78 +0,0 @@
using LibHac;
using LibHac.Bcat;
using LibHac.Common;
using Ryujinx.Common;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
class IDeliveryCacheFileService : DisposableIpcService
{
private SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService> _base;
public IDeliveryCacheFileService(ref SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService> baseService)
{
_base = SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService>.CreateMove(ref baseService);
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_base.Destroy();
}
}
[CommandCmif(0)]
// Open(nn::bcat::DirectoryName, nn::bcat::FileName)
public ResultCode Open(ServiceCtx context)
{
DirectoryName directoryName = context.RequestData.ReadStruct<DirectoryName>();
FileName fileName = context.RequestData.ReadStruct<FileName>();
Result result = _base.Get.Open(ref directoryName, ref fileName);
return (ResultCode)result.Value;
}
[CommandCmif(1)]
// Read(u64) -> (u64, buffer<bytes, 6>)
public ResultCode Read(ServiceCtx context)
{
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
long offset = context.RequestData.ReadInt64();
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _base.Get.Read(out long bytesRead, offset, region.Memory.Span);
context.ResponseData.Write(bytesRead);
return (ResultCode)result.Value;
}
}
[CommandCmif(2)]
// GetSize() -> u64
public ResultCode GetSize(ServiceCtx context)
{
Result result = _base.Get.GetSize(out long size);
context.ResponseData.Write(size);
return (ResultCode)result.Value;
}
[CommandCmif(3)]
// GetDigest() -> nn::bcat::Digest
public ResultCode GetDigest(ServiceCtx context)
{
Result result = _base.Get.GetDigest(out Digest digest);
context.ResponseData.WriteStruct(digest);
return (ResultCode)result.Value;
}
}
}

View File

@@ -1,63 +0,0 @@
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator.Types;
using Ryujinx.Horizon.Common;
using System;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
class IDeliveryCacheProgressService : IpcService
{
private KEvent _event;
private int _eventHandle;
public IDeliveryCacheProgressService(ServiceCtx context)
{
_event = new KEvent(context.Device.System.KernelContext);
}
[CommandCmif(0)]
// GetEvent() -> handle<copy>
public ResultCode GetEvent(ServiceCtx context)
{
if (_eventHandle == 0)
{
if (context.Process.HandleTable.GenerateHandle(_event.ReadableEvent, out _eventHandle) != Result.Success)
{
throw new InvalidOperationException("Out of handles!");
}
}
context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_eventHandle);
Logger.Stub?.PrintStub(LogClass.ServiceBcat);
return ResultCode.Success;
}
[CommandCmif(1)]
// GetImpl() -> buffer<nn::bcat::detail::DeliveryCacheProgressImpl, 0x1a>
public ResultCode GetImpl(ServiceCtx context)
{
DeliveryCacheProgressImpl deliveryCacheProgress = new DeliveryCacheProgressImpl
{
State = DeliveryCacheProgressImpl.Status.Done,
Result = 0
};
ulong dcpSize = WriteDeliveryCacheProgressImpl(context, context.Request.RecvListBuff[0], deliveryCacheProgress);
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(dcpSize);
Logger.Stub?.PrintStub(LogClass.ServiceBcat);
return ResultCode.Success;
}
private ulong WriteDeliveryCacheProgressImpl(ServiceCtx context, IpcRecvListBuffDesc ipcDesc, DeliveryCacheProgressImpl deliveryCacheProgress)
{
return MemoryHelper.Write(context.Memory, ipcDesc.Position, deliveryCacheProgress);
}
}
}

View File

@@ -1,74 +0,0 @@
using LibHac;
using LibHac.Bcat;
using LibHac.Common;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator
{
class IDeliveryCacheStorageService : DisposableIpcService
{
private SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService> _base;
public IDeliveryCacheStorageService(ServiceCtx context, ref SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService> baseService)
{
_base = SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService>.CreateMove(ref baseService);
}
[CommandCmif(0)]
// CreateFileService() -> object<nn::bcat::detail::ipc::IDeliveryCacheFileService>
public ResultCode CreateFileService(ServiceCtx context)
{
using var service = new SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService>();
Result result = _base.Get.CreateFileService(ref service.Ref);
if (result.IsSuccess())
{
MakeObject(context, new IDeliveryCacheFileService(ref service.Ref));
}
return (ResultCode)result.Value;
}
[CommandCmif(1)]
// CreateDirectoryService() -> object<nn::bcat::detail::ipc::IDeliveryCacheDirectoryService>
public ResultCode CreateDirectoryService(ServiceCtx context)
{
using var service = new SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService>();
Result result = _base.Get.CreateDirectoryService(ref service.Ref);
if (result.IsSuccess())
{
MakeObject(context, new IDeliveryCacheDirectoryService(ref service.Ref));
}
return (ResultCode)result.Value;
}
[CommandCmif(10)]
// EnumerateDeliveryCacheDirectory() -> (u32, buffer<nn::bcat::DirectoryName, 6>)
public ResultCode EnumerateDeliveryCacheDirectory(ServiceCtx context)
{
ulong bufferAddress = context.Request.ReceiveBuff[0].Position;
ulong bufferLen = context.Request.ReceiveBuff[0].Size;
using (var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true))
{
Result result = _base.Get.EnumerateDeliveryCacheDirectory(out int count, MemoryMarshal.Cast<byte, DirectoryName>(region.Memory.Span));
context.ResponseData.Write(count);
return (ResultCode)result.Value;
}
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
_base.Destroy();
}
}
}
}

View File

@@ -145,7 +145,7 @@ namespace Ryujinx.Horizon.Generators.Hipc
if (bufferFixedSize != null)
{
arg = $"new CommandArg({bufferFlags}, {bufferFixedSize})";
arg = $"new CommandArg({bufferFlags} | HipcBufferFlags.FixedSize, {bufferFixedSize})";
}
else
{

View File

@@ -0,0 +1,48 @@
using Ryujinx.Horizon.Bcat.Ipc;
using Ryujinx.Horizon.Bcat.Types;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using Ryujinx.Horizon.Sdk.Sm;
namespace Ryujinx.Horizon.Bcat
{
internal class BcatIpcServer
{
private const int BcatMaxSessionsCount = 8;
private const int BcatTotalMaxSessionsCount = BcatMaxSessionsCount * 4;
private const int PointerBufferSize = 0x400;
private const int MaxDomains = 64;
private const int MaxDomainObjects = 64;
private const int MaxPortsCount = 4;
private SmApi _sm;
private BcatServerManager _serverManager;
private static readonly ManagerOptions _bcatManagerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
internal void Initialize()
{
HeapAllocator allocator = new();
_sm = new SmApi();
_sm.Initialize().AbortOnFailure();
_serverManager = new BcatServerManager(allocator, _sm, MaxPortsCount, _bcatManagerOptions, BcatTotalMaxSessionsCount);
_serverManager.RegisterServer((int)BcatPortIndex.Admin, ServiceName.Encode("bcat:a"), BcatMaxSessionsCount);
_serverManager.RegisterServer((int)BcatPortIndex.Manager, ServiceName.Encode("bcat:m"), BcatMaxSessionsCount);
_serverManager.RegisterServer((int)BcatPortIndex.User, ServiceName.Encode("bcat:u"), BcatMaxSessionsCount);
_serverManager.RegisterServer((int)BcatPortIndex.System, ServiceName.Encode("bcat:s"), BcatMaxSessionsCount);
}
public void ServiceRequests()
{
_serverManager.ServiceRequests();
}
public void Shutdown()
{
_serverManager.Dispose();
}
}
}

View File

@@ -0,0 +1,24 @@
using Ryujinx.Horizon.LogManager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ryujinx.Horizon.Bcat
{
internal class BcatMain : IService
{
public static void Main(ServiceTable serviceTable)
{
BcatIpcServer ipcServer = new();
ipcServer.Initialize();
serviceTable.SignalServiceReady();
ipcServer.ServiceRequests();
ipcServer.Shutdown();
}
}
}

View File

@@ -0,0 +1,29 @@
using Ryujinx.Horizon.Common;
namespace Ryujinx.Horizon.Bcat
{
class BcatResult
{
private const int ModuleId = 122;
public static Result Success => new(ModuleId, 0);
public static Result InvalidArgument => new(ModuleId, 1);
public static Result NotFound => new(ModuleId, 2);
public static Result TargetLocked => new(ModuleId, 3);
public static Result TargetAlreadyMounted => new(ModuleId, 4);
public static Result TargetNotMounted => new(ModuleId, 5);
public static Result AlreadyOpen => new(ModuleId, 6);
public static Result NotOpen => new(ModuleId, 7);
public static Result InternetRequestDenied => new(ModuleId, 8);
public static Result ServiceOpenLimitReached => new(ModuleId, 9);
public static Result SaveDataNotFound => new(ModuleId, 10);
public static Result NetworkServiceAccountNotAvailable => new(ModuleId, 31);
public static Result PassphrasePathNotFound => new(ModuleId, 80);
public static Result DataVerificationFailed => new(ModuleId, 81);
public static Result PermissionDenied => new(ModuleId, 90);
public static Result AllocationFailed => new(ModuleId, 91);
public static Result InvalidOperation => new(ModuleId, 98);
public static Result InvalidDeliveryCacheStorageFile => new(ModuleId, 204);
public static Result StorageOpenLimitReached => new(ModuleId, 205);
}
}

View File

@@ -0,0 +1,28 @@
using Ryujinx.Horizon.Bcat.Ipc;
using Ryujinx.Horizon.Bcat.Types;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using Ryujinx.Horizon.Sdk.Sm;
using System;
namespace Ryujinx.Horizon.Bcat
{
class BcatServerManager : ServerManager
{
public BcatServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions)
{
}
protected override Result OnNeedsToAccept(int portIndex, Server server)
{
return (BcatPortIndex)portIndex switch
{
BcatPortIndex.Admin => AcceptImpl(server, new ServiceCreator("bcat:a", BcatServicePermissionLevel.Admin)),
BcatPortIndex.Manager => AcceptImpl(server, new ServiceCreator("bcat:m", BcatServicePermissionLevel.Manager)),
BcatPortIndex.User => AcceptImpl(server, new ServiceCreator("bcat:u", BcatServicePermissionLevel.User)),
BcatPortIndex.System => AcceptImpl(server, new ServiceCreator("bcat:s", BcatServicePermissionLevel.System)),
_ => throw new ArgumentOutOfRangeException(nameof(portIndex)),
};
}
}
}

View File

@@ -0,0 +1,85 @@
using LibHac.Common;
using Ryujinx.Horizon.Bcat.Types;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Bcat;
using Ryujinx.Horizon.Sdk.Sf;
using System;
using System.Threading;
using ApplicationId = Ryujinx.Horizon.Sdk.Ncm.ApplicationId;
namespace Ryujinx.Horizon.Bcat.Ipc
{
partial class ServiceCreator : IServiceCreator, IDisposable
{
private readonly BcatServicePermissionLevel _permissionLevel;
private SharedRef<LibHac.Bcat.Impl.Ipc.IServiceCreator> _libHacService;
private int _disposalState;
public ServiceCreator(string serviceName, BcatServicePermissionLevel permissionLevel)
{
HorizonStatic.Options.BcatClient.Sm.GetService(ref _libHacService, serviceName).ThrowIfFailure();
_permissionLevel = permissionLevel;
}
[CmifCommand(0)]
public Result CreateBcatService(out IBcatService bcatService, [ClientProcessId] ulong pid)
{
// TODO: Call arp:r GetApplicationLaunchProperty with the pid to get the TitleId.
// Add an instance of nn::bcat::detail::service::core::PassphraseManager.
// Add an instance of nn::bcat::detail::service::ServiceMemoryManager.
// Add an instance of nn::bcat::detail::service::core::TaskManager who loads "bcat-sys:/" system save data and opens "dc/task.bin".
// If the file don't exist, create a new one (with a size of 0x800 bytes) and write 2 empty structs with a size of 0x400 bytes.
bcatService = new BcatService(_permissionLevel);
return Result.Success;
}
[CmifCommand(1)]
public Result CreateDeliveryCacheStorageService(out IDeliveryCacheStorageService service, [ClientProcessId] ulong pid)
{
using var libHacService = new SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService>();
var resultCode = _libHacService.Get.CreateDeliveryCacheStorageService(ref libHacService.Ref, pid);
if (resultCode.IsSuccess())
{
service = new DeliveryCacheStorageService(ref libHacService.Ref);
}
else
{
service = null;
}
return resultCode.ToHorizonResult();
}
[CmifCommand(2)]
public Result CreateDeliveryCacheStorageServiceWithApplicationId(out IDeliveryCacheStorageService service, ApplicationId applicationId)
{
using var libHacService = new SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService>();
var resultCode = _libHacService.Get.CreateDeliveryCacheStorageServiceWithApplicationId(ref libHacService.Ref, new LibHac.ApplicationId(applicationId.Id));
if (resultCode.IsSuccess())
{
service = new DeliveryCacheStorageService(ref libHacService.Ref);
}
else
{
service = null;
}
return resultCode.ToHorizonResult();
}
public void Dispose()
{
if (Interlocked.Exchange(ref _disposalState, 1) == 0)
{
_libHacService.Destroy();
}
}
}
}

View File

@@ -0,0 +1,25 @@
using Ryujinx.Horizon.Bcat.Types;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Bcat;
using Ryujinx.Horizon.Sdk.Sf;
namespace Ryujinx.Horizon.Bcat.Ipc
{
partial class BcatService : IBcatService
{
private readonly BcatServicePermissionLevel _permissionLevel;
public BcatService(BcatServicePermissionLevel permissionLevel)
{
_permissionLevel = permissionLevel;
}
[CmifCommand(10100)]
public Result RequestSyncDeliveryCache(out IDeliveryCacheProgressService deliveryCacheProgressService)
{
deliveryCacheProgressService = new DeliveryCacheProgressService();
return Result.Success;
}
}
}

View File

@@ -0,0 +1,48 @@
using LibHac.Bcat;
using LibHac.Common;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Bcat;
using Ryujinx.Horizon.Sdk.Sf;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using System;
using System.Threading;
namespace Ryujinx.Horizon.Bcat.Ipc
{
partial class DeliveryCacheDirectoryService : IDeliveryCacheDirectoryService, IDisposable
{
private SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService> _libHacService;
private int _disposalState;
public DeliveryCacheDirectoryService(ref SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService> libHacService)
{
_libHacService = SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService>.CreateMove(ref libHacService);
}
[CmifCommand(0)]
public Result Open(DirectoryName directoryName)
{
return _libHacService.Get.Open(ref directoryName).ToHorizonResult();
}
[CmifCommand(1)]
public Result Read(out int entriesRead, [Buffer(Sdk.Sf.Hipc.HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<DeliveryCacheDirectoryEntry> entriesBuffer)
{
return _libHacService.Get.Read(out entriesRead, entriesBuffer).ToHorizonResult();
}
[CmifCommand(2)]
public Result GetCount(out int count)
{
return _libHacService.Get.GetCount(out count).ToHorizonResult();
}
public void Dispose()
{
if (Interlocked.Exchange(ref _disposalState, 1) == 0)
{
_libHacService.Destroy();
}
}
}
}

View File

@@ -0,0 +1,54 @@
using LibHac.Bcat;
using LibHac.Common;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Bcat;
using Ryujinx.Horizon.Sdk.Sf;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using System;
using System.Threading;
namespace Ryujinx.Horizon.Bcat.Ipc
{
partial class DeliveryCacheFileService : IDeliveryCacheFileService, IDisposable
{
private SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService> _libHacService;
private int _disposalState;
public DeliveryCacheFileService(ref SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService> libHacService)
{
_libHacService = SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService>.CreateMove(ref libHacService);
}
[CmifCommand(0)]
public Result Open(DirectoryName directoryName, FileName fileName)
{
return _libHacService.Get.Open(ref directoryName, ref fileName).ToHorizonResult();
}
[CmifCommand(1)]
public Result Read(long offset, out long bytesRead, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<byte> data)
{
return _libHacService.Get.Read(out bytesRead, offset, data).ToHorizonResult();
}
[CmifCommand(2)]
public Result GetSize(out long size)
{
return _libHacService.Get.GetSize(out size).ToHorizonResult();
}
[CmifCommand(3)]
public Result GetDigest(out Digest digest)
{
return _libHacService.Get.GetDigest(out digest).ToHorizonResult();
}
public void Dispose()
{
if (Interlocked.Exchange(ref _disposalState, 1) == 0)
{
_libHacService.Destroy();
}
}
}
}

View File

@@ -0,0 +1,58 @@
using Ryujinx.Common.Logging;
using Ryujinx.Horizon.Bcat.Ipc.Types;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Bcat;
using Ryujinx.Horizon.Sdk.OsTypes;
using Ryujinx.Horizon.Sdk.Sf;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using System;
using System.Threading;
namespace Ryujinx.Horizon.Bcat.Ipc
{
partial class DeliveryCacheProgressService : IDeliveryCacheProgressService, IDisposable
{
private int _handle;
private SystemEventType _systemEvent;
private int _disposalState;
[CmifCommand(0)]
public Result GetEvent([CopyHandle] out int handle)
{
if (_handle == 0)
{
Os.CreateSystemEvent(out _systemEvent, EventClearMode.ManualClear, true).AbortOnFailure();
_handle = Os.GetReadableHandleOfSystemEvent(ref _systemEvent);
}
handle = _handle;
Logger.Stub?.PrintStub(LogClass.ServiceBcat);
return Result.Success;
}
[CmifCommand(1)]
public Result GetImpl([Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x200)] out DeliveryCacheProgressImpl deliveryCacheProgressImpl)
{
deliveryCacheProgressImpl = new DeliveryCacheProgressImpl
{
State = DeliveryCacheProgressImpl.Status.Done,
Result = 0
};
Logger.Stub?.PrintStub(LogClass.ServiceBcat);
return Result.Success;
}
public void Dispose()
{
if (_handle != 0 && Interlocked.Exchange(ref _disposalState, 1) == 0)
{
Os.DestroySystemEvent(ref _systemEvent);
}
}
}
}

View File

@@ -0,0 +1,74 @@
using LibHac.Bcat;
using LibHac.Common;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Bcat;
using Ryujinx.Horizon.Sdk.Sf;
using Ryujinx.Horizon.Sdk.Sf.Hipc;
using System;
using System.Threading;
namespace Ryujinx.Horizon.Bcat.Ipc
{
partial class DeliveryCacheStorageService : IDeliveryCacheStorageService, IDisposable
{
private SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService> _libHacService;
private int _disposalState;
public DeliveryCacheStorageService(ref SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService> libHacService)
{
_libHacService = SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheStorageService>.CreateMove(ref libHacService);
}
[CmifCommand(0)]
public Result CreateFileService(out IDeliveryCacheFileService service)
{
using var libHacService = new SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheFileService>();
var resultCode = _libHacService.Get.CreateFileService(ref libHacService.Ref);
if (resultCode.IsSuccess())
{
service = new DeliveryCacheFileService(ref libHacService.Ref);
}
else
{
service = null;
}
return resultCode.ToHorizonResult();
}
[CmifCommand(1)]
public Result CreateDirectoryService(out IDeliveryCacheDirectoryService service)
{
using var libHacService = new SharedRef<LibHac.Bcat.Impl.Ipc.IDeliveryCacheDirectoryService>();
var resultCode = _libHacService.Get.CreateDirectoryService(ref libHacService.Ref);
if (resultCode.IsSuccess())
{
service = new DeliveryCacheDirectoryService(ref libHacService.Ref);
}
else
{
service = null;
}
return resultCode.ToHorizonResult();
}
[CmifCommand(10)]
public Result EnumerateDeliveryCacheDirectory(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<DirectoryName> directoryNames)
{
return _libHacService.Get.EnumerateDeliveryCacheDirectory(out count, directoryNames).ToHorizonResult();
}
public void Dispose()
{
if (Interlocked.Exchange(ref _disposalState, 1) == 0)
{
_libHacService.Destroy();
}
}
}
}

View File

@@ -1,6 +1,6 @@
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Bcat.ServiceCreator.Types
namespace Ryujinx.Horizon.Bcat.Ipc.Types
{
[StructLayout(LayoutKind.Sequential, Size = 0x200)]
public struct DeliveryCacheProgressImpl

View File

@@ -0,0 +1,10 @@
namespace Ryujinx.Horizon.Bcat.Types
{
enum BcatPortIndex
{
Admin,
Manager,
User,
System
}
}

View File

@@ -0,0 +1,10 @@
namespace Ryujinx.Horizon.Bcat.Types
{
enum BcatServicePermissionLevel
{
Admin = -1,
User = 1,
System = 2,
Manager = 6
}
}

View File

@@ -1,3 +1,5 @@
using LibHac;
namespace Ryujinx.Horizon
{
public struct HorizonOptions
@@ -5,10 +7,13 @@ namespace Ryujinx.Horizon
public bool IgnoreMissingServices { get; }
public bool ThrowOnInvalidCommandIds { get; }
public HorizonOptions(bool ignoreMissingServices)
public HorizonClient BcatClient { get; }
public HorizonOptions(bool ignoreMissingServices, HorizonClient bcatClient)
{
IgnoreMissingServices = ignoreMissingServices;
ThrowOnInvalidCommandIds = true;
BcatClient = bcatClient;
}
}
}

View File

@@ -0,0 +1,12 @@
using Ryujinx.Horizon.Common;
namespace Ryujinx.Horizon
{
internal static class LibHacResultExtensions
{
public static Result ToHorizonResult(this LibHac.Result result)
{
return new Result((int)result.Module, (int)result.Description);
}
}
}

View File

@@ -9,12 +9,12 @@ namespace Ryujinx.Horizon.Prepo
private const int PrepoMaxSessionsCount = 12;
private const int PrepoTotalMaxSessionsCount = PrepoMaxSessionsCount * 6;
private const int PointerBufferSize = 0x3800;
private const int PointerBufferSize = 0x80;
private const int MaxDomains = 64;
private const int MaxDomainObjects = 16;
private const int MaxPortsCount = 6;
private static readonly ManagerOptions _logManagerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
private static readonly ManagerOptions _prepoManagerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
private SmApi _sm;
private PrepoServerManager _serverManager;
@@ -26,7 +26,7 @@ namespace Ryujinx.Horizon.Prepo
_sm = new SmApi();
_sm.Initialize().AbortOnFailure();
_serverManager = new PrepoServerManager(allocator, _sm, MaxPortsCount, _logManagerOptions, PrepoTotalMaxSessionsCount);
_serverManager = new PrepoServerManager(allocator, _sm, MaxPortsCount, _prepoManagerOptions, PrepoTotalMaxSessionsCount);
_serverManager.RegisterServer((int)PrepoPortIndex.Admin, ServiceName.Encode("prepo:a"), PrepoMaxSessionsCount); // 1.0.0-5.1.0
_serverManager.RegisterServer((int)PrepoPortIndex.Admin2, ServiceName.Encode("prepo:a2"), PrepoMaxSessionsCount); // 6.0.0+

View File

@@ -0,0 +1,10 @@
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf;
namespace Ryujinx.Horizon.Sdk.Bcat
{
internal interface IBcatService : IServiceObject
{
Result RequestSyncDeliveryCache(out IDeliveryCacheProgressService deliveryCacheProgressService);
}
}

View File

@@ -0,0 +1,14 @@
using LibHac.Bcat;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf;
using System;
namespace Ryujinx.Horizon.Sdk.Bcat
{
internal interface IDeliveryCacheDirectoryService : IServiceObject
{
Result GetCount(out int count);
Result Open(DirectoryName directoryName);
Result Read(out int entriesRead, Span<DeliveryCacheDirectoryEntry> entriesBuffer);
}
}

View File

@@ -0,0 +1,15 @@
using LibHac.Bcat;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf;
using System;
namespace Ryujinx.Horizon.Sdk.Bcat
{
internal interface IDeliveryCacheFileService : IServiceObject
{
Result GetDigest(out Digest digest);
Result GetSize(out long size);
Result Open(DirectoryName directoryName, FileName fileName);
Result Read(long offset, out long bytesRead, Span<byte> data);
}
}

View File

@@ -0,0 +1,12 @@
using Ryujinx.Horizon.Bcat.Ipc.Types;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf;
namespace Ryujinx.Horizon.Sdk.Bcat
{
internal interface IDeliveryCacheProgressService : IServiceObject
{
Result GetEvent(out int handle);
Result GetImpl(out DeliveryCacheProgressImpl deliveryCacheProgressImpl);
}
}

View File

@@ -0,0 +1,14 @@
using LibHac.Bcat;
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf;
using System;
namespace Ryujinx.Horizon.Sdk.Bcat
{
internal interface IDeliveryCacheStorageService : IServiceObject
{
Result CreateDirectoryService(out IDeliveryCacheDirectoryService service);
Result CreateFileService(out IDeliveryCacheFileService service);
Result EnumerateDeliveryCacheDirectory(out int count, Span<DirectoryName> directoryNames);
}
}

View File

@@ -0,0 +1,12 @@
using Ryujinx.Horizon.Common;
using Ryujinx.Horizon.Sdk.Sf;
namespace Ryujinx.Horizon.Sdk.Bcat
{
internal interface IServiceCreator : IServiceObject
{
Result CreateBcatService(out IBcatService service, ulong pid);
Result CreateDeliveryCacheStorageService(out IDeliveryCacheStorageService service, ulong pid);
Result CreateDeliveryCacheStorageServiceWithApplicationId(out IDeliveryCacheStorageService service, Ncm.ApplicationId applicationId);
}
}

View File

@@ -165,6 +165,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
entry.Owner = null;
obj = entry.Obj;
if (obj.ServiceObject is IDisposable disposableObj)
{
disposableObj.Dispose();
}
entry.Obj = null;
_entries.Remove(entry.Node);
entry.Node = null;

View File

@@ -1,3 +1,4 @@
using Ryujinx.Horizon.Bcat;
using Ryujinx.Horizon.LogManager;
using Ryujinx.Horizon.Prepo;
using System.Collections.Generic;
@@ -23,6 +24,7 @@ namespace Ryujinx.Horizon
RegisterService<LmMain>();
RegisterService<PrepoMain>();
RegisterService<BcatMain>();
_totalServices = entries.Count;

View File

@@ -63,6 +63,7 @@ namespace Ryujinx.SDL2.Common
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
// NOTE: As of SDL2 2.24.0, joycons are combined by default but the motion source only come from one of them.

View File

@@ -180,7 +180,7 @@ namespace Ryujinx.Ui.Windows
if (response.IsSuccessStatusCode)
{
return response.Content.Headers.LastModified != oldLastModified;
return response.Content.Headers.LastModified != new DateTimeOffset(oldLastModified.Ticks - (oldLastModified.Ticks % TimeSpan.TicksPerSecond), TimeSpan.Zero);
}
return false;