Compare commits

...

6 Commits

Author SHA1 Message Date
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
38 changed files with 872 additions and 522 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,9 +43,166 @@ 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
with:
ryujinx_version: "1.1.${{ github.run_number }}"
secrets: inherit
secrets: inherit

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

@@ -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;