Compare commits
45 Commits
Canary-1.2
...
8efefeaaca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8efefeaaca | ||
|
|
4e56b1493f | ||
|
|
43f6e4a873 | ||
|
|
55f6b95d8d | ||
|
|
4b84c5d240 | ||
|
|
9f22fc49c8 | ||
|
|
4f206d0e73 | ||
|
|
e2e8502278 | ||
|
|
aa806b1032 | ||
|
|
aabb786016 | ||
|
|
2a38f1bbbf | ||
|
|
fdece62f88 | ||
|
|
6fb58a611e | ||
|
|
02ff76f89a | ||
|
|
d39b3a5864 | ||
|
|
f976c3c362 | ||
|
|
d9f2b813a0 | ||
|
|
8cb6767c7c | ||
|
|
80377c1553 | ||
|
|
1dbcaf1fd7 | ||
|
|
bad1f72918 | ||
|
|
a317184594 | ||
|
|
0cde245875 | ||
|
|
e3638d13b1 | ||
|
|
2fe19044cf | ||
|
|
9320decc45 | ||
|
|
35b23bcafb | ||
|
|
4add4829c7 | ||
|
|
eb46909808 | ||
|
|
c91d9d8049 | ||
|
|
21f23f0a2e | ||
|
|
9ca0926439 | ||
|
|
7b8c8776a2 | ||
|
|
b00d80c17a | ||
|
|
8c0a82bb6e | ||
|
|
1bac6ab19e | ||
|
|
dac137fd43 | ||
|
|
d83d80de73 | ||
|
|
097836bfac | ||
|
|
695f9e277d | ||
|
|
b19ee23c6b | ||
|
|
748e93ba65 | ||
|
|
732a1af863 | ||
|
|
f538cee2e8 | ||
|
|
4275a778aa |
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@@ -64,9 +64,14 @@ jobs:
|
|||||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -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
|
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -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
|
||||||
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||||
|
|
||||||
|
- name: Publish Ryujinx.Headless.SDL2
|
||||||
|
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -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
|
||||||
|
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||||
|
|
||||||
- name: Set executable bit
|
- name: Set executable bit
|
||||||
run: |
|
run: |
|
||||||
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
|
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
|
||||||
|
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
|
||||||
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
|
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
|
||||||
|
|
||||||
- name: Build AppImage
|
- name: Build AppImage
|
||||||
@@ -114,6 +119,13 @@ jobs:
|
|||||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}-AppImage
|
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}-AppImage
|
||||||
path: publish_appimage
|
path: publish_appimage
|
||||||
|
|
||||||
|
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
|
||||||
|
path: publish_sdl2_headless
|
||||||
|
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||||
|
|
||||||
build_macos:
|
build_macos:
|
||||||
name: macOS Universal (${{ matrix.configuration }})
|
name: macOS Universal (${{ matrix.configuration }})
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -159,9 +171,20 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||||
|
|
||||||
|
- name: Publish macOS Ryujinx.Headless.SDL2
|
||||||
|
run: |
|
||||||
|
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
|
||||||
|
|
||||||
- name: Upload Ryujinx artifact
|
- name: Upload Ryujinx artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||||
path: "publish/*.tar.gz"
|
path: "publish/*.tar.gz"
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
|
|
||||||
|
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
|
||||||
|
path: "publish_headless/*.tar.gz"
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
|||||||
20
.github/workflows/canary.yml
vendored
20
.github/workflows/canary.yml
vendored
@@ -116,6 +116,7 @@ jobs:
|
|||||||
- name: Publish
|
- name: Publish
|
||||||
run: |
|
run: |
|
||||||
dotnet publish -c Release -r "${{ matrix.platform.name }}" -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 --self-contained
|
dotnet publish -c Release -r "${{ matrix.platform.name }}" -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 --self-contained
|
||||||
|
dotnet publish -c Release -r "${{ matrix.platform.name }}" -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
|
||||||
|
|
||||||
- name: Packing Windows builds
|
- name: Packing Windows builds
|
||||||
if: matrix.platform.os == 'windows-latest'
|
if: matrix.platform.os == 'windows-latest'
|
||||||
@@ -124,6 +125,11 @@ jobs:
|
|||||||
rm publish/libarmeilleure-jitsupport.dylib
|
rm publish/libarmeilleure-jitsupport.dylib
|
||||||
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
pushd publish_sdl2_headless
|
||||||
|
rm publish/libarmeilleure-jitsupport.dylib
|
||||||
|
7z a ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||||
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Packing Linux builds
|
- name: Packing Linux builds
|
||||||
@@ -134,6 +140,12 @@ jobs:
|
|||||||
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
||||||
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
pushd publish_sdl2_headless
|
||||||
|
rm publish/libarmeilleure-jitsupport.dylib
|
||||||
|
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
|
||||||
|
tar -czvf ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||||
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
#- name: Build AppImage (Linux)
|
#- name: Build AppImage (Linux)
|
||||||
@@ -179,7 +191,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: ${{ steps.version_info.outputs.build_version }}
|
name: ${{ steps.version_info.outputs.build_version }}
|
||||||
artifacts: "release_output/*.tar.gz,release_output/*.zip"
|
artifacts: "release_output/*.tar.gz,release_output/*.zip"
|
||||||
#artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
|
#artifacts: "release_output/*.tar.gz,release_output/*.zip/*AppImage*"
|
||||||
tag: ${{ steps.version_info.outputs.build_version }}
|
tag: ${{ steps.version_info.outputs.build_version }}
|
||||||
body: |
|
body: |
|
||||||
# Canary builds:
|
# Canary builds:
|
||||||
@@ -250,11 +262,15 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
|
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
|
||||||
|
|
||||||
|
- name: Publish macOS Ryujinx.Headless.SDL2
|
||||||
|
run: |
|
||||||
|
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
|
||||||
|
|
||||||
- name: Pushing new release
|
- name: Pushing new release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
||||||
artifacts: "publish_ava/*.tar.gz"
|
artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz"
|
||||||
tag: ${{ steps.version_info.outputs.build_version }}
|
tag: ${{ steps.version_info.outputs.build_version }}
|
||||||
body: ""
|
body: ""
|
||||||
omitBodyDuringUpdate: true
|
omitBodyDuringUpdate: true
|
||||||
|
|||||||
10
.github/workflows/nightly_pr_comment.yml
vendored
10
.github/workflows/nightly_pr_comment.yml
vendored
@@ -38,16 +38,20 @@ jobs:
|
|||||||
return core.error(`No artifacts found`);
|
return core.error(`No artifacts found`);
|
||||||
}
|
}
|
||||||
let body = `Download the artifacts for this pull request:\n`;
|
let body = `Download the artifacts for this pull request:\n`;
|
||||||
|
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less</summary>\n`;
|
||||||
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
||||||
for (const art of artifacts) {
|
for (const art of artifacts) {
|
||||||
const url = `https://github.com/Ryubing/Ryujinx/actions/runs/${run_id}/artifacts/${art.id}`;
|
|
||||||
if(art.name.includes('Debug')) {
|
if(art.name.includes('Debug')) {
|
||||||
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
|
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
|
} else if(art.name.includes('nogui-ryujinx')) {
|
||||||
|
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
} else {
|
} else {
|
||||||
body += `\n* [${art.name}](${url})`;
|
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hidden_headless_artifacts += `\n</details>`;
|
||||||
hidden_debug_artifacts += `\n</details>`;
|
hidden_debug_artifacts += `\n</details>`;
|
||||||
|
body += hidden_headless_artifacts;
|
||||||
body += hidden_debug_artifacts;
|
body += hidden_debug_artifacts;
|
||||||
|
|
||||||
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});
|
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});
|
||||||
|
|||||||
17
.github/workflows/release.yml
vendored
17
.github/workflows/release.yml
vendored
@@ -112,6 +112,7 @@ jobs:
|
|||||||
- name: Publish
|
- name: Publish
|
||||||
run: |
|
run: |
|
||||||
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./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
|
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./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
|
||||||
|
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -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
|
||||||
|
|
||||||
- name: Packing Windows builds
|
- name: Packing Windows builds
|
||||||
if: matrix.platform.os == 'windows-latest'
|
if: matrix.platform.os == 'windows-latest'
|
||||||
@@ -120,6 +121,11 @@ jobs:
|
|||||||
rm libarmeilleure-jitsupport.dylib
|
rm libarmeilleure-jitsupport.dylib
|
||||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
pushd publish_sdl2_headless
|
||||||
|
rm libarmeilleure-jitsupport.dylib
|
||||||
|
7z a ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||||
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Build AppImage (Linux)
|
- name: Build AppImage (Linux)
|
||||||
@@ -166,6 +172,11 @@ jobs:
|
|||||||
chmod +x Ryujinx.sh Ryujinx
|
chmod +x Ryujinx.sh Ryujinx
|
||||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
pushd publish_sdl2_headless
|
||||||
|
chmod +x Ryujinx.sh Ryujinx.Headless.SDL2
|
||||||
|
tar -czvf ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||||
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Pushing new release
|
- name: Pushing new release
|
||||||
@@ -240,11 +251,15 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
|
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
|
||||||
|
|
||||||
|
- name: Publish macOS Ryujinx.Headless.SDL2
|
||||||
|
run: |
|
||||||
|
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
|
||||||
|
|
||||||
- name: Pushing new release
|
- name: Pushing new release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
name: ${{ steps.version_info.outputs.build_version }}
|
name: ${{ steps.version_info.outputs.build_version }}
|
||||||
artifacts: "publish/*.tar.gz"
|
artifacts: "publish/*.tar.gz, publish_headless/*.tar.gz"
|
||||||
tag: ${{ steps.version_info.outputs.build_version }}
|
tag: ${{ steps.version_info.outputs.build_version }}
|
||||||
body: ""
|
body: ""
|
||||||
omitBodyDuringUpdate: true
|
omitBodyDuringUpdate: true
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
<PackageVersion Include="Gommon" Version="2.6.8" />
|
<PackageVersion Include="Gommon" Version="2.6.8" />
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpMetal" Version="1.0.0-preview21" />
|
<PackageVersion Include="SharpMetal" Version="1.0.0-preview20" />
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
|
||||||
|
|||||||
11
Ryujinx.sln
11
Ryujinx.sln
@@ -57,6 +57,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "src\Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}"
|
||||||
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
||||||
@@ -211,6 +213,10 @@ Global
|
|||||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@@ -255,13 +261,12 @@ Global
|
|||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
|
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.Build.Utilities;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.IO;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Microsoft.Build.Framework;
|
|
||||||
|
|
||||||
namespace Ryujinx.BuildValidationTasks
|
|
||||||
{
|
|
||||||
public class LocaleValidationTask : Task
|
|
||||||
{
|
|
||||||
public override bool Execute()
|
|
||||||
{
|
|
||||||
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
|
||||||
|
|
||||||
if (path.Split(["src"], StringSplitOptions.None).Length == 1)
|
|
||||||
{
|
|
||||||
//i assume that we are in a build directory in the solution dir
|
|
||||||
path = new FileInfo(path).Directory!.Parent!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
path = path.Split(["src"], StringSplitOptions.None)[0];
|
|
||||||
path = new FileInfo(path).Directory!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
string data;
|
|
||||||
|
|
||||||
using (StreamReader sr = new(path))
|
|
||||||
{
|
|
||||||
data = sr.ReadToEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalesJson json = JsonConvert.DeserializeObject<LocalesJson>(data);
|
|
||||||
|
|
||||||
for (int i = 0; i < json.Locales.Count; i++)
|
|
||||||
{
|
|
||||||
LocalesEntry locale = json.Locales[i];
|
|
||||||
|
|
||||||
foreach (string langCode in json.Languages.Where(it => !locale.Translations.ContainsKey(it)))
|
|
||||||
{
|
|
||||||
locale.Translations.Add(langCode, string.Empty);
|
|
||||||
Log.LogMessage(MessageImportance.High, $"Added '{langCode}' to Locale '{locale.ID}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
|
|
||||||
json.Locales[i] = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
string jsonString = JsonConvert.SerializeObject(json, Formatting.Indented);
|
|
||||||
|
|
||||||
using (StreamWriter sw = new(path))
|
|
||||||
{
|
|
||||||
sw.Write(jsonString);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LocalesJson
|
|
||||||
{
|
|
||||||
public List<string> Languages { get; set; }
|
|
||||||
public List<LocalesEntry> Locales { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LocalesEntry
|
|
||||||
{
|
|
||||||
public string ID { get; set; }
|
|
||||||
public Dictionary<string, string> Translations { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
117
src/Ryujinx.BuildValidationTasks/LocalesValidationTask.cs
Normal file
117
src/Ryujinx.BuildValidationTasks/LocalesValidationTask.cs
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
|
||||||
|
namespace Ryujinx.BuildValidationTasks
|
||||||
|
{
|
||||||
|
public class LocalesValidationTask : ValidationTask
|
||||||
|
{
|
||||||
|
public LocalesValidationTask() { }
|
||||||
|
|
||||||
|
public bool Execute(string projectPath, bool isGitRunner)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Running Locale Validation Task...");
|
||||||
|
|
||||||
|
string path = projectPath + "src/Ryujinx/Assets/locales.json";
|
||||||
|
string data;
|
||||||
|
|
||||||
|
using (StreamReader sr = new(path))
|
||||||
|
{
|
||||||
|
data = sr.ReadToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalesJson json;
|
||||||
|
|
||||||
|
if (isGitRunner && data.Contains("\r\n"))
|
||||||
|
throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, build locally to fix...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
json = JsonSerializer.Deserialize<LocalesJson>(data);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (JsonException e)
|
||||||
|
{
|
||||||
|
throw new JsonException(e.Message); //shorter and easier stacktrace
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool encounteredIssue = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < json.Locales.Count; i++)
|
||||||
|
{
|
||||||
|
LocalesEntry locale = json.Locales[i];
|
||||||
|
|
||||||
|
foreach (string langCode in json.Languages.Where(lang => !locale.Translations.ContainsKey(lang)))
|
||||||
|
{
|
||||||
|
encounteredIssue = true;
|
||||||
|
|
||||||
|
if (!isGitRunner)
|
||||||
|
{
|
||||||
|
locale.Translations.Add(langCode, string.Empty);
|
||||||
|
Console.WriteLine($"Added '{langCode}' to Locale '{locale.ID}'");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Missing '{langCode}' in Locale '{locale.ID}'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string langCode in json.Languages.Where(lang => locale.Translations.ContainsKey(lang) && lang != "en_US" && locale.Translations[lang] == locale.Translations["en_US"]))
|
||||||
|
{
|
||||||
|
encounteredIssue = true;
|
||||||
|
|
||||||
|
if (!isGitRunner)
|
||||||
|
{
|
||||||
|
locale.Translations[langCode] = string.Empty;
|
||||||
|
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'! Resetting it...");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||||
|
json.Locales[i] = locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGitRunner && encounteredIssue)
|
||||||
|
throw new JsonException("1 or more locales are invalid!");
|
||||||
|
|
||||||
|
JsonSerializerOptions jsonOptions = new JsonSerializerOptions()
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
NewLine = "\n",
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
|
};
|
||||||
|
|
||||||
|
string jsonString = JsonSerializer.Serialize(json, jsonOptions);
|
||||||
|
|
||||||
|
using (StreamWriter sw = new(path))
|
||||||
|
{
|
||||||
|
sw.Write(jsonString);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Finished Locale Validation Task!");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LocalesJson
|
||||||
|
{
|
||||||
|
public List<string> Languages { get; set; }
|
||||||
|
public List<LocalesEntry> Locales { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LocalesEntry
|
||||||
|
{
|
||||||
|
public string ID { get; set; }
|
||||||
|
public Dictionary<string, string> Translations { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/Ryujinx.BuildValidationTasks/Program.cs
Normal file
40
src/Ryujinx.BuildValidationTasks/Program.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ryujinx.BuildValidationTasks
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
// Display the number of command line arguments.
|
||||||
|
if (args.Length == 0)
|
||||||
|
throw new ArgumentException("Error: too few arguments!");
|
||||||
|
|
||||||
|
string path = args[0];
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
throw new ArgumentException("Error: path is null or empty!");
|
||||||
|
|
||||||
|
if (!Path.Exists(path))
|
||||||
|
throw new FileLoadException($"path {{{path}}} does not exist!");
|
||||||
|
|
||||||
|
path = Path.GetFullPath(path);
|
||||||
|
|
||||||
|
if (!Directory.GetDirectories(path).Contains($"{path}src"))
|
||||||
|
throw new FileLoadException($"path {{{path}}} is not a valid ryujinx project!");
|
||||||
|
|
||||||
|
bool isGitRunner = path.Contains("runner") || path.Contains("D:\\a\\Ryujinx\\Ryujinx");
|
||||||
|
if (isGitRunner)
|
||||||
|
Console.WriteLine("Is Git Runner!");
|
||||||
|
|
||||||
|
// Run tasks
|
||||||
|
// Pass extra info needed in the task constructors
|
||||||
|
new LocalesValidationTask().Execute(path, isGitRunner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,16 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<OutputType>Exe</OutputType>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<Target Name="PostBuildTarget" AfterTargets="AfterBuild">
|
||||||
<PackageReference Include="Microsoft.Build.Utilities.Core" />
|
<Message Text="Running Validation Project" Importance="high" />
|
||||||
<PackageReference Include="Newtonsoft.Json" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<UsingTask TaskName="Ryujinx.BuildValidationTasks.LocaleValidationTask" TaskFactory="TaskHostFactory" AssemblyFile="$(OutDir)Ryujinx.BuildValidationTasks.dll" />
|
<Exec WorkingDirectory="$(ProjectDir)bin\Debug\$(TargetFramework)\"
|
||||||
|
Command="dotnet Ryujinx.BuildValidationTasks.dll "$(ProjectDir)..\..\\""
|
||||||
<Target Name="LocalesJsonValidation" AfterTargets="AfterRebuild">
|
ConsoleToMsBuild="true"
|
||||||
<LocaleValidationTask />
|
/>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
13
src/Ryujinx.BuildValidationTasks/ValidationTask.cs
Normal file
13
src/Ryujinx.BuildValidationTasks/ValidationTask.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ryujinx.BuildValidationTasks
|
||||||
|
{
|
||||||
|
public interface ValidationTask
|
||||||
|
{
|
||||||
|
public bool Execute(string projectPath, bool isGitRunner);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,8 +36,6 @@ namespace Ryujinx.Common.Configuration
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static float ToFloatY(this AspectRatio aspectRatio)
|
public static float ToFloatY(this AspectRatio aspectRatio)
|
||||||
{
|
{
|
||||||
return aspectRatio switch
|
return aspectRatio switch
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common.Configuration
|
|
||||||
{
|
|
||||||
[Flags]
|
|
||||||
public enum DirtyHacks
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Xc2MenuSoftlockFix = 1 << 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,5 @@ namespace Ryujinx.Common.Configuration
|
|||||||
Bilinear,
|
Bilinear,
|
||||||
Nearest,
|
Nearest,
|
||||||
Fsr,
|
Fsr,
|
||||||
Area,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@@ -159,15 +158,20 @@ namespace Ryujinx.Common.Logging
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static ILogTarget GetTarget(string targetName)
|
private static ILogTarget GetTarget(string targetName)
|
||||||
=> _logTargets.FirstOrDefault(target => target.Name.Equals(targetName));
|
{
|
||||||
|
foreach (var target in _logTargets)
|
||||||
|
{
|
||||||
|
if (target.Name.Equals(targetName))
|
||||||
|
{
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void AddTarget(ILogTarget target)
|
public static void AddTarget(ILogTarget target)
|
||||||
{
|
{
|
||||||
if (_logTargets.Any(t => t.Name == target.Name))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logTargets.Add(target);
|
_logTargets.Add(target);
|
||||||
|
|
||||||
Updated += target.Log;
|
Updated += target.Log;
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ namespace Ryujinx.Common.Logging.Targets
|
|||||||
|
|
||||||
private readonly int _overflowTimeout;
|
private readonly int _overflowTimeout;
|
||||||
|
|
||||||
string ILogTarget.Name => _target.Name;
|
string ILogTarget.Name { get => _target.Name; }
|
||||||
|
|
||||||
|
public AsyncLogTargetWrapper(ILogTarget target)
|
||||||
|
: this(target, -1)
|
||||||
|
{ }
|
||||||
|
|
||||||
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block)
|
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ namespace Ryujinx.Common
|
|||||||
{
|
{
|
||||||
public static class TitleIDs
|
public static class TitleIDs
|
||||||
{
|
{
|
||||||
public static Optional<string> CurrentApplication;
|
|
||||||
|
|
||||||
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
|
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
|
||||||
{
|
{
|
||||||
switch (currentBackend)
|
switch (currentBackend)
|
||||||
|
|||||||
12
src/Ryujinx.Graphics.GAL/AntiAliasing.cs
Normal file
12
src/Ryujinx.Graphics.GAL/AntiAliasing.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Ryujinx.Graphics.GAL
|
||||||
|
{
|
||||||
|
public enum AntiAliasing
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Fxaa,
|
||||||
|
SmaaLow,
|
||||||
|
SmaaMedium,
|
||||||
|
SmaaHigh,
|
||||||
|
SmaaUltra,
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/Ryujinx.Graphics.GAL/UpscaleType.cs
Normal file
10
src/Ryujinx.Graphics.GAL/UpscaleType.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Ryujinx.Graphics.GAL
|
||||||
|
{
|
||||||
|
public enum ScalingFilter
|
||||||
|
{
|
||||||
|
Bilinear,
|
||||||
|
Nearest,
|
||||||
|
Fsr,
|
||||||
|
Area,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,6 +47,12 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool EnableMacroHLE = true;
|
public static bool EnableMacroHLE = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Title id of the current running game.
|
||||||
|
/// Used by the shader cache.
|
||||||
|
/// </summary>
|
||||||
|
public static string TitleId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables the shader cache.
|
/// Enables or disables the shader cache.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
@@ -117,8 +116,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private static string GetDiskCachePath()
|
private static string GetDiskCachePath()
|
||||||
{
|
{
|
||||||
return GraphicsConfig.EnableShaderCache && TitleIDs.CurrentApplication.HasValue
|
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
|
||||||
? Path.Combine(AppDataManager.GamesDirPath, TitleIDs.CurrentApplication, "cache", "shader")
|
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader")
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using SharpMetal;
|
using SharpMetal;
|
||||||
using SharpMetal.Foundation;
|
|
||||||
using SharpMetal.ObjectiveCCore;
|
using SharpMetal.ObjectiveCCore;
|
||||||
using SharpMetal.QuartzCore;
|
using SharpMetal.QuartzCore;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
@@ -10,13 +9,22 @@ namespace Ryujinx.Graphics.Metal.SharpMetalExtensions
|
|||||||
[SupportedOSPlatform("macOS")]
|
[SupportedOSPlatform("macOS")]
|
||||||
public static class CAMetalLayerExtensions
|
public static class CAMetalLayerExtensions
|
||||||
{
|
{
|
||||||
|
private static readonly Selector sel_displaySyncEnabled = "displaySyncEnabled";
|
||||||
|
private static readonly Selector sel_setDisplaySyncEnabled = "setDisplaySyncEnabled:";
|
||||||
|
|
||||||
private static readonly Selector sel_developerHUDProperties = "developerHUDProperties";
|
private static readonly Selector sel_developerHUDProperties = "developerHUDProperties";
|
||||||
private static readonly Selector sel_setDeveloperHUDProperties = "setDeveloperHUDProperties:";
|
private static readonly Selector sel_setDeveloperHUDProperties = "setDeveloperHUDProperties:";
|
||||||
|
|
||||||
public static NSDictionary GetDeveloperHudProperties(this CAMetalLayer metalLayer)
|
public static bool IsDisplaySyncEnabled(this CAMetalLayer metalLayer)
|
||||||
=> new(ObjectiveCRuntime.IntPtr_objc_msgSend(metalLayer.NativePtr, sel_developerHUDProperties));
|
=> ObjectiveCRuntime.bool_objc_msgSend(metalLayer.NativePtr, sel_displaySyncEnabled);
|
||||||
|
|
||||||
public static void SetDeveloperHudProperties(this CAMetalLayer metalLayer, NSDictionary dictionary)
|
public static void SetDisplaySyncEnabled(this CAMetalLayer metalLayer, bool enabled)
|
||||||
=> ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDeveloperHUDProperties, dictionary);
|
=> ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDisplaySyncEnabled, enabled);
|
||||||
|
|
||||||
|
public static nint GetDeveloperHudProperties(this CAMetalLayer metalLayer)
|
||||||
|
=> ObjectiveCRuntime.IntPtr_objc_msgSend(metalLayer.NativePtr, sel_developerHUDProperties);
|
||||||
|
|
||||||
|
public static void SetDeveloperHudProperties(this CAMetalLayer metalLayer, nint dictionaryPointer)
|
||||||
|
=> ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDeveloperHUDProperties, dictionaryPointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
using SharpMetal.Foundation;
|
|
||||||
using SharpMetal.ObjectiveCCore;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
// ReSharper disable InconsistentNaming
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal.SharpMetalExtensions
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macOS")]
|
|
||||||
public static class NSHelper
|
|
||||||
{
|
|
||||||
private static readonly Selector sel_getCStringMaxLengthEncoding = "getCString:maxLength:encoding:";
|
|
||||||
private static readonly Selector sel_stringWithUTF8String = "stringWithUTF8String:";
|
|
||||||
|
|
||||||
public static unsafe string ToDotNetString(this NSString source)
|
|
||||||
{
|
|
||||||
char[] sourceBuffer = new char[source.Length];
|
|
||||||
fixed (char* pSourceBuffer = sourceBuffer)
|
|
||||||
{
|
|
||||||
ObjectiveC.bool_objc_msgSend(source,
|
|
||||||
sel_getCStringMaxLengthEncoding,
|
|
||||||
pSourceBuffer,
|
|
||||||
source.MaximumLengthOfBytes(NSStringEncoding.UTF16) + 1,
|
|
||||||
(ulong)NSStringEncoding.UTF16);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new string(sourceBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static NSString ToNSString(this string source)
|
|
||||||
=> new(ObjectiveC.IntPtr_objc_msgSend(new ObjectiveCClass(nameof(NSString)), sel_stringWithUTF8String, source));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ using Ryujinx.Common.Configuration;
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Ryujinx.Graphics.Metal.Effects;
|
using Ryujinx.Graphics.Metal.Effects;
|
||||||
|
using Ryujinx.Graphics.Metal.SharpMetalExtensions;
|
||||||
using SharpMetal.ObjectiveCCore;
|
using SharpMetal.ObjectiveCCore;
|
||||||
using SharpMetal.QuartzCore;
|
using SharpMetal.QuartzCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
using AntiAliasing = Ryujinx.Graphics.GAL.AntiAliasing;
|
||||||
|
using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
namespace Ryujinx.Graphics.Metal
|
||||||
{
|
{
|
||||||
@@ -15,7 +18,7 @@ namespace Ryujinx.Graphics.Metal
|
|||||||
public bool ScreenCaptureRequested { get; set; }
|
public bool ScreenCaptureRequested { get; set; }
|
||||||
|
|
||||||
private readonly MetalRenderer _renderer;
|
private readonly MetalRenderer _renderer;
|
||||||
private CAMetalLayer _metalLayer;
|
private readonly CAMetalLayer _metalLayer;
|
||||||
|
|
||||||
private int _width;
|
private int _width;
|
||||||
private int _height;
|
private int _height;
|
||||||
@@ -144,10 +147,10 @@ namespace Ryujinx.Graphics.Metal
|
|||||||
switch (vSyncMode)
|
switch (vSyncMode)
|
||||||
{
|
{
|
||||||
case VSyncMode.Unbounded:
|
case VSyncMode.Unbounded:
|
||||||
_metalLayer.DisplaySyncEnabled = false;
|
_metalLayer.SetDisplaySyncEnabled(false);
|
||||||
break;
|
break;
|
||||||
case VSyncMode.Switch:
|
case VSyncMode.Switch:
|
||||||
_metalLayer.DisplaySyncEnabled = true;
|
_metalLayer.SetDisplaySyncEnabled(true);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
|
|||||||
{
|
{
|
||||||
internal enum BitDepth
|
internal enum BitDepth
|
||||||
{
|
{
|
||||||
Bits8 = 8, // < 8 bits
|
Bits8 = 8, /**< 8 bits */
|
||||||
Bits10 = 10, // < 10 bits
|
Bits10 = 10, /**< 10 bits */
|
||||||
Bits12 = 12, // < 12 bits
|
Bits12 = 12, /**< 12 bits */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ using Ryujinx.Graphics.OpenGL.Effects;
|
|||||||
using Ryujinx.Graphics.OpenGL.Effects.Smaa;
|
using Ryujinx.Graphics.OpenGL.Effects.Smaa;
|
||||||
using Ryujinx.Graphics.OpenGL.Image;
|
using Ryujinx.Graphics.OpenGL.Image;
|
||||||
using System;
|
using System;
|
||||||
|
using AntiAliasing = Ryujinx.Graphics.GAL.AntiAliasing;
|
||||||
|
using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.OpenGL
|
namespace Ryujinx.Graphics.OpenGL
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ using Silk.NET.Vulkan;
|
|||||||
using Silk.NET.Vulkan.Extensions.KHR;
|
using Silk.NET.Vulkan.Extensions.KHR;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using AntiAliasing = Ryujinx.Graphics.GAL.AntiAliasing;
|
||||||
|
using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter;
|
||||||
using VkFormat = Silk.NET.Vulkan.Format;
|
using VkFormat = Silk.NET.Vulkan.Format;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
using System;
|
||||||
|
using AntiAliasing = Ryujinx.Graphics.GAL.AntiAliasing;
|
||||||
|
using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -189,11 +189,6 @@ namespace Ryujinx.HLE
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Action RefreshInputConfig { internal get; set; }
|
public Action RefreshInputConfig { internal get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The desired hacky workarounds.
|
|
||||||
/// </summary>
|
|
||||||
public DirtyHacks Hacks { internal get; set; }
|
|
||||||
|
|
||||||
public HLEConfiguration(VirtualFileSystem virtualFileSystem,
|
public HLEConfiguration(VirtualFileSystem virtualFileSystem,
|
||||||
LibHacHorizonManager libHacHorizonManager,
|
LibHacHorizonManager libHacHorizonManager,
|
||||||
ContentManager contentManager,
|
ContentManager contentManager,
|
||||||
@@ -223,8 +218,7 @@ namespace Ryujinx.HLE
|
|||||||
bool multiplayerDisableP2p,
|
bool multiplayerDisableP2p,
|
||||||
string multiplayerLdnPassphrase,
|
string multiplayerLdnPassphrase,
|
||||||
string multiplayerLdnServer,
|
string multiplayerLdnServer,
|
||||||
int customVSyncInterval,
|
int customVSyncInterval)
|
||||||
DirtyHacks dirtyHacks = DirtyHacks.None)
|
|
||||||
{
|
{
|
||||||
VirtualFileSystem = virtualFileSystem;
|
VirtualFileSystem = virtualFileSystem;
|
||||||
LibHacHorizonManager = libHacHorizonManager;
|
LibHacHorizonManager = libHacHorizonManager;
|
||||||
@@ -256,7 +250,6 @@ namespace Ryujinx.HLE
|
|||||||
MultiplayerDisableP2p = multiplayerDisableP2p;
|
MultiplayerDisableP2p = multiplayerDisableP2p;
|
||||||
MultiplayerLdnPassphrase = multiplayerLdnPassphrase;
|
MultiplayerLdnPassphrase = multiplayerLdnPassphrase;
|
||||||
MultiplayerLdnServer = multiplayerLdnServer;
|
MultiplayerLdnServer = multiplayerLdnServer;
|
||||||
Hacks = dirtyHacks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using Gommon;
|
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
@@ -7,13 +6,12 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||||
{
|
{
|
||||||
public class AccountSaveDataManager
|
class AccountSaveDataManager
|
||||||
{
|
{
|
||||||
private static readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
|
private readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
|
||||||
|
|
||||||
private static readonly ProfilesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly ProfilesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
@@ -51,16 +49,6 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Optional<UserProfile> GetLastUsedUser()
|
|
||||||
{
|
|
||||||
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson);
|
|
||||||
|
|
||||||
return profilesJson.Profiles
|
|
||||||
.FindFirst(profile => profile.AccountState == AccountState.Open)
|
|
||||||
.Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name,
|
|
||||||
profileJson.Image, profileJson.LastModifiedTimestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Save(ConcurrentDictionary<string, UserProfile> profiles)
|
public void Save(ConcurrentDictionary<string, UserProfile> profiles)
|
||||||
{
|
{
|
||||||
ProfilesJson profilesJson = new()
|
ProfilesJson profilesJson = new()
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Sf;
|
using LibHac.Sf;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Configuration;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
||||||
{
|
{
|
||||||
@@ -16,8 +13,6 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
|||||||
_baseStorage = SharedRef<LibHac.FsSrv.Sf.IStorage>.CreateMove(ref baseStorage);
|
_baseStorage = SharedRef<LibHac.FsSrv.Sf.IStorage>.CreateMove(ref baseStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string Xc2TitleId = "0100e95004038000";
|
|
||||||
|
|
||||||
[CommandCmif(0)]
|
[CommandCmif(0)]
|
||||||
// Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
|
// Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
|
||||||
public ResultCode Read(ServiceCtx context)
|
public ResultCode Read(ServiceCtx context)
|
||||||
@@ -39,13 +34,6 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
|
|||||||
using var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true);
|
using var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true);
|
||||||
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size);
|
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size);
|
||||||
|
|
||||||
if (context.Device.DirtyHacks.HasFlag(DirtyHacks.Xc2MenuSoftlockFix) && TitleIDs.CurrentApplication == Xc2TitleId)
|
|
||||||
{
|
|
||||||
// Add a load-bearing sleep to avoid XC2 softlock
|
|
||||||
// https://web.archive.org/web/20240728045136/https://github.com/Ryujinx/Ryujinx/issues/2357
|
|
||||||
Thread.Sleep(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ResultCode)result.Value;
|
return (ResultCode)result.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using LibHac.Fs.Fsa;
|
|||||||
using LibHac.Loader;
|
using LibHac.Loader;
|
||||||
using LibHac.Ns;
|
using LibHac.Ns;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
@@ -103,7 +102,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize GPU.
|
// Initialize GPU.
|
||||||
TitleIDs.CurrentApplication = programId.ToString("X16");
|
Graphics.Gpu.GraphicsConfig.TitleId = $"{programId:x16}";
|
||||||
device.Gpu.HostInitalized.Set();
|
device.Gpu.HostInitalized.Set();
|
||||||
|
|
||||||
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
|
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using LibHac.Ns;
|
|||||||
using LibHac.Tools.Fs;
|
using LibHac.Tools.Fs;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||||
@@ -205,7 +204,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Explicitly null TitleId to disable the shader cache.
|
// Explicitly null TitleId to disable the shader cache.
|
||||||
TitleIDs.CurrentApplication = default;
|
Graphics.Gpu.GraphicsConfig.TitleId = null;
|
||||||
_device.Gpu.HostInitalized.Set();
|
_device.Gpu.HostInitalized.Set();
|
||||||
|
|
||||||
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
|
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ namespace Ryujinx.HLE
|
|||||||
|
|
||||||
public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable;
|
public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable;
|
||||||
|
|
||||||
public DirtyHacks DirtyHacks { get; }
|
|
||||||
|
|
||||||
public Switch(HLEConfiguration configuration)
|
public Switch(HLEConfiguration configuration)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(configuration.GpuRenderer);
|
ArgumentNullException.ThrowIfNull(configuration.GpuRenderer);
|
||||||
@@ -74,7 +72,6 @@ namespace Ryujinx.HLE
|
|||||||
System.EnablePtc = Configuration.EnablePtc;
|
System.EnablePtc = Configuration.EnablePtc;
|
||||||
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
|
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
|
||||||
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
|
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
|
||||||
DirtyHacks = Configuration.Hacks;
|
|
||||||
UpdateVSyncInterval();
|
UpdateVSyncInterval();
|
||||||
#pragma warning restore IDE0055
|
#pragma warning restore IDE0055
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using Ryujinx.HLE.UI;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Headless text processing class, right now there is no way to forward the input to it.
|
/// Headless text processing class, right now there is no way to forward the input to it.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Ryujinx.HLE.UI;
|
using Ryujinx.HLE.UI;
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2
|
||||||
{
|
{
|
||||||
internal class HeadlessHostUiTheme : IHostUITheme
|
internal class HeadlessHostUiTheme : IHostUITheme
|
||||||
{
|
{
|
||||||
@@ -5,7 +5,7 @@ using SharpMetal.QuartzCore;
|
|||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using static SDL2.SDL;
|
using static SDL2.SDL;
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2.Metal
|
||||||
{
|
{
|
||||||
[SupportedOSPlatform("macos")]
|
[SupportedOSPlatform("macos")]
|
||||||
class MetalWindow : WindowBase
|
class MetalWindow : WindowBase
|
||||||
@@ -7,7 +7,7 @@ using Ryujinx.Input.HLE;
|
|||||||
using System;
|
using System;
|
||||||
using static SDL2.SDL;
|
using static SDL2.SDL;
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2.OpenGL
|
||||||
{
|
{
|
||||||
class OpenGLWindow : WindowBase
|
class OpenGLWindow : WindowBase
|
||||||
{
|
{
|
||||||
@@ -1,169 +1,14 @@
|
|||||||
using CommandLine;
|
using CommandLine;
|
||||||
using Gommon;
|
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2
|
||||||
{
|
{
|
||||||
public class Options
|
public class Options
|
||||||
{
|
{
|
||||||
public void InheritMainConfig(string[] originalArgs, ConfigurationState configurationState, out bool needsProfileSet)
|
|
||||||
{
|
|
||||||
needsProfileSet = NeedsOverride(nameof(UserProfile));
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(IsFullscreen)))
|
|
||||||
IsFullscreen = configurationState.UI.StartFullscreen;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(EnableKeyboard)))
|
|
||||||
EnableKeyboard = configurationState.Hid.EnableKeyboard;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(EnableMouse)))
|
|
||||||
EnableMouse = configurationState.Hid.EnableMouse;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(HideCursorMode)))
|
|
||||||
HideCursorMode = configurationState.HideCursor;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(DisablePTC)))
|
|
||||||
DisablePTC = !configurationState.System.EnablePtc;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(EnableInternetAccess)))
|
|
||||||
EnableInternetAccess = configurationState.System.EnableInternetAccess;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(DisableFsIntegrityChecks)))
|
|
||||||
DisableFsIntegrityChecks = configurationState.System.EnableFsIntegrityChecks;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(FsGlobalAccessLogMode)))
|
|
||||||
FsGlobalAccessLogMode = configurationState.System.FsGlobalAccessLogMode;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(VSyncMode)))
|
|
||||||
VSyncMode = configurationState.Graphics.VSyncMode;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(CustomVSyncInterval)))
|
|
||||||
CustomVSyncInterval = configurationState.Graphics.CustomVSyncInterval;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(DisableShaderCache)))
|
|
||||||
DisableShaderCache = !configurationState.Graphics.EnableShaderCache;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(EnableTextureRecompression)))
|
|
||||||
EnableTextureRecompression = configurationState.Graphics.EnableTextureRecompression;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(DisableDockedMode)))
|
|
||||||
DisableDockedMode = !configurationState.System.EnableDockedMode;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(SystemLanguage)))
|
|
||||||
SystemLanguage = (SystemLanguage)(int)configurationState.System.Language.Value;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(SystemRegion)))
|
|
||||||
SystemRegion = (RegionCode)(int)configurationState.System.Region.Value;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(SystemTimeZone)))
|
|
||||||
SystemTimeZone = configurationState.System.TimeZone;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(SystemTimeOffset)))
|
|
||||||
SystemTimeOffset = configurationState.System.SystemTimeOffset;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(MemoryManagerMode)))
|
|
||||||
MemoryManagerMode = configurationState.System.MemoryManagerMode;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(AudioVolume)))
|
|
||||||
AudioVolume = configurationState.System.AudioVolume;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(UseHypervisor)) && OperatingSystem.IsMacOS())
|
|
||||||
UseHypervisor = configurationState.System.UseHypervisor;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(MultiplayerLanInterfaceId)))
|
|
||||||
MultiplayerLanInterfaceId = configurationState.Multiplayer.LanInterfaceId;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(DisableFileLog)))
|
|
||||||
DisableFileLog = !configurationState.Logger.EnableFileLog;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingEnableDebug)))
|
|
||||||
LoggingEnableDebug = configurationState.Logger.EnableDebug;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingDisableStub)))
|
|
||||||
LoggingDisableStub = !configurationState.Logger.EnableStub;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingDisableInfo)))
|
|
||||||
LoggingDisableInfo = !configurationState.Logger.EnableInfo;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingDisableWarning)))
|
|
||||||
LoggingDisableWarning = !configurationState.Logger.EnableWarn;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingDisableError)))
|
|
||||||
LoggingDisableError = !configurationState.Logger.EnableError;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingEnableTrace)))
|
|
||||||
LoggingEnableTrace = configurationState.Logger.EnableTrace;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingDisableGuest)))
|
|
||||||
LoggingDisableGuest = !configurationState.Logger.EnableGuest;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingEnableFsAccessLog)))
|
|
||||||
LoggingEnableFsAccessLog = configurationState.Logger.EnableFsAccessLog;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(LoggingGraphicsDebugLevel)))
|
|
||||||
LoggingGraphicsDebugLevel = configurationState.Logger.GraphicsDebugLevel;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(ResScale)))
|
|
||||||
ResScale = configurationState.Graphics.ResScale;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(MaxAnisotropy)))
|
|
||||||
MaxAnisotropy = configurationState.Graphics.MaxAnisotropy;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(AspectRatio)))
|
|
||||||
AspectRatio = configurationState.Graphics.AspectRatio;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(BackendThreading)))
|
|
||||||
BackendThreading = configurationState.Graphics.BackendThreading;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(DisableMacroHLE)))
|
|
||||||
DisableMacroHLE = !configurationState.Graphics.EnableMacroHLE;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(GraphicsShadersDumpPath)))
|
|
||||||
GraphicsShadersDumpPath = configurationState.Graphics.ShadersDumpPath;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(GraphicsBackend)))
|
|
||||||
GraphicsBackend = configurationState.Graphics.GraphicsBackend;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(AntiAliasing)))
|
|
||||||
AntiAliasing = configurationState.Graphics.AntiAliasing;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(ScalingFilter)))
|
|
||||||
ScalingFilter = configurationState.Graphics.ScalingFilter;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(ScalingFilterLevel)))
|
|
||||||
ScalingFilterLevel = configurationState.Graphics.ScalingFilterLevel;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(DramSize)))
|
|
||||||
DramSize = configurationState.System.DramSize;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(IgnoreMissingServices)))
|
|
||||||
IgnoreMissingServices = configurationState.System.IgnoreMissingServices;
|
|
||||||
|
|
||||||
if (NeedsOverride(nameof(IgnoreControllerApplet)))
|
|
||||||
IgnoreControllerApplet = configurationState.IgnoreApplet;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool NeedsOverride(string argKey) => originalArgs.None(arg => arg.TrimStart('-').EqualsIgnoreCase(OptionName(argKey)));
|
|
||||||
|
|
||||||
string OptionName(string propertyName) =>
|
|
||||||
typeof(Options)!.GetProperty(propertyName)!.GetCustomAttribute<OptionAttribute>()!.LongName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// General
|
// General
|
||||||
|
|
||||||
[Option("use-main-config", Required = false, Default = false, HelpText = "Use the settings from what was configured via the UI.")]
|
|
||||||
public bool InheritConfig { get; set; }
|
|
||||||
|
|
||||||
[Option("root-data-dir", Required = false, HelpText = "Set the custom folder path for Ryujinx data.")]
|
[Option("root-data-dir", Required = false, HelpText = "Set the custom folder path for Ryujinx data.")]
|
||||||
public string BaseDataDir { get; set; }
|
public string BaseDataDir { get; set; }
|
||||||
|
|
||||||
@@ -250,10 +95,10 @@ namespace Ryujinx.Headless
|
|||||||
[Option("hide-cursor", Required = false, Default = HideCursorMode.OnIdle, HelpText = "Change when the cursor gets hidden.")]
|
[Option("hide-cursor", Required = false, Default = HideCursorMode.OnIdle, HelpText = "Change when the cursor gets hidden.")]
|
||||||
public HideCursorMode HideCursorMode { get; set; }
|
public HideCursorMode HideCursorMode { get; set; }
|
||||||
|
|
||||||
[Option("list-input-profiles", Required = false, HelpText = "List input profiles.")]
|
[Option("list-input-profiles", Required = false, HelpText = "List inputs profiles.")]
|
||||||
public bool ListInputProfiles { get; set; }
|
public bool ListInputProfiles { get; set; }
|
||||||
|
|
||||||
[Option("list-input-ids", Required = false, HelpText = "List input IDs.")]
|
[Option("list-inputs-ids", Required = false, HelpText = "List inputs ids.")]
|
||||||
public bool ListInputIds { get; set; }
|
public bool ListInputIds { get; set; }
|
||||||
|
|
||||||
// System
|
// System
|
||||||
@@ -327,7 +172,7 @@ namespace Ryujinx.Headless
|
|||||||
public bool LoggingDisableWarning { get; set; }
|
public bool LoggingDisableWarning { get; set; }
|
||||||
|
|
||||||
[Option("disable-error-logs", Required = false, HelpText = "Disables printing error log messages.")]
|
[Option("disable-error-logs", Required = false, HelpText = "Disables printing error log messages.")]
|
||||||
public bool LoggingDisableError { get; set; }
|
public bool LoggingEnableError { get; set; }
|
||||||
|
|
||||||
[Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")]
|
[Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")]
|
||||||
public bool LoggingEnableTrace { get; set; }
|
public bool LoggingEnableTrace { get; set; }
|
||||||
@@ -370,7 +215,7 @@ namespace Ryujinx.Headless
|
|||||||
[Option("anti-aliasing", Required = false, Default = AntiAliasing.None, HelpText = "Set the type of anti aliasing being used. [None|Fxaa|SmaaLow|SmaaMedium|SmaaHigh|SmaaUltra]")]
|
[Option("anti-aliasing", Required = false, Default = AntiAliasing.None, HelpText = "Set the type of anti aliasing being used. [None|Fxaa|SmaaLow|SmaaMedium|SmaaHigh|SmaaUltra]")]
|
||||||
public AntiAliasing AntiAliasing { get; set; }
|
public AntiAliasing AntiAliasing { get; set; }
|
||||||
|
|
||||||
[Option("scaling-filter", Required = false, Default = ScalingFilter.Bilinear, HelpText = "Set the scaling filter. [Bilinear|Nearest|Fsr|Area]")]
|
[Option("scaling-filter", Required = false, Default = ScalingFilter.Bilinear, HelpText = "Set the scaling filter. [Bilinear|Nearest|Fsr]")]
|
||||||
public ScalingFilter ScalingFilter { get; set; }
|
public ScalingFilter ScalingFilter { get; set; }
|
||||||
|
|
||||||
[Option("scaling-filter-level", Required = false, Default = 0, HelpText = "Set the scaling filter intensity (currently only applies to FSR). [0-100]")]
|
[Option("scaling-filter-level", Required = false, Default = 0, HelpText = "Set the scaling filter intensity (currently only applies to FSR). [0-100]")]
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
using CommandLine;
|
using CommandLine;
|
||||||
using Gommon;
|
using Gommon;
|
||||||
using Ryujinx.Ava;
|
using LibHac.Tools.FsSystem;
|
||||||
|
using Ryujinx.Audio.Backends.SDL2;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
using Ryujinx.Common.GraphicsDriver;
|
using Ryujinx.Common.GraphicsDriver;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Logging.Targets;
|
using Ryujinx.Common.Logging.Targets;
|
||||||
@@ -11,12 +15,16 @@ using Ryujinx.Common.SystemInterop;
|
|||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.Cpu;
|
using Ryujinx.Cpu;
|
||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading;
|
||||||
using Ryujinx.Graphics.Gpu;
|
using Ryujinx.Graphics.Gpu;
|
||||||
using Ryujinx.Graphics.Gpu.Shader;
|
using Ryujinx.Graphics.Gpu.Shader;
|
||||||
using Ryujinx.Graphics.Metal;
|
using Ryujinx.Graphics.Metal;
|
||||||
using Ryujinx.Graphics.OpenGL;
|
using Ryujinx.Graphics.OpenGL;
|
||||||
using Ryujinx.Graphics.Vulkan;
|
using Ryujinx.Graphics.Vulkan;
|
||||||
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||||
|
using Ryujinx.Headless.SDL2.Metal;
|
||||||
|
using Ryujinx.Headless.SDL2.OpenGL;
|
||||||
|
using Ryujinx.Headless.SDL2.Vulkan;
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.HOS;
|
using Ryujinx.HLE.HOS;
|
||||||
@@ -25,16 +33,22 @@ using Ryujinx.Input;
|
|||||||
using Ryujinx.Input.HLE;
|
using Ryujinx.Input.HLE;
|
||||||
using Ryujinx.Input.SDL2;
|
using Ryujinx.Input.SDL2;
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
||||||
|
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||||
|
using Key = Ryujinx.Common.Configuration.Hid.Key;
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2
|
||||||
{
|
{
|
||||||
public partial class HeadlessRyujinx
|
class Program
|
||||||
{
|
{
|
||||||
|
public static string Version { get; private set; }
|
||||||
|
|
||||||
private static VirtualFileSystem _virtualFileSystem;
|
private static VirtualFileSystem _virtualFileSystem;
|
||||||
private static ContentManager _contentManager;
|
private static ContentManager _contentManager;
|
||||||
private static AccountManager _accountManager;
|
private static AccountManager _accountManager;
|
||||||
@@ -44,18 +58,20 @@ namespace Ryujinx.Headless
|
|||||||
private static Switch _emulationContext;
|
private static Switch _emulationContext;
|
||||||
private static WindowBase _window;
|
private static WindowBase _window;
|
||||||
private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
|
private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
|
||||||
private static List<InputConfig> _inputConfiguration = [];
|
private static List<InputConfig> _inputConfiguration;
|
||||||
private static bool _enableKeyboard;
|
private static bool _enableKeyboard;
|
||||||
private static bool _enableMouse;
|
private static bool _enableMouse;
|
||||||
|
|
||||||
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public static void Entrypoint(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
Version = ReleaseInformation.Version;
|
||||||
|
|
||||||
// Make process DPI aware for proper window sizing on high-res screens.
|
// Make process DPI aware for proper window sizing on high-res screens.
|
||||||
ForceDpiAware.Windows();
|
ForceDpiAware.Windows();
|
||||||
|
|
||||||
Console.Title = $"Ryujinx Console {Program.Version} (Headless)";
|
Console.Title = $"Ryujinx Console {Version} (Headless SDL2)";
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
|
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
|
||||||
{
|
{
|
||||||
@@ -83,7 +99,7 @@ namespace Ryujinx.Headless
|
|||||||
}
|
}
|
||||||
|
|
||||||
Parser.Default.ParseArguments<Options>(args)
|
Parser.Default.ParseArguments<Options>(args)
|
||||||
.WithParsed(options => Load(args, options))
|
.WithParsed(Load)
|
||||||
.WithNotParsed(errors =>
|
.WithNotParsed(errors =>
|
||||||
{
|
{
|
||||||
Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:");
|
Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:");
|
||||||
@@ -92,80 +108,238 @@ namespace Ryujinx.Headless
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ReloadConfig(string customConfigPath = null)
|
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
||||||
{
|
{
|
||||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
|
if (inputId == null)
|
||||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
|
|
||||||
|
|
||||||
string configurationPath = null;
|
|
||||||
|
|
||||||
// Now load the configuration as the other subsystems are now registered
|
|
||||||
if (customConfigPath != null && File.Exists(customConfigPath))
|
|
||||||
{
|
{
|
||||||
configurationPath = customConfigPath;
|
if (index == PlayerIndex.Player1)
|
||||||
}
|
|
||||||
else if (File.Exists(localConfigurationPath))
|
|
||||||
{
|
|
||||||
configurationPath = localConfigurationPath;
|
|
||||||
}
|
|
||||||
else if (File.Exists(appDataConfigurationPath))
|
|
||||||
{
|
|
||||||
configurationPath = appDataConfigurationPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (configurationPath == null)
|
|
||||||
{
|
|
||||||
// No configuration, we load the default values and save it to disk
|
|
||||||
configurationPath = appDataConfigurationPath;
|
|
||||||
Logger.Notice.Print(LogClass.Application, $"No configuration file found. Saving default configuration to: {configurationPath}");
|
|
||||||
|
|
||||||
ConfigurationState.Instance.LoadDefault();
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(configurationPath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Notice.Print(LogClass.Application, $"Loading configuration from: {configurationPath}");
|
|
||||||
|
|
||||||
if (ConfigurationFileFormat.TryLoad(configurationPath, out ConfigurationFileFormat configurationFileFormat))
|
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Load(configurationFileFormat, configurationPath);
|
Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard.");
|
||||||
|
|
||||||
|
// Default to keyboard
|
||||||
|
inputId = "0";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location: {configurationPath}");
|
Logger.Info?.Print(LogClass.Application, $"{index} not configured");
|
||||||
|
|
||||||
ConfigurationState.Instance.LoadDefault();
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
|
||||||
|
|
||||||
|
bool isKeyboard = true;
|
||||||
|
|
||||||
|
if (gamepad == null)
|
||||||
|
{
|
||||||
|
gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);
|
||||||
|
isKeyboard = false;
|
||||||
|
|
||||||
|
if (gamepad == null)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string gamepadName = gamepad.Name;
|
||||||
|
|
||||||
|
gamepad.Dispose();
|
||||||
|
|
||||||
|
InputConfig config;
|
||||||
|
|
||||||
|
if (inputProfileName == null || inputProfileName.Equals("default"))
|
||||||
|
{
|
||||||
|
if (isKeyboard)
|
||||||
|
{
|
||||||
|
config = new StandardKeyboardInputConfig
|
||||||
|
{
|
||||||
|
Version = InputConfig.CurrentVersion,
|
||||||
|
Backend = InputBackendType.WindowKeyboard,
|
||||||
|
Id = null,
|
||||||
|
ControllerType = ControllerType.JoyconPair,
|
||||||
|
LeftJoycon = new LeftJoyconCommonConfig<Key>
|
||||||
|
{
|
||||||
|
DpadUp = Key.Up,
|
||||||
|
DpadDown = Key.Down,
|
||||||
|
DpadLeft = Key.Left,
|
||||||
|
DpadRight = Key.Right,
|
||||||
|
ButtonMinus = Key.Minus,
|
||||||
|
ButtonL = Key.E,
|
||||||
|
ButtonZl = Key.Q,
|
||||||
|
ButtonSl = Key.Unbound,
|
||||||
|
ButtonSr = Key.Unbound,
|
||||||
|
},
|
||||||
|
|
||||||
|
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||||
|
{
|
||||||
|
StickUp = Key.W,
|
||||||
|
StickDown = Key.S,
|
||||||
|
StickLeft = Key.A,
|
||||||
|
StickRight = Key.D,
|
||||||
|
StickButton = Key.F,
|
||||||
|
},
|
||||||
|
|
||||||
|
RightJoycon = new RightJoyconCommonConfig<Key>
|
||||||
|
{
|
||||||
|
ButtonA = Key.Z,
|
||||||
|
ButtonB = Key.X,
|
||||||
|
ButtonX = Key.C,
|
||||||
|
ButtonY = Key.V,
|
||||||
|
ButtonPlus = Key.Plus,
|
||||||
|
ButtonR = Key.U,
|
||||||
|
ButtonZr = Key.O,
|
||||||
|
ButtonSl = Key.Unbound,
|
||||||
|
ButtonSr = Key.Unbound,
|
||||||
|
},
|
||||||
|
|
||||||
|
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||||
|
{
|
||||||
|
StickUp = Key.I,
|
||||||
|
StickDown = Key.K,
|
||||||
|
StickLeft = Key.J,
|
||||||
|
StickRight = Key.L,
|
||||||
|
StickButton = Key.H,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool isNintendoStyle = gamepadName.Contains("Nintendo");
|
||||||
|
|
||||||
|
config = new StandardControllerInputConfig
|
||||||
|
{
|
||||||
|
Version = InputConfig.CurrentVersion,
|
||||||
|
Backend = InputBackendType.GamepadSDL2,
|
||||||
|
Id = null,
|
||||||
|
ControllerType = ControllerType.JoyconPair,
|
||||||
|
DeadzoneLeft = 0.1f,
|
||||||
|
DeadzoneRight = 0.1f,
|
||||||
|
RangeLeft = 1.0f,
|
||||||
|
RangeRight = 1.0f,
|
||||||
|
TriggerThreshold = 0.5f,
|
||||||
|
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
|
||||||
|
{
|
||||||
|
DpadUp = ConfigGamepadInputId.DpadUp,
|
||||||
|
DpadDown = ConfigGamepadInputId.DpadDown,
|
||||||
|
DpadLeft = ConfigGamepadInputId.DpadLeft,
|
||||||
|
DpadRight = ConfigGamepadInputId.DpadRight,
|
||||||
|
ButtonMinus = ConfigGamepadInputId.Minus,
|
||||||
|
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
||||||
|
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
||||||
|
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||||
|
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||||
|
},
|
||||||
|
|
||||||
|
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||||
|
{
|
||||||
|
Joystick = ConfigStickInputId.Left,
|
||||||
|
StickButton = ConfigGamepadInputId.LeftStick,
|
||||||
|
InvertStickX = false,
|
||||||
|
InvertStickY = false,
|
||||||
|
Rotate90CW = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
||||||
|
{
|
||||||
|
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
|
||||||
|
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
|
||||||
|
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
|
||||||
|
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
|
||||||
|
ButtonPlus = ConfigGamepadInputId.Plus,
|
||||||
|
ButtonR = ConfigGamepadInputId.RightShoulder,
|
||||||
|
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
||||||
|
ButtonSl = ConfigGamepadInputId.Unbound,
|
||||||
|
ButtonSr = ConfigGamepadInputId.Unbound,
|
||||||
|
},
|
||||||
|
|
||||||
|
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
||||||
|
{
|
||||||
|
Joystick = ConfigStickInputId.Right,
|
||||||
|
StickButton = ConfigGamepadInputId.RightStick,
|
||||||
|
InvertStickX = false,
|
||||||
|
InvertStickY = false,
|
||||||
|
Rotate90CW = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
Motion = new StandardMotionConfigController
|
||||||
|
{
|
||||||
|
MotionBackend = MotionInputBackendType.GamepadDriver,
|
||||||
|
EnableMotion = true,
|
||||||
|
Sensitivity = 100,
|
||||||
|
GyroDeadzone = 1,
|
||||||
|
},
|
||||||
|
Rumble = new RumbleConfigController
|
||||||
|
{
|
||||||
|
StrongRumble = 1f,
|
||||||
|
WeakRumble = 1f,
|
||||||
|
EnableRumble = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string profileBasePath;
|
||||||
|
|
||||||
|
if (isKeyboard)
|
||||||
|
{
|
||||||
|
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller");
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = Path.Combine(profileBasePath, inputProfileName + ".json");
|
||||||
|
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
|
||||||
|
}
|
||||||
|
catch (JsonException)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Id = inputId;
|
||||||
|
config.PlayerIndex = index;
|
||||||
|
|
||||||
|
string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
|
||||||
|
|
||||||
|
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
|
||||||
|
if (config is StandardControllerInputConfig controllerConfig)
|
||||||
|
{
|
||||||
|
if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
|
||||||
|
{
|
||||||
|
controllerConfig.RangeLeft = 1.0f;
|
||||||
|
controllerConfig.RangeRight = 1.0f;
|
||||||
|
|
||||||
|
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Load(string[] originalArgs, Options option)
|
static void Load(Options option)
|
||||||
{
|
{
|
||||||
Initialize();
|
|
||||||
|
|
||||||
bool useLastUsedProfile = false;
|
|
||||||
|
|
||||||
if (option.InheritConfig)
|
|
||||||
{
|
|
||||||
option.InheritMainConfig(originalArgs, ConfigurationState.Instance, out useLastUsedProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
AppDataManager.Initialize(option.BaseDataDir);
|
AppDataManager.Initialize(option.BaseDataDir);
|
||||||
|
|
||||||
if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out var profile))
|
|
||||||
option.UserProfile = profile.Name;
|
|
||||||
|
|
||||||
// Check if keys exists.
|
|
||||||
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
|
||||||
{
|
|
||||||
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, "Keys not found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReloadConfig();
|
|
||||||
|
|
||||||
_virtualFileSystem = VirtualFileSystem.CreateInstance();
|
_virtualFileSystem = VirtualFileSystem.CreateInstance();
|
||||||
_libHacHorizonManager = new LibHacHorizonManager();
|
_libHacHorizonManager = new LibHacHorizonManager();
|
||||||
|
|
||||||
@@ -180,7 +354,7 @@ namespace Ryujinx.Headless
|
|||||||
|
|
||||||
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
|
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
|
||||||
|
|
||||||
GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
|
GraphicsConfig.EnableShaderCache = true;
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
@@ -191,13 +365,15 @@ namespace Ryujinx.Headless
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IGamepad gamepad;
|
||||||
|
|
||||||
if (option.ListInputIds)
|
if (option.ListInputIds)
|
||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Application, "Input Ids:");
|
Logger.Info?.Print(LogClass.Application, "Input Ids:");
|
||||||
|
|
||||||
foreach (string id in _inputManager.KeyboardDriver.GamepadsIds)
|
foreach (string id in _inputManager.KeyboardDriver.GamepadsIds)
|
||||||
{
|
{
|
||||||
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
|
gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
|
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
|
||||||
|
|
||||||
@@ -206,7 +382,7 @@ namespace Ryujinx.Headless
|
|||||||
|
|
||||||
foreach (string id in _inputManager.GamepadDriver.GamepadsIds)
|
foreach (string id in _inputManager.GamepadDriver.GamepadsIds)
|
||||||
{
|
{
|
||||||
IGamepad gamepad = _inputManager.GamepadDriver.GetGamepad(id);
|
gamepad = _inputManager.GamepadDriver.GetGamepad(id);
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
|
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
|
||||||
|
|
||||||
@@ -223,7 +399,7 @@ namespace Ryujinx.Headless
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_inputConfiguration ??= [];
|
_inputConfiguration = new List<InputConfig>();
|
||||||
_enableKeyboard = option.EnableKeyboard;
|
_enableKeyboard = option.EnableKeyboard;
|
||||||
_enableMouse = option.EnableMouse;
|
_enableMouse = option.EnableMouse;
|
||||||
|
|
||||||
@@ -247,7 +423,6 @@ namespace Ryujinx.Headless
|
|||||||
LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8);
|
LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8);
|
||||||
LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld);
|
LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld);
|
||||||
|
|
||||||
|
|
||||||
if (_inputConfiguration.Count == 0)
|
if (_inputConfiguration.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -258,7 +433,7 @@ namespace Ryujinx.Headless
|
|||||||
Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub);
|
Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub);
|
||||||
Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo);
|
Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo);
|
||||||
Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning);
|
Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning);
|
||||||
Logger.SetEnable(LogLevel.Error, !option.LoggingDisableError);
|
Logger.SetEnable(LogLevel.Error, option.LoggingEnableError);
|
||||||
Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace);
|
Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace);
|
||||||
Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest);
|
Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest);
|
||||||
Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog);
|
Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog);
|
||||||
@@ -347,6 +522,88 @@ namespace Ryujinx.Headless
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IRenderer CreateRenderer(Options options, WindowBase window)
|
||||||
|
{
|
||||||
|
if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
|
||||||
|
{
|
||||||
|
string preferredGpuId = string.Empty;
|
||||||
|
Vk api = Vk.GetApi();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
|
||||||
|
{
|
||||||
|
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
|
||||||
|
var devices = VulkanRenderer.GetPhysicalDevices(api);
|
||||||
|
|
||||||
|
foreach (var device in devices)
|
||||||
|
{
|
||||||
|
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
|
||||||
|
{
|
||||||
|
preferredGpuId = device.Id;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new VulkanRenderer(
|
||||||
|
api,
|
||||||
|
(instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
|
||||||
|
vulkanWindow.GetRequiredInstanceExtensions,
|
||||||
|
preferredGpuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.GraphicsBackend == GraphicsBackend.Metal && window is MetalWindow metalWindow && OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
return new MetalRenderer(metalWindow.GetLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new OpenGLRenderer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
|
||||||
|
{
|
||||||
|
BackendThreading threadingMode = options.BackendThreading;
|
||||||
|
|
||||||
|
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
||||||
|
|
||||||
|
if (threadedGAL)
|
||||||
|
{
|
||||||
|
renderer = new ThreadedRenderer(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
HLEConfiguration configuration = new(_virtualFileSystem,
|
||||||
|
_libHacHorizonManager,
|
||||||
|
_contentManager,
|
||||||
|
_accountManager,
|
||||||
|
_userChannelPersistence,
|
||||||
|
renderer,
|
||||||
|
new SDL2HardwareDeviceDriver(),
|
||||||
|
options.DramSize,
|
||||||
|
window,
|
||||||
|
options.SystemLanguage,
|
||||||
|
options.SystemRegion,
|
||||||
|
options.VSyncMode,
|
||||||
|
!options.DisableDockedMode,
|
||||||
|
!options.DisablePTC,
|
||||||
|
options.EnableInternetAccess,
|
||||||
|
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
|
||||||
|
options.FsGlobalAccessLogMode,
|
||||||
|
options.SystemTimeOffset,
|
||||||
|
options.SystemTimeZone,
|
||||||
|
options.MemoryManagerMode,
|
||||||
|
options.IgnoreMissingServices,
|
||||||
|
options.AspectRatio,
|
||||||
|
options.AudioVolume,
|
||||||
|
options.UseHypervisor ?? true,
|
||||||
|
options.MultiplayerLanInterfaceId,
|
||||||
|
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
|
||||||
|
false,
|
||||||
|
string.Empty,
|
||||||
|
string.Empty,
|
||||||
|
options.CustomVSyncInterval);
|
||||||
|
|
||||||
|
return new Switch(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
private static void ExecutionEntrypoint()
|
private static void ExecutionEntrypoint()
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
73
src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj
Normal file
73
src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<Version>1.0.0-dirty</Version>
|
||||||
|
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
||||||
|
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
|
||||||
|
<TieredPGO>true</TieredPGO>
|
||||||
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="OpenTK.Core" />
|
||||||
|
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
||||||
|
<Exec Command="codesign --entitlements '$(ProjectDir)..\..\distribution\macos\entitlements.xml' -f -s $(SigningCertificate) '$(TargetDir)$(TargetName)'" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||||
|
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CommandLineParser" />
|
||||||
|
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64'" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="..\..\distribution\legal\THIRDPARTY.md">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
<TargetPath>THIRDPARTY.md</TargetPath>
|
||||||
|
</Content>
|
||||||
|
<Content Include="..\..\LICENSE.txt">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
<TargetPath>LICENSE.txt</TargetPath>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64' OR ('$(RuntimeIdentifier)' == '' AND $([MSBuild]::IsOSPlatform('Linux')))">
|
||||||
|
<Content Include="..\..\distribution\linux\Ryujinx.sh">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Ryujinx.bmp" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Due to .net core 3.1 embedded resource loading -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
|
||||||
|
<ApplicationIcon>..\Ryujinx\Ryujinx.ico</ApplicationIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
|
||||||
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
|
<TrimMode>partial</TrimMode>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
BIN
src/Ryujinx.Headless.SDL2/Ryujinx.bmp
Normal file
BIN
src/Ryujinx.Headless.SDL2/Ryujinx.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2
|
||||||
{
|
{
|
||||||
class StatusUpdatedEventArgs(
|
class StatusUpdatedEventArgs(
|
||||||
string vSyncMode,
|
string vSyncMode,
|
||||||
@@ -6,7 +6,7 @@ using System;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using static SDL2.SDL;
|
using static SDL2.SDL;
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2.Vulkan
|
||||||
{
|
{
|
||||||
class VulkanWindow : WindowBase
|
class VulkanWindow : WindowBase
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using Humanizer;
|
using Humanizer;
|
||||||
using LibHac.Tools.Fs;
|
using LibHac.Tools.Fs;
|
||||||
using Ryujinx.Ava;
|
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
@@ -27,7 +26,7 @@ using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
|||||||
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
||||||
using Switch = Ryujinx.HLE.Switch;
|
using Switch = Ryujinx.HLE.Switch;
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
namespace Ryujinx.Headless.SDL2
|
||||||
{
|
{
|
||||||
abstract partial class WindowBase : IHostUIHandler, IDisposable
|
abstract partial class WindowBase : IHostUIHandler, IDisposable
|
||||||
{
|
{
|
||||||
@@ -137,7 +136,7 @@ namespace Ryujinx.Headless
|
|||||||
|
|
||||||
private void SetWindowIcon()
|
private void SetWindowIcon()
|
||||||
{
|
{
|
||||||
Stream iconStream = typeof(Program).Assembly.GetManifestResourceStream("HeadlessLogo");
|
Stream iconStream = typeof(WindowBase).Assembly.GetManifestResourceStream("Ryujinx.Headless.SDL2.Ryujinx.bmp");
|
||||||
byte[] iconBytes = new byte[iconStream!.Length];
|
byte[] iconBytes = new byte[iconStream!.Length];
|
||||||
|
|
||||||
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
|
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
|
||||||
@@ -255,12 +254,12 @@ namespace Ryujinx.Headless
|
|||||||
|
|
||||||
private void SetAntiAliasing()
|
private void SetAntiAliasing()
|
||||||
{
|
{
|
||||||
Renderer?.Window.SetAntiAliasing(AntiAliasing);
|
Renderer?.Window.SetAntiAliasing((Graphics.GAL.AntiAliasing)AntiAliasing);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetScalingFilter()
|
private void SetScalingFilter()
|
||||||
{
|
{
|
||||||
Renderer?.Window.SetScalingFilter(ScalingFilter);
|
Renderer?.Window.SetScalingFilter((Graphics.GAL.ScalingFilter)ScalingFilter);
|
||||||
Renderer?.Window.SetScalingFilterLevel(ScalingFilterLevel);
|
Renderer?.Window.SetScalingFilterLevel(ScalingFilterLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +318,7 @@ namespace Ryujinx.Headless
|
|||||||
Device.VSyncMode.ToString(),
|
Device.VSyncMode.ToString(),
|
||||||
dockedMode,
|
dockedMode,
|
||||||
Device.Configuration.AspectRatio.ToText(),
|
Device.Configuration.AspectRatio.ToText(),
|
||||||
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
$"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||||
$"FIFO: {Device.Statistics.GetFifoPercent():0.00} %",
|
$"FIFO: {Device.Statistics.GetFifoPercent():0.00} %",
|
||||||
$"GPU: {_gpuDriverName}"));
|
$"GPU: {_gpuDriverName}"));
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 58;
|
public const int CurrentVersion = 57;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the configuration file format
|
/// Version of the configuration file format
|
||||||
@@ -430,16 +430,6 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseHypervisor { get; set; }
|
public bool UseHypervisor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Show toggles for dirty hacks in the UI.
|
|
||||||
/// </summary>
|
|
||||||
public bool ShowDirtyHacks { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The packed value of the enabled dirty hacks.
|
|
||||||
/// </summary>
|
|
||||||
public int EnabledDirtyHacks { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads a configuration file from disk
|
/// Loads a configuration file from disk
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -736,9 +736,6 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
Multiplayer.LdnPassphrase.Value = configurationFileFormat.MultiplayerLdnPassphrase;
|
Multiplayer.LdnPassphrase.Value = configurationFileFormat.MultiplayerLdnPassphrase;
|
||||||
Multiplayer.LdnServer.Value = configurationFileFormat.LdnServer;
|
Multiplayer.LdnServer.Value = configurationFileFormat.LdnServer;
|
||||||
|
|
||||||
Hacks.ShowDirtyHacks.Value = configurationFileFormat.ShowDirtyHacks;
|
|
||||||
Hacks.Xc2MenuSoftlockFix.Value = ((DirtyHacks)configurationFileFormat.EnabledDirtyHacks).HasFlag(DirtyHacks.Xc2MenuSoftlockFix);
|
|
||||||
|
|
||||||
if (configurationFileUpdated)
|
if (configurationFileUpdated)
|
||||||
{
|
{
|
||||||
ToFileFormat().SaveConfig(configurationFilePath);
|
ToFileFormat().SaveConfig(configurationFilePath);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure;
|
using ARMeilleure;
|
||||||
using Gommon;
|
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
@@ -618,49 +617,6 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HacksSection
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Show toggles for dirty hacks in the UI.
|
|
||||||
/// </summary>
|
|
||||||
public ReactiveObject<bool> ShowDirtyHacks { get; private set; }
|
|
||||||
|
|
||||||
public ReactiveObject<bool> Xc2MenuSoftlockFix { get; private set; }
|
|
||||||
|
|
||||||
public HacksSection()
|
|
||||||
{
|
|
||||||
ShowDirtyHacks = new ReactiveObject<bool>();
|
|
||||||
Xc2MenuSoftlockFix = new ReactiveObject<bool>();
|
|
||||||
Xc2MenuSoftlockFix.Event += HackChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HackChanged(object sender, ReactiveEventArgs<bool> rxe)
|
|
||||||
{
|
|
||||||
Ryujinx.Common.Logging.Logger.Info?.Print(LogClass.Configuration, $"EnabledDirtyHacks set to: {EnabledHacks}", "LogValueChange");
|
|
||||||
}
|
|
||||||
|
|
||||||
public DirtyHacks EnabledHacks
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
DirtyHacks dirtyHacks = DirtyHacks.None;
|
|
||||||
|
|
||||||
if (Xc2MenuSoftlockFix)
|
|
||||||
Apply(DirtyHacks.Xc2MenuSoftlockFix);
|
|
||||||
|
|
||||||
return dirtyHacks;
|
|
||||||
|
|
||||||
void Apply(DirtyHacks hack)
|
|
||||||
{
|
|
||||||
if (dirtyHacks is not DirtyHacks.None)
|
|
||||||
dirtyHacks |= hack;
|
|
||||||
else
|
|
||||||
dirtyHacks = hack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default configuration instance
|
/// The default configuration instance
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -696,11 +652,6 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public MultiplayerSection Multiplayer { get; private set; }
|
public MultiplayerSection Multiplayer { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Dirty Hacks section
|
|
||||||
/// </summary>
|
|
||||||
public HacksSection Hacks { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables Discord Rich Presence
|
/// Enables or disables Discord Rich Presence
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -749,7 +700,6 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
Graphics = new GraphicsSection();
|
Graphics = new GraphicsSection();
|
||||||
Hid = new HidSection();
|
Hid = new HidSection();
|
||||||
Multiplayer = new MultiplayerSection();
|
Multiplayer = new MultiplayerSection();
|
||||||
Hacks = new HacksSection();
|
|
||||||
EnableDiscordIntegration = new ReactiveObject<bool>();
|
EnableDiscordIntegration = new ReactiveObject<bool>();
|
||||||
CheckUpdatesOnStart = new ReactiveObject<bool>();
|
CheckUpdatesOnStart = new ReactiveObject<bool>();
|
||||||
ShowConfirmExit = new ReactiveObject<bool>();
|
ShowConfirmExit = new ReactiveObject<bool>();
|
||||||
|
|||||||
@@ -138,8 +138,6 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
MultiplayerDisableP2p = Multiplayer.DisableP2p,
|
MultiplayerDisableP2p = Multiplayer.DisableP2p,
|
||||||
MultiplayerLdnPassphrase = Multiplayer.LdnPassphrase,
|
MultiplayerLdnPassphrase = Multiplayer.LdnPassphrase,
|
||||||
LdnServer = Multiplayer.LdnServer,
|
LdnServer = Multiplayer.LdnServer,
|
||||||
ShowDirtyHacks = Hacks.ShowDirtyHacks,
|
|
||||||
EnabledDirtyHacks = (int)Hacks.EnabledHacks,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return configurationFile;
|
return configurationFile;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.HLE.HOS.SystemState;
|
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Ryujinx.UI.Common.Configuration.System
|
namespace Ryujinx.UI.Common.Configuration.System
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.HLE.Loaders.Processes;
|
using Ryujinx.HLE.Loaders.Processes;
|
||||||
using Ryujinx.UI.App.Common;
|
using Ryujinx.UI.App.Common;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.UI.Common
|
namespace Ryujinx.UI.Common
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
|
|
||||||
if (uninstall)
|
if (uninstall)
|
||||||
{
|
{
|
||||||
// If the types don't already exist, there's nothing to do, and we can call this operation successful.
|
// If the types don't already exist, there's nothing to do and we can call this operation successful.
|
||||||
if (!AreMimeTypesRegisteredWindows())
|
if (!AreMimeTypesRegisteredWindows())
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -289,19 +289,19 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
private void UpdateScalingFilterLevel(object sender, ReactiveEventArgs<int> e)
|
private void UpdateScalingFilterLevel(object sender, ReactiveEventArgs<int> e)
|
||||||
{
|
{
|
||||||
_renderer.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
|
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
|
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateScalingFilter(object sender, ReactiveEventArgs<ScalingFilter> e)
|
private void UpdateScalingFilter(object sender, ReactiveEventArgs<ScalingFilter> e)
|
||||||
{
|
{
|
||||||
_renderer.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
|
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||||
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
|
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs<bool> e)
|
private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs<bool> e)
|
||||||
{
|
{
|
||||||
_renderer.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough);
|
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateVSyncMode(object sender, ReactiveEventArgs<VSyncMode> e)
|
public void UpdateVSyncMode(object sender, ReactiveEventArgs<VSyncMode> e)
|
||||||
@@ -311,7 +311,6 @@ namespace Ryujinx.Ava
|
|||||||
Device.VSyncMode = e.NewValue;
|
Device.VSyncMode = e.NewValue;
|
||||||
Device.UpdateVSyncInterval();
|
Device.UpdateVSyncInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderer.Window?.ChangeVSyncMode(e.NewValue);
|
_renderer.Window?.ChangeVSyncMode(e.NewValue);
|
||||||
|
|
||||||
_viewModel.ShowCustomVSyncIntervalPicker = (e.NewValue == VSyncMode.Custom);
|
_viewModel.ShowCustomVSyncIntervalPicker = (e.NewValue == VSyncMode.Custom);
|
||||||
@@ -527,7 +526,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e)
|
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e)
|
||||||
{
|
{
|
||||||
_renderer?.Window?.SetAntiAliasing(e.NewValue);
|
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)e.NewValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateDockedModeState(object sender, ReactiveEventArgs<bool> e)
|
private void UpdateDockedModeState(object sender, ReactiveEventArgs<bool> e)
|
||||||
@@ -924,7 +923,7 @@ namespace Ryujinx.Ava
|
|||||||
// Initialize Configuration.
|
// Initialize Configuration.
|
||||||
var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
|
var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
|
||||||
|
|
||||||
Device = new Switch(new HLEConfiguration(
|
Device = new HLE.Switch(new HLEConfiguration(
|
||||||
VirtualFileSystem,
|
VirtualFileSystem,
|
||||||
_viewModel.LibHacHorizonManager,
|
_viewModel.LibHacHorizonManager,
|
||||||
ContentManager,
|
ContentManager,
|
||||||
@@ -954,8 +953,7 @@ namespace Ryujinx.Ava
|
|||||||
ConfigurationState.Instance.Multiplayer.DisableP2p,
|
ConfigurationState.Instance.Multiplayer.DisableP2p,
|
||||||
ConfigurationState.Instance.Multiplayer.LdnPassphrase,
|
ConfigurationState.Instance.Multiplayer.LdnPassphrase,
|
||||||
ConfigurationState.Instance.Multiplayer.LdnServer,
|
ConfigurationState.Instance.Multiplayer.LdnServer,
|
||||||
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value,
|
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value));
|
||||||
ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : DirtyHacks.None));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IHardwareDeviceDriver InitializeAudio()
|
private static IHardwareDeviceDriver InitializeAudio()
|
||||||
@@ -1059,10 +1057,10 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
||||||
|
|
||||||
_renderer?.Window?.SetAntiAliasing(ConfigurationState.Instance.Graphics.AntiAliasing);
|
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)ConfigurationState.Instance.Graphics.AntiAliasing.Value);
|
||||||
_renderer?.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
|
_renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
|
||||||
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
|
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
|
||||||
_renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough);
|
_renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
|
||||||
|
|
||||||
Width = (int)RendererHost.Bounds.Width;
|
Width = (int)RendererHost.Bounds.Width;
|
||||||
Height = (int)RendererHost.Bounds.Height;
|
Height = (int)RendererHost.Bounds.Height;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,367 +0,0 @@
|
|||||||
using DiscordRPC;
|
|
||||||
using LibHac.Tools.FsSystem;
|
|
||||||
using Ryujinx.Audio.Backends.SDL2;
|
|
||||||
using Ryujinx.Ava;
|
|
||||||
using Ryujinx.Common.Configuration;
|
|
||||||
using Ryujinx.Common.Configuration.Hid;
|
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
|
||||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
|
||||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Common.Utilities;
|
|
||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
using Ryujinx.Graphics.GAL.Multithreading;
|
|
||||||
using Ryujinx.Graphics.Metal;
|
|
||||||
using Ryujinx.Graphics.OpenGL;
|
|
||||||
using Ryujinx.Graphics.Vulkan;
|
|
||||||
using Ryujinx.HLE;
|
|
||||||
using Ryujinx.Input;
|
|
||||||
using Ryujinx.UI.Common;
|
|
||||||
using Ryujinx.UI.Common.Configuration;
|
|
||||||
using Silk.NET.Vulkan;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
|
|
||||||
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
|
||||||
using Key = Ryujinx.Common.Configuration.Hid.Key;
|
|
||||||
|
|
||||||
namespace Ryujinx.Headless
|
|
||||||
{
|
|
||||||
public partial class HeadlessRyujinx
|
|
||||||
{
|
|
||||||
public static void Initialize()
|
|
||||||
{
|
|
||||||
// Ensure Discord presence timestamp begins at the absolute start of when Ryujinx is launched
|
|
||||||
DiscordIntegrationModule.StartedAt = Timestamps.Now;
|
|
||||||
|
|
||||||
// Delete backup files after updating.
|
|
||||||
Task.Run(Updater.CleanupUpdate);
|
|
||||||
|
|
||||||
// Hook unhandled exception and process exit events.
|
|
||||||
AppDomain.CurrentDomain.UnhandledException += (sender, e)
|
|
||||||
=> Program.ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating);
|
|
||||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => Program.Exit();
|
|
||||||
|
|
||||||
// Initialize the configuration.
|
|
||||||
ConfigurationState.Initialize();
|
|
||||||
|
|
||||||
// Initialize Discord integration.
|
|
||||||
DiscordIntegrationModule.Initialize();
|
|
||||||
|
|
||||||
// Logging system information.
|
|
||||||
Program.PrintSystemInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
|
|
||||||
{
|
|
||||||
if (inputId == null)
|
|
||||||
{
|
|
||||||
if (index == PlayerIndex.Player1)
|
|
||||||
{
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard.");
|
|
||||||
|
|
||||||
// Default to keyboard
|
|
||||||
inputId = "0";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"{index} not configured");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
|
|
||||||
|
|
||||||
bool isKeyboard = true;
|
|
||||||
|
|
||||||
if (gamepad == null)
|
|
||||||
{
|
|
||||||
gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);
|
|
||||||
isKeyboard = false;
|
|
||||||
|
|
||||||
if (gamepad == null)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string gamepadName = gamepad.Name;
|
|
||||||
|
|
||||||
gamepad.Dispose();
|
|
||||||
|
|
||||||
InputConfig config;
|
|
||||||
|
|
||||||
if (inputProfileName == null || inputProfileName.Equals("default"))
|
|
||||||
{
|
|
||||||
if (isKeyboard)
|
|
||||||
{
|
|
||||||
config = new StandardKeyboardInputConfig
|
|
||||||
{
|
|
||||||
Version = InputConfig.CurrentVersion,
|
|
||||||
Backend = InputBackendType.WindowKeyboard,
|
|
||||||
Id = null,
|
|
||||||
ControllerType = ControllerType.JoyconPair,
|
|
||||||
LeftJoycon = new LeftJoyconCommonConfig<Key>
|
|
||||||
{
|
|
||||||
DpadUp = Key.Up,
|
|
||||||
DpadDown = Key.Down,
|
|
||||||
DpadLeft = Key.Left,
|
|
||||||
DpadRight = Key.Right,
|
|
||||||
ButtonMinus = Key.Minus,
|
|
||||||
ButtonL = Key.E,
|
|
||||||
ButtonZl = Key.Q,
|
|
||||||
ButtonSl = Key.Unbound,
|
|
||||||
ButtonSr = Key.Unbound,
|
|
||||||
},
|
|
||||||
|
|
||||||
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
|
|
||||||
{
|
|
||||||
StickUp = Key.W,
|
|
||||||
StickDown = Key.S,
|
|
||||||
StickLeft = Key.A,
|
|
||||||
StickRight = Key.D,
|
|
||||||
StickButton = Key.F,
|
|
||||||
},
|
|
||||||
|
|
||||||
RightJoycon = new RightJoyconCommonConfig<Key>
|
|
||||||
{
|
|
||||||
ButtonA = Key.Z,
|
|
||||||
ButtonB = Key.X,
|
|
||||||
ButtonX = Key.C,
|
|
||||||
ButtonY = Key.V,
|
|
||||||
ButtonPlus = Key.Plus,
|
|
||||||
ButtonR = Key.U,
|
|
||||||
ButtonZr = Key.O,
|
|
||||||
ButtonSl = Key.Unbound,
|
|
||||||
ButtonSr = Key.Unbound,
|
|
||||||
},
|
|
||||||
|
|
||||||
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
|
||||||
{
|
|
||||||
StickUp = Key.I,
|
|
||||||
StickDown = Key.K,
|
|
||||||
StickLeft = Key.J,
|
|
||||||
StickRight = Key.L,
|
|
||||||
StickButton = Key.H,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool isNintendoStyle = gamepadName.Contains("Nintendo");
|
|
||||||
|
|
||||||
config = new StandardControllerInputConfig
|
|
||||||
{
|
|
||||||
Version = InputConfig.CurrentVersion,
|
|
||||||
Backend = InputBackendType.GamepadSDL2,
|
|
||||||
Id = null,
|
|
||||||
ControllerType = ControllerType.JoyconPair,
|
|
||||||
DeadzoneLeft = 0.1f,
|
|
||||||
DeadzoneRight = 0.1f,
|
|
||||||
RangeLeft = 1.0f,
|
|
||||||
RangeRight = 1.0f,
|
|
||||||
TriggerThreshold = 0.5f,
|
|
||||||
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
|
|
||||||
{
|
|
||||||
DpadUp = ConfigGamepadInputId.DpadUp,
|
|
||||||
DpadDown = ConfigGamepadInputId.DpadDown,
|
|
||||||
DpadLeft = ConfigGamepadInputId.DpadLeft,
|
|
||||||
DpadRight = ConfigGamepadInputId.DpadRight,
|
|
||||||
ButtonMinus = ConfigGamepadInputId.Minus,
|
|
||||||
ButtonL = ConfigGamepadInputId.LeftShoulder,
|
|
||||||
ButtonZl = ConfigGamepadInputId.LeftTrigger,
|
|
||||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
|
||||||
ButtonSr = ConfigGamepadInputId.Unbound,
|
|
||||||
},
|
|
||||||
|
|
||||||
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
|
||||||
{
|
|
||||||
Joystick = ConfigStickInputId.Left,
|
|
||||||
StickButton = ConfigGamepadInputId.LeftStick,
|
|
||||||
InvertStickX = false,
|
|
||||||
InvertStickY = false,
|
|
||||||
Rotate90CW = false,
|
|
||||||
},
|
|
||||||
|
|
||||||
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
|
|
||||||
{
|
|
||||||
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
|
|
||||||
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
|
|
||||||
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
|
|
||||||
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
|
|
||||||
ButtonPlus = ConfigGamepadInputId.Plus,
|
|
||||||
ButtonR = ConfigGamepadInputId.RightShoulder,
|
|
||||||
ButtonZr = ConfigGamepadInputId.RightTrigger,
|
|
||||||
ButtonSl = ConfigGamepadInputId.Unbound,
|
|
||||||
ButtonSr = ConfigGamepadInputId.Unbound,
|
|
||||||
},
|
|
||||||
|
|
||||||
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
|
|
||||||
{
|
|
||||||
Joystick = ConfigStickInputId.Right,
|
|
||||||
StickButton = ConfigGamepadInputId.RightStick,
|
|
||||||
InvertStickX = false,
|
|
||||||
InvertStickY = false,
|
|
||||||
Rotate90CW = false,
|
|
||||||
},
|
|
||||||
|
|
||||||
Motion = new StandardMotionConfigController
|
|
||||||
{
|
|
||||||
MotionBackend = MotionInputBackendType.GamepadDriver,
|
|
||||||
EnableMotion = true,
|
|
||||||
Sensitivity = 100,
|
|
||||||
GyroDeadzone = 1,
|
|
||||||
},
|
|
||||||
Rumble = new RumbleConfigController
|
|
||||||
{
|
|
||||||
StrongRumble = 1f,
|
|
||||||
WeakRumble = 1f,
|
|
||||||
EnableRumble = false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string profileBasePath;
|
|
||||||
|
|
||||||
if (isKeyboard)
|
|
||||||
{
|
|
||||||
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller");
|
|
||||||
}
|
|
||||||
|
|
||||||
string path = Path.Combine(profileBasePath, inputProfileName + ".json");
|
|
||||||
|
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
|
|
||||||
}
|
|
||||||
catch (JsonException)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Id = inputId;
|
|
||||||
config.PlayerIndex = index;
|
|
||||||
|
|
||||||
string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
|
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
|
|
||||||
|
|
||||||
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
|
|
||||||
if (config is StandardControllerInputConfig controllerConfig)
|
|
||||||
{
|
|
||||||
if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
|
|
||||||
{
|
|
||||||
controllerConfig.RangeLeft = 1.0f;
|
|
||||||
controllerConfig.RangeRight = 1.0f;
|
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IRenderer CreateRenderer(Options options, WindowBase window)
|
|
||||||
{
|
|
||||||
if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
|
|
||||||
{
|
|
||||||
string preferredGpuId = string.Empty;
|
|
||||||
Vk api = Vk.GetApi();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
|
|
||||||
{
|
|
||||||
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
|
|
||||||
var devices = VulkanRenderer.GetPhysicalDevices(api);
|
|
||||||
|
|
||||||
foreach (var device in devices)
|
|
||||||
{
|
|
||||||
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
|
|
||||||
{
|
|
||||||
preferredGpuId = device.Id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new VulkanRenderer(
|
|
||||||
api,
|
|
||||||
(instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
|
|
||||||
vulkanWindow.GetRequiredInstanceExtensions,
|
|
||||||
preferredGpuId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.GraphicsBackend == GraphicsBackend.Metal && window is MetalWindow metalWindow && OperatingSystem.IsMacOS())
|
|
||||||
{
|
|
||||||
return new MetalRenderer(metalWindow.GetLayer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new OpenGLRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
|
|
||||||
{
|
|
||||||
BackendThreading threadingMode = options.BackendThreading;
|
|
||||||
|
|
||||||
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
|
|
||||||
|
|
||||||
if (threadedGAL)
|
|
||||||
{
|
|
||||||
renderer = new ThreadedRenderer(renderer);
|
|
||||||
}
|
|
||||||
|
|
||||||
HLEConfiguration configuration = new(_virtualFileSystem,
|
|
||||||
_libHacHorizonManager,
|
|
||||||
_contentManager,
|
|
||||||
_accountManager,
|
|
||||||
_userChannelPersistence,
|
|
||||||
renderer,
|
|
||||||
new SDL2HardwareDeviceDriver(),
|
|
||||||
options.DramSize,
|
|
||||||
window,
|
|
||||||
options.SystemLanguage,
|
|
||||||
options.SystemRegion,
|
|
||||||
options.VSyncMode,
|
|
||||||
!options.DisableDockedMode,
|
|
||||||
!options.DisablePTC,
|
|
||||||
options.EnableInternetAccess,
|
|
||||||
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
|
|
||||||
options.FsGlobalAccessLogMode,
|
|
||||||
options.SystemTimeOffset,
|
|
||||||
options.SystemTimeZone,
|
|
||||||
options.MemoryManagerMode,
|
|
||||||
options.IgnoreMissingServices,
|
|
||||||
options.AspectRatio,
|
|
||||||
options.AudioVolume,
|
|
||||||
options.UseHypervisor ?? true,
|
|
||||||
options.MultiplayerLanInterfaceId,
|
|
||||||
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
|
|
||||||
false,
|
|
||||||
string.Empty,
|
|
||||||
string.Empty,
|
|
||||||
options.CustomVSyncInterval);
|
|
||||||
|
|
||||||
return new Switch(configuration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.9 KiB |
@@ -14,7 +14,6 @@ using Ryujinx.Common.GraphicsDriver;
|
|||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.SystemInterop;
|
using Ryujinx.Common.SystemInterop;
|
||||||
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||||
using Ryujinx.Headless;
|
|
||||||
using Ryujinx.SDL2.Common;
|
using Ryujinx.SDL2.Common;
|
||||||
using Ryujinx.UI.App.Common;
|
using Ryujinx.UI.App.Common;
|
||||||
using Ryujinx.UI.Common;
|
using Ryujinx.UI.Common;
|
||||||
@@ -54,12 +53,6 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
PreviewerDetached = true;
|
PreviewerDetached = true;
|
||||||
|
|
||||||
if (args.Length > 0 && args[0] is "--no-gui" or "nogui")
|
|
||||||
{
|
|
||||||
HeadlessRyujinx.Entrypoint(args[1..]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Initialize(args);
|
Initialize(args);
|
||||||
|
|
||||||
LoggerAdapter.Register();
|
LoggerAdapter.Register();
|
||||||
@@ -230,7 +223,7 @@ namespace Ryujinx.Ava
|
|||||||
UseHardwareAcceleration = CommandLineState.OverrideHardwareAcceleration.Value;
|
UseHardwareAcceleration = CommandLineState.OverrideHardwareAcceleration.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void PrintSystemInfo()
|
private static void PrintSystemInfo()
|
||||||
{
|
{
|
||||||
Logger.Notice.Print(LogClass.Application, $"{RyujinxApp.FullAppName} Version: {Version}");
|
Logger.Notice.Print(LogClass.Application, $"{RyujinxApp.FullAppName} Version: {Version}");
|
||||||
SystemInfo.Gather().Print();
|
SystemInfo.Gather().Print();
|
||||||
@@ -247,7 +240,7 @@ namespace Ryujinx.Ava
|
|||||||
: $"Launch Mode: {AppDataManager.Mode}");
|
: $"Launch Mode: {AppDataManager.Mode}");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating)
|
private static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating)
|
||||||
{
|
{
|
||||||
Logger.Log log = Logger.Error ?? Logger.Notice;
|
Logger.Log log = Logger.Error ?? Logger.Notice;
|
||||||
string message = $"Unhandled exception caught: {ex}";
|
string message = $"Unhandled exception caught: {ex}";
|
||||||
@@ -262,7 +255,7 @@ namespace Ryujinx.Ava
|
|||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void Exit()
|
public static void Exit()
|
||||||
{
|
{
|
||||||
DiscordIntegrationModule.Exit();
|
DiscordIntegrationModule.Exit();
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,13 @@
|
|||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="BuildValidationProj" BeforeTargets="BeforeRebuild">
|
<Target Name="BuildValidationProj" BeforeTargets="BeforeBuild">
|
||||||
<MSBuild Projects="..\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj" Targets="Rebuild">
|
<Message Text="Building Validation Project for $(TargetFramework)" Importance="high" Condition="'$(RuntimeIdentifier)' == ''" />
|
||||||
</MSBuild>
|
<Message Text="Building Validation Project for $(TargetFramework) with runtime $(RuntimeIdentifier)" Importance="high" Condition="'$(RuntimeIdentifier)' != ''" />
|
||||||
|
<Exec WorkingDirectory="..\Ryujinx.BuildValidationTasks\" Command="dotnet restore Ryujinx.BuildValidationTasks.csproj --force --ucr true" Condition="'$(RuntimeIdentifier)' == ''" />
|
||||||
|
<Exec WorkingDirectory="..\Ryujinx.BuildValidationTasks\" Command="dotnet restore Ryujinx.BuildValidationTasks.csproj --force --runtime $(RuntimeIdentifier)" Condition="'$(RuntimeIdentifier)' != ''" />
|
||||||
|
<MSBuild Projects="..\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj" Properties="Configuration=Debug" />
|
||||||
|
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
||||||
@@ -47,7 +51,6 @@
|
|||||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" />
|
<PackageReference Include="Avalonia.Markup.Xaml.Loader" />
|
||||||
<PackageReference Include="Avalonia.Svg" />
|
<PackageReference Include="Avalonia.Svg" />
|
||||||
<PackageReference Include="Avalonia.Svg.Skia" />
|
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||||
<PackageReference Include="CommandLineParser" />
|
|
||||||
<PackageReference Include="DynamicData" />
|
<PackageReference Include="DynamicData" />
|
||||||
<PackageReference Include="FluentAvaloniaUI" />
|
<PackageReference Include="FluentAvaloniaUI" />
|
||||||
<PackageReference Include="Projektanker.Icons.Avalonia" />
|
<PackageReference Include="Projektanker.Icons.Avalonia" />
|
||||||
@@ -67,7 +70,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" />
|
<ProjectReference Include="..\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
|
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
|
|
||||||
<ProjectReference Include="..\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj" />
|
<ProjectReference Include="..\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
|
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" />
|
<ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" />
|
||||||
@@ -76,6 +78,7 @@
|
|||||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||||
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
|
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
|
||||||
|
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj" />
|
<ProjectReference Include="..\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj" />
|
||||||
<ProjectReference Include="..\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
<ProjectReference Include="..\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||||
@@ -134,15 +137,8 @@
|
|||||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
|
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
|
||||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" />
|
<EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" />
|
||||||
<EmbeddedResource Include="Assets\Icons\Controller_ProCon.svg" />
|
<EmbeddedResource Include="Assets\Icons\Controller_ProCon.svg" />
|
||||||
<EmbeddedResource Include="Headless\Ryujinx.bmp" LogicalName="HeadlessLogo" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AdditionalFiles Include="Assets\locales.json" />
|
<AdditionalFiles Include="Assets\locales.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Compile Update="UI\Views\Settings\SettingsHacksView.axaml.cs">
|
|
||||||
<DependentUpon>SettingsHacksView.axaml</DependentUpon>
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -13,9 +13,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void OnPropertiesChanged(string firstPropertyName, params ReadOnlySpan<string> propertyNames)
|
protected void OnPropertiesChanged(params ReadOnlySpan<string> propertyNames)
|
||||||
{
|
{
|
||||||
OnPropertyChanged(firstPropertyName);
|
|
||||||
foreach (var propertyName in propertyNames)
|
foreach (var propertyName in propertyNames)
|
||||||
{
|
{
|
||||||
OnPropertyChanged(propertyName);
|
OnPropertyChanged(propertyName);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Gommon;
|
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using Ryujinx.Audio.Backends.OpenAL;
|
using Ryujinx.Audio.Backends.OpenAL;
|
||||||
using Ryujinx.Audio.Backends.SDL2;
|
using Ryujinx.Audio.Backends.SDL2;
|
||||||
@@ -63,9 +62,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private int _networkInterfaceIndex;
|
private int _networkInterfaceIndex;
|
||||||
private int _multiplayerModeIndex;
|
private int _multiplayerModeIndex;
|
||||||
private string _ldnPassphrase;
|
private string _ldnPassphrase;
|
||||||
private string _ldnServer;
|
private string _LdnServer;
|
||||||
|
|
||||||
private bool _xc2MenuSoftlockFix = ConfigurationState.Instance.Hacks.Xc2MenuSoftlockFix;
|
|
||||||
|
|
||||||
public int ResolutionScale
|
public int ResolutionScale
|
||||||
{
|
{
|
||||||
@@ -165,7 +162,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
get => _vSyncMode;
|
get => _vSyncMode;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value is VSyncMode.Custom or VSyncMode.Switch or VSyncMode.Unbounded)
|
if (value == VSyncMode.Custom ||
|
||||||
|
value == VSyncMode.Switch ||
|
||||||
|
value == VSyncMode.Unbounded)
|
||||||
{
|
{
|
||||||
_vSyncMode = value;
|
_vSyncMode = value;
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
@@ -259,8 +258,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
public bool UseHypervisor { get; set; }
|
public bool UseHypervisor { get; set; }
|
||||||
public bool DisableP2P { get; set; }
|
public bool DisableP2P { get; set; }
|
||||||
|
|
||||||
public bool ShowDirtyHacks => ConfigurationState.Instance.Hacks.ShowDirtyHacks;
|
|
||||||
|
|
||||||
public string TimeZone { get; set; }
|
public string TimeZone { get; set; }
|
||||||
public string ShaderDumpPath { get; set; }
|
public string ShaderDumpPath { get; set; }
|
||||||
|
|
||||||
@@ -277,17 +274,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Xc2MenuSoftlockFixEnabled
|
|
||||||
{
|
|
||||||
get => _xc2MenuSoftlockFix;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_xc2MenuSoftlockFix = value;
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Language { get; set; }
|
public int Language { get; set; }
|
||||||
public int Region { get; set; }
|
public int Region { get; set; }
|
||||||
public int FsGlobalAccessLogMode { get; set; }
|
public int FsGlobalAccessLogMode { get; set; }
|
||||||
@@ -388,10 +374,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public string LdnServer
|
public string LdnServer
|
||||||
{
|
{
|
||||||
get => _ldnServer;
|
get => _LdnServer;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_ldnServer = value;
|
_LdnServer = value;
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -761,9 +747,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
config.Multiplayer.LdnPassphrase.Value = LdnPassphrase;
|
config.Multiplayer.LdnPassphrase.Value = LdnPassphrase;
|
||||||
config.Multiplayer.LdnServer.Value = LdnServer;
|
config.Multiplayer.LdnServer.Value = LdnServer;
|
||||||
|
|
||||||
// Dirty Hacks
|
|
||||||
config.Hacks.Xc2MenuSoftlockFix.Value = Xc2MenuSoftlockFixEnabled;
|
|
||||||
|
|
||||||
config.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
config.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
|
|
||||||
MainWindow.UpdateGraphicsConfig();
|
MainWindow.UpdateGraphicsConfig();
|
||||||
@@ -796,18 +779,5 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
RevertIfNotSaved();
|
RevertIfNotSaved();
|
||||||
CloseWindow?.Invoke();
|
CloseWindow?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Xc2MenuFixTooltip { get; } = Lambda.String(sb =>
|
|
||||||
{
|
|
||||||
sb.AppendLine(
|
|
||||||
"This fix applies a 2ms delay (via 'Thread.Sleep(2)') every time the game tries to read data from the emulated Switch filesystem.")
|
|
||||||
.AppendLine();
|
|
||||||
|
|
||||||
sb.AppendLine("From the issue on GitHub:").AppendLine();
|
|
||||||
sb.Append(
|
|
||||||
"When clicking very fast from game main menu to 2nd submenu, " +
|
|
||||||
"there is a low chance that the game will softlock, " +
|
|
||||||
"the submenu won't show up, while background music is still there.");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
<UserControl
|
|
||||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsHacksView"
|
|
||||||
xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
x:DataType="viewModels:SettingsViewModel">
|
|
||||||
<Design.DataContext>
|
|
||||||
<viewModels:SettingsViewModel />
|
|
||||||
</Design.DataContext>
|
|
||||||
<ScrollViewer
|
|
||||||
Name="HacksPage"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Border Classes="settings">
|
|
||||||
<StackPanel
|
|
||||||
Margin="10"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Orientation="Vertical"
|
|
||||||
Spacing="5">
|
|
||||||
<TextBlock
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Classes="h1"
|
|
||||||
Text="Dirty Hacks" />
|
|
||||||
<TextBlock
|
|
||||||
Foreground="{DynamicResource SecondaryTextColor}"
|
|
||||||
TextDecorations="Underline"
|
|
||||||
Text="Game-specific hacks & tricks to alleviate performance issues or crashing. May cause issues." />
|
|
||||||
<StackPanel
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
ToolTip.Tip="{Binding Xc2MenuFixTooltip}">
|
|
||||||
<CheckBox
|
|
||||||
Margin="0"
|
|
||||||
IsChecked="{Binding Xc2MenuSoftlockFixEnabled}"/>
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Text="Xenoblade Chronicles 2 Menu Softlock Fix" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</ScrollViewer>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
|
||||||
using Ryujinx.UI.Common.Configuration;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Views.Settings
|
|
||||||
{
|
|
||||||
public partial class SettingsHacksView : UserControl
|
|
||||||
{
|
|
||||||
public SettingsViewModel ViewModel;
|
|
||||||
|
|
||||||
public SettingsHacksView()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,7 +37,6 @@
|
|||||||
<settings:SettingsAudioView Name="AudioPage" />
|
<settings:SettingsAudioView Name="AudioPage" />
|
||||||
<settings:SettingsNetworkView Name="NetworkPage" />
|
<settings:SettingsNetworkView Name="NetworkPage" />
|
||||||
<settings:SettingsLoggingView Name="LoggingPage" />
|
<settings:SettingsLoggingView Name="LoggingPage" />
|
||||||
<settings:SettingsHacksView Name="HacksPage" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<ui:NavigationView
|
<ui:NavigationView
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
@@ -92,11 +91,6 @@
|
|||||||
Content="{ext:Locale SettingsTabLogging}"
|
Content="{ext:Locale SettingsTabLogging}"
|
||||||
Tag="LoggingPage"
|
Tag="LoggingPage"
|
||||||
IconSource="Document" />
|
IconSource="Document" />
|
||||||
<ui:NavigationViewItem
|
|
||||||
IsVisible="{Binding ShowDirtyHacks}"
|
|
||||||
Content="Dirty Hacks"
|
|
||||||
Tag="HacksPage"
|
|
||||||
IconSource="Code" />
|
|
||||||
</ui:NavigationView.MenuItems>
|
</ui:NavigationView.MenuItems>
|
||||||
<ui:NavigationView.Styles>
|
<ui:NavigationView.Styles>
|
||||||
<Style Selector="Grid#PlaceholderGrid">
|
<Style Selector="Grid#PlaceholderGrid">
|
||||||
|
|||||||
@@ -86,10 +86,6 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
case nameof(LoggingPage):
|
case nameof(LoggingPage):
|
||||||
NavPanel.Content = LoggingPage;
|
NavPanel.Content = LoggingPage;
|
||||||
break;
|
break;
|
||||||
case nameof(HacksPage):
|
|
||||||
HacksPage.ViewModel = ViewModel;
|
|
||||||
NavPanel.Content = HacksPage;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user