Compare commits
140 Commits
Canary-1.2
...
6effa13252
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6effa13252 | ||
|
|
3b5f6170d1 | ||
|
|
9b6afa0ea2 | ||
|
|
3541e282ea | ||
|
|
1ce37ec317 | ||
|
|
c06f16c5e6 | ||
|
|
7829fd8ee7 | ||
|
|
33079422fe | ||
|
|
f81cb093fc | ||
|
|
dc0c7a2912 | ||
|
|
1fbee5a584 | ||
|
|
c140e9b23c | ||
|
|
9c8055440e | ||
|
|
c03cd50fa3 | ||
|
|
069f630776 | ||
|
|
13d411e4de | ||
|
|
9f53b07491 | ||
|
|
cd8113dadf | ||
|
|
9089c4ffe5 | ||
|
|
fe9d8d05bd | ||
|
|
880a8ae748 | ||
|
|
11531dacb6 | ||
|
|
3974739ed3 | ||
|
|
440a3447fb | ||
|
|
65374ed6cb | ||
|
|
789d6ab959 | ||
|
|
182db31343 | ||
|
|
ea296b134d | ||
|
|
bf584442b2 | ||
|
|
cb7c294dbf | ||
|
|
eaf1e7efd2 | ||
|
|
471e7ed2e4 | ||
|
|
ad3e80b383 | ||
|
|
ed64a63094 | ||
|
|
8df7ba2d56 | ||
|
|
e743d78115 | ||
|
|
04ba762710 | ||
|
|
f42b2ed59d | ||
|
|
d135385cab | ||
|
|
b360f4e721 | ||
|
|
f3e1d9cd50 | ||
|
|
a1c0c70ec2 | ||
|
|
290ac405ac | ||
|
|
bbd64fd5f0 | ||
|
|
09446fd80e | ||
|
|
4f014a89cf | ||
|
|
6482e566ab | ||
|
|
7fcd9b792e | ||
|
|
e676fd8b17 | ||
|
|
dd16e3cee1 | ||
|
|
31e5f74e05 | ||
|
|
f2f099bddb | ||
|
|
2616dc57fb | ||
|
|
0cdf7cfe21 | ||
|
|
2ecf999569 | ||
|
|
b612fc5155 | ||
|
|
25eb545409 | ||
|
|
52269964b6 | ||
|
|
ccdddac8fc | ||
|
|
1bc30bf3ba | ||
|
|
4868fface8 | ||
|
|
6fca4492d0 | ||
|
|
ade2f256e0 | ||
|
|
580b150c9a | ||
|
|
e6bad52945 | ||
|
|
beda3206e0 | ||
|
|
2f93a0f706 | ||
|
|
80f44d9547 | ||
|
|
b08e5db6d8 | ||
|
|
6a291d4116 | ||
|
|
6fc827fe67 | ||
|
|
6cd4866d76 | ||
|
|
4d7ca5c0f0 | ||
|
|
a375faecc1 | ||
|
|
1728b0f20c | ||
|
|
5aa071c59b | ||
|
|
1018c9db8b | ||
|
|
01ccd18726 | ||
|
|
abfbc6f4bc | ||
|
|
6a4bc02d7a | ||
|
|
814c0526d2 | ||
|
|
a5a4ef38e6 | ||
|
|
c17e3bfcdf | ||
|
|
017f46f318 | ||
|
|
fd4d801bfd | ||
|
|
f1dee50275 | ||
|
|
c2ae49eb47 | ||
|
|
47c71966d0 | ||
|
|
f9e8f4bc29 | ||
|
|
7694c8c046 | ||
|
|
0dd789e8a5 | ||
|
|
4e0aafd005 | ||
|
|
c5091f499e | ||
|
|
41c8fd8194 | ||
|
|
d4a7ee25ea | ||
|
|
3141c560fb | ||
|
|
de341b285b | ||
|
|
cc95e80ee9 | ||
|
|
d75ce52bd4 | ||
|
|
4a4ea557de | ||
|
|
33f42adb11 | ||
|
|
918ec1bde3 | ||
|
|
cca429d46a | ||
|
|
845c86f545 | ||
|
|
27993b789f | ||
|
|
bdd890cf6f | ||
|
|
c5574b41a1 | ||
|
|
292e27f0da | ||
|
|
606e149bd3 | ||
|
|
a8c3407d11 | ||
|
|
daa8168985 | ||
|
|
f580521e99 | ||
|
|
2226521f6c | ||
|
|
384416953d | ||
|
|
1343fabe41 | ||
|
|
1e52af5e29 | ||
|
|
672f5df0f9 | ||
|
|
804d9c1efe | ||
|
|
9270b35648 | ||
|
|
5a6d01db3c | ||
|
|
ef9c1416ec | ||
|
|
5efa7d5dfa | ||
|
|
a82569d615 | ||
|
|
ed5832ca73 | ||
|
|
574aa9ff9c | ||
|
|
8a29428de2 | ||
|
|
f4272b05fa | ||
|
|
d8265f7772 | ||
|
|
259526430c | ||
|
|
b5fafb6394 | ||
|
|
323c356d9c | ||
|
|
30b22ce6ba | ||
|
|
9acecc9eb2 | ||
|
|
4193a37a91 | ||
|
|
c4cc657b89 | ||
|
|
9726b0feb0 | ||
|
|
159ff828a1 | ||
|
|
6fa2bfc736 | ||
|
|
2c24df0247 | ||
|
|
13efc3e544 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -22,7 +22,7 @@ body:
|
||||
id: log
|
||||
attributes:
|
||||
label: Log file
|
||||
description: A log file will help our developers to better diagnose and fix the issue.
|
||||
description: "A log file will help our developers to better diagnose and fix the issue. UPLOAD THE FILE. DO NOT COPY AND PASTE THE FILE'S CONTENT."
|
||||
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste).
|
||||
validations:
|
||||
required: true
|
||||
|
||||
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
@@ -18,6 +18,10 @@ gpu:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Vulkan/**', 'src/Spv.Generator/**']
|
||||
|
||||
'graphics-backend:metal':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Metal/**', 'src/Ryujinx.Graphics.Metal.SharpMetalExtensions/**']
|
||||
|
||||
gui:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**']
|
||||
|
||||
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -129,11 +129,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
||||
83
.github/workflows/canary.yml
vendored
83
.github/workflows/canary.yml
vendored
@@ -108,6 +108,7 @@ jobs:
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||
sed -r --in-place '/^Name=Ryujinx$/s/Name=Ryujinx/Name=Ryujinx-Canary/' distribution/linux/Ryujinx.desktop
|
||||
shell: bash
|
||||
|
||||
- name: Create output dir
|
||||
@@ -115,71 +116,69 @@ jobs:
|
||||
|
||||
- name: Publish
|
||||
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 -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
|
||||
|
||||
- name: Packing Windows builds
|
||||
if: matrix.platform.os == 'windows-latest'
|
||||
run: |
|
||||
pushd publish_ava
|
||||
rm publish/libarmeilleure-jitsupport.dylib
|
||||
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||
pushd publish
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish_ava
|
||||
rm publish/libarmeilleure-jitsupport.dylib
|
||||
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
|
||||
pushd publish
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
#- name: Build AppImage (Linux)
|
||||
# if: matrix.platform.os == 'ubuntu-latest'
|
||||
# run: |
|
||||
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
# PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||
PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||
|
||||
# sudo apt install -y zsync desktop-file-utils appstream
|
||||
sudo apt install -y zsync desktop-file-utils appstream
|
||||
|
||||
# mkdir -p tools
|
||||
# export PATH="$PATH:$(readlink -f tools)"
|
||||
mkdir -p tools
|
||||
export PATH="$PATH:$(readlink -f tools)"
|
||||
|
||||
# Setup appimagetool
|
||||
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
# chmod +x tools/appimagetool
|
||||
# chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||
chmod +x tools/appimagetool
|
||||
chmod +x distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
# ARCH_NAME=x64
|
||||
# export ARCH=x86_64
|
||||
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
# ARCH_NAME=arm64
|
||||
# export ARCH=aarch64
|
||||
# else
|
||||
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
# exit 1
|
||||
# fi
|
||||
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||
ARCH_NAME=x64
|
||||
export ARCH=x86_64
|
||||
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||
ARCH_NAME=arm64
|
||||
export ARCH=aarch64
|
||||
else
|
||||
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
# BUILDDIR=publish_ava OUTDIR=publish_ava_appimage distribution/linux/appimage/build-appimage.sh
|
||||
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|Canary-Releases|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||
|
||||
# Add to release output
|
||||
# pushd publish_ava_appimage
|
||||
# mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
# mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
# popd
|
||||
# shell: bash
|
||||
pushd publish_appimage
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Pushing new release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
name: ${{ steps.version_info.outputs.build_version }}
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip"
|
||||
#artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: |
|
||||
# Canary builds:
|
||||
@@ -203,7 +202,7 @@ jobs:
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -211,11 +210,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 15
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 15
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
||||
6
.github/workflows/nightly_pr_comment.yml
vendored
6
.github/workflows/nightly_pr_comment.yml
vendored
@@ -37,11 +37,11 @@ jobs:
|
||||
if (!artifacts.length) {
|
||||
return core.error(`No artifacts found`);
|
||||
}
|
||||
let body = `*You need to be logged into GitHub to download these files.*\n\nDownload the artifacts for this pull request:\n`;
|
||||
let body = `Download the artifacts for this pull request:\n`;
|
||||
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
||||
for (const art of artifacts) {
|
||||
const url = `https://github.com/Ryubing/Ryujinx/actions/runs/${run_id}/artifacts/${art.id}`;
|
||||
if(art.name.includes('Debug')) {
|
||||
const url = `https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip`;
|
||||
if (art.name.includes('Debug')) {
|
||||
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
|
||||
} else {
|
||||
body += `\n* [${art.name}](${url})`;
|
||||
|
||||
34
.github/workflows/release.yml
vendored
34
.github/workflows/release.yml
vendored
@@ -3,16 +3,6 @@ name: Release job
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
push:
|
||||
branches: [ release ]
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
- 'docs/**'
|
||||
- 'assets/**'
|
||||
- '*.yml'
|
||||
- '*.json'
|
||||
- '*.config'
|
||||
- '*.md'
|
||||
|
||||
concurrency: release
|
||||
|
||||
@@ -121,6 +111,15 @@ jobs:
|
||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
@@ -157,15 +156,6 @@ jobs:
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Packing Linux builds
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
run: |
|
||||
pushd publish
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||
popd
|
||||
shell: bash
|
||||
|
||||
- name: Pushing new release
|
||||
@@ -193,7 +183,7 @@ jobs:
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -201,11 +191,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 15
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 15
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.18" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" />
|
||||
<PackageVersion Include="Avalonia" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.19" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.19" />
|
||||
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.6" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
@@ -18,7 +18,7 @@
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
||||
<PackageVersion Include="Concentus" Version="2.2.0" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
@@ -26,7 +26,7 @@
|
||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.1.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
@@ -42,16 +42,17 @@
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.0.1" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.1" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.6.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpMetal" Version="1.0.0-preview21" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<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.KHR" Version="2.21.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.7" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.0" />
|
||||
|
||||
@@ -54,12 +54,13 @@ failing to meet this requirement may result in a poor gameplay experience or une
|
||||
|
||||
## Latest build
|
||||
|
||||
Stable builds are made every so often onto a separate "release" branch that then gets put into the releases you know and love.
|
||||
Stable builds are made every so often, based on the `master` branch, that then gets put into the releases you know and love.
|
||||
These stable builds exist so that the end user can get a more **enjoyable and stable experience**.
|
||||
They are released every month or so, to ensure consistent updates, while not being an annoying amount of individual updates to download over the course of that month.
|
||||
|
||||
You can find the latest stable release [here](https://github.com/GreemDev/Ryujinx/releases/latest).
|
||||
|
||||
Canary builds are compiled automatically for each commit on the master branch.
|
||||
Canary builds are compiled automatically for each commit on the `master` branch.
|
||||
While we strive to ensure optimal stability and performance prior to pushing an update, these builds **may be unstable or completely broken**.
|
||||
These canary builds are only recommended for experienced users.
|
||||
|
||||
@@ -109,7 +110,7 @@ If you are planning to contribute or just want to learn more about this project
|
||||
- **Configuration**
|
||||
|
||||
The emulator has settings for enabling or disabling some logging, remapping controllers, and more.
|
||||
You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
|
||||
You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the Ryujinx data folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ cd "$ROOTDIR"
|
||||
|
||||
BUILDDIR=${BUILDDIR:-publish}
|
||||
OUTDIR=${OUTDIR:-publish_appimage}
|
||||
UFLAG=${UFLAG:-"gh-releases-zsync|GreemDev|ryujinx|latest|*-x64.AppImage.zsync"}
|
||||
UFLAG=${UFLAG:-"gh-releases-zsync|Ryubing|ryujinx|latest|*-x64.AppImage.zsync"}
|
||||
|
||||
rm -rf AppDir
|
||||
mkdir -p AppDir/usr/bin
|
||||
|
||||
@@ -19,7 +19,7 @@ if platform.system() == "Darwin":
|
||||
else:
|
||||
OTOOL = shutil.which("llvm-otool")
|
||||
if OTOOL is None:
|
||||
for llvm_ver in [15, 14, 13]:
|
||||
for llvm_ver in [17, 16, 15, 14, 13]:
|
||||
otool_path = shutil.which(f"llvm-otool-{llvm_ver}")
|
||||
if otool_path is not None:
|
||||
OTOOL = otool_path
|
||||
|
||||
@@ -26,7 +26,7 @@ else:
|
||||
LIPO = shutil.which("llvm-lipo")
|
||||
|
||||
if LIPO is None:
|
||||
for llvm_ver in [15, 14, 13]:
|
||||
for llvm_ver in [17, 16, 15, 14, 13]:
|
||||
lipo_path = shutil.which(f"llvm-lipo-{llvm_ver}")
|
||||
if lipo_path is not None:
|
||||
LIPO = lipo_path
|
||||
|
||||
@@ -67,11 +67,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-14
|
||||
LIPO=llvm-lipo-17
|
||||
fi
|
||||
else
|
||||
LIPO=lipo
|
||||
|
||||
@@ -62,11 +62,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTP
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-14
|
||||
LIPO=llvm-lipo-17
|
||||
fi
|
||||
else
|
||||
LIPO=lipo
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
|
||||
<string>Copyright © 2018 - 2025 Ryujinx Team and Contributors.</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.games</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
3425
docs/compatibility.csv
Normal file
3425
docs/compatibility.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -78,5 +78,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
/// Controller Rumble Settings
|
||||
/// </summary>
|
||||
public RumbleConfigController Rumble { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controller LED Settings
|
||||
/// </summary>
|
||||
public LedConfigController Led { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public class LedConfigController
|
||||
{
|
||||
/// <summary>
|
||||
/// Enable LED color changing by the emulator
|
||||
/// </summary>
|
||||
public bool EnableLed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ignores the color and disables the LED entirely.
|
||||
/// </summary>
|
||||
public bool TurnOffLed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ignores the color and uses the rainbow color functionality for the LED.
|
||||
/// </summary>
|
||||
public bool UseRainbow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Packed RGB int of the color
|
||||
/// </summary>
|
||||
public uint LedColor { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,13 @@
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common.GraphicsDriver
|
||||
{
|
||||
public static class DriverUtilities
|
||||
{
|
||||
private static void AddMesaFlags(string envVar, string newFlags)
|
||||
{
|
||||
string existingFlags = Environment.GetEnvironmentVariable(envVar);
|
||||
|
||||
string flags = existingFlags == null ? newFlags : $"{existingFlags},{newFlags}";
|
||||
|
||||
OsUtils.SetEnvironmentVariableNoCaching(envVar, flags);
|
||||
}
|
||||
|
||||
public static void InitDriverConfig(bool oglThreading)
|
||||
{
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
AddMesaFlags("RADV_DEBUG", "nodcc");
|
||||
}
|
||||
|
||||
ToggleOGLThreading(oglThreading);
|
||||
}
|
||||
|
||||
public static void ToggleOGLThreading(bool enabled)
|
||||
{
|
||||
OsUtils.SetEnvironmentVariableNoCaching("mesa_glthread", enabled.ToString().ToLower());
|
||||
OsUtils.SetEnvironmentVariableNoCaching("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
|
||||
Environment.SetEnvironmentVariable("mesa_glthread", enabled.ToString().ToLower());
|
||||
Environment.SetEnvironmentVariable("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
23
src/Ryujinx.Common/Helpers/RunningPlatform.cs
Normal file
23
src/Ryujinx.Common/Helpers/RunningPlatform.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace Ryujinx.Common.Helper
|
||||
{
|
||||
public static class RunningPlatform
|
||||
{
|
||||
public static bool IsMacOS => OperatingSystem.IsMacOS();
|
||||
public static bool IsWindows => OperatingSystem.IsWindows();
|
||||
public static bool IsLinux => OperatingSystem.IsLinux();
|
||||
|
||||
public static bool IsIntelMac => IsMacOS && RuntimeInformation.OSArchitecture is Architecture.X64;
|
||||
public static bool IsArmMac => IsMacOS && RuntimeInformation.OSArchitecture is Architecture.Arm64;
|
||||
|
||||
public static bool IsX64Windows => IsWindows && (RuntimeInformation.OSArchitecture is Architecture.X64);
|
||||
public static bool IsArmWindows => IsWindows && (RuntimeInformation.OSArchitecture is Architecture.Arm64);
|
||||
|
||||
public static bool IsX64Linux => IsLinux && (RuntimeInformation.OSArchitecture is Architecture.X64);
|
||||
public static bool IsArmLinux => IsLinux && (RuntimeInformation.OSArchitecture is Architecture.Arm64);
|
||||
}
|
||||
}
|
||||
10
src/Ryujinx.Common/RyujinxException.cs
Normal file
10
src/Ryujinx.Common/RyujinxException.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public class RyujinxException : Exception
|
||||
{
|
||||
public RyujinxException(string message) : base(message)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Gommon;
|
||||
using Gommon;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Helper;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -8,19 +9,20 @@ namespace Ryujinx.Common
|
||||
{
|
||||
public static class TitleIDs
|
||||
{
|
||||
public static ReactiveObject<Optional<string>> CurrentApplication { get; set; } = new();
|
||||
public static ReactiveObject<Optional<string>> CurrentApplication { get; } = new();
|
||||
|
||||
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
|
||||
{
|
||||
switch (currentBackend)
|
||||
{
|
||||
case GraphicsBackend.Metal when !OperatingSystem.IsMacOS():
|
||||
case GraphicsBackend.OpenGl when OperatingSystem.IsMacOS():
|
||||
return GraphicsBackend.Vulkan;
|
||||
case GraphicsBackend.Vulkan or GraphicsBackend.OpenGl or GraphicsBackend.Metal:
|
||||
return currentBackend;
|
||||
}
|
||||
|
||||
if (!(OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture is Architecture.Arm64))
|
||||
if (!RunningPlatform.IsArmMac)
|
||||
return GraphicsBackend.Vulkan;
|
||||
|
||||
return GreatMetalTitles.ContainsIgnoreCase(titleId) ? GraphicsBackend.Metal : GraphicsBackend.Vulkan;
|
||||
@@ -28,18 +30,28 @@ namespace Ryujinx.Common
|
||||
|
||||
public static readonly string[] GreatMetalTitles =
|
||||
[
|
||||
"01006f8002326000", // Animal Crossings: New Horizons
|
||||
"01009bf0072d4000", // Captain Toad: Treasure Tracker
|
||||
"010076f0049a2000", // Bayonetta
|
||||
"0100a5c00d162000", // Cuphead
|
||||
"010023800d64a000", // Deltarune
|
||||
"01003a30012c0000", // LEGO City Undercover
|
||||
"010028600EBDA000", // Mario 3D World
|
||||
"0100152000022000", // Mario Kart 8 Deluxe
|
||||
"01005CA01580E000", // Persona 5
|
||||
"0100187003A36000", // Pokémon: Let's Go, Evoli!
|
||||
"010075a016a3a000", // Persona 4 Arena Ultimax
|
||||
"0100187003A36000", // Pokémon: Let's Go, Eevee!
|
||||
"010003f003a34000", // Pokémon: Let's Go, Pikachu!
|
||||
"01008C0016544000", // Sea of Stars
|
||||
"01006A800016E000", // Smash Ultimate
|
||||
"0100000000010000", // Super Mario Odyessy
|
||||
"01006bb00c6f0000", // The Legend of Zelda: Link's Awakening
|
||||
|
||||
// These ones have small issues, but those happen on Vulkan as well:
|
||||
"01006f8002326000", // Animal Crossings: New Horizons
|
||||
"01009bf0072d4000", // Captain Toad: Treasure Tracker
|
||||
"01009510001ca000", // Fast RMX
|
||||
"01005CA01580E000", // Persona 5 Royale
|
||||
"0100000000010000", // Super Mario Odyssey
|
||||
|
||||
//Isaac claims it has a issue in level 2, but I am not able to replicate it on my M3. More testing would be appreciated:
|
||||
"010015100b514000", // Super Mario Bros. Wonder
|
||||
];
|
||||
|
||||
public static string GetDiscordGameAsset(string titleId)
|
||||
@@ -47,93 +59,117 @@ namespace Ryujinx.Common
|
||||
|
||||
public static readonly string[] DiscordGameAssetKeys =
|
||||
[
|
||||
"010055d009f78000", // Fire Emblem: Three Houses
|
||||
"0100a12011cc8000", // Fire Emblem: Shadow Dragon
|
||||
//All games are in Alphabetical order by Game name.
|
||||
|
||||
//Dragon Quest Franchise
|
||||
"010008900705c000", // Dragon Quest Builders
|
||||
"010042000a986000", // Dragon Quest Builders 2
|
||||
|
||||
//Fire Emblem Franchise
|
||||
"0100a6301214e000", // Fire Emblem Engage
|
||||
"0100a12011cc8000", // Fire Emblem: Shadow Dragon
|
||||
"010055d009f78000", // Fire Emblem: Three Houses
|
||||
"0100f15003e64000", // Fire Emblem Warriors
|
||||
"010071f0143ea000", // Fire Emblem Warriors: Three Hopes
|
||||
|
||||
"01007e3006dda000", // Kirby Star Allies
|
||||
|
||||
//Kirby Franchise
|
||||
"01004d300c5ae000", // Kirby and the Forgotten Land
|
||||
"01006b601380e000", // Kirby's Return to Dream Land Deluxe
|
||||
"01003fb00c5a8000", // Super Kirby Clash
|
||||
"0100227010460000", // Kirby Fighters 2
|
||||
"0100a8e016236000", // Kirby's Dream Buffet
|
||||
|
||||
"0100227010460000", // Kirby Fighters 2
|
||||
"01006b601380e000", // Kirby's Return to Dream Land Deluxe
|
||||
"01007e3006dda000", // Kirby Star Allies
|
||||
"01003fb00c5a8000", // Super Kirby Clash
|
||||
|
||||
|
||||
//The Zelda Franchise
|
||||
"01000b900d8b0000", // Cadence of Hyrule
|
||||
"0100ae00096ea000", // Hyrule Warriors: Definitive Edition
|
||||
"01002b00111a2000", // Hyrule Warriors: Age of Calamity
|
||||
"01007ef00011e000", // The Legend of Zelda: Breath of the Wild
|
||||
"01006bb00c6f0000", // The Legend of Zelda: Link's Awakening
|
||||
"01002da013484000", // The Legend of Zelda: Skyward Sword HD
|
||||
"0100f2c0115b6000", // The Legend of Zelda: Tears of the Kingdom
|
||||
"01008cf01baac000", // The Legend of Zelda: Echoes of Wisdom
|
||||
"01000b900d8b0000", // Cadence of Hyrule
|
||||
"0100ae00096ea000", // Hyrule Warriors: Definitive Edition
|
||||
"01002b00111a2000", // Hyrule Warriors: Age of Calamity
|
||||
|
||||
|
||||
//Luigi Franchise
|
||||
"010048701995e000", // Luigi's Mansion 2 HD
|
||||
"0100dca0064a6000", // Luigi's Mansion 3
|
||||
|
||||
//Metroid Franchise
|
||||
"010093801237c000", // Metroid Dread
|
||||
"010012101468c000", // Metroid Prime Remastered
|
||||
|
||||
"0100000000010000", // SUPER MARIO ODYSSEY
|
||||
"0100ea80032ea000", // Super Mario Bros. U Deluxe
|
||||
"01009b90006dc000", // Super Mario Maker 2
|
||||
"010049900f546000", // Super Mario 3D All-Stars
|
||||
"010049900F546001", // ^ 64
|
||||
"010049900F546002", // ^ Sunshine
|
||||
"010049900F546003", // ^ Galaxy
|
||||
"010028600ebda000", // Super Mario 3D World + Bowser's Fury
|
||||
"010015100b514000", // Super Mario Bros. Wonder
|
||||
"0100152000022000", // Mario Kart 8 Deluxe
|
||||
"010036b0034e4000", // Super Mario Party
|
||||
"01006fe013472000", // Mario Party Superstars
|
||||
"0100965017338000", // Super Mario Party Jamboree
|
||||
//Monster Hunter Franchise
|
||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||
"0100b04011742000", // Monster Hunter Rise
|
||||
|
||||
//Mario Franchise
|
||||
"01006d0017f7a000", // Mario & Luigi: Brothership
|
||||
"010003000e146000", // Mario & Sonic at the Olympic Games Tokyo 2020
|
||||
"010067300059a000", // Mario + Rabbids: Kingdom Battle
|
||||
"0100317013770000", // Mario + Rabbids: Sparks of Hope
|
||||
"0100c9c00e25c000", // Mario Golf: Super Rush
|
||||
"0100152000022000", // Mario Kart 8 Deluxe
|
||||
"01006fe013472000", // Mario Party Superstars
|
||||
"010019401051c000", // Mario Strikers: Battle League
|
||||
"0100bde00862a000", // Mario Tennis Aces
|
||||
"0100b99019412000", // Mario vs. Donkey Kong
|
||||
"010049900f546000", // Super Mario 3D All-Stars
|
||||
"010028600ebda000", // Super Mario 3D World + Bowser's Fury
|
||||
"010049900F546001", // Super Mario 64
|
||||
"0100ea80032ea000", // Super Mario Bros. U Deluxe
|
||||
"010015100b514000", // Super Mario Bros. Wonder
|
||||
"010049900F546003", // Super Mario Galaxy
|
||||
"01009b90006dc000", // Super Mario Maker 2
|
||||
"0100000000010000", // SUPER MARIO ODYSSEY
|
||||
"010036b0034e4000", // Super Mario Party
|
||||
"0100965017338000", // Super Mario Party Jamboree
|
||||
"0100bc0018138000", // Super Mario RPG
|
||||
"010049900F546002", // Super Mario Sunshine
|
||||
"0100a3900c3e2000", // Paper Mario: The Origami King
|
||||
"0100ecd018ebe000", // Paper Mario: The Thousand-Year Door
|
||||
"0100bc0018138000", // Super Mario RPG
|
||||
"0100bde00862a000", // Mario Tennis Aces
|
||||
"0100c9c00e25c000", // Mario Golf: Super Rush
|
||||
"010019401051c000", // Mario Strikers: Battle League
|
||||
"010003000e146000", // Mario & Sonic at the Olympic Games Tokyo 2020
|
||||
"0100b99019412000", // Mario vs. Donkey Kong
|
||||
|
||||
//Pikmin Franchise
|
||||
"0100aa80194b0000", // Pikmin 1
|
||||
"0100d680194b2000", // Pikmin 2
|
||||
"0100f4c009322000", // Pikmin 3 Deluxe
|
||||
"0100b7c00933a000", // Pikmin 4
|
||||
|
||||
"010003f003a34000", // Pokémon: Let's Go Pikachu!
|
||||
"0100187003a36000", // Pokémon: Let's Go Eevee!
|
||||
"0100abf008968000", // Pokémon Sword
|
||||
"01008db008c2c000", // Pokémon Shield
|
||||
//The Pokémon Franchise
|
||||
"0100f4300bf2c000", // New Pokémon Snap
|
||||
"0100000011d90000", // Pokémon Brilliant Diamond
|
||||
"010018e011d92000", // Pokémon Shining Pearl
|
||||
"01001f5010dfa000", // Pokémon Legends: Arceus
|
||||
"01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX
|
||||
"0100a3d008c5c000", // Pokémon Scarlet
|
||||
"01008db008c2c000", // Pokémon Shield
|
||||
"010018e011d92000", // Pokémon Shining Pearl
|
||||
"0100abf008968000", // Pokémon Sword
|
||||
"01008f6008c5e000", // Pokémon Violet
|
||||
"0100b3f000be2000", // Pokkén Tournament DX
|
||||
"0100f4300bf2c000", // New Pokémon Snap
|
||||
"0100187003a36000", // Pokémon: Let's Go Eevee!
|
||||
"010003f003a34000", // Pokémon: Let's Go Pikachu!
|
||||
|
||||
"01003bc0000a0000", // Splatoon 2 (US)
|
||||
//Splatoon Franchise
|
||||
"0100f8f0000a2000", // Splatoon 2 (EU)
|
||||
"01003c700009c000", // Splatoon 2 (JP)
|
||||
"01003bc0000a0000", // Splatoon 2 (US)
|
||||
"0100c2500fc20000", // Splatoon 3
|
||||
"0100ba0018500000", // Splatoon 3: Splatfest World Premiere
|
||||
|
||||
"010040600c5ce000", // Tetris 99
|
||||
"0100277011f1a000", // Super Mario Bros. 35
|
||||
"0100ad9012510000", // PAC-MAN 99
|
||||
//NSO Membership games
|
||||
"0100ccf019c8c000", // F-ZERO 99
|
||||
"0100d870045b6000", // NES - Nintendo Switch Online
|
||||
"01008d300c50c000", // SNES - Nintendo Switch Online
|
||||
"0100c9a00ece6000", // N64 - Nintendo Switch Online
|
||||
"0100e0601c632000", // N64 - Nintendo Switch Online 18+
|
||||
"0100c62011050000", // GB - Nintendo Switch Online
|
||||
"010012f017576000", // GBA - Nintendo Switch Online
|
||||
"0100c9a00ece6000", // N64 - Nintendo Switch Online
|
||||
"0100e0601c632000", // N64 - Nintendo Switch Online 18+
|
||||
"0100d870045b6000", // NES - Nintendo Switch Online
|
||||
"0100ad9012510000", // PAC-MAN 99
|
||||
"010040600c5ce000", // Tetris 99
|
||||
"01008d300c50c000", // SNES - Nintendo Switch Online
|
||||
"0100277011f1a000", // Super Mario Bros. 35
|
||||
|
||||
//Misc Nintendo 1st party games
|
||||
"01000320000cc000", // 1-2 Switch
|
||||
"0100300012f2a000", // Advance Wars 1+2: Re-Boot Camp
|
||||
"01006f8002326000", // Animal Crossing: New Horizons
|
||||
@@ -148,33 +184,44 @@ namespace Ryujinx.Common
|
||||
"01006a800016e000", // Super Smash Bros. Ultimate
|
||||
"0100a9400c9c2000", // Tokyo Mirage Sessions #FE Encore
|
||||
|
||||
//Bayonetta Franchise
|
||||
"010076f0049a2000", // Bayonetta
|
||||
"01007960049a0000", // Bayonetta 2
|
||||
"01004a4010fea000", // Bayonetta 3
|
||||
"0100cf5010fec000", // Bayonetta Origins: Cereza and the Lost Demon
|
||||
|
||||
//Persona Franchise
|
||||
"0100dcd01525a000", // Persona 3 Portable
|
||||
"010062b01525c000", // Persona 4 Golden
|
||||
"010075a016a3a000", // Persona 4 Arena Ultimax
|
||||
"010062b01525c000", // Persona 4 Golden
|
||||
"01005ca01580e000", // Persona 5 Royal
|
||||
"0100801011c3e000", // Persona 5 Strikers
|
||||
"010087701b092000", // Persona 5 Tactica
|
||||
|
||||
"01009aa000faa000", // Sonic Mania
|
||||
//Sonic Franchise
|
||||
"01004ad014bf0000", // Sonic Frontiers
|
||||
"01009aa000faa000", // Sonic Mania
|
||||
"01005ea01c0fc000", // SONIC X SHADOW GENERATIONS
|
||||
"01005ea01c0fc001", // ^
|
||||
|
||||
//Xenoblade Franchise
|
||||
"0100ff500e34a000", // Xenoblade Chronicles - Definitive Edition
|
||||
"0100e95004038000", // Xenoblade Chronicles 2
|
||||
"010074f013262000", // Xenoblade Chronicles 3
|
||||
|
||||
//Misc Games
|
||||
"010056e00853a000", // A Hat in Time
|
||||
"0100fd1014726000", // Baldurs Gate: Dark Alliance
|
||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
||||
"0100744001588000", // Cars 3: Driven to Win
|
||||
"0100b41013c82000", // Cruis'n Blast
|
||||
"010085900337e000", // Death Squared
|
||||
"01001b300b9be000", // Diablo III: Eternal Collection
|
||||
"01008c8012920000", // Dying Light Platinum Edition
|
||||
"01001cc01b2d4000", // Goat Simulator 3
|
||||
"01003620068ea000", // Hand of Fate 2
|
||||
"010085500130a000", // Lego City: Undercover
|
||||
"010073c01af34000", // LEGO Horizon Adventures
|
||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||
"0100b04011742000", // Monster Hunter Rise
|
||||
"0100853015e86000", // No Man's Sky
|
||||
"01007bb017812000", // Portal
|
||||
"0100abd01785c000", // Portal 2
|
||||
@@ -190,6 +237,8 @@ namespace Ryujinx.Common
|
||||
"01000a10041ea000", // The Elder Scrolls V: Skyrim
|
||||
"010057a01e4d4000", // TSUKIHIME -A piece of blue glass moon-
|
||||
"010080b00ad66000", // Undertale
|
||||
"010069401adb8000", // Unicorn Overlord
|
||||
"0100534009ff2000", // Yonder - The cloud catcher chronicles
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public partial class OsUtils
|
||||
{
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
|
||||
|
||||
public static void SetEnvironmentVariableNoCaching(string key, string value)
|
||||
{
|
||||
// Set the value in the cached environment variables, too.
|
||||
Environment.SetEnvironmentVariable(key, value);
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
int res = setenv(key, value, 1);
|
||||
Debug.Assert(res != -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
110
src/Ryujinx.Common/Utilities/Rainbow.cs
Normal file
110
src/Ryujinx.Common/Utilities/Rainbow.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
using Gommon;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public static class Rainbow
|
||||
{
|
||||
public static bool CyclingEnabled { get; set; }
|
||||
|
||||
public static void Enable()
|
||||
{
|
||||
if (!CyclingEnabled)
|
||||
{
|
||||
CyclingEnabled = true;
|
||||
Executor.ExecuteBackgroundAsync(async () =>
|
||||
{
|
||||
while (CyclingEnabled)
|
||||
{
|
||||
await Task.Delay(15);
|
||||
Tick();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Disable()
|
||||
{
|
||||
CyclingEnabled = false;
|
||||
}
|
||||
|
||||
|
||||
public static float Speed { get; set; } = 1;
|
||||
|
||||
public static Color Color { get; private set; } = Color.Blue;
|
||||
|
||||
public static void Tick()
|
||||
{
|
||||
Color = HsbToRgb((Color.GetHue() + Speed) / 360);
|
||||
|
||||
UpdatedHandler.Call(Color.ToArgb());
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
Color = Color.Blue;
|
||||
UpdatedHandler.Clear();
|
||||
}
|
||||
|
||||
public static event Action<int> Updated
|
||||
{
|
||||
add => UpdatedHandler.Add(value);
|
||||
remove => UpdatedHandler.Remove(value);
|
||||
}
|
||||
|
||||
internal static Event<int> UpdatedHandler = new();
|
||||
|
||||
private static Color HsbToRgb(float hue, float saturation = 1, float brightness = 1)
|
||||
{
|
||||
int r = 0, g = 0, b = 0;
|
||||
if (saturation == 0)
|
||||
{
|
||||
r = g = b = (int)(brightness * 255.0f + 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
float h = (hue - (float)Math.Floor(hue)) * 6.0f;
|
||||
float f = h - (float)Math.Floor(h);
|
||||
float p = brightness * (1.0f - saturation);
|
||||
float q = brightness * (1.0f - saturation * f);
|
||||
float t = brightness * (1.0f - (saturation * (1.0f - f)));
|
||||
switch ((int)h)
|
||||
{
|
||||
case 0:
|
||||
r = (int)(brightness * 255.0f + 0.5f);
|
||||
g = (int)(t * 255.0f + 0.5f);
|
||||
b = (int)(p * 255.0f + 0.5f);
|
||||
break;
|
||||
case 1:
|
||||
r = (int)(q * 255.0f + 0.5f);
|
||||
g = (int)(brightness * 255.0f + 0.5f);
|
||||
b = (int)(p * 255.0f + 0.5f);
|
||||
break;
|
||||
case 2:
|
||||
r = (int)(p * 255.0f + 0.5f);
|
||||
g = (int)(brightness * 255.0f + 0.5f);
|
||||
b = (int)(t * 255.0f + 0.5f);
|
||||
break;
|
||||
case 3:
|
||||
r = (int)(p * 255.0f + 0.5f);
|
||||
g = (int)(q * 255.0f + 0.5f);
|
||||
b = (int)(brightness * 255.0f + 0.5f);
|
||||
break;
|
||||
case 4:
|
||||
r = (int)(t * 255.0f + 0.5f);
|
||||
g = (int)(p * 255.0f + 0.5f);
|
||||
b = (int)(brightness * 255.0f + 0.5f);
|
||||
break;
|
||||
case 5:
|
||||
r = (int)(brightness * 255.0f + 0.5f);
|
||||
g = (int)(p * 255.0f + 0.5f);
|
||||
b = (int)(q * 255.0f + 0.5f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Color.FromArgb(Convert.ToByte(255), Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
private static string GetDiskCachePath()
|
||||
{
|
||||
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
|
||||
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader")
|
||||
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId.ToLower(), "cache", "shader")
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,12 +32,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
CommandBuffer
|
||||
}
|
||||
|
||||
private bool _feedbackLoopActive;
|
||||
private PipelineStageFlags _incoherentBufferWriteStages;
|
||||
private PipelineStageFlags _incoherentTextureWriteStages;
|
||||
private PipelineStageFlags _extraStages;
|
||||
private IncoherentBarrierType _queuedIncoherentBarrier;
|
||||
private bool _queuedFeedbackLoopBarrier;
|
||||
|
||||
public BarrierBatch(VulkanRenderer gd)
|
||||
{
|
||||
@@ -55,6 +53,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
stages |= PipelineStageFlags.TransformFeedbackBitExt;
|
||||
}
|
||||
|
||||
if (!gd.IsTBDR)
|
||||
{
|
||||
// Desktop GPUs can transform image barriers into memory barriers.
|
||||
|
||||
access |= AccessFlags.DepthStencilAttachmentWriteBit | AccessFlags.ColorAttachmentWriteBit;
|
||||
access |= AccessFlags.DepthStencilAttachmentReadBit | AccessFlags.ColorAttachmentReadBit;
|
||||
|
||||
stages |= PipelineStageFlags.EarlyFragmentTestsBit | PipelineStageFlags.LateFragmentTestsBit;
|
||||
stages |= PipelineStageFlags.ColorAttachmentOutputBit;
|
||||
}
|
||||
|
||||
return (access, stages);
|
||||
}
|
||||
|
||||
@@ -169,34 +178,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
|
||||
_queuedIncoherentBarrier = IncoherentBarrierType.None;
|
||||
_queuedFeedbackLoopBarrier = false;
|
||||
}
|
||||
else if (_feedbackLoopActive && _queuedFeedbackLoopBarrier)
|
||||
{
|
||||
// Feedback loop barrier.
|
||||
|
||||
MemoryBarrier barrier = new MemoryBarrier()
|
||||
{
|
||||
SType = StructureType.MemoryBarrier,
|
||||
SrcAccessMask = AccessFlags.ShaderWriteBit,
|
||||
DstAccessMask = AccessFlags.ShaderReadBit
|
||||
};
|
||||
|
||||
QueueBarrier(barrier, PipelineStageFlags.FragmentShaderBit, PipelineStageFlags.AllGraphicsBit);
|
||||
|
||||
_queuedFeedbackLoopBarrier = false;
|
||||
}
|
||||
|
||||
_feedbackLoopActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Flush(CommandBufferScoped cbs, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||
{
|
||||
Flush(cbs, null, false, inRenderPass, rpHolder, endRenderPass);
|
||||
Flush(cbs, null, inRenderPass, rpHolder, endRenderPass);
|
||||
}
|
||||
|
||||
public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool feedbackLoopActive, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||
public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||
{
|
||||
if (program != null)
|
||||
{
|
||||
@@ -204,8 +195,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_incoherentTextureWriteStages |= program.IncoherentTextureWriteStages;
|
||||
}
|
||||
|
||||
_feedbackLoopActive |= feedbackLoopActive;
|
||||
|
||||
FlushMemoryBarrier(program, inRenderPass);
|
||||
|
||||
if (!inRenderPass && rpHolder != null)
|
||||
@@ -417,8 +406,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
_queuedIncoherentBarrier = type;
|
||||
}
|
||||
|
||||
_queuedFeedbackLoopBarrier = true;
|
||||
}
|
||||
|
||||
public void QueueTextureBarrier()
|
||||
|
||||
@@ -4,7 +4,6 @@ using Ryujinx.Graphics.Shader;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
||||
@@ -43,15 +42,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private record struct TextureRef
|
||||
{
|
||||
public ShaderStage Stage;
|
||||
public TextureView View;
|
||||
public Auto<DisposableImageView> ImageView;
|
||||
public TextureStorage Storage;
|
||||
public Auto<DisposableImageView> View;
|
||||
public Auto<DisposableSampler> Sampler;
|
||||
|
||||
public TextureRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView, Auto<DisposableSampler> sampler)
|
||||
public TextureRef(ShaderStage stage, TextureStorage storage, Auto<DisposableImageView> view, Auto<DisposableSampler> sampler)
|
||||
{
|
||||
Stage = stage;
|
||||
Storage = storage;
|
||||
View = view;
|
||||
ImageView = imageView;
|
||||
Sampler = sampler;
|
||||
}
|
||||
}
|
||||
@@ -59,14 +58,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private record struct ImageRef
|
||||
{
|
||||
public ShaderStage Stage;
|
||||
public TextureView View;
|
||||
public Auto<DisposableImageView> ImageView;
|
||||
public TextureStorage Storage;
|
||||
public Auto<DisposableImageView> View;
|
||||
|
||||
public ImageRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView)
|
||||
public ImageRef(ShaderStage stage, TextureStorage storage, Auto<DisposableImageView> view)
|
||||
{
|
||||
Stage = stage;
|
||||
Storage = storage;
|
||||
View = view;
|
||||
ImageView = imageView;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +123,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly TextureView _dummyTexture;
|
||||
private readonly SamplerHolder _dummySampler;
|
||||
|
||||
public List<TextureView> FeedbackLoopHazards { get; private set; }
|
||||
|
||||
public DescriptorSetUpdater(VulkanRenderer gd, Device device)
|
||||
{
|
||||
_gd = gd;
|
||||
@@ -210,15 +207,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_templateUpdater = new();
|
||||
}
|
||||
|
||||
public void Initialize(bool isMainPipeline)
|
||||
public void Initialize()
|
||||
{
|
||||
MemoryOwner<byte> dummyTextureData = MemoryOwner<byte>.RentCleared(4);
|
||||
_dummyTexture.SetData(dummyTextureData);
|
||||
|
||||
if (isMainPipeline)
|
||||
{
|
||||
FeedbackLoopHazards = new();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size)
|
||||
@@ -281,18 +273,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void InsertBindingBarriers(CommandBufferScoped cbs)
|
||||
{
|
||||
if ((FeedbackLoopHazards?.Count ?? 0) > 0)
|
||||
{
|
||||
// Clear existing hazards - they will be rebuilt.
|
||||
|
||||
foreach (TextureView hazard in FeedbackLoopHazards)
|
||||
{
|
||||
hazard.DecrementHazardUses();
|
||||
}
|
||||
|
||||
FeedbackLoopHazards.Clear();
|
||||
}
|
||||
|
||||
foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex])
|
||||
{
|
||||
if (segment.Type == ResourceType.TextureAndSampler)
|
||||
@@ -302,7 +282,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
for (int i = 0; i < segment.Count; i++)
|
||||
{
|
||||
ref var texture = ref _textureRefs[segment.Binding + i];
|
||||
texture.View?.PrepareForUsage(cbs, texture.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||
texture.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, texture.Stage.ConvertToPipelineStageFlags());
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -323,7 +303,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
for (int i = 0; i < segment.Count; i++)
|
||||
{
|
||||
ref var image = ref _imageRefs[segment.Binding + i];
|
||||
image.View?.PrepareForUsage(cbs, image.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||
image.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, image.Stage.ConvertToPipelineStageFlags());
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -397,12 +377,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
else if (image is TextureView view)
|
||||
{
|
||||
ref ImageRef iRef = ref _imageRefs[binding];
|
||||
|
||||
iRef.View?.ClearUsage(FeedbackLoopHazards);
|
||||
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||
|
||||
iRef = new(stage, view, view.GetIdentityImageView());
|
||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||
_imageRefs[binding] = new(stage, view.Storage, view.GetIdentityImageView());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -500,12 +476,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
else if (texture is TextureView view)
|
||||
{
|
||||
ref TextureRef iRef = ref _textureRefs[binding];
|
||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||
|
||||
iRef.View?.ClearUsage(FeedbackLoopHazards);
|
||||
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||
|
||||
iRef = new(stage, view, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||
_textureRefs[binding] = new(stage, view.Storage, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -527,7 +500,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||
|
||||
_textureRefs[binding] = new(stage, view, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||
_textureRefs[binding] = new(stage, view.Storage, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||
|
||||
SignalDirty(DirtyFlags.Texture);
|
||||
}
|
||||
@@ -853,7 +826,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ref var texture = ref textures[i];
|
||||
ref var refs = ref _textureRefs[binding + i];
|
||||
|
||||
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
||||
texture.ImageView = refs.View?.Get(cbs).Value ?? default;
|
||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
||||
|
||||
if (texture.ImageView.Handle == 0)
|
||||
@@ -903,7 +876,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default;
|
||||
images[i].ImageView = _imageRefs[binding + i].View?.Get(cbs).Value ?? default;
|
||||
}
|
||||
|
||||
tu.Push<DescriptorImageInfo>(images[..count]);
|
||||
@@ -974,7 +947,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ref var texture = ref textures[i];
|
||||
ref var refs = ref _textureRefs[binding + i];
|
||||
|
||||
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
||||
texture.ImageView = refs.View?.Get(cbs).Value ?? default;
|
||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
||||
|
||||
if (texture.ImageView.Handle == 0)
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
[Flags]
|
||||
internal enum FeedbackLoopAspects
|
||||
{
|
||||
None = 0,
|
||||
Color = 1 << 0,
|
||||
Depth = 1 << 1,
|
||||
}
|
||||
}
|
||||
@@ -302,27 +302,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_depthStencil?.Storage?.AddStoreOpUsage(true);
|
||||
}
|
||||
|
||||
public void ClearBindings()
|
||||
{
|
||||
_depthStencil?.Storage.ClearBindings();
|
||||
|
||||
for (int i = 0; i < _colorsCanonical.Length; i++)
|
||||
{
|
||||
_colorsCanonical[i]?.Storage.ClearBindings();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBindings()
|
||||
{
|
||||
_depthStencil?.Storage.AddBinding(_depthStencil);
|
||||
|
||||
for (int i = 0; i < _colorsCanonical.Length; i++)
|
||||
{
|
||||
TextureView color = _colorsCanonical[i];
|
||||
color?.Storage.AddBinding(color);
|
||||
}
|
||||
}
|
||||
|
||||
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
||||
VulkanRenderer gd,
|
||||
Device device,
|
||||
|
||||
@@ -46,8 +46,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly bool SupportsViewportArray2;
|
||||
public readonly bool SupportsHostImportedMemory;
|
||||
public readonly bool SupportsDepthClipControl;
|
||||
public readonly bool SupportsAttachmentFeedbackLoop;
|
||||
public readonly bool SupportsDynamicAttachmentFeedbackLoop;
|
||||
public readonly uint SubgroupSize;
|
||||
public readonly SampleCountFlags SupportedSampleCounts;
|
||||
public readonly PortabilitySubsetFlags PortabilitySubset;
|
||||
@@ -86,8 +84,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
bool supportsViewportArray2,
|
||||
bool supportsHostImportedMemory,
|
||||
bool supportsDepthClipControl,
|
||||
bool supportsAttachmentFeedbackLoop,
|
||||
bool supportsDynamicAttachmentFeedbackLoop,
|
||||
uint subgroupSize,
|
||||
SampleCountFlags supportedSampleCounts,
|
||||
PortabilitySubsetFlags portabilitySubset,
|
||||
@@ -125,8 +121,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SupportsViewportArray2 = supportsViewportArray2;
|
||||
SupportsHostImportedMemory = supportsHostImportedMemory;
|
||||
SupportsDepthClipControl = supportsDepthClipControl;
|
||||
SupportsAttachmentFeedbackLoop = supportsAttachmentFeedbackLoop;
|
||||
SupportsDynamicAttachmentFeedbackLoop = supportsDynamicAttachmentFeedbackLoop;
|
||||
SubgroupSize = subgroupSize;
|
||||
SupportedSampleCounts = supportedSampleCounts;
|
||||
PortabilitySubset = portabilitySubset;
|
||||
|
||||
@@ -2,7 +2,6 @@ using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
@@ -34,7 +33,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly Action EndRenderPassDelegate;
|
||||
|
||||
protected PipelineDynamicState DynamicState;
|
||||
protected bool IsMainPipeline;
|
||||
private PipelineState _newState;
|
||||
private bool _graphicsStateDirty;
|
||||
private bool _computeStateDirty;
|
||||
@@ -87,9 +85,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private bool _tfEnabled;
|
||||
private bool _tfActive;
|
||||
|
||||
private FeedbackLoopAspects _feedbackLoop;
|
||||
private bool _passWritesDepthStencil;
|
||||
|
||||
private readonly PipelineColorBlendAttachmentState[] _storedBlend;
|
||||
public ulong DrawCount { get; private set; }
|
||||
public bool RenderPassActive { get; private set; }
|
||||
@@ -131,7 +126,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_descriptorSetUpdater.Initialize(IsMainPipeline);
|
||||
_descriptorSetUpdater.Initialize();
|
||||
|
||||
QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false);
|
||||
TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true);
|
||||
@@ -819,8 +814,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_newState.DepthTestEnable = depthTest.TestEnable;
|
||||
_newState.DepthWriteEnable = depthTest.WriteEnable;
|
||||
_newState.DepthCompareOp = depthTest.Func.Convert();
|
||||
|
||||
UpdatePassDepthStencil();
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
@@ -1086,8 +1079,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
|
||||
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
|
||||
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
|
||||
|
||||
UpdatePassDepthStencil();
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
@@ -1435,23 +1426,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMainPipeline)
|
||||
{
|
||||
FramebufferParams?.ClearBindings();
|
||||
}
|
||||
|
||||
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
||||
|
||||
if (IsMainPipeline)
|
||||
{
|
||||
FramebufferParams.AddBindings();
|
||||
|
||||
_newState.FeedbackLoopAspects = FeedbackLoopAspects.None;
|
||||
_bindingBarriersDirty = true;
|
||||
}
|
||||
|
||||
_passWritesDepthStencil = false;
|
||||
UpdatePassDepthStencil();
|
||||
UpdatePipelineAttachmentFormats();
|
||||
}
|
||||
|
||||
@@ -1518,82 +1493,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
|
||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute);
|
||||
}
|
||||
|
||||
private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects)
|
||||
{
|
||||
if (_feedbackLoop != aspects)
|
||||
{
|
||||
if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
||||
{
|
||||
DynamicState.SetFeedbackLoop(aspects);
|
||||
}
|
||||
else
|
||||
{
|
||||
_newState.FeedbackLoopAspects = aspects;
|
||||
}
|
||||
|
||||
_feedbackLoop = aspects;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool UpdateFeedbackLoop()
|
||||
{
|
||||
List<TextureView> hazards = _descriptorSetUpdater.FeedbackLoopHazards;
|
||||
|
||||
if ((hazards?.Count ?? 0) > 0)
|
||||
{
|
||||
FeedbackLoopAspects aspects = 0;
|
||||
|
||||
foreach (TextureView view in hazards)
|
||||
{
|
||||
// May need to enforce feedback loop layout here in the future.
|
||||
// Though technically, it should always work with the general layout.
|
||||
|
||||
if (view.Info.Format.IsDepthOrStencil())
|
||||
{
|
||||
if (_passWritesDepthStencil)
|
||||
{
|
||||
// If depth/stencil isn't written in the pass, it doesn't count as a feedback loop.
|
||||
|
||||
aspects |= FeedbackLoopAspects.Depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aspects |= FeedbackLoopAspects.Color;
|
||||
}
|
||||
}
|
||||
|
||||
return ChangeFeedbackLoop(aspects);
|
||||
}
|
||||
else if (_feedbackLoop != 0)
|
||||
{
|
||||
return ChangeFeedbackLoop(FeedbackLoopAspects.None);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdatePassDepthStencil()
|
||||
{
|
||||
if (!RenderPassActive)
|
||||
{
|
||||
_passWritesDepthStencil = false;
|
||||
}
|
||||
|
||||
// Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check.
|
||||
_passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable;
|
||||
}
|
||||
|
||||
private bool RecreateGraphicsPipelineIfNeeded()
|
||||
{
|
||||
if (AutoFlush.ShouldFlushDraw(DrawCount))
|
||||
@@ -1601,7 +1505,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Gd.FlushAllCommands();
|
||||
}
|
||||
|
||||
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
||||
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||
|
||||
if (_needsIndexBufferRebind && _indexBufferPattern == null)
|
||||
{
|
||||
@@ -1635,15 +1539,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_vertexBufferUpdater.Commit(Cbs);
|
||||
}
|
||||
|
||||
if (_bindingBarriersDirty)
|
||||
{
|
||||
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
||||
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
||||
|
||||
_bindingBarriersDirty = false;
|
||||
}
|
||||
|
||||
if (UpdateFeedbackLoop() || _graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
||||
if (_graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
||||
{
|
||||
if (!CreatePipeline(PipelineBindPoint.Graphics))
|
||||
{
|
||||
@@ -1652,9 +1548,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_graphicsStateDirty = false;
|
||||
Pbp = PipelineBindPoint.Graphics;
|
||||
|
||||
if (_bindingBarriersDirty)
|
||||
{
|
||||
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
||||
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
||||
|
||||
_bindingBarriersDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
|
||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Silk.NET.Vulkan;
|
||||
using Silk.NET.Vulkan.Extensions.EXT;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
@@ -22,8 +21,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
private Array4<float> _blendConstants;
|
||||
|
||||
private FeedbackLoopAspects _feedbackLoopAspects;
|
||||
|
||||
public uint ViewportsCount;
|
||||
public Array16<Viewport> Viewports;
|
||||
|
||||
@@ -35,8 +32,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Scissor = 1 << 2,
|
||||
Stencil = 1 << 3,
|
||||
Viewport = 1 << 4,
|
||||
FeedbackLoop = 1 << 5,
|
||||
All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop,
|
||||
All = Blend | DepthBias | Scissor | Stencil | Viewport,
|
||||
}
|
||||
|
||||
private DirtyFlags _dirty;
|
||||
@@ -103,22 +99,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFeedbackLoop(FeedbackLoopAspects aspects)
|
||||
{
|
||||
_feedbackLoopAspects = aspects;
|
||||
|
||||
_dirty |= DirtyFlags.FeedbackLoop;
|
||||
}
|
||||
|
||||
public void ForceAllDirty()
|
||||
{
|
||||
_dirty = DirtyFlags.All;
|
||||
}
|
||||
|
||||
public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer)
|
||||
public void ReplayIfDirty(Vk api, CommandBuffer commandBuffer)
|
||||
{
|
||||
Vk api = gd.Api;
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.Blend))
|
||||
{
|
||||
RecordBlend(api, commandBuffer);
|
||||
@@ -144,11 +131,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
RecordViewport(api, commandBuffer);
|
||||
}
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
||||
{
|
||||
RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer);
|
||||
}
|
||||
|
||||
_dirty = DirtyFlags.None;
|
||||
}
|
||||
|
||||
@@ -187,17 +169,5 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
|
||||
}
|
||||
}
|
||||
|
||||
private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer)
|
||||
{
|
||||
ImageAspectFlags aspects = (_feedbackLoopAspects & FeedbackLoopAspects.Color) != 0 ? ImageAspectFlags.ColorBit : 0;
|
||||
|
||||
if ((_feedbackLoopAspects & FeedbackLoopAspects.Depth) != 0)
|
||||
{
|
||||
aspects |= ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
|
||||
}
|
||||
|
||||
api.CmdSetAttachmentFeedbackLoopEnable(commandBuffer, aspects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_activeBufferMirrors = new();
|
||||
|
||||
CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer;
|
||||
|
||||
IsMainPipeline = true;
|
||||
}
|
||||
|
||||
private void CopyPendingQuery()
|
||||
@@ -237,7 +235,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (Pipeline != null && Pbp == PipelineBindPoint.Graphics)
|
||||
{
|
||||
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
||||
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
struct PipelineState : IDisposable
|
||||
{
|
||||
private const int RequiredSubgroupSize = 32;
|
||||
private const int MaxDynamicStatesCount = 9;
|
||||
|
||||
public PipelineUid Internal;
|
||||
|
||||
@@ -300,12 +299,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
|
||||
}
|
||||
|
||||
public FeedbackLoopAspects FeedbackLoopAspects
|
||||
{
|
||||
readonly get => (FeedbackLoopAspects)((Internal.Id8 >> 7) & 0x3);
|
||||
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFE7F) | (((ulong)value) << 7);
|
||||
}
|
||||
|
||||
public bool HasTessellationControlShader;
|
||||
public NativeArray<PipelineShaderStageCreateInfo> Stages;
|
||||
public PipelineLayout PipelineLayout;
|
||||
@@ -571,11 +564,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
|
||||
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
|
||||
bool supportsFeedbackLoopDynamicState = gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop;
|
||||
int dynamicStatesCount = supportsExtDynamicState ? 8 : 7;
|
||||
|
||||
DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount];
|
||||
|
||||
int dynamicStatesCount = 7;
|
||||
DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
|
||||
|
||||
dynamicStates[0] = DynamicState.Viewport;
|
||||
dynamicStates[1] = DynamicState.Scissor;
|
||||
@@ -587,12 +578,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (supportsExtDynamicState)
|
||||
{
|
||||
dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt;
|
||||
}
|
||||
|
||||
if (supportsFeedbackLoopDynamicState)
|
||||
{
|
||||
dynamicStates[dynamicStatesCount++] = DynamicState.AttachmentFeedbackLoopEnableExt;
|
||||
dynamicStates[7] = DynamicState.VertexInputBindingStrideExt;
|
||||
}
|
||||
|
||||
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo
|
||||
@@ -602,27 +588,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PDynamicStates = dynamicStates,
|
||||
};
|
||||
|
||||
PipelineCreateFlags flags = 0;
|
||||
|
||||
if (gd.Capabilities.SupportsAttachmentFeedbackLoop)
|
||||
{
|
||||
FeedbackLoopAspects aspects = FeedbackLoopAspects;
|
||||
|
||||
if ((aspects & FeedbackLoopAspects.Color) != 0)
|
||||
{
|
||||
flags |= PipelineCreateFlags.CreateColorAttachmentFeedbackLoopBitExt;
|
||||
}
|
||||
|
||||
if ((aspects & FeedbackLoopAspects.Depth) != 0)
|
||||
{
|
||||
flags |= PipelineCreateFlags.CreateDepthStencilAttachmentFeedbackLoopBitExt;
|
||||
}
|
||||
}
|
||||
|
||||
var pipelineCreateInfo = new GraphicsPipelineCreateInfo
|
||||
{
|
||||
SType = StructureType.GraphicsPipelineCreateInfo,
|
||||
Flags = flags,
|
||||
StageCount = StagesCount,
|
||||
PStages = Stages.Pointer,
|
||||
PVertexInputState = &vertexInputState,
|
||||
|
||||
@@ -4,7 +4,6 @@ using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Format = Ryujinx.Graphics.GAL.Format;
|
||||
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
||||
using VkFormat = Silk.NET.Vulkan.Format;
|
||||
@@ -13,11 +12,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class TextureStorage : IDisposable
|
||||
{
|
||||
private struct TextureSliceInfo
|
||||
{
|
||||
public int BindCount;
|
||||
}
|
||||
|
||||
private const MemoryPropertyFlags DefaultImageMemoryFlags =
|
||||
MemoryPropertyFlags.DeviceLocalBit;
|
||||
|
||||
@@ -49,7 +43,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly Image _image;
|
||||
private readonly Auto<DisposableImage> _imageAuto;
|
||||
private readonly Auto<MemoryAllocation> _allocationAuto;
|
||||
private readonly int _depthOrLayers;
|
||||
private Auto<MemoryAllocation> _foreignAllocationAuto;
|
||||
|
||||
private Dictionary<Format, TextureStorage> _aliasedStorages;
|
||||
@@ -62,9 +55,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private int _viewsCount;
|
||||
private readonly ulong _size;
|
||||
|
||||
private int _bindCount;
|
||||
private readonly TextureSliceInfo[] _slices;
|
||||
|
||||
public VkFormat VkFormat { get; }
|
||||
|
||||
public unsafe TextureStorage(
|
||||
@@ -85,7 +75,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1);
|
||||
|
||||
VkFormat = format;
|
||||
_depthOrLayers = info.GetDepthOrLayers();
|
||||
|
||||
var type = info.Target.Convert();
|
||||
|
||||
@@ -161,8 +150,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
InitialTransition(ImageLayout.Preinitialized, ImageLayout.General);
|
||||
}
|
||||
|
||||
_slices = new TextureSliceInfo[levels * _depthOrLayers];
|
||||
}
|
||||
|
||||
public TextureStorage CreateAliasedColorForDepthStorageUnsafe(Format format)
|
||||
@@ -325,12 +312,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
usage |= ImageUsageFlags.StorageBit;
|
||||
}
|
||||
|
||||
if (capabilities.SupportsAttachmentFeedbackLoop &&
|
||||
(usage & (ImageUsageFlags.DepthStencilAttachmentBit | ImageUsageFlags.ColorAttachmentBit)) != 0)
|
||||
{
|
||||
usage |= ImageUsageFlags.AttachmentFeedbackLoopBitExt;
|
||||
}
|
||||
|
||||
return usage;
|
||||
}
|
||||
|
||||
@@ -531,55 +512,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBinding(TextureView view)
|
||||
{
|
||||
// Assumes a view only has a first level.
|
||||
|
||||
int index = view.FirstLevel * _depthOrLayers + view.FirstLayer;
|
||||
int layers = view.Layers;
|
||||
|
||||
for (int i = 0; i < layers; i++)
|
||||
{
|
||||
ref TextureSliceInfo info = ref _slices[index++];
|
||||
|
||||
info.BindCount++;
|
||||
}
|
||||
|
||||
_bindCount++;
|
||||
}
|
||||
|
||||
public void ClearBindings()
|
||||
{
|
||||
if (_bindCount != 0)
|
||||
{
|
||||
Array.Clear(_slices, 0, _slices.Length);
|
||||
|
||||
_bindCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsBound(TextureView view)
|
||||
{
|
||||
if (_bindCount != 0)
|
||||
{
|
||||
int index = view.FirstLevel * _depthOrLayers + view.FirstLayer;
|
||||
int layers = view.Layers;
|
||||
|
||||
for (int i = 0; i < layers; i++)
|
||||
{
|
||||
ref TextureSliceInfo info = ref _slices[index++];
|
||||
|
||||
if (info.BindCount != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void IncrementViewsCount()
|
||||
{
|
||||
_viewsCount++;
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly Auto<DisposableImageView> _imageView2dArray;
|
||||
private Dictionary<Format, TextureView> _selfManagedViews;
|
||||
|
||||
private int _hazardUses;
|
||||
|
||||
private readonly TextureCreateInfo _info;
|
||||
|
||||
private HashTableSlim<RenderPassCacheKey, RenderPassHolder> _renderPasses;
|
||||
@@ -1039,34 +1037,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void PrepareForUsage(CommandBufferScoped cbs, PipelineStageFlags flags, List<TextureView> feedbackLoopHazards)
|
||||
{
|
||||
Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, flags);
|
||||
|
||||
if (feedbackLoopHazards != null && Storage.IsBound(this))
|
||||
{
|
||||
feedbackLoopHazards.Add(this);
|
||||
_hazardUses++;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearUsage(List<TextureView> feedbackLoopHazards)
|
||||
{
|
||||
if (_hazardUses != 0 && feedbackLoopHazards != null)
|
||||
{
|
||||
feedbackLoopHazards.Remove(this);
|
||||
_hazardUses--;
|
||||
}
|
||||
}
|
||||
|
||||
public void DecrementHazardUses()
|
||||
{
|
||||
if (_hazardUses != 0)
|
||||
{
|
||||
_hazardUses--;
|
||||
}
|
||||
}
|
||||
|
||||
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
||||
VulkanRenderer gd,
|
||||
Device device,
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DriverId.MesaDozen => "Dozen",
|
||||
DriverId.MesaNvk => "NVK",
|
||||
DriverId.ImaginationOpenSourceMesa => "Imagination (Open)",
|
||||
DriverId.MesaAgxv => "Honeykrisp",
|
||||
DriverId.MesaHoneykrisp => "Honeykrisp",
|
||||
_ => id.ToString(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,8 +44,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
"VK_EXT_4444_formats",
|
||||
"VK_KHR_8bit_storage",
|
||||
"VK_KHR_maintenance2",
|
||||
"VK_EXT_attachment_feedback_loop_layout",
|
||||
"VK_EXT_attachment_feedback_loop_dynamic_state",
|
||||
};
|
||||
|
||||
private static readonly string[] _requiredExtensions = {
|
||||
@@ -359,28 +357,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
features2.PNext = &supportedFeaturesDepthClipControl;
|
||||
}
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT supportedFeaturesAttachmentFeedbackLoopLayout = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||
PNext = features2.PNext,
|
||||
};
|
||||
|
||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout"))
|
||||
{
|
||||
features2.PNext = &supportedFeaturesAttachmentFeedbackLoopLayout;
|
||||
}
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT supportedFeaturesDynamicAttachmentFeedbackLoopLayout = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||
PNext = features2.PNext,
|
||||
};
|
||||
|
||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state"))
|
||||
{
|
||||
features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout;
|
||||
}
|
||||
|
||||
PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceVulkan12Features,
|
||||
@@ -555,36 +531,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
pExtendedFeatures = &featuresDepthClipControl;
|
||||
}
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoopLayout;
|
||||
|
||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout") &&
|
||||
supportedFeaturesAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopLayout)
|
||||
{
|
||||
featuresAttachmentFeedbackLoopLayout = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||
PNext = pExtendedFeatures,
|
||||
AttachmentFeedbackLoopLayout = true,
|
||||
};
|
||||
|
||||
pExtendedFeatures = &featuresAttachmentFeedbackLoopLayout;
|
||||
}
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoopLayout;
|
||||
|
||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state") &&
|
||||
supportedFeaturesDynamicAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopDynamicState)
|
||||
{
|
||||
featuresDynamicAttachmentFeedbackLoopLayout = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||
PNext = pExtendedFeatures,
|
||||
AttachmentFeedbackLoopDynamicState = true,
|
||||
};
|
||||
|
||||
pExtendedFeatures = &featuresDynamicAttachmentFeedbackLoopLayout;
|
||||
}
|
||||
|
||||
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
|
||||
|
||||
nint* ppEnabledExtensions = stackalloc nint[enabledExtensions.Length];
|
||||
|
||||
@@ -42,7 +42,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
internal KhrPushDescriptor PushDescriptorApi { get; private set; }
|
||||
internal ExtTransformFeedback TransformFeedbackApi { get; private set; }
|
||||
internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; }
|
||||
internal ExtAttachmentFeedbackLoopDynamicState DynamicFeedbackLoopApi { get; private set; }
|
||||
|
||||
internal uint QueueFamilyIndex { get; private set; }
|
||||
internal Queue Queue { get; private set; }
|
||||
@@ -156,11 +155,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DrawIndirectCountApi = drawIndirectCountApi;
|
||||
}
|
||||
|
||||
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtAttachmentFeedbackLoopDynamicState dynamicFeedbackLoopApi))
|
||||
{
|
||||
DynamicFeedbackLoopApi = dynamicFeedbackLoopApi;
|
||||
}
|
||||
|
||||
if (maxQueueCount >= 2)
|
||||
{
|
||||
Api.GetDeviceQueue(_device, queueFamilyIndex, 1, out var backgroundQueue);
|
||||
@@ -255,16 +249,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt,
|
||||
};
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoop = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||
};
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoop = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||
};
|
||||
|
||||
PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr,
|
||||
@@ -301,22 +285,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
features2.PNext = &featuresDepthClipControl;
|
||||
}
|
||||
|
||||
bool supportsAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout");
|
||||
|
||||
if (supportsAttachmentFeedbackLoop)
|
||||
{
|
||||
featuresAttachmentFeedbackLoop.PNext = features2.PNext;
|
||||
features2.PNext = &featuresAttachmentFeedbackLoop;
|
||||
}
|
||||
|
||||
bool supportsDynamicAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state");
|
||||
|
||||
if (supportsDynamicAttachmentFeedbackLoop)
|
||||
{
|
||||
featuresDynamicAttachmentFeedbackLoop.PNext = features2.PNext;
|
||||
features2.PNext = &featuresDynamicAttachmentFeedbackLoop;
|
||||
}
|
||||
|
||||
bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset");
|
||||
|
||||
if (usePortability)
|
||||
@@ -439,8 +407,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
|
||||
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
|
||||
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,
|
||||
supportsAttachmentFeedbackLoop && featuresAttachmentFeedbackLoop.AttachmentFeedbackLoopLayout,
|
||||
supportsDynamicAttachmentFeedbackLoop && featuresDynamicAttachmentFeedbackLoop.AttachmentFeedbackLoopDynamicState,
|
||||
propertiesSubgroup.SubgroupSize,
|
||||
supportedSampleCounts,
|
||||
portabilityFlags,
|
||||
|
||||
@@ -710,9 +710,8 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
updateNcasItem.Add((nca.Header.ContentType, entry.FullName));
|
||||
}
|
||||
else
|
||||
else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>()))
|
||||
{
|
||||
updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>());
|
||||
updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName));
|
||||
}
|
||||
}
|
||||
@@ -898,9 +897,8 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
updateNcasItem.Add((nca.Header.ContentType, entry.FullPath));
|
||||
}
|
||||
else
|
||||
else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>()))
|
||||
{
|
||||
updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>());
|
||||
updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullPath));
|
||||
}
|
||||
|
||||
|
||||
@@ -26,10 +26,20 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
_normalSession = normalSession;
|
||||
_interactiveSession = interactiveSession;
|
||||
|
||||
// TODO(jduncanator): Parse PlayerSelectConfig from input data
|
||||
_normalSession.Push(BuildResponse());
|
||||
|
||||
|
||||
UserProfile selected = _system.Device.UIHandler.ShowPlayerSelectDialog();
|
||||
if (selected == null)
|
||||
{
|
||||
_normalSession.Push(BuildResponse());
|
||||
}
|
||||
else if (selected.UserId == new UserId("00000000000000000000000000000080"))
|
||||
{
|
||||
_normalSession.Push(BuildGuestResponse());
|
||||
}
|
||||
else
|
||||
{
|
||||
_normalSession.Push(BuildResponse(selected));
|
||||
}
|
||||
AppletStateChanged?.Invoke(this, null);
|
||||
|
||||
_system.ReturnFocus();
|
||||
@@ -37,16 +47,34 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private byte[] BuildResponse()
|
||||
private byte[] BuildResponse(UserProfile selectedUser)
|
||||
{
|
||||
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
||||
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write((ulong)PlayerSelectResult.Success);
|
||||
|
||||
currentUser.UserId.Write(writer);
|
||||
selectedUser.UserId.Write(writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private byte[] BuildGuestResponse()
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write(new byte());
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private byte[] BuildResponse()
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write((ulong)PlayerSelectResult.Failure);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ namespace Ryujinx.HLE.HOS
|
||||
ProcessCreationInfo creationInfo = new("Service", 1, 0, 0x8000000, 1, Flags, 0, 0);
|
||||
|
||||
uint[] defaultCapabilities = {
|
||||
0x030363F7,
|
||||
(((uint)KScheduler.CpuCoresCount - 1) << 24) + (((uint)KScheduler.CpuCoresCount - 1) << 16) + 0x63F7u,
|
||||
0x1FFFFFCF,
|
||||
0x207FFFEF,
|
||||
0x47E0060F,
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
TickSource = tickSource;
|
||||
Device = device;
|
||||
Memory = memory;
|
||||
KScheduler.CpuCoresCount = device.CpuCoresCount;
|
||||
|
||||
Running = true;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return result;
|
||||
}
|
||||
|
||||
process.DefaultCpuCore = 3;
|
||||
process.DefaultCpuCore = KScheduler.CpuCoresCount - 1;
|
||||
|
||||
context.Processes.TryAdd(process.Pid, process);
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
return result;
|
||||
}
|
||||
|
||||
result = Capabilities.InitializeForUser(capabilities, MemoryManager);
|
||||
result = Capabilities.InitializeForUser(capabilities, MemoryManager, IsApplication);
|
||||
|
||||
if (result != Result.Success)
|
||||
{
|
||||
|
||||
@@ -35,15 +35,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
DebuggingFlags &= ~3u;
|
||||
KernelReleaseVersion = KProcess.KernelVersionPacked;
|
||||
|
||||
return Parse(capabilities, memoryManager);
|
||||
return Parse(capabilities, memoryManager, false);
|
||||
}
|
||||
|
||||
public Result InitializeForUser(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager)
|
||||
public Result InitializeForUser(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
return Parse(capabilities, memoryManager);
|
||||
return Parse(capabilities, memoryManager, isApplication);
|
||||
}
|
||||
|
||||
private Result Parse(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager)
|
||||
private Result Parse(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
int mask0 = 0;
|
||||
int mask1 = 0;
|
||||
@@ -54,7 +54,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
if (cap.GetCapabilityType() != CapabilityType.MapRange)
|
||||
{
|
||||
Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
|
||||
Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager, isApplication);
|
||||
|
||||
if (result != Result.Success)
|
||||
{
|
||||
@@ -120,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager)
|
||||
private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
CapabilityType code = cap.GetCapabilityType();
|
||||
|
||||
@@ -176,6 +176,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
AllowedCpuCoresMask = GetMaskFromMinMax(lowestCpuCore, highestCpuCore);
|
||||
AllowedThreadPriosMask = GetMaskFromMinMax(lowestThreadPrio, highestThreadPrio);
|
||||
|
||||
if (isApplication)
|
||||
Ryujinx.Common.Logging.Logger.Info?.Print(Ryujinx.Common.Logging.LogClass.Application, $"Application requested cores with index range {lowestCpuCore} to {highestCpuCore}");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -2683,7 +2683,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
if ((uint)preferredCore > 3)
|
||||
if ((uint)preferredCore > KScheduler.CpuCoresCount - 1)
|
||||
{
|
||||
if ((preferredCore | 2) != -1)
|
||||
{
|
||||
|
||||
@@ -9,13 +9,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
partial class KScheduler : IDisposable
|
||||
{
|
||||
public const int PrioritiesCount = 64;
|
||||
public const int CpuCoresCount = 4;
|
||||
public static int CpuCoresCount;
|
||||
|
||||
private const int RoundRobinTimeQuantumMs = 10;
|
||||
|
||||
private static readonly int[] _preemptionPriorities = { 59, 59, 59, 63 };
|
||||
|
||||
private static readonly int[] _srcCoresHighestPrioThreads = new int[CpuCoresCount];
|
||||
private static int[] _srcCoresHighestPrioThreads;
|
||||
|
||||
private readonly KernelContext _context;
|
||||
private readonly int _coreId;
|
||||
@@ -47,6 +45,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
_coreId = coreId;
|
||||
|
||||
_currentThread = null;
|
||||
|
||||
if (_srcCoresHighestPrioThreads == null)
|
||||
{
|
||||
_srcCoresHighestPrioThreads = new int[CpuCoresCount];
|
||||
}
|
||||
}
|
||||
|
||||
private static int PreemptionPriorities(int index)
|
||||
{
|
||||
return index == CpuCoresCount - 1 ? 63 : 59;
|
||||
}
|
||||
|
||||
public static ulong SelectThreads(KernelContext context)
|
||||
@@ -437,7 +445,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
for (int core = 0; core < CpuCoresCount; core++)
|
||||
{
|
||||
RotateScheduledQueue(context, core, _preemptionPriorities[core]);
|
||||
RotateScheduledQueue(context, core, PreemptionPriorities(core));
|
||||
}
|
||||
|
||||
context.CriticalSection.Leave();
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson);
|
||||
|
||||
return profilesJson.Profiles
|
||||
.FindFirst(profile => profile.AccountState == AccountState.Open)
|
||||
.FindFirst(profile => profile.UserId == profilesJson.LastOpened)
|
||||
.Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name,
|
||||
profileJson.Image, profileJson.LastModifiedTimestamp));
|
||||
}
|
||||
|
||||
BIN
src/Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg
Normal file
BIN
src/Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
@@ -659,7 +659,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filePath))
|
||||
{
|
||||
throw new InvalidSystemResourceException("JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/GreemDev/Ryujinx#requirements for more information)");
|
||||
throw new InvalidSystemResourceException("JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/Ryubing/Ryujinx#requirements for more information)");
|
||||
}
|
||||
|
||||
context.Device.LoadNca(filePath);
|
||||
|
||||
@@ -702,6 +702,18 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(92)]
|
||||
// SetGestureOutputRanges(pid, ushort Unknown0)
|
||||
public ResultCode SetGestureOutputRanges(ServiceCtx context)
|
||||
{
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
ushort unknown0 = context.RequestData.ReadUInt16();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { pid, unknown0 });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(100)]
|
||||
// SetSupportedNpadStyleSet(pid, nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
|
||||
titleName = "Unknown";
|
||||
}
|
||||
|
||||
throw new InvalidSystemResourceException($"{titleName} ({fontTitle:x8}) system title not found! This font will not work, provide the system archive to fix this error. (See https://github.com/GreemDev/Ryujinx#requirements for more information)");
|
||||
throw new InvalidSystemResourceException($"{titleName} ({fontTitle:x8}) system title not found! This font will not work, provide the system archive to fix this error. (See https://github.com/Ryubing/Ryujinx#requirements for more information)");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -24,14 +24,14 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
// not large enough.
|
||||
private const int PointerBufferSize = 0x8000;
|
||||
|
||||
private readonly static uint[] _defaultCapabilities = {
|
||||
0x030363F7,
|
||||
private static uint[] _defaultCapabilities => [
|
||||
(((uint)KScheduler.CpuCoresCount - 1) << 24) + (((uint)KScheduler.CpuCoresCount - 1) << 16) + 0x63F7u,
|
||||
0x1FFFFFCF,
|
||||
0x207FFFEF,
|
||||
0x47E0060F,
|
||||
0x0048BFFF,
|
||||
0x01007FFF,
|
||||
};
|
||||
];
|
||||
|
||||
// The amount of time Dispose() will wait to Join() the thread executing the ServerLoop()
|
||||
private static readonly TimeSpan _threadJoinTimeout = TimeSpan.FromSeconds(3);
|
||||
|
||||
@@ -244,6 +244,15 @@ namespace Ryujinx.HLE.HOS.Services.Settings
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(68)]
|
||||
// GetSerialNumber() -> buffer<nn::settings::system::SerialNumber, 0x16>
|
||||
public ResultCode GetSerialNumber(ServiceCtx context)
|
||||
{
|
||||
context.ResponseData.Write(Encoding.ASCII.GetBytes("RYU00000000000"));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(77)]
|
||||
// GetDeviceNickName() -> buffer<nn::settings::system::DeviceNickName, 0x16>
|
||||
public ResultCode GetDeviceNickName(ServiceCtx context)
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace Ryujinx.HLE.HOS.Services.Spl
|
||||
|
||||
context.ResponseData.Write(configValue);
|
||||
|
||||
if (result == SmcResult.Success)
|
||||
return ResultCode.Success;
|
||||
|
||||
return (ResultCode)((int)result << 9) | ResultCode.ModuleId;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,17 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
private ulong _latestPid;
|
||||
|
||||
public ProcessResult ActiveApplication => _processesByPid[_latestPid];
|
||||
public ProcessResult ActiveApplication
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_processesByPid.TryGetValue(_latestPid, out ProcessResult value))
|
||||
throw new RyujinxException(
|
||||
$"The HLE Process map did not have a process with ID {_latestPid}. Are you missing firmware?");
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public ProcessLoader(Switch device)
|
||||
{
|
||||
|
||||
@@ -161,5 +161,20 @@ namespace Ryujinx.HLE
|
||||
{
|
||||
return 1000 / _frameRate[FrameTypeGame];
|
||||
}
|
||||
|
||||
public string FormatGameFrameRate()
|
||||
{
|
||||
double frameRate = GetGameFrameRate();
|
||||
double frameTime = GetGameFrameTime();
|
||||
|
||||
return $"{frameRate:00.00} FPS ({frameTime:00.00}ms)";
|
||||
}
|
||||
|
||||
public string FormatFifoPercent()
|
||||
{
|
||||
double fifoPercent = GetFifoPercent();
|
||||
|
||||
return $"FIFO: {fifoPercent:00.00}%";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_BtnB.png" />
|
||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_KeyF6.png" />
|
||||
<EmbeddedResource Include="HOS\Services\Account\Acc\DefaultUserImage.jpg" />
|
||||
<EmbeddedResource Include="HOS\Services\Account\Acc\GuestUserImage.jpg" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -32,8 +32,10 @@ namespace Ryujinx.HLE
|
||||
public TamperMachine TamperMachine { get; }
|
||||
public IHostUIHandler UIHandler { get; }
|
||||
|
||||
public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch;
|
||||
public bool CustomVSyncIntervalEnabled { get; set; } = false;
|
||||
public int CpuCoresCount = 4; //Switch 1 has 4 cores
|
||||
|
||||
public VSyncMode VSyncMode { get; set; }
|
||||
public bool CustomVSyncIntervalEnabled { get; set; }
|
||||
public int CustomVSyncInterval { get; set; }
|
||||
|
||||
public long TargetVSyncInterval { get; set; } = 60;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
|
||||
namespace Ryujinx.HLE.UI
|
||||
@@ -59,5 +60,11 @@ namespace Ryujinx.HLE.UI
|
||||
/// Gets fonts and colors used by the host.
|
||||
/// </summary>
|
||||
IHostUITheme HostUITheme { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Displays the player select dialog and returns the selected profile.
|
||||
/// </summary>
|
||||
UserProfile ShowPlayerSelectDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.HOS.Services.Hid;
|
||||
using SDL2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
@@ -85,7 +88,7 @@ namespace Ryujinx.Input.SDL2
|
||||
Id = driverId;
|
||||
Features = GetFeaturesFlag();
|
||||
_triggerThreshold = 0.0f;
|
||||
|
||||
|
||||
// Enable motion tracking
|
||||
if (Features.HasFlag(GamepadFeaturesFlag.Motion))
|
||||
{
|
||||
@@ -101,6 +104,18 @@ namespace Ryujinx.Input.SDL2
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLed(uint packedRgb)
|
||||
{
|
||||
if (!Features.HasFlag(GamepadFeaturesFlag.Led)) return;
|
||||
|
||||
byte red = packedRgb > 0 ? (byte)(packedRgb >> 16) : (byte)0;
|
||||
byte green = packedRgb > 0 ? (byte)(packedRgb >> 8) : (byte)0;
|
||||
byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0;
|
||||
|
||||
if (SDL_GameControllerSetLED(_gamepadHandle, red, green, blue) != 0)
|
||||
Logger.Error?.Print(LogClass.Hid, "LED is not supported on this game controller.");
|
||||
}
|
||||
|
||||
private GamepadFeaturesFlag GetFeaturesFlag()
|
||||
{
|
||||
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
|
||||
@@ -111,13 +126,16 @@ namespace Ryujinx.Input.SDL2
|
||||
result |= GamepadFeaturesFlag.Motion;
|
||||
}
|
||||
|
||||
int error = SDL_GameControllerRumble(_gamepadHandle, 0, 0, 100);
|
||||
|
||||
if (error == 0)
|
||||
if (SDL_GameControllerHasRumble(_gamepadHandle) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Rumble;
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasLED(_gamepadHandle) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Led;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -130,6 +148,8 @@ namespace Ryujinx.Input.SDL2
|
||||
{
|
||||
if (disposing && _gamepadHandle != nint.Zero)
|
||||
{
|
||||
Rainbow.Updated -= RainbowColorChanged;
|
||||
|
||||
SDL_GameControllerClose(_gamepadHandle);
|
||||
|
||||
_gamepadHandle = nint.Zero;
|
||||
@@ -208,12 +228,41 @@ namespace Ryujinx.Input.SDL2
|
||||
|
||||
private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
|
||||
|
||||
private void RainbowColorChanged(int packedRgb)
|
||||
{
|
||||
if (!_configuration.Led.UseRainbow) return;
|
||||
|
||||
SetLed((uint)packedRgb);
|
||||
}
|
||||
|
||||
private bool _rainbowColorEnabled;
|
||||
|
||||
public void SetConfiguration(InputConfig configuration)
|
||||
{
|
||||
lock (_userMappingLock)
|
||||
{
|
||||
_configuration = (StandardControllerInputConfig)configuration;
|
||||
|
||||
if (Features.HasFlag(GamepadFeaturesFlag.Led) && _configuration.Led.EnableLed)
|
||||
{
|
||||
if (_configuration.Led.TurnOffLed)
|
||||
(this as IGamepad).ClearLed();
|
||||
else switch (_configuration.Led.UseRainbow)
|
||||
{
|
||||
case true when !_rainbowColorEnabled:
|
||||
Rainbow.Updated += RainbowColorChanged;
|
||||
_rainbowColorEnabled = true;
|
||||
break;
|
||||
case false when _rainbowColorEnabled:
|
||||
Rainbow.Updated -= RainbowColorChanged;
|
||||
_rainbowColorEnabled = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_configuration.Led.TurnOffLed && !_rainbowColorEnabled)
|
||||
SetLed(_configuration.Led.LedColor);
|
||||
}
|
||||
|
||||
_buttonsUserMapping.Clear();
|
||||
|
||||
// First update sticks
|
||||
|
||||
@@ -173,5 +173,16 @@ namespace Ryujinx.Input.SDL2
|
||||
|
||||
return new SDL2Gamepad(gamepadHandle, id);
|
||||
}
|
||||
|
||||
public IEnumerable<IGamepad> GetGamepads()
|
||||
{
|
||||
lock (_gamepadsIds)
|
||||
{
|
||||
foreach (string gamepadId in _gamepadsIds)
|
||||
{
|
||||
yield return GetGamepad(gamepadId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
@@ -385,6 +386,11 @@ namespace Ryujinx.Input.SDL2
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLed(uint packedRgb)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Keyboard");
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
// No operations
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
@@ -76,6 +77,11 @@ namespace Ryujinx.Input.SDL2
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetLed(uint packedRgb)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Mouse");
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Numerics;
|
||||
@@ -164,6 +165,8 @@ namespace Ryujinx.Input.SDL2
|
||||
return new SDL2Mouse(this);
|
||||
}
|
||||
|
||||
public IEnumerable<IGamepad> GetGamepads() => [GetGamepad("0")];
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.SDL2.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Input.SDL2
|
||||
{
|
||||
@@ -51,5 +52,13 @@ namespace Ryujinx.Input.SDL2
|
||||
|
||||
return new SDL2Keyboard(this, _keyboardIdentifers[0], "All keyboards");
|
||||
}
|
||||
|
||||
public IEnumerable<IGamepad> GetGamepads()
|
||||
{
|
||||
foreach (var keyboardId in _keyboardIdentifers)
|
||||
{
|
||||
yield return GetGamepad(keyboardId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,5 +24,10 @@ namespace Ryujinx.Input
|
||||
/// <remarks>Also named sixaxis</remarks>
|
||||
/// </summary>
|
||||
Motion,
|
||||
|
||||
/// <summary>
|
||||
/// The LED on the back of modern PlayStation controllers (DualSense & DualShock 4).
|
||||
/// </summary>
|
||||
Led,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,15 @@ namespace Ryujinx.Input
|
||||
/// <param name="configuration">The configuration of the gamepad</param>
|
||||
void SetConfiguration(InputConfig configuration);
|
||||
|
||||
/// <summary>
|
||||
/// Set the LED on the gamepad to a given color.
|
||||
/// </summary>
|
||||
/// <remarks>Does nothing on a controller without LED functionality.</remarks>
|
||||
/// <param name="packedRgb">The packed RGB integer.</param>
|
||||
void SetLed(uint packedRgb);
|
||||
|
||||
public void ClearLed() => SetLed(0);
|
||||
|
||||
/// <summary>
|
||||
/// Starts a rumble effect on the gamepad.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Input
|
||||
{
|
||||
@@ -33,6 +34,11 @@ namespace Ryujinx.Input
|
||||
/// <param name="id">The unique id of the gamepad</param>
|
||||
/// <returns>An instance of <see cref="IGamepad"/> associated to the gamepad id given or null if not found</returns>
|
||||
IGamepad GetGamepad(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an <see cref="IEnumerable{T}"/> of the connected gamepads.
|
||||
/// </summary>
|
||||
IEnumerable<IGamepad> GetGamepads();
|
||||
|
||||
/// <summary>
|
||||
/// Clear the internal state of the driver.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Controller_JoyConLeft.svg" />
|
||||
<None Remove="Resources\Controller_JoyConPair.svg" />
|
||||
<None Remove="Resources\Controller_JoyConRight.svg" />
|
||||
<None Remove="Resources\Controller_ProCon.svg" />
|
||||
<None Remove="Resources\Icon_NCA.png" />
|
||||
<None Remove="Resources\Icon_NRO.png" />
|
||||
<None Remove="Resources\Icon_NSO.png" />
|
||||
<None Remove="Resources\Icon_NSP.png" />
|
||||
<None Remove="Resources\Icon_XCI.png" />
|
||||
<None Remove="Resources\Logo_Amiibo.png" />
|
||||
<None Remove="Resources\Logo_Discord.png" />
|
||||
<None Remove="Resources\Logo_GitHub.png" />
|
||||
<None Remove="Resources\Logo_Ryujinx.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscordRichPresence" />
|
||||
<PackageReference Include="DynamicData" />
|
||||
<PackageReference Include="securifybv.ShellLink" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -19,7 +19,7 @@ namespace Ryujinx.UI.LocaleGenerator
|
||||
|
||||
StringBuilder enumSourceBuilder = new();
|
||||
enumSourceBuilder.AppendLine("namespace Ryujinx.Ava.Common.Locale;");
|
||||
enumSourceBuilder.AppendLine("internal enum LocaleKeys");
|
||||
enumSourceBuilder.AppendLine("public enum LocaleKeys");
|
||||
enumSourceBuilder.AppendLine("{");
|
||||
foreach (var line in lines)
|
||||
{
|
||||
|
||||
@@ -489,7 +489,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device.Processes.ActiveApplication, Program.Version);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar);
|
||||
});
|
||||
|
||||
_viewModel.SetUiProgressHandlers(Device);
|
||||
@@ -501,6 +501,8 @@ namespace Ryujinx.Ava
|
||||
_renderingThread.Start();
|
||||
|
||||
_viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value;
|
||||
|
||||
Rainbow.Enable();
|
||||
|
||||
MainLoop();
|
||||
|
||||
@@ -587,6 +589,15 @@ namespace Ryujinx.Ava
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (IGamepad gamepad in RyujinxApp.MainWindow.InputManager.GamepadDriver.GetGamepads())
|
||||
{
|
||||
gamepad?.ClearLed();
|
||||
gamepad?.Dispose();
|
||||
}
|
||||
|
||||
Rainbow.Disable();
|
||||
Rainbow.Reset();
|
||||
|
||||
_isStopped = true;
|
||||
Stop();
|
||||
}
|
||||
@@ -674,7 +685,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||
{
|
||||
InitializeSwitchInstance();
|
||||
InitEmulatedSwitch();
|
||||
MainWindow.UpdateGraphicsConfig();
|
||||
|
||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||
@@ -757,6 +768,8 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
romFsFiles = Directory.GetFiles(ApplicationPath, "*.romfs");
|
||||
}
|
||||
|
||||
Logger.Notice.Print(LogClass.Application, $"Loading unpacked content archive from '{ApplicationPath}'.");
|
||||
|
||||
if (romFsFiles.Length > 0)
|
||||
{
|
||||
@@ -783,6 +796,8 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else if (File.Exists(ApplicationPath))
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Loading content archive from '{ApplicationPath}'.");
|
||||
|
||||
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
{
|
||||
case ".xci":
|
||||
@@ -872,7 +887,7 @@ namespace Ryujinx.Ava
|
||||
Device?.System.TogglePauseEmulation(false);
|
||||
|
||||
_viewModel.IsPaused = false;
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar);
|
||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed");
|
||||
}
|
||||
|
||||
@@ -881,11 +896,11 @@ namespace Ryujinx.Ava
|
||||
Device?.System.TogglePauseEmulation(true);
|
||||
|
||||
_viewModel.IsPaused = true;
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, LocaleManager.Instance[LocaleKeys.Paused]);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar, LocaleManager.Instance[LocaleKeys.Paused]);
|
||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused");
|
||||
}
|
||||
|
||||
private void InitializeSwitchInstance()
|
||||
private void InitEmulatedSwitch()
|
||||
{
|
||||
// Initialize KeySet.
|
||||
VirtualFileSystem.ReloadKeySet();
|
||||
@@ -1040,7 +1055,7 @@ namespace Ryujinx.Ava
|
||||
_viewModel.WindowState = WindowState.FullScreen;
|
||||
}
|
||||
|
||||
if (_viewModel.WindowState is WindowState.FullScreen)
|
||||
if (_viewModel.WindowState is WindowState.FullScreen || _viewModel.StartGamesWithoutUI)
|
||||
{
|
||||
_viewModel.ShowMenuAndStatusBar = false;
|
||||
}
|
||||
@@ -1147,8 +1162,8 @@ namespace Ryujinx.Ava
|
||||
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
|
||||
dockedMode,
|
||||
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
||||
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
||||
Device.Statistics.FormatGameFrameRate(),
|
||||
Device.Statistics.FormatFifoPercent(),
|
||||
_displayCount));
|
||||
}
|
||||
|
||||
|
||||
10
src/Ryujinx/Assets/Fonts/Mono/AUTHORS.txt
Normal file
10
src/Ryujinx/Assets/Fonts/Mono/AUTHORS.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
# This is the official list of project authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS.txt file.
|
||||
# See the latter for an explanation.
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
|
||||
JetBrains <>
|
||||
Philipp Nurullin <philipp.nurullin@jetbrains.com>
|
||||
Konstantin Bulenkov <kb@jetbrains.com>
|
||||
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Bold.ttf
Normal file
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Bold.ttf
Normal file
Binary file not shown.
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-BoldItalic.ttf
Normal file
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Italic.ttf
Normal file
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Italic.ttf
Normal file
Binary file not shown.
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Regular.ttf
Normal file
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Regular.ttf
Normal file
Binary file not shown.
93
src/Ryujinx/Assets/Fonts/Mono/OFL.txt
Normal file
93
src/Ryujinx/Assets/Fonts/Mono/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
13
src/Ryujinx/Assets/Styles/CheckboxMenuItemStyle.axaml
Normal file
13
src/Ryujinx/Assets/Styles/CheckboxMenuItemStyle.axaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style Selector="MenuItem.withCheckbox Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="MenuItem.withCheckbox ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</Styles>
|
||||
|
||||
@@ -402,7 +402,7 @@
|
||||
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
|
||||
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
||||
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxWidth">700</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxWidth">900</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
|
||||
</Styles.Resources>
|
||||
</Styles>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
using Avalonia.Controls.Notifications;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Threading;
|
||||
using Gommon;
|
||||
using LibHac;
|
||||
using LibHac.Account;
|
||||
using LibHac.Common;
|
||||
@@ -15,6 +15,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common.Helper;
|
||||
using Ryujinx.Common.Logging;
|
||||
@@ -295,22 +296,150 @@ namespace Ryujinx.Ava.Common
|
||||
};
|
||||
extractorThread.Start();
|
||||
}
|
||||
|
||||
public static void ExtractAoc(string destination, string updateFilePath, string updateName)
|
||||
{
|
||||
var cancellationToken = new CancellationTokenSource();
|
||||
|
||||
UpdateWaitWindow waitingDialog = new(
|
||||
RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle),
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, NcaSectionType.Data, Path.GetFileName(updateFilePath)),
|
||||
cancellationToken);
|
||||
|
||||
Thread extractorThread = new(() =>
|
||||
{
|
||||
Dispatcher.UIThread.Post(waitingDialog.Show);
|
||||
|
||||
using FileStream file = new(updateFilePath, FileMode.Open, FileAccess.Read);
|
||||
|
||||
Nca publicDataNca = null;
|
||||
|
||||
string extension = Path.GetExtension(updateFilePath).ToLower();
|
||||
if (extension is ".nsp")
|
||||
{
|
||||
var pfsTemp = new PartitionFileSystem();
|
||||
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
|
||||
IFileSystem pfs = pfsTemp;
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||
{
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
||||
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage());
|
||||
if (nca.Header.ContentType is NcaContentType.PublicData && nca.SectionExists(NcaSectionType.Data))
|
||||
{
|
||||
publicDataNca = nca;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (publicDataNca is null)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "Extraction failure. The NCA was not present in the selected file");
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
waitingDialog.Close();
|
||||
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
|
||||
int index = Nca.GetSectionIndexFromType(NcaSectionType.Data, publicDataNca.Header.ContentType);
|
||||
|
||||
try
|
||||
{
|
||||
IFileSystem ncaFileSystem = publicDataNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid);
|
||||
|
||||
FileSystemClient fsClient = _horizonClient.Fs;
|
||||
|
||||
string source = DateTime.Now.ToFileTime().ToString()[10..];
|
||||
string output = DateTime.Now.ToFileTime().ToString()[10..];
|
||||
|
||||
using var uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
|
||||
using var uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
|
||||
|
||||
fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
|
||||
fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);
|
||||
|
||||
(Result? resultCode, bool canceled) = CopyDirectory(fsClient, $"{source}:/", $"{output}:/", cancellationToken.Token);
|
||||
|
||||
if (!canceled)
|
||||
{
|
||||
if (resultCode.Value.IsFailure())
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}");
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
waitingDialog.Close();
|
||||
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
|
||||
});
|
||||
}
|
||||
else if (resultCode.Value.IsSuccess())
|
||||
{
|
||||
Dispatcher.UIThread.Post(waitingDialog.Close);
|
||||
|
||||
NotificationHelper.ShowInformation(
|
||||
RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle),
|
||||
$"{updateName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}");
|
||||
}
|
||||
}
|
||||
|
||||
fsClient.Unmount(source.ToU8Span());
|
||||
fsClient.Unmount(output.ToU8Span());
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"{ex.Message}");
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
waitingDialog.Close();
|
||||
|
||||
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
||||
});
|
||||
}
|
||||
})
|
||||
{
|
||||
Name = "GUI.AocExtractorThread",
|
||||
IsBackground = true,
|
||||
};
|
||||
extractorThread.Start();
|
||||
}
|
||||
|
||||
public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName)
|
||||
{
|
||||
Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||
});
|
||||
|
||||
if (!result.HasValue) return;
|
||||
|
||||
ExtractAoc(result.Value.Path.LocalPath, updateFilePath, updateName);
|
||||
}
|
||||
|
||||
|
||||
public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
|
||||
{
|
||||
var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||
AllowMultiple = false,
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||
});
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!result.HasValue) return;
|
||||
|
||||
ExtractSection(result[0].Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex);
|
||||
ExtractSection(result.Value.Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex);
|
||||
}
|
||||
|
||||
public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Ryujinx.Ava.Common.Models
|
||||
public bool IsBundled { get; } = System.IO.Path.GetExtension(ContainerPath)?.ToLower() == ".xci";
|
||||
|
||||
public string FileName => System.IO.Path.GetFileName(ContainerPath);
|
||||
public string TitleIdStr => TitleId.ToString("x16");
|
||||
public string TitleIdStr => TitleId.ToString("x16").ToUpper();
|
||||
public ulong TitleIdBase => TitleId & ~0x1FFFUL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ namespace Ryujinx.Ava.Common
|
||||
{
|
||||
public static class ThemeManager
|
||||
{
|
||||
public static event EventHandler ThemeChanged;
|
||||
public static event Action ThemeChanged;
|
||||
|
||||
public static void OnThemeChanged()
|
||||
{
|
||||
ThemeChanged?.Invoke(null, EventArgs.Empty);
|
||||
ThemeChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using DiscordRPC;
|
||||
using Gommon;
|
||||
using Humanizer;
|
||||
using Humanizer.Localisation;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
@@ -45,16 +47,7 @@ namespace Ryujinx.Ava
|
||||
};
|
||||
|
||||
ConfigurationState.Instance.EnableDiscordIntegration.Event += Update;
|
||||
TitleIDs.CurrentApplication.Event += (_, e) =>
|
||||
{
|
||||
if (e.NewValue)
|
||||
SwitchToPlayingState(
|
||||
ApplicationLibrary.LoadAndSaveMetaData(e.NewValue),
|
||||
Switch.Shared.Processes.ActiveApplication
|
||||
);
|
||||
else
|
||||
SwitchToMainState();
|
||||
};
|
||||
TitleIDs.CurrentApplication.Event += (_, e) => Use(e.NewValue);
|
||||
}
|
||||
|
||||
private static void Update(object sender, ReactiveEventArgs<bool> evnt)
|
||||
@@ -75,11 +68,23 @@ namespace Ryujinx.Ava
|
||||
_discordClient = new DiscordRpcClient(ApplicationId);
|
||||
|
||||
_discordClient.Initialize();
|
||||
_discordClient.SetPresence(_discordPresenceMain);
|
||||
|
||||
Use(TitleIDs.CurrentApplication);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Use(Optional<string> titleId)
|
||||
{
|
||||
if (titleId.TryGet(out string tid))
|
||||
SwitchToPlayingState(
|
||||
ApplicationLibrary.LoadAndSaveMetaData(tid),
|
||||
Switch.Shared.Processes.ActiveApplication
|
||||
);
|
||||
else
|
||||
SwitchToMainState();
|
||||
}
|
||||
|
||||
private static void SwitchToPlayingState(ApplicationMetadata appMeta, ProcessResult procRes)
|
||||
{
|
||||
_discordClient?.SetPresence(new RichPresence
|
||||
@@ -93,7 +98,7 @@ namespace Ryujinx.Ava
|
||||
},
|
||||
Details = TruncateToByteLength($"Playing {appMeta.Title}"),
|
||||
State = appMeta.LastPlayed.HasValue && appMeta.TimePlayed.TotalSeconds > 5
|
||||
? $"Total play time: {appMeta.TimePlayed.Humanize(2, false, maxUnit: TimeUnit.Hour)}"
|
||||
? $"Total play time: {ValueFormatUtils.FormatTimeSpan(appMeta.TimePlayed)}"
|
||||
: "Never played",
|
||||
Timestamps = Timestamps.Now
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using DiscordRPC;
|
||||
using DiscordRPC;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using Ryujinx.Audio.Backends.SDL2;
|
||||
using Ryujinx.Ava;
|
||||
|
||||
@@ -5,7 +5,6 @@ using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.GraphicsDriver;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Logging.Targets;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
@@ -228,8 +227,6 @@ namespace Ryujinx.Headless
|
||||
_inputConfiguration ??= [];
|
||||
_enableKeyboard = option.EnableKeyboard;
|
||||
_enableMouse = option.EnableMouse;
|
||||
|
||||
|
||||
|
||||
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1);
|
||||
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
|
||||
@@ -287,8 +284,6 @@ namespace Ryujinx.Headless
|
||||
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
|
||||
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
|
||||
|
||||
DriverUtilities.InitDriverConfig(option.BackendThreading == BackendThreading.Off);
|
||||
|
||||
while (true)
|
||||
{
|
||||
LoadApplication(option);
|
||||
@@ -301,7 +296,10 @@ namespace Ryujinx.Headless
|
||||
_userChannelPersistence.ShouldRestart = false;
|
||||
}
|
||||
|
||||
_inputManager.Dispose();
|
||||
try
|
||||
{
|
||||
_inputManager.Dispose();
|
||||
} catch {}
|
||||
|
||||
return;
|
||||
|
||||
@@ -338,12 +336,12 @@ namespace Ryujinx.Headless
|
||||
{
|
||||
string label = state switch
|
||||
{
|
||||
LoadState => $"PTC : {current}/{total}",
|
||||
ShaderCacheState => $"Shaders : {current}/{total}",
|
||||
_ => throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}"),
|
||||
LoadState => "PTC",
|
||||
ShaderCacheState => "Shaders",
|
||||
_ => throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}")
|
||||
};
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, label);
|
||||
Logger.Info?.Print(LogClass.Application, $"{label} : {current}/{total}");
|
||||
}
|
||||
|
||||
private static WindowBase CreateWindow(Options options)
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace Ryujinx.Headless
|
||||
IgnoreMissingServices = configurationState.System.IgnoreMissingServices;
|
||||
|
||||
if (NeedsOverride(nameof(IgnoreControllerApplet)))
|
||||
IgnoreControllerApplet = configurationState.IgnoreApplet;
|
||||
IgnoreControllerApplet = configurationState.System.IgnoreApplet;
|
||||
|
||||
return;
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.9 KiB |
@@ -1,21 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Headless
|
||||
{
|
||||
class StatusUpdatedEventArgs(
|
||||
string vSyncMode,
|
||||
string dockedMode,
|
||||
string aspectRatio,
|
||||
string gameStatus,
|
||||
string fifoStatus,
|
||||
string gpuName)
|
||||
: EventArgs
|
||||
{
|
||||
public string VSyncMode = vSyncMode;
|
||||
public string DockedMode = dockedMode;
|
||||
public string AspectRatio = aspectRatio;
|
||||
public string GameStatus = gameStatus;
|
||||
public string FifoStatus = fifoStatus;
|
||||
public string GpuName = gpuName;
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace Ryujinx.Headless
|
||||
bool ignoreControllerApplet)
|
||||
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet) { }
|
||||
|
||||
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_METAL;
|
||||
public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_METAL;
|
||||
|
||||
protected override void InitializeWindowRenderer()
|
||||
{
|
||||
@@ -108,8 +108,7 @@ namespace Ryujinx.Headless
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly GraphicsDebugLevel _glLogLevel;
|
||||
|
||||
private SDL2OpenGLContext _openGLContext;
|
||||
|
||||
public OpenGLWindow(
|
||||
@@ -121,15 +120,14 @@ namespace Ryujinx.Headless
|
||||
bool ignoreControllerApplet)
|
||||
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
|
||||
{
|
||||
_glLogLevel = glLogLevel;
|
||||
}
|
||||
|
||||
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_OPENGL;
|
||||
public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_OPENGL;
|
||||
|
||||
protected override void InitializeWindowRenderer()
|
||||
{
|
||||
// Ensure to not share this context with other contexts before this point.
|
||||
SetupOpenGLAttributes(false, _glLogLevel);
|
||||
SetupOpenGLAttributes(false, GlLogLevel);
|
||||
nint context = SDL_GL_CreateContext(WindowHandle);
|
||||
CheckResult(SDL_GL_SetSwapInterval(1));
|
||||
|
||||
@@ -10,8 +10,6 @@ namespace Ryujinx.Headless
|
||||
{
|
||||
class VulkanWindow : WindowBase
|
||||
{
|
||||
private readonly GraphicsDebugLevel _glLogLevel;
|
||||
|
||||
public VulkanWindow(
|
||||
InputManager inputManager,
|
||||
GraphicsDebugLevel glLogLevel,
|
||||
@@ -21,10 +19,9 @@ namespace Ryujinx.Headless
|
||||
bool ignoreControllerApplet)
|
||||
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
|
||||
{
|
||||
_glLogLevel = glLogLevel;
|
||||
}
|
||||
|
||||
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_VULKAN;
|
||||
public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_VULKAN;
|
||||
|
||||
protected override void InitializeWindowRenderer() { }
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using Humanizer;
|
||||
using LibHac.Tools.Fs;
|
||||
using Ryujinx.Ava;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
using Ryujinx.HLE.UI;
|
||||
using Ryujinx.Input;
|
||||
@@ -26,6 +27,7 @@ using static SDL2.SDL;
|
||||
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
||||
using Switch = Ryujinx.HLE.Switch;
|
||||
using UserProfile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
||||
|
||||
namespace Ryujinx.Headless
|
||||
{
|
||||
@@ -53,8 +55,6 @@ namespace Ryujinx.Headless
|
||||
public Switch Device { get; private set; }
|
||||
public IRenderer Renderer { get; private set; }
|
||||
|
||||
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
||||
|
||||
protected nint WindowHandle { get; set; }
|
||||
|
||||
public IHostUITheme HostUITheme { get; }
|
||||
@@ -72,7 +72,7 @@ namespace Ryujinx.Headless
|
||||
protected SDL2MouseDriver MouseDriver;
|
||||
private readonly InputManager _inputManager;
|
||||
private readonly IKeyboard _keyboardInterface;
|
||||
private readonly GraphicsDebugLevel _glLogLevel;
|
||||
protected readonly GraphicsDebugLevel GlLogLevel;
|
||||
private readonly Stopwatch _chrono;
|
||||
private readonly long _ticksPerFrame;
|
||||
private readonly CancellationTokenSource _gpuCancellationTokenSource;
|
||||
@@ -104,7 +104,7 @@ namespace Ryujinx.Headless
|
||||
NpadManager = _inputManager.CreateNpadManager();
|
||||
TouchScreenManager = _inputManager.CreateTouchScreenManager();
|
||||
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
|
||||
_glLogLevel = glLogLevel;
|
||||
GlLogLevel = glLogLevel;
|
||||
_chrono = new Stopwatch();
|
||||
_ticksPerFrame = Stopwatch.Frequency / TargetFps;
|
||||
_gpuCancellationTokenSource = new CancellationTokenSource();
|
||||
@@ -137,7 +137,7 @@ namespace Ryujinx.Headless
|
||||
|
||||
private void SetWindowIcon()
|
||||
{
|
||||
Stream iconStream = typeof(Program).Assembly.GetManifestResourceStream("HeadlessLogo");
|
||||
Stream iconStream = EmbeddedResources.GetStream("Ryujinx/Assets/UIImages/Logo_Ryujinx.png");
|
||||
byte[] iconBytes = new byte[iconStream!.Length];
|
||||
|
||||
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
|
||||
@@ -191,7 +191,7 @@ namespace Ryujinx.Headless
|
||||
FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
}
|
||||
|
||||
WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | GetWindowFlags());
|
||||
WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | WindowFlags);
|
||||
|
||||
if (WindowHandle == nint.Zero)
|
||||
{
|
||||
@@ -246,7 +246,7 @@ namespace Ryujinx.Headless
|
||||
|
||||
protected abstract void SwapBuffers();
|
||||
|
||||
public abstract SDL_WindowFlags GetWindowFlags();
|
||||
public abstract SDL_WindowFlags WindowFlags { get; }
|
||||
|
||||
private string GetGpuDriverName()
|
||||
{
|
||||
@@ -268,7 +268,7 @@ namespace Ryujinx.Headless
|
||||
{
|
||||
InitializeWindowRenderer();
|
||||
|
||||
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
||||
Device.Gpu.Renderer.Initialize(GlLogLevel);
|
||||
|
||||
InitializeRenderer();
|
||||
|
||||
@@ -308,21 +308,6 @@ namespace Ryujinx.Headless
|
||||
|
||||
if (_ticks >= _ticksPerFrame)
|
||||
{
|
||||
string dockedMode = Device.System.State.DockedMode ? "Docked" : "Handheld";
|
||||
float scale = GraphicsConfig.ResScale;
|
||||
if (scale != 1)
|
||||
{
|
||||
dockedMode += $" ({scale}x)";
|
||||
}
|
||||
|
||||
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
||||
Device.VSyncMode.ToString(),
|
||||
dockedMode,
|
||||
Device.Configuration.AspectRatio.ToText(),
|
||||
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||
$"FIFO: {Device.Statistics.GetFifoPercent():0.00} %",
|
||||
$"GPU: {_gpuDriverName}"));
|
||||
|
||||
_ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame);
|
||||
}
|
||||
}
|
||||
@@ -572,5 +557,10 @@ namespace Ryujinx.Headless
|
||||
SDL2Driver.Instance.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public UserProfile ShowPlayerSelectDialog()
|
||||
{
|
||||
return AccountSaveDataManager.GetLastUsedUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -143,6 +144,11 @@ namespace Ryujinx.Ava.Input
|
||||
}
|
||||
}
|
||||
|
||||
public void SetLed(uint packedRgb)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.UI, "SetLed called on an AvaloniaKeyboard");
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold) { }
|
||||
|
||||
public void Rumble(float lowFrequency, float highFrequency, uint durationMs) { }
|
||||
|
||||
@@ -59,6 +59,8 @@ namespace Ryujinx.Ava.Input
|
||||
return new AvaloniaKeyboard(this, _keyboardIdentifers[0], LocaleManager.Instance[LocaleKeys.AllKeyboards]);
|
||||
}
|
||||
|
||||
public IEnumerable<IGamepad> GetGamepads() => [GetGamepad("0")];
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
@@ -74,6 +75,11 @@ namespace Ryujinx.Ava.Input
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SetLed(uint packedRgb)
|
||||
{
|
||||
Logger.Info?.Print(LogClass.UI, "SetLed called on an AvaloniaMouse");
|
||||
}
|
||||
|
||||
public void SetTriggerThreshold(float triggerThreshold)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -3,6 +3,7 @@ using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Ryujinx.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using MouseButton = Ryujinx.Input.MouseButton;
|
||||
using Size = System.Drawing.Size;
|
||||
@@ -134,6 +135,8 @@ namespace Ryujinx.Ava.Input
|
||||
return new AvaloniaMouse(this);
|
||||
}
|
||||
|
||||
public IEnumerable<IGamepad> GetGamepads() => [GetGamepad("0")];
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed)
|
||||
|
||||
@@ -21,6 +21,7 @@ using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||
using Ryujinx.Headless;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -46,9 +47,9 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
Version = ReleaseInformation.Version;
|
||||
|
||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041))
|
||||
{
|
||||
_ = MessageBoxA(nint.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 1803 and newer.\n", $"Ryujinx {Version}", MbIconwarning);
|
||||
_ = MessageBoxA(nint.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 20H1 and newer.\n", $"Ryujinx {Version}", MbIconwarning);
|
||||
}
|
||||
|
||||
PreviewerDetached = true;
|
||||
@@ -135,8 +136,8 @@ namespace Ryujinx.Ava
|
||||
// Logging system information.
|
||||
PrintSystemInfo();
|
||||
|
||||
// Enable OGL multithreading on the driver, and some other flags.
|
||||
DriverUtilities.InitDriverConfig(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
||||
// Enable OGL multithreading on the driver, when available.
|
||||
DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
||||
|
||||
// Check if keys exists.
|
||||
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
||||
@@ -229,13 +230,16 @@ namespace Ryujinx.Ava
|
||||
internal static void PrintSystemInfo()
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"{RyujinxApp.FullAppName} Version: {Version}");
|
||||
Logger.Notice.Print(LogClass.Application, $".NET Runtime: {RuntimeInformation.FrameworkDescription}");
|
||||
SystemInfo.Gather().Print();
|
||||
|
||||
var enabledLogLevels = Logger.GetEnabledLevels().ToArray();
|
||||
|
||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogLevels.Length is 0
|
||||
? "<None>"
|
||||
: enabledLogLevels.JoinToString(", "))}");
|
||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {
|
||||
Logger.GetEnabledLevels()
|
||||
.FormatCollection(
|
||||
x => x.ToString(),
|
||||
separator: ", ",
|
||||
emptyCollectionFallback: "<None>")
|
||||
}");
|
||||
|
||||
Logger.Notice.Print(LogClass.Application,
|
||||
AppDataManager.Mode == AppDataManager.LaunchMode.Custom
|
||||
@@ -243,16 +247,33 @@ namespace Ryujinx.Ava
|
||||
: $"Launch Mode: {AppDataManager.Mode}");
|
||||
}
|
||||
|
||||
internal static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating)
|
||||
internal static void ProcessUnhandledException(object sender, Exception initialException, bool isTerminating)
|
||||
{
|
||||
Logger.Log log = Logger.Error ?? Logger.Notice;
|
||||
string message = $"Unhandled exception caught: {ex}";
|
||||
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
if (sender?.GetType()?.AsPrettyString() is { } senderName)
|
||||
log.Print(LogClass.Application, message, senderName);
|
||||
List<Exception> exceptions = [];
|
||||
|
||||
if (initialException is AggregateException ae)
|
||||
{
|
||||
exceptions.AddRange(ae.InnerExceptions);
|
||||
}
|
||||
else
|
||||
log.PrintMsg(LogClass.Application, message);
|
||||
{
|
||||
exceptions.Add(initialException);
|
||||
}
|
||||
|
||||
foreach (var e in exceptions)
|
||||
{
|
||||
string message = $"Unhandled exception caught: {e}";
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
if (sender?.GetType()?.AsPrettyString() is { } senderName)
|
||||
log.Print(LogClass.Application, message, senderName);
|
||||
else
|
||||
log.PrintMsg(LogClass.Application, message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (isTerminating)
|
||||
Exit();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user