Compare commits
61 Commits
Canary-1.2
...
1.2.78
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f07a9737db | ||
|
|
73638582c5 | ||
|
|
246b4bd555 | ||
|
|
c77dced809 | ||
|
|
1e8235414f | ||
|
|
fc41960fd3 | ||
|
|
26319ba487 | ||
|
|
aeeeaca37c | ||
|
|
8b3fa0011b | ||
|
|
c4bfe7ec21 | ||
|
|
5b6449d916 | ||
|
|
71646c3757 | ||
|
|
966ca60847 | ||
|
|
f1a222bb9a | ||
|
|
8f789dd04c | ||
|
|
f239ca2de0 | ||
|
|
ac577e76a1 | ||
|
|
04e6d44607 | ||
|
|
4f9cf2be6b | ||
|
|
44fcb4f5cd | ||
|
|
f838f00c04 | ||
|
|
0d369fc1da | ||
|
|
7c3e89c4f4 | ||
|
|
87394b8d4d | ||
|
|
b59d8f9e4e | ||
|
|
468f6f782d | ||
|
|
aae92bbf15 | ||
|
|
f23547d911 | ||
|
|
9573476db6 | ||
|
|
7f279cd4ed | ||
|
|
cde38fb1c5 | ||
|
|
164cf7ea7f | ||
|
|
29c4435791 | ||
|
|
84cc3559f0 | ||
|
|
1963cda121 | ||
|
|
b59b8ac943 | ||
|
|
b40cf692c8 | ||
|
|
fd2972ec84 | ||
|
|
9190796c62 | ||
|
|
08d2929ea0 | ||
|
|
df6798cf7a | ||
|
|
484dc13314 | ||
|
|
bada08258e | ||
|
|
dc4ac64faf | ||
|
|
67bb3dc2d9 | ||
|
|
5e5b3aeaf1 | ||
|
|
84d340b4fb | ||
|
|
ef7ce19867 | ||
|
|
394fabb8cc | ||
|
|
68525ab7f1 | ||
|
|
904d249dad | ||
|
|
413eb755cb | ||
|
|
2ed3836093 | ||
|
|
b5d5256c61 | ||
|
|
32bfa06024 | ||
|
|
b31a8946ae | ||
|
|
0f85cadf28 | ||
|
|
4892e72907 | ||
|
|
c565da03c5 | ||
|
|
0cf125a4d9 | ||
|
|
f8c53f03fd |
2
.github/labeler.yml
vendored
2
.github/labeler.yml
vendored
@@ -32,7 +32,7 @@ kernel:
|
|||||||
|
|
||||||
infra:
|
infra:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
- any-glob-to-any-file: ['.github/**', 'distribution/**', 'Directory.Packages.props', 'src/Ryujinx.BuildValidationTasks/**']
|
- any-glob-to-any-file: ['.github/**', 'distribution/**', 'Directory.Packages.props']
|
||||||
|
|
||||||
documentation:
|
documentation:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
|
|||||||
28
.github/workflows/canary.yml
vendored
28
.github/workflows/canary.yml
vendored
@@ -61,9 +61,9 @@ jobs:
|
|||||||
|
|
||||||
| Platform | Artifact |
|
| Platform | Artifact |
|
||||||
|--|--|
|
|--|--|
|
||||||
| Windows 64-bit | [Canary Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
|
| Windows 64 bit | [Canary Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
|
||||||
| Linux 64-bit | [Canary Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
|
| Linux 64 bit | [Canary Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
|
||||||
| Linux ARM 64-bit | [Canary Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
|
| Linux arm 64 bit | [Canary Linux arm Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
|
||||||
| macOS | [Canary macOS artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
|
| macOS | [Canary macOS artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}
|
**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}
|
||||||
@@ -200,10 +200,10 @@ jobs:
|
|||||||
|
|
||||||
| Platform | Artifact |
|
| Platform | Artifact |
|
||||||
|--|--|
|
|--|--|
|
||||||
| Windows 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip |
|
| Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip |
|
||||||
| Linux 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz |
|
| Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz |
|
||||||
| Linux ARM 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz |
|
| Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz |
|
||||||
| macOS | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz |
|
| Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz |
|
||||||
|
|
||||||
"**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}"
|
"**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}"
|
||||||
omitBodyDuringUpdate: true
|
omitBodyDuringUpdate: true
|
||||||
@@ -272,7 +272,19 @@ jobs:
|
|||||||
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
||||||
artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz"
|
artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz"
|
||||||
tag: ${{ steps.version_info.outputs.build_version }}
|
tag: ${{ steps.version_info.outputs.build_version }}
|
||||||
body: ""
|
body: |
|
||||||
|
# Canary builds:
|
||||||
|
|
||||||
|
These builds are experimental and may sometimes not work, use [regular builds](https://github.com/GreemDev/Ryujinx/releases/latest) instead if that sounds like something you don't want to deal with.
|
||||||
|
|
||||||
|
| Platform | Artifact |
|
||||||
|
|--|--|
|
||||||
|
| Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip |
|
||||||
|
| Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz |
|
||||||
|
| Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz |
|
||||||
|
| Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz |
|
||||||
|
|
||||||
|
"**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}"
|
||||||
omitBodyDuringUpdate: true
|
omitBodyDuringUpdate: true
|
||||||
allowUpdates: true
|
allowUpdates: true
|
||||||
replacesArtifacts: true
|
replacesArtifacts: true
|
||||||
|
|||||||
25
.github/workflows/release.yml
vendored
25
.github/workflows/release.yml
vendored
@@ -57,9 +57,9 @@ jobs:
|
|||||||
# Regular builds:
|
# Regular builds:
|
||||||
| Platform | Artifact |
|
| Platform | Artifact |
|
||||||
|--|--|
|
|--|--|
|
||||||
| Windows 64-bit | [Release Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
|
| Windows 64 bit | [Release Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) |
|
||||||
| Linux 64-bit | [Release Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
|
| Linux 64 bit | [Release Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) |
|
||||||
| Linux ARM 64-bit | [Release Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
|
| Linux arm 64 bit | [Release Linux arm Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) |
|
||||||
| macOS | [Release macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
|
| macOS | [Release macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) |
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}
|
**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}
|
||||||
@@ -189,10 +189,10 @@ jobs:
|
|||||||
# Regular builds:
|
# Regular builds:
|
||||||
| Platform | Artifact |
|
| Platform | Artifact |
|
||||||
|--|--|
|
|--|--|
|
||||||
| Windows 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip |
|
| Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip |
|
||||||
| Linux 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz |
|
| Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz |
|
||||||
| Linux ARM 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz |
|
| Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz |
|
||||||
| macOS | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz |
|
| Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz |
|
||||||
|
|
||||||
"**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}"
|
"**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}"
|
||||||
omitBodyDuringUpdate: true
|
omitBodyDuringUpdate: true
|
||||||
@@ -261,7 +261,16 @@ jobs:
|
|||||||
name: ${{ steps.version_info.outputs.build_version }}
|
name: ${{ steps.version_info.outputs.build_version }}
|
||||||
artifacts: "publish/*.tar.gz, publish_headless/*.tar.gz"
|
artifacts: "publish/*.tar.gz, publish_headless/*.tar.gz"
|
||||||
tag: ${{ steps.version_info.outputs.build_version }}
|
tag: ${{ steps.version_info.outputs.build_version }}
|
||||||
body: ""
|
body: |
|
||||||
|
# Regular builds:
|
||||||
|
| Platform | Artifact |
|
||||||
|
|--|--|
|
||||||
|
| Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip |
|
||||||
|
| Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz |
|
||||||
|
| Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz |
|
||||||
|
| Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz |
|
||||||
|
|
||||||
|
"**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}"
|
||||||
omitBodyDuringUpdate: true
|
omitBodyDuringUpdate: true
|
||||||
allowUpdates: true
|
allowUpdates: true
|
||||||
replacesArtifacts: true
|
replacesArtifacts: true
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ If you wish to build the emulator yourself, follow these steps:
|
|||||||
|
|
||||||
### Step 1
|
### Step 1
|
||||||
|
|
||||||
Install the [.NET 9.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/9.0).
|
Install the [.NET 8.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/8.0).
|
||||||
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
|
Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json).
|
||||||
|
|
||||||
### Step 2
|
### Step 2
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<Project>
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -10,9 +10,6 @@
|
|||||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" 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" Version="11.0.0.18" />
|
||||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" />
|
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" />
|
||||||
<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" />
|
|
||||||
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.4.0" />
|
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.4.0" />
|
||||||
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0"/>
|
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0"/>
|
||||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
|
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
|
||||||
@@ -44,7 +41,6 @@
|
|||||||
<PackageVersion Include="Gommon" Version="2.6.8" />
|
<PackageVersion Include="Gommon" Version="2.6.8" />
|
||||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||||
<PackageVersion Include="SharpMetal" Version="1.0.0-preview20" />
|
|
||||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
|
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
|
||||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
|
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
|
||||||
@@ -52,8 +48,8 @@
|
|||||||
<PackageVersion Include="SkiaSharp" Version="2.88.7" />
|
<PackageVersion Include="SkiaSharp" Version="2.88.7" />
|
||||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
|
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.0" />
|
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
|
||||||
<PackageVersion Include="System.Management" Version="9.0.0" />
|
<PackageVersion Include="System.Management" Version="8.0.0" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ failing to meet this requirement may result in a poor gameplay experience or une
|
|||||||
|
|
||||||
## Latest build
|
## 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 onto a separate "release" 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**.
|
These stable builds exist so that the end user can get a more **enjoyable and stable experience**.
|
||||||
|
|
||||||
You can find the latest stable release [here](https://github.com/GreemDev/Ryujinx/releases/latest).
|
You can find the latest stable release [here](https://github.com/GreemDev/Ryujinx/releases/latest).
|
||||||
@@ -82,7 +82,7 @@ If you are planning to contribute or just want to learn more about this project
|
|||||||
It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code.
|
It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code.
|
||||||
There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster).
|
There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster).
|
||||||
The fastest option (host, unchecked) is set by default.
|
The fastest option (host, unchecked) is set by default.
|
||||||
Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads.
|
Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads.
|
||||||
The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game.
|
The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game.
|
||||||
NOTE: This feature is enabled by default in the Options menu > System tab.
|
NOTE: This feature is enabled by default in the Options menu > System tab.
|
||||||
You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch!
|
You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch!
|
||||||
|
|||||||
26
Ryujinx.sln
26
Ryujinx.sln
@@ -81,22 +81,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Gene
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal", "src\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj", "{C08931FA-1191-417A-864F-3882D93E683B}"
|
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E} = {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal.SharpMetalExtensions", "src/Ryujinx.Graphics.Metal.SharpMetalExtensions\Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj", "{81EA598C-DBA1-40B0-8DA4-4796B78F2037}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
.editorconfig = .editorconfig
|
.editorconfig = .editorconfig
|
||||||
.github\workflows\build.yml = .github\workflows\build.yml
|
|
||||||
.github\workflows\canary.yml = .github\workflows\canary.yml
|
|
||||||
Directory.Packages.props = Directory.Packages.props
|
Directory.Packages.props = Directory.Packages.props
|
||||||
.github\workflows\release.yml = .github\workflows\release.yml
|
.github/workflows/release.yml = .github/workflows/release.yml
|
||||||
|
.github/workflows/canary.yml = .github/workflows/canary.yml
|
||||||
|
.github/workflows/build.yml = .github/workflows/build.yml
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
@@ -261,17 +252,6 @@ Global
|
|||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
61
distribution/misc/macOS.svg
Normal file
61
distribution/misc/macOS.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 48 KiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "9.0.100",
|
"version": "8.0.100",
|
||||||
"rollForward": "latestFeature"
|
"rollForward": "latestFeature"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.Common;
|
using ARMeilleure.Common;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
@@ -150,7 +149,7 @@ namespace ARMeilleure.Decoders
|
|||||||
return (((long)opCode << 45) >> 48) & ~3;
|
return (((long)opCode << 45) >> 48) & ~3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool VectorArgumentsInvalid(bool q, params ReadOnlySpan<int> args)
|
public static bool VectorArgumentsInvalid(bool q, params int[] args)
|
||||||
{
|
{
|
||||||
if (q)
|
if (q)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params ReadOnlySpan<V128> tb)
|
private static V128 TblOrTbx(V128 dest, V128 vector, int bytes, params V128[] tb)
|
||||||
{
|
{
|
||||||
byte[] res = new byte[16];
|
byte[] res = new byte[16];
|
||||||
|
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operation Operation(Intrinsic intrin, Operand dest, params ReadOnlySpan<Operand> srcs)
|
public static Operation Operation(Intrinsic intrin, Operand dest, params Operand[] srcs)
|
||||||
{
|
{
|
||||||
Operation result = Make(Instruction.Extended, 0, srcs.Length);
|
Operation result = Make(Instruction.Extended, 0, srcs.Length);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Translation.Cache
|
namespace ARMeilleure.Translation.Cache
|
||||||
{
|
{
|
||||||
@@ -27,7 +26,7 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
|
|
||||||
private static readonly List<CacheEntry> _cacheEntries = new();
|
private static readonly List<CacheEntry> _cacheEntries = new();
|
||||||
|
|
||||||
private static readonly Lock _lock = new();
|
private static readonly object _lock = new();
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
|
|||||||
@@ -559,27 +559,27 @@ namespace ARMeilleure.Translation
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Operand AddIntrinsic(Intrinsic intrin, params ReadOnlySpan<Operand> args)
|
public Operand AddIntrinsic(Intrinsic intrin, params Operand[] args)
|
||||||
{
|
{
|
||||||
return Add(intrin, Local(OperandType.V128), args);
|
return Add(intrin, Local(OperandType.V128), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Operand AddIntrinsicInt(Intrinsic intrin, params ReadOnlySpan<Operand> args)
|
public Operand AddIntrinsicInt(Intrinsic intrin, params Operand[] args)
|
||||||
{
|
{
|
||||||
return Add(intrin, Local(OperandType.I32), args);
|
return Add(intrin, Local(OperandType.I32), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Operand AddIntrinsicLong(Intrinsic intrin, params ReadOnlySpan<Operand> args)
|
public Operand AddIntrinsicLong(Intrinsic intrin, params Operand[] args)
|
||||||
{
|
{
|
||||||
return Add(intrin, Local(OperandType.I64), args);
|
return Add(intrin, Local(OperandType.I64), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddIntrinsicNoRet(Intrinsic intrin, params ReadOnlySpan<Operand> args)
|
public void AddIntrinsicNoRet(Intrinsic intrin, params Operand[] args)
|
||||||
{
|
{
|
||||||
Add(intrin, default, args);
|
Add(intrin, default, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Operand Add(Intrinsic intrin, Operand dest, params ReadOnlySpan<Operand> sources)
|
private Operand Add(Intrinsic intrin, Operand dest, params Operand[] sources)
|
||||||
{
|
{
|
||||||
NewNextBlockIfNeeded();
|
NewNextBlockIfNeeded();
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
private readonly ManualResetEvent _waitEvent;
|
private readonly ManualResetEvent _waitEvent;
|
||||||
|
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -89,6 +89,8 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
_waitEvent = new ManualResetEvent(true);
|
_waitEvent = new ManualResetEvent(true);
|
||||||
|
|
||||||
|
_lock = new object();
|
||||||
|
|
||||||
_disposed = false;
|
_disposed = false;
|
||||||
|
|
||||||
TitleIdText = TitleIdTextDefault;
|
TitleIdText = TitleIdTextDefault;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using Humanizer;
|
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
@@ -42,7 +41,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
|
|
||||||
private readonly ManualResetEvent _waitEvent;
|
private readonly ManualResetEvent _waitEvent;
|
||||||
|
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock;
|
||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
@@ -59,13 +58,15 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
_ptc = ptc;
|
_ptc = ptc;
|
||||||
|
|
||||||
_timer = new Timer(SaveInterval.Seconds());
|
_timer = new Timer(SaveInterval * 1000d);
|
||||||
_timer.Elapsed += TimerElapsed;
|
_timer.Elapsed += PreSave;
|
||||||
|
|
||||||
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
|
_outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
|
||||||
|
|
||||||
_waitEvent = new ManualResetEvent(true);
|
_waitEvent = new ManualResetEvent(true);
|
||||||
|
|
||||||
|
_lock = new object();
|
||||||
|
|
||||||
_disposed = false;
|
_disposed = false;
|
||||||
|
|
||||||
ProfiledFuncs = new Dictionary<ulong, FuncProfile>();
|
ProfiledFuncs = new Dictionary<ulong, FuncProfile>();
|
||||||
@@ -73,9 +74,6 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
Enabled = false;
|
Enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TimerElapsed(object _, ElapsedEventArgs __)
|
|
||||||
=> new Thread(PreSave) { Name = "Ptc.DiskWriter" }.Start();
|
|
||||||
|
|
||||||
public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
|
public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
|
||||||
{
|
{
|
||||||
if (IsAddressInStaticCodeRange(address))
|
if (IsAddressInStaticCodeRange(address))
|
||||||
@@ -266,7 +264,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
compressedStream.SetLength(0L);
|
compressedStream.SetLength(0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PreSave()
|
private void PreSave(object source, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
_waitEvent.Reset();
|
_waitEvent.Reset();
|
||||||
|
|
||||||
@@ -432,7 +430,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
{
|
{
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
|
||||||
_timer.Elapsed -= TimerElapsed;
|
_timer.Elapsed -= PreSave;
|
||||||
_timer.Dispose();
|
_timer.Dispose();
|
||||||
|
|
||||||
Wait();
|
Wait();
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Ryujinx.Memory;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Backends.OpenAL
|
namespace Ryujinx.Audio.Backends.OpenAL
|
||||||
{
|
{
|
||||||
@@ -19,7 +18,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
private ulong _playedSampleCount;
|
private ulong _playedSampleCount;
|
||||||
private float _volume;
|
private float _volume;
|
||||||
|
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
public OpenALHardwareDeviceSession(OpenALHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace Ryujinx.Audio
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used to control the waiters registration.
|
/// Lock used to control the waiters registration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Events signaled when the driver played audio buffers.
|
/// Events signaled when the driver played audio buffers.
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Ryujinx.Common;
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Backends.Common
|
namespace Ryujinx.Audio.Backends.Common
|
||||||
{
|
{
|
||||||
@@ -13,7 +12,7 @@ namespace Ryujinx.Audio.Backends.Common
|
|||||||
{
|
{
|
||||||
private const int RingBufferAlignment = 2048;
|
private const int RingBufferAlignment = 2048;
|
||||||
|
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
private MemoryOwner<byte> _bufferOwner;
|
private MemoryOwner<byte> _bufferOwner;
|
||||||
private Memory<byte> _buffer;
|
private Memory<byte> _buffer;
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Input
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioInputManager : IDisposable
|
public class AudioInputManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used for session allocation.
|
/// Lock used for session allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Lock _sessionLock = new();
|
private readonly object _sessionLock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The session ids allocation table.
|
/// The session ids allocation table.
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Input
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The lock of the parent.
|
/// The lock of the parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Lock _parentLock;
|
private readonly object _parentLock;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The dispose state.
|
/// The dispose state.
|
||||||
@@ -62,7 +62,7 @@ namespace Ryujinx.Audio.Input
|
|||||||
/// <param name="parentLock">The lock of the manager</param>
|
/// <param name="parentLock">The lock of the manager</param>
|
||||||
/// <param name="deviceSession">The hardware device session</param>
|
/// <param name="deviceSession">The hardware device session</param>
|
||||||
/// <param name="bufferEvent">The buffer release event of the audio input</param>
|
/// <param name="bufferEvent">The buffer release event of the audio input</param>
|
||||||
public AudioInputSystem(AudioInputManager manager, Lock parentLock, IHardwareDeviceSession deviceSession, IWritableEvent bufferEvent)
|
public AudioInputSystem(AudioInputManager manager, object parentLock, IHardwareDeviceSession deviceSession, IWritableEvent bufferEvent)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_parentLock = parentLock;
|
_parentLock = parentLock;
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ namespace Ryujinx.Audio.Output
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AudioOutputManager : IDisposable
|
public class AudioOutputManager : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used for session allocation.
|
/// Lock used for session allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Lock _sessionLock = new();
|
private readonly object _sessionLock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The session ids allocation table.
|
/// The session ids allocation table.
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace Ryujinx.Audio.Output
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// THe lock of the parent.
|
/// THe lock of the parent.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Lock _parentLock;
|
private readonly object _parentLock;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The dispose state.
|
/// The dispose state.
|
||||||
@@ -62,7 +62,7 @@ namespace Ryujinx.Audio.Output
|
|||||||
/// <param name="parentLock">The lock of the manager</param>
|
/// <param name="parentLock">The lock of the manager</param>
|
||||||
/// <param name="deviceSession">The hardware device session</param>
|
/// <param name="deviceSession">The hardware device session</param>
|
||||||
/// <param name="bufferEvent">The buffer release event of the audio output</param>
|
/// <param name="bufferEvent">The buffer release event of the audio output</param>
|
||||||
public AudioOutputSystem(AudioOutputManager manager, Lock parentLock, IHardwareDeviceSession deviceSession, IWritableEvent bufferEvent)
|
public AudioOutputSystem(AudioOutputManager manager, object parentLock, IHardwareDeviceSession deviceSession, IWritableEvent bufferEvent)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_parentLock = parentLock;
|
_parentLock = parentLock;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
{
|
{
|
||||||
public class AudioRenderSystem : IDisposable
|
public class AudioRenderSystem : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
private AudioRendererRenderingDevice _renderingDevice;
|
private AudioRendererRenderingDevice _renderingDevice;
|
||||||
private AudioRendererExecutionMode _executionMode;
|
private AudioRendererExecutionMode _executionMode;
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ namespace Ryujinx.Audio.Renderer.Server
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used for session allocation.
|
/// Lock used for session allocation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Lock _sessionLock = new();
|
private readonly object _sessionLock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock used to control the <see cref="AudioProcessor"/> running state.
|
/// Lock used to control the <see cref="AudioProcessor"/> running state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Lock _audioProcessorLock = new();
|
private readonly object _audioProcessorLock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The session ids allocation table.
|
/// The session ids allocation table.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Audio.Renderer.Server.Upsampler
|
namespace Ryujinx.Audio.Renderer.Server.Upsampler
|
||||||
{
|
{
|
||||||
@@ -17,7 +16,7 @@ namespace Ryujinx.Audio.Renderer.Server.Upsampler
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Global lock of the object.
|
/// Global lock of the object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The upsamplers instances.
|
/// The upsamplers instances.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Microsoft.Build.Utilities;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.IO;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Microsoft.Build.Framework;
|
|
||||||
|
|
||||||
namespace Ryujinx.BuildValidationTasks
|
|
||||||
{
|
|
||||||
public class LocaleValidationTask : Task
|
|
||||||
{
|
|
||||||
public override bool Execute()
|
|
||||||
{
|
|
||||||
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
|
||||||
|
|
||||||
if (path.Split(["src"], StringSplitOptions.None).Length == 1)
|
|
||||||
{
|
|
||||||
//i assume that we are in a build directory in the solution dir
|
|
||||||
path = new FileInfo(path).Directory!.Parent!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
path = path.Split(["src"], StringSplitOptions.None)[0];
|
|
||||||
path = new FileInfo(path).Directory!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
string data;
|
|
||||||
|
|
||||||
using (StreamReader sr = new(path))
|
|
||||||
{
|
|
||||||
data = sr.ReadToEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalesJson json = JsonConvert.DeserializeObject<LocalesJson>(data);
|
|
||||||
|
|
||||||
for (int i = 0; i < json.Locales.Count; i++)
|
|
||||||
{
|
|
||||||
LocalesEntry locale = json.Locales[i];
|
|
||||||
|
|
||||||
foreach (string langCode in json.Languages.Where(it => !locale.Translations.ContainsKey(it)))
|
|
||||||
{
|
|
||||||
locale.Translations.Add(langCode, string.Empty);
|
|
||||||
Log.LogMessage(MessageImportance.High, $"Added '{langCode}' to Locale '{locale.ID}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
|
|
||||||
json.Locales[i] = locale;
|
|
||||||
}
|
|
||||||
|
|
||||||
string jsonString = JsonConvert.SerializeObject(json, Formatting.Indented);
|
|
||||||
|
|
||||||
using (StreamWriter sw = new(path))
|
|
||||||
{
|
|
||||||
sw.Write(jsonString);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LocalesJson
|
|
||||||
{
|
|
||||||
public List<string> Languages { get; set; }
|
|
||||||
public List<LocalesEntry> Locales { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
struct LocalesEntry
|
|
||||||
{
|
|
||||||
public string ID { get; set; }
|
|
||||||
public Dictionary<string, string> Translations { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.Build.Utilities.Core" />
|
|
||||||
<PackageReference Include="Newtonsoft.Json" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<UsingTask TaskName="Ryujinx.BuildValidationTasks.LocaleValidationTask" TaskFactory="TaskHostFactory" AssemblyFile="$(OutDir)Ryujinx.BuildValidationTasks.dll" />
|
|
||||||
|
|
||||||
<Target Name="LocalesJsonValidation" AfterTargets="AfterRebuild">
|
|
||||||
<LocaleValidationTask />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -6,9 +6,7 @@ namespace Ryujinx.Common.Configuration
|
|||||||
[JsonConverter(typeof(TypedStringEnumConverter<GraphicsBackend>))]
|
[JsonConverter(typeof(TypedStringEnumConverter<GraphicsBackend>))]
|
||||||
public enum GraphicsBackend
|
public enum GraphicsBackend
|
||||||
{
|
{
|
||||||
Auto,
|
|
||||||
Vulkan,
|
Vulkan,
|
||||||
OpenGl,
|
OpenGl,
|
||||||
Metal
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ namespace Ryujinx.Common.PreciseSleep
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
private readonly List<NanosleepThread> _threads = new();
|
private readonly List<NanosleepThread> _threads = new();
|
||||||
private readonly List<NanosleepThread> _active = new();
|
private readonly List<NanosleepThread> _active = new();
|
||||||
private readonly Stack<NanosleepThread> _free = new();
|
private readonly Stack<NanosleepThread> _free = new();
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||||||
private long _lastTicks = PerformanceCounter.ElapsedTicks;
|
private long _lastTicks = PerformanceCounter.ElapsedTicks;
|
||||||
private long _lastId;
|
private long _lastId;
|
||||||
|
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
private readonly List<WaitingObject> _waitingObjects = new();
|
private readonly List<WaitingObject> _waitingObjects = new();
|
||||||
|
|
||||||
private WindowsGranularTimer()
|
private WindowsGranularTimer()
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace Ryujinx.Common
|
|||||||
// DO NOT EDIT, filled by CI
|
// DO NOT EDIT, filled by CI
|
||||||
public static class ReleaseInformation
|
public static class ReleaseInformation
|
||||||
{
|
{
|
||||||
|
private const string FlatHubChannel = "flathub";
|
||||||
private const string CanaryChannel = "canary";
|
private const string CanaryChannel = "canary";
|
||||||
private const string ReleaseChannel = "release";
|
private const string ReleaseChannel = "release";
|
||||||
|
|
||||||
@@ -28,6 +29,8 @@ namespace Ryujinx.Common
|
|||||||
!ReleaseChannelRepo.StartsWith("%%") &&
|
!ReleaseChannelRepo.StartsWith("%%") &&
|
||||||
!ConfigFileName.StartsWith("%%");
|
!ConfigFileName.StartsWith("%%");
|
||||||
|
|
||||||
|
public static bool IsFlatHubBuild => IsValid && ReleaseChannelOwner.Equals(FlatHubChannel);
|
||||||
|
|
||||||
public static bool IsCanaryBuild => IsValid && ReleaseChannelName.Equals(CanaryChannel);
|
public static bool IsCanaryBuild => IsValid && ReleaseChannelName.Equals(CanaryChannel);
|
||||||
|
|
||||||
public static bool IsReleaseBuild => IsValid && ReleaseChannelName.Equals(ReleaseChannel);
|
public static bool IsReleaseBuild => IsValid && ReleaseChannelName.Equals(ReleaseChannel);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
|
|||||||
@@ -1,190 +0,0 @@
|
|||||||
using Gommon;
|
|
||||||
using Ryujinx.Common.Configuration;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Common
|
|
||||||
{
|
|
||||||
public static class TitleIDs
|
|
||||||
{
|
|
||||||
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
|
|
||||||
{
|
|
||||||
switch (currentBackend)
|
|
||||||
{
|
|
||||||
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))
|
|
||||||
return GraphicsBackend.Vulkan;
|
|
||||||
|
|
||||||
return GreatMetalTitles.ContainsIgnoreCase(titleId) ? GraphicsBackend.Metal : GraphicsBackend.Vulkan;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly string[] GreatMetalTitles =
|
|
||||||
[
|
|
||||||
"01006f8002326000", // Animal Crossings: New Horizons
|
|
||||||
"01009bf0072d4000", // Captain Toad: Treasure Tracker
|
|
||||||
"0100a5c00d162000", // Cuphead
|
|
||||||
"010023800d64a000", // Deltarune
|
|
||||||
"010028600EBDA000", // Mario 3D World
|
|
||||||
"0100152000022000", // Mario Kart 8 Deluxe
|
|
||||||
"01005CA01580E000", // Persona 5
|
|
||||||
"01008C0016544000", // Sea of Stars
|
|
||||||
"01006A800016E000", // Smash Ultimate
|
|
||||||
"0100000000010000", // Super Mario Odyessy
|
|
||||||
];
|
|
||||||
|
|
||||||
public static string GetDiscordGameAsset(string titleId)
|
|
||||||
=> DiscordGameAssetKeys.Contains(titleId) ? titleId : "game";
|
|
||||||
|
|
||||||
public static readonly string[] DiscordGameAssetKeys =
|
|
||||||
[
|
|
||||||
"010055d009f78000", // Fire Emblem: Three Houses
|
|
||||||
"0100a12011cc8000", // Fire Emblem: Shadow Dragon
|
|
||||||
"0100a6301214e000", // Fire Emblem Engage
|
|
||||||
"0100f15003e64000", // Fire Emblem Warriors
|
|
||||||
"010071f0143ea000", // Fire Emblem Warriors: Three Hopes
|
|
||||||
|
|
||||||
"01007e3006dda000", // Kirby Star Allies
|
|
||||||
"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
|
|
||||||
|
|
||||||
"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
|
|
||||||
|
|
||||||
"010048701995e000", // Luigi's Mansion 2 HD
|
|
||||||
"0100dca0064a6000", // Luigi's Mansion 3
|
|
||||||
|
|
||||||
"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
|
|
||||||
"01006d0017f7a000", // Mario & Luigi: Brothership
|
|
||||||
"010067300059a000", // Mario + Rabbids: Kingdom Battle
|
|
||||||
"0100317013770000", // Mario + Rabbids: Sparks of Hope
|
|
||||||
"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
|
|
||||||
|
|
||||||
"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
|
|
||||||
"0100000011d90000", // Pokémon Brilliant Diamond
|
|
||||||
"010018e011d92000", // Pokémon Shining Pearl
|
|
||||||
"01001f5010dfa000", // Pokémon Legends: Arceus
|
|
||||||
"0100a3d008c5c000", // Pokémon Scarlet
|
|
||||||
"01008f6008c5e000", // Pokémon Violet
|
|
||||||
"0100b3f000be2000", // Pokkén Tournament DX
|
|
||||||
"0100f4300bf2c000", // New Pokémon Snap
|
|
||||||
|
|
||||||
"01003bc0000a0000", // Splatoon 2 (US)
|
|
||||||
"0100f8f0000a2000", // Splatoon 2 (EU)
|
|
||||||
"01003c700009c000", // Splatoon 2 (JP)
|
|
||||||
"0100c2500fc20000", // Splatoon 3
|
|
||||||
"0100ba0018500000", // Splatoon 3: Splatfest World Premiere
|
|
||||||
|
|
||||||
"010040600c5ce000", // Tetris 99
|
|
||||||
"0100277011f1a000", // Super Mario Bros. 35
|
|
||||||
"0100ad9012510000", // PAC-MAN 99
|
|
||||||
"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
|
|
||||||
|
|
||||||
"01000320000cc000", // 1-2 Switch
|
|
||||||
"0100300012f2a000", // Advance Wars 1+2: Re-Boot Camp
|
|
||||||
"01006f8002326000", // Animal Crossing: New Horizons
|
|
||||||
"0100620012d6e000", // Big Brain Academy: Brain vs. Brain
|
|
||||||
"010018300d006000", // BOXBOY! + BOXGIRL!
|
|
||||||
"0100c1f0051b6000", // Donkey Kong Country: Tropical Freeze
|
|
||||||
"0100ed000d390000", // Dr. Kawashima's Brain Training
|
|
||||||
"010067b017588000", // Endless Ocean Luminous
|
|
||||||
"0100d2f00d5c0000", // Nintendo Switch Sports
|
|
||||||
"01006b5012b32000", // Part Time UFO
|
|
||||||
"0100704000B3A000", // Snipperclips
|
|
||||||
"01006a800016e000", // Super Smash Bros. Ultimate
|
|
||||||
"0100a9400c9c2000", // Tokyo Mirage Sessions #FE Encore
|
|
||||||
|
|
||||||
"010076f0049a2000", // Bayonetta
|
|
||||||
"01007960049a0000", // Bayonetta 2
|
|
||||||
"01004a4010fea000", // Bayonetta 3
|
|
||||||
"0100cf5010fec000", // Bayonetta Origins: Cereza and the Lost Demon
|
|
||||||
|
|
||||||
"0100dcd01525a000", // Persona 3 Portable
|
|
||||||
"010062b01525c000", // Persona 4 Golden
|
|
||||||
"010075a016a3a000", // Persona 4 Arena Ultimax
|
|
||||||
"01005ca01580e000", // Persona 5 Royal
|
|
||||||
"0100801011c3e000", // Persona 5 Strikers
|
|
||||||
"010087701b092000", // Persona 5 Tactica
|
|
||||||
|
|
||||||
"01009aa000faa000", // Sonic Mania
|
|
||||||
"01004ad014bf0000", // Sonic Frontiers
|
|
||||||
"01005ea01c0fc000", // SONIC X SHADOW GENERATIONS
|
|
||||||
"01005ea01c0fc001", // ^
|
|
||||||
|
|
||||||
"010056e00853a000", // A Hat in Time
|
|
||||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
|
||||||
"0100744001588000", // Cars 3: Driven to Win
|
|
||||||
"0100b41013c82000", // Cruis'n Blast
|
|
||||||
"01001b300b9be000", // Diablo III: Eternal Collection
|
|
||||||
"01008c8012920000", // Dying Light Platinum Edition
|
|
||||||
"010073c01af34000", // LEGO Horizon Adventures
|
|
||||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
|
||||||
"0100b04011742000", // Monster Hunter Rise
|
|
||||||
"0100853015e86000", // No Man's Sky
|
|
||||||
"01007bb017812000", // Portal
|
|
||||||
"0100abd01785c000", // Portal 2
|
|
||||||
"01008e200c5c2000", // Muse Dash
|
|
||||||
"01007820196a6000", // Red Dead Redemption
|
|
||||||
"01002f7013224000", // Rune Factory 5
|
|
||||||
"01008d100d43e000", // Saints Row IV
|
|
||||||
"0100de600beee000", // Saints Row: The Third - The Full Package
|
|
||||||
"01001180021fa000", // Shovel Knight: Specter of Torment
|
|
||||||
"0100d7a01b7a2000", // Star Wars: Bounty Hunter
|
|
||||||
"0100800015926000", // Suika Game
|
|
||||||
"0100e46006708000", // Terraria
|
|
||||||
"01000a10041ea000", // The Elder Scrolls V: Skyrim
|
|
||||||
"010057a01e4d4000", // TSUKIHIME -A piece of blue glass moon-
|
|
||||||
"010080b00ad66000", // Undertale
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -28,14 +27,9 @@ namespace Ryujinx.Common.Utilities
|
|||||||
ReadCommentHandling = JsonCommentHandling.Skip
|
ReadCommentHandling = JsonCommentHandling.Skip
|
||||||
};
|
};
|
||||||
|
|
||||||
public static string Serialize<T>(T value, JsonTypeInfo<T> typeInfo)
|
public static string Serialize<T>(T value, JsonTypeInfo<T> typeInfo) => JsonSerializer.Serialize(value, typeInfo);
|
||||||
=> JsonSerializer.Serialize(value, typeInfo);
|
|
||||||
|
|
||||||
public static T Deserialize<T>(string value, JsonTypeInfo<T> typeInfo)
|
public static T Deserialize<T>(string value, JsonTypeInfo<T> typeInfo) => JsonSerializer.Deserialize(value, typeInfo);
|
||||||
=> JsonSerializer.Deserialize(value, typeInfo);
|
|
||||||
|
|
||||||
public static T Deserialize<T>(ReadOnlySpan<byte> utf8Value, JsonTypeInfo<T> typeInfo)
|
|
||||||
=> JsonSerializer.Deserialize<T>(utf8Value, typeInfo);
|
|
||||||
|
|
||||||
public static void SerializeToFile<T>(string filePath, T value, JsonTypeInfo<T> typeInfo)
|
public static void SerializeToFile<T>(string filePath, T value, JsonTypeInfo<T> typeInfo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -230,20 +230,25 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
yield break;
|
return Enumerable.Empty<HostMemoryRange>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var guestRegions = GetPhysicalRegionsImpl(va, size);
|
var guestRegions = GetPhysicalRegionsImpl(va, size);
|
||||||
if (guestRegions == null)
|
if (guestRegions == null)
|
||||||
{
|
{
|
||||||
yield break;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var guestRegion in guestRegions)
|
var regions = new HostMemoryRange[guestRegions.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < regions.Length; i++)
|
||||||
{
|
{
|
||||||
|
var guestRegion = guestRegions[i];
|
||||||
nint pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size);
|
nint pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size);
|
||||||
yield return new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size);
|
regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -251,24 +256,23 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
yield break;
|
return Enumerable.Empty<MemoryRange>();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var physicalRegion in GetPhysicalRegionsImpl(va, size))
|
return GetPhysicalRegionsImpl(va, size);
|
||||||
{
|
|
||||||
yield return physicalRegion;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
|
private List<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
|
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
|
||||||
{
|
{
|
||||||
yield break;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pages = GetPagesCount(va, (uint)size, out va);
|
int pages = GetPagesCount(va, (uint)size, out va);
|
||||||
|
|
||||||
|
var regions = new List<MemoryRange>();
|
||||||
|
|
||||||
ulong regionStart = GetPhysicalAddressInternal(va);
|
ulong regionStart = GetPhysicalAddressInternal(va);
|
||||||
ulong regionSize = PageSize;
|
ulong regionSize = PageSize;
|
||||||
|
|
||||||
@@ -276,14 +280,14 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
{
|
{
|
||||||
if (!ValidateAddress(va + PageSize))
|
if (!ValidateAddress(va + PageSize))
|
||||||
{
|
{
|
||||||
yield break;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
|
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
|
||||||
|
|
||||||
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
|
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
|
||||||
{
|
{
|
||||||
yield return new MemoryRange(regionStart, regionSize);
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
regionStart = newPa;
|
regionStart = newPa;
|
||||||
regionSize = 0;
|
regionSize = 0;
|
||||||
}
|
}
|
||||||
@@ -292,7 +296,9 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
regionSize += PageSize;
|
regionSize += PageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return new MemoryRange(regionStart, regionSize);
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
|
|
||||||
|
return regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Ryujinx.Memory;
|
using Ryujinx.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.AppleHv
|
namespace Ryujinx.Cpu.AppleHv
|
||||||
{
|
{
|
||||||
@@ -13,7 +12,7 @@ namespace Ryujinx.Cpu.AppleHv
|
|||||||
|
|
||||||
private static int _addressSpaces;
|
private static int _addressSpaces;
|
||||||
private static HvIpaAllocator _ipaAllocator;
|
private static HvIpaAllocator _ipaAllocator;
|
||||||
private static readonly Lock _lock = new();
|
private static readonly object _lock = new();
|
||||||
|
|
||||||
public static (ulong, HvIpaAllocator) CreateAddressSpace(MemoryBlock block)
|
public static (ulong, HvIpaAllocator) CreateAddressSpace(MemoryBlock block)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -115,9 +115,6 @@ namespace Ryujinx.Cpu.Jit.HostTracked
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly AddressIntrusiveRedBlackTree<Mapping> _mappingTree;
|
private readonly AddressIntrusiveRedBlackTree<Mapping> _mappingTree;
|
||||||
|
|
||||||
// type is not Lock due to the unique usage of this mechanism,
|
|
||||||
// an arbitrary object is used as the lock passed in by constructor.
|
|
||||||
private readonly object _lock;
|
private readonly object _lock;
|
||||||
|
|
||||||
public Block(MemoryTracking tracking, Func<ulong, ulong> readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size)
|
public Block(MemoryTracking tracking, Func<ulong, ulong> readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size)
|
||||||
@@ -177,9 +174,6 @@ namespace Ryujinx.Cpu.Jit.HostTracked
|
|||||||
|
|
||||||
private readonly MemoryTracking _tracking;
|
private readonly MemoryTracking _tracking;
|
||||||
private readonly Func<ulong, ulong> _readPtCallback;
|
private readonly Func<ulong, ulong> _readPtCallback;
|
||||||
|
|
||||||
// type is not Lock due to the unique usage of this mechanism,
|
|
||||||
// an arbitrary object is used as the lock passed in by constructor.
|
|
||||||
private readonly object _lock;
|
private readonly object _lock;
|
||||||
|
|
||||||
public AddressSpacePartitionAllocator(
|
public AddressSpacePartitionAllocator(
|
||||||
|
|||||||
@@ -250,20 +250,25 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
yield break;
|
return Enumerable.Empty<HostMemoryRange>();
|
||||||
}
|
}
|
||||||
|
|
||||||
var guestRegions = GetPhysicalRegionsImpl(va, size);
|
var guestRegions = GetPhysicalRegionsImpl(va, size);
|
||||||
if (guestRegions == null)
|
if (guestRegions == null)
|
||||||
{
|
{
|
||||||
yield break;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var guestRegion in guestRegions)
|
var regions = new HostMemoryRange[guestRegions.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < regions.Length; i++)
|
||||||
{
|
{
|
||||||
|
var guestRegion = guestRegions[i];
|
||||||
nint pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size);
|
nint pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size);
|
||||||
yield return new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size);
|
regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -271,24 +276,23 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
{
|
{
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
{
|
||||||
yield break;
|
return Enumerable.Empty<MemoryRange>();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var physicalRegion in GetPhysicalRegionsImpl(va, size))
|
return GetPhysicalRegionsImpl(va, size);
|
||||||
{
|
|
||||||
yield return physicalRegion;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
|
private List<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
|
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
|
||||||
{
|
{
|
||||||
yield break;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pages = GetPagesCount(va, (uint)size, out va);
|
int pages = GetPagesCount(va, (uint)size, out va);
|
||||||
|
|
||||||
|
var regions = new List<MemoryRange>();
|
||||||
|
|
||||||
ulong regionStart = GetPhysicalAddressInternal(va);
|
ulong regionStart = GetPhysicalAddressInternal(va);
|
||||||
ulong regionSize = PageSize;
|
ulong regionSize = PageSize;
|
||||||
|
|
||||||
@@ -296,14 +300,14 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
{
|
{
|
||||||
if (!ValidateAddress(va + PageSize))
|
if (!ValidateAddress(va + PageSize))
|
||||||
{
|
{
|
||||||
yield break;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
|
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
|
||||||
|
|
||||||
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
|
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
|
||||||
{
|
{
|
||||||
yield return new MemoryRange(regionStart, regionSize);
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
regionStart = newPa;
|
regionStart = newPa;
|
||||||
regionSize = 0;
|
regionSize = 0;
|
||||||
}
|
}
|
||||||
@@ -312,7 +316,9 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
regionSize += PageSize;
|
regionSize += PageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return new MemoryRange(regionStart, regionSize);
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
|
|
||||||
|
return regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -475,15 +475,17 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
return GetPhysicalRegionsImpl(va, size);
|
return GetPhysicalRegionsImpl(va, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
|
private List<MemoryRange> GetPhysicalRegionsImpl(ulong va, ulong size)
|
||||||
{
|
{
|
||||||
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
|
if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size))
|
||||||
{
|
{
|
||||||
yield break;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pages = GetPagesCount(va, (uint)size, out va);
|
int pages = GetPagesCount(va, (uint)size, out va);
|
||||||
|
|
||||||
|
var regions = new List<MemoryRange>();
|
||||||
|
|
||||||
ulong regionStart = GetPhysicalAddressInternal(va);
|
ulong regionStart = GetPhysicalAddressInternal(va);
|
||||||
ulong regionSize = PageSize;
|
ulong regionSize = PageSize;
|
||||||
|
|
||||||
@@ -491,14 +493,14 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
{
|
{
|
||||||
if (!ValidateAddress(va + PageSize))
|
if (!ValidateAddress(va + PageSize))
|
||||||
{
|
{
|
||||||
yield break;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
|
ulong newPa = GetPhysicalAddressInternal(va + PageSize);
|
||||||
|
|
||||||
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
|
if (GetPhysicalAddressInternal(va) + PageSize != newPa)
|
||||||
{
|
{
|
||||||
yield return new MemoryRange(regionStart, regionSize);
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
regionStart = newPa;
|
regionStart = newPa;
|
||||||
regionSize = 0;
|
regionSize = 0;
|
||||||
}
|
}
|
||||||
@@ -507,7 +509,9 @@ namespace Ryujinx.Cpu.Jit
|
|||||||
regionSize += PageSize;
|
regionSize += PageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return new MemoryRange(regionStart, regionSize);
|
regions.Add(new MemoryRange(regionStart, regionSize));
|
||||||
|
|
||||||
|
return regions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -478,7 +478,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
bool skipContext,
|
bool skipContext,
|
||||||
int spillBaseOffset,
|
int spillBaseOffset,
|
||||||
int? resultRegister,
|
int? resultRegister,
|
||||||
params ReadOnlySpan<ulong> callArgs)
|
params ulong[] callArgs)
|
||||||
{
|
{
|
||||||
uint resultMask = 0u;
|
uint resultMask = 0u;
|
||||||
|
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
int tempRegister;
|
int tempRegister;
|
||||||
int tempGuestAddress = -1;
|
int tempGuestAddress = -1;
|
||||||
|
|
||||||
bool inlineLookup = guestAddress.Kind != OperandKind.Constant &&
|
bool inlineLookup = guestAddress.Kind != OperandKind.Constant &&
|
||||||
funcTable is { Sparse: true };
|
funcTable is { Sparse: true };
|
||||||
|
|
||||||
if (guestAddress.Kind == OperandKind.Constant)
|
if (guestAddress.Kind == OperandKind.Constant)
|
||||||
@@ -417,7 +417,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
nint funcPtr,
|
nint funcPtr,
|
||||||
int spillBaseOffset,
|
int spillBaseOffset,
|
||||||
int? resultRegister,
|
int? resultRegister,
|
||||||
params ReadOnlySpan<ulong> callArgs)
|
params ulong[] callArgs)
|
||||||
{
|
{
|
||||||
uint resultMask = 0u;
|
uint resultMask = 0u;
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.LightningJit.Cache
|
namespace Ryujinx.Cpu.LightningJit.Cache
|
||||||
{
|
{
|
||||||
@@ -24,7 +23,7 @@ namespace Ryujinx.Cpu.LightningJit.Cache
|
|||||||
|
|
||||||
private static readonly List<CacheEntry> _cacheEntries = new();
|
private static readonly List<CacheEntry> _cacheEntries = new();
|
||||||
|
|
||||||
private static readonly Lock _lock = new();
|
private static readonly object _lock = new();
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Ryujinx.Memory;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.LightningJit.Cache
|
namespace Ryujinx.Cpu.LightningJit.Cache
|
||||||
{
|
{
|
||||||
@@ -105,7 +104,7 @@ namespace Ryujinx.Cpu.LightningJit.Cache
|
|||||||
private readonly MemoryCache _sharedCache;
|
private readonly MemoryCache _sharedCache;
|
||||||
private readonly MemoryCache _localCache;
|
private readonly MemoryCache _localCache;
|
||||||
private readonly PageAlignedRangeList _pendingMap;
|
private readonly PageAlignedRangeList _pendingMap;
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock;
|
||||||
|
|
||||||
class ThreadLocalCacheEntry
|
class ThreadLocalCacheEntry
|
||||||
{
|
{
|
||||||
@@ -138,6 +137,7 @@ namespace Ryujinx.Cpu.LightningJit.Cache
|
|||||||
_sharedCache = new(allocator, SharedCacheSize);
|
_sharedCache = new(allocator, SharedCacheSize);
|
||||||
_localCache = new(allocator, LocalCacheSize);
|
_localCache = new(allocator, LocalCacheSize);
|
||||||
_pendingMap = new(_sharedCache.ReprotectAsRx, RegisterFunction);
|
_pendingMap = new(_sharedCache.ReprotectAsRx, RegisterFunction);
|
||||||
|
_lock = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe nint Map(nint framePointer, ReadOnlySpan<byte> code, ulong guestAddress, ulong guestSize)
|
public unsafe nint Map(nint framePointer, ReadOnlySpan<byte> code, ulong guestAddress, ulong guestSize)
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
{
|
{
|
||||||
public IEnumerable<ulong> GetCallStack(nint framePointer, nint codeRegionStart, int codeRegionSize, nint codeRegion2Start, int codeRegion2Size)
|
public IEnumerable<ulong> GetCallStack(nint framePointer, nint codeRegionStart, int codeRegionSize, nint codeRegion2Start, int codeRegion2Size)
|
||||||
{
|
{
|
||||||
|
List<ulong> functionPointers = new();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
nint functionPointer = Marshal.ReadIntPtr(framePointer, nint.Size);
|
nint functionPointer = Marshal.ReadIntPtr(framePointer, nint.Size);
|
||||||
@@ -18,9 +20,11 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return (ulong)functionPointer - 4;
|
functionPointers.Add((ulong)functionPointer - 4);
|
||||||
framePointer = Marshal.ReadIntPtr(framePointer);
|
framePointer = Marshal.ReadIntPtr(framePointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return functionPointers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using System;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.Signal
|
namespace Ryujinx.Cpu.Signal
|
||||||
{
|
{
|
||||||
@@ -60,7 +59,7 @@ namespace Ryujinx.Cpu.Signal
|
|||||||
|
|
||||||
private static MemoryBlock _codeBlock;
|
private static MemoryBlock _codeBlock;
|
||||||
|
|
||||||
private static readonly Lock _lock = new();
|
private static readonly object _lock = new();
|
||||||
private static bool _initialized;
|
private static bool _initialized;
|
||||||
|
|
||||||
static NativeSignalHandler()
|
static NativeSignalHandler()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
namespace Ryujinx.Graphics.GAL
|
|
||||||
{
|
|
||||||
public readonly struct ComputeSize
|
|
||||||
{
|
|
||||||
public readonly static ComputeSize VtgAsCompute = new ComputeSize(32, 32, 1);
|
|
||||||
|
|
||||||
public readonly int X;
|
|
||||||
public readonly int Y;
|
|
||||||
public readonly int Z;
|
|
||||||
|
|
||||||
public ComputeSize(int x, int y, int z)
|
|
||||||
{
|
|
||||||
X = x;
|
|
||||||
Y = y;
|
|
||||||
Z = z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -339,84 +339,6 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get bytes per element for this format.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="format">Texture format</param>
|
|
||||||
/// <returns>Byte size for an element of this format (pixel, vertex attribute, etc)</returns>
|
|
||||||
public static int GetBytesPerElement(this Format format)
|
|
||||||
{
|
|
||||||
int scalarSize = format.GetScalarSize();
|
|
||||||
|
|
||||||
switch (format)
|
|
||||||
{
|
|
||||||
case Format.R8G8Unorm:
|
|
||||||
case Format.R8G8Snorm:
|
|
||||||
case Format.R8G8Uint:
|
|
||||||
case Format.R8G8Sint:
|
|
||||||
case Format.R8G8Uscaled:
|
|
||||||
case Format.R8G8Sscaled:
|
|
||||||
case Format.R16G16Float:
|
|
||||||
case Format.R16G16Unorm:
|
|
||||||
case Format.R16G16Snorm:
|
|
||||||
case Format.R16G16Uint:
|
|
||||||
case Format.R16G16Sint:
|
|
||||||
case Format.R16G16Uscaled:
|
|
||||||
case Format.R16G16Sscaled:
|
|
||||||
case Format.R32G32Float:
|
|
||||||
case Format.R32G32Uint:
|
|
||||||
case Format.R32G32Sint:
|
|
||||||
case Format.R32G32Uscaled:
|
|
||||||
case Format.R32G32Sscaled:
|
|
||||||
return 2 * scalarSize;
|
|
||||||
|
|
||||||
case Format.R8G8B8Unorm:
|
|
||||||
case Format.R8G8B8Snorm:
|
|
||||||
case Format.R8G8B8Uint:
|
|
||||||
case Format.R8G8B8Sint:
|
|
||||||
case Format.R8G8B8Uscaled:
|
|
||||||
case Format.R8G8B8Sscaled:
|
|
||||||
case Format.R16G16B16Float:
|
|
||||||
case Format.R16G16B16Unorm:
|
|
||||||
case Format.R16G16B16Snorm:
|
|
||||||
case Format.R16G16B16Uint:
|
|
||||||
case Format.R16G16B16Sint:
|
|
||||||
case Format.R16G16B16Uscaled:
|
|
||||||
case Format.R16G16B16Sscaled:
|
|
||||||
case Format.R32G32B32Float:
|
|
||||||
case Format.R32G32B32Uint:
|
|
||||||
case Format.R32G32B32Sint:
|
|
||||||
case Format.R32G32B32Uscaled:
|
|
||||||
case Format.R32G32B32Sscaled:
|
|
||||||
return 3 * scalarSize;
|
|
||||||
|
|
||||||
case Format.R8G8B8A8Unorm:
|
|
||||||
case Format.R8G8B8A8Snorm:
|
|
||||||
case Format.R8G8B8A8Uint:
|
|
||||||
case Format.R8G8B8A8Sint:
|
|
||||||
case Format.R8G8B8A8Srgb:
|
|
||||||
case Format.R8G8B8A8Uscaled:
|
|
||||||
case Format.R8G8B8A8Sscaled:
|
|
||||||
case Format.B8G8R8A8Unorm:
|
|
||||||
case Format.B8G8R8A8Srgb:
|
|
||||||
case Format.R16G16B16A16Float:
|
|
||||||
case Format.R16G16B16A16Unorm:
|
|
||||||
case Format.R16G16B16A16Snorm:
|
|
||||||
case Format.R16G16B16A16Uint:
|
|
||||||
case Format.R16G16B16A16Sint:
|
|
||||||
case Format.R16G16B16A16Uscaled:
|
|
||||||
case Format.R16G16B16A16Sscaled:
|
|
||||||
case Format.R32G32B32A32Float:
|
|
||||||
case Format.R32G32B32A32Uint:
|
|
||||||
case Format.R32G32B32A32Sint:
|
|
||||||
case Format.R32G32B32A32Uscaled:
|
|
||||||
case Format.R32G32B32A32Sscaled:
|
|
||||||
return 4 * scalarSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return scalarSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the texture format is a depth or depth-stencil format.
|
/// Checks if the texture format is a depth or depth-stencil format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
|||||||
public uint ProgramCount { get; set; } = 0;
|
public uint ProgramCount { get; set; } = 0;
|
||||||
|
|
||||||
private Action _interruptAction;
|
private Action _interruptAction;
|
||||||
private readonly Lock _interruptLock = new();
|
private readonly object _interruptLock = new();
|
||||||
|
|
||||||
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,23 @@ namespace Ryujinx.Graphics.GAL
|
|||||||
{
|
{
|
||||||
public int FragmentOutputMap { get; }
|
public int FragmentOutputMap { get; }
|
||||||
public ResourceLayout ResourceLayout { get; }
|
public ResourceLayout ResourceLayout { get; }
|
||||||
public ComputeSize ComputeLocalSize { get; }
|
|
||||||
public ProgramPipelineState? State { get; }
|
public ProgramPipelineState? State { get; }
|
||||||
public bool FromCache { get; set; }
|
public bool FromCache { get; set; }
|
||||||
|
|
||||||
public ShaderInfo(
|
public ShaderInfo(int fragmentOutputMap, ResourceLayout resourceLayout, ProgramPipelineState state, bool fromCache = false)
|
||||||
int fragmentOutputMap,
|
|
||||||
ResourceLayout resourceLayout,
|
|
||||||
ComputeSize computeLocalSize,
|
|
||||||
ProgramPipelineState? state,
|
|
||||||
bool fromCache = false)
|
|
||||||
{
|
{
|
||||||
FragmentOutputMap = fragmentOutputMap;
|
FragmentOutputMap = fragmentOutputMap;
|
||||||
ResourceLayout = resourceLayout;
|
ResourceLayout = resourceLayout;
|
||||||
ComputeLocalSize = computeLocalSize;
|
|
||||||
State = state;
|
State = state;
|
||||||
FromCache = fromCache;
|
FromCache = fromCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ShaderInfo(int fragmentOutputMap, ResourceLayout resourceLayout, bool fromCache = false)
|
||||||
|
{
|
||||||
|
FragmentOutputMap = fragmentOutputMap;
|
||||||
|
ResourceLayout = resourceLayout;
|
||||||
|
State = null;
|
||||||
|
FromCache = fromCache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
class VtgAsComputeContext : IDisposable
|
class VtgAsComputeContext : IDisposable
|
||||||
{
|
{
|
||||||
|
private const int DummyBufferSize = 16;
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -46,7 +48,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
|||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
format.GetBytesPerElement(),
|
1,
|
||||||
format,
|
format,
|
||||||
DepthStencilMode.Depth,
|
DepthStencilMode.Depth,
|
||||||
Target.TextureBuffer,
|
Target.TextureBuffer,
|
||||||
@@ -519,6 +521,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
|||||||
return new BufferRange(_geometryIndexDataBuffer.Handle, offset, size, write);
|
return new BufferRange(_geometryIndexDataBuffer.Handle, offset, size, write);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the range for a dummy 16 bytes buffer, filled with zeros.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Dummy buffer range</returns>
|
||||||
|
public BufferRange GetDummyBufferRange()
|
||||||
|
{
|
||||||
|
if (_dummyBuffer == BufferHandle.Null)
|
||||||
|
{
|
||||||
|
_dummyBuffer = _context.Renderer.CreateBuffer(DummyBufferSize, BufferAccess.DeviceMemory);
|
||||||
|
_context.Renderer.Pipeline.ClearBuffer(_dummyBuffer, 0, DummyBufferSize, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BufferRange(_dummyBuffer, 0, DummyBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the range for a sequential index buffer, with ever incrementing index values.
|
/// Gets the range for a sequential index buffer, with ever incrementing index values.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
|||||||
{
|
{
|
||||||
_vacContext.VertexInfoBufferUpdater.SetVertexStride(index, 0, componentsCount);
|
_vacContext.VertexInfoBufferUpdater.SetVertexStride(index, 0, componentsCount);
|
||||||
_vacContext.VertexInfoBufferUpdater.SetVertexOffset(index, 0, 0);
|
_vacContext.VertexInfoBufferUpdater.SetVertexOffset(index, 0, 0);
|
||||||
|
SetDummyBufferTexture(_vertexAsCompute.Reservations, index, format);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,12 +163,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
|||||||
{
|
{
|
||||||
_vacContext.VertexInfoBufferUpdater.SetVertexStride(index, 0, componentsCount);
|
_vacContext.VertexInfoBufferUpdater.SetVertexStride(index, 0, componentsCount);
|
||||||
_vacContext.VertexInfoBufferUpdater.SetVertexOffset(index, 0, 0);
|
_vacContext.VertexInfoBufferUpdater.SetVertexOffset(index, 0, 0);
|
||||||
|
SetDummyBufferTexture(_vertexAsCompute.Reservations, index, format);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vbStride = vertexBuffer.UnpackStride();
|
int vbStride = vertexBuffer.UnpackStride();
|
||||||
ulong vbSize = GetVertexBufferSize(address, endAddress.Pack(), vbStride, _indexed, instanced, _firstVertex, _count);
|
ulong vbSize = GetVertexBufferSize(address, endAddress.Pack(), vbStride, _indexed, instanced, _firstVertex, _count);
|
||||||
|
|
||||||
|
ulong oldVbSize = vbSize;
|
||||||
|
|
||||||
ulong attributeOffset = (ulong)vertexAttrib.UnpackOffset();
|
ulong attributeOffset = (ulong)vertexAttrib.UnpackOffset();
|
||||||
int componentSize = format.GetScalarSize();
|
int componentSize = format.GetScalarSize();
|
||||||
|
|
||||||
@@ -341,6 +345,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
|
|||||||
return maxOutputVertices / verticesPerPrimitive;
|
return maxOutputVertices / verticesPerPrimitive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Binds a dummy buffer as vertex buffer into a buffer texture.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reservations">Shader resource binding reservations</param>
|
||||||
|
/// <param name="index">Buffer texture index</param>
|
||||||
|
/// <param name="format">Buffer texture format</param>
|
||||||
|
private readonly void SetDummyBufferTexture(ResourceReservations reservations, int index, Format format)
|
||||||
|
{
|
||||||
|
ITexture bufferTexture = _vacContext.EnsureBufferTexture(index + 2, format);
|
||||||
|
bufferTexture.SetStorage(_vacContext.GetDummyBufferRange());
|
||||||
|
|
||||||
|
_context.Renderer.Pipeline.SetTextureAndSampler(ShaderStage.Compute, reservations.GetVertexBufferTextureBinding(index), bufferTexture, null);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Binds a vertex buffer into a buffer texture.
|
/// Binds a vertex buffer into a buffer texture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Ryujinx.Graphics.Texture;
|
|||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
@@ -999,7 +998,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
bool dataOverlaps = texture.DataOverlaps(overlap, compatibility);
|
bool dataOverlaps = texture.DataOverlaps(overlap, compatibility);
|
||||||
|
|
||||||
if (!overlap.IsView && dataOverlaps && !incompatibleOverlaps.Any(incompatible => incompatible.Group == overlap.Group))
|
if (!overlap.IsView && dataOverlaps && !incompatibleOverlaps.Exists(incompatible => incompatible.Group == overlap.Group))
|
||||||
{
|
{
|
||||||
incompatibleOverlaps.Add(new TextureIncompatibleOverlap(overlap.Group, compatibility));
|
incompatibleOverlaps.Add(new TextureIncompatibleOverlap(overlap.Group, compatibility));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ using Ryujinx.Memory.Range;
|
|||||||
using Ryujinx.Memory.Tracking;
|
using Ryujinx.Memory.Tracking;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Image
|
namespace Ryujinx.Graphics.Gpu.Image
|
||||||
@@ -1556,7 +1555,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="copy">True if the overlap should register copy dependencies</param>
|
/// <param name="copy">True if the overlap should register copy dependencies</param>
|
||||||
public void RegisterIncompatibleOverlap(TextureIncompatibleOverlap other, bool copy)
|
public void RegisterIncompatibleOverlap(TextureIncompatibleOverlap other, bool copy)
|
||||||
{
|
{
|
||||||
if (!_incompatibleOverlaps.Any(overlap => overlap.Group == other.Group))
|
if (!_incompatibleOverlaps.Exists(overlap => overlap.Group == other.Group))
|
||||||
{
|
{
|
||||||
if (copy && other.Compatibility == TextureViewCompatibility.LayoutIncompatible)
|
if (copy && other.Compatibility == TextureViewCompatibility.LayoutIncompatible)
|
||||||
{
|
{
|
||||||
@@ -1702,4 +1701,3 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -721,7 +721,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <param name="format">The format of the texture</param>
|
/// <param name="format">The format of the texture</param>
|
||||||
/// <param name="components">The texture swizzle components</param>
|
/// <param name="components">The texture swizzle components</param>
|
||||||
/// <returns>The depth-stencil mode</returns>
|
/// <returns>The depth-stencil mode</returns>
|
||||||
private static DepthStencilMode GetDepthStencilMode(Format format, params ReadOnlySpan<SwizzleComponent> components)
|
private static DepthStencilMode GetDepthStencilMode(Format format, params SwizzleComponent[] components)
|
||||||
{
|
{
|
||||||
// R = Depth, G = Stencil.
|
// R = Depth, G = Stencil.
|
||||||
// On 24-bits depth formats, this is inverted (Stencil is R etc).
|
// On 24-bits depth formats, this is inverted (Stencil is R etc).
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using Ryujinx.Common.Pools;
|
|||||||
using Ryujinx.Memory.Range;
|
using Ryujinx.Memory.Range;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Memory
|
namespace Ryujinx.Graphics.Gpu.Memory
|
||||||
{
|
{
|
||||||
@@ -77,7 +76,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
private BufferMigration _source;
|
private BufferMigration _source;
|
||||||
private BufferModifiedRangeList _migrationTarget;
|
private BufferModifiedRangeList _migrationTarget;
|
||||||
|
|
||||||
private readonly Lock _lock = new();
|
private readonly object _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the modified range list has any entries or not.
|
/// Whether the modified range list has any entries or not.
|
||||||
@@ -436,7 +435,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
|
|
||||||
if (_source == null)
|
if (_source == null)
|
||||||
{
|
{
|
||||||
// Create a new migration.
|
// Create a new migration.
|
||||||
_source = new BufferMigration(new BufferMigrationSpan[] { span }, this, _context.SyncNumber);
|
_source = new BufferMigration(new BufferMigrationSpan[] { span }, this, _context.SyncNumber);
|
||||||
|
|
||||||
_context.RegisterBufferMigration(_source);
|
_context.RegisterBufferMigration(_source);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -324,11 +324,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
|
|
||||||
bool loadHostCache = header.CodeGenVersion == CodeGenVersion;
|
bool loadHostCache = header.CodeGenVersion == CodeGenVersion;
|
||||||
|
|
||||||
if (context.Capabilities.Api == TargetApi.Metal)
|
|
||||||
{
|
|
||||||
loadHostCache = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int programIndex = 0;
|
int programIndex = 0;
|
||||||
|
|
||||||
DataEntry entry = new();
|
DataEntry entry = new();
|
||||||
@@ -397,8 +392,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
context,
|
context,
|
||||||
shaders,
|
shaders,
|
||||||
specState.PipelineState,
|
specState.PipelineState,
|
||||||
specState.TransformFeedbackDescriptors != null,
|
specState.TransformFeedbackDescriptors != null);
|
||||||
specState.ComputeState.GetLocalSize());
|
|
||||||
|
|
||||||
IProgram hostProgram;
|
IProgram hostProgram;
|
||||||
|
|
||||||
@@ -635,10 +629,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.Capabilities.Api != TargetApi.Metal)
|
WriteHostCode(context, hostCode, program.Shaders, streams, timestamp);
|
||||||
{
|
|
||||||
WriteHostCode(context, hostCode, program.Shaders, streams, timestamp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -490,12 +490,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
{
|
{
|
||||||
ShaderSource[] shaderSources = new ShaderSource[compilation.TranslatedStages.Length];
|
ShaderSource[] shaderSources = new ShaderSource[compilation.TranslatedStages.Length];
|
||||||
|
|
||||||
ref GpuChannelComputeState computeState = ref compilation.SpecializationState.ComputeState;
|
ShaderInfoBuilder shaderInfoBuilder = new(_context, compilation.SpecializationState.TransformFeedbackDescriptors != null);
|
||||||
|
|
||||||
ShaderInfoBuilder shaderInfoBuilder = new(
|
|
||||||
_context,
|
|
||||||
compilation.SpecializationState.TransformFeedbackDescriptors != null,
|
|
||||||
computeLocalSize: computeState.GetLocalSize());
|
|
||||||
|
|
||||||
for (int index = 0; index < compilation.TranslatedStages.Length; index++)
|
for (int index = 0; index < compilation.TranslatedStages.Length; index++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
private readonly GpuAccessorState _state;
|
private readonly GpuAccessorState _state;
|
||||||
private readonly int _stageIndex;
|
private readonly int _stageIndex;
|
||||||
private readonly bool _compute;
|
private readonly bool _compute;
|
||||||
private readonly bool _isOpenGL;
|
private readonly bool _isVulkan;
|
||||||
private readonly bool _hasGeometryShader;
|
private readonly bool _hasGeometryShader;
|
||||||
private readonly bool _supportsQuads;
|
private readonly bool _supportsQuads;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
_channel = channel;
|
_channel = channel;
|
||||||
_state = state;
|
_state = state;
|
||||||
_stageIndex = stageIndex;
|
_stageIndex = stageIndex;
|
||||||
_isOpenGL = context.Capabilities.Api == TargetApi.OpenGL;
|
_isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
|
||||||
_hasGeometryShader = hasGeometryShader;
|
_hasGeometryShader = hasGeometryShader;
|
||||||
_supportsQuads = context.Capabilities.SupportsQuads;
|
_supportsQuads = context.Capabilities.SupportsQuads;
|
||||||
|
|
||||||
@@ -116,10 +116,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
public GpuGraphicsState QueryGraphicsState()
|
public GpuGraphicsState QueryGraphicsState()
|
||||||
{
|
{
|
||||||
return _state.GraphicsState.CreateShaderGraphicsState(
|
return _state.GraphicsState.CreateShaderGraphicsState(
|
||||||
_isOpenGL,
|
!_isVulkan,
|
||||||
_supportsQuads,
|
_supportsQuads,
|
||||||
_hasGeometryShader,
|
_hasGeometryShader,
|
||||||
!_isOpenGL || _state.GraphicsState.YNegateEnabled);
|
_isVulkan || _state.GraphicsState.YNegateEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
int binding;
|
int binding;
|
||||||
|
|
||||||
if (_context.Capabilities.Api != TargetApi.OpenGL)
|
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||||
{
|
{
|
||||||
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer");
|
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer");
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
int binding;
|
int binding;
|
||||||
|
|
||||||
if (_context.Capabilities.Api != TargetApi.OpenGL)
|
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||||
{
|
{
|
||||||
if (count == 1)
|
if (count == 1)
|
||||||
{
|
{
|
||||||
@@ -103,7 +103,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
int binding;
|
int binding;
|
||||||
|
|
||||||
if (_context.Capabilities.Api != TargetApi.OpenGL)
|
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||||
{
|
{
|
||||||
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
|
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
{
|
{
|
||||||
int binding;
|
int binding;
|
||||||
|
|
||||||
if (_context.Capabilities.Api != TargetApi.OpenGL)
|
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||||
{
|
{
|
||||||
if (count == 1)
|
if (count == 1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Gpu.Shader
|
namespace Ryujinx.Graphics.Gpu.Shader
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -63,14 +61,5 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
SharedMemorySize = sharedMemorySize;
|
SharedMemorySize = sharedMemorySize;
|
||||||
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the local group size of the shader in a GAL compatible struct.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Local group size</returns>
|
|
||||||
public ComputeSize GetLocalSize()
|
|
||||||
{
|
|
||||||
return new ComputeSize(LocalSizeX, LocalSizeY, LocalSizeZ);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,10 +224,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
TranslatedShader translatedShader = TranslateShader(_dumper, channel, translatorContext, cachedGuestCode, asCompute: false);
|
TranslatedShader translatedShader = TranslateShader(_dumper, channel, translatorContext, cachedGuestCode, asCompute: false);
|
||||||
|
|
||||||
ShaderSource[] shaderSourcesArray = new ShaderSource[] { CreateShaderSource(translatedShader.Program) };
|
ShaderSource[] shaderSourcesArray = new ShaderSource[] { CreateShaderSource(translatedShader.Program) };
|
||||||
ShaderInfo info = ShaderInfoBuilder.BuildForCompute(
|
ShaderInfo info = ShaderInfoBuilder.BuildForCompute(_context, translatedShader.Program.Info);
|
||||||
_context,
|
|
||||||
translatedShader.Program.Info,
|
|
||||||
computeState.GetLocalSize());
|
|
||||||
IProgram hostProgram = _context.Renderer.CreateProgram(shaderSourcesArray, info);
|
IProgram hostProgram = _context.Renderer.CreateProgram(shaderSourcesArray, info);
|
||||||
|
|
||||||
cpShader = new CachedShaderProgram(hostProgram, specState, translatedShader.Shader);
|
cpShader = new CachedShaderProgram(hostProgram, specState, translatedShader.Shader);
|
||||||
@@ -428,8 +425,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
TranslatorContext lastInVertexPipeline = geometryToCompute ? translatorContexts[4] ?? currentStage : currentStage;
|
TranslatorContext lastInVertexPipeline = geometryToCompute ? translatorContexts[4] ?? currentStage : currentStage;
|
||||||
|
|
||||||
(program, ShaderProgramInfo vacInfo) = lastInVertexPipeline.GenerateVertexPassthroughForCompute();
|
program = lastInVertexPipeline.GenerateVertexPassthroughForCompute();
|
||||||
infoBuilder.AddStageInfoVac(vacInfo);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -534,7 +530,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
private ShaderAsCompute CreateHostVertexAsComputeProgram(ShaderProgram program, TranslatorContext context, bool tfEnabled)
|
private ShaderAsCompute CreateHostVertexAsComputeProgram(ShaderProgram program, TranslatorContext context, bool tfEnabled)
|
||||||
{
|
{
|
||||||
ShaderSource source = new(program.Code, program.BinaryCode, ShaderStage.Compute, program.Language);
|
ShaderSource source = new(program.Code, program.BinaryCode, ShaderStage.Compute, program.Language);
|
||||||
ShaderInfo info = ShaderInfoBuilder.BuildForVertexAsCompute(_context, program.Info, context.GetVertexAsComputeInfo(), tfEnabled);
|
ShaderInfo info = ShaderInfoBuilder.BuildForVertexAsCompute(_context, program.Info, tfEnabled);
|
||||||
|
|
||||||
return new(_context.Renderer.CreateProgram(new[] { source }, info), program.Info, context.GetResourceReservations());
|
return new(_context.Renderer.CreateProgram(new[] { source }, info), program.Info, context.GetResourceReservations());
|
||||||
}
|
}
|
||||||
@@ -826,20 +822,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates shader translation options with the requested graphics API and flags.
|
/// Creates shader translation options with the requested graphics API and flags.
|
||||||
/// The shader language is chosen based on the current configuration and graphics API.
|
/// The shader language is choosen based on the current configuration and graphics API.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="api">Target graphics API</param>
|
/// <param name="api">Target graphics API</param>
|
||||||
/// <param name="flags">Translation flags</param>
|
/// <param name="flags">Translation flags</param>
|
||||||
/// <returns>Translation options</returns>
|
/// <returns>Translation options</returns>
|
||||||
private static TranslationOptions CreateTranslationOptions(TargetApi api, TranslationFlags flags)
|
private static TranslationOptions CreateTranslationOptions(TargetApi api, TranslationFlags flags)
|
||||||
{
|
{
|
||||||
TargetLanguage lang = api switch
|
TargetLanguage lang = GraphicsConfig.EnableSpirvCompilationOnVulkan && api == TargetApi.Vulkan
|
||||||
{
|
? TargetLanguage.Spirv
|
||||||
TargetApi.OpenGL => TargetLanguage.Glsl,
|
: TargetLanguage.Glsl;
|
||||||
TargetApi.Vulkan => GraphicsConfig.EnableSpirvCompilationOnVulkan ? TargetLanguage.Spirv : TargetLanguage.Glsl,
|
|
||||||
TargetApi.Metal => TargetLanguage.Msl,
|
|
||||||
_ => throw new NotImplementedException()
|
|
||||||
};
|
|
||||||
|
|
||||||
return new TranslationOptions(lang, api, flags);
|
return new TranslationOptions(lang, api, flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
ResourceStages.Geometry;
|
ResourceStages.Geometry;
|
||||||
|
|
||||||
private readonly GpuContext _context;
|
private readonly GpuContext _context;
|
||||||
private readonly ComputeSize _computeLocalSize;
|
|
||||||
|
|
||||||
private int _fragmentOutputMap;
|
private int _fragmentOutputMap;
|
||||||
|
|
||||||
@@ -40,11 +39,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="context">GPU context that owns the shaders that will be added to the builder</param>
|
/// <param name="context">GPU context that owns the shaders that will be added to the builder</param>
|
||||||
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
||||||
/// <param name="vertexAsCompute">Indicates that the vertex shader will be emulated on a compute shader</param>
|
/// <param name="vertexAsCompute">Indicates that the vertex shader will be emulated on a compute shader</param>
|
||||||
/// <param name="computeLocalSize">Indicates the local thread size for a compute shader</param>
|
public ShaderInfoBuilder(GpuContext context, bool tfEnabled, bool vertexAsCompute = false)
|
||||||
public ShaderInfoBuilder(GpuContext context, bool tfEnabled, bool vertexAsCompute = false, ComputeSize computeLocalSize = default)
|
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_computeLocalSize = computeLocalSize;
|
|
||||||
|
|
||||||
_fragmentOutputMap = -1;
|
_fragmentOutputMap = -1;
|
||||||
|
|
||||||
@@ -98,7 +95,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count, bool write = false)
|
private void PopulateDescriptorAndUsages(ResourceStages stages, ResourceType type, int setIndex, int start, int count, bool write = false)
|
||||||
{
|
{
|
||||||
AddDescriptor(stages, type, setIndex, start, count);
|
AddDescriptor(stages, type, setIndex, start, count);
|
||||||
// AddUsage(stages, type, setIndex, start, count, write);
|
AddUsage(stages, type, setIndex, start, count, write);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -162,25 +159,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
AddUsage(info.Images, stages, isImage: true);
|
AddUsage(info.Images, stages, isImage: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddStageInfoVac(ShaderProgramInfo info)
|
|
||||||
{
|
|
||||||
ResourceStages stages = info.Stage switch
|
|
||||||
{
|
|
||||||
ShaderStage.Compute => ResourceStages.Compute,
|
|
||||||
ShaderStage.Vertex => ResourceStages.Vertex,
|
|
||||||
ShaderStage.TessellationControl => ResourceStages.TessellationControl,
|
|
||||||
ShaderStage.TessellationEvaluation => ResourceStages.TessellationEvaluation,
|
|
||||||
ShaderStage.Geometry => ResourceStages.Geometry,
|
|
||||||
ShaderStage.Fragment => ResourceStages.Fragment,
|
|
||||||
_ => ResourceStages.None,
|
|
||||||
};
|
|
||||||
|
|
||||||
AddUsage(info.CBuffers, stages, isStorage: false);
|
|
||||||
AddUsage(info.SBuffers, stages, isStorage: true);
|
|
||||||
AddUsage(info.Textures, stages, isImage: false);
|
|
||||||
AddUsage(info.Images, stages, isImage: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a resource descriptor to the list of descriptors.
|
/// Adds a resource descriptor to the list of descriptors.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -383,7 +361,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
|
|
||||||
ResourceLayout resourceLayout = new(descriptors.AsReadOnly(), usages.AsReadOnly());
|
ResourceLayout resourceLayout = new(descriptors.AsReadOnly(), usages.AsReadOnly());
|
||||||
|
|
||||||
return new ShaderInfo(_fragmentOutputMap, resourceLayout, _computeLocalSize, pipeline, fromCache);
|
if (pipeline.HasValue)
|
||||||
|
{
|
||||||
|
return new ShaderInfo(_fragmentOutputMap, resourceLayout, pipeline.Value, fromCache);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new ShaderInfo(_fragmentOutputMap, resourceLayout, fromCache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -393,16 +378,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="programs">Shaders from the disk cache</param>
|
/// <param name="programs">Shaders from the disk cache</param>
|
||||||
/// <param name="pipeline">Optional pipeline for background compilation</param>
|
/// <param name="pipeline">Optional pipeline for background compilation</param>
|
||||||
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
||||||
/// <param name="computeLocalSize">Compute local thread size</param>
|
|
||||||
/// <returns>Shader information</returns>
|
/// <returns>Shader information</returns>
|
||||||
public static ShaderInfo BuildForCache(
|
public static ShaderInfo BuildForCache(
|
||||||
GpuContext context,
|
GpuContext context,
|
||||||
IEnumerable<CachedShaderStage> programs,
|
IEnumerable<CachedShaderStage> programs,
|
||||||
ProgramPipelineState? pipeline,
|
ProgramPipelineState? pipeline,
|
||||||
bool tfEnabled,
|
bool tfEnabled)
|
||||||
ComputeSize computeLocalSize)
|
|
||||||
{
|
{
|
||||||
ShaderInfoBuilder builder = new(context, tfEnabled, computeLocalSize: computeLocalSize);
|
ShaderInfoBuilder builder = new(context, tfEnabled);
|
||||||
|
|
||||||
foreach (CachedShaderStage program in programs)
|
foreach (CachedShaderStage program in programs)
|
||||||
{
|
{
|
||||||
@@ -420,12 +403,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">GPU context that owns the shader</param>
|
/// <param name="context">GPU context that owns the shader</param>
|
||||||
/// <param name="info">Compute shader information</param>
|
/// <param name="info">Compute shader information</param>
|
||||||
/// <param name="computeLocalSize">Compute local thread size</param>
|
|
||||||
/// <param name="fromCache">True if the compute shader comes from a disk cache, false otherwise</param>
|
/// <param name="fromCache">True if the compute shader comes from a disk cache, false otherwise</param>
|
||||||
/// <returns>Shader information</returns>
|
/// <returns>Shader information</returns>
|
||||||
public static ShaderInfo BuildForCompute(GpuContext context, ShaderProgramInfo info, ComputeSize computeLocalSize, bool fromCache = false)
|
public static ShaderInfo BuildForCompute(GpuContext context, ShaderProgramInfo info, bool fromCache = false)
|
||||||
{
|
{
|
||||||
ShaderInfoBuilder builder = new(context, tfEnabled: false, vertexAsCompute: false, computeLocalSize: computeLocalSize);
|
ShaderInfoBuilder builder = new(context, tfEnabled: false, vertexAsCompute: false);
|
||||||
|
|
||||||
builder.AddStageInfo(info);
|
builder.AddStageInfo(info);
|
||||||
|
|
||||||
@@ -440,11 +422,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
|||||||
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
/// <param name="tfEnabled">Indicates if the graphics shader is used with transform feedback enabled</param>
|
||||||
/// <param name="fromCache">True if the compute shader comes from a disk cache, false otherwise</param>
|
/// <param name="fromCache">True if the compute shader comes from a disk cache, false otherwise</param>
|
||||||
/// <returns>Shader information</returns>
|
/// <returns>Shader information</returns>
|
||||||
public static ShaderInfo BuildForVertexAsCompute(GpuContext context, ShaderProgramInfo info, ShaderProgramInfo info2, bool tfEnabled, bool fromCache = false)
|
public static ShaderInfo BuildForVertexAsCompute(GpuContext context, ShaderProgramInfo info, bool tfEnabled, bool fromCache = false)
|
||||||
{
|
{
|
||||||
ShaderInfoBuilder builder = new(context, tfEnabled, vertexAsCompute: true, computeLocalSize: ComputeSize.VtgAsCompute);
|
ShaderInfoBuilder builder = new(context, tfEnabled, vertexAsCompute: true);
|
||||||
|
|
||||||
builder.AddStageInfoVac(info2);
|
|
||||||
builder.AddStageInfo(info, vertexAsCompute: true);
|
builder.AddStageInfo(info, vertexAsCompute: true);
|
||||||
|
|
||||||
return builder.Build(null, fromCache);
|
return builder.Build(null, fromCache);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using SharpMetal;
|
|
||||||
using SharpMetal.ObjectiveCCore;
|
|
||||||
using SharpMetal.QuartzCore;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
// ReSharper disable InconsistentNaming
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal.SharpMetalExtensions
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("OSX")]
|
|
||||||
public static class CAMetalLayerExtensions
|
|
||||||
{
|
|
||||||
private static readonly Selector sel_displaySyncEnabled = "displaySyncEnabled";
|
|
||||||
private static readonly Selector sel_setDisplaySyncEnabled = "setDisplaySyncEnabled:";
|
|
||||||
|
|
||||||
public static bool IsDisplaySyncEnabled(this CAMetalLayer metalLayer)
|
|
||||||
=> ObjectiveCRuntime.bool_objc_msgSend(metalLayer.NativePtr, sel_displaySyncEnabled);
|
|
||||||
|
|
||||||
public static void SetDisplaySyncEnabled(this CAMetalLayer metalLayer, bool enabled)
|
|
||||||
=> ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDisplaySyncEnabled, enabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="SharpMetal" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
interface IAuto
|
|
||||||
{
|
|
||||||
bool HasCommandBufferDependency(CommandBufferScoped cbs);
|
|
||||||
|
|
||||||
void IncrementReferenceCount();
|
|
||||||
void DecrementReferenceCount(int cbIndex);
|
|
||||||
void DecrementReferenceCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IAutoPrivate : IAuto
|
|
||||||
{
|
|
||||||
void AddCommandBufferDependencies(CommandBufferScoped cbs);
|
|
||||||
}
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class Auto<T> : IAutoPrivate, IDisposable where T : IDisposable
|
|
||||||
{
|
|
||||||
private int _referenceCount;
|
|
||||||
private T _value;
|
|
||||||
|
|
||||||
private readonly BitMap _cbOwnership;
|
|
||||||
private readonly MultiFenceHolder _waitable;
|
|
||||||
|
|
||||||
private bool _disposed;
|
|
||||||
private bool _destroyed;
|
|
||||||
|
|
||||||
public Auto(T value)
|
|
||||||
{
|
|
||||||
_referenceCount = 1;
|
|
||||||
_value = value;
|
|
||||||
_cbOwnership = new BitMap(CommandBufferPool.MaxCommandBuffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto(T value, MultiFenceHolder waitable) : this(value)
|
|
||||||
{
|
|
||||||
_waitable = waitable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Get(CommandBufferScoped cbs, int offset, int size, bool write = false)
|
|
||||||
{
|
|
||||||
_waitable?.AddBufferUse(cbs.CommandBufferIndex, offset, size, write);
|
|
||||||
return Get(cbs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetUnsafe()
|
|
||||||
{
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Get(CommandBufferScoped cbs)
|
|
||||||
{
|
|
||||||
if (!_destroyed)
|
|
||||||
{
|
|
||||||
AddCommandBufferDependencies(cbs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasCommandBufferDependency(CommandBufferScoped cbs)
|
|
||||||
{
|
|
||||||
return _cbOwnership.IsSet(cbs.CommandBufferIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasRentedCommandBufferDependency(CommandBufferPool cbp)
|
|
||||||
{
|
|
||||||
return _cbOwnership.AnySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddCommandBufferDependencies(CommandBufferScoped cbs)
|
|
||||||
{
|
|
||||||
// We don't want to add a reference to this object to the command buffer
|
|
||||||
// more than once, so if we detect that the command buffer already has ownership
|
|
||||||
// of this object, then we can just return without doing anything else.
|
|
||||||
if (_cbOwnership.Set(cbs.CommandBufferIndex))
|
|
||||||
{
|
|
||||||
if (_waitable != null)
|
|
||||||
{
|
|
||||||
cbs.AddWaitable(_waitable);
|
|
||||||
}
|
|
||||||
|
|
||||||
cbs.AddDependant(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryIncrementReferenceCount()
|
|
||||||
{
|
|
||||||
int lastValue;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
lastValue = _referenceCount;
|
|
||||||
|
|
||||||
if (lastValue == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void IncrementReferenceCount()
|
|
||||||
{
|
|
||||||
if (Interlocked.Increment(ref _referenceCount) == 1)
|
|
||||||
{
|
|
||||||
Interlocked.Decrement(ref _referenceCount);
|
|
||||||
throw new InvalidOperationException("Attempted to increment the reference count of an object that was already destroyed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DecrementReferenceCount(int cbIndex)
|
|
||||||
{
|
|
||||||
_cbOwnership.Clear(cbIndex);
|
|
||||||
DecrementReferenceCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DecrementReferenceCount()
|
|
||||||
{
|
|
||||||
if (Interlocked.Decrement(ref _referenceCount) == 0)
|
|
||||||
{
|
|
||||||
_value.Dispose();
|
|
||||||
_value = default;
|
|
||||||
_destroyed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.Assert(_referenceCount >= 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (!_disposed)
|
|
||||||
{
|
|
||||||
DecrementReferenceCount();
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class BackgroundResource : IDisposable
|
|
||||||
{
|
|
||||||
private readonly MetalRenderer _renderer;
|
|
||||||
|
|
||||||
private CommandBufferPool _pool;
|
|
||||||
private PersistentFlushBuffer _flushBuffer;
|
|
||||||
|
|
||||||
public BackgroundResource(MetalRenderer renderer)
|
|
||||||
{
|
|
||||||
_renderer = renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBufferPool GetPool()
|
|
||||||
{
|
|
||||||
if (_pool == null)
|
|
||||||
{
|
|
||||||
MTLCommandQueue queue = _renderer.BackgroundQueue;
|
|
||||||
_pool = new CommandBufferPool(queue, true);
|
|
||||||
_pool.Initialize(null); // TODO: Proper encoder factory for background render/compute
|
|
||||||
}
|
|
||||||
|
|
||||||
return _pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PersistentFlushBuffer GetFlushBuffer()
|
|
||||||
{
|
|
||||||
_flushBuffer ??= new PersistentFlushBuffer(_renderer);
|
|
||||||
|
|
||||||
return _flushBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_pool?.Dispose();
|
|
||||||
_flushBuffer?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class BackgroundResources : IDisposable
|
|
||||||
{
|
|
||||||
private readonly MetalRenderer _renderer;
|
|
||||||
|
|
||||||
private readonly Dictionary<Thread, BackgroundResource> _resources;
|
|
||||||
|
|
||||||
public BackgroundResources(MetalRenderer renderer)
|
|
||||||
{
|
|
||||||
_renderer = renderer;
|
|
||||||
|
|
||||||
_resources = new Dictionary<Thread, BackgroundResource>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Cleanup()
|
|
||||||
{
|
|
||||||
lock (_resources)
|
|
||||||
{
|
|
||||||
foreach (KeyValuePair<Thread, BackgroundResource> tuple in _resources)
|
|
||||||
{
|
|
||||||
if (!tuple.Key.IsAlive)
|
|
||||||
{
|
|
||||||
tuple.Value.Dispose();
|
|
||||||
_resources.Remove(tuple.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BackgroundResource Get()
|
|
||||||
{
|
|
||||||
Thread thread = Thread.CurrentThread;
|
|
||||||
|
|
||||||
lock (_resources)
|
|
||||||
{
|
|
||||||
if (!_resources.TryGetValue(thread, out BackgroundResource resource))
|
|
||||||
{
|
|
||||||
Cleanup();
|
|
||||||
|
|
||||||
resource = new BackgroundResource(_renderer);
|
|
||||||
|
|
||||||
_resources[thread] = resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
return resource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
lock (_resources)
|
|
||||||
{
|
|
||||||
foreach (var resource in _resources.Values)
|
|
||||||
{
|
|
||||||
resource.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
readonly struct BitMap
|
|
||||||
{
|
|
||||||
public const int IntSize = 64;
|
|
||||||
|
|
||||||
private const int IntShift = 6;
|
|
||||||
private const int IntMask = IntSize - 1;
|
|
||||||
|
|
||||||
private readonly long[] _masks;
|
|
||||||
|
|
||||||
public BitMap(int count)
|
|
||||||
{
|
|
||||||
_masks = new long[(count + IntMask) / IntSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AnySet()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _masks.Length; i++)
|
|
||||||
{
|
|
||||||
if (_masks[i] != 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSet(int bit)
|
|
||||||
{
|
|
||||||
int wordIndex = bit >> IntShift;
|
|
||||||
int wordBit = bit & IntMask;
|
|
||||||
|
|
||||||
long wordMask = 1L << wordBit;
|
|
||||||
|
|
||||||
return (_masks[wordIndex] & wordMask) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSet(int start, int end)
|
|
||||||
{
|
|
||||||
if (start == end)
|
|
||||||
{
|
|
||||||
return IsSet(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
int startIndex = start >> IntShift;
|
|
||||||
int startBit = start & IntMask;
|
|
||||||
long startMask = -1L << startBit;
|
|
||||||
|
|
||||||
int endIndex = end >> IntShift;
|
|
||||||
int endBit = end & IntMask;
|
|
||||||
long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
|
|
||||||
|
|
||||||
if (startIndex == endIndex)
|
|
||||||
{
|
|
||||||
return (_masks[startIndex] & startMask & endMask) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((_masks[startIndex] & startMask) != 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = startIndex + 1; i < endIndex; i++)
|
|
||||||
{
|
|
||||||
if (_masks[i] != 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((_masks[endIndex] & endMask) != 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Set(int bit)
|
|
||||||
{
|
|
||||||
int wordIndex = bit >> IntShift;
|
|
||||||
int wordBit = bit & IntMask;
|
|
||||||
|
|
||||||
long wordMask = 1L << wordBit;
|
|
||||||
|
|
||||||
if ((_masks[wordIndex] & wordMask) != 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_masks[wordIndex] |= wordMask;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetRange(int start, int end)
|
|
||||||
{
|
|
||||||
if (start == end)
|
|
||||||
{
|
|
||||||
Set(start);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int startIndex = start >> IntShift;
|
|
||||||
int startBit = start & IntMask;
|
|
||||||
long startMask = -1L << startBit;
|
|
||||||
|
|
||||||
int endIndex = end >> IntShift;
|
|
||||||
int endBit = end & IntMask;
|
|
||||||
long endMask = (long)(ulong.MaxValue >> (IntMask - endBit));
|
|
||||||
|
|
||||||
if (startIndex == endIndex)
|
|
||||||
{
|
|
||||||
_masks[startIndex] |= startMask & endMask;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_masks[startIndex] |= startMask;
|
|
||||||
|
|
||||||
for (int i = startIndex + 1; i < endIndex; i++)
|
|
||||||
{
|
|
||||||
_masks[i] |= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
_masks[endIndex] |= endMask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear(int bit)
|
|
||||||
{
|
|
||||||
int wordIndex = bit >> IntShift;
|
|
||||||
int wordBit = bit & IntMask;
|
|
||||||
|
|
||||||
long wordMask = 1L << wordBit;
|
|
||||||
|
|
||||||
_masks[wordIndex] &= ~wordMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _masks.Length; i++)
|
|
||||||
{
|
|
||||||
_masks[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearInt(int start, int end)
|
|
||||||
{
|
|
||||||
for (int i = start; i <= end; i++)
|
|
||||||
{
|
|
||||||
_masks[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,385 +0,0 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class BufferHolder : IDisposable
|
|
||||||
{
|
|
||||||
private CacheByRange<BufferHolder> _cachedConvertedBuffers;
|
|
||||||
|
|
||||||
public int Size { get; }
|
|
||||||
|
|
||||||
private readonly IntPtr _map;
|
|
||||||
private readonly MetalRenderer _renderer;
|
|
||||||
private readonly Pipeline _pipeline;
|
|
||||||
|
|
||||||
private readonly MultiFenceHolder _waitable;
|
|
||||||
private readonly Auto<DisposableBuffer> _buffer;
|
|
||||||
|
|
||||||
private readonly ReaderWriterLockSlim _flushLock;
|
|
||||||
private FenceHolder _flushFence;
|
|
||||||
private int _flushWaiting;
|
|
||||||
|
|
||||||
public BufferHolder(MetalRenderer renderer, Pipeline pipeline, MTLBuffer buffer, int size)
|
|
||||||
{
|
|
||||||
_renderer = renderer;
|
|
||||||
_pipeline = pipeline;
|
|
||||||
_map = buffer.Contents;
|
|
||||||
_waitable = new MultiFenceHolder(size);
|
|
||||||
_buffer = new Auto<DisposableBuffer>(new(buffer), _waitable);
|
|
||||||
|
|
||||||
_flushLock = new ReaderWriterLockSlim();
|
|
||||||
|
|
||||||
Size = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBuffer()
|
|
||||||
{
|
|
||||||
return _buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBuffer(bool isWrite)
|
|
||||||
{
|
|
||||||
if (isWrite)
|
|
||||||
{
|
|
||||||
SignalWrite(0, Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBuffer(int offset, int size, bool isWrite)
|
|
||||||
{
|
|
||||||
if (isWrite)
|
|
||||||
{
|
|
||||||
SignalWrite(offset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SignalWrite(int offset, int size)
|
|
||||||
{
|
|
||||||
if (offset == 0 && size == Size)
|
|
||||||
{
|
|
||||||
_cachedConvertedBuffers.Clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_cachedConvertedBuffers.ClearRange(offset, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearFlushFence()
|
|
||||||
{
|
|
||||||
// Assumes _flushLock is held as writer.
|
|
||||||
|
|
||||||
if (_flushFence != null)
|
|
||||||
{
|
|
||||||
if (_flushWaiting == 0)
|
|
||||||
{
|
|
||||||
_flushFence.Put();
|
|
||||||
}
|
|
||||||
|
|
||||||
_flushFence = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WaitForFlushFence()
|
|
||||||
{
|
|
||||||
if (_flushFence == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If storage has changed, make sure the fence has been reached so that the data is in place.
|
|
||||||
_flushLock.ExitReadLock();
|
|
||||||
_flushLock.EnterWriteLock();
|
|
||||||
|
|
||||||
if (_flushFence != null)
|
|
||||||
{
|
|
||||||
var fence = _flushFence;
|
|
||||||
Interlocked.Increment(ref _flushWaiting);
|
|
||||||
|
|
||||||
// Don't wait in the lock.
|
|
||||||
|
|
||||||
_flushLock.ExitWriteLock();
|
|
||||||
|
|
||||||
fence.Wait();
|
|
||||||
|
|
||||||
_flushLock.EnterWriteLock();
|
|
||||||
|
|
||||||
if (Interlocked.Decrement(ref _flushWaiting) == 0)
|
|
||||||
{
|
|
||||||
fence.Put();
|
|
||||||
}
|
|
||||||
|
|
||||||
_flushFence = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assumes the _flushLock is held as reader, returns in same state.
|
|
||||||
_flushLock.ExitWriteLock();
|
|
||||||
_flushLock.EnterReadLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PinnedSpan<byte> GetData(int offset, int size)
|
|
||||||
{
|
|
||||||
_flushLock.EnterReadLock();
|
|
||||||
|
|
||||||
WaitForFlushFence();
|
|
||||||
|
|
||||||
Span<byte> result;
|
|
||||||
|
|
||||||
if (_map != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
result = GetDataStorage(offset, size);
|
|
||||||
|
|
||||||
// Need to be careful here, the buffer can't be unmapped while the data is being used.
|
|
||||||
_buffer.IncrementReferenceCount();
|
|
||||||
|
|
||||||
_flushLock.ExitReadLock();
|
|
||||||
|
|
||||||
return PinnedSpan<byte>.UnsafeFromSpan(result, _buffer.DecrementReferenceCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidOperationException("The buffer is not mapped");
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe Span<byte> GetDataStorage(int offset, int size)
|
|
||||||
{
|
|
||||||
int mappingSize = Math.Min(size, Size - offset);
|
|
||||||
|
|
||||||
if (_map != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return new Span<byte>((void*)(_map + offset), mappingSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidOperationException("The buffer is not mapped.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void SetData(int offset, ReadOnlySpan<byte> data, CommandBufferScoped? cbs = null, bool allowCbsWait = true)
|
|
||||||
{
|
|
||||||
int dataSize = Math.Min(data.Length, Size - offset);
|
|
||||||
if (dataSize == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_map != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
// If persistently mapped, set the data directly if the buffer is not currently in use.
|
|
||||||
bool isRented = _buffer.HasRentedCommandBufferDependency(_renderer.CommandBufferPool);
|
|
||||||
|
|
||||||
// If the buffer is rented, take a little more time and check if the use overlaps this handle.
|
|
||||||
bool needsFlush = isRented && _waitable.IsBufferRangeInUse(offset, dataSize, false);
|
|
||||||
|
|
||||||
if (!needsFlush)
|
|
||||||
{
|
|
||||||
WaitForFences(offset, dataSize);
|
|
||||||
|
|
||||||
data[..dataSize].CopyTo(new Span<byte>((void*)(_map + offset), dataSize));
|
|
||||||
|
|
||||||
SignalWrite(offset, dataSize);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cbs != null &&
|
|
||||||
cbs.Value.Encoders.CurrentEncoderType == EncoderType.Render &&
|
|
||||||
!(_buffer.HasCommandBufferDependency(cbs.Value) &&
|
|
||||||
_waitable.IsBufferRangeInUse(cbs.Value.CommandBufferIndex, offset, dataSize)))
|
|
||||||
{
|
|
||||||
// If the buffer hasn't been used on the command buffer yet, try to preload the data.
|
|
||||||
// This avoids ending and beginning render passes on each buffer data upload.
|
|
||||||
|
|
||||||
cbs = _pipeline.GetPreloadCommandBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allowCbsWait)
|
|
||||||
{
|
|
||||||
_renderer.BufferManager.StagingBuffer.PushData(_renderer.CommandBufferPool, cbs, this, offset, data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool rentCbs = cbs == null;
|
|
||||||
if (rentCbs)
|
|
||||||
{
|
|
||||||
cbs = _renderer.CommandBufferPool.Rent();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_renderer.BufferManager.StagingBuffer.TryPushData(cbs.Value, this, offset, data))
|
|
||||||
{
|
|
||||||
// Need to do a slow upload.
|
|
||||||
BufferHolder srcHolder = _renderer.BufferManager.Create(dataSize);
|
|
||||||
srcHolder.SetDataUnchecked(0, data);
|
|
||||||
|
|
||||||
var srcBuffer = srcHolder.GetBuffer();
|
|
||||||
var dstBuffer = this.GetBuffer(true);
|
|
||||||
|
|
||||||
Copy(cbs.Value, srcBuffer, dstBuffer, 0, offset, dataSize);
|
|
||||||
|
|
||||||
srcHolder.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rentCbs)
|
|
||||||
{
|
|
||||||
cbs.Value.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void SetDataUnchecked(int offset, ReadOnlySpan<byte> data)
|
|
||||||
{
|
|
||||||
int dataSize = Math.Min(data.Length, Size - offset);
|
|
||||||
if (dataSize == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_map != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
data[..dataSize].CopyTo(new Span<byte>((void*)(_map + offset), dataSize));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetDataUnchecked<T>(int offset, ReadOnlySpan<T> data) where T : unmanaged
|
|
||||||
{
|
|
||||||
SetDataUnchecked(offset, MemoryMarshal.AsBytes(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Copy(
|
|
||||||
CommandBufferScoped cbs,
|
|
||||||
Auto<DisposableBuffer> src,
|
|
||||||
Auto<DisposableBuffer> dst,
|
|
||||||
int srcOffset,
|
|
||||||
int dstOffset,
|
|
||||||
int size,
|
|
||||||
bool registerSrcUsage = true)
|
|
||||||
{
|
|
||||||
var srcBuffer = registerSrcUsage ? src.Get(cbs, srcOffset, size).Value : src.GetUnsafe().Value;
|
|
||||||
var dstbuffer = dst.Get(cbs, dstOffset, size, true).Value;
|
|
||||||
|
|
||||||
cbs.Encoders.EnsureBlitEncoder().CopyFromBuffer(
|
|
||||||
srcBuffer,
|
|
||||||
(ulong)srcOffset,
|
|
||||||
dstbuffer,
|
|
||||||
(ulong)dstOffset,
|
|
||||||
(ulong)size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WaitForFences()
|
|
||||||
{
|
|
||||||
_waitable.WaitForFences();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WaitForFences(int offset, int size)
|
|
||||||
{
|
|
||||||
_waitable.WaitForFences(offset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool BoundToRange(int offset, ref int size)
|
|
||||||
{
|
|
||||||
if (offset >= Size)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = Math.Min(Size - offset, size);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, int offset, int size)
|
|
||||||
{
|
|
||||||
if (!BoundToRange(offset, ref size))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = new I8ToI16CacheKey(_renderer);
|
|
||||||
|
|
||||||
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
|
||||||
{
|
|
||||||
holder = _renderer.BufferManager.Create((size * 2 + 3) & ~3);
|
|
||||||
|
|
||||||
_renderer.HelperShader.ConvertI8ToI16(cbs, this, holder, offset, size);
|
|
||||||
|
|
||||||
key.SetBuffer(holder.GetBuffer());
|
|
||||||
|
|
||||||
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
return holder.GetBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferTopologyConversion(CommandBufferScoped cbs, int offset, int size, IndexBufferPattern pattern, int indexSize)
|
|
||||||
{
|
|
||||||
if (!BoundToRange(offset, ref size))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = new TopologyConversionCacheKey(_renderer, pattern, indexSize);
|
|
||||||
|
|
||||||
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out var holder))
|
|
||||||
{
|
|
||||||
// The destination index size is always I32.
|
|
||||||
|
|
||||||
int indexCount = size / indexSize;
|
|
||||||
|
|
||||||
int convertedCount = pattern.GetConvertedCount(indexCount);
|
|
||||||
|
|
||||||
holder = _renderer.BufferManager.Create(convertedCount * 4);
|
|
||||||
|
|
||||||
_renderer.HelperShader.ConvertIndexBuffer(cbs, this, holder, pattern, indexSize, offset, indexCount);
|
|
||||||
|
|
||||||
key.SetBuffer(holder.GetBuffer());
|
|
||||||
|
|
||||||
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
return holder.GetBuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetCachedConvertedBuffer(int offset, int size, ICacheKey key, out BufferHolder holder)
|
|
||||||
{
|
|
||||||
return _cachedConvertedBuffers.TryGetValue(offset, size, key, out holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddCachedConvertedBuffer(int offset, int size, ICacheKey key, BufferHolder holder)
|
|
||||||
{
|
|
||||||
_cachedConvertedBuffers.Add(offset, size, key, holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddCachedConvertedBufferDependency(int offset, int size, ICacheKey key, Dependency dependency)
|
|
||||||
{
|
|
||||||
_cachedConvertedBuffers.AddDependency(offset, size, key, dependency);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveCachedConvertedBuffer(int offset, int size, ICacheKey key)
|
|
||||||
{
|
|
||||||
_cachedConvertedBuffers.Remove(offset, size, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_pipeline.FlushCommandsIfWeightExceeding(_buffer, (ulong)Size);
|
|
||||||
|
|
||||||
_buffer.Dispose();
|
|
||||||
_cachedConvertedBuffers.Dispose();
|
|
||||||
|
|
||||||
_flushLock.EnterWriteLock();
|
|
||||||
|
|
||||||
ClearFlushFence();
|
|
||||||
|
|
||||||
_flushLock.ExitWriteLock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,237 +0,0 @@
|
|||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
readonly struct ScopedTemporaryBuffer : IDisposable
|
|
||||||
{
|
|
||||||
private readonly BufferManager _bufferManager;
|
|
||||||
private readonly bool _isReserved;
|
|
||||||
|
|
||||||
public readonly BufferRange Range;
|
|
||||||
public readonly BufferHolder Holder;
|
|
||||||
|
|
||||||
public BufferHandle Handle => Range.Handle;
|
|
||||||
public int Offset => Range.Offset;
|
|
||||||
|
|
||||||
public ScopedTemporaryBuffer(BufferManager bufferManager, BufferHolder holder, BufferHandle handle, int offset, int size, bool isReserved)
|
|
||||||
{
|
|
||||||
_bufferManager = bufferManager;
|
|
||||||
|
|
||||||
Range = new BufferRange(handle, offset, size);
|
|
||||||
Holder = holder;
|
|
||||||
|
|
||||||
_isReserved = isReserved;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (!_isReserved)
|
|
||||||
{
|
|
||||||
_bufferManager.Delete(Range.Handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class BufferManager : IDisposable
|
|
||||||
{
|
|
||||||
private readonly IdList<BufferHolder> _buffers;
|
|
||||||
|
|
||||||
private readonly MTLDevice _device;
|
|
||||||
private readonly MetalRenderer _renderer;
|
|
||||||
private readonly Pipeline _pipeline;
|
|
||||||
|
|
||||||
public int BufferCount { get; private set; }
|
|
||||||
|
|
||||||
public StagingBuffer StagingBuffer { get; }
|
|
||||||
|
|
||||||
public BufferManager(MTLDevice device, MetalRenderer renderer, Pipeline pipeline)
|
|
||||||
{
|
|
||||||
_device = device;
|
|
||||||
_renderer = renderer;
|
|
||||||
_pipeline = pipeline;
|
|
||||||
_buffers = new IdList<BufferHolder>();
|
|
||||||
|
|
||||||
StagingBuffer = new StagingBuffer(_renderer, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BufferHandle Create(nint pointer, int size)
|
|
||||||
{
|
|
||||||
// TODO: This is the wrong Metal method, we need no-copy which SharpMetal isn't giving us.
|
|
||||||
var buffer = _device.NewBuffer(pointer, (ulong)size, MTLResourceOptions.ResourceStorageModeShared);
|
|
||||||
|
|
||||||
if (buffer == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create buffer with size 0x{size:X}, and pointer 0x{pointer:X}.");
|
|
||||||
|
|
||||||
return BufferHandle.Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var holder = new BufferHolder(_renderer, _pipeline, buffer, size);
|
|
||||||
|
|
||||||
BufferCount++;
|
|
||||||
|
|
||||||
ulong handle64 = (uint)_buffers.Add(holder);
|
|
||||||
|
|
||||||
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BufferHandle CreateWithHandle(int size)
|
|
||||||
{
|
|
||||||
return CreateWithHandle(size, out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BufferHandle CreateWithHandle(int size, out BufferHolder holder)
|
|
||||||
{
|
|
||||||
holder = Create(size);
|
|
||||||
|
|
||||||
if (holder == null)
|
|
||||||
{
|
|
||||||
return BufferHandle.Null;
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferCount++;
|
|
||||||
|
|
||||||
ulong handle64 = (uint)_buffers.Add(holder);
|
|
||||||
|
|
||||||
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScopedTemporaryBuffer ReserveOrCreate(CommandBufferScoped cbs, int size)
|
|
||||||
{
|
|
||||||
StagingBufferReserved? result = StagingBuffer.TryReserveData(cbs, size);
|
|
||||||
|
|
||||||
if (result.HasValue)
|
|
||||||
{
|
|
||||||
return new ScopedTemporaryBuffer(this, result.Value.Buffer, StagingBuffer.Handle, result.Value.Offset, result.Value.Size, true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Create a temporary buffer.
|
|
||||||
BufferHandle handle = CreateWithHandle(size, out BufferHolder holder);
|
|
||||||
|
|
||||||
return new ScopedTemporaryBuffer(this, holder, handle, 0, size, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BufferHolder Create(int size)
|
|
||||||
{
|
|
||||||
var buffer = _device.NewBuffer((ulong)size, MTLResourceOptions.ResourceStorageModeShared);
|
|
||||||
|
|
||||||
if (buffer != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
return new BufferHolder(_renderer, _pipeline, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"Failed to create buffer with size 0x{size:X}.");
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBuffer(BufferHandle handle, bool isWrite, out int size)
|
|
||||||
{
|
|
||||||
if (TryGetBuffer(handle, out var holder))
|
|
||||||
{
|
|
||||||
size = holder.Size;
|
|
||||||
return holder.GetBuffer(isWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
size = 0;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBuffer(BufferHandle handle, int offset, int size, bool isWrite)
|
|
||||||
{
|
|
||||||
if (TryGetBuffer(handle, out var holder))
|
|
||||||
{
|
|
||||||
return holder.GetBuffer(offset, size, isWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBuffer(BufferHandle handle, bool isWrite)
|
|
||||||
{
|
|
||||||
if (TryGetBuffer(handle, out var holder))
|
|
||||||
{
|
|
||||||
return holder.GetBuffer(isWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size)
|
|
||||||
{
|
|
||||||
if (TryGetBuffer(handle, out var holder))
|
|
||||||
{
|
|
||||||
return holder.GetBufferI8ToI16(cbs, offset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Auto<DisposableBuffer> GetBufferTopologyConversion(CommandBufferScoped cbs, BufferHandle handle, int offset, int size, IndexBufferPattern pattern, int indexSize)
|
|
||||||
{
|
|
||||||
if (TryGetBuffer(handle, out var holder))
|
|
||||||
{
|
|
||||||
return holder.GetBufferTopologyConversion(cbs, offset, size, pattern, indexSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PinnedSpan<byte> GetData(BufferHandle handle, int offset, int size)
|
|
||||||
{
|
|
||||||
if (TryGetBuffer(handle, out var holder))
|
|
||||||
{
|
|
||||||
return holder.GetData(offset, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PinnedSpan<byte>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetData<T>(BufferHandle handle, int offset, ReadOnlySpan<T> data) where T : unmanaged
|
|
||||||
{
|
|
||||||
SetData(handle, offset, MemoryMarshal.Cast<T, byte>(data), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetData(BufferHandle handle, int offset, ReadOnlySpan<byte> data, CommandBufferScoped? cbs)
|
|
||||||
{
|
|
||||||
if (TryGetBuffer(handle, out var holder))
|
|
||||||
{
|
|
||||||
holder.SetData(offset, data, cbs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete(BufferHandle handle)
|
|
||||||
{
|
|
||||||
if (TryGetBuffer(handle, out var holder))
|
|
||||||
{
|
|
||||||
holder.Dispose();
|
|
||||||
_buffers.Remove((int)Unsafe.As<BufferHandle, ulong>(ref handle));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryGetBuffer(BufferHandle handle, out BufferHolder holder)
|
|
||||||
{
|
|
||||||
return _buffers.TryGetValue((int)Unsafe.As<BufferHandle, ulong>(ref handle), out holder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
StagingBuffer.Dispose();
|
|
||||||
|
|
||||||
foreach (var buffer in _buffers)
|
|
||||||
{
|
|
||||||
buffer.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
internal class BufferUsageBitmap
|
|
||||||
{
|
|
||||||
private readonly BitMap _bitmap;
|
|
||||||
private readonly int _size;
|
|
||||||
private readonly int _granularity;
|
|
||||||
private readonly int _bits;
|
|
||||||
private readonly int _writeBitOffset;
|
|
||||||
|
|
||||||
private readonly int _intsPerCb;
|
|
||||||
private readonly int _bitsPerCb;
|
|
||||||
|
|
||||||
public BufferUsageBitmap(int size, int granularity)
|
|
||||||
{
|
|
||||||
_size = size;
|
|
||||||
_granularity = granularity;
|
|
||||||
|
|
||||||
// There are two sets of bits - one for read tracking, and the other for write.
|
|
||||||
int bits = (size + (granularity - 1)) / granularity;
|
|
||||||
_writeBitOffset = bits;
|
|
||||||
_bits = bits << 1;
|
|
||||||
|
|
||||||
_intsPerCb = (_bits + (BitMap.IntSize - 1)) / BitMap.IntSize;
|
|
||||||
_bitsPerCb = _intsPerCb * BitMap.IntSize;
|
|
||||||
|
|
||||||
_bitmap = new BitMap(_bitsPerCb * CommandBufferPool.MaxCommandBuffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(int cbIndex, int offset, int size, bool write)
|
|
||||||
{
|
|
||||||
if (size == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some usages can be out of bounds (vertex buffer on amd), so bound if necessary.
|
|
||||||
if (offset + size > _size)
|
|
||||||
{
|
|
||||||
size = _size - offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cbBase = cbIndex * _bitsPerCb + (write ? _writeBitOffset : 0);
|
|
||||||
int start = cbBase + offset / _granularity;
|
|
||||||
int end = cbBase + (offset + size - 1) / _granularity;
|
|
||||||
|
|
||||||
_bitmap.SetRange(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OverlapsWith(int cbIndex, int offset, int size, bool write = false)
|
|
||||||
{
|
|
||||||
if (size == 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int cbBase = cbIndex * _bitsPerCb + (write ? _writeBitOffset : 0);
|
|
||||||
int start = cbBase + offset / _granularity;
|
|
||||||
int end = cbBase + (offset + size - 1) / _granularity;
|
|
||||||
|
|
||||||
return _bitmap.IsSet(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OverlapsWith(int offset, int size, bool write)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < CommandBufferPool.MaxCommandBuffers; i++)
|
|
||||||
{
|
|
||||||
if (OverlapsWith(i, offset, size, write))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear(int cbIndex)
|
|
||||||
{
|
|
||||||
_bitmap.ClearInt(cbIndex * _intsPerCb, (cbIndex + 1) * _intsPerCb - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,294 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
interface ICacheKey : IDisposable
|
|
||||||
{
|
|
||||||
bool KeyEqual(ICacheKey other);
|
|
||||||
}
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
struct I8ToI16CacheKey : ICacheKey
|
|
||||||
{
|
|
||||||
// Used to notify the pipeline that bindings have invalidated on dispose.
|
|
||||||
// private readonly MetalRenderer _renderer;
|
|
||||||
// private Auto<DisposableBuffer> _buffer;
|
|
||||||
|
|
||||||
public I8ToI16CacheKey(MetalRenderer renderer)
|
|
||||||
{
|
|
||||||
// _renderer = renderer;
|
|
||||||
// _buffer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly bool KeyEqual(ICacheKey other)
|
|
||||||
{
|
|
||||||
return other is I8ToI16CacheKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly void SetBuffer(Auto<DisposableBuffer> buffer)
|
|
||||||
{
|
|
||||||
// _buffer = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
// TODO: Tell pipeline buffer is dirty!
|
|
||||||
// _renderer.PipelineInternal.DirtyIndexBuffer(_buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
readonly struct TopologyConversionCacheKey : ICacheKey
|
|
||||||
{
|
|
||||||
private readonly IndexBufferPattern _pattern;
|
|
||||||
private readonly int _indexSize;
|
|
||||||
|
|
||||||
// Used to notify the pipeline that bindings have invalidated on dispose.
|
|
||||||
// private readonly MetalRenderer _renderer;
|
|
||||||
// private Auto<DisposableBuffer> _buffer;
|
|
||||||
|
|
||||||
public TopologyConversionCacheKey(MetalRenderer renderer, IndexBufferPattern pattern, int indexSize)
|
|
||||||
{
|
|
||||||
// _renderer = renderer;
|
|
||||||
// _buffer = null;
|
|
||||||
_pattern = pattern;
|
|
||||||
_indexSize = indexSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly bool KeyEqual(ICacheKey other)
|
|
||||||
{
|
|
||||||
return other is TopologyConversionCacheKey entry &&
|
|
||||||
entry._pattern == _pattern &&
|
|
||||||
entry._indexSize == _indexSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetBuffer(Auto<DisposableBuffer> buffer)
|
|
||||||
{
|
|
||||||
// _buffer = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly void Dispose()
|
|
||||||
{
|
|
||||||
// TODO: Tell pipeline buffer is dirty!
|
|
||||||
// _renderer.PipelineInternal.DirtyVertexBuffer(_buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
readonly struct Dependency
|
|
||||||
{
|
|
||||||
private readonly BufferHolder _buffer;
|
|
||||||
private readonly int _offset;
|
|
||||||
private readonly int _size;
|
|
||||||
private readonly ICacheKey _key;
|
|
||||||
|
|
||||||
public Dependency(BufferHolder buffer, int offset, int size, ICacheKey key)
|
|
||||||
{
|
|
||||||
_buffer = buffer;
|
|
||||||
_offset = offset;
|
|
||||||
_size = size;
|
|
||||||
_key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveFromOwner()
|
|
||||||
{
|
|
||||||
_buffer.RemoveCachedConvertedBuffer(_offset, _size, _key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
struct CacheByRange<T> where T : IDisposable
|
|
||||||
{
|
|
||||||
private struct Entry
|
|
||||||
{
|
|
||||||
public readonly ICacheKey Key;
|
|
||||||
public readonly T Value;
|
|
||||||
public List<Dependency> DependencyList;
|
|
||||||
|
|
||||||
public Entry(ICacheKey key, T value)
|
|
||||||
{
|
|
||||||
Key = key;
|
|
||||||
Value = value;
|
|
||||||
DependencyList = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly void InvalidateDependencies()
|
|
||||||
{
|
|
||||||
if (DependencyList != null)
|
|
||||||
{
|
|
||||||
foreach (Dependency dependency in DependencyList)
|
|
||||||
{
|
|
||||||
dependency.RemoveFromOwner();
|
|
||||||
}
|
|
||||||
|
|
||||||
DependencyList.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dictionary<ulong, List<Entry>> _ranges;
|
|
||||||
|
|
||||||
public void Add(int offset, int size, ICacheKey key, T value)
|
|
||||||
{
|
|
||||||
List<Entry> entries = GetEntries(offset, size);
|
|
||||||
|
|
||||||
entries.Add(new Entry(key, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddDependency(int offset, int size, ICacheKey key, Dependency dependency)
|
|
||||||
{
|
|
||||||
List<Entry> entries = GetEntries(offset, size);
|
|
||||||
|
|
||||||
for (int i = 0; i < entries.Count; i++)
|
|
||||||
{
|
|
||||||
Entry entry = entries[i];
|
|
||||||
|
|
||||||
if (entry.Key.KeyEqual(key))
|
|
||||||
{
|
|
||||||
if (entry.DependencyList == null)
|
|
||||||
{
|
|
||||||
entry.DependencyList = new List<Dependency>();
|
|
||||||
entries[i] = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.DependencyList.Add(dependency);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(int offset, int size, ICacheKey key)
|
|
||||||
{
|
|
||||||
List<Entry> entries = GetEntries(offset, size);
|
|
||||||
|
|
||||||
for (int i = 0; i < entries.Count; i++)
|
|
||||||
{
|
|
||||||
Entry entry = entries[i];
|
|
||||||
|
|
||||||
if (entry.Key.KeyEqual(key))
|
|
||||||
{
|
|
||||||
entries.RemoveAt(i--);
|
|
||||||
|
|
||||||
DestroyEntry(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entries.Count == 0)
|
|
||||||
{
|
|
||||||
_ranges.Remove(PackRange(offset, size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(int offset, int size, ICacheKey key, out T value)
|
|
||||||
{
|
|
||||||
List<Entry> entries = GetEntries(offset, size);
|
|
||||||
|
|
||||||
foreach (Entry entry in entries)
|
|
||||||
{
|
|
||||||
if (entry.Key.KeyEqual(key))
|
|
||||||
{
|
|
||||||
value = entry.Value;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
if (_ranges != null)
|
|
||||||
{
|
|
||||||
foreach (List<Entry> entries in _ranges.Values)
|
|
||||||
{
|
|
||||||
foreach (Entry entry in entries)
|
|
||||||
{
|
|
||||||
DestroyEntry(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ranges.Clear();
|
|
||||||
_ranges = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly void ClearRange(int offset, int size)
|
|
||||||
{
|
|
||||||
if (_ranges != null && _ranges.Count > 0)
|
|
||||||
{
|
|
||||||
int end = offset + size;
|
|
||||||
|
|
||||||
List<ulong> toRemove = null;
|
|
||||||
|
|
||||||
foreach (KeyValuePair<ulong, List<Entry>> range in _ranges)
|
|
||||||
{
|
|
||||||
(int rOffset, int rSize) = UnpackRange(range.Key);
|
|
||||||
|
|
||||||
int rEnd = rOffset + rSize;
|
|
||||||
|
|
||||||
if (rEnd > offset && rOffset < end)
|
|
||||||
{
|
|
||||||
List<Entry> entries = range.Value;
|
|
||||||
|
|
||||||
foreach (Entry entry in entries)
|
|
||||||
{
|
|
||||||
DestroyEntry(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
(toRemove ??= new List<ulong>()).Add(range.Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toRemove != null)
|
|
||||||
{
|
|
||||||
foreach (ulong range in toRemove)
|
|
||||||
{
|
|
||||||
_ranges.Remove(range);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Entry> GetEntries(int offset, int size)
|
|
||||||
{
|
|
||||||
_ranges ??= new Dictionary<ulong, List<Entry>>();
|
|
||||||
|
|
||||||
ulong key = PackRange(offset, size);
|
|
||||||
|
|
||||||
if (!_ranges.TryGetValue(key, out List<Entry> value))
|
|
||||||
{
|
|
||||||
value = new List<Entry>();
|
|
||||||
_ranges.Add(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DestroyEntry(Entry entry)
|
|
||||||
{
|
|
||||||
entry.Key.Dispose();
|
|
||||||
entry.Value?.Dispose();
|
|
||||||
entry.InvalidateDependencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ulong PackRange(int offset, int size)
|
|
||||||
{
|
|
||||||
return (uint)offset | ((ulong)size << 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static (int offset, int size) UnpackRange(ulong range)
|
|
||||||
{
|
|
||||||
return ((int)range, (int)(range >> 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
using Ryujinx.Graphics.Metal;
|
|
||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
interface IEncoderFactory
|
|
||||||
{
|
|
||||||
MTLRenderCommandEncoder CreateRenderCommandEncoder();
|
|
||||||
MTLComputeCommandEncoder CreateComputeCommandEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tracks active encoder object for a command buffer.
|
|
||||||
/// </summary>
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class CommandBufferEncoder
|
|
||||||
{
|
|
||||||
public EncoderType CurrentEncoderType { get; private set; } = EncoderType.None;
|
|
||||||
|
|
||||||
public MTLBlitCommandEncoder BlitEncoder => new(CurrentEncoder.Value);
|
|
||||||
|
|
||||||
public MTLComputeCommandEncoder ComputeEncoder => new(CurrentEncoder.Value);
|
|
||||||
|
|
||||||
public MTLRenderCommandEncoder RenderEncoder => new(CurrentEncoder.Value);
|
|
||||||
|
|
||||||
internal MTLCommandEncoder? CurrentEncoder { get; private set; }
|
|
||||||
|
|
||||||
private MTLCommandBuffer _commandBuffer;
|
|
||||||
private IEncoderFactory _encoderFactory;
|
|
||||||
|
|
||||||
public void Initialize(MTLCommandBuffer commandBuffer, IEncoderFactory encoderFactory)
|
|
||||||
{
|
|
||||||
_commandBuffer = commandBuffer;
|
|
||||||
_encoderFactory = encoderFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public MTLRenderCommandEncoder EnsureRenderEncoder()
|
|
||||||
{
|
|
||||||
if (CurrentEncoderType != EncoderType.Render)
|
|
||||||
{
|
|
||||||
return BeginRenderPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
return RenderEncoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public MTLBlitCommandEncoder EnsureBlitEncoder()
|
|
||||||
{
|
|
||||||
if (CurrentEncoderType != EncoderType.Blit)
|
|
||||||
{
|
|
||||||
return BeginBlitPass();
|
|
||||||
}
|
|
||||||
|
|
||||||
return BlitEncoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public MTLComputeCommandEncoder EnsureComputeEncoder()
|
|
||||||
{
|
|
||||||
if (CurrentEncoderType != EncoderType.Compute)
|
|
||||||
{
|
|
||||||
return BeginComputePass();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ComputeEncoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool TryGetRenderEncoder(out MTLRenderCommandEncoder encoder)
|
|
||||||
{
|
|
||||||
if (CurrentEncoderType != EncoderType.Render)
|
|
||||||
{
|
|
||||||
encoder = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder = RenderEncoder;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool TryGetBlitEncoder(out MTLBlitCommandEncoder encoder)
|
|
||||||
{
|
|
||||||
if (CurrentEncoderType != EncoderType.Blit)
|
|
||||||
{
|
|
||||||
encoder = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder = BlitEncoder;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool TryGetComputeEncoder(out MTLComputeCommandEncoder encoder)
|
|
||||||
{
|
|
||||||
if (CurrentEncoderType != EncoderType.Compute)
|
|
||||||
{
|
|
||||||
encoder = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder = ComputeEncoder;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void EndCurrentPass()
|
|
||||||
{
|
|
||||||
if (CurrentEncoder != null)
|
|
||||||
{
|
|
||||||
switch (CurrentEncoderType)
|
|
||||||
{
|
|
||||||
case EncoderType.Blit:
|
|
||||||
BlitEncoder.EndEncoding();
|
|
||||||
CurrentEncoder = null;
|
|
||||||
break;
|
|
||||||
case EncoderType.Compute:
|
|
||||||
ComputeEncoder.EndEncoding();
|
|
||||||
CurrentEncoder = null;
|
|
||||||
break;
|
|
||||||
case EncoderType.Render:
|
|
||||||
RenderEncoder.EndEncoding();
|
|
||||||
CurrentEncoder = null;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentEncoderType = EncoderType.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MTLRenderCommandEncoder BeginRenderPass()
|
|
||||||
{
|
|
||||||
EndCurrentPass();
|
|
||||||
|
|
||||||
var renderCommandEncoder = _encoderFactory.CreateRenderCommandEncoder();
|
|
||||||
|
|
||||||
CurrentEncoder = renderCommandEncoder;
|
|
||||||
CurrentEncoderType = EncoderType.Render;
|
|
||||||
|
|
||||||
return renderCommandEncoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MTLBlitCommandEncoder BeginBlitPass()
|
|
||||||
{
|
|
||||||
EndCurrentPass();
|
|
||||||
|
|
||||||
using var descriptor = new MTLBlitPassDescriptor();
|
|
||||||
var blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor);
|
|
||||||
|
|
||||||
CurrentEncoder = blitCommandEncoder;
|
|
||||||
CurrentEncoderType = EncoderType.Blit;
|
|
||||||
return blitCommandEncoder;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MTLComputeCommandEncoder BeginComputePass()
|
|
||||||
{
|
|
||||||
EndCurrentPass();
|
|
||||||
|
|
||||||
var computeCommandEncoder = _encoderFactory.CreateComputeCommandEncoder();
|
|
||||||
|
|
||||||
CurrentEncoder = computeCommandEncoder;
|
|
||||||
CurrentEncoderType = EncoderType.Compute;
|
|
||||||
return computeCommandEncoder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,289 +0,0 @@
|
|||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class CommandBufferPool : IDisposable
|
|
||||||
{
|
|
||||||
public const int MaxCommandBuffers = 16;
|
|
||||||
|
|
||||||
private readonly int _totalCommandBuffers;
|
|
||||||
private readonly int _totalCommandBuffersMask;
|
|
||||||
private readonly MTLCommandQueue _queue;
|
|
||||||
private readonly Thread _owner;
|
|
||||||
private IEncoderFactory _defaultEncoderFactory;
|
|
||||||
|
|
||||||
public bool OwnedByCurrentThread => _owner == Thread.CurrentThread;
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
private struct ReservedCommandBuffer
|
|
||||||
{
|
|
||||||
public bool InUse;
|
|
||||||
public bool InConsumption;
|
|
||||||
public int SubmissionCount;
|
|
||||||
public MTLCommandBuffer CommandBuffer;
|
|
||||||
public CommandBufferEncoder Encoders;
|
|
||||||
public FenceHolder Fence;
|
|
||||||
|
|
||||||
public List<IAuto> Dependants;
|
|
||||||
public List<MultiFenceHolder> Waitables;
|
|
||||||
|
|
||||||
public void Use(MTLCommandQueue queue, IEncoderFactory stateManager)
|
|
||||||
{
|
|
||||||
MTLCommandBufferDescriptor descriptor = new();
|
|
||||||
#if DEBUG
|
|
||||||
descriptor.ErrorOptions = MTLCommandBufferErrorOption.EncoderExecutionStatus;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
CommandBuffer = queue.CommandBuffer(descriptor);
|
|
||||||
Fence = new FenceHolder(CommandBuffer);
|
|
||||||
|
|
||||||
Encoders.Initialize(CommandBuffer, stateManager);
|
|
||||||
|
|
||||||
InUse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Initialize()
|
|
||||||
{
|
|
||||||
Dependants = new List<IAuto>();
|
|
||||||
Waitables = new List<MultiFenceHolder>();
|
|
||||||
Encoders = new CommandBufferEncoder();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly ReservedCommandBuffer[] _commandBuffers;
|
|
||||||
|
|
||||||
private readonly int[] _queuedIndexes;
|
|
||||||
private int _queuedIndexesPtr;
|
|
||||||
private int _queuedCount;
|
|
||||||
private int _inUseCount;
|
|
||||||
|
|
||||||
public CommandBufferPool(MTLCommandQueue queue, bool isLight = false)
|
|
||||||
{
|
|
||||||
_queue = queue;
|
|
||||||
_owner = Thread.CurrentThread;
|
|
||||||
|
|
||||||
_totalCommandBuffers = isLight ? 2 : MaxCommandBuffers;
|
|
||||||
_totalCommandBuffersMask = _totalCommandBuffers - 1;
|
|
||||||
|
|
||||||
_commandBuffers = new ReservedCommandBuffer[_totalCommandBuffers];
|
|
||||||
|
|
||||||
_queuedIndexes = new int[_totalCommandBuffers];
|
|
||||||
_queuedIndexesPtr = 0;
|
|
||||||
_queuedCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Initialize(IEncoderFactory encoderFactory)
|
|
||||||
{
|
|
||||||
_defaultEncoderFactory = encoderFactory;
|
|
||||||
|
|
||||||
for (int i = 0; i < _totalCommandBuffers; i++)
|
|
||||||
{
|
|
||||||
_commandBuffers[i].Initialize();
|
|
||||||
WaitAndDecrementRef(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddDependant(int cbIndex, IAuto dependant)
|
|
||||||
{
|
|
||||||
dependant.IncrementReferenceCount();
|
|
||||||
_commandBuffers[cbIndex].Dependants.Add(dependant);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddWaitable(MultiFenceHolder waitable)
|
|
||||||
{
|
|
||||||
lock (_commandBuffers)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _totalCommandBuffers; i++)
|
|
||||||
{
|
|
||||||
ref var entry = ref _commandBuffers[i];
|
|
||||||
|
|
||||||
if (entry.InConsumption)
|
|
||||||
{
|
|
||||||
AddWaitable(i, waitable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddInUseWaitable(MultiFenceHolder waitable)
|
|
||||||
{
|
|
||||||
lock (_commandBuffers)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _totalCommandBuffers; i++)
|
|
||||||
{
|
|
||||||
ref var entry = ref _commandBuffers[i];
|
|
||||||
|
|
||||||
if (entry.InUse)
|
|
||||||
{
|
|
||||||
AddWaitable(i, waitable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddWaitable(int cbIndex, MultiFenceHolder waitable)
|
|
||||||
{
|
|
||||||
ref var entry = ref _commandBuffers[cbIndex];
|
|
||||||
if (waitable.AddFence(cbIndex, entry.Fence))
|
|
||||||
{
|
|
||||||
entry.Waitables.Add(waitable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsFenceOnRentedCommandBuffer(FenceHolder fence)
|
|
||||||
{
|
|
||||||
lock (_commandBuffers)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _totalCommandBuffers; i++)
|
|
||||||
{
|
|
||||||
ref var entry = ref _commandBuffers[i];
|
|
||||||
|
|
||||||
if (entry.InUse && entry.Fence == fence)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FenceHolder GetFence(int cbIndex)
|
|
||||||
{
|
|
||||||
return _commandBuffers[cbIndex].Fence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetSubmissionCount(int cbIndex)
|
|
||||||
{
|
|
||||||
return _commandBuffers[cbIndex].SubmissionCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int FreeConsumed(bool wait)
|
|
||||||
{
|
|
||||||
int freeEntry = 0;
|
|
||||||
|
|
||||||
while (_queuedCount > 0)
|
|
||||||
{
|
|
||||||
int index = _queuedIndexes[_queuedIndexesPtr];
|
|
||||||
|
|
||||||
ref var entry = ref _commandBuffers[index];
|
|
||||||
|
|
||||||
if (wait || !entry.InConsumption || entry.Fence.IsSignaled())
|
|
||||||
{
|
|
||||||
WaitAndDecrementRef(index);
|
|
||||||
|
|
||||||
wait = false;
|
|
||||||
freeEntry = index;
|
|
||||||
|
|
||||||
_queuedCount--;
|
|
||||||
_queuedIndexesPtr = (_queuedIndexesPtr + 1) % _totalCommandBuffers;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return freeEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBufferScoped ReturnAndRent(CommandBufferScoped cbs)
|
|
||||||
{
|
|
||||||
Return(cbs);
|
|
||||||
return Rent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBufferScoped Rent()
|
|
||||||
{
|
|
||||||
lock (_commandBuffers)
|
|
||||||
{
|
|
||||||
int cursor = FreeConsumed(_inUseCount + _queuedCount == _totalCommandBuffers);
|
|
||||||
|
|
||||||
for (int i = 0; i < _totalCommandBuffers; i++)
|
|
||||||
{
|
|
||||||
ref var entry = ref _commandBuffers[cursor];
|
|
||||||
|
|
||||||
if (!entry.InUse && !entry.InConsumption)
|
|
||||||
{
|
|
||||||
entry.Use(_queue, _defaultEncoderFactory);
|
|
||||||
|
|
||||||
_inUseCount++;
|
|
||||||
|
|
||||||
return new CommandBufferScoped(this, entry.CommandBuffer, entry.Encoders, cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor = (cursor + 1) & _totalCommandBuffersMask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidOperationException($"Out of command buffers (In use: {_inUseCount}, queued: {_queuedCount}, total: {_totalCommandBuffers})");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Return(CommandBufferScoped cbs)
|
|
||||||
{
|
|
||||||
// Ensure the encoder is committed.
|
|
||||||
cbs.Encoders.EndCurrentPass();
|
|
||||||
|
|
||||||
lock (_commandBuffers)
|
|
||||||
{
|
|
||||||
int cbIndex = cbs.CommandBufferIndex;
|
|
||||||
|
|
||||||
ref var entry = ref _commandBuffers[cbIndex];
|
|
||||||
|
|
||||||
Debug.Assert(entry.InUse);
|
|
||||||
Debug.Assert(entry.CommandBuffer.NativePtr == cbs.CommandBuffer.NativePtr);
|
|
||||||
entry.InUse = false;
|
|
||||||
entry.InConsumption = true;
|
|
||||||
entry.SubmissionCount++;
|
|
||||||
_inUseCount--;
|
|
||||||
|
|
||||||
var commandBuffer = entry.CommandBuffer;
|
|
||||||
commandBuffer.Commit();
|
|
||||||
|
|
||||||
int ptr = (_queuedIndexesPtr + _queuedCount) % _totalCommandBuffers;
|
|
||||||
_queuedIndexes[ptr] = cbIndex;
|
|
||||||
_queuedCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WaitAndDecrementRef(int cbIndex)
|
|
||||||
{
|
|
||||||
ref var entry = ref _commandBuffers[cbIndex];
|
|
||||||
|
|
||||||
if (entry.InConsumption)
|
|
||||||
{
|
|
||||||
entry.Fence.Wait();
|
|
||||||
entry.InConsumption = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var dependant in entry.Dependants)
|
|
||||||
{
|
|
||||||
dependant.DecrementReferenceCount(cbIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var waitable in entry.Waitables)
|
|
||||||
{
|
|
||||||
waitable.RemoveFence(cbIndex);
|
|
||||||
waitable.RemoveBufferUses(cbIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.Dependants.Clear();
|
|
||||||
entry.Waitables.Clear();
|
|
||||||
entry.Fence?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _totalCommandBuffers; i++)
|
|
||||||
{
|
|
||||||
WaitAndDecrementRef(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
readonly struct CommandBufferScoped : IDisposable
|
|
||||||
{
|
|
||||||
private readonly CommandBufferPool _pool;
|
|
||||||
public MTLCommandBuffer CommandBuffer { get; }
|
|
||||||
public CommandBufferEncoder Encoders { get; }
|
|
||||||
public int CommandBufferIndex { get; }
|
|
||||||
|
|
||||||
public CommandBufferScoped(CommandBufferPool pool, MTLCommandBuffer commandBuffer, CommandBufferEncoder encoders, int commandBufferIndex)
|
|
||||||
{
|
|
||||||
_pool = pool;
|
|
||||||
CommandBuffer = commandBuffer;
|
|
||||||
Encoders = encoders;
|
|
||||||
CommandBufferIndex = commandBufferIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddDependant(IAuto dependant)
|
|
||||||
{
|
|
||||||
_pool.AddDependant(CommandBufferIndex, dependant);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddWaitable(MultiFenceHolder waitable)
|
|
||||||
{
|
|
||||||
_pool.AddWaitable(CommandBufferIndex, waitable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FenceHolder GetFence()
|
|
||||||
{
|
|
||||||
return _pool.GetFence(CommandBufferIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_pool?.Return(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
static class Constants
|
|
||||||
{
|
|
||||||
public const int MaxShaderStages = 5;
|
|
||||||
public const int MaxVertexBuffers = 16;
|
|
||||||
public const int MaxUniformBuffersPerStage = 18;
|
|
||||||
public const int MaxStorageBuffersPerStage = 16;
|
|
||||||
public const int MaxTexturesPerStage = 64;
|
|
||||||
public const int MaxImagesPerStage = 16;
|
|
||||||
|
|
||||||
public const int MaxUniformBufferBindings = MaxUniformBuffersPerStage * MaxShaderStages;
|
|
||||||
public const int MaxStorageBufferBindings = MaxStorageBuffersPerStage * MaxShaderStages;
|
|
||||||
public const int MaxTextureBindings = MaxTexturesPerStage * MaxShaderStages;
|
|
||||||
public const int MaxImageBindings = MaxImagesPerStage * MaxShaderStages;
|
|
||||||
public const int MaxColorAttachments = 8;
|
|
||||||
public const int MaxViewports = 16;
|
|
||||||
// TODO: Check this value
|
|
||||||
public const int MaxVertexAttributes = 31;
|
|
||||||
|
|
||||||
public const int MinResourceAlignment = 16;
|
|
||||||
|
|
||||||
// Must match constants set in shader generation
|
|
||||||
public const uint ZeroBufferIndex = MaxVertexBuffers;
|
|
||||||
public const uint BaseSetIndex = MaxVertexBuffers + 1;
|
|
||||||
|
|
||||||
public const uint ConstantBuffersIndex = BaseSetIndex;
|
|
||||||
public const uint StorageBuffersIndex = BaseSetIndex + 1;
|
|
||||||
public const uint TexturesIndex = BaseSetIndex + 2;
|
|
||||||
public const uint ImagesIndex = BaseSetIndex + 3;
|
|
||||||
|
|
||||||
public const uint ConstantBuffersSetIndex = 0;
|
|
||||||
public const uint StorageBuffersSetIndex = 1;
|
|
||||||
public const uint TexturesSetIndex = 2;
|
|
||||||
public const uint ImagesSetIndex = 3;
|
|
||||||
|
|
||||||
public const uint MaximumBufferArgumentTableEntries = 31;
|
|
||||||
|
|
||||||
public const uint MaximumExtraSets = MaximumBufferArgumentTableEntries - ImagesIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
class CounterEvent : ICounterEvent
|
|
||||||
{
|
|
||||||
public CounterEvent()
|
|
||||||
{
|
|
||||||
Invalid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Invalid { get; set; }
|
|
||||||
public bool ReserveForHostAccess()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Flush() { }
|
|
||||||
|
|
||||||
public void Dispose() { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
using Ryujinx.Graphics.Metal.State;
|
|
||||||
using SharpMetal.Metal;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class DepthStencilCache : StateCache<MTLDepthStencilState, DepthStencilUid, DepthStencilUid>
|
|
||||||
{
|
|
||||||
private readonly MTLDevice _device;
|
|
||||||
|
|
||||||
public DepthStencilCache(MTLDevice device)
|
|
||||||
{
|
|
||||||
_device = device;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override DepthStencilUid GetHash(DepthStencilUid descriptor)
|
|
||||||
{
|
|
||||||
return descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override MTLDepthStencilState CreateValue(DepthStencilUid descriptor)
|
|
||||||
{
|
|
||||||
// Create descriptors
|
|
||||||
|
|
||||||
ref StencilUid frontUid = ref descriptor.FrontFace;
|
|
||||||
|
|
||||||
using var frontFaceStencil = new MTLStencilDescriptor
|
|
||||||
{
|
|
||||||
StencilFailureOperation = frontUid.StencilFailureOperation,
|
|
||||||
DepthFailureOperation = frontUid.DepthFailureOperation,
|
|
||||||
DepthStencilPassOperation = frontUid.DepthStencilPassOperation,
|
|
||||||
StencilCompareFunction = frontUid.StencilCompareFunction,
|
|
||||||
ReadMask = frontUid.ReadMask,
|
|
||||||
WriteMask = frontUid.WriteMask
|
|
||||||
};
|
|
||||||
|
|
||||||
ref StencilUid backUid = ref descriptor.BackFace;
|
|
||||||
|
|
||||||
using var backFaceStencil = new MTLStencilDescriptor
|
|
||||||
{
|
|
||||||
StencilFailureOperation = backUid.StencilFailureOperation,
|
|
||||||
DepthFailureOperation = backUid.DepthFailureOperation,
|
|
||||||
DepthStencilPassOperation = backUid.DepthStencilPassOperation,
|
|
||||||
StencilCompareFunction = backUid.StencilCompareFunction,
|
|
||||||
ReadMask = backUid.ReadMask,
|
|
||||||
WriteMask = backUid.WriteMask
|
|
||||||
};
|
|
||||||
|
|
||||||
var mtlDescriptor = new MTLDepthStencilDescriptor
|
|
||||||
{
|
|
||||||
DepthCompareFunction = descriptor.DepthCompareFunction,
|
|
||||||
DepthWriteEnabled = descriptor.DepthWriteEnabled
|
|
||||||
};
|
|
||||||
|
|
||||||
if (descriptor.StencilTestEnabled)
|
|
||||||
{
|
|
||||||
mtlDescriptor.BackFaceStencil = backFaceStencil;
|
|
||||||
mtlDescriptor.FrontFaceStencil = frontFaceStencil;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (mtlDescriptor)
|
|
||||||
{
|
|
||||||
return _device.NewDepthStencilState(mtlDescriptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
readonly struct DisposableBuffer : IDisposable
|
|
||||||
{
|
|
||||||
public MTLBuffer Value { get; }
|
|
||||||
|
|
||||||
public DisposableBuffer(MTLBuffer buffer)
|
|
||||||
{
|
|
||||||
Value = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (Value != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
Value.SetPurgeableState(MTLPurgeableState.Empty);
|
|
||||||
Value.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
readonly struct DisposableSampler : IDisposable
|
|
||||||
{
|
|
||||||
public MTLSamplerState Value { get; }
|
|
||||||
|
|
||||||
public DisposableSampler(MTLSamplerState sampler)
|
|
||||||
{
|
|
||||||
Value = sampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Value.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal.Effects
|
|
||||||
{
|
|
||||||
internal interface IPostProcessingEffect : IDisposable
|
|
||||||
{
|
|
||||||
const int LocalGroupSize = 64;
|
|
||||||
Texture Run(Texture view, int width, int height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal.Effects
|
|
||||||
{
|
|
||||||
internal interface IScalingFilter : IDisposable
|
|
||||||
{
|
|
||||||
float Level { get; set; }
|
|
||||||
void Run(
|
|
||||||
Texture view,
|
|
||||||
Texture destinationTexture,
|
|
||||||
Format format,
|
|
||||||
int width,
|
|
||||||
int height,
|
|
||||||
Extents2D source,
|
|
||||||
Extents2D destination);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
using SharpMetal.Metal;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
public struct RenderEncoderBindings
|
|
||||||
{
|
|
||||||
public List<Resource> Resources = new();
|
|
||||||
public List<BufferResource> VertexBuffers = new();
|
|
||||||
public List<BufferResource> FragmentBuffers = new();
|
|
||||||
|
|
||||||
public RenderEncoderBindings() { }
|
|
||||||
|
|
||||||
public readonly void Clear()
|
|
||||||
{
|
|
||||||
Resources.Clear();
|
|
||||||
VertexBuffers.Clear();
|
|
||||||
FragmentBuffers.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct ComputeEncoderBindings
|
|
||||||
{
|
|
||||||
public List<Resource> Resources = new();
|
|
||||||
public List<BufferResource> Buffers = new();
|
|
||||||
|
|
||||||
public ComputeEncoderBindings() { }
|
|
||||||
|
|
||||||
public readonly void Clear()
|
|
||||||
{
|
|
||||||
Resources.Clear();
|
|
||||||
Buffers.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct BufferResource
|
|
||||||
{
|
|
||||||
public MTLBuffer Buffer;
|
|
||||||
public ulong Offset;
|
|
||||||
public ulong Binding;
|
|
||||||
|
|
||||||
public BufferResource(MTLBuffer buffer, ulong offset, ulong binding)
|
|
||||||
{
|
|
||||||
Buffer = buffer;
|
|
||||||
Offset = offset;
|
|
||||||
Binding = binding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct Resource
|
|
||||||
{
|
|
||||||
public MTLResource MtlResource;
|
|
||||||
public MTLResourceUsage ResourceUsage;
|
|
||||||
public MTLRenderStages Stages;
|
|
||||||
|
|
||||||
public Resource(MTLResource resource, MTLResourceUsage resourceUsage, MTLRenderStages stages)
|
|
||||||
{
|
|
||||||
MtlResource = resource;
|
|
||||||
ResourceUsage = resourceUsage;
|
|
||||||
Stages = stages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
using Ryujinx.Common.Memory;
|
|
||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
using Ryujinx.Graphics.Metal.State;
|
|
||||||
using Ryujinx.Graphics.Shader;
|
|
||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[Flags]
|
|
||||||
enum DirtyFlags
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
RenderPipeline = 1 << 0,
|
|
||||||
ComputePipeline = 1 << 1,
|
|
||||||
DepthStencil = 1 << 2,
|
|
||||||
DepthClamp = 1 << 3,
|
|
||||||
DepthBias = 1 << 4,
|
|
||||||
CullMode = 1 << 5,
|
|
||||||
FrontFace = 1 << 6,
|
|
||||||
StencilRef = 1 << 7,
|
|
||||||
Viewports = 1 << 8,
|
|
||||||
Scissors = 1 << 9,
|
|
||||||
Uniforms = 1 << 10,
|
|
||||||
Storages = 1 << 11,
|
|
||||||
Textures = 1 << 12,
|
|
||||||
Images = 1 << 13,
|
|
||||||
|
|
||||||
ArgBuffers = Uniforms | Storages | Textures | Images,
|
|
||||||
|
|
||||||
RenderAll = RenderPipeline | DepthStencil | DepthClamp | DepthBias | CullMode | FrontFace | StencilRef | Viewports | Scissors | ArgBuffers,
|
|
||||||
ComputeAll = ComputePipeline | ArgBuffers,
|
|
||||||
All = RenderAll | ComputeAll,
|
|
||||||
}
|
|
||||||
|
|
||||||
record struct BufferRef
|
|
||||||
{
|
|
||||||
public Auto<DisposableBuffer> Buffer;
|
|
||||||
public BufferRange? Range;
|
|
||||||
|
|
||||||
public BufferRef(Auto<DisposableBuffer> buffer)
|
|
||||||
{
|
|
||||||
Buffer = buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BufferRef(Auto<DisposableBuffer> buffer, ref BufferRange range)
|
|
||||||
{
|
|
||||||
Buffer = buffer;
|
|
||||||
Range = range;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
record struct TextureRef
|
|
||||||
{
|
|
||||||
public ShaderStage Stage;
|
|
||||||
public TextureBase Storage;
|
|
||||||
public Auto<DisposableSampler> Sampler;
|
|
||||||
public Format ImageFormat;
|
|
||||||
|
|
||||||
public TextureRef(ShaderStage stage, TextureBase storage, Auto<DisposableSampler> sampler)
|
|
||||||
{
|
|
||||||
Stage = stage;
|
|
||||||
Storage = storage;
|
|
||||||
Sampler = sampler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
record struct ImageRef
|
|
||||||
{
|
|
||||||
public ShaderStage Stage;
|
|
||||||
public Texture Storage;
|
|
||||||
|
|
||||||
public ImageRef(ShaderStage stage, Texture storage)
|
|
||||||
{
|
|
||||||
Stage = stage;
|
|
||||||
Storage = storage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PredrawState
|
|
||||||
{
|
|
||||||
public MTLCullMode CullMode;
|
|
||||||
public DepthStencilUid DepthStencilUid;
|
|
||||||
public PrimitiveTopology Topology;
|
|
||||||
public MTLViewport[] Viewports;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RenderTargetCopy
|
|
||||||
{
|
|
||||||
public MTLScissorRect[] Scissors;
|
|
||||||
public Texture DepthStencil;
|
|
||||||
public Texture[] RenderTargets;
|
|
||||||
}
|
|
||||||
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class EncoderState
|
|
||||||
{
|
|
||||||
public Program RenderProgram = null;
|
|
||||||
public Program ComputeProgram = null;
|
|
||||||
|
|
||||||
public PipelineState Pipeline;
|
|
||||||
public DepthStencilUid DepthStencilUid;
|
|
||||||
|
|
||||||
public readonly record struct ArrayRef<T>(ShaderStage Stage, T Array);
|
|
||||||
|
|
||||||
public readonly BufferRef[] UniformBufferRefs = new BufferRef[Constants.MaxUniformBufferBindings];
|
|
||||||
public readonly BufferRef[] StorageBufferRefs = new BufferRef[Constants.MaxStorageBufferBindings];
|
|
||||||
public readonly TextureRef[] TextureRefs = new TextureRef[Constants.MaxTextureBindings * 2];
|
|
||||||
public readonly ImageRef[] ImageRefs = new ImageRef[Constants.MaxImageBindings * 2];
|
|
||||||
|
|
||||||
public ArrayRef<TextureArray>[] TextureArrayRefs = [];
|
|
||||||
public ArrayRef<ImageArray>[] ImageArrayRefs = [];
|
|
||||||
|
|
||||||
public ArrayRef<TextureArray>[] TextureArrayExtraRefs = [];
|
|
||||||
public ArrayRef<ImageArray>[] ImageArrayExtraRefs = [];
|
|
||||||
|
|
||||||
public IndexBufferState IndexBuffer = default;
|
|
||||||
|
|
||||||
public MTLDepthClipMode DepthClipMode = MTLDepthClipMode.Clip;
|
|
||||||
|
|
||||||
public float DepthBias;
|
|
||||||
public float SlopeScale;
|
|
||||||
public float Clamp;
|
|
||||||
|
|
||||||
public int BackRefValue = 0;
|
|
||||||
public int FrontRefValue = 0;
|
|
||||||
|
|
||||||
public PrimitiveTopology Topology = PrimitiveTopology.Triangles;
|
|
||||||
public MTLCullMode CullMode = MTLCullMode.None;
|
|
||||||
public MTLWinding Winding = MTLWinding.CounterClockwise;
|
|
||||||
public bool CullBoth = false;
|
|
||||||
|
|
||||||
public MTLViewport[] Viewports = new MTLViewport[Constants.MaxViewports];
|
|
||||||
public MTLScissorRect[] Scissors = new MTLScissorRect[Constants.MaxViewports];
|
|
||||||
|
|
||||||
// Changes to attachments take recreation!
|
|
||||||
public Texture DepthStencil;
|
|
||||||
public Texture[] RenderTargets = new Texture[Constants.MaxColorAttachments];
|
|
||||||
public ITexture PreMaskDepthStencil = default;
|
|
||||||
public ITexture[] PreMaskRenderTargets;
|
|
||||||
public bool FramebufferUsingColorWriteMask;
|
|
||||||
|
|
||||||
public Array8<ColorBlendStateUid> StoredBlend;
|
|
||||||
public ColorF BlendColor = new();
|
|
||||||
|
|
||||||
public readonly VertexBufferState[] VertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers];
|
|
||||||
public readonly VertexAttribDescriptor[] VertexAttribs = new VertexAttribDescriptor[Constants.MaxVertexAttributes];
|
|
||||||
// Dirty flags
|
|
||||||
public DirtyFlags Dirty = DirtyFlags.None;
|
|
||||||
|
|
||||||
// Only to be used for present
|
|
||||||
public bool ClearLoadAction = false;
|
|
||||||
|
|
||||||
public RenderEncoderBindings RenderEncoderBindings = new();
|
|
||||||
public ComputeEncoderBindings ComputeEncoderBindings = new();
|
|
||||||
|
|
||||||
public EncoderState()
|
|
||||||
{
|
|
||||||
Pipeline.Initialize();
|
|
||||||
DepthStencilUid.DepthCompareFunction = MTLCompareFunction.Always;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RenderTargetCopy InheritForClear(EncoderState other, bool depth, int singleIndex = -1)
|
|
||||||
{
|
|
||||||
// Inherit render target related information without causing a render encoder split.
|
|
||||||
|
|
||||||
var oldState = new RenderTargetCopy
|
|
||||||
{
|
|
||||||
Scissors = other.Scissors,
|
|
||||||
RenderTargets = other.RenderTargets,
|
|
||||||
DepthStencil = other.DepthStencil
|
|
||||||
};
|
|
||||||
|
|
||||||
Scissors = other.Scissors;
|
|
||||||
RenderTargets = other.RenderTargets;
|
|
||||||
DepthStencil = other.DepthStencil;
|
|
||||||
|
|
||||||
Pipeline.ColorBlendAttachmentStateCount = other.Pipeline.ColorBlendAttachmentStateCount;
|
|
||||||
Pipeline.Internal.ColorBlendState = other.Pipeline.Internal.ColorBlendState;
|
|
||||||
Pipeline.DepthStencilFormat = other.Pipeline.DepthStencilFormat;
|
|
||||||
|
|
||||||
ref var blendStates = ref Pipeline.Internal.ColorBlendState;
|
|
||||||
|
|
||||||
// Mask out irrelevant attachments.
|
|
||||||
for (int i = 0; i < blendStates.Length; i++)
|
|
||||||
{
|
|
||||||
if (depth || (singleIndex != -1 && singleIndex != i))
|
|
||||||
{
|
|
||||||
blendStates[i].WriteMask = MTLColorWriteMask.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return oldState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Restore(RenderTargetCopy copy)
|
|
||||||
{
|
|
||||||
Scissors = copy.Scissors;
|
|
||||||
RenderTargets = copy.RenderTargets;
|
|
||||||
DepthStencil = copy.DepthStencil;
|
|
||||||
|
|
||||||
Pipeline.Internal.ResetColorState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,293 +0,0 @@
|
|||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
static class EnumConversion
|
|
||||||
{
|
|
||||||
public static MTLSamplerAddressMode Convert(this AddressMode mode)
|
|
||||||
{
|
|
||||||
return mode switch
|
|
||||||
{
|
|
||||||
AddressMode.Clamp => MTLSamplerAddressMode.ClampToEdge, // TODO: Should be clamp.
|
|
||||||
AddressMode.Repeat => MTLSamplerAddressMode.Repeat,
|
|
||||||
AddressMode.MirrorClamp => MTLSamplerAddressMode.MirrorClampToEdge, // TODO: Should be mirror clamp.
|
|
||||||
AddressMode.MirroredRepeat => MTLSamplerAddressMode.MirrorRepeat,
|
|
||||||
AddressMode.ClampToBorder => MTLSamplerAddressMode.ClampToBorderColor,
|
|
||||||
AddressMode.ClampToEdge => MTLSamplerAddressMode.ClampToEdge,
|
|
||||||
AddressMode.MirrorClampToEdge => MTLSamplerAddressMode.MirrorClampToEdge,
|
|
||||||
AddressMode.MirrorClampToBorder => MTLSamplerAddressMode.ClampToBorderColor, // TODO: Should be mirror clamp to border.
|
|
||||||
_ => LogInvalidAndReturn(mode, nameof(AddressMode), MTLSamplerAddressMode.ClampToEdge) // TODO: Should be clamp.
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLBlendFactor Convert(this BlendFactor factor)
|
|
||||||
{
|
|
||||||
return factor switch
|
|
||||||
{
|
|
||||||
BlendFactor.Zero or BlendFactor.ZeroGl => MTLBlendFactor.Zero,
|
|
||||||
BlendFactor.One or BlendFactor.OneGl => MTLBlendFactor.One,
|
|
||||||
BlendFactor.SrcColor or BlendFactor.SrcColorGl => MTLBlendFactor.SourceColor,
|
|
||||||
BlendFactor.OneMinusSrcColor or BlendFactor.OneMinusSrcColorGl => MTLBlendFactor.OneMinusSourceColor,
|
|
||||||
BlendFactor.SrcAlpha or BlendFactor.SrcAlphaGl => MTLBlendFactor.SourceAlpha,
|
|
||||||
BlendFactor.OneMinusSrcAlpha or BlendFactor.OneMinusSrcAlphaGl => MTLBlendFactor.OneMinusSourceAlpha,
|
|
||||||
BlendFactor.DstAlpha or BlendFactor.DstAlphaGl => MTLBlendFactor.DestinationAlpha,
|
|
||||||
BlendFactor.OneMinusDstAlpha or BlendFactor.OneMinusDstAlphaGl => MTLBlendFactor.OneMinusDestinationAlpha,
|
|
||||||
BlendFactor.DstColor or BlendFactor.DstColorGl => MTLBlendFactor.DestinationColor,
|
|
||||||
BlendFactor.OneMinusDstColor or BlendFactor.OneMinusDstColorGl => MTLBlendFactor.OneMinusDestinationColor,
|
|
||||||
BlendFactor.SrcAlphaSaturate or BlendFactor.SrcAlphaSaturateGl => MTLBlendFactor.SourceAlphaSaturated,
|
|
||||||
BlendFactor.Src1Color or BlendFactor.Src1ColorGl => MTLBlendFactor.Source1Color,
|
|
||||||
BlendFactor.OneMinusSrc1Color or BlendFactor.OneMinusSrc1ColorGl => MTLBlendFactor.OneMinusSource1Color,
|
|
||||||
BlendFactor.Src1Alpha or BlendFactor.Src1AlphaGl => MTLBlendFactor.Source1Alpha,
|
|
||||||
BlendFactor.OneMinusSrc1Alpha or BlendFactor.OneMinusSrc1AlphaGl => MTLBlendFactor.OneMinusSource1Alpha,
|
|
||||||
BlendFactor.ConstantColor => MTLBlendFactor.BlendColor,
|
|
||||||
BlendFactor.OneMinusConstantColor => MTLBlendFactor.OneMinusBlendColor,
|
|
||||||
BlendFactor.ConstantAlpha => MTLBlendFactor.BlendAlpha,
|
|
||||||
BlendFactor.OneMinusConstantAlpha => MTLBlendFactor.OneMinusBlendAlpha,
|
|
||||||
_ => LogInvalidAndReturn(factor, nameof(BlendFactor), MTLBlendFactor.Zero)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLBlendOperation Convert(this BlendOp op)
|
|
||||||
{
|
|
||||||
return op switch
|
|
||||||
{
|
|
||||||
BlendOp.Add or BlendOp.AddGl => MTLBlendOperation.Add,
|
|
||||||
BlendOp.Subtract or BlendOp.SubtractGl => MTLBlendOperation.Subtract,
|
|
||||||
BlendOp.ReverseSubtract or BlendOp.ReverseSubtractGl => MTLBlendOperation.ReverseSubtract,
|
|
||||||
BlendOp.Minimum => MTLBlendOperation.Min,
|
|
||||||
BlendOp.Maximum => MTLBlendOperation.Max,
|
|
||||||
_ => LogInvalidAndReturn(op, nameof(BlendOp), MTLBlendOperation.Add)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLCompareFunction Convert(this CompareOp op)
|
|
||||||
{
|
|
||||||
return op switch
|
|
||||||
{
|
|
||||||
CompareOp.Never or CompareOp.NeverGl => MTLCompareFunction.Never,
|
|
||||||
CompareOp.Less or CompareOp.LessGl => MTLCompareFunction.Less,
|
|
||||||
CompareOp.Equal or CompareOp.EqualGl => MTLCompareFunction.Equal,
|
|
||||||
CompareOp.LessOrEqual or CompareOp.LessOrEqualGl => MTLCompareFunction.LessEqual,
|
|
||||||
CompareOp.Greater or CompareOp.GreaterGl => MTLCompareFunction.Greater,
|
|
||||||
CompareOp.NotEqual or CompareOp.NotEqualGl => MTLCompareFunction.NotEqual,
|
|
||||||
CompareOp.GreaterOrEqual or CompareOp.GreaterOrEqualGl => MTLCompareFunction.GreaterEqual,
|
|
||||||
CompareOp.Always or CompareOp.AlwaysGl => MTLCompareFunction.Always,
|
|
||||||
_ => LogInvalidAndReturn(op, nameof(CompareOp), MTLCompareFunction.Never)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLCullMode Convert(this Face face)
|
|
||||||
{
|
|
||||||
return face switch
|
|
||||||
{
|
|
||||||
Face.Back => MTLCullMode.Back,
|
|
||||||
Face.Front => MTLCullMode.Front,
|
|
||||||
Face.FrontAndBack => MTLCullMode.None,
|
|
||||||
_ => LogInvalidAndReturn(face, nameof(Face), MTLCullMode.Back)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLWinding Convert(this FrontFace frontFace)
|
|
||||||
{
|
|
||||||
// The viewport is flipped vertically, therefore we need to switch the winding order as well
|
|
||||||
return frontFace switch
|
|
||||||
{
|
|
||||||
FrontFace.Clockwise => MTLWinding.CounterClockwise,
|
|
||||||
FrontFace.CounterClockwise => MTLWinding.Clockwise,
|
|
||||||
_ => LogInvalidAndReturn(frontFace, nameof(FrontFace), MTLWinding.Clockwise)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLIndexType Convert(this IndexType type)
|
|
||||||
{
|
|
||||||
return type switch
|
|
||||||
{
|
|
||||||
IndexType.UShort => MTLIndexType.UInt16,
|
|
||||||
IndexType.UInt => MTLIndexType.UInt32,
|
|
||||||
_ => LogInvalidAndReturn(type, nameof(IndexType), MTLIndexType.UInt16)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLLogicOperation Convert(this LogicalOp op)
|
|
||||||
{
|
|
||||||
return op switch
|
|
||||||
{
|
|
||||||
LogicalOp.Clear => MTLLogicOperation.Clear,
|
|
||||||
LogicalOp.And => MTLLogicOperation.And,
|
|
||||||
LogicalOp.AndReverse => MTLLogicOperation.AndReverse,
|
|
||||||
LogicalOp.Copy => MTLLogicOperation.Copy,
|
|
||||||
LogicalOp.AndInverted => MTLLogicOperation.AndInverted,
|
|
||||||
LogicalOp.Noop => MTLLogicOperation.Noop,
|
|
||||||
LogicalOp.Xor => MTLLogicOperation.Xor,
|
|
||||||
LogicalOp.Or => MTLLogicOperation.Or,
|
|
||||||
LogicalOp.Nor => MTLLogicOperation.Nor,
|
|
||||||
LogicalOp.Equiv => MTLLogicOperation.Equivalence,
|
|
||||||
LogicalOp.Invert => MTLLogicOperation.Invert,
|
|
||||||
LogicalOp.OrReverse => MTLLogicOperation.OrReverse,
|
|
||||||
LogicalOp.CopyInverted => MTLLogicOperation.CopyInverted,
|
|
||||||
LogicalOp.OrInverted => MTLLogicOperation.OrInverted,
|
|
||||||
LogicalOp.Nand => MTLLogicOperation.Nand,
|
|
||||||
LogicalOp.Set => MTLLogicOperation.Set,
|
|
||||||
_ => LogInvalidAndReturn(op, nameof(LogicalOp), MTLLogicOperation.And)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLSamplerMinMagFilter Convert(this MagFilter filter)
|
|
||||||
{
|
|
||||||
return filter switch
|
|
||||||
{
|
|
||||||
MagFilter.Nearest => MTLSamplerMinMagFilter.Nearest,
|
|
||||||
MagFilter.Linear => MTLSamplerMinMagFilter.Linear,
|
|
||||||
_ => LogInvalidAndReturn(filter, nameof(MagFilter), MTLSamplerMinMagFilter.Nearest)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static (MTLSamplerMinMagFilter, MTLSamplerMipFilter) Convert(this MinFilter filter)
|
|
||||||
{
|
|
||||||
return filter switch
|
|
||||||
{
|
|
||||||
MinFilter.Nearest => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Nearest),
|
|
||||||
MinFilter.Linear => (MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Linear),
|
|
||||||
MinFilter.NearestMipmapNearest => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Nearest),
|
|
||||||
MinFilter.LinearMipmapNearest => (MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Nearest),
|
|
||||||
MinFilter.NearestMipmapLinear => (MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Linear),
|
|
||||||
MinFilter.LinearMipmapLinear => (MTLSamplerMinMagFilter.Linear, MTLSamplerMipFilter.Linear),
|
|
||||||
_ => LogInvalidAndReturn(filter, nameof(MinFilter), (MTLSamplerMinMagFilter.Nearest, MTLSamplerMipFilter.Nearest))
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLPrimitiveType Convert(this PrimitiveTopology topology)
|
|
||||||
{
|
|
||||||
return topology switch
|
|
||||||
{
|
|
||||||
PrimitiveTopology.Points => MTLPrimitiveType.Point,
|
|
||||||
PrimitiveTopology.Lines => MTLPrimitiveType.Line,
|
|
||||||
PrimitiveTopology.LineStrip => MTLPrimitiveType.LineStrip,
|
|
||||||
PrimitiveTopology.Triangles => MTLPrimitiveType.Triangle,
|
|
||||||
PrimitiveTopology.TriangleStrip => MTLPrimitiveType.TriangleStrip,
|
|
||||||
_ => LogInvalidAndReturn(topology, nameof(PrimitiveTopology), MTLPrimitiveType.Triangle)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLStencilOperation Convert(this StencilOp op)
|
|
||||||
{
|
|
||||||
return op switch
|
|
||||||
{
|
|
||||||
StencilOp.Keep or StencilOp.KeepGl => MTLStencilOperation.Keep,
|
|
||||||
StencilOp.Zero or StencilOp.ZeroGl => MTLStencilOperation.Zero,
|
|
||||||
StencilOp.Replace or StencilOp.ReplaceGl => MTLStencilOperation.Replace,
|
|
||||||
StencilOp.IncrementAndClamp or StencilOp.IncrementAndClampGl => MTLStencilOperation.IncrementClamp,
|
|
||||||
StencilOp.DecrementAndClamp or StencilOp.DecrementAndClampGl => MTLStencilOperation.DecrementClamp,
|
|
||||||
StencilOp.Invert or StencilOp.InvertGl => MTLStencilOperation.Invert,
|
|
||||||
StencilOp.IncrementAndWrap or StencilOp.IncrementAndWrapGl => MTLStencilOperation.IncrementWrap,
|
|
||||||
StencilOp.DecrementAndWrap or StencilOp.DecrementAndWrapGl => MTLStencilOperation.DecrementWrap,
|
|
||||||
_ => LogInvalidAndReturn(op, nameof(StencilOp), MTLStencilOperation.Keep)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLTextureType Convert(this Target target)
|
|
||||||
{
|
|
||||||
return target switch
|
|
||||||
{
|
|
||||||
Target.TextureBuffer => MTLTextureType.TextureBuffer,
|
|
||||||
Target.Texture1D => MTLTextureType.Type1D,
|
|
||||||
Target.Texture1DArray => MTLTextureType.Type1DArray,
|
|
||||||
Target.Texture2D => MTLTextureType.Type2D,
|
|
||||||
Target.Texture2DArray => MTLTextureType.Type2DArray,
|
|
||||||
Target.Texture2DMultisample => MTLTextureType.Type2DMultisample,
|
|
||||||
Target.Texture2DMultisampleArray => MTLTextureType.Type2DMultisampleArray,
|
|
||||||
Target.Texture3D => MTLTextureType.Type3D,
|
|
||||||
Target.Cubemap => MTLTextureType.Cube,
|
|
||||||
Target.CubemapArray => MTLTextureType.CubeArray,
|
|
||||||
_ => LogInvalidAndReturn(target, nameof(Target), MTLTextureType.Type2D)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLTextureSwizzle Convert(this SwizzleComponent swizzleComponent)
|
|
||||||
{
|
|
||||||
return swizzleComponent switch
|
|
||||||
{
|
|
||||||
SwizzleComponent.Zero => MTLTextureSwizzle.Zero,
|
|
||||||
SwizzleComponent.One => MTLTextureSwizzle.One,
|
|
||||||
SwizzleComponent.Red => MTLTextureSwizzle.Red,
|
|
||||||
SwizzleComponent.Green => MTLTextureSwizzle.Green,
|
|
||||||
SwizzleComponent.Blue => MTLTextureSwizzle.Blue,
|
|
||||||
SwizzleComponent.Alpha => MTLTextureSwizzle.Alpha,
|
|
||||||
_ => LogInvalidAndReturn(swizzleComponent, nameof(SwizzleComponent), MTLTextureSwizzle.Zero)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLVertexFormat Convert(this Format format)
|
|
||||||
{
|
|
||||||
return format switch
|
|
||||||
{
|
|
||||||
Format.R16Float => MTLVertexFormat.Half,
|
|
||||||
Format.R16G16Float => MTLVertexFormat.Half2,
|
|
||||||
Format.R16G16B16Float => MTLVertexFormat.Half3,
|
|
||||||
Format.R16G16B16A16Float => MTLVertexFormat.Half4,
|
|
||||||
Format.R32Float => MTLVertexFormat.Float,
|
|
||||||
Format.R32G32Float => MTLVertexFormat.Float2,
|
|
||||||
Format.R32G32B32Float => MTLVertexFormat.Float3,
|
|
||||||
Format.R11G11B10Float => MTLVertexFormat.FloatRG11B10,
|
|
||||||
Format.R32G32B32A32Float => MTLVertexFormat.Float4,
|
|
||||||
Format.R8Uint => MTLVertexFormat.UChar,
|
|
||||||
Format.R8G8Uint => MTLVertexFormat.UChar2,
|
|
||||||
Format.R8G8B8Uint => MTLVertexFormat.UChar3,
|
|
||||||
Format.R8G8B8A8Uint => MTLVertexFormat.UChar4,
|
|
||||||
Format.R16Uint => MTLVertexFormat.UShort,
|
|
||||||
Format.R16G16Uint => MTLVertexFormat.UShort2,
|
|
||||||
Format.R16G16B16Uint => MTLVertexFormat.UShort3,
|
|
||||||
Format.R16G16B16A16Uint => MTLVertexFormat.UShort4,
|
|
||||||
Format.R32Uint => MTLVertexFormat.UInt,
|
|
||||||
Format.R32G32Uint => MTLVertexFormat.UInt2,
|
|
||||||
Format.R32G32B32Uint => MTLVertexFormat.UInt3,
|
|
||||||
Format.R32G32B32A32Uint => MTLVertexFormat.UInt4,
|
|
||||||
Format.R8Sint => MTLVertexFormat.Char,
|
|
||||||
Format.R8G8Sint => MTLVertexFormat.Char2,
|
|
||||||
Format.R8G8B8Sint => MTLVertexFormat.Char3,
|
|
||||||
Format.R8G8B8A8Sint => MTLVertexFormat.Char4,
|
|
||||||
Format.R16Sint => MTLVertexFormat.Short,
|
|
||||||
Format.R16G16Sint => MTLVertexFormat.Short2,
|
|
||||||
Format.R16G16B16Sint => MTLVertexFormat.Short3,
|
|
||||||
Format.R16G16B16A16Sint => MTLVertexFormat.Short4,
|
|
||||||
Format.R32Sint => MTLVertexFormat.Int,
|
|
||||||
Format.R32G32Sint => MTLVertexFormat.Int2,
|
|
||||||
Format.R32G32B32Sint => MTLVertexFormat.Int3,
|
|
||||||
Format.R32G32B32A32Sint => MTLVertexFormat.Int4,
|
|
||||||
Format.R8Unorm => MTLVertexFormat.UCharNormalized,
|
|
||||||
Format.R8G8Unorm => MTLVertexFormat.UChar2Normalized,
|
|
||||||
Format.R8G8B8Unorm => MTLVertexFormat.UChar3Normalized,
|
|
||||||
Format.R8G8B8A8Unorm => MTLVertexFormat.UChar4Normalized,
|
|
||||||
Format.R16Unorm => MTLVertexFormat.UShortNormalized,
|
|
||||||
Format.R16G16Unorm => MTLVertexFormat.UShort2Normalized,
|
|
||||||
Format.R16G16B16Unorm => MTLVertexFormat.UShort3Normalized,
|
|
||||||
Format.R16G16B16A16Unorm => MTLVertexFormat.UShort4Normalized,
|
|
||||||
Format.R10G10B10A2Unorm => MTLVertexFormat.UInt1010102Normalized,
|
|
||||||
Format.R8Snorm => MTLVertexFormat.CharNormalized,
|
|
||||||
Format.R8G8Snorm => MTLVertexFormat.Char2Normalized,
|
|
||||||
Format.R8G8B8Snorm => MTLVertexFormat.Char3Normalized,
|
|
||||||
Format.R8G8B8A8Snorm => MTLVertexFormat.Char4Normalized,
|
|
||||||
Format.R16Snorm => MTLVertexFormat.ShortNormalized,
|
|
||||||
Format.R16G16Snorm => MTLVertexFormat.Short2Normalized,
|
|
||||||
Format.R16G16B16Snorm => MTLVertexFormat.Short3Normalized,
|
|
||||||
Format.R16G16B16A16Snorm => MTLVertexFormat.Short4Normalized,
|
|
||||||
Format.R10G10B10A2Snorm => MTLVertexFormat.Int1010102Normalized,
|
|
||||||
|
|
||||||
_ => LogInvalidAndReturn(format, nameof(Format), MTLVertexFormat.Float4)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static T2 LogInvalidAndReturn<T1, T2>(T1 value, string name, T2 defaultValue = default)
|
|
||||||
{
|
|
||||||
Logger.Debug?.Print(LogClass.Gpu, $"Invalid {name} enum value: {value}.");
|
|
||||||
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
class FenceHolder : IDisposable
|
|
||||||
{
|
|
||||||
private MTLCommandBuffer _fence;
|
|
||||||
private int _referenceCount;
|
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
public FenceHolder(MTLCommandBuffer fence)
|
|
||||||
{
|
|
||||||
_fence = fence;
|
|
||||||
_referenceCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MTLCommandBuffer GetUnsafe()
|
|
||||||
{
|
|
||||||
return _fence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGet(out MTLCommandBuffer fence)
|
|
||||||
{
|
|
||||||
int lastValue;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
lastValue = _referenceCount;
|
|
||||||
|
|
||||||
if (lastValue == 0)
|
|
||||||
{
|
|
||||||
fence = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} while (Interlocked.CompareExchange(ref _referenceCount, lastValue + 1, lastValue) != lastValue);
|
|
||||||
|
|
||||||
fence = _fence;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MTLCommandBuffer Get()
|
|
||||||
{
|
|
||||||
Interlocked.Increment(ref _referenceCount);
|
|
||||||
return _fence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Put()
|
|
||||||
{
|
|
||||||
if (Interlocked.Decrement(ref _referenceCount) == 0)
|
|
||||||
{
|
|
||||||
_fence = default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Wait()
|
|
||||||
{
|
|
||||||
_fence.WaitUntilCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSignaled()
|
|
||||||
{
|
|
||||||
return _fence.Status == MTLCommandBufferStatus.Completed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (!_disposed)
|
|
||||||
{
|
|
||||||
Put();
|
|
||||||
_disposed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
class FormatConverter
|
|
||||||
{
|
|
||||||
public static void ConvertD24S8ToD32FS8(Span<byte> output, ReadOnlySpan<byte> input)
|
|
||||||
{
|
|
||||||
const float UnormToFloat = 1f / 0xffffff;
|
|
||||||
|
|
||||||
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
|
|
||||||
ReadOnlySpan<uint> inputUint = MemoryMarshal.Cast<byte, uint>(input);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (; i < inputUint.Length; i++)
|
|
||||||
{
|
|
||||||
uint depthStencil = inputUint[i];
|
|
||||||
uint depth = depthStencil >> 8;
|
|
||||||
uint stencil = depthStencil & 0xff;
|
|
||||||
|
|
||||||
int j = i * 2;
|
|
||||||
|
|
||||||
outputUint[j] = (uint)BitConverter.SingleToInt32Bits(depth * UnormToFloat);
|
|
||||||
outputUint[j + 1] = stencil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ConvertD32FS8ToD24S8(Span<byte> output, ReadOnlySpan<byte> input)
|
|
||||||
{
|
|
||||||
Span<uint> outputUint = MemoryMarshal.Cast<byte, uint>(output);
|
|
||||||
ReadOnlySpan<uint> inputUint = MemoryMarshal.Cast<byte, uint>(input);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (; i < inputUint.Length; i += 2)
|
|
||||||
{
|
|
||||||
float depth = BitConverter.Int32BitsToSingle((int)inputUint[i]);
|
|
||||||
uint stencil = inputUint[i + 1];
|
|
||||||
uint depthStencil = (Math.Clamp((uint)(depth * 0xffffff), 0, 0xffffff) << 8) | (stencil & 0xff);
|
|
||||||
|
|
||||||
int j = i >> 1;
|
|
||||||
|
|
||||||
outputUint[j] = depthStencil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,196 +0,0 @@
|
|||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.GAL;
|
|
||||||
using SharpMetal.Metal;
|
|
||||||
using System;
|
|
||||||
using System.Runtime.Versioning;
|
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Metal
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("macos")]
|
|
||||||
static class FormatTable
|
|
||||||
{
|
|
||||||
private static readonly MTLPixelFormat[] _table;
|
|
||||||
|
|
||||||
static FormatTable()
|
|
||||||
{
|
|
||||||
_table = new MTLPixelFormat[Enum.GetNames(typeof(Format)).Length];
|
|
||||||
|
|
||||||
Add(Format.R8Unorm, MTLPixelFormat.R8Unorm);
|
|
||||||
Add(Format.R8Snorm, MTLPixelFormat.R8Snorm);
|
|
||||||
Add(Format.R8Uint, MTLPixelFormat.R8Uint);
|
|
||||||
Add(Format.R8Sint, MTLPixelFormat.R8Sint);
|
|
||||||
Add(Format.R16Float, MTLPixelFormat.R16Float);
|
|
||||||
Add(Format.R16Unorm, MTLPixelFormat.R16Unorm);
|
|
||||||
Add(Format.R16Snorm, MTLPixelFormat.R16Snorm);
|
|
||||||
Add(Format.R16Uint, MTLPixelFormat.R16Uint);
|
|
||||||
Add(Format.R16Sint, MTLPixelFormat.R16Sint);
|
|
||||||
Add(Format.R32Float, MTLPixelFormat.R32Float);
|
|
||||||
Add(Format.R32Uint, MTLPixelFormat.R32Uint);
|
|
||||||
Add(Format.R32Sint, MTLPixelFormat.R32Sint);
|
|
||||||
Add(Format.R8G8Unorm, MTLPixelFormat.RG8Unorm);
|
|
||||||
Add(Format.R8G8Snorm, MTLPixelFormat.RG8Snorm);
|
|
||||||
Add(Format.R8G8Uint, MTLPixelFormat.RG8Uint);
|
|
||||||
Add(Format.R8G8Sint, MTLPixelFormat.RG8Sint);
|
|
||||||
Add(Format.R16G16Float, MTLPixelFormat.RG16Float);
|
|
||||||
Add(Format.R16G16Unorm, MTLPixelFormat.RG16Unorm);
|
|
||||||
Add(Format.R16G16Snorm, MTLPixelFormat.RG16Snorm);
|
|
||||||
Add(Format.R16G16Uint, MTLPixelFormat.RG16Uint);
|
|
||||||
Add(Format.R16G16Sint, MTLPixelFormat.RG16Sint);
|
|
||||||
Add(Format.R32G32Float, MTLPixelFormat.RG32Float);
|
|
||||||
Add(Format.R32G32Uint, MTLPixelFormat.RG32Uint);
|
|
||||||
Add(Format.R32G32Sint, MTLPixelFormat.RG32Sint);
|
|
||||||
// Add(Format.R8G8B8Unorm, MTLPixelFormat.R8G8B8Unorm);
|
|
||||||
// Add(Format.R8G8B8Snorm, MTLPixelFormat.R8G8B8Snorm);
|
|
||||||
// Add(Format.R8G8B8Uint, MTLPixelFormat.R8G8B8Uint);
|
|
||||||
// Add(Format.R8G8B8Sint, MTLPixelFormat.R8G8B8Sint);
|
|
||||||
// Add(Format.R16G16B16Float, MTLPixelFormat.R16G16B16Float);
|
|
||||||
// Add(Format.R16G16B16Unorm, MTLPixelFormat.R16G16B16Unorm);
|
|
||||||
// Add(Format.R16G16B16Snorm, MTLPixelFormat.R16G16B16SNorm);
|
|
||||||
// Add(Format.R16G16B16Uint, MTLPixelFormat.R16G16B16Uint);
|
|
||||||
// Add(Format.R16G16B16Sint, MTLPixelFormat.R16G16B16Sint);
|
|
||||||
// Add(Format.R32G32B32Float, MTLPixelFormat.R32G32B32Sfloat);
|
|
||||||
// Add(Format.R32G32B32Uint, MTLPixelFormat.R32G32B32Uint);
|
|
||||||
// Add(Format.R32G32B32Sint, MTLPixelFormat.R32G32B32Sint);
|
|
||||||
Add(Format.R8G8B8A8Unorm, MTLPixelFormat.RGBA8Unorm);
|
|
||||||
Add(Format.R8G8B8A8Snorm, MTLPixelFormat.RGBA8Snorm);
|
|
||||||
Add(Format.R8G8B8A8Uint, MTLPixelFormat.RGBA8Uint);
|
|
||||||
Add(Format.R8G8B8A8Sint, MTLPixelFormat.RGBA8Sint);
|
|
||||||
Add(Format.R16G16B16A16Float, MTLPixelFormat.RGBA16Float);
|
|
||||||
Add(Format.R16G16B16A16Unorm, MTLPixelFormat.RGBA16Unorm);
|
|
||||||
Add(Format.R16G16B16A16Snorm, MTLPixelFormat.RGBA16Snorm);
|
|
||||||
Add(Format.R16G16B16A16Uint, MTLPixelFormat.RGBA16Uint);
|
|
||||||
Add(Format.R16G16B16A16Sint, MTLPixelFormat.RGBA16Sint);
|
|
||||||
Add(Format.R32G32B32A32Float, MTLPixelFormat.RGBA32Float);
|
|
||||||
Add(Format.R32G32B32A32Uint, MTLPixelFormat.RGBA32Uint);
|
|
||||||
Add(Format.R32G32B32A32Sint, MTLPixelFormat.RGBA32Sint);
|
|
||||||
Add(Format.S8Uint, MTLPixelFormat.Stencil8);
|
|
||||||
Add(Format.D16Unorm, MTLPixelFormat.Depth16Unorm);
|
|
||||||
Add(Format.S8UintD24Unorm, MTLPixelFormat.Depth24UnormStencil8);
|
|
||||||
Add(Format.X8UintD24Unorm, MTLPixelFormat.Depth24UnormStencil8);
|
|
||||||
Add(Format.D32Float, MTLPixelFormat.Depth32Float);
|
|
||||||
Add(Format.D24UnormS8Uint, MTLPixelFormat.Depth24UnormStencil8);
|
|
||||||
Add(Format.D32FloatS8Uint, MTLPixelFormat.Depth32FloatStencil8);
|
|
||||||
Add(Format.R8G8B8A8Srgb, MTLPixelFormat.RGBA8UnormsRGB);
|
|
||||||
// Add(Format.R4G4Unorm, MTLPixelFormat.R4G4Unorm);
|
|
||||||
Add(Format.R4G4B4A4Unorm, MTLPixelFormat.RGBA8Unorm);
|
|
||||||
// Add(Format.R5G5B5X1Unorm, MTLPixelFormat.R5G5B5X1Unorm);
|
|
||||||
Add(Format.R5G5B5A1Unorm, MTLPixelFormat.BGR5A1Unorm);
|
|
||||||
Add(Format.R5G6B5Unorm, MTLPixelFormat.B5G6R5Unorm);
|
|
||||||
Add(Format.R10G10B10A2Unorm, MTLPixelFormat.RGB10A2Unorm);
|
|
||||||
Add(Format.R10G10B10A2Uint, MTLPixelFormat.RGB10A2Uint);
|
|
||||||
Add(Format.R11G11B10Float, MTLPixelFormat.RG11B10Float);
|
|
||||||
Add(Format.R9G9B9E5Float, MTLPixelFormat.RGB9E5Float);
|
|
||||||
Add(Format.Bc1RgbaUnorm, MTLPixelFormat.BC1RGBA);
|
|
||||||
Add(Format.Bc2Unorm, MTLPixelFormat.BC2RGBA);
|
|
||||||
Add(Format.Bc3Unorm, MTLPixelFormat.BC3RGBA);
|
|
||||||
Add(Format.Bc1RgbaSrgb, MTLPixelFormat.BC1RGBAsRGB);
|
|
||||||
Add(Format.Bc2Srgb, MTLPixelFormat.BC2RGBAsRGB);
|
|
||||||
Add(Format.Bc3Srgb, MTLPixelFormat.BC3RGBAsRGB);
|
|
||||||
Add(Format.Bc4Unorm, MTLPixelFormat.BC4RUnorm);
|
|
||||||
Add(Format.Bc4Snorm, MTLPixelFormat.BC4RSnorm);
|
|
||||||
Add(Format.Bc5Unorm, MTLPixelFormat.BC5RGUnorm);
|
|
||||||
Add(Format.Bc5Snorm, MTLPixelFormat.BC5RGSnorm);
|
|
||||||
Add(Format.Bc7Unorm, MTLPixelFormat.BC7RGBAUnorm);
|
|
||||||
Add(Format.Bc7Srgb, MTLPixelFormat.BC7RGBAUnormsRGB);
|
|
||||||
Add(Format.Bc6HSfloat, MTLPixelFormat.BC6HRGBFloat);
|
|
||||||
Add(Format.Bc6HUfloat, MTLPixelFormat.BC6HRGBUfloat);
|
|
||||||
Add(Format.Etc2RgbUnorm, MTLPixelFormat.ETC2RGB8);
|
|
||||||
// Add(Format.Etc2RgbaUnorm, MTLPixelFormat.ETC2RGBA8);
|
|
||||||
Add(Format.Etc2RgbPtaUnorm, MTLPixelFormat.ETC2RGB8A1);
|
|
||||||
Add(Format.Etc2RgbSrgb, MTLPixelFormat.ETC2RGB8sRGB);
|
|
||||||
// Add(Format.Etc2RgbaSrgb, MTLPixelFormat.ETC2RGBA8sRGB);
|
|
||||||
Add(Format.Etc2RgbPtaSrgb, MTLPixelFormat.ETC2RGB8A1sRGB);
|
|
||||||
// Add(Format.R8Uscaled, MTLPixelFormat.R8Uscaled);
|
|
||||||
// Add(Format.R8Sscaled, MTLPixelFormat.R8Sscaled);
|
|
||||||
// Add(Format.R16Uscaled, MTLPixelFormat.R16Uscaled);
|
|
||||||
// Add(Format.R16Sscaled, MTLPixelFormat.R16Sscaled);
|
|
||||||
// Add(Format.R32Uscaled, MTLPixelFormat.R32Uscaled);
|
|
||||||
// Add(Format.R32Sscaled, MTLPixelFormat.R32Sscaled);
|
|
||||||
// Add(Format.R8G8Uscaled, MTLPixelFormat.R8G8Uscaled);
|
|
||||||
// Add(Format.R8G8Sscaled, MTLPixelFormat.R8G8Sscaled);
|
|
||||||
// Add(Format.R16G16Uscaled, MTLPixelFormat.R16G16Uscaled);
|
|
||||||
// Add(Format.R16G16Sscaled, MTLPixelFormat.R16G16Sscaled);
|
|
||||||
// Add(Format.R32G32Uscaled, MTLPixelFormat.R32G32Uscaled);
|
|
||||||
// Add(Format.R32G32Sscaled, MTLPixelFormat.R32G32Sscaled);
|
|
||||||
// Add(Format.R8G8B8Uscaled, MTLPixelFormat.R8G8B8Uscaled);
|
|
||||||
// Add(Format.R8G8B8Sscaled, MTLPixelFormat.R8G8B8Sscaled);
|
|
||||||
// Add(Format.R16G16B16Uscaled, MTLPixelFormat.R16G16B16Uscaled);
|
|
||||||
// Add(Format.R16G16B16Sscaled, MTLPixelFormat.R16G16B16Sscaled);
|
|
||||||
// Add(Format.R32G32B32Uscaled, MTLPixelFormat.R32G32B32Uscaled);
|
|
||||||
// Add(Format.R32G32B32Sscaled, MTLPixelFormat.R32G32B32Sscaled);
|
|
||||||
// Add(Format.R8G8B8A8Uscaled, MTLPixelFormat.R8G8B8A8Uscaled);
|
|
||||||
// Add(Format.R8G8B8A8Sscaled, MTLPixelFormat.R8G8B8A8Sscaled);
|
|
||||||
// Add(Format.R16G16B16A16Uscaled, MTLPixelFormat.R16G16B16A16Uscaled);
|
|
||||||
// Add(Format.R16G16B16A16Sscaled, MTLPixelFormat.R16G16B16A16Sscaled);
|
|
||||||
// Add(Format.R32G32B32A32Uscaled, MTLPixelFormat.R32G32B32A32Uscaled);
|
|
||||||
// Add(Format.R32G32B32A32Sscaled, MTLPixelFormat.R32G32B32A32Sscaled);
|
|
||||||
// Add(Format.R10G10B10A2Snorm, MTLPixelFormat.A2B10G10R10SNormPack32);
|
|
||||||
// Add(Format.R10G10B10A2Sint, MTLPixelFormat.A2B10G10R10SintPack32);
|
|
||||||
// Add(Format.R10G10B10A2Uscaled, MTLPixelFormat.A2B10G10R10UscaledPack32);
|
|
||||||
// Add(Format.R10G10B10A2Sscaled, MTLPixelFormat.A2B10G10R10SscaledPack32);
|
|
||||||
Add(Format.Astc4x4Unorm, MTLPixelFormat.ASTC4x4LDR);
|
|
||||||
Add(Format.Astc5x4Unorm, MTLPixelFormat.ASTC5x4LDR);
|
|
||||||
Add(Format.Astc5x5Unorm, MTLPixelFormat.ASTC5x5LDR);
|
|
||||||
Add(Format.Astc6x5Unorm, MTLPixelFormat.ASTC6x5LDR);
|
|
||||||
Add(Format.Astc6x6Unorm, MTLPixelFormat.ASTC6x6LDR);
|
|
||||||
Add(Format.Astc8x5Unorm, MTLPixelFormat.ASTC8x5LDR);
|
|
||||||
Add(Format.Astc8x6Unorm, MTLPixelFormat.ASTC8x6LDR);
|
|
||||||
Add(Format.Astc8x8Unorm, MTLPixelFormat.ASTC8x8LDR);
|
|
||||||
Add(Format.Astc10x5Unorm, MTLPixelFormat.ASTC10x5LDR);
|
|
||||||
Add(Format.Astc10x6Unorm, MTLPixelFormat.ASTC10x6LDR);
|
|
||||||
Add(Format.Astc10x8Unorm, MTLPixelFormat.ASTC10x8LDR);
|
|
||||||
Add(Format.Astc10x10Unorm, MTLPixelFormat.ASTC10x10LDR);
|
|
||||||
Add(Format.Astc12x10Unorm, MTLPixelFormat.ASTC12x10LDR);
|
|
||||||
Add(Format.Astc12x12Unorm, MTLPixelFormat.ASTC12x12LDR);
|
|
||||||
Add(Format.Astc4x4Srgb, MTLPixelFormat.ASTC4x4sRGB);
|
|
||||||
Add(Format.Astc5x4Srgb, MTLPixelFormat.ASTC5x4sRGB);
|
|
||||||
Add(Format.Astc5x5Srgb, MTLPixelFormat.ASTC5x5sRGB);
|
|
||||||
Add(Format.Astc6x5Srgb, MTLPixelFormat.ASTC6x5sRGB);
|
|
||||||
Add(Format.Astc6x6Srgb, MTLPixelFormat.ASTC6x6sRGB);
|
|
||||||
Add(Format.Astc8x5Srgb, MTLPixelFormat.ASTC8x5sRGB);
|
|
||||||
Add(Format.Astc8x6Srgb, MTLPixelFormat.ASTC8x6sRGB);
|
|
||||||
Add(Format.Astc8x8Srgb, MTLPixelFormat.ASTC8x8sRGB);
|
|
||||||
Add(Format.Astc10x5Srgb, MTLPixelFormat.ASTC10x5sRGB);
|
|
||||||
Add(Format.Astc10x6Srgb, MTLPixelFormat.ASTC10x6sRGB);
|
|
||||||
Add(Format.Astc10x8Srgb, MTLPixelFormat.ASTC10x8sRGB);
|
|
||||||
Add(Format.Astc10x10Srgb, MTLPixelFormat.ASTC10x10sRGB);
|
|
||||||
Add(Format.Astc12x10Srgb, MTLPixelFormat.ASTC12x10sRGB);
|
|
||||||
Add(Format.Astc12x12Srgb, MTLPixelFormat.ASTC12x12sRGB);
|
|
||||||
Add(Format.B5G6R5Unorm, MTLPixelFormat.B5G6R5Unorm);
|
|
||||||
Add(Format.B5G5R5A1Unorm, MTLPixelFormat.BGR5A1Unorm);
|
|
||||||
Add(Format.A1B5G5R5Unorm, MTLPixelFormat.A1BGR5Unorm);
|
|
||||||
Add(Format.B8G8R8A8Unorm, MTLPixelFormat.BGRA8Unorm);
|
|
||||||
Add(Format.B8G8R8A8Srgb, MTLPixelFormat.BGRA8UnormsRGB);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Add(Format format, MTLPixelFormat mtlFormat)
|
|
||||||
{
|
|
||||||
_table[(int)format] = mtlFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MTLPixelFormat GetFormat(Format format)
|
|
||||||
{
|
|
||||||
var mtlFormat = _table[(int)format];
|
|
||||||
|
|
||||||
if (IsD24S8(format))
|
|
||||||
{
|
|
||||||
if (!MTLDevice.CreateSystemDefaultDevice().Depth24Stencil8PixelFormatSupported)
|
|
||||||
{
|
|
||||||
mtlFormat = MTLPixelFormat.Depth32FloatStencil8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mtlFormat == MTLPixelFormat.Invalid)
|
|
||||||
{
|
|
||||||
Logger.Error?.PrintMsg(LogClass.Gpu, $"Format {format} is not supported by the host.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return mtlFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsD24S8(Format format)
|
|
||||||
{
|
|
||||||
return format == Format.D24UnormS8Uint || format == Format.S8UintD24Unorm || format == Format.X8UintD24Unorm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user