Compare commits

...

37 Commits

Author SHA1 Message Date
Evan Husted
206452e655 Merge branch 'master' into feature/native_aot 2025-03-04 14:52:14 -06:00
Evan Husted
57c22a1f32 misc: chore: [ci skip] Reduce duplicated close button & command space styling for dialogs 2025-03-04 02:57:11 -06:00
Evan Husted
f7976753fd misc: chore: move ThreadedRenderer creation logic into IRenderer base (since ThreadedRenderer is a GAL construct anyways) 2025-03-04 00:14:56 -06:00
Evan Husted
b45a65fbdc misc: chore: rework HLEConfiguration 2025-03-04 00:08:01 -06:00
Evan Husted
c410474d83 misc: chore: Remove MiniCommand 2025-03-02 21:49:58 -06:00
Evan Husted
ffdc419417 misc: chore: [ci skip] small Avalonia project restructure
Moved the Views that existed in the Controls namespace into the Ryujinx.Ava.UI.Views.Misc namespace
Moved UpdateWaitWindow to Ryujinx.Ava.UI.Windows
2025-03-02 21:42:25 -06:00
Evan Husted
da3f4e1d3a misc: Created generic type RyujinxControl to allow for more unified control view model definitions 2025-03-02 21:24:39 -06:00
Evan Husted
69d79322bb misc: chore: remove old title ID constructor for RendererHost 2025-03-02 21:23:36 -06:00
Evan Husted
c3af1dbf1a Stick Visualizer (#579)
![](https://i.imgur.com/iSaXRMr.png)

---------

Co-authored-by: MutantAura <domw0401@gmail.com>
2025-03-02 20:43:31 -06:00
Piplup
10ac381525 compat: Updates (#742)
These are branches i have on my private repo that i been meaning to push
Bluey The Videogame - compatibility/Bluey
Grand Theft Auto: III – The Definitive Edition -
compatibility/gta-definitiveedition
Grand Theft Auto: Vice City – The Definitive Edition -
compatibility/gta-definitiveedition
Grand Theft Auto: San Andreas – The Definitive Edition -
compatibility/gta-definitiveedition
SpongeBob SquarePants: The Cosmic Shake - compatibility/TheCosmicShake

p.s i didn't mess up one of the commit names i swear
2025-03-02 18:39:32 -06:00
Evan Husted
6c159372f5 Clarify that this branch should not really be used yet 2025-03-02 02:26:37 -06:00
Evan Husted
39ced98cb6 Check RuntimeFeature before trying to create MacroJit instead of baking that logic into GraphicsConfig.EnableMacroJit 2025-03-02 02:01:05 -06:00
Evan Husted
5a1476148f collection expressions 2025-03-02 00:50:35 -06:00
Evan Husted
d304779938 Revert "Use UnmanagedCallersOnly for delegates".
This reverts commit c8d598d5ac
2025-03-02 00:47:58 -06:00
Evan Husted
c3083076ee Allow reflection for NativeInterface + statically reference GetFunctionAddress so it gets compiled 2025-03-01 19:56:00 -06:00
Evan Husted
ccfcdd4219 feature: Native AOT
Based on emmauss' work.

Does not launch games yet. ARMeilleure code is missing from the build.
2025-03-01 19:04:03 -06:00
Evan Husted
64a283c4e6 fix aot build for GAL & VK 2025-03-01 18:45:21 -06:00
Evan Husted
2c15b1ccb6 infra: add aot build configs (by emmaus)
Remade manually because the original commit edited a solution thats very different from current.
2025-03-01 18:25:17 -06:00
Danik2343
e104ee6be3 Update: Russian Language (Some missing strings) (#732) 2025-02-27 16:53:18 -06:00
Nicola
e65d1ec6c9 JoyCon to Joy-Con (#729)
Joy-Con is the official name
2025-02-26 20:00:35 -06:00
Evan Husted
534f92506b misc: chore: Add warning logs for invalid ips patch attempts 2025-02-26 02:31:18 -06:00
Daniel Nylander
10d20c1ae3 Update Swedish locale (#720) 2025-02-26 02:02:07 -06:00
Evan Husted
e294a79975 UI: dev: [ci skip] Add Avalonia DevTools support to all Windows defined by Ryujinx, accessible via Ctrl + F12 when running in Debug. 2025-02-25 23:12:57 -06:00
Evan Husted
ec06a86899 UI: Increase default size for setting windows to include autoload setting & the bottom of the input settings 2025-02-25 22:51:26 -06:00
Vladimir Sokolov
2e4de17472 Custom configuration for each game (#632)
![image](https://github.com/user-attachments/assets/5dd139b4-2004-4c13-85d1-fc3378382adf)

![image](https://github.com/user-attachments/assets/9bcb8524-a403-428f-9f98-e8c03c75f079)

Now you can make a separate configuration (independent file) for each
game. All emulator settings are available except for some UI functionality ones. 
The configuration file can be changed and deleted from a separate menu. The
user configuration menu is available through the context menu on a given application.

---------

Co-authored-by: Evan Husted <greem@greemdev.net>
2025-02-25 21:11:20 -06:00
Piplup
9227cbe5a7 Dynamic RPC: Improve Pokemon Scarlet/Violet (#723)
Updated Pokemon Scarlet and Violet to use multi parser it now displays
if your in a team circle and area of the game

![image](https://github.com/user-attachments/assets/6d8d52c5-65a9-4ac3-af91-cb0c03576ad6)
2025-02-25 17:48:47 -06:00
Evan Husted
332bcdfaf1 UI: Updater: Add support for eventual Windows on ARM updates 2025-02-25 17:34:56 -06:00
FluffyOMC
1c8276197f SSBU DRPC - Stage Editing (#707)
Adds it so the Rich Presence now notices when the player edits a custom
stage!
2025-02-25 15:48:35 -06:00
LotP1
a3596ba858 Reset in-memory JIT cache on game quit + fix Purge PPTC (#709)
Jit cache now fully resets when booting a game multiple times.
This should fix random jit cache crashes.
Also removed some redundant code related to region allocation and fixed
PPTC Purge not fully purging all PPTC files in the backup folder.
2025-02-25 15:34:21 -06:00
Evan Husted
3ffcc72117 UI: Fix compatibility list crashing (missing font) 2025-02-22 23:48:47 -06:00
Evan Husted
fe1617ffea Revert the Metal Experiment (#701)
Metal sounded like a good idea to get in the emulator but frankly I
underestimated just how experimental and not ready it was.
From my write up in the Discord:
```
As is, Metal supports only a few games.
The games it does support freeze on first use of not playing them via Vulkan, because shader translation is broken.
So you need to use a dirty hack to not delete all your shaders.
Not to mention it breaks many games via MoltenVK because of changes to the shared GPU code.

Merging Metal seemed like a great idea, because of the few games it does support.
But I don't think it's worth it. Many of the games it breaks via MoltenVK *don't work via Metal*. 
Which effectively makes current Ryubing worse for Mac users than Ryujinx 1.1.1403.

I think what I'm gonna do is revert Metal, and reopen it as a PR. That way, you can still take advantage of the Metal backend as is, but without making other games worse with no solution.
```

For what it's worth, the shader translation part could at least be
"fixed" by always applying a 30ms delay for shader translation to Metal.
That being said, that solution sucks ass.
The MoltenVK regressions are even worse.



I hope this is not a let down to the Mac users. I hope you realize I'm
reverting this because you're actively getting a worse experience with
it in the emulator.
2025-02-22 21:26:46 -06:00
shinyoyo
eb6b0e9adc Updated Zh-CN Simplified Chinese. (#703) 2025-02-22 02:16:28 -06:00
Evan Husted
9631bdfe16 docs: compat: Hogwarts Legacy is an Unreal Engine 4 game 2025-02-20 20:56:52 -06:00
Evan Husted
2a84656ffc misc: chore: use new array in LdnGameDataReceivedEventArgs instead of collecting the ldn datas into a list 2025-02-20 19:49:17 -06:00
Evan Husted
6c6580ddcc misc: chore: Move the LDN constants into a SharedConstants class 2025-02-20 19:30:00 -06:00
Evan Husted
c47448628c UI: Print LED setting failed on Debug 2025-02-20 19:29:18 -06:00
Evan Husted
d0ac83b493 misc: chore: Prevent firmware installation prompt from showing up multiple times during runtime when using --install-firmware 2025-02-20 18:52:45 -06:00
285 changed files with 4094 additions and 16774 deletions

View File

@@ -46,7 +46,6 @@
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="Sep" Version="0.6.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpMetal" Version="1.0.0-preview21" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />

View File

@@ -1,3 +1,12 @@
# You have stumbled on a gimped version of Ryujinx.
This is the NativeAOT branch. It should run much faster than the normal version, however it's ruined by one thing: the Macro JIT.
This single part of Ryujinx, which handles common Maxwell GPU Macros by using .NET Reflection Emit, is entirely unusable via NativeAOT and it kills the performance.
I was getting 20FPS in BOTW with 98% FIFO usage.
This is compared to over 100FPS with about 70% FIFO usage in standard, managed C#, Ryujinx.
If there are any JIT wizards out there; I am calling to you. I believe getting this to work would be a game changer.
[This is the offending JIT implementation.](https://github.com/Ryubing/Ryujinx/blob/feature/native_aot/src/Ryujinx.Graphics.Gpu/Engine/MME/MacroJitCompiler.cs)
<table align="center">
<tr>
<td align="center" width="25%">
@@ -97,7 +106,7 @@ If you are planning to contribute or just want to learn more about this project
- **Input**
We currently have support for keyboard, mouse, touch input, JoyCon input support, and nearly all controllers.
We currently have support for keyboard, mouse, touch input, Joy-Con input support, and nearly all controllers.
Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required.
In all scenarios, you can set up everything inside the input configuration menu.

View File

@@ -77,15 +77,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Gene
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
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}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
@@ -95,170 +86,327 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.github\workflows\release.yml = .github\workflows\release.yml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
DebugAOT|Any CPU = DebugAOT|Any CPU
Release|Any CPU = Release|Any CPU
ReleaseAOT|Any CPU = ReleaseAOT|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.Build.0 = Release|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.Build.0 = Release|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.Build.0 = Release|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{ADA7EA87-0D63-4D97-9433-922A2124401F}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.Build.0 = Release|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.Build.0 = Release|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{9558FB96-075D-4219-8FFF-401979DC0B69}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.Build.0 = Release|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{E1B1AD28-289D-47B7-A106-326972240207}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.Build.0 = Release|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.Build.0 = Release|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.Build.0 = Debug|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.ActiveCfg = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.Build.0 = Release|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.Build.0 = Release|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.Build.0 = Release|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{D1CC5322-7325-4F6B-9625-194B30BE1296}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.Build.0 = Release|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.Build.0 = Release|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.Build.0 = Release|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.Build.0 = Release|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{B9AECA11-E248-4886-A10B-81B631CAAF29}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{81BB2C11-9408-4EA3-822E-42987AF54429}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.Build.0 = Release|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.Build.0 = Release|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.Build.0 = Release|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{716364DE-B988-41A6-BAB4-327964266ECC}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.Build.0 = Release|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{C16F112F-38C3-40BC-9F5F-4791112063D6}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.Build.0 = Release|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.Build.0 = Release|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.Build.0 = Release|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{77F96ECE-4952-42DB-A528-DED25572A573}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{AF34127A-3A92-43E5-8496-14960A50B1F1}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.DebugAOT|Any CPU.Build.0 = DebugAOT|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
{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
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.ReleaseAOT|Any CPU.Build.0 = ReleaseAOT|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}.DebugAOT|Any CPU.ActiveCfg = DebugAOT|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.DebugAOT|Any CPU.Build.0 = DebugAOT|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.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
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.ReleaseAOT|Any CPU.ActiveCfg = ReleaseAOT|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -631,6 +631,7 @@
010030D012FF6000,"Bus Driver Simulator",,playable,2022-10-17 13:55:27
0100A9101418C000,"BUSTAFELLOWS",nvdec,playable,2020-10-17 20:04:41
0100177005C8A000,"BUTCHER",,playable,2021-01-11 18:50:17
01008c2019598000,"Bluey: The Videogame",,playable,2025-02-11 04:38:00
01000B900D8B0000,"Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda",slow;nvdec,playable,2024-04-01 22:43:40
010065700EE06000,"Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda Demo",demo;gpu;nvdec,ingame,2021-02-14 21:48:15
01005C00117A8000,"Café Enchanté",,playable,2020-11-13 14:54:25
@@ -1382,6 +1383,9 @@
0100763015C2E000,"Gunvolt Chronicles: Luminous Avenger iX 2",crash;Needs Update,nothing,2022-04-29 15:34:34
01002C8018554000,"Gurimugurimoa OnceMore Demo",,playable,2022-07-29 22:07:31
0100AC601DCA8000,"GYLT",crash,ingame,2024-03-18 20:16:51
0100c3c012718000,"Grand Theft Auto: III The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
0100182014022000,"Grand Theft Auto: Vice City The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
010065a014024000,"Grand Theft Auto: San Andreas The Definitive Edition",gpu;UE4,ingame,2022-10-31 20:13:52
0100822012D76000,"HAAK",gpu,ingame,2023-02-19 14:31:05
01007E100EFA8000,"Habroxia",,playable,2020-06-16 23:04:42
0100535012974000,"Hades",vulkan,playable,2022-10-05 10:45:21
@@ -1436,7 +1440,7 @@
010083A018262000,"Hitman: Blood Money — Reprisal",deadlock,ingame,2024-09-28 16:28:50
01004B100A5CC000,"Hob: The Definitive Edition",,playable,2021-01-13 09:39:19
0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35
0100F7E00C70E000,"Hogwarts Legacy",slow,ingame,2024-09-03 19:53:58
0100F7E00C70E000,"Hogwarts Legacy",UE4;slow,ingame,2024-09-03 19:53:58
0100633007D48000,"Hollow Knight",nvdec,playable,2023-01-16 15:44:56
0100F2100061E800,"Hollow0",UE4;gpu,ingame,2021-03-03 23:42:56
0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56
@@ -2729,7 +2733,7 @@
0100C2500FC20000,"Splatoon™ 3",ldn-works;opengl-backend-bug;LAN;amd-vendor-bug,playable,2024-08-04 23:49:11
0100BA0018500000,"Splatoon™ 3: Splatfest World Premiere",gpu;online-broken;demo,ingame,2022-09-19 03:17:12
010062800D39C000,"SpongeBob SquarePants: Battle for Bikini Bottom - Rehydrated",online-broken;UE4;ldn-broken;vulkan-backend-bug,playable,2023-08-01 19:29:34
01009FB0172F4000,"SpongeBob SquarePants: The Cosmic Shake",gpu;UE4,ingame,2023-08-01 19:29:53
01009FB0172F4000,"SpongeBob SquarePants: The Cosmic Shake",gpu;UE4,ingame,2024-03-04 16:35:00
010097C01336A000,"Spooky Chase",,playable,2022-11-04 12:17:44
0100C6100D75E000,"Spooky Ghosts Dot Com",,playable,2021-06-15 15:16:11
0100DE9005170000,"Sports Party",nvdec,playable,2021-03-05 13:40:42
1 title_id game_name labels status last_updated
631 010030D012FF6000 Bus Driver Simulator playable 2022-10-17 13:55:27
632 0100A9101418C000 BUSTAFELLOWS nvdec playable 2020-10-17 20:04:41
633 0100177005C8A000 BUTCHER playable 2021-01-11 18:50:17
634 01008c2019598000 Bluey: The Videogame playable 2025-02-11 04:38:00
635 01000B900D8B0000 Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda slow;nvdec playable 2024-04-01 22:43:40
636 010065700EE06000 Cadence of Hyrule: Crypt of the NecroDancer Featuring The Legend of Zelda Demo demo;gpu;nvdec ingame 2021-02-14 21:48:15
637 01005C00117A8000 Café Enchanté playable 2020-11-13 14:54:25
1383 0100763015C2E000 Gunvolt Chronicles: Luminous Avenger iX 2 crash;Needs Update nothing 2022-04-29 15:34:34
1384 01002C8018554000 Gurimugurimoa OnceMore Demo playable 2022-07-29 22:07:31
1385 0100AC601DCA8000 GYLT crash ingame 2024-03-18 20:16:51
1386 0100c3c012718000 Grand Theft Auto: III – The Definitive Edition gpu;UE4 ingame 2022-10-31 20:13:52
1387 0100182014022000 Grand Theft Auto: Vice City – The Definitive Edition gpu;UE4 ingame 2022-10-31 20:13:52
1388 010065a014024000 Grand Theft Auto: San Andreas – The Definitive Edition gpu;UE4 ingame 2022-10-31 20:13:52
1389 0100822012D76000 HAAK gpu ingame 2023-02-19 14:31:05
1390 01007E100EFA8000 Habroxia playable 2020-06-16 23:04:42
1391 0100535012974000 Hades vulkan playable 2022-10-05 10:45:21
1440 010083A018262000 Hitman: Blood Money — Reprisal deadlock ingame 2024-09-28 16:28:50
1441 01004B100A5CC000 Hob: The Definitive Edition playable 2021-01-13 09:39:19
1442 0100F7300ED2C000 Hoggy2 playable 2022-10-10 13:53:35
1443 0100F7E00C70E000 Hogwarts Legacy slow UE4;slow ingame 2024-09-03 19:53:58
1444 0100633007D48000 Hollow Knight nvdec playable 2023-01-16 15:44:56
1445 0100F2100061E800 Hollow0 UE4;gpu ingame 2021-03-03 23:42:56
1446 0100342009E16000 Holy Potatoes! What The Hell?! playable 2020-07-03 10:48:56
2733 0100C2500FC20000 Splatoon™ 3 ldn-works;opengl-backend-bug;LAN;amd-vendor-bug playable 2024-08-04 23:49:11
2734 0100BA0018500000 Splatoon™ 3: Splatfest World Premiere gpu;online-broken;demo ingame 2022-09-19 03:17:12
2735 010062800D39C000 SpongeBob SquarePants: Battle for Bikini Bottom - Rehydrated online-broken;UE4;ldn-broken;vulkan-backend-bug playable 2023-08-01 19:29:34
2736 01009FB0172F4000 SpongeBob SquarePants: The Cosmic Shake gpu;UE4 ingame 2023-08-01 19:29:53 2024-03-04 16:35:00
2737 010097C01336A000 Spooky Chase playable 2022-11-04 12:17:44
2738 0100C6100D75E000 Spooky Ghosts Dot Com playable 2021-06-15 15:16:11
2739 0100DE9005170000 Sports Party nvdec playable 2021-03-05 13:40:42

View File

@@ -3,6 +3,7 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -7,15 +7,17 @@ namespace ARMeilleure.Instructions
{
static partial class InstEmit
{
private const string SupervisorCallName = nameof(NativeInterface.SupervisorCall);
private const string BreakName = nameof(NativeInterface.Break);
private const string UndefinedName = nameof(NativeInterface.Undefined);
public static void Brk(ArmEmitterContext context)
{
OpCodeException op = (OpCodeException)context.CurrOp;
string name = nameof(NativeInterface.Break);
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
context.Call(NativeInterface.Type.GetMethod(BreakName), Const(op.Address), Const(op.Id));
context.LoadFromContext();
@@ -25,12 +27,10 @@ namespace ARMeilleure.Instructions
public static void Svc(ArmEmitterContext context)
{
OpCodeException op = (OpCodeException)context.CurrOp;
string name = nameof(NativeInterface.SupervisorCall);
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
context.Call(NativeInterface.Type.GetMethod(SupervisorCallName), Const(op.Address), Const(op.Id));
context.LoadFromContext();
@@ -41,11 +41,9 @@ namespace ARMeilleure.Instructions
{
OpCode op = context.CurrOp;
string name = nameof(NativeInterface.Undefined);
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.RawOpCode));
context.Call(NativeInterface.Type.GetMethod(UndefinedName), Const(op.Address), Const(op.RawOpCode));
context.LoadFromContext();

View File

@@ -14,7 +14,7 @@ namespace ARMeilleure.Instructions
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.Call(NativeInterface.Type.GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.LoadFromContext();
@@ -29,7 +29,7 @@ namespace ARMeilleure.Instructions
context.StoreToContext();
context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.Call(NativeInterface.Type.GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
context.LoadFromContext();

View File

@@ -478,7 +478,7 @@ namespace ARMeilleure.Instructions
context.BranchIf(lblNotWatched, pte, Const(0L), Comparison.GreaterOrEqual, BasicBlockFrequency.Cold);
// Signal memory tracking. Size here doesn't matter as address is assumed to be size aligned here.
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)), address, Const(1UL), Const(write ? 1 : 0));
context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.SignalMemoryTracking)), address, Const(1UL), Const(write ? 1 : 0));
context.MarkLabel(lblNotWatched);
pte = context.BitwiseAnd(pte, Const(0xffffffffffffUL)); // Ignore any software protection bits. (they are still used by C# memory access)
@@ -489,7 +489,7 @@ namespace ARMeilleure.Instructions
context.BranchIfTrue(lblNonNull, pte, BasicBlockFrequency.Cold);
// The call is not expected to return (it should throw).
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);
context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);
context.MarkLabel(lblNonNull);
}
@@ -535,16 +535,16 @@ namespace ARMeilleure.Instructions
switch (size)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadByte));
break;
case 1:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt16));
break;
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt32));
break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt64));
break;
}
@@ -564,19 +564,19 @@ namespace ARMeilleure.Instructions
switch (size)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadByte));
break;
case 1:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt16));
break;
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt32));
break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadUInt64));
break;
case 4:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.ReadVector128));
break;
}
@@ -608,16 +608,16 @@ namespace ARMeilleure.Instructions
switch (size)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteByte));
break;
case 1:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt16));
break;
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt32));
break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt64));
break;
}
@@ -643,19 +643,19 @@ namespace ARMeilleure.Instructions
switch (size)
{
case 0:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteByte));
break;
case 1:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt16));
break;
case 2:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt32));
break;
case 3:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteUInt64));
break;
case 4:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.WriteVector128));
break;
}

View File

@@ -406,7 +406,7 @@ namespace ARMeilleure.Instructions
{
Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2);
return EmitUnaryMathCall(context, nameof(MathHelper.Abs), res);
return EmitUnaryMathCall(context, nameof(Math.Abs), res);
});
}
}
@@ -451,7 +451,7 @@ namespace ARMeilleure.Instructions
{
Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2);
return EmitUnaryMathCall(context, nameof(MathHelper.Abs), res);
return EmitUnaryMathCall(context, nameof(Math.Abs), res);
});
}
}
@@ -483,7 +483,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
return EmitUnaryMathCall(context, nameof(MathHelper.Abs), op1);
return EmitUnaryMathCall(context, nameof(Math.Abs), op1);
});
}
}
@@ -522,7 +522,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
return EmitUnaryMathCall(context, nameof(MathHelper.Abs), op1);
return EmitUnaryMathCall(context, nameof(Math.Abs), op1);
});
}
}
@@ -2246,7 +2246,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
return EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1);
return EmitUnaryMathCall(context, nameof(Math.Floor), op1);
});
}
}
@@ -2265,7 +2265,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
return EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1);
return EmitUnaryMathCall(context, nameof(Math.Floor), op1);
});
}
}
@@ -2322,7 +2322,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
return EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op1);
return EmitUnaryMathCall(context, nameof(Math.Ceiling), op1);
});
}
}
@@ -2341,7 +2341,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
return EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op1);
return EmitUnaryMathCall(context, nameof(Math.Ceiling), op1);
});
}
}
@@ -2390,7 +2390,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
return EmitUnaryMathCall(context, nameof(MathHelper.Truncate), op1);
return EmitUnaryMathCall(context, nameof(Math.Truncate), op1);
});
}
}
@@ -2409,7 +2409,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
return EmitUnaryMathCall(context, nameof(MathHelper.Truncate), op1);
return EmitUnaryMathCall(context, nameof(Math.Truncate), op1);
});
}
}

View File

@@ -43,7 +43,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Abs), op1));
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Abs), op1));
}
}
@@ -66,7 +66,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitVectorUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Abs), op1));
EmitVectorUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Abs), op1));
}
}
else

View File

@@ -726,8 +726,8 @@ namespace ARMeilleure.Instructions
if (absolute)
{
ne = EmitUnaryMathCall(context, nameof(MathHelper.Abs), ne);
me = EmitUnaryMathCall(context, nameof(MathHelper.Abs), me);
ne = EmitUnaryMathCall(context, nameof(Math.Abs), ne);
me = EmitUnaryMathCall(context, nameof(Math.Abs), me);
}
Operand e = EmitSoftFloatCall(context, name, ne, me);

View File

@@ -333,7 +333,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1));
EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1));
}
}
@@ -349,7 +349,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitFcvt(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1), signed: true, scalar: false);
EmitFcvt(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1), signed: true, scalar: false);
}
}
@@ -365,7 +365,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Floor), op1));
EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1));
}
}
@@ -538,7 +538,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op1));
EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Ceiling), op1));
}
}
@@ -554,7 +554,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op1));
EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Ceiling), op1));
}
}

View File

@@ -357,10 +357,10 @@ namespace ARMeilleure.Instructions
toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert);
break;
case 0b10: // Towards positive infinity
toConvert = EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), toConvert);
toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert);
break;
case 0b11: // Towards negative infinity
toConvert = EmitUnaryMathCall(context, nameof(MathHelper.Floor), toConvert);
toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert);
break;
}
@@ -494,10 +494,10 @@ namespace ARMeilleure.Instructions
toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert);
break;
case 0b10: // Towards positive infinity
toConvert = EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), toConvert);
toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert);
break;
case 0b11: // Towards negative infinity
toConvert = EmitUnaryMathCall(context, nameof(MathHelper.Floor), toConvert);
toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert);
break;
}
@@ -534,7 +534,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(MathHelper.Floor), m));
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Floor), m));
}
}
@@ -574,7 +574,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), m));
EmitVectorUnaryOpF32(context, (m) => EmitUnaryMathCall(context, nameof(Math.Ceiling), m));
}
}
@@ -613,7 +613,7 @@ namespace ARMeilleure.Instructions
}
else
{
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(MathHelper.Truncate), op1));
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Truncate), op1));
}
}

View File

@@ -460,8 +460,8 @@ namespace ARMeilleure.Instructions
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
MethodInfo info = (op.Size & 1) == 0
? typeof(MathHelperF).GetMethod(name, [typeof(float)])
: typeof(MathHelper).GetMethod(name, [typeof(double)]);
? typeof(MathF).GetMethod(name, [typeof(float)])
: typeof(Math).GetMethod(name, [typeof(double)]);
return context.Call(info, n);
}
@@ -470,11 +470,11 @@ namespace ARMeilleure.Instructions
{
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
string name = nameof(MathHelper.Round);
string name = nameof(Math.Round);
MethodInfo info = (op.Size & 1) == 0
? typeof(MathHelperF).GetMethod(name, [typeof(float), typeof(int)])
: typeof(MathHelper).GetMethod(name, [typeof(double), typeof(int)]);
? typeof(MathF).GetMethod(name, [typeof(float), typeof(MidpointRounding)])
: typeof(Math).GetMethod(name, [typeof(double), typeof(MidpointRounding)]);
return context.Call(info, n, Const((int)roundMode));
}
@@ -510,16 +510,16 @@ namespace ARMeilleure.Instructions
context.MarkLabel(lbl1);
context.BranchIf(lbl2, rMode, rP, Comparison.NotEqual);
context.Copy(res, EmitUnaryMathCall(context, nameof(MathHelper.Ceiling), op));
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Ceiling), op));
context.Branch(lblEnd);
context.MarkLabel(lbl2);
context.BranchIf(lbl3, rMode, rM, Comparison.NotEqual);
context.Copy(res, EmitUnaryMathCall(context, nameof(MathHelper.Floor), op));
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Floor), op));
context.Branch(lblEnd);
context.MarkLabel(lbl3);
context.Copy(res, EmitUnaryMathCall(context, nameof(MathHelper.Truncate), op));
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Truncate), op));
context.Branch(lblEnd);
context.MarkLabel(lblEnd);

View File

@@ -29,10 +29,10 @@ namespace ARMeilleure.Instructions
switch (GetPackedId(op))
{
case 0b11_011_0000_0000_001:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCtrEl0));
break;
case 0b11_011_0000_0000_111:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetDczidEl0));
break;
case 0b11_011_0100_0010_000:
EmitGetNzcv(context);
@@ -53,13 +53,13 @@ namespace ARMeilleure.Instructions
EmitGetTpidr2El0(context);
return;
case 0b11_011_1110_0000_000:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntfrqEl0));
break;
case 0b11_011_1110_0000_001:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntpctEl0));
break;
case 0b11_011_1110_0000_010:
info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0));
info = NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntvctEl0));
break;
default:
@@ -131,7 +131,7 @@ namespace ARMeilleure.Instructions
case 0b11_011_0111_0101_001: // IC IVAU
Operand target = Register(op.Rt, RegisterType.Integer, OperandType.I64);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
break;
}
}

View File

@@ -127,7 +127,7 @@ namespace ARMeilleure.Instructions
// Timer.
14 => opc switch
{
0 => typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)),
0 => NativeInterface.Type.GetMethod(nameof(NativeInterface.GetCntpctEl0)),
_ => throw new NotImplementedException($"Unknown MRRC Opc1 0x{opc:X} at 0x{op.Address:X} (0x{op.RawOpCode:X})."),
},
_ => throw new NotImplementedException($"Unknown MRRC 0x{op.RawOpCode:X} at 0x{op.Address:X}."),

View File

@@ -1,71 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class MathHelper
{
[UnmanagedCallersOnly]
public static double Abs(double value)
{
return Math.Abs(value);
}
[UnmanagedCallersOnly]
public static double Ceiling(double value)
{
return Math.Ceiling(value);
}
[UnmanagedCallersOnly]
public static double Floor(double value)
{
return Math.Floor(value);
}
[UnmanagedCallersOnly]
public static double Round(double value, int mode)
{
return Math.Round(value, (MidpointRounding)mode);
}
[UnmanagedCallersOnly]
public static double Truncate(double value)
{
return Math.Truncate(value);
}
}
static class MathHelperF
{
[UnmanagedCallersOnly]
public static float Abs(float value)
{
return MathF.Abs(value);
}
[UnmanagedCallersOnly]
public static float Ceiling(float value)
{
return MathF.Ceiling(value);
}
[UnmanagedCallersOnly]
public static float Floor(float value)
{
return MathF.Floor(value);
}
[UnmanagedCallersOnly]
public static float Round(float value, int mode)
{
return MathF.Round(value, (MidpointRounding)mode);
}
[UnmanagedCallersOnly]
public static float Truncate(float value)
{
return MathF.Truncate(value);
}
}
}

View File

@@ -2,12 +2,15 @@ using ARMeilleure.Memory;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
namespace ARMeilleure.Instructions
{
static class NativeInterface
{
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public static readonly Type Type = typeof(NativeInterface);
private class ThreadContext
{
public ExecutionContext Context { get; }
@@ -35,7 +38,6 @@ namespace ARMeilleure.Instructions
Context = null;
}
[UnmanagedCallersOnly]
public static void Break(ulong address, int imm)
{
Statistics.PauseTimer();
@@ -45,7 +47,6 @@ namespace ARMeilleure.Instructions
Statistics.ResumeTimer();
}
[UnmanagedCallersOnly]
public static void SupervisorCall(ulong address, int imm)
{
Statistics.PauseTimer();
@@ -55,7 +56,6 @@ namespace ARMeilleure.Instructions
Statistics.ResumeTimer();
}
[UnmanagedCallersOnly]
public static void Undefined(ulong address, int opCode)
{
Statistics.PauseTimer();
@@ -66,31 +66,26 @@ namespace ARMeilleure.Instructions
}
#region "System registers"
[UnmanagedCallersOnly]
public static ulong GetCtrEl0()
{
return GetContext().CtrEl0;
}
[UnmanagedCallersOnly]
public static ulong GetDczidEl0()
{
return GetContext().DczidEl0;
}
[UnmanagedCallersOnly]
public static ulong GetCntfrqEl0()
{
return GetContext().CntfrqEl0;
}
[UnmanagedCallersOnly]
public static ulong GetCntpctEl0()
{
return GetContext().CntpctEl0;
}
[UnmanagedCallersOnly]
public static ulong GetCntvctEl0()
{
return GetContext().CntvctEl0;
@@ -98,31 +93,26 @@ namespace ARMeilleure.Instructions
#endregion
#region "Read"
[UnmanagedCallersOnly]
public static byte ReadByte(ulong address)
{
return GetMemoryManager().ReadGuest<byte>(address);
}
[UnmanagedCallersOnly]
public static ushort ReadUInt16(ulong address)
{
return GetMemoryManager().ReadGuest<ushort>(address);
}
[UnmanagedCallersOnly]
public static uint ReadUInt32(ulong address)
{
return GetMemoryManager().ReadGuest<uint>(address);
}
[UnmanagedCallersOnly]
public static ulong ReadUInt64(ulong address)
{
return GetMemoryManager().ReadGuest<ulong>(address);
}
[UnmanagedCallersOnly]
public static V128 ReadVector128(ulong address)
{
return GetMemoryManager().ReadGuest<V128>(address);
@@ -130,56 +120,47 @@ namespace ARMeilleure.Instructions
#endregion
#region "Write"
[UnmanagedCallersOnly]
public static void WriteByte(ulong address, byte value)
{
GetMemoryManager().WriteGuest(address, value);
}
[UnmanagedCallersOnly]
public static void WriteUInt16(ulong address, ushort value)
{
GetMemoryManager().WriteGuest(address, value);
}
[UnmanagedCallersOnly]
public static void WriteUInt32(ulong address, uint value)
{
GetMemoryManager().WriteGuest(address, value);
}
[UnmanagedCallersOnly]
public static void WriteUInt64(ulong address, ulong value)
{
GetMemoryManager().WriteGuest(address, value);
}
[UnmanagedCallersOnly]
public static void WriteVector128(ulong address, V128 value)
{
GetMemoryManager().WriteGuest(address, value);
}
#endregion
[UnmanagedCallersOnly]
public static void EnqueueForRejit(ulong address)
{
Context.Translator.EnqueueForRejit(address, GetContext().ExecutionMode);
}
[UnmanagedCallersOnly]
public static void SignalMemoryTracking(ulong address, ulong size, byte write)
public static void SignalMemoryTracking(ulong address, ulong size, bool write)
{
GetMemoryManager().SignalMemoryTracking(address, size, write == 1);
GetMemoryManager().SignalMemoryTracking(address, size, write);
}
[UnmanagedCallersOnly]
public static void ThrowInvalidMemoryAccess(ulong address)
{
throw new InvalidAccessException(address);
}
[UnmanagedCallersOnly]
public static ulong GetFunctionAddress(ulong address)
{
TranslatedFunction function = Context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
@@ -187,14 +168,12 @@ namespace ARMeilleure.Instructions
return (ulong)function.FuncPointer.ToInt64();
}
[UnmanagedCallersOnly]
public static void InvalidateCacheLine(ulong address)
{
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
}
[UnmanagedCallersOnly]
public static byte CheckSynchronization()
public static bool CheckSynchronization()
{
Statistics.PauseTimer();
@@ -204,7 +183,7 @@ namespace ARMeilleure.Instructions
Statistics.ResumeTimer();
return (byte)(context.Running ? 1 : 0);
return context.Running;
}
public static ExecutionContext GetContext()

View File

@@ -1,13 +1,11 @@
using ARMeilleure.State;
using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
static class SoftFallback
{
#region "ShrImm64"
[UnmanagedCallersOnly]
public static long SignedShrImm64(long value, long roundConst, int shift)
{
if (roundConst == 0L)
@@ -50,7 +48,6 @@ namespace ARMeilleure.Instructions
}
}
[UnmanagedCallersOnly]
public static ulong UnsignedShrImm64(ulong value, long roundConst, int shift)
{
if (roundConst == 0L)
@@ -95,7 +92,6 @@ namespace ARMeilleure.Instructions
#endregion
#region "Saturation"
[UnmanagedCallersOnly]
public static int SatF32ToS32(float value)
{
if (float.IsNaN(value))
@@ -107,7 +103,6 @@ namespace ARMeilleure.Instructions
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF32ToS64(float value)
{
if (float.IsNaN(value))
@@ -119,7 +114,6 @@ namespace ARMeilleure.Instructions
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF32ToU32(float value)
{
if (float.IsNaN(value))
@@ -131,7 +125,6 @@ namespace ARMeilleure.Instructions
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF32ToU64(float value)
{
if (float.IsNaN(value))
@@ -143,7 +136,6 @@ namespace ARMeilleure.Instructions
value <= ulong.MinValue ? ulong.MinValue : (ulong)value;
}
[UnmanagedCallersOnly]
public static int SatF64ToS32(double value)
{
if (double.IsNaN(value))
@@ -155,7 +147,6 @@ namespace ARMeilleure.Instructions
value <= int.MinValue ? int.MinValue : (int)value;
}
[UnmanagedCallersOnly]
public static long SatF64ToS64(double value)
{
if (double.IsNaN(value))
@@ -167,7 +158,6 @@ namespace ARMeilleure.Instructions
value <= long.MinValue ? long.MinValue : (long)value;
}
[UnmanagedCallersOnly]
public static uint SatF64ToU32(double value)
{
if (double.IsNaN(value))
@@ -179,7 +169,6 @@ namespace ARMeilleure.Instructions
value <= uint.MinValue ? uint.MinValue : (uint)value;
}
[UnmanagedCallersOnly]
public static ulong SatF64ToU64(double value)
{
if (double.IsNaN(value))
@@ -193,7 +182,6 @@ namespace ARMeilleure.Instructions
#endregion
#region "Count"
[UnmanagedCallersOnly]
public static ulong CountLeadingSigns(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
value ^= value >> 1;
@@ -213,7 +201,6 @@ namespace ARMeilleure.Instructions
private static ReadOnlySpan<byte> ClzNibbleTbl => [4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
[UnmanagedCallersOnly]
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
{
if (value == 0ul)
@@ -237,49 +224,41 @@ namespace ARMeilleure.Instructions
#endregion
#region "Table"
[UnmanagedCallersOnly]
public static V128 Tbl1(V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(default, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbl2(V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(default, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(default, vector, bytes, tb0, tb1, tb2, tb3);
}
[UnmanagedCallersOnly]
public static V128 Tbx1(V128 dest, V128 vector, int bytes, V128 tb0)
{
return TblOrTbx(dest, vector, bytes, tb0);
}
[UnmanagedCallersOnly]
public static V128 Tbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1);
}
[UnmanagedCallersOnly]
public static V128 Tbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2);
}
[UnmanagedCallersOnly]
public static V128 Tbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3)
{
return TblOrTbx(dest, vector, bytes, tb0, tb1, tb2, tb3);
@@ -321,22 +300,14 @@ namespace ARMeilleure.Instructions
private const uint Crc32RevPoly = 0xedb88320;
private const uint Crc32cRevPoly = 0x82f63b78;
[UnmanagedCallersOnly]
public static uint Crc32b(uint crc, byte value) => Crc32(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32h(uint crc, ushort value) => Crc32h(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32w(uint crc, uint value) => Crc32w(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32x(uint crc, ulong value) => Crc32x(crc, Crc32RevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cb(uint crc, byte value) => Crc32(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32ch(uint crc, ushort value) => Crc32h(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cw(uint crc, uint value) => Crc32w(crc, Crc32cRevPoly, value);
[UnmanagedCallersOnly]
public static uint Crc32cx(uint crc, ulong value) => Crc32x(crc, Crc32cRevPoly, value);
private static uint Crc32h(uint crc, uint poly, ushort val)
@@ -387,25 +358,21 @@ namespace ARMeilleure.Instructions
#endregion
#region "Aes"
[UnmanagedCallersOnly]
public static V128 Decrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesInvSubBytes(CryptoHelper.AesInvShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 Encrypt(V128 value, V128 roundKey)
{
return CryptoHelper.AesSubBytes(CryptoHelper.AesShiftRows(value ^ roundKey));
}
[UnmanagedCallersOnly]
public static V128 InverseMixColumns(V128 value)
{
return CryptoHelper.AesInvMixColumns(value);
}
[UnmanagedCallersOnly]
public static V128 MixColumns(V128 value)
{
return CryptoHelper.AesMixColumns(value);
@@ -413,7 +380,6 @@ namespace ARMeilleure.Instructions
#endregion
#region "Sha1"
[UnmanagedCallersOnly]
public static V128 HashChoose(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
@@ -434,13 +400,11 @@ namespace ARMeilleure.Instructions
return hash_abcd;
}
[UnmanagedCallersOnly]
public static uint FixedRotate(uint hash_e)
{
return hash_e.Rol(30);
}
[UnmanagedCallersOnly]
public static V128 HashMajority(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
@@ -461,7 +425,6 @@ namespace ARMeilleure.Instructions
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 HashParity(V128 hash_abcd, uint hash_e, V128 wk)
{
for (int e = 0; e <= 3; e++)
@@ -482,7 +445,6 @@ namespace ARMeilleure.Instructions
return hash_abcd;
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11)
{
ulong t2 = w4_7.Extract<ulong>(0);
@@ -493,7 +455,6 @@ namespace ARMeilleure.Instructions
return result ^ (w0_3 ^ w8_11);
}
[UnmanagedCallersOnly]
public static V128 Sha1SchedulePart2(V128 tw0_3, V128 w12_15)
{
V128 t = tw0_3 ^ (w12_15 >> 32);
@@ -538,19 +499,16 @@ namespace ARMeilleure.Instructions
#endregion
#region "Sha256"
[UnmanagedCallersOnly]
public static V128 HashLower(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
}
[UnmanagedCallersOnly]
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
{
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart1(V128 w0_3, V128 w4_7)
{
V128 result = new();
@@ -569,7 +527,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static V128 Sha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15)
{
V128 result = new();
@@ -671,7 +628,6 @@ namespace ARMeilleure.Instructions
}
#endregion
[UnmanagedCallersOnly]
public static V128 PolynomialMult64_128(ulong op1, ulong op2)
{
V128 result = V128.Zero;

View File

@@ -1,7 +1,6 @@
using ARMeilleure.State;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ARMeilleure.Instructions
{
@@ -313,7 +312,6 @@ namespace ARMeilleure.Instructions
static class SoftFloat16_32
{
[UnmanagedCallersOnly]
public static float FPConvert(ushort valueBits)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -489,7 +487,6 @@ namespace ARMeilleure.Instructions
static class SoftFloat16_64
{
[UnmanagedCallersOnly]
public static double FPConvert(ushort valueBits)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -665,7 +662,6 @@ namespace ARMeilleure.Instructions
static class SoftFloat32_16
{
[UnmanagedCallersOnly]
public static ushort FPConvert(float value)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -785,19 +781,12 @@ namespace ARMeilleure.Instructions
static class SoftFloat32
{
[UnmanagedCallersOnly]
public static float FPAdd(float value1, float value2)
{
return FPAddFpscrImpl(value1, value2, false);
return FPAddFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static float FPAddFpscr(float value1, float value2, byte standardFpscr)
{
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
}
private static float FPAddFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPAddFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -848,8 +837,7 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static int FPCompare(float value1, float value2, byte signalNaNs)
public static int FPCompare(float value1, float value2, bool signalNaNs)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = context.Fpcr;
@@ -863,7 +851,7 @@ namespace ARMeilleure.Instructions
{
result = 0b0011;
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs == 1)
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
}
@@ -887,13 +875,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPCompareEQ(float value1, float value2)
{
return FPCompareEQFpscrImpl(value1, value2, false);
return FPCompareEQFpscr(value1, value2, false);
}
private static float FPCompareEQFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPCompareEQFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -920,25 +907,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPCompareEQFpscr(float value1, float value2, byte standardFpscr)
{
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
}
[UnmanagedCallersOnly]
public static float FPCompareGE(float value1, float value2)
{
return FPCompareGEFpscrImpl(value1, value2, false);
return FPCompareGEFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static float FPCompareGEFpscr(float value1, float value2, byte standardFpscr)
{
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
}
private static float FPCompareGEFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPCompareGEFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -962,19 +936,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPCompareGT(float value1, float value2)
{
return FPCompareGTFpscrImpl(value1, value2, false);
return FPCompareGTFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static float FPCompareGTFpscr(float value1, float value2, byte standardFpscr)
{
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
}
private static float FPCompareGTFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPCompareGTFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -998,31 +965,26 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPCompareLE(float value1, float value2)
{
return FPCompareGEFpscrImpl(value2, value1, false);
return FPCompareGE(value2, value1);
}
[UnmanagedCallersOnly]
public static float FPCompareLT(float value1, float value2)
{
return FPCompareGTFpscrImpl(value2, value1, false);
return FPCompareGT(value2, value1);
}
[UnmanagedCallersOnly]
public static float FPCompareLEFpscr(float value1, float value2, byte standardFpscr)
public static float FPCompareLEFpscr(float value1, float value2, bool standardFpscr)
{
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
return FPCompareGEFpscr(value2, value1, standardFpscr);
}
[UnmanagedCallersOnly]
public static float FPCompareLTFpscr(float value1, float value2, byte standardFpscr)
public static float FPCompareLTFpscr(float value1, float value2, bool standardFpscr)
{
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
return FPCompareGTFpscr(value2, value1, standardFpscr);
}
[UnmanagedCallersOnly]
public static float FPDiv(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -1075,19 +1037,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPMax(float value1, float value2)
{
return FPMaxFpscrImpl(value1, value2, false);
return FPMaxFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static float FPMaxFpscr(float value1, float value2, byte standardFpscr)
{
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
}
private static float FPMaxFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPMaxFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -1148,13 +1103,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPMaxNum(float value1, float value2)
{
return FPMaxNumFpscrImpl(value1, value2, false);
return FPMaxNumFpscr(value1, value2, false);
}
private static float FPMaxNumFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPMaxNumFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -1171,28 +1125,15 @@ namespace ARMeilleure.Instructions
value2 = FPInfinity(true);
}
return FPMaxFpscrImpl(value1, value2, standardFpscr);
return FPMaxFpscr(value1, value2, standardFpscr);
}
[UnmanagedCallersOnly]
public static float FPMaxNumFpscr(float value1, float value2, byte standardFpscr)
{
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
}
[UnmanagedCallersOnly]
public static float FPMin(float value1, float value2)
{
return FPMinFpscrImpl(value1, value2, false);
return FPMinFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static float FPMinFpscr(float value1, float value2, byte standardFpscr)
{
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
}
private static float FPMinFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPMinFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -1253,19 +1194,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPMinNum(float value1, float value2)
{
return FPMinNumFpscrImpl(value1, value2, false);
return FPMinNumFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static float FPMinNumFpscr(float value1, float value2, byte standardFpscr)
{
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
}
private static float FPMinNumFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPMinNumFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -1282,22 +1216,15 @@ namespace ARMeilleure.Instructions
value2 = FPInfinity(false);
}
return FPMinFpscrImpl(value1, value2, standardFpscr);
return FPMinFpscr(value1, value2, standardFpscr);
}
[UnmanagedCallersOnly]
public static float FPMul(float value1, float value2)
{
return FPMulFpscrImpl(value1, value2, false);
return FPMulFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static float FPMulFpscr(float value1, float value2, byte standardFpscr)
{
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
}
private static float FPMulFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPMulFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -1344,19 +1271,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPMulAdd(float valueA, float value1, float value2)
{
return FPMulAddFpscrImpl(valueA, value1, value2, false);
return FPMulAddFpscr(valueA, value1, value2, false);
}
[UnmanagedCallersOnly]
public static float FPMulAddFpscr(float valueA, float value1, float value2, byte standardFpscr)
{
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
}
private static float FPMulAddFpscrImpl(float valueA, float value1, float value2, bool standardFpscr)
public static float FPMulAddFpscr(float valueA, float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -1422,23 +1342,20 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPMulSub(float valueA, float value1, float value2)
{
value1 = value1.FPNeg();
return FPMulAddFpscrImpl(valueA, value1, value2, false);
return FPMulAdd(valueA, value1, value2);
}
[UnmanagedCallersOnly]
public static float FPMulSubFpscr(float valueA, float value1, float value2, byte standardFpscr)
public static float FPMulSubFpscr(float valueA, float value1, float value2, bool standardFpscr)
{
value1 = value1.FPNeg();
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
return FPMulAddFpscr(valueA, value1, value2, standardFpscr);
}
[UnmanagedCallersOnly]
public static float FPMulX(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -1484,36 +1401,27 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPNegMulAdd(float valueA, float value1, float value2)
{
valueA = valueA.FPNeg();
value1 = value1.FPNeg();
return FPMulAddFpscrImpl(valueA, value1, value2, false);
return FPMulAdd(valueA, value1, value2);
}
[UnmanagedCallersOnly]
public static float FPNegMulSub(float valueA, float value1, float value2)
{
valueA = valueA.FPNeg();
return FPMulAddFpscrImpl(valueA, value1, value2, false);
return FPMulAdd(valueA, value1, value2);
}
[UnmanagedCallersOnly]
public static float FPRecipEstimate(float value)
{
return FPRecipEstimateFpscrImpl(value, false);
return FPRecipEstimateFpscr(value, false);
}
[UnmanagedCallersOnly]
public static float FPRecipEstimateFpscr(float value, byte standardFpscr)
{
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
}
private static float FPRecipEstimateFpscrImpl(float value, bool standardFpscr)
public static float FPRecipEstimateFpscr(float value, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -1600,7 +1508,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPRecipStep(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -1626,16 +1533,15 @@ namespace ARMeilleure.Instructions
}
else
{
product = FPMulFpscrImpl(value1, value2, true);
product = FPMulFpscr(value1, value2, true);
}
result = FPSubFpscrImpl(FPTwo(false), product, true);
result = FPSubFpscr(FPTwo(false), product, true);
}
return result;
}
[UnmanagedCallersOnly]
public static float FPRecipStepFused(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -1679,7 +1585,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPRecpX(float value)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -1705,19 +1610,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPRSqrtEstimate(float value)
{
return FPRSqrtEstimateFpscrImpl(value, false);
return FPRSqrtEstimateFpscr(value, false);
}
[UnmanagedCallersOnly]
public static float FPRSqrtEstimateFpscr(float value, byte standardFpscr)
{
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
}
private static float FPRSqrtEstimateFpscrImpl(float value, bool standardFpscr)
public static float FPRSqrtEstimateFpscr(float value, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -1831,7 +1729,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPRSqrtStep(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -1857,7 +1754,7 @@ namespace ARMeilleure.Instructions
}
else
{
product = FPMulFpscrImpl(value1, value2, true);
product = FPMulFpscr(value1, value2, true);
}
result = FPHalvedSub(FPThree(false), product, context, fpcr);
@@ -1866,7 +1763,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPRSqrtStepFused(float value1, float value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -1910,7 +1806,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPSqrt(float value)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -1953,13 +1848,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static float FPSub(float value1, float value2)
{
return FPSubFpscrImpl(value1, value2, false);
return FPSubFpscr(value1, value2, false);
}
private static float FPSubFpscrImpl(float value1, float value2, bool standardFpscr)
public static float FPSubFpscr(float value1, float value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2200,7 +2094,6 @@ namespace ARMeilleure.Instructions
static class SoftFloat64_16
{
[UnmanagedCallersOnly]
public static ushort FPConvert(double value)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -2320,19 +2213,12 @@ namespace ARMeilleure.Instructions
static class SoftFloat64
{
[UnmanagedCallersOnly]
public static double FPAdd(double value1, double value2)
{
return FPAddFpscrImpl(value1, value2, false);
return FPAddFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPAddFpscr(double value1, double value2, byte standardFpscr)
{
return FPAddFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPAddFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPAddFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2383,8 +2269,7 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static int FPCompare(double value1, double value2, byte signalNaNs)
public static int FPCompare(double value1, double value2, bool signalNaNs)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = context.Fpcr;
@@ -2398,7 +2283,7 @@ namespace ARMeilleure.Instructions
{
result = 0b0011;
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs == 1)
if (type1 == FPType.SNaN || type2 == FPType.SNaN || signalNaNs)
{
SoftFloat.FPProcessException(FPException.InvalidOp, context, fpcr);
}
@@ -2422,19 +2307,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPCompareEQ(double value1, double value2)
{
return FPCompareEQFpscrImpl(value1, value2, false);
return FPCompareEQFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPCompareEQFpscr(double value1, double value2, byte standardFpscr)
{
return FPCompareEQFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPCompareEQFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPCompareEQFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2461,19 +2339,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPCompareGE(double value1, double value2)
{
return FPCompareGEFpscrImpl(value1, value2, false);
return FPCompareGEFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPCompareGEFpscr(double value1, double value2, byte standardFpscr)
{
return FPCompareGEFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPCompareGEFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPCompareGEFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2497,19 +2368,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPCompareGT(double value1, double value2)
{
return FPCompareGTFpscrImpl(value1, value2, false);
return FPCompareGTFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPCompareGTFpscr(double value1, double value2, byte standardFpscr)
{
return FPCompareGTFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPCompareGTFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPCompareGTFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2533,31 +2397,26 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPCompareLE(double value1, double value2)
{
return FPCompareGEFpscrImpl(value2, value1, false);
return FPCompareGE(value2, value1);
}
[UnmanagedCallersOnly]
public static double FPCompareLT(double value1, double value2)
{
return FPCompareGTFpscrImpl(value2, value1, false);
return FPCompareGT(value2, value1);
}
[UnmanagedCallersOnly]
public static double FPCompareLEFpscr(double value1, double value2, byte standardFpscr)
public static double FPCompareLEFpscr(double value1, double value2, bool standardFpscr)
{
return FPCompareGEFpscrImpl(value2, value1, standardFpscr == 1);
return FPCompareGEFpscr(value2, value1, standardFpscr);
}
[UnmanagedCallersOnly]
public static double FPCompareLTFpscr(double value1, double value2, byte standardFpscr)
public static double FPCompareLTFpscr(double value1, double value2, bool standardFpscr)
{
return FPCompareGTFpscrImpl(value2, value1, standardFpscr == 1);
return FPCompareGTFpscr(value2, value1, standardFpscr);
}
[UnmanagedCallersOnly]
public static double FPDiv(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -2610,19 +2469,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPMax(double value1, double value2)
{
return FPMaxFpscrImpl(value1, value2, false);
return FPMaxFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPMaxFpscr(double value1, double value2, byte standardFpscr)
{
return FPMaxFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPMaxFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPMaxFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2683,19 +2535,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPMaxNum(double value1, double value2)
{
return FPMaxNumFpscrImpl(value1, value2, false);
return FPMaxNumFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPMaxNumFpscr(double value1, double value2, byte standardFpscr)
{
return FPMaxNumFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPMaxNumFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPMaxNumFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2712,22 +2557,15 @@ namespace ARMeilleure.Instructions
value2 = FPInfinity(true);
}
return FPMaxFpscrImpl(value1, value2, standardFpscr);
return FPMaxFpscr(value1, value2, standardFpscr);
}
[UnmanagedCallersOnly]
public static double FPMin(double value1, double value2)
{
return FPMinFpscrImpl(value1, value2, false);
return FPMinFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPMinFpscr(double value1, double value2, byte standardFpscr)
{
return FPMinFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPMinFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPMinFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2788,19 +2626,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPMinNum(double value1, double value2)
{
return FPMinNumFpscrImpl(value1, value2, false);
return FPMinNumFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPMinNumFpscr(double value1, double value2, byte standardFpscr)
{
return FPMinNumFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPMinNumFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPMinNumFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2817,22 +2648,15 @@ namespace ARMeilleure.Instructions
value2 = FPInfinity(false);
}
return FPMinFpscrImpl(value1, value2, standardFpscr);
return FPMinFpscr(value1, value2, standardFpscr);
}
[UnmanagedCallersOnly]
public static double FPMul(double value1, double value2)
{
return FPMulFpscrImpl(value1, value2, false);
return FPMulFpscr(value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPMulFpscr(double value1, double value2, byte standardFpscr)
{
return FPMulFpscrImpl(value1, value2, standardFpscr == 1);
}
private static double FPMulFpscrImpl(double value1, double value2, bool standardFpscr)
public static double FPMulFpscr(double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2879,19 +2703,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPMulAdd(double valueA, double value1, double value2)
{
return FPMulAddFpscrImpl(valueA, value1, value2, false);
return FPMulAddFpscr(valueA, value1, value2, false);
}
[UnmanagedCallersOnly]
public static double FPMulAddFpscr(double valueA, double value1, double value2, byte standardFpscr)
{
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
}
private static double FPMulAddFpscrImpl(double valueA, double value1, double value2, bool standardFpscr)
public static double FPMulAddFpscr(double valueA, double value1, double value2, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -2957,23 +2774,20 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPMulSub(double valueA, double value1, double value2)
{
value1 = value1.FPNeg();
return FPMulAddFpscrImpl(valueA, value1, value2, false);
return FPMulAdd(valueA, value1, value2);
}
[UnmanagedCallersOnly]
public static double FPMulSubFpscr(double valueA, double value1, double value2, byte standardFpscr)
public static double FPMulSubFpscr(double valueA, double value1, double value2, bool standardFpscr)
{
value1 = value1.FPNeg();
return FPMulAddFpscrImpl(valueA, value1, value2, standardFpscr == 1);
return FPMulAddFpscr(valueA, value1, value2, standardFpscr);
}
[UnmanagedCallersOnly]
public static double FPMulX(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -3019,36 +2833,27 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPNegMulAdd(double valueA, double value1, double value2)
{
valueA = valueA.FPNeg();
value1 = value1.FPNeg();
return FPMulAddFpscrImpl(valueA, value1, value2, false);
return FPMulAdd(valueA, value1, value2);
}
[UnmanagedCallersOnly]
public static double FPNegMulSub(double valueA, double value1, double value2)
{
valueA = valueA.FPNeg();
return FPMulAddFpscrImpl(valueA, value1, value2, false);
return FPMulAdd(valueA, value1, value2);
}
[UnmanagedCallersOnly]
public static double FPRecipEstimate(double value)
{
return FPRecipEstimateFpscrImpl(value, false);
return FPRecipEstimateFpscr(value, false);
}
[UnmanagedCallersOnly]
public static double FPRecipEstimateFpscr(double value, byte standardFpscr)
{
return FPRecipEstimateFpscrImpl(value, standardFpscr == 1);
}
private static double FPRecipEstimateFpscrImpl(double value, bool standardFpscr)
public static double FPRecipEstimateFpscr(double value, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -3135,7 +2940,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPRecipStep(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -3161,7 +2965,7 @@ namespace ARMeilleure.Instructions
}
else
{
product = FPMulFpscrImpl(value1, value2, true);
product = FPMulFpscr(value1, value2, true);
}
result = FPSubFpscr(FPTwo(false), product, true);
@@ -3170,7 +2974,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPRecipStepFused(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -3214,7 +3017,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPRecpX(double value)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -3240,19 +3042,12 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPRSqrtEstimate(double value)
{
return FPRSqrtEstimateFpscrImpl(value, false);
return FPRSqrtEstimateFpscr(value, false);
}
[UnmanagedCallersOnly]
public static double FPRSqrtEstimateFpscr(double value, byte standardFpscr)
{
return FPRSqrtEstimateFpscrImpl(value, standardFpscr == 1);
}
private static double FPRSqrtEstimateFpscrImpl(double value, bool standardFpscr)
public static double FPRSqrtEstimateFpscr(double value, bool standardFpscr)
{
ExecutionContext context = NativeInterface.GetContext();
FPCR fpcr = standardFpscr ? context.StandardFpcrValue : context.Fpcr;
@@ -3366,7 +3161,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPRSqrtStep(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -3392,7 +3186,7 @@ namespace ARMeilleure.Instructions
}
else
{
product = FPMulFpscrImpl(value1, value2, true);
product = FPMulFpscr(value1, value2, true);
}
result = FPHalvedSub(FPThree(false), product, context, fpcr);
@@ -3401,7 +3195,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPRSqrtStepFused(double value1, double value2)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -3445,7 +3238,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPSqrt(double value)
{
ExecutionContext context = NativeInterface.GetContext();
@@ -3488,7 +3280,6 @@ namespace ARMeilleure.Instructions
return result;
}
[UnmanagedCallersOnly]
public static double FPSub(double value1, double value2)
{
return FPSubFpscr(value1, value2, false);

View File

@@ -24,7 +24,7 @@ namespace ARMeilleure.Translation.Cache
private static JitCacheInvalidation _jitCacheInvalidator;
private static CacheMemoryAllocator _cacheAllocator;
private static List<CacheMemoryAllocator> _cacheAllocators = [];
private static readonly List<CacheEntry> _cacheEntries = [];
@@ -40,37 +40,48 @@ namespace ARMeilleure.Translation.Cache
public static void Initialize(IJitMemoryAllocator allocator)
{
if (_initialized)
{
return;
}
lock (_lock)
{
if (_initialized)
{
return;
if (OperatingSystem.IsWindows())
{
JitUnwindWindows.RemoveFunctionTableHandler(
_jitRegions[0].Pointer);
}
for (int i = 0; i < _jitRegions.Count; i++)
{
_jitRegions[i].Dispose();
}
_jitRegions.Clear();
_cacheAllocators.Clear();
}
else
{
_initialized = true;
}
_activeRegionIndex = 0;
ReservedRegion firstRegion = new(allocator, CacheSize);
_jitRegions.Add(firstRegion);
_activeRegionIndex = 0;
CacheMemoryAllocator firstCacheAllocator = new(CacheSize);
_cacheAllocators.Add(firstCacheAllocator);
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
{
_jitCacheInvalidator = new JitCacheInvalidation(allocator);
}
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
if (OperatingSystem.IsWindows())
{
JitUnwindWindows.InstallFunctionTableHandler(
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
);
}
_initialized = true;
}
}
@@ -136,7 +147,7 @@ namespace ARMeilleure.Translation.Cache
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
{
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
_cacheAllocators[_activeRegionIndex].Free(funcOffset, AlignCodeSize(entry.Size));
_cacheEntries.RemoveAt(entryIndex);
}
@@ -167,30 +178,24 @@ namespace ARMeilleure.Translation.Cache
{
codeSize = AlignCodeSize(codeSize);
for (int i = _activeRegionIndex; i < _jitRegions.Count; i++)
int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
if (allocOffset >= 0)
{
int allocOffset = _cacheAllocator.Allocate(codeSize);
if (allocOffset >= 0)
{
_jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
_activeRegionIndex = i;
return allocOffset;
}
_jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
return allocOffset;
}
int exhaustedRegion = _activeRegionIndex;
ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize);
_jitRegions.Add(newRegion);
_activeRegionIndex = _jitRegions.Count - 1;
int newRegionNumber = _activeRegionIndex;
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {newRegionNumber} ({((long)(newRegionNumber + 1) * CacheSize).Bytes()} Total Allocation).");
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation).");
int allocOffsetNew = _cacheAllocator.Allocate(codeSize);
_cacheAllocators.Add(new CacheMemoryAllocator(CacheSize));
int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
if (allocOffsetNew < 0)
{
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");

View File

@@ -52,6 +52,11 @@ namespace ARMeilleure.Translation.Cache
nint context,
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static unsafe partial bool RtlDeleteFunctionTable(
ulong tableIdentifier);
private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
private static int _sizeOfRuntimeFunction;
@@ -91,6 +96,23 @@ namespace ARMeilleure.Translation.Cache
}
}
public static void RemoveFunctionTableHandler(nint codeCachePointer)
{
ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
bool result;
unsafe
{
result = RtlDeleteFunctionTable(codeCachePtr | 3);
}
if (!result)
{
throw new InvalidOperationException("Failure removing function table callback.");
}
}
private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
{
int offset = (int)((long)controlPc - context.ToInt64());

View File

@@ -1,10 +1,18 @@
using System;
namespace ARMeilleure.Translation
{
class DelegateInfo
{
public nint FuncPtr { get; private set; }
public DelegateInfo(nint funcPtr)
#pragma warning disable IDE0052 // Remove unread private member
private readonly Delegate _dlg; // Ensure that this delegate will not be garbage collected.
#pragma warning restore IDE0052
public nint FuncPtr { get; }
public DelegateInfo(Delegate dlg, nint funcPtr)
{
_dlg = dlg;
FuncPtr = funcPtr;
}
}

View File

@@ -1,7 +1,10 @@
using ARMeilleure.Instructions;
using ARMeilleure.State;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
// ReSharper disable RedundantTypeArgumentsOfMethod
namespace ARMeilleure.Translation
{
@@ -32,7 +35,21 @@ namespace ARMeilleure.Translation
return _delegates.Values[index].FuncPtr; // O(1).
}
public static nint GetDelegateFuncPtr(MethodInfo info)
{
ArgumentNullException.ThrowIfNull(info);
string key = GetKey(info);
if (!_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) // O(log(n)).
{
throw new KeyNotFoundException($"({nameof(key)} = {key})");
}
return dlgInfo.FuncPtr;
}
public static int GetDelegateIndex(MethodInfo info)
{
ArgumentNullException.ThrowIfNull(info);
@@ -48,12 +65,12 @@ namespace ARMeilleure.Translation
return index;
}
private static void SetDelegateInfo(MethodInfo method)
{
string key = GetKey(method);
_delegates.Add(key, new DelegateInfo(method.MethodHandle.GetFunctionPointer())); // ArgumentException (key).
private static void SetDelegateInfo(Delegate dlg, nint funcPtr)
{
string key = GetKey(dlg.Method);
_delegates.Add(key, new DelegateInfo(dlg, funcPtr)); // ArgumentException (key).
}
private static string GetKey(MethodInfo info)
@@ -67,179 +84,533 @@ namespace ARMeilleure.Translation
{
_delegates = new SortedList<string, DelegateInfo>();
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Abs)));
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Ceiling)));
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Floor)));
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Round)));
SetDelegateInfo(typeof(MathHelper).GetMethod(nameof(MathHelper.Truncate)));
// ReSharper disable InconsistentNaming
// ReSharper disable RedundantDelegateCreation
MathAbs dlgMathAbs = new(Math.Abs);
MathCeiling dlgMathCeiling = new(Math.Ceiling);
MathFloor dlgMathFloor = new(Math.Floor);
MathRound dlgMathRound = new(Math.Round);
MathTruncate dlgMathTruncate = new(Math.Truncate);
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Abs)));
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Ceiling)));
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Floor)));
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Round)));
SetDelegateInfo(typeof(MathHelperF).GetMethod(nameof(MathHelperF.Truncate)));
MathFAbs dlgMathFAbs = new(MathF.Abs);
MathFCeiling dlgMathFCeiling = new(MathF.Ceiling);
MathFFloor dlgMathFFloor = new(MathF.Floor);
MathFRound dlgMathFRound = new(MathF.Round);
MathFTruncate dlgMathFTruncate = new(MathF.Truncate);
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Break)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)));
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)));
NativeInterfaceBreak dlgNativeInterfaceBreak = new(NativeInterface.Break);
NativeInterfaceCheckSynchronization dlgNativeInterfaceCheckSynchronization = new(NativeInterface.CheckSynchronization);
NativeInterfaceEnqueueForRejit dlgNativeInterfaceEnqueueForRejit = new(NativeInterface.EnqueueForRejit);
NativeInterfaceGetCntfrqEl0 dlgNativeInterfaceGetCntfrqEl0 = new(NativeInterface.GetCntfrqEl0);
NativeInterfaceGetCntpctEl0 dlgNativeInterfaceGetCntpctEl0 = new(NativeInterface.GetCntpctEl0);
NativeInterfaceGetCntvctEl0 dlgNativeInterfaceGetCntvctEl0 = new(NativeInterface.GetCntvctEl0);
NativeInterfaceGetCtrEl0 dlgNativeInterfaceGetCtrEl0 = new(NativeInterface.GetCtrEl0);
NativeInterfaceGetDczidEl0 dlgNativeInterfaceGetDczidEl0 = new(NativeInterface.GetDczidEl0);
NativeInterfaceGetFunctionAddress dlgNativeInterfaceGetFunctionAddress = new(NativeInterface.GetFunctionAddress);
NativeInterfaceInvalidateCacheLine dlgNativeInterfaceInvalidateCacheLine = new(NativeInterface.InvalidateCacheLine);
NativeInterfaceReadByte dlgNativeInterfaceReadByte = new(NativeInterface.ReadByte);
NativeInterfaceReadUInt16 dlgNativeInterfaceReadUInt16 = new(NativeInterface.ReadUInt16);
NativeInterfaceReadUInt32 dlgNativeInterfaceReadUInt32 = new(NativeInterface.ReadUInt32);
NativeInterfaceReadUInt64 dlgNativeInterfaceReadUInt64 = new(NativeInterface.ReadUInt64);
NativeInterfaceReadVector128 dlgNativeInterfaceReadVector128 = new(NativeInterface.ReadVector128);
NativeInterfaceSignalMemoryTracking dlgNativeInterfaceSignalMemoryTracking = new(NativeInterface.SignalMemoryTracking);
NativeInterfaceSupervisorCall dlgNativeInterfaceSupervisorCall = new(NativeInterface.SupervisorCall);
NativeInterfaceThrowInvalidMemoryAccess dlgNativeInterfaceThrowInvalidMemoryAccess = new(NativeInterface.ThrowInvalidMemoryAccess);
NativeInterfaceUndefined dlgNativeInterfaceUndefined = new(NativeInterface.Undefined);
NativeInterfaceWriteByte dlgNativeInterfaceWriteByte = new(NativeInterface.WriteByte);
NativeInterfaceWriteUInt16 dlgNativeInterfaceWriteUInt16 = new(NativeInterface.WriteUInt16);
NativeInterfaceWriteUInt32 dlgNativeInterfaceWriteUInt32 = new(NativeInterface.WriteUInt32);
NativeInterfaceWriteUInt64 dlgNativeInterfaceWriteUInt64 = new(NativeInterface.WriteUInt64);
NativeInterfaceWriteVector128 dlgNativeInterfaceWriteVector128 = new(NativeInterface.WriteVector128);
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32b)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cb)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32ch)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cw)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cx)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32h)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashParity)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart1)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
SoftFallbackCountLeadingSigns dlgSoftFallbackCountLeadingSigns = new(SoftFallback.CountLeadingSigns);
SoftFallbackCountLeadingZeros dlgSoftFallbackCountLeadingZeros = new(SoftFallback.CountLeadingZeros);
SoftFallbackCrc32b dlgSoftFallbackCrc32b = new(SoftFallback.Crc32b);
SoftFallbackCrc32cb dlgSoftFallbackCrc32cb = new(SoftFallback.Crc32cb);
SoftFallbackCrc32ch dlgSoftFallbackCrc32ch = new(SoftFallback.Crc32ch);
SoftFallbackCrc32cw dlgSoftFallbackCrc32cw = new(SoftFallback.Crc32cw);
SoftFallbackCrc32cx dlgSoftFallbackCrc32cx = new(SoftFallback.Crc32cx);
SoftFallbackCrc32h dlgSoftFallbackCrc32h = new(SoftFallback.Crc32h);
SoftFallbackCrc32w dlgSoftFallbackCrc32w = new(SoftFallback.Crc32w);
SoftFallbackCrc32x dlgSoftFallbackCrc32x = new(SoftFallback.Crc32x);
SoftFallbackDecrypt dlgSoftFallbackDecrypt = new(SoftFallback.Decrypt);
SoftFallbackEncrypt dlgSoftFallbackEncrypt = new(SoftFallback.Encrypt);
SoftFallbackFixedRotate dlgSoftFallbackFixedRotate = new(SoftFallback.FixedRotate);
SoftFallbackHashChoose dlgSoftFallbackHashChoose = new(SoftFallback.HashChoose);
SoftFallbackHashLower dlgSoftFallbackHashLower = new(SoftFallback.HashLower);
SoftFallbackHashMajority dlgSoftFallbackHashMajority = new(SoftFallback.HashMajority);
SoftFallbackHashParity dlgSoftFallbackHashParity = new(SoftFallback.HashParity);
SoftFallbackHashUpper dlgSoftFallbackHashUpper = new(SoftFallback.HashUpper);
SoftFallbackInverseMixColumns dlgSoftFallbackInverseMixColumns = new(SoftFallback.InverseMixColumns);
SoftFallbackMixColumns dlgSoftFallbackMixColumns = new(SoftFallback.MixColumns);
SoftFallbackPolynomialMult64_128 dlgSoftFallbackPolynomialMult64_128 = new(SoftFallback.PolynomialMult64_128);
SoftFallbackSatF32ToS32 dlgSoftFallbackSatF32ToS32 = new(SoftFallback.SatF32ToS32);
SoftFallbackSatF32ToS64 dlgSoftFallbackSatF32ToS64 = new(SoftFallback.SatF32ToS64);
SoftFallbackSatF32ToU32 dlgSoftFallbackSatF32ToU32 = new(SoftFallback.SatF32ToU32);
SoftFallbackSatF32ToU64 dlgSoftFallbackSatF32ToU64 = new(SoftFallback.SatF32ToU64);
SoftFallbackSatF64ToS32 dlgSoftFallbackSatF64ToS32 = new(SoftFallback.SatF64ToS32);
SoftFallbackSatF64ToS64 dlgSoftFallbackSatF64ToS64 = new(SoftFallback.SatF64ToS64);
SoftFallbackSatF64ToU32 dlgSoftFallbackSatF64ToU32 = new(SoftFallback.SatF64ToU32);
SoftFallbackSatF64ToU64 dlgSoftFallbackSatF64ToU64 = new(SoftFallback.SatF64ToU64);
SoftFallbackSha1SchedulePart1 dlgSoftFallbackSha1SchedulePart1 = new(SoftFallback.Sha1SchedulePart1);
SoftFallbackSha1SchedulePart2 dlgSoftFallbackSha1SchedulePart2 = new(SoftFallback.Sha1SchedulePart2);
SoftFallbackSha256SchedulePart1 dlgSoftFallbackSha256SchedulePart1 = new(SoftFallback.Sha256SchedulePart1);
SoftFallbackSha256SchedulePart2 dlgSoftFallbackSha256SchedulePart2 = new(SoftFallback.Sha256SchedulePart2);
SoftFallbackSignedShrImm64 dlgSoftFallbackSignedShrImm64 = new(SoftFallback.SignedShrImm64);
SoftFallbackTbl1 dlgSoftFallbackTbl1 = new(SoftFallback.Tbl1);
SoftFallbackTbl2 dlgSoftFallbackTbl2 = new(SoftFallback.Tbl2);
SoftFallbackTbl3 dlgSoftFallbackTbl3 = new(SoftFallback.Tbl3);
SoftFallbackTbl4 dlgSoftFallbackTbl4 = new(SoftFallback.Tbl4);
SoftFallbackTbx1 dlgSoftFallbackTbx1 = new(SoftFallback.Tbx1);
SoftFallbackTbx2 dlgSoftFallbackTbx2 = new(SoftFallback.Tbx2);
SoftFallbackTbx3 dlgSoftFallbackTbx3 = new(SoftFallback.Tbx3);
SoftFallbackTbx4 dlgSoftFallbackTbx4 = new(SoftFallback.Tbx4);
SoftFallbackUnsignedShrImm64 dlgSoftFallbackUnsignedShrImm64 = new(SoftFallback.UnsignedShrImm64);
SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
SoftFloat16_32FPConvert dlgSoftFloat16_32FPConvert = new(SoftFloat16_32.FPConvert);
SoftFloat16_64FPConvert dlgSoftFloat16_64FPConvert = new(SoftFloat16_64.FPConvert);
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
SoftFloat32FPAdd dlgSoftFloat32FPAdd = new(SoftFloat32.FPAdd);
SoftFloat32FPAddFpscr dlgSoftFloat32FPAddFpscr = new(SoftFloat32.FPAddFpscr); // A32 only.
SoftFloat32FPCompare dlgSoftFloat32FPCompare = new(SoftFloat32.FPCompare);
SoftFloat32FPCompareEQ dlgSoftFloat32FPCompareEQ = new(SoftFloat32.FPCompareEQ);
SoftFloat32FPCompareEQFpscr dlgSoftFloat32FPCompareEQFpscr = new(SoftFloat32.FPCompareEQFpscr); // A32 only.
SoftFloat32FPCompareGE dlgSoftFloat32FPCompareGE = new(SoftFloat32.FPCompareGE);
SoftFloat32FPCompareGEFpscr dlgSoftFloat32FPCompareGEFpscr = new(SoftFloat32.FPCompareGEFpscr); // A32 only.
SoftFloat32FPCompareGT dlgSoftFloat32FPCompareGT = new(SoftFloat32.FPCompareGT);
SoftFloat32FPCompareGTFpscr dlgSoftFloat32FPCompareGTFpscr = new(SoftFloat32.FPCompareGTFpscr); // A32 only.
SoftFloat32FPCompareLE dlgSoftFloat32FPCompareLE = new(SoftFloat32.FPCompareLE);
SoftFloat32FPCompareLEFpscr dlgSoftFloat32FPCompareLEFpscr = new(SoftFloat32.FPCompareLEFpscr); // A32 only.
SoftFloat32FPCompareLT dlgSoftFloat32FPCompareLT = new(SoftFloat32.FPCompareLT);
SoftFloat32FPCompareLTFpscr dlgSoftFloat32FPCompareLTFpscr = new(SoftFloat32.FPCompareLTFpscr); // A32 only.
SoftFloat32FPDiv dlgSoftFloat32FPDiv = new(SoftFloat32.FPDiv);
SoftFloat32FPMax dlgSoftFloat32FPMax = new(SoftFloat32.FPMax);
SoftFloat32FPMaxFpscr dlgSoftFloat32FPMaxFpscr = new(SoftFloat32.FPMaxFpscr); // A32 only.
SoftFloat32FPMaxNum dlgSoftFloat32FPMaxNum = new(SoftFloat32.FPMaxNum);
SoftFloat32FPMaxNumFpscr dlgSoftFloat32FPMaxNumFpscr = new(SoftFloat32.FPMaxNumFpscr); // A32 only.
SoftFloat32FPMin dlgSoftFloat32FPMin = new(SoftFloat32.FPMin);
SoftFloat32FPMinFpscr dlgSoftFloat32FPMinFpscr = new(SoftFloat32.FPMinFpscr); // A32 only.
SoftFloat32FPMinNum dlgSoftFloat32FPMinNum = new(SoftFloat32.FPMinNum);
SoftFloat32FPMinNumFpscr dlgSoftFloat32FPMinNumFpscr = new(SoftFloat32.FPMinNumFpscr); // A32 only.
SoftFloat32FPMul dlgSoftFloat32FPMul = new(SoftFloat32.FPMul);
SoftFloat32FPMulFpscr dlgSoftFloat32FPMulFpscr = new(SoftFloat32.FPMulFpscr); // A32 only.
SoftFloat32FPMulAdd dlgSoftFloat32FPMulAdd = new(SoftFloat32.FPMulAdd);
SoftFloat32FPMulAddFpscr dlgSoftFloat32FPMulAddFpscr = new(SoftFloat32.FPMulAddFpscr); // A32 only.
SoftFloat32FPMulSub dlgSoftFloat32FPMulSub = new(SoftFloat32.FPMulSub);
SoftFloat32FPMulSubFpscr dlgSoftFloat32FPMulSubFpscr = new(SoftFloat32.FPMulSubFpscr); // A32 only.
SoftFloat32FPMulX dlgSoftFloat32FPMulX = new(SoftFloat32.FPMulX);
SoftFloat32FPNegMulAdd dlgSoftFloat32FPNegMulAdd = new(SoftFloat32.FPNegMulAdd);
SoftFloat32FPNegMulSub dlgSoftFloat32FPNegMulSub = new(SoftFloat32.FPNegMulSub);
SoftFloat32FPRecipEstimate dlgSoftFloat32FPRecipEstimate = new(SoftFloat32.FPRecipEstimate);
SoftFloat32FPRecipEstimateFpscr dlgSoftFloat32FPRecipEstimateFpscr = new(SoftFloat32.FPRecipEstimateFpscr); // A32 only.
SoftFloat32FPRecipStep dlgSoftFloat32FPRecipStep = new(SoftFloat32.FPRecipStep); // A32 only.
SoftFloat32FPRecipStepFused dlgSoftFloat32FPRecipStepFused = new(SoftFloat32.FPRecipStepFused);
SoftFloat32FPRecpX dlgSoftFloat32FPRecpX = new(SoftFloat32.FPRecpX);
SoftFloat32FPRSqrtEstimate dlgSoftFloat32FPRSqrtEstimate = new(SoftFloat32.FPRSqrtEstimate);
SoftFloat32FPRSqrtEstimateFpscr dlgSoftFloat32FPRSqrtEstimateFpscr = new(SoftFloat32.FPRSqrtEstimateFpscr); // A32 only.
SoftFloat32FPRSqrtStep dlgSoftFloat32FPRSqrtStep = new(SoftFloat32.FPRSqrtStep); // A32 only.
SoftFloat32FPRSqrtStepFused dlgSoftFloat32FPRSqrtStepFused = new(SoftFloat32.FPRSqrtStepFused);
SoftFloat32FPSqrt dlgSoftFloat32FPSqrt = new(SoftFloat32.FPSqrt);
SoftFloat32FPSub dlgSoftFloat32FPSub = new(SoftFloat32.FPSub);
SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
SoftFloat32_16FPConvert dlgSoftFloat32_16FPConvert = new(SoftFloat32_16.FPConvert);
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
SoftFloat64FPAdd dlgSoftFloat64FPAdd = new(SoftFloat64.FPAdd);
SoftFloat64FPAddFpscr dlgSoftFloat64FPAddFpscr = new(SoftFloat64.FPAddFpscr); // A32 only.
SoftFloat64FPCompare dlgSoftFloat64FPCompare = new(SoftFloat64.FPCompare);
SoftFloat64FPCompareEQ dlgSoftFloat64FPCompareEQ = new(SoftFloat64.FPCompareEQ);
SoftFloat64FPCompareEQFpscr dlgSoftFloat64FPCompareEQFpscr = new(SoftFloat64.FPCompareEQFpscr); // A32 only.
SoftFloat64FPCompareGE dlgSoftFloat64FPCompareGE = new(SoftFloat64.FPCompareGE);
SoftFloat64FPCompareGEFpscr dlgSoftFloat64FPCompareGEFpscr = new(SoftFloat64.FPCompareGEFpscr); // A32 only.
SoftFloat64FPCompareGT dlgSoftFloat64FPCompareGT = new(SoftFloat64.FPCompareGT);
SoftFloat64FPCompareGTFpscr dlgSoftFloat64FPCompareGTFpscr = new(SoftFloat64.FPCompareGTFpscr); // A32 only.
SoftFloat64FPCompareLE dlgSoftFloat64FPCompareLE = new(SoftFloat64.FPCompareLE);
SoftFloat64FPCompareLEFpscr dlgSoftFloat64FPCompareLEFpscr = new(SoftFloat64.FPCompareLEFpscr); // A32 only.
SoftFloat64FPCompareLT dlgSoftFloat64FPCompareLT = new(SoftFloat64.FPCompareLT);
SoftFloat64FPCompareLTFpscr dlgSoftFloat64FPCompareLTFpscr = new(SoftFloat64.FPCompareLTFpscr); // A32 only.
SoftFloat64FPDiv dlgSoftFloat64FPDiv = new(SoftFloat64.FPDiv);
SoftFloat64FPMax dlgSoftFloat64FPMax = new(SoftFloat64.FPMax);
SoftFloat64FPMaxFpscr dlgSoftFloat64FPMaxFpscr = new(SoftFloat64.FPMaxFpscr); // A32 only.
SoftFloat64FPMaxNum dlgSoftFloat64FPMaxNum = new(SoftFloat64.FPMaxNum);
SoftFloat64FPMaxNumFpscr dlgSoftFloat64FPMaxNumFpscr = new(SoftFloat64.FPMaxNumFpscr); // A32 only.
SoftFloat64FPMin dlgSoftFloat64FPMin = new(SoftFloat64.FPMin);
SoftFloat64FPMinFpscr dlgSoftFloat64FPMinFpscr = new(SoftFloat64.FPMinFpscr); // A32 only.
SoftFloat64FPMinNum dlgSoftFloat64FPMinNum = new(SoftFloat64.FPMinNum);
SoftFloat64FPMinNumFpscr dlgSoftFloat64FPMinNumFpscr = new(SoftFloat64.FPMinNumFpscr); // A32 only.
SoftFloat64FPMul dlgSoftFloat64FPMul = new(SoftFloat64.FPMul);
SoftFloat64FPMulFpscr dlgSoftFloat64FPMulFpscr = new(SoftFloat64.FPMulFpscr); // A32 only.
SoftFloat64FPMulAdd dlgSoftFloat64FPMulAdd = new(SoftFloat64.FPMulAdd);
SoftFloat64FPMulAddFpscr dlgSoftFloat64FPMulAddFpscr = new(SoftFloat64.FPMulAddFpscr); // A32 only.
SoftFloat64FPMulSub dlgSoftFloat64FPMulSub = new(SoftFloat64.FPMulSub);
SoftFloat64FPMulSubFpscr dlgSoftFloat64FPMulSubFpscr = new(SoftFloat64.FPMulSubFpscr); // A32 only.
SoftFloat64FPMulX dlgSoftFloat64FPMulX = new(SoftFloat64.FPMulX);
SoftFloat64FPNegMulAdd dlgSoftFloat64FPNegMulAdd = new(SoftFloat64.FPNegMulAdd);
SoftFloat64FPNegMulSub dlgSoftFloat64FPNegMulSub = new(SoftFloat64.FPNegMulSub);
SoftFloat64FPRecipEstimate dlgSoftFloat64FPRecipEstimate = new(SoftFloat64.FPRecipEstimate);
SoftFloat64FPRecipEstimateFpscr dlgSoftFloat64FPRecipEstimateFpscr = new(SoftFloat64.FPRecipEstimateFpscr); // A32 only.
SoftFloat64FPRecipStep dlgSoftFloat64FPRecipStep = new(SoftFloat64.FPRecipStep); // A32 only.
SoftFloat64FPRecipStepFused dlgSoftFloat64FPRecipStepFused = new(SoftFloat64.FPRecipStepFused);
SoftFloat64FPRecpX dlgSoftFloat64FPRecpX = new(SoftFloat64.FPRecpX);
SoftFloat64FPRSqrtEstimate dlgSoftFloat64FPRSqrtEstimate = new(SoftFloat64.FPRSqrtEstimate);
SoftFloat64FPRSqrtEstimateFpscr dlgSoftFloat64FPRSqrtEstimateFpscr = new(SoftFloat64.FPRSqrtEstimateFpscr); // A32 only.
SoftFloat64FPRSqrtStep dlgSoftFloat64FPRSqrtStep = new(SoftFloat64.FPRSqrtStep); // A32 only.
SoftFloat64FPRSqrtStepFused dlgSoftFloat64FPRSqrtStepFused = new(SoftFloat64.FPRSqrtStepFused);
SoftFloat64FPSqrt dlgSoftFloat64FPSqrt = new(SoftFloat64.FPSqrt);
SoftFloat64FPSub dlgSoftFloat64FPSub = new(SoftFloat64.FPSub);
SetDelegateInfo(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)));
SoftFloat64_16FPConvert dlgSoftFloat64_16FPConvert = new(SoftFloat64_16.FPConvert);
// ReSharper restore InconsistentNaming
// ReSharper restore RedundantDelegateCreation
SetDelegateInfo(dlgMathAbs, Marshal.GetFunctionPointerForDelegate<MathAbs>(dlgMathAbs));
SetDelegateInfo(dlgMathCeiling, Marshal.GetFunctionPointerForDelegate<MathCeiling>(dlgMathCeiling));
SetDelegateInfo(dlgMathFloor, Marshal.GetFunctionPointerForDelegate<MathFloor>(dlgMathFloor));
SetDelegateInfo(dlgMathRound, Marshal.GetFunctionPointerForDelegate<MathRound>(dlgMathRound));
SetDelegateInfo(dlgMathTruncate, Marshal.GetFunctionPointerForDelegate<MathTruncate>(dlgMathTruncate));
SetDelegateInfo(dlgMathFAbs, Marshal.GetFunctionPointerForDelegate<MathFAbs>(dlgMathFAbs));
SetDelegateInfo(dlgMathFCeiling, Marshal.GetFunctionPointerForDelegate<MathFCeiling>(dlgMathFCeiling));
SetDelegateInfo(dlgMathFFloor, Marshal.GetFunctionPointerForDelegate<MathFFloor>(dlgMathFFloor));
SetDelegateInfo(dlgMathFRound, Marshal.GetFunctionPointerForDelegate<MathFRound>(dlgMathFRound));
SetDelegateInfo(dlgMathFTruncate, Marshal.GetFunctionPointerForDelegate<MathFTruncate>(dlgMathFTruncate));
SetDelegateInfo(dlgNativeInterfaceBreak, Marshal.GetFunctionPointerForDelegate<NativeInterfaceBreak>(dlgNativeInterfaceBreak));
SetDelegateInfo(dlgNativeInterfaceCheckSynchronization, Marshal.GetFunctionPointerForDelegate<NativeInterfaceCheckSynchronization>(dlgNativeInterfaceCheckSynchronization));
SetDelegateInfo(dlgNativeInterfaceEnqueueForRejit, Marshal.GetFunctionPointerForDelegate<NativeInterfaceEnqueueForRejit>(dlgNativeInterfaceEnqueueForRejit));
SetDelegateInfo(dlgNativeInterfaceGetCntfrqEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntfrqEl0>(dlgNativeInterfaceGetCntfrqEl0));
SetDelegateInfo(dlgNativeInterfaceGetCntpctEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntpctEl0>(dlgNativeInterfaceGetCntpctEl0));
SetDelegateInfo(dlgNativeInterfaceGetCntvctEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntvctEl0>(dlgNativeInterfaceGetCntvctEl0));
SetDelegateInfo(dlgNativeInterfaceGetCtrEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCtrEl0>(dlgNativeInterfaceGetCtrEl0));
SetDelegateInfo(dlgNativeInterfaceGetDczidEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetDczidEl0>(dlgNativeInterfaceGetDczidEl0));
SetDelegateInfo(dlgNativeInterfaceGetFunctionAddress, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetFunctionAddress>(dlgNativeInterfaceGetFunctionAddress));
SetDelegateInfo(dlgNativeInterfaceInvalidateCacheLine, Marshal.GetFunctionPointerForDelegate<NativeInterfaceInvalidateCacheLine>(dlgNativeInterfaceInvalidateCacheLine));
SetDelegateInfo(dlgNativeInterfaceReadByte, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadByte>(dlgNativeInterfaceReadByte));
SetDelegateInfo(dlgNativeInterfaceReadUInt16, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt16>(dlgNativeInterfaceReadUInt16));
SetDelegateInfo(dlgNativeInterfaceReadUInt32, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt32>(dlgNativeInterfaceReadUInt32));
SetDelegateInfo(dlgNativeInterfaceReadUInt64, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt64>(dlgNativeInterfaceReadUInt64));
SetDelegateInfo(dlgNativeInterfaceReadVector128, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadVector128>(dlgNativeInterfaceReadVector128));
SetDelegateInfo(dlgNativeInterfaceSignalMemoryTracking, Marshal.GetFunctionPointerForDelegate<NativeInterfaceSignalMemoryTracking>(dlgNativeInterfaceSignalMemoryTracking));
SetDelegateInfo(dlgNativeInterfaceSupervisorCall, Marshal.GetFunctionPointerForDelegate<NativeInterfaceSupervisorCall>(dlgNativeInterfaceSupervisorCall));
SetDelegateInfo(dlgNativeInterfaceThrowInvalidMemoryAccess, Marshal.GetFunctionPointerForDelegate<NativeInterfaceThrowInvalidMemoryAccess>(dlgNativeInterfaceThrowInvalidMemoryAccess));
SetDelegateInfo(dlgNativeInterfaceUndefined, Marshal.GetFunctionPointerForDelegate<NativeInterfaceUndefined>(dlgNativeInterfaceUndefined));
SetDelegateInfo(dlgNativeInterfaceWriteByte, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteByte>(dlgNativeInterfaceWriteByte));
SetDelegateInfo(dlgNativeInterfaceWriteUInt16, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt16>(dlgNativeInterfaceWriteUInt16));
SetDelegateInfo(dlgNativeInterfaceWriteUInt32, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt32>(dlgNativeInterfaceWriteUInt32));
SetDelegateInfo(dlgNativeInterfaceWriteUInt64, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt64>(dlgNativeInterfaceWriteUInt64));
SetDelegateInfo(dlgNativeInterfaceWriteVector128, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteVector128>(dlgNativeInterfaceWriteVector128));
SetDelegateInfo(dlgSoftFallbackCountLeadingSigns, Marshal.GetFunctionPointerForDelegate<SoftFallbackCountLeadingSigns>(dlgSoftFallbackCountLeadingSigns));
SetDelegateInfo(dlgSoftFallbackCountLeadingZeros, Marshal.GetFunctionPointerForDelegate<SoftFallbackCountLeadingZeros>(dlgSoftFallbackCountLeadingZeros));
SetDelegateInfo(dlgSoftFallbackCrc32b, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32b>(dlgSoftFallbackCrc32b));
SetDelegateInfo(dlgSoftFallbackCrc32cb, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cb>(dlgSoftFallbackCrc32cb));
SetDelegateInfo(dlgSoftFallbackCrc32ch, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32ch>(dlgSoftFallbackCrc32ch));
SetDelegateInfo(dlgSoftFallbackCrc32cw, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cw>(dlgSoftFallbackCrc32cw));
SetDelegateInfo(dlgSoftFallbackCrc32cx, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cx>(dlgSoftFallbackCrc32cx));
SetDelegateInfo(dlgSoftFallbackCrc32h, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32h>(dlgSoftFallbackCrc32h));
SetDelegateInfo(dlgSoftFallbackCrc32w, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32w>(dlgSoftFallbackCrc32w));
SetDelegateInfo(dlgSoftFallbackCrc32x, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32x>(dlgSoftFallbackCrc32x));
SetDelegateInfo(dlgSoftFallbackDecrypt, Marshal.GetFunctionPointerForDelegate<SoftFallbackDecrypt>(dlgSoftFallbackDecrypt));
SetDelegateInfo(dlgSoftFallbackEncrypt, Marshal.GetFunctionPointerForDelegate<SoftFallbackEncrypt>(dlgSoftFallbackEncrypt));
SetDelegateInfo(dlgSoftFallbackFixedRotate, Marshal.GetFunctionPointerForDelegate<SoftFallbackFixedRotate>(dlgSoftFallbackFixedRotate));
SetDelegateInfo(dlgSoftFallbackHashChoose, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashChoose>(dlgSoftFallbackHashChoose));
SetDelegateInfo(dlgSoftFallbackHashLower, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashLower>(dlgSoftFallbackHashLower));
SetDelegateInfo(dlgSoftFallbackHashMajority, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashMajority>(dlgSoftFallbackHashMajority));
SetDelegateInfo(dlgSoftFallbackHashParity, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashParity>(dlgSoftFallbackHashParity));
SetDelegateInfo(dlgSoftFallbackHashUpper, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashUpper>(dlgSoftFallbackHashUpper));
SetDelegateInfo(dlgSoftFallbackInverseMixColumns, Marshal.GetFunctionPointerForDelegate<SoftFallbackInverseMixColumns>(dlgSoftFallbackInverseMixColumns));
SetDelegateInfo(dlgSoftFallbackMixColumns, Marshal.GetFunctionPointerForDelegate<SoftFallbackMixColumns>(dlgSoftFallbackMixColumns));
SetDelegateInfo(dlgSoftFallbackPolynomialMult64_128, Marshal.GetFunctionPointerForDelegate<SoftFallbackPolynomialMult64_128>(dlgSoftFallbackPolynomialMult64_128));
SetDelegateInfo(dlgSoftFallbackSatF32ToS32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToS32>(dlgSoftFallbackSatF32ToS32));
SetDelegateInfo(dlgSoftFallbackSatF32ToS64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToS64>(dlgSoftFallbackSatF32ToS64));
SetDelegateInfo(dlgSoftFallbackSatF32ToU32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToU32>(dlgSoftFallbackSatF32ToU32));
SetDelegateInfo(dlgSoftFallbackSatF32ToU64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToU64>(dlgSoftFallbackSatF32ToU64));
SetDelegateInfo(dlgSoftFallbackSatF64ToS32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToS32>(dlgSoftFallbackSatF64ToS32));
SetDelegateInfo(dlgSoftFallbackSatF64ToS64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToS64>(dlgSoftFallbackSatF64ToS64));
SetDelegateInfo(dlgSoftFallbackSatF64ToU32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToU32>(dlgSoftFallbackSatF64ToU32));
SetDelegateInfo(dlgSoftFallbackSatF64ToU64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToU64>(dlgSoftFallbackSatF64ToU64));
SetDelegateInfo(dlgSoftFallbackSha1SchedulePart1, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha1SchedulePart1>(dlgSoftFallbackSha1SchedulePart1));
SetDelegateInfo(dlgSoftFallbackSha1SchedulePart2, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha1SchedulePart2>(dlgSoftFallbackSha1SchedulePart2));
SetDelegateInfo(dlgSoftFallbackSha256SchedulePart1, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha256SchedulePart1>(dlgSoftFallbackSha256SchedulePart1));
SetDelegateInfo(dlgSoftFallbackSha256SchedulePart2, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha256SchedulePart2>(dlgSoftFallbackSha256SchedulePart2));
SetDelegateInfo(dlgSoftFallbackSignedShrImm64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSignedShrImm64>(dlgSoftFallbackSignedShrImm64));
SetDelegateInfo(dlgSoftFallbackTbl1, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl1>(dlgSoftFallbackTbl1));
SetDelegateInfo(dlgSoftFallbackTbl2, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl2>(dlgSoftFallbackTbl2));
SetDelegateInfo(dlgSoftFallbackTbl3, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl3>(dlgSoftFallbackTbl3));
SetDelegateInfo(dlgSoftFallbackTbl4, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl4>(dlgSoftFallbackTbl4));
SetDelegateInfo(dlgSoftFallbackTbx1, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx1>(dlgSoftFallbackTbx1));
SetDelegateInfo(dlgSoftFallbackTbx2, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx2>(dlgSoftFallbackTbx2));
SetDelegateInfo(dlgSoftFallbackTbx3, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx3>(dlgSoftFallbackTbx3));
SetDelegateInfo(dlgSoftFallbackTbx4, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx4>(dlgSoftFallbackTbx4));
SetDelegateInfo(dlgSoftFallbackUnsignedShrImm64, Marshal.GetFunctionPointerForDelegate<SoftFallbackUnsignedShrImm64>(dlgSoftFallbackUnsignedShrImm64));
SetDelegateInfo(dlgSoftFloat16_32FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat16_32FPConvert>(dlgSoftFloat16_32FPConvert));
SetDelegateInfo(dlgSoftFloat16_64FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat16_64FPConvert>(dlgSoftFloat16_64FPConvert));
SetDelegateInfo(dlgSoftFloat32FPAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPAdd>(dlgSoftFloat32FPAdd));
SetDelegateInfo(dlgSoftFloat32FPAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPAddFpscr>(dlgSoftFloat32FPAddFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPCompare, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompare>(dlgSoftFloat32FPCompare));
SetDelegateInfo(dlgSoftFloat32FPCompareEQ, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareEQ>(dlgSoftFloat32FPCompareEQ));
SetDelegateInfo(dlgSoftFloat32FPCompareEQFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareEQFpscr>(dlgSoftFloat32FPCompareEQFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPCompareGE, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGE>(dlgSoftFloat32FPCompareGE));
SetDelegateInfo(dlgSoftFloat32FPCompareGEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGEFpscr>(dlgSoftFloat32FPCompareGEFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPCompareGT, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGT>(dlgSoftFloat32FPCompareGT));
SetDelegateInfo(dlgSoftFloat32FPCompareGTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGTFpscr>(dlgSoftFloat32FPCompareGTFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPCompareLE, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLE>(dlgSoftFloat32FPCompareLE));
SetDelegateInfo(dlgSoftFloat32FPCompareLEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLEFpscr>(dlgSoftFloat32FPCompareLEFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPCompareLT, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLT>(dlgSoftFloat32FPCompareLT));
SetDelegateInfo(dlgSoftFloat32FPCompareLTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLTFpscr>(dlgSoftFloat32FPCompareLTFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPDiv, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPDiv>(dlgSoftFloat32FPDiv));
SetDelegateInfo(dlgSoftFloat32FPMax, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMax>(dlgSoftFloat32FPMax));
SetDelegateInfo(dlgSoftFloat32FPMaxFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxFpscr>(dlgSoftFloat32FPMaxFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPMaxNum, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxNum>(dlgSoftFloat32FPMaxNum));
SetDelegateInfo(dlgSoftFloat32FPMaxNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxNumFpscr>(dlgSoftFloat32FPMaxNumFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPMin, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMin>(dlgSoftFloat32FPMin));
SetDelegateInfo(dlgSoftFloat32FPMinFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinFpscr>(dlgSoftFloat32FPMinFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPMinNum, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinNum>(dlgSoftFloat32FPMinNum));
SetDelegateInfo(dlgSoftFloat32FPMinNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinNumFpscr>(dlgSoftFloat32FPMinNumFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPMul, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMul>(dlgSoftFloat32FPMul));
SetDelegateInfo(dlgSoftFloat32FPMulFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulFpscr>(dlgSoftFloat32FPMulFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulAdd>(dlgSoftFloat32FPMulAdd));
SetDelegateInfo(dlgSoftFloat32FPMulAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulAddFpscr>(dlgSoftFloat32FPMulAddFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulSub>(dlgSoftFloat32FPMulSub));
SetDelegateInfo(dlgSoftFloat32FPMulSubFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulSubFpscr>(dlgSoftFloat32FPMulSubFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPMulX, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulX>(dlgSoftFloat32FPMulX));
SetDelegateInfo(dlgSoftFloat32FPNegMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPNegMulAdd>(dlgSoftFloat32FPNegMulAdd));
SetDelegateInfo(dlgSoftFloat32FPNegMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPNegMulSub>(dlgSoftFloat32FPNegMulSub));
SetDelegateInfo(dlgSoftFloat32FPRecipEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipEstimate>(dlgSoftFloat32FPRecipEstimate));
SetDelegateInfo(dlgSoftFloat32FPRecipEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipEstimateFpscr>(dlgSoftFloat32FPRecipEstimateFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPRecipStep, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipStep>(dlgSoftFloat32FPRecipStep)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPRecipStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipStepFused>(dlgSoftFloat32FPRecipStepFused));
SetDelegateInfo(dlgSoftFloat32FPRecpX, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecpX>(dlgSoftFloat32FPRecpX));
SetDelegateInfo(dlgSoftFloat32FPRSqrtEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtEstimate>(dlgSoftFloat32FPRSqrtEstimate));
SetDelegateInfo(dlgSoftFloat32FPRSqrtEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtEstimateFpscr>(dlgSoftFloat32FPRSqrtEstimateFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPRSqrtStep, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtStep>(dlgSoftFloat32FPRSqrtStep)); // A32 only.
SetDelegateInfo(dlgSoftFloat32FPRSqrtStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtStepFused>(dlgSoftFloat32FPRSqrtStepFused));
SetDelegateInfo(dlgSoftFloat32FPSqrt, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPSqrt>(dlgSoftFloat32FPSqrt));
SetDelegateInfo(dlgSoftFloat32FPSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPSub>(dlgSoftFloat32FPSub));
SetDelegateInfo(dlgSoftFloat32_16FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat32_16FPConvert>(dlgSoftFloat32_16FPConvert));
SetDelegateInfo(dlgSoftFloat64FPAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPAdd>(dlgSoftFloat64FPAdd));
SetDelegateInfo(dlgSoftFloat64FPAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPAddFpscr>(dlgSoftFloat64FPAddFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPCompare, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompare>(dlgSoftFloat64FPCompare));
SetDelegateInfo(dlgSoftFloat64FPCompareEQ, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareEQ>(dlgSoftFloat64FPCompareEQ));
SetDelegateInfo(dlgSoftFloat64FPCompareEQFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareEQFpscr>(dlgSoftFloat64FPCompareEQFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPCompareGE, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGE>(dlgSoftFloat64FPCompareGE));
SetDelegateInfo(dlgSoftFloat64FPCompareGEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGEFpscr>(dlgSoftFloat64FPCompareGEFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPCompareGT, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGT>(dlgSoftFloat64FPCompareGT));
SetDelegateInfo(dlgSoftFloat64FPCompareGTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGTFpscr>(dlgSoftFloat64FPCompareGTFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPCompareLE, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLE>(dlgSoftFloat64FPCompareLE));
SetDelegateInfo(dlgSoftFloat64FPCompareLEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLEFpscr>(dlgSoftFloat64FPCompareLEFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPCompareLT, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLT>(dlgSoftFloat64FPCompareLT));
SetDelegateInfo(dlgSoftFloat64FPCompareLTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLTFpscr>(dlgSoftFloat64FPCompareLTFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPDiv, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPDiv>(dlgSoftFloat64FPDiv));
SetDelegateInfo(dlgSoftFloat64FPMax, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMax>(dlgSoftFloat64FPMax));
SetDelegateInfo(dlgSoftFloat64FPMaxFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxFpscr>(dlgSoftFloat64FPMaxFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPMaxNum, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxNum>(dlgSoftFloat64FPMaxNum));
SetDelegateInfo(dlgSoftFloat64FPMaxNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxNumFpscr>(dlgSoftFloat64FPMaxNumFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPMin, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMin>(dlgSoftFloat64FPMin));
SetDelegateInfo(dlgSoftFloat64FPMinFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinFpscr>(dlgSoftFloat64FPMinFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPMinNum, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinNum>(dlgSoftFloat64FPMinNum));
SetDelegateInfo(dlgSoftFloat64FPMinNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinNumFpscr>(dlgSoftFloat64FPMinNumFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPMul, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMul>(dlgSoftFloat64FPMul));
SetDelegateInfo(dlgSoftFloat64FPMulFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulFpscr>(dlgSoftFloat64FPMulFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulAdd>(dlgSoftFloat64FPMulAdd));
SetDelegateInfo(dlgSoftFloat64FPMulAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulAddFpscr>(dlgSoftFloat64FPMulAddFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulSub>(dlgSoftFloat64FPMulSub));
SetDelegateInfo(dlgSoftFloat64FPMulSubFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulSubFpscr>(dlgSoftFloat64FPMulSubFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPMulX, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulX>(dlgSoftFloat64FPMulX));
SetDelegateInfo(dlgSoftFloat64FPNegMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPNegMulAdd>(dlgSoftFloat64FPNegMulAdd));
SetDelegateInfo(dlgSoftFloat64FPNegMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPNegMulSub>(dlgSoftFloat64FPNegMulSub));
SetDelegateInfo(dlgSoftFloat64FPRecipEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipEstimate>(dlgSoftFloat64FPRecipEstimate));
SetDelegateInfo(dlgSoftFloat64FPRecipEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipEstimateFpscr>(dlgSoftFloat64FPRecipEstimateFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPRecipStep, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipStep>(dlgSoftFloat64FPRecipStep)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPRecipStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipStepFused>(dlgSoftFloat64FPRecipStepFused));
SetDelegateInfo(dlgSoftFloat64FPRecpX, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecpX>(dlgSoftFloat64FPRecpX));
SetDelegateInfo(dlgSoftFloat64FPRSqrtEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtEstimate>(dlgSoftFloat64FPRSqrtEstimate));
SetDelegateInfo(dlgSoftFloat64FPRSqrtEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtEstimateFpscr>(dlgSoftFloat64FPRSqrtEstimateFpscr)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPRSqrtStep, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtStep>(dlgSoftFloat64FPRSqrtStep)); // A32 only.
SetDelegateInfo(dlgSoftFloat64FPRSqrtStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtStepFused>(dlgSoftFloat64FPRSqrtStepFused));
SetDelegateInfo(dlgSoftFloat64FPSqrt, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPSqrt>(dlgSoftFloat64FPSqrt));
SetDelegateInfo(dlgSoftFloat64FPSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPSub>(dlgSoftFloat64FPSub));
SetDelegateInfo(dlgSoftFloat64_16FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat64_16FPConvert>(dlgSoftFloat64_16FPConvert));
}
private delegate double MathAbs(double value);
private delegate double MathCeiling(double a);
private delegate double MathFloor(double d);
private delegate double MathRound(double value, MidpointRounding mode);
private delegate double MathTruncate(double d);
private delegate float MathFAbs(float x);
private delegate float MathFCeiling(float x);
private delegate float MathFFloor(float x);
private delegate float MathFRound(float x, MidpointRounding mode);
private delegate float MathFTruncate(float x);
private delegate void NativeInterfaceBreak(ulong address, int imm);
private delegate bool NativeInterfaceCheckSynchronization();
private delegate void NativeInterfaceEnqueueForRejit(ulong address);
private delegate ulong NativeInterfaceGetCntfrqEl0();
private delegate ulong NativeInterfaceGetCntpctEl0();
private delegate ulong NativeInterfaceGetCntvctEl0();
private delegate ulong NativeInterfaceGetCtrEl0();
private delegate ulong NativeInterfaceGetDczidEl0();
private delegate ulong NativeInterfaceGetFunctionAddress(ulong address);
private delegate void NativeInterfaceInvalidateCacheLine(ulong address);
private delegate byte NativeInterfaceReadByte(ulong address);
private delegate ushort NativeInterfaceReadUInt16(ulong address);
private delegate uint NativeInterfaceReadUInt32(ulong address);
private delegate ulong NativeInterfaceReadUInt64(ulong address);
private delegate V128 NativeInterfaceReadVector128(ulong address);
private delegate void NativeInterfaceSignalMemoryTracking(ulong address, ulong size, bool write);
private delegate void NativeInterfaceSupervisorCall(ulong address, int imm);
private delegate void NativeInterfaceThrowInvalidMemoryAccess(ulong address);
private delegate void NativeInterfaceUndefined(ulong address, int opCode);
private delegate void NativeInterfaceWriteByte(ulong address, byte value);
private delegate void NativeInterfaceWriteUInt16(ulong address, ushort value);
private delegate void NativeInterfaceWriteUInt32(ulong address, uint value);
private delegate void NativeInterfaceWriteUInt64(ulong address, ulong value);
private delegate void NativeInterfaceWriteVector128(ulong address, V128 value);
private delegate ulong SoftFallbackCountLeadingSigns(ulong value, int size);
private delegate ulong SoftFallbackCountLeadingZeros(ulong value, int size);
private delegate uint SoftFallbackCrc32b(uint crc, byte value);
private delegate uint SoftFallbackCrc32cb(uint crc, byte value);
private delegate uint SoftFallbackCrc32ch(uint crc, ushort value);
private delegate uint SoftFallbackCrc32cw(uint crc, uint value);
private delegate uint SoftFallbackCrc32cx(uint crc, ulong value);
private delegate uint SoftFallbackCrc32h(uint crc, ushort value);
private delegate uint SoftFallbackCrc32w(uint crc, uint value);
private delegate uint SoftFallbackCrc32x(uint crc, ulong value);
private delegate V128 SoftFallbackDecrypt(V128 value, V128 roundKey);
private delegate V128 SoftFallbackEncrypt(V128 value, V128 roundKey);
private delegate uint SoftFallbackFixedRotate(uint hash_e);
private delegate V128 SoftFallbackHashChoose(V128 hash_abcd, uint hash_e, V128 wk);
private delegate V128 SoftFallbackHashLower(V128 hash_abcd, V128 hash_efgh, V128 wk);
private delegate V128 SoftFallbackHashMajority(V128 hash_abcd, uint hash_e, V128 wk);
private delegate V128 SoftFallbackHashParity(V128 hash_abcd, uint hash_e, V128 wk);
private delegate V128 SoftFallbackHashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk);
private delegate V128 SoftFallbackInverseMixColumns(V128 value);
private delegate V128 SoftFallbackMixColumns(V128 value);
private delegate V128 SoftFallbackPolynomialMult64_128(ulong op1, ulong op2);
private delegate int SoftFallbackSatF32ToS32(float value);
private delegate long SoftFallbackSatF32ToS64(float value);
private delegate uint SoftFallbackSatF32ToU32(float value);
private delegate ulong SoftFallbackSatF32ToU64(float value);
private delegate int SoftFallbackSatF64ToS32(double value);
private delegate long SoftFallbackSatF64ToS64(double value);
private delegate uint SoftFallbackSatF64ToU32(double value);
private delegate ulong SoftFallbackSatF64ToU64(double value);
private delegate V128 SoftFallbackSha1SchedulePart1(V128 w0_3, V128 w4_7, V128 w8_11);
private delegate V128 SoftFallbackSha1SchedulePart2(V128 tw0_3, V128 w12_15);
private delegate V128 SoftFallbackSha256SchedulePart1(V128 w0_3, V128 w4_7);
private delegate V128 SoftFallbackSha256SchedulePart2(V128 w0_3, V128 w8_11, V128 w12_15);
private delegate long SoftFallbackSignedShrImm64(long value, long roundConst, int shift);
private delegate V128 SoftFallbackTbl1(V128 vector, int bytes, V128 tb0);
private delegate V128 SoftFallbackTbl2(V128 vector, int bytes, V128 tb0, V128 tb1);
private delegate V128 SoftFallbackTbl3(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2);
private delegate V128 SoftFallbackTbl4(V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3);
private delegate V128 SoftFallbackTbx1(V128 dest, V128 vector, int bytes, V128 tb0);
private delegate V128 SoftFallbackTbx2(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1);
private delegate V128 SoftFallbackTbx3(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2);
private delegate V128 SoftFallbackTbx4(V128 dest, V128 vector, int bytes, V128 tb0, V128 tb1, V128 tb2, V128 tb3);
private delegate ulong SoftFallbackUnsignedShrImm64(ulong value, long roundConst, int shift);
private delegate float SoftFloat16_32FPConvert(ushort valueBits);
private delegate double SoftFloat16_64FPConvert(ushort valueBits);
private delegate float SoftFloat32FPAdd(float value1, float value2);
private delegate float SoftFloat32FPAddFpscr(float value1, float value2, bool standardFpscr);
private delegate int SoftFloat32FPCompare(float value1, float value2, bool signalNaNs);
private delegate float SoftFloat32FPCompareEQ(float value1, float value2);
private delegate float SoftFloat32FPCompareEQFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPCompareGE(float value1, float value2);
private delegate float SoftFloat32FPCompareGEFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPCompareGT(float value1, float value2);
private delegate float SoftFloat32FPCompareGTFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPCompareLE(float value1, float value2);
private delegate float SoftFloat32FPCompareLEFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPCompareLT(float value1, float value2);
private delegate float SoftFloat32FPCompareLTFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPDiv(float value1, float value2);
private delegate float SoftFloat32FPMax(float value1, float value2);
private delegate float SoftFloat32FPMaxFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPMaxNum(float value1, float value2);
private delegate float SoftFloat32FPMaxNumFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPMin(float value1, float value2);
private delegate float SoftFloat32FPMinFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPMinNum(float value1, float value2);
private delegate float SoftFloat32FPMinNumFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPMul(float value1, float value2);
private delegate float SoftFloat32FPMulFpscr(float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPMulAdd(float valueA, float value1, float value2);
private delegate float SoftFloat32FPMulAddFpscr(float valueA, float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPMulSub(float valueA, float value1, float value2);
private delegate float SoftFloat32FPMulSubFpscr(float valueA, float value1, float value2, bool standardFpscr);
private delegate float SoftFloat32FPMulX(float value1, float value2);
private delegate float SoftFloat32FPNegMulAdd(float valueA, float value1, float value2);
private delegate float SoftFloat32FPNegMulSub(float valueA, float value1, float value2);
private delegate float SoftFloat32FPRecipEstimate(float value);
private delegate float SoftFloat32FPRecipEstimateFpscr(float value, bool standardFpscr);
private delegate float SoftFloat32FPRecipStep(float value1, float value2);
private delegate float SoftFloat32FPRecipStepFused(float value1, float value2);
private delegate float SoftFloat32FPRecpX(float value);
private delegate float SoftFloat32FPRSqrtEstimate(float value);
private delegate float SoftFloat32FPRSqrtEstimateFpscr(float value, bool standardFpscr);
private delegate float SoftFloat32FPRSqrtStep(float value1, float value2);
private delegate float SoftFloat32FPRSqrtStepFused(float value1, float value2);
private delegate float SoftFloat32FPSqrt(float value);
private delegate float SoftFloat32FPSub(float value1, float value2);
private delegate ushort SoftFloat32_16FPConvert(float value);
private delegate double SoftFloat64FPAdd(double value1, double value2);
private delegate double SoftFloat64FPAddFpscr(double value1, double value2, bool standardFpscr);
private delegate int SoftFloat64FPCompare(double value1, double value2, bool signalNaNs);
private delegate double SoftFloat64FPCompareEQ(double value1, double value2);
private delegate double SoftFloat64FPCompareEQFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPCompareGE(double value1, double value2);
private delegate double SoftFloat64FPCompareGEFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPCompareGT(double value1, double value2);
private delegate double SoftFloat64FPCompareGTFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPCompareLE(double value1, double value2);
private delegate double SoftFloat64FPCompareLEFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPCompareLT(double value1, double value2);
private delegate double SoftFloat64FPCompareLTFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPDiv(double value1, double value2);
private delegate double SoftFloat64FPMax(double value1, double value2);
private delegate double SoftFloat64FPMaxFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPMaxNum(double value1, double value2);
private delegate double SoftFloat64FPMaxNumFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPMin(double value1, double value2);
private delegate double SoftFloat64FPMinFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPMinNum(double value1, double value2);
private delegate double SoftFloat64FPMinNumFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPMul(double value1, double value2);
private delegate double SoftFloat64FPMulFpscr(double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPMulAdd(double valueA, double value1, double value2);
private delegate double SoftFloat64FPMulAddFpscr(double valueA, double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPMulSub(double valueA, double value1, double value2);
private delegate double SoftFloat64FPMulSubFpscr(double valueA, double value1, double value2, bool standardFpscr);
private delegate double SoftFloat64FPMulX(double value1, double value2);
private delegate double SoftFloat64FPNegMulAdd(double valueA, double value1, double value2);
private delegate double SoftFloat64FPNegMulSub(double valueA, double value1, double value2);
private delegate double SoftFloat64FPRecipEstimate(double value);
private delegate double SoftFloat64FPRecipEstimateFpscr(double value, bool standardFpscr);
private delegate double SoftFloat64FPRecipStep(double value1, double value2);
private delegate double SoftFloat64FPRecipStepFused(double value1, double value2);
private delegate double SoftFloat64FPRecpX(double value);
private delegate double SoftFloat64FPRSqrtEstimate(double value);
private delegate double SoftFloat64FPRSqrtEstimateFpscr(double value, bool standardFpscr);
private delegate double SoftFloat64FPRSqrtStep(double value1, double value2);
private delegate double SoftFloat64FPRSqrtStepFused(double value1, double value2);
private delegate double SoftFloat64FPSqrt(double value);
private delegate double SoftFloat64FPSub(double value1, double value2);
private delegate ushort SoftFloat64_16FPConvert(double value);
}
}

View File

@@ -97,7 +97,7 @@ namespace ARMeilleure.Translation
public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
{
nint funcPtr = info.MethodHandle.GetFunctionPointer();
nint funcPtr = Delegates.GetDelegateFuncPtr(info);
OperandType returnType = GetOperandType(info.ReturnType);

View File

@@ -457,7 +457,7 @@ namespace ARMeilleure.Translation
context.Store(address, count);
context.BranchIf(lblEnd, curCount, Const(MinsCallForRejit), Comparison.NotEqual, BasicBlockFrequency.Cold);
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)), Const(context.EntryAddress));
context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.EnqueueForRejit)), Const(context.EntryAddress));
context.MarkLabel(lblEnd);
}
@@ -473,7 +473,7 @@ namespace ARMeilleure.Translation
Operand count = context.Load(OperandType.I32, countAddr);
context.BranchIfTrue(lblNonZero, count, BasicBlockFrequency.Cold);
Operand running = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
Operand running = context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.CheckSynchronization)));
context.BranchIfTrue(lblExit, running, BasicBlockFrequency.Cold);
context.Return(Const(0L));

View File

@@ -4,6 +4,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation.Cache;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
@@ -181,7 +182,7 @@ namespace ARMeilleure.Translation
context.Tailcall(hostAddress, nativeContext);
context.MarkLabel(lblFallback);
hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
hostAddress = context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
context.Tailcall(hostAddress, nativeContext);
ControlFlowGraph cfg = context.GetControlFlowGraph();
@@ -206,7 +207,7 @@ namespace ARMeilleure.Translation
Operand guestAddress = context.Load(OperandType.I64,
context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())));
Operand hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
Operand hostAddress = context.Call(NativeInterface.Type.GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
context.Tailcall(hostAddress, nativeContext);
ControlFlowGraph cfg = context.GetControlFlowGraph();

View File

@@ -2,6 +2,7 @@
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -3,6 +3,7 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -4,6 +4,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -3,6 +3,7 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -6,9 +6,7 @@ namespace Ryujinx.Common.Configuration
[JsonConverter(typeof(TypedStringEnumConverter<GraphicsBackend>))]
public enum GraphicsBackend
{
Auto,
Vulkan,
OpenGl,
Metal
}
}

View File

@@ -5,15 +5,34 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Common.Helper
{
public enum OperatingSystemType
{
MacOS,
Linux,
Windows
}
public static class RunningPlatform
{
public static readonly OperatingSystemType CurrentOS
= IsMacOS
? OperatingSystemType.MacOS
: IsWindows
? OperatingSystemType.Windows
: IsLinux
? OperatingSystemType.Linux
: throw new PlatformNotSupportedException();
public static Architecture Architecture => RuntimeInformation.OSArchitecture;
public static Architecture CurrentProcessArchitecture => RuntimeInformation.ProcessArchitecture;
public static bool IsMacOS => OperatingSystem.IsMacOS();
public static bool IsWindows => OperatingSystem.IsWindows();
public static bool IsLinux => OperatingSystem.IsLinux();
public static bool IsArm => RuntimeInformation.OSArchitecture is Architecture.Arm64;
public static bool IsArm => Architecture is Architecture.Arm64;
public static bool IsX64 => RuntimeInformation.OSArchitecture is Architecture.X64;
public static bool IsX64 => Architecture is Architecture.X64;
public static bool IsIntelMac => IsMacOS && IsX64;
public static bool IsArmMac => IsMacOS && IsArm;

View File

@@ -4,6 +4,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -0,0 +1,9 @@
namespace Ryujinx.Common
{
public static class SharedConstants
{
public const string DefaultLanPlayHost = "ryuldn.vudjun.com";
public const short LanPlayPort = 30456;
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
}
}

View File

@@ -10,54 +10,6 @@ namespace Ryujinx.Common
{
public static ReactiveObject<Optional<string>> CurrentApplication { get; } = new();
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
{
switch (currentBackend)
{
case GraphicsBackend.Metal when !OperatingSystem.IsMacOS():
case GraphicsBackend.OpenGl when OperatingSystem.IsMacOS():
return GraphicsBackend.Vulkan;
case GraphicsBackend.Vulkan or GraphicsBackend.OpenGl or GraphicsBackend.Metal:
return currentBackend;
}
if (!RunningPlatform.IsArmMac)
return GraphicsBackend.Vulkan;
return GreatMetalTitles.ContainsIgnoreCase(titleId) ? GraphicsBackend.Metal : GraphicsBackend.Vulkan;
}
public static readonly string[] GreatMetalTitles =
[
"01009b500007c000", // ARMS
"0100a5c00d162000", // Cuphead
"010023800d64a000", // Deltarune
"01003a30012c0000", // LEGO City Undercover
"010048701995e000", // Luigi's Manion 2 HD
"010028600EBDA000", // Mario 3D World
"0100152000022000", // Mario Kart 8 Deluxe
"010075a016a3a000", // Persona 4 Arena Ultimax
"0100187003A36000", // Pokémon: Let's Go, Eevee!
"010003f003a34000", // Pokémon: Let's Go, Pikachu!
"01008C0016544000", // Sea of Stars
"01006A800016E000", // Smash Ultimate
"01006bb00c6f0000", // The Legend of Zelda: Link's Awakening
// These ones have small issues, but those happen on Vulkan as well:
"01006f8002326000", // Animal Crossings: New Horizons
"01009bf0072d4000", // Captain Toad: Treasure Tracker
"01009510001ca000", // Fast RMX
"01005CA01580E000", // Persona 5 Royal
"0100b880154fc000", // Persona 5 The Royal (Japan)
"010015100b514000", // Super Mario Bros. Wonder
"0100000000010000", // Super Mario Odyssey
// Further testing is appreciated, I did not test the entire game:
//"010076f0049a2000", // Bayonetta
//"0100cf5010fec000", // Bayonetta Origins: Cereza and the Lost Demon
//"0100f4300bf2c000", // New Pokemon Snap
];
public static string GetDiscordGameAsset(string titleId)
=> DiscordGameAssetKeys.Contains(titleId) ? titleId : "game";

View File

@@ -3,6 +3,7 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -2,6 +2,7 @@
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,18 +0,0 @@
namespace Ryujinx.Graphics.GAL
{
public readonly struct ComputeSize
{
public readonly static ComputeSize VtgAsCompute = new(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;
}
}
}

View File

@@ -339,84 +339,6 @@ namespace Ryujinx.Graphics.GAL
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>
/// Checks if the texture format is a depth or depth-stencil format.
/// </summary>

View File

@@ -1,4 +1,6 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL.Multithreading;
using System;
using System.Threading;
@@ -10,6 +12,20 @@ namespace Ryujinx.Graphics.GAL
bool PreferThreading { get; }
public IRenderer TryMakeThreaded(BackendThreading backendThreading = BackendThreading.Auto)
{
if (backendThreading is BackendThreading.On ||
(backendThreading is BackendThreading.Auto && PreferThreading))
{
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({backendThreading}): True");
return new ThreadedRenderer(this);
}
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({backendThreading}): False");
return this;
}
IPipeline Pipeline { get; }
IWindow Window { get; }

View File

@@ -2,16 +2,25 @@
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseAOT|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugAOT|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />

View File

@@ -4,22 +4,23 @@ namespace Ryujinx.Graphics.GAL
{
public int FragmentOutputMap { get; }
public ResourceLayout ResourceLayout { get; }
public ComputeSize ComputeLocalSize { get; }
public ProgramPipelineState? State { get; }
public bool FromCache { get; set; }
public ShaderInfo(
int fragmentOutputMap,
ResourceLayout resourceLayout,
ComputeSize computeLocalSize,
ProgramPipelineState? state,
bool fromCache = false)
public ShaderInfo(int fragmentOutputMap, ResourceLayout resourceLayout, ProgramPipelineState state, bool fromCache = false)
{
FragmentOutputMap = fragmentOutputMap;
ResourceLayout = resourceLayout;
ComputeLocalSize = computeLocalSize;
State = state;
FromCache = fromCache;
}
public ShaderInfo(int fragmentOutputMap, ResourceLayout resourceLayout, bool fromCache = false)
{
FragmentOutputMap = fragmentOutputMap;
ResourceLayout = resourceLayout;
State = null;
FromCache = fromCache;
}
}
}

View File

@@ -1,6 +1,7 @@
using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
using System;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Gpu.Engine.MME
{
@@ -52,7 +53,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
{
_executionEngine = new MacroHLE(processor, _hleFunction);
}
else if (GraphicsConfig.EnableMacroJit)
else if (GraphicsConfig.EnableMacroJit && RuntimeFeature.IsDynamicCodeSupported)
{
_executionEngine = new MacroJit();
}

View File

@@ -11,6 +11,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
/// </summary>
class VtgAsComputeContext : IDisposable
{
private const int DummyBufferSize = 16;
private readonly GpuContext _context;
/// <summary>
@@ -46,7 +48,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
1,
1,
1,
format.GetBytesPerElement(),
1,
format,
DepthStencilMode.Depth,
Target.TextureBuffer,
@@ -519,6 +521,21 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
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>
/// Gets the range for a sequential index buffer, with ever incrementing index values.
/// </summary>

View File

@@ -147,6 +147,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
{
_vacContext.VertexInfoBufferUpdater.SetVertexStride(index, 0, componentsCount);
_vacContext.VertexInfoBufferUpdater.SetVertexOffset(index, 0, 0);
SetDummyBufferTexture(_vertexAsCompute.Reservations, index, format);
continue;
}
@@ -162,12 +163,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
{
_vacContext.VertexInfoBufferUpdater.SetVertexStride(index, 0, componentsCount);
_vacContext.VertexInfoBufferUpdater.SetVertexOffset(index, 0, 0);
SetDummyBufferTexture(_vertexAsCompute.Reservations, index, format);
continue;
}
int vbStride = vertexBuffer.UnpackStride();
ulong vbSize = GetVertexBufferSize(address, endAddress.Pack(), vbStride, _indexed, instanced, _firstVertex, _count);
ulong oldVbSize = vbSize;
ulong attributeOffset = (ulong)vertexAttrib.UnpackOffset();
int componentSize = format.GetScalarSize();
@@ -340,6 +344,20 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
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>
/// Binds a vertex buffer into a buffer texture.
/// </summary>

View File

@@ -3,6 +3,7 @@
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

@@ -324,11 +324,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
bool loadHostCache = header.CodeGenVersion == CodeGenVersion;
if (context.Capabilities.Api == TargetApi.Metal)
{
loadHostCache = false;
}
int programIndex = 0;
DataEntry entry = new();
@@ -397,8 +392,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
context,
shaders,
specState.PipelineState,
specState.TransformFeedbackDescriptors != null,
specState.ComputeState.GetLocalSize());
specState.TransformFeedbackDescriptors != null);
IProgram hostProgram;
@@ -635,10 +629,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
return;
}
if (context.Capabilities.Api != TargetApi.Metal)
{
WriteHostCode(context, hostCode, program.Shaders, streams, timestamp);
}
WriteHostCode(context, hostCode, program.Shaders, streams, timestamp);
}
/// <summary>

View File

@@ -1,4 +1,3 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
@@ -367,9 +366,6 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
try
{
if (_context.Capabilities.Api == TargetApi.Metal && _context.DirtyHacks.IsEnabled(DirtyHack.ShaderTranslationDelay))
Thread.Sleep(_context.DirtyHacks[DirtyHack.ShaderTranslationDelay]);
AsyncProgramTranslation asyncTranslation = new(guestShaders, specState, programIndex, isCompute);
_asyncTranslationQueue.Add(asyncTranslation, _cancellationToken);
}
@@ -494,12 +490,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
ShaderSource[] shaderSources = new ShaderSource[compilation.TranslatedStages.Length];
ref GpuChannelComputeState computeState = ref compilation.SpecializationState.ComputeState;
ShaderInfoBuilder shaderInfoBuilder = new(
_context,
compilation.SpecializationState.TransformFeedbackDescriptors != null,
computeLocalSize: computeState.GetLocalSize());
ShaderInfoBuilder shaderInfoBuilder = new(_context, compilation.SpecializationState.TransformFeedbackDescriptors != null);
for (int index = 0; index < compilation.TranslatedStages.Length; index++)
{

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private readonly GpuAccessorState _state;
private readonly int _stageIndex;
private readonly bool _compute;
private readonly bool _isOpenGL;
private readonly bool _isVulkan;
private readonly bool _hasGeometryShader;
private readonly bool _supportsQuads;
@@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
_channel = channel;
_state = state;
_stageIndex = stageIndex;
_isOpenGL = context.Capabilities.Api == TargetApi.OpenGL;
_isVulkan = context.Capabilities.Api == TargetApi.Vulkan;
_hasGeometryShader = hasGeometryShader;
_supportsQuads = context.Capabilities.SupportsQuads;
@@ -117,10 +117,10 @@ namespace Ryujinx.Graphics.Gpu.Shader
public GpuGraphicsState QueryGraphicsState()
{
return _state.GraphicsState.CreateShaderGraphicsState(
_isOpenGL,
!_isVulkan,
_supportsQuads,
_hasGeometryShader,
!_isOpenGL || _state.GraphicsState.YNegateEnabled);
_isVulkan || _state.GraphicsState.YNegateEnabled);
}
/// <inheritdoc/>

View File

@@ -55,7 +55,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int binding;
if (_context.Capabilities.Api != TargetApi.OpenGL)
if (_context.Capabilities.Api == TargetApi.Vulkan)
{
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumUniformBuffersPerStage, "Uniform buffer");
}
@@ -71,7 +71,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int binding;
if (_context.Capabilities.Api != TargetApi.OpenGL)
if (_context.Capabilities.Api == TargetApi.Vulkan)
{
if (count == 1)
{
@@ -103,7 +103,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int binding;
if (_context.Capabilities.Api != TargetApi.OpenGL)
if (_context.Capabilities.Api == TargetApi.Vulkan)
{
binding = GetBindingFromIndex(index, _context.Capabilities.MaximumStorageBuffersPerStage, "Storage buffer");
}
@@ -119,7 +119,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int binding;
if (_context.Capabilities.Api != TargetApi.OpenGL)
if (_context.Capabilities.Api == TargetApi.Vulkan)
{
if (count == 1)
{

View File

@@ -1,5 +1,3 @@
using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Gpu.Shader
{
/// <summary>
@@ -63,14 +61,5 @@ namespace Ryujinx.Graphics.Gpu.Shader
SharedMemorySize = sharedMemorySize;
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);
}
}
}

View File

@@ -117,7 +117,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private static string GetDiskCachePath()
{
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId.ToLower(), "cache", "shader")
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader")
: null;
}
@@ -204,7 +204,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
GpuChannelComputeState computeState,
ulong gpuVa)
{
if (_cpPrograms.TryGetValue(gpuVa, out CachedShaderProgram cpShader) && IsShaderEqual(channel, poolState, computeState, cpShader, gpuVa))
if (_cpPrograms.TryGetValue(gpuVa, out var cpShader) && IsShaderEqual(channel, poolState, computeState, cpShader, gpuVa))
{
return cpShader;
}
@@ -223,11 +223,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
TranslatorContext translatorContext = DecodeComputeShader(gpuAccessor, _context.Capabilities.Api, gpuVa);
TranslatedShader translatedShader = TranslateShader(_dumper, channel, translatorContext, cachedGuestCode, asCompute: false);
ShaderSource[] shaderSourcesArray = [CreateShaderSource(translatedShader.Program)];
ShaderInfo info = ShaderInfoBuilder.BuildForCompute(
_context,
translatedShader.Program.Info,
computeState.GetLocalSize());
ShaderSource[] shaderSourcesArray = new ShaderSource[] { CreateShaderSource(translatedShader.Program) };
ShaderInfo info = ShaderInfoBuilder.BuildForCompute(_context, translatedShader.Program.Info);
IProgram hostProgram = _context.Renderer.CreateProgram(shaderSourcesArray, info);
cpShader = new CachedShaderProgram(hostProgram, specState, translatedShader.Shader);
@@ -254,8 +251,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
channel.TextureManager.UpdateRenderTargets();
RtControl rtControl = state.RtControl;
TextureMsaaMode msaaMode = state.RtMsaaMode;
var rtControl = state.RtControl;
var msaaMode = state.RtMsaaMode;
pipeline.SamplesCount = msaaMode.SamplesInX() * msaaMode.SamplesInY();
@@ -265,7 +262,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
int rtIndex = rtControl.UnpackPermutationIndex(index);
RtColorState colorState = state.RtColorState[rtIndex];
var colorState = state.RtColorState[rtIndex];
if (index >= count || colorState.Format == 0 || colorState.WidthOrStride == 0)
{
@@ -310,12 +307,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
ref GpuChannelGraphicsState graphicsState,
ShaderAddresses addresses)
{
if (_gpPrograms.TryGetValue(addresses, out CachedShaderProgram gpShaders) && IsShaderEqual(channel, ref poolState, ref graphicsState, gpShaders, addresses))
if (_gpPrograms.TryGetValue(addresses, out var gpShaders) && IsShaderEqual(channel, ref poolState, ref graphicsState, gpShaders, addresses))
{
return gpShaders;
}
if (_graphicsShaderCache.TryFind(channel, ref poolState, ref graphicsState, addresses, out gpShaders, out CachedGraphicsGuestCode cachedGuestCode))
if (_graphicsShaderCache.TryFind(channel, ref poolState, ref graphicsState, addresses, out gpShaders, out var cachedGuestCode))
{
_gpPrograms[addresses] = gpShaders;
return gpShaders;
@@ -368,7 +365,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
bool geometryToCompute = ShouldConvertGeometryToCompute(_context, geometryHasStore);
CachedShaderStage[] shaders = new CachedShaderStage[Constants.ShaderStages + 1];
List<ShaderSource> shaderSources = [];
List<ShaderSource> shaderSources = new();
TranslatorContext previousStage = null;
ShaderInfoBuilder infoBuilder = new(_context, transformFeedbackDescriptors != null, vertexToCompute);
@@ -428,8 +425,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
TranslatorContext lastInVertexPipeline = geometryToCompute ? translatorContexts[4] ?? currentStage : currentStage;
(program, ShaderProgramInfo vacInfo) = lastInVertexPipeline.GenerateVertexPassthroughForCompute();
infoBuilder.AddStageInfoVac(vacInfo);
program = lastInVertexPipeline.GenerateVertexPassthroughForCompute();
}
else
{
@@ -534,9 +530,9 @@ namespace Ryujinx.Graphics.Gpu.Shader
private ShaderAsCompute CreateHostVertexAsComputeProgram(ShaderProgram program, TranslatorContext context, bool tfEnabled)
{
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([source], info), program.Info, context.GetResourceReservations());
return new(_context.Renderer.CreateProgram(new[] { source }, info), program.Info, context.GetResourceReservations());
}
/// <summary>
@@ -586,7 +582,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
for (int i = 0; i < Constants.TotalTransformFeedbackBuffers; i++)
{
TfState tf = state.TfState[i];
var tf = state.TfState[i];
descs[i] = new TransformFeedbackDescriptor(
tf.BufferIndex,
@@ -692,7 +688,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>The generated translator context</returns>
public static TranslatorContext DecodeComputeShader(IGpuAccessor gpuAccessor, TargetApi api, ulong gpuVa)
{
TranslationOptions options = CreateTranslationOptions(api, DefaultFlags | TranslationFlags.Compute);
var options = CreateTranslationOptions(api, DefaultFlags | TranslationFlags.Compute);
return Translator.CreateContext(gpuVa, gpuAccessor, options);
}
@@ -709,7 +705,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>The generated translator context</returns>
public static TranslatorContext DecodeGraphicsShader(IGpuAccessor gpuAccessor, TargetApi api, TranslationFlags flags, ulong gpuVa)
{
TranslationOptions options = CreateTranslationOptions(api, flags);
var options = CreateTranslationOptions(api, flags);
return Translator.CreateContext(gpuVa, gpuAccessor, options);
}
@@ -735,7 +731,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
ulong cb1DataAddress = channel.BufferManager.GetGraphicsUniformBufferAddress(0, 1);
MemoryManager memoryManager = channel.MemoryManager;
var memoryManager = channel.MemoryManager;
codeA ??= memoryManager.GetSpan(vertexA.Address, vertexA.Size).ToArray();
codeB ??= memoryManager.GetSpan(currentStage.Address, currentStage.Size).ToArray();
@@ -773,7 +769,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <returns>Compiled graphics shader code</returns>
private static TranslatedShader TranslateShader(ShaderDumper dumper, GpuChannel channel, TranslatorContext context, byte[] code, bool asCompute)
{
MemoryManager memoryManager = channel.MemoryManager;
var memoryManager = channel.MemoryManager;
ulong cb1DataAddress = context.Stage == ShaderStage.Compute
? channel.BufferManager.GetComputeUniformBufferAddress(1)
@@ -801,7 +797,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
{
if (address == MemoryManager.PteUnmapped || size == 0)
{
return [];
return Array.Empty<byte>();
}
return memoryManager.Physical.GetSpan(address, size).ToArray();
@@ -826,20 +822,16 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary>
/// 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>
/// <param name="api">Target graphics API</param>
/// <param name="flags">Translation flags</param>
/// <returns>Translation options</returns>
private static TranslationOptions CreateTranslationOptions(TargetApi api, TranslationFlags flags)
{
TargetLanguage lang = api switch
{
TargetApi.OpenGL => TargetLanguage.Glsl,
TargetApi.Vulkan => GraphicsConfig.EnableSpirvCompilationOnVulkan ? TargetLanguage.Spirv : TargetLanguage.Glsl,
TargetApi.Metal => TargetLanguage.Msl,
_ => throw new NotImplementedException()
};
TargetLanguage lang = GraphicsConfig.EnableSpirvCompilationOnVulkan && api == TargetApi.Vulkan
? TargetLanguage.Spirv
: TargetLanguage.Glsl;
return new TranslationOptions(lang, api, flags);
}

View File

@@ -22,7 +22,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
ResourceStages.Geometry;
private readonly GpuContext _context;
private readonly ComputeSize _computeLocalSize;
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="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="computeLocalSize">Indicates the local thread size for a compute shader</param>
public ShaderInfoBuilder(GpuContext context, bool tfEnabled, bool vertexAsCompute = false, ComputeSize computeLocalSize = default)
public ShaderInfoBuilder(GpuContext context, bool tfEnabled, bool vertexAsCompute = false)
{
_context = context;
_computeLocalSize = computeLocalSize;
_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)
{
AddDescriptor(stages, type, setIndex, start, count);
// AddUsage(stages, type, setIndex, start, count, write);
AddUsage(stages, type, setIndex, start, count, write);
}
/// <summary>
@@ -162,25 +159,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
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>
/// Adds a resource descriptor to the list of descriptors.
/// </summary>
@@ -383,7 +361,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
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>
@@ -393,16 +378,14 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <param name="programs">Shaders from the disk cache</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="computeLocalSize">Compute local thread size</param>
/// <returns>Shader information</returns>
public static ShaderInfo BuildForCache(
GpuContext context,
IEnumerable<CachedShaderStage> programs,
ProgramPipelineState? pipeline,
bool tfEnabled,
ComputeSize computeLocalSize)
bool tfEnabled)
{
ShaderInfoBuilder builder = new(context, tfEnabled, computeLocalSize: computeLocalSize);
ShaderInfoBuilder builder = new(context, tfEnabled);
foreach (CachedShaderStage program in programs)
{
@@ -420,12 +403,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
/// <param name="context">GPU context that owns the shader</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>
/// <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);
@@ -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="fromCache">True if the compute shader comes from a disk cache, false otherwise</param>
/// <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);
return builder.Build(null, fromCache);

View File

@@ -2,6 +2,7 @@
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
<Configurations>Debug;Release;DebugAOT;ReleaseAOT</Configurations>
</PropertyGroup>
<ItemGroup>

View File

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

View File

@@ -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 (BackgroundResource resource in _resources.Values)
{
resource.Dispose();
}
}
}
}
}

View File

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

View File

@@ -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)
{
FenceHolder 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);
Auto<DisposableBuffer> srcBuffer = srcHolder.GetBuffer();
Auto<DisposableBuffer> 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)
{
MTLBuffer srcBuffer = registerSrcUsage ? src.Get(cbs, srcOffset, size).Value : src.GetUnsafe().Value;
MTLBuffer 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;
}
I8ToI16CacheKey key = new(_renderer);
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out BufferHolder 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;
}
TopologyConversionCacheKey key = new(_renderer, pattern, indexSize);
if (!_cachedConvertedBuffers.TryGetValue(offset, size, key, out BufferHolder 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();
}
}
}

View File

@@ -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.
MTLBuffer 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;
}
BufferHolder holder = new(_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)
{
MTLBuffer 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 BufferHolder 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 BufferHolder holder))
{
return holder.GetBuffer(offset, size, isWrite);
}
return null;
}
public Auto<DisposableBuffer> GetBuffer(BufferHandle handle, bool isWrite)
{
if (TryGetBuffer(handle, out BufferHolder holder))
{
return holder.GetBuffer(isWrite);
}
return null;
}
public Auto<DisposableBuffer> GetBufferI8ToI16(CommandBufferScoped cbs, BufferHandle handle, int offset, int size)
{
if (TryGetBuffer(handle, out BufferHolder 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 BufferHolder 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 BufferHolder 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 BufferHolder holder))
{
holder.SetData(offset, data, cbs);
}
}
public void Delete(BufferHandle handle)
{
if (TryGetBuffer(handle, out BufferHolder 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 (BufferHolder buffer in _buffers)
{
buffer.Dispose();
}
}
}
}

View File

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

View File

@@ -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 = [];
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 ??= []).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 = [];
_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();
}
}
}

View File

@@ -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();
MTLRenderCommandEncoder renderCommandEncoder = _encoderFactory.CreateRenderCommandEncoder();
CurrentEncoder = renderCommandEncoder;
CurrentEncoderType = EncoderType.Render;
return renderCommandEncoder;
}
private MTLBlitCommandEncoder BeginBlitPass()
{
EndCurrentPass();
using MTLBlitPassDescriptor descriptor = new();
MTLBlitCommandEncoder blitCommandEncoder = _commandBuffer.BlitCommandEncoder(descriptor);
CurrentEncoder = blitCommandEncoder;
CurrentEncoderType = EncoderType.Blit;
return blitCommandEncoder;
}
private MTLComputeCommandEncoder BeginComputePass()
{
EndCurrentPass();
MTLComputeCommandEncoder computeCommandEncoder = _encoderFactory.CreateComputeCommandEncoder();
CurrentEncoder = computeCommandEncoder;
CurrentEncoderType = EncoderType.Compute;
return computeCommandEncoder;
}
}

View File

@@ -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 = [];
Waitables = [];
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 ReservedCommandBuffer 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 ReservedCommandBuffer entry = ref _commandBuffers[i];
if (entry.InUse)
{
AddWaitable(i, waitable);
}
}
}
}
public void AddWaitable(int cbIndex, MultiFenceHolder waitable)
{
ref ReservedCommandBuffer 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 ReservedCommandBuffer 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 ReservedCommandBuffer 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 ReservedCommandBuffer 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 ReservedCommandBuffer 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--;
MTLCommandBuffer commandBuffer = entry.CommandBuffer;
commandBuffer.Commit();
int ptr = (_queuedIndexesPtr + _queuedCount) % _totalCommandBuffers;
_queuedIndexes[ptr] = cbIndex;
_queuedCount++;
}
}
private void WaitAndDecrementRef(int cbIndex)
{
ref ReservedCommandBuffer entry = ref _commandBuffers[cbIndex];
if (entry.InConsumption)
{
entry.Fence.Wait();
entry.InConsumption = false;
}
foreach (IAuto dependant in entry.Dependants)
{
dependant.DecrementReferenceCount(cbIndex);
}
foreach (MultiFenceHolder 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);
}
}
}
}

View File

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

View File

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

View File

@@ -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() { }
}
}

View File

@@ -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 MTLStencilDescriptor frontFaceStencil = new()
{
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 MTLStencilDescriptor backFaceStencil = new()
{
StencilFailureOperation = backUid.StencilFailureOperation,
DepthFailureOperation = backUid.DepthFailureOperation,
DepthStencilPassOperation = backUid.DepthStencilPassOperation,
StencilCompareFunction = backUid.StencilCompareFunction,
ReadMask = backUid.ReadMask,
WriteMask = backUid.WriteMask
};
MTLDepthStencilDescriptor mtlDescriptor = new()
{
DepthCompareFunction = descriptor.DepthCompareFunction,
DepthWriteEnabled = descriptor.DepthWriteEnabled
};
if (descriptor.StencilTestEnabled)
{
mtlDescriptor.BackFaceStencil = backFaceStencil;
mtlDescriptor.FrontFaceStencil = frontFaceStencil;
}
using (mtlDescriptor)
{
return _device.NewDepthStencilState(mtlDescriptor);
}
}
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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();
}
}
}

View File

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

View File

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

View File

@@ -1,63 +0,0 @@
using SharpMetal.Metal;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Metal
{
public struct RenderEncoderBindings
{
public List<Resource> Resources = [];
public List<BufferResource> VertexBuffers = [];
public List<BufferResource> FragmentBuffers = [];
public RenderEncoderBindings() { }
public readonly void Clear()
{
Resources.Clear();
VertexBuffers.Clear();
FragmentBuffers.Clear();
}
}
public struct ComputeEncoderBindings
{
public List<Resource> Resources = [];
public List<BufferResource> Buffers = [];
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;
}
}
}

View File

@@ -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.
RenderTargetCopy oldState = new()
{
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 Array8<ColorBlendStateUid> 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

View File

@@ -1,292 +0,0 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using SharpMetal.Metal;
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;
}
}
}

View File

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

View File

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

View File

@@ -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)
{
MTLPixelFormat 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;
}
}
}

View File

@@ -1,82 +0,0 @@
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Metal
{
static partial class HardwareInfoTools
{
private readonly static IntPtr _kCFAllocatorDefault = IntPtr.Zero;
private readonly static UInt32 _kCFStringEncodingASCII = 0x0600;
private const string IOKit = "/System/Library/Frameworks/IOKit.framework/IOKit";
private const string CoreFoundation = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation";
[LibraryImport(IOKit, StringMarshalling = StringMarshalling.Utf8)]
private static partial IntPtr IOServiceMatching(string name);
[LibraryImport(IOKit)]
private static partial IntPtr IOServiceGetMatchingService(IntPtr mainPort, IntPtr matching);
[LibraryImport(IOKit)]
private static partial IntPtr IORegistryEntryCreateCFProperty(IntPtr entry, IntPtr key, IntPtr allocator, UInt32 options);
[LibraryImport(CoreFoundation, StringMarshalling = StringMarshalling.Utf8)]
private static partial IntPtr CFStringCreateWithCString(IntPtr allocator, string cString, UInt32 encoding);
[LibraryImport(CoreFoundation)]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool CFStringGetCString(IntPtr theString, IntPtr buffer, long bufferSizes, UInt32 encoding);
[LibraryImport(CoreFoundation)]
public static partial IntPtr CFDataGetBytePtr(IntPtr theData);
static string GetNameFromId(uint id)
{
return id switch
{
0x1002 => "AMD",
0x106B => "Apple",
0x10DE => "NVIDIA",
0x13B5 => "ARM",
0x8086 => "Intel",
_ => $"0x{id:X}"
};
}
public static string GetVendor()
{
IntPtr serviceDict = IOServiceMatching("IOGPU");
IntPtr service = IOServiceGetMatchingService(IntPtr.Zero, serviceDict);
IntPtr cfString = CFStringCreateWithCString(_kCFAllocatorDefault, "vendor-id", _kCFStringEncodingASCII);
IntPtr cfProperty = IORegistryEntryCreateCFProperty(service, cfString, _kCFAllocatorDefault, 0);
byte[] buffer = new byte[4];
IntPtr bufferPtr = CFDataGetBytePtr(cfProperty);
Marshal.Copy(bufferPtr, buffer, 0, buffer.Length);
uint vendorId = BitConverter.ToUInt32(buffer);
return GetNameFromId(vendorId);
}
public static string GetModel()
{
IntPtr serviceDict = IOServiceMatching("IOGPU");
IntPtr service = IOServiceGetMatchingService(IntPtr.Zero, serviceDict);
IntPtr cfString = CFStringCreateWithCString(_kCFAllocatorDefault, "model", _kCFStringEncodingASCII);
IntPtr cfProperty = IORegistryEntryCreateCFProperty(service, cfString, _kCFAllocatorDefault, 0);
char[] buffer = new char[64];
IntPtr bufferPtr = Marshal.AllocHGlobal(buffer.Length);
if (CFStringGetCString(cfProperty, bufferPtr, buffer.Length, _kCFStringEncodingASCII))
{
string model = Marshal.PtrToStringUTF8(bufferPtr);
Marshal.FreeHGlobal(bufferPtr);
return model;
}
return string.Empty;
}
}
}

View File

@@ -1,143 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Metal
{
interface IRefEquatable<T>
{
bool Equals(ref T other);
}
class HashTableSlim<TKey, TValue> where TKey : IRefEquatable<TKey>
{
private const int TotalBuckets = 16; // Must be power of 2
private const int TotalBucketsMask = TotalBuckets - 1;
private struct Entry
{
public int Hash;
public TKey Key;
public TValue Value;
}
private struct Bucket
{
public int Length;
public Entry[] Entries;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Span<Entry> AsSpan()
{
return Entries == null ? Span<Entry>.Empty : Entries.AsSpan(0, Length);
}
}
private readonly Bucket[] _hashTable = new Bucket[TotalBuckets];
public IEnumerable<TKey> Keys
{
get
{
foreach (Bucket bucket in _hashTable)
{
for (int i = 0; i < bucket.Length; i++)
{
yield return bucket.Entries[i].Key;
}
}
}
}
public IEnumerable<TValue> Values
{
get
{
foreach (Bucket bucket in _hashTable)
{
for (int i = 0; i < bucket.Length; i++)
{
yield return bucket.Entries[i].Value;
}
}
}
}
public void Add(ref TKey key, TValue value)
{
Entry entry = new()
{
Hash = key.GetHashCode(),
Key = key,
Value = value,
};
int hashCode = key.GetHashCode();
int bucketIndex = hashCode & TotalBucketsMask;
ref Bucket bucket = ref _hashTable[bucketIndex];
if (bucket.Entries != null)
{
int index = bucket.Length;
if (index >= bucket.Entries.Length)
{
Array.Resize(ref bucket.Entries, index + 1);
}
bucket.Entries[index] = entry;
}
else
{
bucket.Entries =
[
entry
];
}
bucket.Length++;
}
public bool Remove(ref TKey key)
{
int hashCode = key.GetHashCode();
ref Bucket bucket = ref _hashTable[hashCode & TotalBucketsMask];
Span<Entry> entries = bucket.AsSpan();
for (int i = 0; i < entries.Length; i++)
{
ref Entry entry = ref entries[i];
if (entry.Hash == hashCode && entry.Key.Equals(ref key))
{
entries[(i + 1)..].CopyTo(entries[i..]);
bucket.Length--;
return true;
}
}
return false;
}
public bool TryGetValue(ref TKey key, out TValue value)
{
int hashCode = key.GetHashCode();
Span<Entry> entries = _hashTable[hashCode & TotalBucketsMask].AsSpan();
for (int i = 0; i < entries.Length; i++)
{
ref Entry entry = ref entries[i];
if (entry.Hash == hashCode && entry.Key.Equals(ref key))
{
value = entry.Value;
return true;
}
}
value = default;
return false;
}
}
}

View File

@@ -1,868 +0,0 @@
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation;
using SharpMetal.Metal;
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
class HelperShader : IDisposable
{
private const int ConvertElementsPerWorkgroup = 32 * 100; // Work group size of 32 times 100 elements.
private const string ShadersSourcePath = "/Ryujinx.Graphics.Metal/Shaders";
private readonly MetalRenderer _renderer;
private readonly Pipeline _pipeline;
private MTLDevice _device;
private readonly ISampler _samplerLinear;
private readonly ISampler _samplerNearest;
private readonly IProgram _programColorBlitF;
private readonly IProgram _programColorBlitI;
private readonly IProgram _programColorBlitU;
private readonly IProgram _programColorBlitMsF;
private readonly IProgram _programColorBlitMsI;
private readonly IProgram _programColorBlitMsU;
private readonly List<IProgram> _programsColorClearF = [];
private readonly List<IProgram> _programsColorClearI = [];
private readonly List<IProgram> _programsColorClearU = [];
private readonly IProgram _programDepthStencilClear;
private readonly IProgram _programStrideChange;
private readonly IProgram _programConvertD32S8ToD24S8;
private readonly IProgram _programConvertIndexBuffer;
private readonly IProgram _programDepthBlit;
private readonly IProgram _programDepthBlitMs;
private readonly IProgram _programStencilBlit;
private readonly IProgram _programStencilBlitMs;
private readonly EncoderState _helperShaderState = new();
public HelperShader(MTLDevice device, MetalRenderer renderer, Pipeline pipeline)
{
_device = device;
_renderer = renderer;
_pipeline = pipeline;
_samplerNearest = new SamplerHolder(renderer, _device, SamplerCreateInfo.Create(MinFilter.Nearest, MagFilter.Nearest));
_samplerLinear = new SamplerHolder(renderer, _device, SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
ResourceLayout blitResourceLayout = new ResourceLayoutBuilder()
.Add(ResourceStages.Vertex, ResourceType.UniformBuffer, 0)
.Add(ResourceStages.Fragment, ResourceType.TextureAndSampler, 0).Build();
string blitSource = ReadMsl("Blit.metal");
string blitSourceF = blitSource.Replace("FORMAT", "float", StringComparison.Ordinal);
_programColorBlitF = new Program(renderer, device, [
new ShaderSource(blitSourceF, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
string blitSourceI = blitSource.Replace("FORMAT", "int");
_programColorBlitI = new Program(renderer, device, [
new ShaderSource(blitSourceI, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitSourceI, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
string blitSourceU = blitSource.Replace("FORMAT", "uint");
_programColorBlitU = new Program(renderer, device, [
new ShaderSource(blitSourceU, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitSourceU, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
string blitMsSource = ReadMsl("BlitMs.metal");
string blitMsSourceF = blitMsSource.Replace("FORMAT", "float");
_programColorBlitMsF = new Program(renderer, device, [
new ShaderSource(blitMsSourceF, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitMsSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
string blitMsSourceI = blitMsSource.Replace("FORMAT", "int");
_programColorBlitMsI = new Program(renderer, device, [
new ShaderSource(blitMsSourceI, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitMsSourceI, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
string blitMsSourceU = blitMsSource.Replace("FORMAT", "uint");
_programColorBlitMsU = new Program(renderer, device, [
new ShaderSource(blitMsSourceU, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitMsSourceU, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
ResourceLayout colorClearResourceLayout = new ResourceLayoutBuilder()
.Add(ResourceStages.Fragment, ResourceType.UniformBuffer, 0).Build();
string colorClearSource = ReadMsl("ColorClear.metal");
for (int i = 0; i < Constants.MaxColorAttachments; i++)
{
string crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "float");
_programsColorClearF.Add(new Program(renderer, device, [
new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl)
], colorClearResourceLayout));
}
for (int i = 0; i < Constants.MaxColorAttachments; i++)
{
string crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "int");
_programsColorClearI.Add(new Program(renderer, device, [
new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl)
], colorClearResourceLayout));
}
for (int i = 0; i < Constants.MaxColorAttachments; i++)
{
string crntSource = colorClearSource.Replace("COLOR_ATTACHMENT_INDEX", i.ToString()).Replace("FORMAT", "uint");
_programsColorClearU.Add(new Program(renderer, device, [
new ShaderSource(crntSource, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(crntSource, ShaderStage.Vertex, TargetLanguage.Msl)
], colorClearResourceLayout));
}
string depthStencilClearSource = ReadMsl("DepthStencilClear.metal");
_programDepthStencilClear = new Program(renderer, device, [
new ShaderSource(depthStencilClearSource, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(depthStencilClearSource, ShaderStage.Vertex, TargetLanguage.Msl)
], colorClearResourceLayout);
ResourceLayout strideChangeResourceLayout = new ResourceLayoutBuilder()
.Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0)
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1)
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true).Build();
string strideChangeSource = ReadMsl("ChangeBufferStride.metal");
_programStrideChange = new Program(renderer, device, [
new ShaderSource(strideChangeSource, ShaderStage.Compute, TargetLanguage.Msl)
], strideChangeResourceLayout, new ComputeSize(64, 1, 1));
ResourceLayout convertD32S8ToD24S8ResourceLayout = new ResourceLayoutBuilder()
.Add(ResourceStages.Compute, ResourceType.UniformBuffer, 0)
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1)
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true).Build();
string convertD32S8ToD24S8Source = ReadMsl("ConvertD32S8ToD24S8.metal");
_programConvertD32S8ToD24S8 = new Program(renderer, device, [
new ShaderSource(convertD32S8ToD24S8Source, ShaderStage.Compute, TargetLanguage.Msl)
], convertD32S8ToD24S8ResourceLayout, new ComputeSize(64, 1, 1));
ResourceLayout convertIndexBufferLayout = new ResourceLayoutBuilder()
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 1)
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 2, true)
.Add(ResourceStages.Compute, ResourceType.StorageBuffer, 3).Build();
string convertIndexBufferSource = ReadMsl("ConvertIndexBuffer.metal");
_programConvertIndexBuffer = new Program(renderer, device, [
new ShaderSource(convertIndexBufferSource, ShaderStage.Compute, TargetLanguage.Msl)
], convertIndexBufferLayout, new ComputeSize(16, 1, 1));
string depthBlitSource = ReadMsl("DepthBlit.metal");
_programDepthBlit = new Program(renderer, device, [
new ShaderSource(depthBlitSource, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
string depthBlitMsSource = ReadMsl("DepthBlitMs.metal");
_programDepthBlitMs = new Program(renderer, device, [
new ShaderSource(depthBlitMsSource, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
string stencilBlitSource = ReadMsl("StencilBlit.metal");
_programStencilBlit = new Program(renderer, device, [
new ShaderSource(stencilBlitSource, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
string stencilBlitMsSource = ReadMsl("StencilBlitMs.metal");
_programStencilBlitMs = new Program(renderer, device, [
new ShaderSource(stencilBlitMsSource, ShaderStage.Fragment, TargetLanguage.Msl),
new ShaderSource(blitSourceF, ShaderStage.Vertex, TargetLanguage.Msl)
], blitResourceLayout);
}
private static string ReadMsl(string fileName)
{
string msl = EmbeddedResources.ReadAllText(string.Join('/', ShadersSourcePath, fileName));
#pragma warning disable IDE0055 // Disable formatting
msl = msl.Replace("CONSTANT_BUFFERS_INDEX", $"{Constants.ConstantBuffersIndex}")
.Replace("STORAGE_BUFFERS_INDEX", $"{Constants.StorageBuffersIndex}")
.Replace("TEXTURES_INDEX", $"{Constants.TexturesIndex}")
.Replace("IMAGES_INDEX", $"{Constants.ImagesIndex}");
#pragma warning restore IDE0055
return msl;
}
public unsafe void BlitColor(
CommandBufferScoped cbs,
Texture src,
Texture dst,
Extents2D srcRegion,
Extents2D dstRegion,
bool linearFilter,
bool clear = false)
{
_pipeline.SwapState(_helperShaderState);
const int RegionBufferSize = 16;
ISampler sampler = linearFilter ? _samplerLinear : _samplerNearest;
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, sampler);
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
region[0] = srcRegion.X1 / (float)src.Width;
region[1] = srcRegion.X2 / (float)src.Width;
region[2] = srcRegion.Y1 / (float)src.Height;
region[3] = srcRegion.Y2 / (float)src.Height;
if (dstRegion.X1 > dstRegion.X2)
{
(region[0], region[1]) = (region[1], region[0]);
}
if (dstRegion.Y1 > dstRegion.Y2)
{
(region[2], region[3]) = (region[3], region[2]);
}
using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(cbs, RegionBufferSize);
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, region);
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
Rectangle<float> rect = new(
MathF.Min(dstRegion.X1, dstRegion.X2),
MathF.Min(dstRegion.Y1, dstRegion.Y2),
MathF.Abs(dstRegion.X2 - dstRegion.X1),
MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
Span<Viewport> viewports = stackalloc Viewport[16];
viewports[0] = new Viewport(
rect,
ViewportSwizzle.PositiveX,
ViewportSwizzle.PositiveY,
ViewportSwizzle.PositiveZ,
ViewportSwizzle.PositiveW,
0f,
1f);
bool dstIsDepthOrStencil = dst.Info.Format.IsDepthOrStencil();
if (dstIsDepthOrStencil)
{
// TODO: Depth & stencil blit!
Logger.Warning?.PrintMsg(LogClass.Gpu, "Requested a depth or stencil blit!");
_pipeline.SwapState(null);
return;
}
string debugGroupName = "Blit Color ";
if (src.Info.Target.IsMultisample())
{
if (dst.Info.Format.IsSint())
{
debugGroupName += "MS Int";
_pipeline.SetProgram(_programColorBlitMsI);
}
else if (dst.Info.Format.IsUint())
{
debugGroupName += "MS UInt";
_pipeline.SetProgram(_programColorBlitMsU);
}
else
{
debugGroupName += "MS Float";
_pipeline.SetProgram(_programColorBlitMsF);
}
}
else
{
if (dst.Info.Format.IsSint())
{
debugGroupName += "Int";
_pipeline.SetProgram(_programColorBlitI);
}
else if (dst.Info.Format.IsUint())
{
debugGroupName += "UInt";
_pipeline.SetProgram(_programColorBlitU);
}
else
{
debugGroupName += "Float";
_pipeline.SetProgram(_programColorBlitF);
}
}
int dstWidth = dst.Width;
int dstHeight = dst.Height;
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[16];
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
_pipeline.SetRenderTargets([dst], null);
_pipeline.SetScissors(scissors);
_pipeline.SetClearLoadAction(clear);
_pipeline.SetViewports(viewports);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
_pipeline.Draw(4, 1, 0, 0, debugGroupName);
// Cleanup
if (clear)
{
_pipeline.SetClearLoadAction(false);
}
// Restore previous state
_pipeline.SwapState(null);
}
public unsafe void BlitDepthStencil(
CommandBufferScoped cbs,
Texture src,
Texture dst,
Extents2D srcRegion,
Extents2D dstRegion)
{
_pipeline.SwapState(_helperShaderState);
const int RegionBufferSize = 16;
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
region[0] = srcRegion.X1 / (float)src.Width;
region[1] = srcRegion.X2 / (float)src.Width;
region[2] = srcRegion.Y1 / (float)src.Height;
region[3] = srcRegion.Y2 / (float)src.Height;
if (dstRegion.X1 > dstRegion.X2)
{
(region[0], region[1]) = (region[1], region[0]);
}
if (dstRegion.Y1 > dstRegion.Y2)
{
(region[2], region[3]) = (region[3], region[2]);
}
using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(cbs, RegionBufferSize);
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, region);
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
Span<Viewport> viewports = stackalloc Viewport[16];
Rectangle<float> rect = new(
MathF.Min(dstRegion.X1, dstRegion.X2),
MathF.Min(dstRegion.Y1, dstRegion.Y2),
MathF.Abs(dstRegion.X2 - dstRegion.X1),
MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
viewports[0] = new Viewport(
rect,
ViewportSwizzle.PositiveX,
ViewportSwizzle.PositiveY,
ViewportSwizzle.PositiveZ,
ViewportSwizzle.PositiveW,
0f,
1f);
int dstWidth = dst.Width;
int dstHeight = dst.Height;
Span<Rectangle<int>> scissors = stackalloc Rectangle<int>[16];
scissors[0] = new Rectangle<int>(0, 0, dstWidth, dstHeight);
_pipeline.SetRenderTargets([], dst);
_pipeline.SetScissors(scissors);
_pipeline.SetViewports(viewports);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
if (src.Info.Format is
Format.D16Unorm or
Format.D32Float or
Format.X8UintD24Unorm or
Format.D24UnormS8Uint or
Format.D32FloatS8Uint or
Format.S8UintD24Unorm)
{
Texture depthTexture = CreateDepthOrStencilView(src, DepthStencilMode.Depth);
BlitDepthStencilDraw(depthTexture, isDepth: true);
if (depthTexture != src)
{
depthTexture.Release();
}
}
if (src.Info.Format is
Format.S8Uint or
Format.D24UnormS8Uint or
Format.D32FloatS8Uint or
Format.S8UintD24Unorm)
{
Texture stencilTexture = CreateDepthOrStencilView(src, DepthStencilMode.Stencil);
BlitDepthStencilDraw(stencilTexture, isDepth: false);
if (stencilTexture != src)
{
stencilTexture.Release();
}
}
// Restore previous state
_pipeline.SwapState(null);
}
private static Texture CreateDepthOrStencilView(Texture depthStencilTexture, DepthStencilMode depthStencilMode)
{
if (depthStencilTexture.Info.DepthStencilMode == depthStencilMode)
{
return depthStencilTexture;
}
return (Texture)depthStencilTexture.CreateView(new TextureCreateInfo(
depthStencilTexture.Info.Width,
depthStencilTexture.Info.Height,
depthStencilTexture.Info.Depth,
depthStencilTexture.Info.Levels,
depthStencilTexture.Info.Samples,
depthStencilTexture.Info.BlockWidth,
depthStencilTexture.Info.BlockHeight,
depthStencilTexture.Info.BytesPerPixel,
depthStencilTexture.Info.Format,
depthStencilMode,
depthStencilTexture.Info.Target,
SwizzleComponent.Red,
SwizzleComponent.Green,
SwizzleComponent.Blue,
SwizzleComponent.Alpha), 0, 0);
}
private void BlitDepthStencilDraw(Texture src, bool isDepth)
{
// TODO: Check this https://github.com/Ryujinx/Ryujinx/pull/5003/
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, _samplerNearest);
string debugGroupName;
if (isDepth)
{
debugGroupName = "Depth Blit";
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, true, CompareOp.Always));
}
else
{
debugGroupName = "Stencil Blit";
_pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programStencilBlitMs : _programStencilBlit);
_pipeline.SetStencilTest(CreateStencilTestDescriptor(true));
}
_pipeline.Draw(4, 1, 0, 0, debugGroupName);
if (isDepth)
{
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
}
else
{
_pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
}
}
public unsafe void DrawTexture(
ITexture src,
ISampler srcSampler,
Extents2DF srcRegion,
Extents2DF dstRegion)
{
// Save current state
PredrawState state = _pipeline.SavePredrawState();
_pipeline.SetFaceCulling(false, Face.Front);
_pipeline.SetStencilTest(new StencilTestDescriptor());
_pipeline.SetDepthTest(new DepthTestDescriptor());
const int RegionBufferSize = 16;
_pipeline.SetTextureAndSampler(ShaderStage.Fragment, 0, src, srcSampler);
Span<float> region = stackalloc float[RegionBufferSize / sizeof(float)];
region[0] = srcRegion.X1 / src.Width;
region[1] = srcRegion.X2 / src.Width;
region[2] = srcRegion.Y1 / src.Height;
region[3] = srcRegion.Y2 / src.Height;
if (dstRegion.X1 > dstRegion.X2)
{
(region[0], region[1]) = (region[1], region[0]);
}
if (dstRegion.Y1 > dstRegion.Y2)
{
(region[2], region[3]) = (region[3], region[2]);
}
BufferHandle bufferHandle = _renderer.BufferManager.CreateWithHandle(RegionBufferSize);
_renderer.BufferManager.SetData<float>(bufferHandle, 0, region);
_pipeline.SetUniformBuffers([new BufferAssignment(0, new BufferRange(bufferHandle, 0, RegionBufferSize))]);
Span<Viewport> viewports = stackalloc Viewport[16];
Rectangle<float> rect = new(
MathF.Min(dstRegion.X1, dstRegion.X2),
MathF.Min(dstRegion.Y1, dstRegion.Y2),
MathF.Abs(dstRegion.X2 - dstRegion.X1),
MathF.Abs(dstRegion.Y2 - dstRegion.Y1));
viewports[0] = new Viewport(
rect,
ViewportSwizzle.PositiveX,
ViewportSwizzle.PositiveY,
ViewportSwizzle.PositiveZ,
ViewportSwizzle.PositiveW,
0f,
1f);
_pipeline.SetProgram(_programColorBlitF);
_pipeline.SetViewports(viewports);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
_pipeline.Draw(4, 1, 0, 0, "Draw Texture");
_renderer.BufferManager.Delete(bufferHandle);
// Restore previous state
_pipeline.RestorePredrawState(state);
}
public void ConvertI8ToI16(CommandBufferScoped cbs, BufferHolder src, BufferHolder dst, int srcOffset, int size)
{
ChangeStride(cbs, src, dst, srcOffset, size, 1, 2);
}
public unsafe void ChangeStride(
CommandBufferScoped cbs,
BufferHolder src,
BufferHolder dst,
int srcOffset,
int size,
int stride,
int newStride)
{
int elems = size / stride;
Auto<DisposableBuffer> srcBuffer = src.GetBuffer();
Auto<DisposableBuffer> dstBuffer = dst.GetBuffer();
const int ParamsBufferSize = 4 * sizeof(int);
// Save current state
_pipeline.SwapState(_helperShaderState);
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
shaderParams[0] = stride;
shaderParams[1] = newStride;
shaderParams[2] = size;
shaderParams[3] = srcOffset;
using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(cbs, ParamsBufferSize);
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
sbRanges[0] = srcBuffer;
sbRanges[1] = dstBuffer;
_pipeline.SetStorageBuffers(1, sbRanges);
_pipeline.SetProgram(_programStrideChange);
_pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1, "Change Stride");
// Restore previous state
_pipeline.SwapState(null);
}
public unsafe void ConvertD32S8ToD24S8(CommandBufferScoped cbs, BufferHolder src, Auto<DisposableBuffer> dstBuffer, int pixelCount, int dstOffset)
{
int inSize = pixelCount * 2 * sizeof(int);
Auto<DisposableBuffer> srcBuffer = src.GetBuffer();
const int ParamsBufferSize = sizeof(int) * 2;
// Save current state
_pipeline.SwapState(_helperShaderState);
Span<int> shaderParams = stackalloc int[2];
shaderParams[0] = pixelCount;
shaderParams[1] = dstOffset;
using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(cbs, ParamsBufferSize);
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
sbRanges[0] = srcBuffer;
sbRanges[1] = dstBuffer;
_pipeline.SetStorageBuffers(1, sbRanges);
_pipeline.SetProgram(_programConvertD32S8ToD24S8);
_pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1, "D32S8 to D24S8 Conversion");
// Restore previous state
_pipeline.SwapState(null);
}
public void ConvertIndexBuffer(
CommandBufferScoped cbs,
BufferHolder src,
BufferHolder dst,
IndexBufferPattern pattern,
int indexSize,
int srcOffset,
int indexCount)
{
// TODO: Support conversion with primitive restart enabled.
int primitiveCount = pattern.GetPrimitiveCount(indexCount);
int outputIndexSize = 4;
Auto<DisposableBuffer> srcBuffer = src.GetBuffer();
Auto<DisposableBuffer> dstBuffer = dst.GetBuffer();
const int ParamsBufferSize = 16 * sizeof(int);
// Save current state
_pipeline.SwapState(_helperShaderState);
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
shaderParams[8] = pattern.PrimitiveVertices;
shaderParams[9] = pattern.PrimitiveVerticesOut;
shaderParams[10] = indexSize;
shaderParams[11] = outputIndexSize;
shaderParams[12] = pattern.BaseIndex;
shaderParams[13] = pattern.IndexStride;
shaderParams[14] = srcOffset;
shaderParams[15] = primitiveCount;
pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
using ScopedTemporaryBuffer patternScoped = _renderer.BufferManager.ReserveOrCreate(cbs, ParamsBufferSize);
patternScoped.Holder.SetDataUnchecked<int>(patternScoped.Offset, shaderParams);
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
sbRanges[0] = srcBuffer;
sbRanges[1] = dstBuffer;
_pipeline.SetStorageBuffers(1, sbRanges);
_pipeline.SetStorageBuffers([new BufferAssignment(3, patternScoped.Range)]);
_pipeline.SetProgram(_programConvertIndexBuffer);
_pipeline.DispatchCompute(BitUtils.DivRoundUp(primitiveCount, 16), 1, 1, "Convert Index Buffer");
// Restore previous state
_pipeline.SwapState(null);
}
public unsafe void ClearColor(
int index,
ReadOnlySpan<float> clearColor,
uint componentMask,
int dstWidth,
int dstHeight,
Format format)
{
// Keep original scissor
DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors);
// Save current state
EncoderState originalState = _pipeline.SwapState(_helperShaderState, clearFlags, false);
// Inherit some state without fully recreating render pipeline.
RenderTargetCopy save = _helperShaderState.InheritForClear(originalState, false, index);
const int ClearColorBufferSize = 16;
// TODO: Flush
using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(_pipeline.Cbs, ClearColorBufferSize);
buffer.Holder.SetDataUnchecked(buffer.Offset, clearColor);
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
Span<Viewport> viewports = stackalloc Viewport[16];
// TODO: Set exact viewport!
viewports[0] = new Viewport(
new Rectangle<float>(0, 0, dstWidth, dstHeight),
ViewportSwizzle.PositiveX,
ViewportSwizzle.PositiveY,
ViewportSwizzle.PositiveZ,
ViewportSwizzle.PositiveW,
0f,
1f);
Span<uint> componentMasks = stackalloc uint[index + 1];
componentMasks[index] = componentMask;
string debugGroupName = "Clear Color ";
if (format.IsSint())
{
debugGroupName += "Int";
_pipeline.SetProgram(_programsColorClearI[index]);
}
else if (format.IsUint())
{
debugGroupName += "UInt";
_pipeline.SetProgram(_programsColorClearU[index]);
}
else
{
debugGroupName += "Float";
_pipeline.SetProgram(_programsColorClearF[index]);
}
_pipeline.SetBlendState(index, new BlendDescriptor());
_pipeline.SetFaceCulling(false, Face.Front);
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
_pipeline.SetRenderTargetColorMasks(componentMasks);
_pipeline.SetViewports(viewports);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
_pipeline.Draw(4, 1, 0, 0, debugGroupName);
// Restore previous state
_pipeline.SwapState(null, clearFlags, false);
_helperShaderState.Restore(save);
}
public unsafe void ClearDepthStencil(
float depthValue,
bool depthMask,
int stencilValue,
int stencilMask,
int dstWidth,
int dstHeight)
{
// Keep original scissor
DirtyFlags clearFlags = DirtyFlags.All & (~DirtyFlags.Scissors);
MTLScissorRect[] helperScissors = _helperShaderState.Scissors;
// Save current state
EncoderState originalState = _pipeline.SwapState(_helperShaderState, clearFlags, false);
// Inherit some state without fully recreating render pipeline.
RenderTargetCopy save = _helperShaderState.InheritForClear(originalState, true);
const int ClearDepthBufferSize = 16;
using ScopedTemporaryBuffer buffer = _renderer.BufferManager.ReserveOrCreate(_pipeline.Cbs, ClearDepthBufferSize);
buffer.Holder.SetDataUnchecked(buffer.Offset, new ReadOnlySpan<float>(ref depthValue));
_pipeline.SetUniformBuffers([new BufferAssignment(0, buffer.Range)]);
Span<Viewport> viewports = stackalloc Viewport[1];
viewports[0] = new Viewport(
new Rectangle<float>(0, 0, dstWidth, dstHeight),
ViewportSwizzle.PositiveX,
ViewportSwizzle.PositiveY,
ViewportSwizzle.PositiveZ,
ViewportSwizzle.PositiveW,
0f,
1f);
_pipeline.SetProgram(_programDepthStencilClear);
_pipeline.SetFaceCulling(false, Face.Front);
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
_pipeline.SetViewports(viewports);
_pipeline.SetDepthTest(new DepthTestDescriptor(true, depthMask, CompareOp.Always));
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xFF, stencilMask));
_pipeline.Draw(4, 1, 0, 0, "Clear Depth Stencil");
// Cleanup
_pipeline.SetDepthTest(new DepthTestDescriptor(false, false, CompareOp.Always));
_pipeline.SetStencilTest(CreateStencilTestDescriptor(false));
// Restore previous state
_pipeline.SwapState(null, clearFlags, false);
_helperShaderState.Restore(save);
}
private static StencilTestDescriptor CreateStencilTestDescriptor(
bool enabled,
int refValue = 0,
int compareMask = 0xff,
int writeMask = 0xff)
{
return new StencilTestDescriptor(
enabled,
CompareOp.Always,
StencilOp.Replace,
StencilOp.Replace,
StencilOp.Replace,
refValue,
compareMask,
writeMask,
CompareOp.Always,
StencilOp.Replace,
StencilOp.Replace,
StencilOp.Replace,
refValue,
compareMask,
writeMask);
}
public void Dispose()
{
_programColorBlitF.Dispose();
_programColorBlitI.Dispose();
_programColorBlitU.Dispose();
_programColorBlitMsF.Dispose();
_programColorBlitMsI.Dispose();
_programColorBlitMsU.Dispose();
foreach (IProgram programColorClear in _programsColorClearF)
{
programColorClear.Dispose();
}
foreach (IProgram programColorClear in _programsColorClearU)
{
programColorClear.Dispose();
}
foreach (IProgram programColorClear in _programsColorClearI)
{
programColorClear.Dispose();
}
_programDepthStencilClear.Dispose();
_pipeline.Dispose();
_samplerLinear.Dispose();
_samplerNearest.Dispose();
}
}
}

View File

@@ -1,121 +0,0 @@
using System;
using System.Collections.Generic;
namespace Ryujinx.Graphics.Metal
{
class IdList<T> where T : class
{
private readonly List<T> _list;
private int _freeMin;
public IdList()
{
_list = [];
_freeMin = 0;
}
public int Add(T value)
{
int id;
int count = _list.Count;
id = _list.IndexOf(null, _freeMin);
if ((uint)id < (uint)count)
{
_list[id] = value;
}
else
{
id = count;
_freeMin = id + 1;
_list.Add(value);
}
return id + 1;
}
public void Remove(int id)
{
id--;
int count = _list.Count;
if ((uint)id >= (uint)count)
{
return;
}
if (id + 1 == count)
{
// Trim unused items.
int removeIndex = id;
while (removeIndex > 0 && _list[removeIndex - 1] == null)
{
removeIndex--;
}
_list.RemoveRange(removeIndex, count - removeIndex);
if (_freeMin > removeIndex)
{
_freeMin = removeIndex;
}
}
else
{
_list[id] = null;
if (_freeMin > id)
{
_freeMin = id;
}
}
}
public bool TryGetValue(int id, out T value)
{
id--;
try
{
if ((uint)id < (uint)_list.Count)
{
value = _list[id];
return value != null;
}
value = null;
return false;
}
catch (ArgumentOutOfRangeException)
{
value = null;
return false;
}
catch (IndexOutOfRangeException)
{
value = null;
return false;
}
}
public void Clear()
{
_list.Clear();
_freeMin = 0;
}
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < _list.Count; i++)
{
if (_list[i] != null)
{
yield return _list[i];
}
}
}
}
}

View File

@@ -1,74 +0,0 @@
using Ryujinx.Graphics.GAL;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
internal class ImageArray : IImageArray
{
private readonly TextureRef[] _textureRefs;
private readonly TextureBuffer[] _bufferTextureRefs;
private readonly bool _isBuffer;
private readonly Pipeline _pipeline;
public ImageArray(int size, bool isBuffer, Pipeline pipeline)
{
if (isBuffer)
{
_bufferTextureRefs = new TextureBuffer[size];
}
else
{
_textureRefs = new TextureRef[size];
}
_isBuffer = isBuffer;
_pipeline = pipeline;
}
public void SetImages(int index, ITexture[] images)
{
for (int i = 0; i < images.Length; i++)
{
ITexture image = images[i];
if (image is TextureBuffer textureBuffer)
{
_bufferTextureRefs[index + i] = textureBuffer;
}
else if (image is Texture texture)
{
_textureRefs[index + i].Storage = texture;
}
else if (!_isBuffer)
{
_textureRefs[index + i].Storage = null;
}
else
{
_bufferTextureRefs[index + i] = null;
}
}
SetDirty();
}
public TextureRef[] GetTextureRefs()
{
return _textureRefs;
}
public TextureBuffer[] GetBufferTextureRefs()
{
return _bufferTextureRefs;
}
private void SetDirty()
{
_pipeline.DirtyImages();
}
public void Dispose() { }
}
}

View File

@@ -1,118 +0,0 @@
using Ryujinx.Graphics.GAL;
using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
internal class IndexBufferPattern : IDisposable
{
public int PrimitiveVertices { get; }
public int PrimitiveVerticesOut { get; }
public int BaseIndex { get; }
public int[] OffsetIndex { get; }
public int IndexStride { get; }
public bool RepeatStart { get; }
private readonly MetalRenderer _renderer;
private int _currentSize;
private BufferHandle _repeatingBuffer;
public IndexBufferPattern(MetalRenderer renderer,
int primitiveVertices,
int primitiveVerticesOut,
int baseIndex,
int[] offsetIndex,
int indexStride,
bool repeatStart)
{
PrimitiveVertices = primitiveVertices;
PrimitiveVerticesOut = primitiveVerticesOut;
BaseIndex = baseIndex;
OffsetIndex = offsetIndex;
IndexStride = indexStride;
RepeatStart = repeatStart;
_renderer = renderer;
}
public int GetPrimitiveCount(int vertexCount)
{
return Math.Max(0, (vertexCount - BaseIndex) / IndexStride);
}
public int GetConvertedCount(int indexCount)
{
int primitiveCount = GetPrimitiveCount(indexCount);
return primitiveCount * OffsetIndex.Length;
}
public BufferHandle GetRepeatingBuffer(int vertexCount, out int indexCount)
{
int primitiveCount = GetPrimitiveCount(vertexCount);
indexCount = primitiveCount * PrimitiveVerticesOut;
int expectedSize = primitiveCount * OffsetIndex.Length;
if (expectedSize <= _currentSize && _repeatingBuffer != BufferHandle.Null)
{
return _repeatingBuffer;
}
// Expand the repeating pattern to the number of requested primitives.
BufferHandle newBuffer = _renderer.BufferManager.CreateWithHandle(expectedSize * sizeof(int));
// Copy the old data to the new one.
if (_repeatingBuffer != BufferHandle.Null)
{
_renderer.Pipeline.CopyBuffer(_repeatingBuffer, newBuffer, 0, 0, _currentSize * sizeof(int));
_renderer.BufferManager.Delete(_repeatingBuffer);
}
_repeatingBuffer = newBuffer;
// Add the additional repeats on top.
int newPrimitives = primitiveCount;
int oldPrimitives = (_currentSize) / OffsetIndex.Length;
int[] newData;
newPrimitives -= oldPrimitives;
newData = new int[expectedSize - _currentSize];
int outOffset = 0;
int index = oldPrimitives * IndexStride + BaseIndex;
for (int i = 0; i < newPrimitives; i++)
{
if (RepeatStart)
{
// Used for triangle fan
newData[outOffset++] = 0;
}
for (int j = RepeatStart ? 1 : 0; j < OffsetIndex.Length; j++)
{
newData[outOffset++] = index + OffsetIndex[j];
}
index += IndexStride;
}
_renderer.SetBufferData(newBuffer, _currentSize * sizeof(int), MemoryMarshal.Cast<int, byte>(newData));
_currentSize = expectedSize;
return newBuffer;
}
public void Dispose()
{
if (_repeatingBuffer != BufferHandle.Null)
{
_renderer.BufferManager.Delete(_repeatingBuffer);
_repeatingBuffer = BufferHandle.Null;
}
}
}
}

View File

@@ -1,103 +0,0 @@
using Ryujinx.Graphics.GAL;
using SharpMetal.Metal;
using System;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
readonly internal struct IndexBufferState
{
public static IndexBufferState Null => new(BufferHandle.Null, 0, 0);
private readonly int _offset;
private readonly int _size;
private readonly IndexType _type;
private readonly BufferHandle _handle;
public IndexBufferState(BufferHandle handle, int offset, int size, IndexType type = IndexType.UInt)
{
_handle = handle;
_offset = offset;
_size = size;
_type = type;
}
public (MTLBuffer, int, MTLIndexType) GetIndexBuffer(MetalRenderer renderer, CommandBufferScoped cbs)
{
Auto<DisposableBuffer> autoBuffer;
int offset, size;
MTLIndexType type;
if (_type == IndexType.UByte)
{
// Index type is not supported. Convert to I16.
autoBuffer = renderer.BufferManager.GetBufferI8ToI16(cbs, _handle, _offset, _size);
type = MTLIndexType.UInt16;
offset = 0;
size = _size * 2;
}
else
{
autoBuffer = renderer.BufferManager.GetBuffer(_handle, false, out int bufferSize);
if (_offset >= bufferSize)
{
autoBuffer = null;
}
type = _type.Convert();
offset = _offset;
size = _size;
}
if (autoBuffer != null)
{
DisposableBuffer buffer = autoBuffer.Get(cbs, offset, size);
return (buffer.Value, offset, type);
}
return (new MTLBuffer(IntPtr.Zero), 0, MTLIndexType.UInt16);
}
public (MTLBuffer, int, MTLIndexType) GetConvertedIndexBuffer(
MetalRenderer renderer,
CommandBufferScoped cbs,
int firstIndex,
int indexCount,
int convertedCount,
IndexBufferPattern pattern)
{
// Convert the index buffer using the given pattern.
int indexSize = GetIndexSize();
int firstIndexOffset = firstIndex * indexSize;
Auto<DisposableBuffer> autoBuffer = renderer.BufferManager.GetBufferTopologyConversion(cbs, _handle, _offset + firstIndexOffset, indexCount * indexSize, pattern, indexSize);
int size = convertedCount * 4;
if (autoBuffer != null)
{
DisposableBuffer buffer = autoBuffer.Get(cbs, 0, size);
return (buffer.Value, 0, MTLIndexType.UInt32);
}
return (new MTLBuffer(IntPtr.Zero), 0, MTLIndexType.UInt32);
}
private int GetIndexSize()
{
return _type switch
{
IndexType.UInt => 4,
IndexType.UShort => 2,
_ => 1,
};
}
}
}

View File

@@ -1,312 +0,0 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader.Translation;
using SharpMetal.Metal;
using SharpMetal.QuartzCore;
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
public sealed class MetalRenderer : IRenderer
{
public const int TotalSets = 4;
private readonly MTLDevice _device;
private readonly MTLCommandQueue _queue;
private readonly Func<CAMetalLayer> _getMetalLayer;
private Pipeline _pipeline;
private Window _window;
public uint ProgramCount { get; set; }
#pragma warning disable CS0067 // The event is never used
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
#pragma warning restore CS0067
public bool PreferThreading => true;
public IPipeline Pipeline => _pipeline;
public IWindow Window => _window;
internal MTLCommandQueue BackgroundQueue { get; private set; }
internal HelperShader HelperShader { get; private set; }
internal BufferManager BufferManager { get; private set; }
internal CommandBufferPool CommandBufferPool { get; private set; }
internal BackgroundResources BackgroundResources { get; private set; }
internal Action<Action> InterruptAction { get; private set; }
internal SyncManager SyncManager { get; private set; }
internal HashSet<Program> Programs { get; }
internal HashSet<SamplerHolder> Samplers { get; }
public MetalRenderer(Func<CAMetalLayer> metalLayer)
{
_device = MTLDevice.CreateSystemDefaultDevice();
Programs = [];
Samplers = [];
if (_device.ArgumentBuffersSupport != MTLArgumentBuffersTier.Tier2)
{
throw new NotSupportedException("Metal backend requires Tier 2 Argument Buffer support.");
}
_queue = _device.NewCommandQueue(CommandBufferPool.MaxCommandBuffers + 1);
BackgroundQueue = _device.NewCommandQueue(CommandBufferPool.MaxCommandBuffers);
_getMetalLayer = metalLayer;
}
public void Initialize(GraphicsDebugLevel logLevel)
{
CAMetalLayer layer = _getMetalLayer();
layer.Device = _device;
layer.FramebufferOnly = false;
CommandBufferPool = new CommandBufferPool(_queue);
_window = new Window(this, layer);
_pipeline = new Pipeline(_device, this);
BufferManager = new BufferManager(_device, this, _pipeline);
_pipeline.InitEncoderStateManager(BufferManager);
BackgroundResources = new BackgroundResources(this);
HelperShader = new HelperShader(_device, this, _pipeline);
SyncManager = new SyncManager(this);
}
public void BackgroundContextAction(Action action, bool alwaysBackground = false)
{
// GetData methods should be thread safe, so we can call this directly.
// Texture copy (scaled) may also happen in here, so that should also be thread safe.
action();
}
public BufferHandle CreateBuffer(int size, BufferAccess access)
{
return BufferManager.CreateWithHandle(size);
}
public BufferHandle CreateBuffer(IntPtr pointer, int size)
{
return BufferManager.Create(pointer, size);
}
public BufferHandle CreateBufferSparse(ReadOnlySpan<BufferRange> storageBuffers)
{
throw new NotImplementedException();
}
public IImageArray CreateImageArray(int size, bool isBuffer)
{
return new ImageArray(size, isBuffer, _pipeline);
}
public IProgram CreateProgram(ShaderSource[] shaders, ShaderInfo info)
{
ProgramCount++;
return new Program(this, _device, shaders, info.ResourceLayout, info.ComputeLocalSize);
}
public ISampler CreateSampler(SamplerCreateInfo info)
{
return new SamplerHolder(this, _device, info);
}
public ITexture CreateTexture(TextureCreateInfo info)
{
if (info.Target == Target.TextureBuffer)
{
return new TextureBuffer(_device, this, _pipeline, info);
}
return new Texture(_device, this, _pipeline, info);
}
public ITextureArray CreateTextureArray(int size, bool isBuffer)
{
return new TextureArray(size, isBuffer, _pipeline);
}
public bool PrepareHostMapping(IntPtr address, ulong size)
{
// TODO: Metal Host Mapping
return false;
}
public void CreateSync(ulong id, bool strict)
{
SyncManager.Create(id, strict);
}
public void DeleteBuffer(BufferHandle buffer)
{
BufferManager.Delete(buffer);
}
public PinnedSpan<byte> GetBufferData(BufferHandle buffer, int offset, int size)
{
return BufferManager.GetData(buffer, offset, size);
}
public Capabilities GetCapabilities()
{
// TODO: Finalize these values
return new Capabilities(
api: TargetApi.Metal,
vendorName: HardwareInfoTools.GetVendor(),
SystemMemoryType.UnifiedMemory,
hasFrontFacingBug: false,
hasVectorIndexingBug: false,
needsFragmentOutputSpecialization: true,
reduceShaderPrecision: true,
supportsAstcCompression: true,
supportsBc123Compression: true,
supportsBc45Compression: true,
supportsBc67Compression: true,
supportsEtc2Compression: true,
supports3DTextureCompression: true,
supportsBgraFormat: true,
supportsR4G4Format: false,
supportsR4G4B4A4Format: true,
supportsScaledVertexFormats: false,
supportsSnormBufferTextureFormat: true,
supportsSparseBuffer: false,
supports5BitComponentFormat: true,
supportsBlendEquationAdvanced: false,
supportsFragmentShaderInterlock: true,
supportsFragmentShaderOrderingIntel: false,
supportsGeometryShader: false,
supportsGeometryShaderPassthrough: false,
supportsTransformFeedback: false,
supportsImageLoadFormatted: false,
supportsLayerVertexTessellation: false,
supportsMismatchingViewFormat: true,
supportsCubemapView: true,
supportsNonConstantTextureOffset: false,
supportsQuads: false,
supportsSeparateSampler: true,
supportsShaderBallot: false,
supportsShaderBarrierDivergence: false,
supportsShaderFloat64: false,
supportsTextureGatherOffsets: false,
supportsTextureShadowLod: false,
supportsVertexStoreAndAtomics: false,
supportsViewportIndexVertexTessellation: false,
supportsViewportMask: false,
supportsViewportSwizzle: false,
supportsIndirectParameters: true,
supportsDepthClipControl: false,
uniformBufferSetIndex: (int)Constants.ConstantBuffersSetIndex,
storageBufferSetIndex: (int)Constants.StorageBuffersSetIndex,
textureSetIndex: (int)Constants.TexturesSetIndex,
imageSetIndex: (int)Constants.ImagesSetIndex,
extraSetBaseIndex: TotalSets,
maximumExtraSets: (int)Constants.MaximumExtraSets,
maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,
maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage,
maximumTexturesPerStage: Constants.MaxTexturesPerStage,
maximumImagesPerStage: Constants.MaxImagesPerStage,
maximumComputeSharedMemorySize: (int)_device.MaxThreadgroupMemoryLength,
maximumSupportedAnisotropy: 16,
shaderSubgroupSize: 256,
storageBufferOffsetAlignment: 16,
textureBufferOffsetAlignment: 16,
gatherBiasPrecision: 0,
maximumGpuMemory: 0
);
}
public ulong GetCurrentSync()
{
return SyncManager.GetCurrent();
}
public HardwareInfo GetHardwareInfo()
{
return new HardwareInfo(HardwareInfoTools.GetVendor(), HardwareInfoTools.GetModel(), "Apple");
}
public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
{
throw new NotImplementedException();
}
public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data)
{
BufferManager.SetData(buffer, offset, data, _pipeline.Cbs);
}
public void UpdateCounters()
{
// https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
}
public void PreFrame()
{
SyncManager.Cleanup();
}
public ICounterEvent ReportCounter(CounterType type, EventHandler<ulong> resultHandler, float divisor, bool hostReserved)
{
// https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
CounterEvent counterEvent = new();
resultHandler?.Invoke(counterEvent, type == CounterType.SamplesPassed ? (ulong)1 : 0);
return counterEvent;
}
public void ResetCounter(CounterType type)
{
// https://developer.apple.com/documentation/metal/gpu_counters_and_counter_sample_buffers/creating_a_counter_sample_buffer_to_store_a_gpu_s_counter_data_during_a_pass?language=objc
}
public void WaitSync(ulong id)
{
SyncManager.Wait(id);
}
public void FlushAllCommands()
{
_pipeline.FlushCommandsImpl();
}
public void RegisterFlush()
{
SyncManager.RegisterFlush();
// Periodically free unused regions of the staging buffer to avoid doing it all at once.
BufferManager.StagingBuffer.FreeCompleted();
}
public void SetInterruptAction(Action<Action> interruptAction)
{
InterruptAction = interruptAction;
}
public void Screenshot()
{
// TODO: Screenshots
}
public void Dispose()
{
BackgroundResources.Dispose();
foreach (Program program in Programs)
{
program.Dispose();
}
foreach (SamplerHolder sampler in Samplers)
{
sampler.Dispose();
}
_pipeline.Dispose();
_window.Dispose();
}
}
}

View File

@@ -1,262 +0,0 @@
using SharpMetal.Metal;
using System;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
/// <summary>
/// Holder for multiple host GPU fences.
/// </summary>
[SupportedOSPlatform("macos")]
class MultiFenceHolder
{
private const int BufferUsageTrackingGranularity = 4096;
private readonly FenceHolder[] _fences;
private readonly BufferUsageBitmap _bufferUsageBitmap;
/// <summary>
/// Creates a new instance of the multiple fence holder.
/// </summary>
public MultiFenceHolder()
{
_fences = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
}
/// <summary>
/// Creates a new instance of the multiple fence holder, with a given buffer size in mind.
/// </summary>
/// <param name="size">Size of the buffer</param>
public MultiFenceHolder(int size)
{
_fences = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
_bufferUsageBitmap = new BufferUsageBitmap(size, BufferUsageTrackingGranularity);
}
/// <summary>
/// Adds read/write buffer usage information to the uses list.
/// </summary>
/// <param name="cbIndex">Index of the command buffer where the buffer is used</param>
/// <param name="offset">Offset of the buffer being used</param>
/// <param name="size">Size of the buffer region being used, in bytes</param>
/// <param name="write">Whether the access is a write or not</param>
public void AddBufferUse(int cbIndex, int offset, int size, bool write)
{
_bufferUsageBitmap.Add(cbIndex, offset, size, false);
if (write)
{
_bufferUsageBitmap.Add(cbIndex, offset, size, true);
}
}
/// <summary>
/// Removes all buffer usage information for a given command buffer.
/// </summary>
/// <param name="cbIndex">Index of the command buffer where the buffer is used</param>
public void RemoveBufferUses(int cbIndex)
{
_bufferUsageBitmap?.Clear(cbIndex);
}
/// <summary>
/// Checks if a given range of a buffer is being used by a command buffer still being processed by the GPU.
/// </summary>
/// <param name="cbIndex">Index of the command buffer where the buffer is used</param>
/// <param name="offset">Offset of the buffer being used</param>
/// <param name="size">Size of the buffer region being used, in bytes</param>
/// <returns>True if in use, false otherwise</returns>
public bool IsBufferRangeInUse(int cbIndex, int offset, int size)
{
return _bufferUsageBitmap.OverlapsWith(cbIndex, offset, size);
}
/// <summary>
/// Checks if a given range of a buffer is being used by any command buffer still being processed by the GPU.
/// </summary>
/// <param name="offset">Offset of the buffer being used</param>
/// <param name="size">Size of the buffer region being used, in bytes</param>
/// <param name="write">True if only write usages should count</param>
/// <returns>True if in use, false otherwise</returns>
public bool IsBufferRangeInUse(int offset, int size, bool write)
{
return _bufferUsageBitmap.OverlapsWith(offset, size, write);
}
/// <summary>
/// Adds a fence to the holder.
/// </summary>
/// <param name="cbIndex">Command buffer index of the command buffer that owns the fence</param>
/// <param name="fence">Fence to be added</param>
/// <returns>True if the command buffer's previous fence value was null</returns>
public bool AddFence(int cbIndex, FenceHolder fence)
{
ref FenceHolder fenceRef = ref _fences[cbIndex];
if (fenceRef == null)
{
fenceRef = fence;
return true;
}
return false;
}
/// <summary>
/// Removes a fence from the holder.
/// </summary>
/// <param name="cbIndex">Command buffer index of the command buffer that owns the fence</param>
public void RemoveFence(int cbIndex)
{
_fences[cbIndex] = null;
}
/// <summary>
/// Determines if a fence referenced on the given command buffer.
/// </summary>
/// <param name="cbIndex">Index of the command buffer to check if it's used</param>
/// <returns>True if referenced, false otherwise</returns>
public bool HasFence(int cbIndex)
{
return _fences[cbIndex] != null;
}
/// <summary>
/// Wait until all the fences on the holder are signaled.
/// </summary>
public void WaitForFences()
{
WaitForFencesImpl(0, 0, true);
}
/// <summary>
/// Wait until all the fences on the holder with buffer uses overlapping the specified range are signaled.
/// </summary>
/// <param name="offset">Start offset of the buffer range</param>
/// <param name="size">Size of the buffer range in bytes</param>
public void WaitForFences(int offset, int size)
{
WaitForFencesImpl(offset, size, true);
}
/// <summary>
/// Wait until all the fences on the holder with buffer uses overlapping the specified range are signaled.
/// </summary>
// TODO: Add a proper timeout!
public bool WaitForFences(bool indefinite)
{
return WaitForFencesImpl(0, 0, indefinite);
}
/// <summary>
/// Wait until all the fences on the holder with buffer uses overlapping the specified range are signaled.
/// </summary>
/// <param name="offset">Start offset of the buffer range</param>
/// <param name="size">Size of the buffer range in bytes</param>
/// <param name="indefinite">Indicates if this should wait indefinitely</param>
/// <returns>True if all fences were signaled before the timeout expired, false otherwise</returns>
private bool WaitForFencesImpl(int offset, int size, bool indefinite)
{
Span<FenceHolder> fenceHolders = new FenceHolder[CommandBufferPool.MaxCommandBuffers];
int count = size != 0 ? GetOverlappingFences(fenceHolders, offset, size) : GetFences(fenceHolders);
Span<MTLCommandBuffer> fences = stackalloc MTLCommandBuffer[count];
int fenceCount = 0;
for (int i = 0; i < count; i++)
{
if (fenceHolders[i].TryGet(out MTLCommandBuffer fence))
{
fences[fenceCount] = fence;
if (fenceCount < i)
{
fenceHolders[fenceCount] = fenceHolders[i];
}
fenceCount++;
}
}
if (fenceCount == 0)
{
return true;
}
bool signaled = true;
if (indefinite)
{
foreach (MTLCommandBuffer fence in fences)
{
fence.WaitUntilCompleted();
}
}
else
{
foreach (MTLCommandBuffer fence in fences)
{
if (fence.Status != MTLCommandBufferStatus.Completed)
{
signaled = false;
}
}
}
for (int i = 0; i < fenceCount; i++)
{
fenceHolders[i].Put();
}
return signaled;
}
/// <summary>
/// Gets fences to wait for.
/// </summary>
/// <param name="storage">Span to store fences in</param>
/// <returns>Number of fences placed in storage</returns>
private int GetFences(Span<FenceHolder> storage)
{
int count = 0;
for (int i = 0; i < _fences.Length; i++)
{
FenceHolder fence = _fences[i];
if (fence != null)
{
storage[count++] = fence;
}
}
return count;
}
/// <summary>
/// Gets fences to wait for use of a given buffer region.
/// </summary>
/// <param name="storage">Span to store overlapping fences in</param>
/// <param name="offset">Offset of the range</param>
/// <param name="size">Size of the range in bytes</param>
/// <returns>Number of fences for the specified region placed in storage</returns>
private int GetOverlappingFences(Span<FenceHolder> storage, int offset, int size)
{
int count = 0;
for (int i = 0; i < _fences.Length; i++)
{
FenceHolder fence = _fences[i];
if (fence != null && _bufferUsageBitmap.OverlapsWith(i, offset, size))
{
storage[count++] = fence;
}
}
return count;
}
}
}

View File

@@ -1,100 +0,0 @@
using Ryujinx.Graphics.GAL;
using SharpMetal.Metal;
using System;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
internal class PersistentFlushBuffer : IDisposable
{
private readonly MetalRenderer _renderer;
private BufferHolder _flushStorage;
public PersistentFlushBuffer(MetalRenderer renderer)
{
_renderer = renderer;
}
private BufferHolder ResizeIfNeeded(int size)
{
BufferHolder flushStorage = _flushStorage;
if (flushStorage == null || size > _flushStorage.Size)
{
flushStorage?.Dispose();
flushStorage = _renderer.BufferManager.Create(size);
_flushStorage = flushStorage;
}
return flushStorage;
}
public Span<byte> GetBufferData(CommandBufferPool cbp, BufferHolder buffer, int offset, int size)
{
BufferHolder flushStorage = ResizeIfNeeded(size);
Auto<DisposableBuffer> srcBuffer;
using (CommandBufferScoped cbs = cbp.Rent())
{
srcBuffer = buffer.GetBuffer();
Auto<DisposableBuffer> dstBuffer = flushStorage.GetBuffer();
if (srcBuffer.TryIncrementReferenceCount())
{
BufferHolder.Copy(cbs, srcBuffer, dstBuffer, offset, 0, size, registerSrcUsage: false);
}
else
{
// Source buffer is no longer alive, don't copy anything to flush storage.
srcBuffer = null;
}
}
flushStorage.WaitForFences();
srcBuffer?.DecrementReferenceCount();
return flushStorage.GetDataStorage(0, size);
}
public Span<byte> GetTextureData(CommandBufferPool cbp, Texture view, int size)
{
TextureCreateInfo info = view.Info;
BufferHolder flushStorage = ResizeIfNeeded(size);
using (CommandBufferScoped cbs = cbp.Rent())
{
MTLBuffer buffer = flushStorage.GetBuffer().Get(cbs).Value;
MTLTexture image = view.GetHandle();
view.CopyFromOrToBuffer(cbs, buffer, image, size, true, 0, 0, info.GetLayers(), info.Levels, singleSlice: false);
}
flushStorage.WaitForFences();
return flushStorage.GetDataStorage(0, size);
}
public Span<byte> GetTextureData(CommandBufferPool cbp, Texture view, int size, int layer, int level)
{
BufferHolder flushStorage = ResizeIfNeeded(size);
using (CommandBufferScoped cbs = cbp.Rent())
{
MTLBuffer buffer = flushStorage.GetBuffer().Get(cbs).Value;
MTLTexture image = view.GetHandle();
view.CopyFromOrToBuffer(cbs, buffer, image, size, true, layer, level, 1, 1, singleSlice: true);
}
flushStorage.WaitForFences();
return flushStorage.GetDataStorage(0, size);
}
public void Dispose()
{
_flushStorage.Dispose();
}
}
}

View File

@@ -1,877 +0,0 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
using SharpMetal.Foundation;
using SharpMetal.Metal;
using SharpMetal.QuartzCore;
using System;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
public enum EncoderType
{
Blit,
Compute,
Render,
None
}
[SupportedOSPlatform("macos")]
class Pipeline : IPipeline, IEncoderFactory, IDisposable
{
private const ulong MinByteWeightForFlush = 256 * 1024 * 1024; // MiB
private readonly MTLDevice _device;
private readonly MetalRenderer _renderer;
private EncoderStateManager _encoderStateManager;
private ulong _byteWeight;
public MTLCommandBuffer CommandBuffer;
public IndexBufferPattern QuadsToTrisPattern;
public IndexBufferPattern TriFanToTrisPattern;
internal CommandBufferScoped? PreloadCbs { get; private set; }
internal CommandBufferScoped Cbs { get; private set; }
internal CommandBufferEncoder Encoders => Cbs.Encoders;
internal EncoderType CurrentEncoderType => Encoders.CurrentEncoderType;
public Pipeline(MTLDevice device, MetalRenderer renderer)
{
_device = device;
_renderer = renderer;
renderer.CommandBufferPool.Initialize(this);
CommandBuffer = (Cbs = _renderer.CommandBufferPool.Rent()).CommandBuffer;
}
internal void InitEncoderStateManager(BufferManager bufferManager)
{
_encoderStateManager = new EncoderStateManager(_device, bufferManager, this);
QuadsToTrisPattern = new IndexBufferPattern(_renderer, 4, 6, 0, [0, 1, 2, 0, 2, 3], 4, false);
TriFanToTrisPattern = new IndexBufferPattern(_renderer, 3, 3, 2, [int.MinValue, -1, 0], 1, true);
}
public EncoderState SwapState(EncoderState state, DirtyFlags flags = DirtyFlags.All, bool endRenderPass = true)
{
if (endRenderPass && CurrentEncoderType == EncoderType.Render)
{
EndCurrentPass();
}
return _encoderStateManager.SwapState(state, flags);
}
public PredrawState SavePredrawState()
{
return _encoderStateManager.SavePredrawState();
}
public void RestorePredrawState(PredrawState state)
{
_encoderStateManager.RestorePredrawState(state);
}
public void SetClearLoadAction(bool clear)
{
_encoderStateManager.SetClearLoadAction(clear);
}
public MTLRenderCommandEncoder GetOrCreateRenderEncoder(bool forDraw = false)
{
// Mark all state as dirty to ensure it is set on the new encoder
if (Cbs.Encoders.CurrentEncoderType != EncoderType.Render)
{
_encoderStateManager.SignalRenderDirty();
}
if (forDraw)
{
_encoderStateManager.RenderResourcesPrepass();
}
MTLRenderCommandEncoder renderCommandEncoder = Cbs.Encoders.EnsureRenderEncoder();
if (forDraw)
{
_encoderStateManager.RebindRenderState(renderCommandEncoder);
}
return renderCommandEncoder;
}
public MTLBlitCommandEncoder GetOrCreateBlitEncoder()
{
return Cbs.Encoders.EnsureBlitEncoder();
}
public MTLComputeCommandEncoder GetOrCreateComputeEncoder(bool forDispatch = false)
{
// Mark all state as dirty to ensure it is set on the new encoder
if (Cbs.Encoders.CurrentEncoderType != EncoderType.Compute)
{
_encoderStateManager.SignalComputeDirty();
}
if (forDispatch)
{
_encoderStateManager.ComputeResourcesPrepass();
}
MTLComputeCommandEncoder computeCommandEncoder = Cbs.Encoders.EnsureComputeEncoder();
if (forDispatch)
{
_encoderStateManager.RebindComputeState(computeCommandEncoder);
}
return computeCommandEncoder;
}
public void EndCurrentPass()
{
Cbs.Encoders.EndCurrentPass();
}
public MTLRenderCommandEncoder CreateRenderCommandEncoder()
{
return _encoderStateManager.CreateRenderCommandEncoder();
}
public MTLComputeCommandEncoder CreateComputeCommandEncoder()
{
return _encoderStateManager.CreateComputeCommandEncoder();
}
public void Present(CAMetalDrawable drawable, Texture src, Extents2D srcRegion, Extents2D dstRegion, bool isLinear)
{
// TODO: Clean this up
TextureCreateInfo textureInfo = new((int)drawable.Texture.Width, (int)drawable.Texture.Height, (int)drawable.Texture.Depth, (int)drawable.Texture.MipmapLevelCount, (int)drawable.Texture.SampleCount, 0, 0, 0, Format.B8G8R8A8Unorm, 0, Target.Texture2D, SwizzleComponent.Red, SwizzleComponent.Green, SwizzleComponent.Blue, SwizzleComponent.Alpha);
Texture dst = new(_device, _renderer, this, textureInfo, drawable.Texture, 0, 0);
_renderer.HelperShader.BlitColor(Cbs, src, dst, srcRegion, dstRegion, isLinear, true);
EndCurrentPass();
Cbs.CommandBuffer.PresentDrawable(drawable);
FlushCommandsImpl();
// TODO: Auto flush counting
_renderer.SyncManager.GetAndResetWaitTicks();
// Cleanup
dst.Dispose();
}
public CommandBufferScoped GetPreloadCommandBuffer()
{
PreloadCbs ??= _renderer.CommandBufferPool.Rent();
return PreloadCbs.Value;
}
public void FlushCommandsIfWeightExceeding(IAuto disposedResource, ulong byteWeight)
{
bool usedByCurrentCb = disposedResource.HasCommandBufferDependency(Cbs);
if (PreloadCbs != null && !usedByCurrentCb)
{
usedByCurrentCb = disposedResource.HasCommandBufferDependency(PreloadCbs.Value);
}
if (usedByCurrentCb)
{
// Since we can only free memory after the command buffer that uses a given resource was executed,
// keeping the command buffer might cause a high amount of memory to be in use.
// To prevent that, we force submit command buffers if the memory usage by resources
// in use by the current command buffer is above a given limit, and those resources were disposed.
_byteWeight += byteWeight;
if (_byteWeight >= MinByteWeightForFlush)
{
FlushCommandsImpl();
}
}
}
public void FlushCommandsImpl()
{
EndCurrentPass();
_byteWeight = 0;
if (PreloadCbs != null)
{
PreloadCbs.Value.Dispose();
PreloadCbs = null;
}
CommandBuffer = (Cbs = _renderer.CommandBufferPool.ReturnAndRent(Cbs)).CommandBuffer;
_renderer.RegisterFlush();
}
public void DirtyTextures()
{
_encoderStateManager.DirtyTextures();
}
public void DirtyImages()
{
_encoderStateManager.DirtyImages();
}
public void Blit(
Texture src,
Texture dst,
Extents2D srcRegion,
Extents2D dstRegion,
bool isDepthOrStencil,
bool linearFilter)
{
if (isDepthOrStencil)
{
_renderer.HelperShader.BlitDepthStencil(Cbs, src, dst, srcRegion, dstRegion);
}
else
{
_renderer.HelperShader.BlitColor(Cbs, src, dst, srcRegion, dstRegion, linearFilter);
}
}
public void Barrier()
{
switch (CurrentEncoderType)
{
case EncoderType.Render:
{
MTLBarrierScope scope = MTLBarrierScope.Buffers | MTLBarrierScope.Textures | MTLBarrierScope.RenderTargets;
MTLRenderStages stages = MTLRenderStages.RenderStageVertex | MTLRenderStages.RenderStageFragment;
Encoders.RenderEncoder.MemoryBarrier(scope, stages, stages);
break;
}
case EncoderType.Compute:
{
MTLBarrierScope scope = MTLBarrierScope.Buffers | MTLBarrierScope.Textures | MTLBarrierScope.RenderTargets;
Encoders.ComputeEncoder.MemoryBarrier(scope);
break;
}
}
}
public void ClearBuffer(BufferHandle destination, int offset, int size, uint value)
{
MTLBlitCommandEncoder blitCommandEncoder = GetOrCreateBlitEncoder();
MTLBuffer mtlBuffer = _renderer.BufferManager.GetBuffer(destination, offset, size, true).Get(Cbs, offset, size, true).Value;
// Might need a closer look, range's count, lower, and upper bound
// must be a multiple of 4
blitCommandEncoder.FillBuffer(mtlBuffer,
new NSRange
{
location = (ulong)offset,
length = (ulong)size
},
(byte)value);
}
public void ClearRenderTargetColor(int index, int layer, int layerCount, uint componentMask, ColorF color)
{
float[] colors = [color.Red, color.Green, color.Blue, color.Alpha];
Texture dst = _encoderStateManager.RenderTargets[index];
// TODO: Remove workaround for Wonder which has an invalid texture due to unsupported format
if (dst == null)
{
Logger.Warning?.PrintMsg(LogClass.Gpu, "Attempted to clear invalid render target!");
return;
}
_renderer.HelperShader.ClearColor(index, colors, componentMask, dst.Width, dst.Height, dst.Info.Format);
}
public void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, int stencilMask)
{
Texture depthStencil = _encoderStateManager.DepthStencil;
if (depthStencil == null)
{
return;
}
_renderer.HelperShader.ClearDepthStencil(depthValue, depthMask, stencilValue, stencilMask, depthStencil.Width, depthStencil.Height);
}
public void CommandBufferBarrier()
{
Barrier();
}
public void CopyBuffer(BufferHandle src, BufferHandle dst, int srcOffset, int dstOffset, int size)
{
Auto<DisposableBuffer> srcBuffer = _renderer.BufferManager.GetBuffer(src, srcOffset, size, false);
Auto<DisposableBuffer> dstBuffer = _renderer.BufferManager.GetBuffer(dst, dstOffset, size, true);
BufferHolder.Copy(Cbs, srcBuffer, dstBuffer, srcOffset, dstOffset, size);
}
public void PushDebugGroup(string name)
{
MTLCommandEncoder? encoder = Encoders.CurrentEncoder;
NSString debugGroupName = StringHelper.NSString(name);
if (encoder == null)
{
return;
}
switch (Encoders.CurrentEncoderType)
{
case EncoderType.Render:
encoder.Value.PushDebugGroup(debugGroupName);
break;
case EncoderType.Blit:
encoder.Value.PushDebugGroup(debugGroupName);
break;
case EncoderType.Compute:
encoder.Value.PushDebugGroup(debugGroupName);
break;
}
}
public void PopDebugGroup()
{
MTLCommandEncoder? encoder = Encoders.CurrentEncoder;
if (encoder == null)
{
return;
}
switch (Encoders.CurrentEncoderType)
{
case EncoderType.Render:
encoder.Value.PopDebugGroup();
break;
case EncoderType.Blit:
encoder.Value.PopDebugGroup();
break;
case EncoderType.Compute:
encoder.Value.PopDebugGroup();
break;
}
}
public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
{
DispatchCompute(groupsX, groupsY, groupsZ, String.Empty);
}
public void DispatchCompute(int groupsX, int groupsY, int groupsZ, string debugGroupName)
{
MTLComputeCommandEncoder computeCommandEncoder = GetOrCreateComputeEncoder(true);
ComputeSize localSize = _encoderStateManager.ComputeLocalSize;
if (debugGroupName != String.Empty)
{
PushDebugGroup(debugGroupName);
}
computeCommandEncoder.DispatchThreadgroups(
new MTLSize { width = (ulong)groupsX, height = (ulong)groupsY, depth = (ulong)groupsZ },
new MTLSize { width = (ulong)localSize.X, height = (ulong)localSize.Y, depth = (ulong)localSize.Z });
if (debugGroupName != String.Empty)
{
PopDebugGroup();
}
}
public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
{
Draw(vertexCount, instanceCount, firstVertex, firstInstance, String.Empty);
}
public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance, string debugGroupName)
{
if (vertexCount == 0)
{
return;
}
MTLPrimitiveType primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert();
if (TopologyUnsupported(_encoderStateManager.Topology))
{
IndexBufferPattern pattern = GetIndexBufferPattern();
BufferHandle handle = pattern.GetRepeatingBuffer(vertexCount, out int indexCount);
Auto<DisposableBuffer> buffer = _renderer.BufferManager.GetBuffer(handle, false);
MTLBuffer mtlBuffer = buffer.Get(Cbs, 0, indexCount * sizeof(int)).Value;
MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
renderCommandEncoder.DrawIndexedPrimitives(
primitiveType,
(ulong)indexCount,
MTLIndexType.UInt32,
mtlBuffer,
0);
}
else
{
MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
if (debugGroupName != String.Empty)
{
PushDebugGroup(debugGroupName);
}
renderCommandEncoder.DrawPrimitives(
primitiveType,
(ulong)firstVertex,
(ulong)vertexCount,
(ulong)instanceCount,
(ulong)firstInstance);
if (debugGroupName != String.Empty)
{
PopDebugGroup();
}
}
}
private IndexBufferPattern GetIndexBufferPattern()
{
return _encoderStateManager.Topology switch
{
PrimitiveTopology.Quads => QuadsToTrisPattern,
PrimitiveTopology.TriangleFan or PrimitiveTopology.Polygon => TriFanToTrisPattern,
_ => throw new NotSupportedException($"Unsupported topology: {_encoderStateManager.Topology}"),
};
}
private PrimitiveTopology TopologyRemap(PrimitiveTopology topology)
{
return topology switch
{
PrimitiveTopology.Quads => PrimitiveTopology.Triangles,
PrimitiveTopology.QuadStrip => PrimitiveTopology.TriangleStrip,
PrimitiveTopology.TriangleFan or PrimitiveTopology.Polygon => PrimitiveTopology.Triangles,
_ => topology,
};
}
private bool TopologyUnsupported(PrimitiveTopology topology)
{
return topology switch
{
PrimitiveTopology.Quads or PrimitiveTopology.TriangleFan or PrimitiveTopology.Polygon => true,
_ => false,
};
}
public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
{
if (indexCount == 0)
{
return;
}
MTLBuffer mtlBuffer;
int offset;
MTLIndexType type;
int finalIndexCount = indexCount;
MTLPrimitiveType primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert();
if (TopologyUnsupported(_encoderStateManager.Topology))
{
IndexBufferPattern pattern = GetIndexBufferPattern();
int convertedCount = pattern.GetConvertedCount(indexCount);
finalIndexCount = convertedCount;
(mtlBuffer, offset, type) = _encoderStateManager.IndexBuffer.GetConvertedIndexBuffer(_renderer, Cbs, firstIndex, indexCount, convertedCount, pattern);
}
else
{
(mtlBuffer, offset, type) = _encoderStateManager.IndexBuffer.GetIndexBuffer(_renderer, Cbs);
}
if (mtlBuffer.NativePtr != IntPtr.Zero)
{
MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
renderCommandEncoder.DrawIndexedPrimitives(
primitiveType,
(ulong)finalIndexCount,
type,
mtlBuffer,
(ulong)offset,
(ulong)instanceCount,
firstVertex,
(ulong)firstInstance);
}
}
public void DrawIndexedIndirect(BufferRange indirectBuffer)
{
DrawIndexedIndirectOffset(indirectBuffer);
}
public void DrawIndexedIndirectOffset(BufferRange indirectBuffer, int offset = 0)
{
// TODO: Reindex unsupported topologies
if (TopologyUnsupported(_encoderStateManager.Topology))
{
Logger.Warning?.Print(LogClass.Gpu, $"Drawing indexed with unsupported topology: {_encoderStateManager.Topology}");
}
MTLBuffer buffer = _renderer.BufferManager
.GetBuffer(indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
MTLPrimitiveType primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert();
(MTLBuffer indexBuffer, int indexOffset, MTLIndexType type) = _encoderStateManager.IndexBuffer.GetIndexBuffer(_renderer, Cbs);
if (indexBuffer.NativePtr != IntPtr.Zero && buffer.NativePtr != IntPtr.Zero)
{
MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
renderCommandEncoder.DrawIndexedPrimitives(
primitiveType,
type,
indexBuffer,
(ulong)indexOffset,
buffer,
(ulong)(indirectBuffer.Offset + offset));
}
}
public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
{
for (int i = 0; i < maxDrawCount; i++)
{
DrawIndexedIndirectOffset(indirectBuffer, stride * i);
}
}
public void DrawIndirect(BufferRange indirectBuffer)
{
DrawIndirectOffset(indirectBuffer);
}
public void DrawIndirectOffset(BufferRange indirectBuffer, int offset = 0)
{
if (TopologyUnsupported(_encoderStateManager.Topology))
{
// TODO: Reindex unsupported topologies
Logger.Warning?.Print(LogClass.Gpu, $"Drawing indirect with unsupported topology: {_encoderStateManager.Topology}");
}
MTLBuffer buffer = _renderer.BufferManager
.GetBuffer(indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
.Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
MTLPrimitiveType primitiveType = TopologyRemap(_encoderStateManager.Topology).Convert();
MTLRenderCommandEncoder renderCommandEncoder = GetOrCreateRenderEncoder(true);
renderCommandEncoder.DrawPrimitives(
primitiveType,
buffer,
(ulong)(indirectBuffer.Offset + offset));
}
public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
{
for (int i = 0; i < maxDrawCount; i++)
{
DrawIndirectOffset(indirectBuffer, stride * i);
}
}
public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
{
_renderer.HelperShader.DrawTexture(texture, sampler, srcRegion, dstRegion);
}
public void SetAlphaTest(bool enable, float reference, CompareOp op)
{
// This is currently handled using shader specialization, as Metal does not support alpha test.
// In the future, we may want to use this to write the reference value into the support buffer,
// to avoid creating one version of the shader per reference value used.
}
public void SetBlendState(AdvancedBlendDescriptor blend)
{
// Metal does not support advanced blend.
}
public void SetBlendState(int index, BlendDescriptor blend)
{
_encoderStateManager.UpdateBlendDescriptors(index, blend);
}
public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
{
if (enables == 0)
{
_encoderStateManager.UpdateDepthBias(0, 0, 0);
}
else
{
_encoderStateManager.UpdateDepthBias(units, factor, clamp);
}
}
public void SetDepthClamp(bool clamp)
{
_encoderStateManager.UpdateDepthClamp(clamp);
}
public void SetDepthMode(DepthMode mode)
{
// Metal does not support depth clip control.
}
public void SetDepthTest(DepthTestDescriptor depthTest)
{
_encoderStateManager.UpdateDepthState(depthTest);
}
public void SetFaceCulling(bool enable, Face face)
{
_encoderStateManager.UpdateCullMode(enable, face);
}
public void SetFrontFace(FrontFace frontFace)
{
_encoderStateManager.UpdateFrontFace(frontFace);
}
public void SetIndexBuffer(BufferRange buffer, IndexType type)
{
_encoderStateManager.UpdateIndexBuffer(buffer, type);
}
public void SetImage(ShaderStage stage, int binding, ITexture image)
{
if (image is TextureBase img)
{
_encoderStateManager.UpdateImage(stage, binding, img);
}
}
public void SetImageArray(ShaderStage stage, int binding, IImageArray array)
{
if (array is ImageArray imageArray)
{
_encoderStateManager.UpdateImageArray(stage, binding, imageArray);
}
}
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
{
if (array is ImageArray imageArray)
{
_encoderStateManager.UpdateImageArraySeparate(stage, setIndex, imageArray);
}
}
public void SetLineParameters(float width, bool smooth)
{
// Metal does not support wide-lines.
}
public void SetLogicOpState(bool enable, LogicalOp op)
{
_encoderStateManager.UpdateLogicOpState(enable, op);
}
public void SetMultisampleState(MultisampleDescriptor multisample)
{
_encoderStateManager.UpdateMultisampleState(multisample);
}
public void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel)
{
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
}
public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
{
Logger.Warning?.Print(LogClass.Gpu, "Not Implemented!");
}
public void SetPolygonMode(PolygonMode frontMode, PolygonMode backMode)
{
// Metal does not support polygon mode.
}
public void SetPrimitiveRestart(bool enable, int index)
{
// Always active for LineStrip and TriangleStrip
// https://github.com/gpuweb/gpuweb/issues/1220#issuecomment-732483263
// https://developer.apple.com/documentation/metal/mtlrendercommandencoder/1515520-drawindexedprimitives
// https://stackoverflow.com/questions/70813665/how-to-render-multiple-trianglestrips-using-metal
// Emulating disabling this is very difficult. It's unlikely for an index buffer to use the largest possible index,
// so it's fine nearly all of the time.
}
public void SetPrimitiveTopology(PrimitiveTopology topology)
{
_encoderStateManager.UpdatePrimitiveTopology(topology);
}
public void SetProgram(IProgram program)
{
_encoderStateManager.UpdateProgram(program);
}
public void SetRasterizerDiscard(bool discard)
{
_encoderStateManager.UpdateRasterizerDiscard(discard);
}
public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask)
{
_encoderStateManager.UpdateRenderTargetColorMasks(componentMask);
}
public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
{
_encoderStateManager.UpdateRenderTargets(colors, depthStencil);
}
public void SetScissors(ReadOnlySpan<Rectangle<int>> regions)
{
_encoderStateManager.UpdateScissors(regions);
}
public void SetStencilTest(StencilTestDescriptor stencilTest)
{
_encoderStateManager.UpdateStencilState(stencilTest);
}
public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
{
_encoderStateManager.UpdateUniformBuffers(buffers);
}
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
{
_encoderStateManager.UpdateStorageBuffers(buffers);
}
internal void SetStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
{
_encoderStateManager.UpdateStorageBuffers(first, buffers);
}
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
{
if (texture is TextureBase tex)
{
if (sampler == null || sampler is SamplerHolder)
{
_encoderStateManager.UpdateTextureAndSampler(stage, binding, tex, (SamplerHolder)sampler);
}
}
}
public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array)
{
if (array is TextureArray textureArray)
{
_encoderStateManager.UpdateTextureArray(stage, binding, textureArray);
}
}
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
{
if (array is TextureArray textureArray)
{
_encoderStateManager.UpdateTextureArraySeparate(stage, setIndex, textureArray);
}
}
public void SetUserClipDistance(int index, bool enableClip)
{
// TODO. Same as Vulkan
}
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
{
_encoderStateManager.UpdateVertexAttribs(vertexAttribs);
}
public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
{
_encoderStateManager.UpdateVertexBuffers(vertexBuffers);
}
public void SetViewports(ReadOnlySpan<Viewport> viewports)
{
_encoderStateManager.UpdateViewports(viewports);
}
public void TextureBarrier()
{
if (CurrentEncoderType == EncoderType.Render)
{
Encoders.RenderEncoder.MemoryBarrier(MTLBarrierScope.Textures, MTLRenderStages.RenderStageFragment, MTLRenderStages.RenderStageFragment);
}
}
public void TextureBarrierTiled()
{
TextureBarrier();
}
public bool TryHostConditionalRendering(ICounterEvent value, ulong compare, bool isEqual)
{
// TODO: Implementable via indirect draw commands
return false;
}
public bool TryHostConditionalRendering(ICounterEvent value, ICounterEvent compare, bool isEqual)
{
// TODO: Implementable via indirect draw commands
return false;
}
public void EndHostConditionalRendering()
{
// TODO: Implementable via indirect draw commands
}
public void BeginTransformFeedback(PrimitiveTopology topology)
{
// Metal does not support transform feedback.
}
public void EndTransformFeedback()
{
// Metal does not support transform feedback.
}
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
{
// Metal does not support transform feedback.
}
public void Dispose()
{
EndCurrentPass();
_encoderStateManager.Dispose();
}
}
}

View File

@@ -1,286 +0,0 @@
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
using SharpMetal.Foundation;
using SharpMetal.Metal;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
class Program : IProgram
{
private ProgramLinkStatus _status;
private readonly ShaderSource[] _shaders;
private readonly GCHandle[] _handles;
private int _successCount;
private readonly MetalRenderer _renderer;
public MTLFunction VertexFunction;
public MTLFunction FragmentFunction;
public MTLFunction ComputeFunction;
public ComputeSize ComputeLocalSize { get; }
private HashTableSlim<PipelineUid, MTLRenderPipelineState> _graphicsPipelineCache;
private MTLComputePipelineState? _computePipelineCache;
private bool _firstBackgroundUse;
public ResourceBindingSegment[][] BindingSegments { get; }
// Argument buffer sizes for Vertex or Compute stages
public int[] ArgumentBufferSizes { get; }
// Argument buffer sizes for Fragment stage
public int[] FragArgumentBufferSizes { get; }
public Program(
MetalRenderer renderer,
MTLDevice device,
ShaderSource[] shaders,
ResourceLayout resourceLayout,
ComputeSize computeLocalSize = default)
{
_renderer = renderer;
renderer.Programs.Add(this);
ComputeLocalSize = computeLocalSize;
_shaders = shaders;
_handles = new GCHandle[_shaders.Length];
_status = ProgramLinkStatus.Incomplete;
for (int i = 0; i < _shaders.Length; i++)
{
ShaderSource shader = _shaders[i];
using MTLCompileOptions compileOptions = new()
{
PreserveInvariance = true,
LanguageVersion = MTLLanguageVersion.Version31,
};
int index = i;
_handles[i] = device.NewLibrary(StringHelper.NSString(shader.Code), compileOptions, (library, error) => CompilationResultHandler(library, error, index));
}
(BindingSegments, ArgumentBufferSizes, FragArgumentBufferSizes) = BuildBindingSegments(resourceLayout.SetUsages);
}
public void CompilationResultHandler(MTLLibrary library, NSError error, int index)
{
ShaderSource shader = _shaders[index];
if (_handles[index].IsAllocated)
{
_handles[index].Free();
}
if (error != IntPtr.Zero)
{
Logger.Warning?.PrintMsg(LogClass.Gpu, shader.Code);
Logger.Warning?.Print(LogClass.Gpu, $"{shader.Stage} shader linking failed: \n{StringHelper.String(error.LocalizedDescription)}");
_status = ProgramLinkStatus.Failure;
return;
}
switch (shader.Stage)
{
case ShaderStage.Compute:
ComputeFunction = library.NewFunction(StringHelper.NSString("kernelMain"));
break;
case ShaderStage.Vertex:
VertexFunction = library.NewFunction(StringHelper.NSString("vertexMain"));
break;
case ShaderStage.Fragment:
FragmentFunction = library.NewFunction(StringHelper.NSString("fragmentMain"));
break;
default:
Logger.Warning?.Print(LogClass.Gpu, $"Cannot handle stage {shader.Stage}!");
break;
}
_successCount++;
if (_successCount >= _shaders.Length && _status != ProgramLinkStatus.Failure)
{
_status = ProgramLinkStatus.Success;
}
}
private static (ResourceBindingSegment[][], int[], int[]) BuildBindingSegments(ReadOnlyCollection<ResourceUsageCollection> setUsages)
{
ResourceBindingSegment[][] segments = new ResourceBindingSegment[setUsages.Count][];
int[] argBufferSizes = new int[setUsages.Count];
int[] fragArgBufferSizes = new int[setUsages.Count];
for (int setIndex = 0; setIndex < setUsages.Count; setIndex++)
{
List<ResourceBindingSegment> currentSegments = [];
ResourceUsage currentUsage = default;
int currentCount = 0;
for (int index = 0; index < setUsages[setIndex].Usages.Count; index++)
{
ResourceUsage usage = setUsages[setIndex].Usages[index];
if (currentUsage.Binding + currentCount != usage.Binding ||
currentUsage.Type != usage.Type ||
currentUsage.Stages != usage.Stages ||
currentUsage.ArrayLength > 1 ||
usage.ArrayLength > 1)
{
if (currentCount != 0)
{
currentSegments.Add(new ResourceBindingSegment(
currentUsage.Binding,
currentCount,
currentUsage.Type,
currentUsage.Stages,
currentUsage.ArrayLength > 1));
int size = currentCount * ResourcePointerSize(currentUsage.Type);
if (currentUsage.Stages.HasFlag(ResourceStages.Fragment))
{
fragArgBufferSizes[setIndex] += size;
}
if (currentUsage.Stages.HasFlag(ResourceStages.Vertex) ||
currentUsage.Stages.HasFlag(ResourceStages.Compute))
{
argBufferSizes[setIndex] += size;
}
}
currentUsage = usage;
currentCount = usage.ArrayLength;
}
else
{
currentCount++;
}
}
if (currentCount != 0)
{
currentSegments.Add(new ResourceBindingSegment(
currentUsage.Binding,
currentCount,
currentUsage.Type,
currentUsage.Stages,
currentUsage.ArrayLength > 1));
int size = currentCount * ResourcePointerSize(currentUsage.Type);
if (currentUsage.Stages.HasFlag(ResourceStages.Fragment))
{
fragArgBufferSizes[setIndex] += size;
}
if (currentUsage.Stages.HasFlag(ResourceStages.Vertex) ||
currentUsage.Stages.HasFlag(ResourceStages.Compute))
{
argBufferSizes[setIndex] += size;
}
}
segments[setIndex] = currentSegments.ToArray();
}
return (segments, argBufferSizes, fragArgBufferSizes);
}
private static int ResourcePointerSize(ResourceType type)
{
return (type == ResourceType.TextureAndSampler ? 2 : 1);
}
public ProgramLinkStatus CheckProgramLink(bool blocking)
{
if (blocking)
{
while (_status == ProgramLinkStatus.Incomplete)
{ }
return _status;
}
return _status;
}
public byte[] GetBinary()
{
return [];
}
public void AddGraphicsPipeline(ref PipelineUid key, MTLRenderPipelineState pipeline)
{
(_graphicsPipelineCache ??= new()).Add(ref key, pipeline);
}
public void AddComputePipeline(MTLComputePipelineState pipeline)
{
_computePipelineCache = pipeline;
}
public bool TryGetGraphicsPipeline(ref PipelineUid key, out MTLRenderPipelineState pipeline)
{
if (_graphicsPipelineCache == null)
{
pipeline = default;
return false;
}
if (!_graphicsPipelineCache.TryGetValue(ref key, out pipeline))
{
if (_firstBackgroundUse)
{
Logger.Warning?.Print(LogClass.Gpu, "Background pipeline compile missed on draw - incorrect pipeline state?");
_firstBackgroundUse = false;
}
return false;
}
_firstBackgroundUse = false;
return true;
}
public bool TryGetComputePipeline(out MTLComputePipelineState pipeline)
{
if (_computePipelineCache.HasValue)
{
pipeline = _computePipelineCache.Value;
return true;
}
pipeline = default;
return false;
}
public void Dispose()
{
if (!_renderer.Programs.Remove(this))
{
return;
}
if (_graphicsPipelineCache != null)
{
foreach (MTLRenderPipelineState pipeline in _graphicsPipelineCache.Values)
{
pipeline.Dispose();
}
}
_computePipelineCache?.Dispose();
VertexFunction.Dispose();
FragmentFunction.Dispose();
ComputeFunction.Dispose();
}
}
}

View File

@@ -1,22 +0,0 @@
using Ryujinx.Graphics.GAL;
namespace Ryujinx.Graphics.Metal
{
readonly struct ResourceBindingSegment
{
public readonly int Binding;
public readonly int Count;
public readonly ResourceType Type;
public readonly ResourceStages Stages;
public readonly bool IsArray;
public ResourceBindingSegment(int binding, int count, ResourceType type, ResourceStages stages, bool isArray)
{
Binding = binding;
Count = count;
Type = type;
Stages = stages;
IsArray = isArray;
}
}
}

View File

@@ -1,59 +0,0 @@
using Ryujinx.Graphics.GAL;
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
class ResourceLayoutBuilder
{
private const int TotalSets = MetalRenderer.TotalSets;
private readonly List<ResourceDescriptor>[] _resourceDescriptors;
private readonly List<ResourceUsage>[] _resourceUsages;
public ResourceLayoutBuilder()
{
_resourceDescriptors = new List<ResourceDescriptor>[TotalSets];
_resourceUsages = new List<ResourceUsage>[TotalSets];
for (int index = 0; index < TotalSets; index++)
{
_resourceDescriptors[index] = [];
_resourceUsages[index] = [];
}
}
public ResourceLayoutBuilder Add(ResourceStages stages, ResourceType type, int binding, bool write = false)
{
uint setIndex = type switch
{
ResourceType.UniformBuffer => Constants.ConstantBuffersSetIndex,
ResourceType.StorageBuffer => Constants.StorageBuffersSetIndex,
ResourceType.TextureAndSampler or ResourceType.BufferTexture => Constants.TexturesSetIndex,
ResourceType.Image or ResourceType.BufferImage => Constants.ImagesSetIndex,
_ => throw new ArgumentException($"Invalid resource type \"{type}\"."),
};
_resourceDescriptors[setIndex].Add(new ResourceDescriptor(binding, 1, type, stages));
_resourceUsages[setIndex].Add(new ResourceUsage(binding, 1, type, stages, write));
return this;
}
public ResourceLayout Build()
{
ResourceDescriptorCollection[] descriptors = new ResourceDescriptorCollection[TotalSets];
ResourceUsageCollection[] usages = new ResourceUsageCollection[TotalSets];
for (int index = 0; index < TotalSets; index++)
{
descriptors[index] = new ResourceDescriptorCollection(_resourceDescriptors[index].ToArray().AsReadOnly());
usages[index] = new ResourceUsageCollection(_resourceUsages[index].ToArray().AsReadOnly());
}
return new ResourceLayout(descriptors.AsReadOnly(), usages.AsReadOnly());
}
}
}

View File

@@ -1,27 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Metal.SharpMetalExtensions\Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Shaders\Blit.metal" />
<EmbeddedResource Include="Shaders\BlitMs.metal" />
<EmbeddedResource Include="Shaders\ChangeBufferStride.metal" />
<EmbeddedResource Include="Shaders\ConvertD32S8ToD24S8.metal" />
<EmbeddedResource Include="Shaders\ConvertIndexBuffer.metal" />
<EmbeddedResource Include="Shaders\ColorClear.metal" />
<EmbeddedResource Include="Shaders\DepthStencilClear.metal" />
<EmbeddedResource Include="Shaders\DepthBlit.metal" />
<EmbeddedResource Include="Shaders\DepthBlitMs.metal" />
<EmbeddedResource Include="Shaders\StencilBlit.metal" />
<EmbeddedResource Include="Shaders\StencilBlitMs.metal" />
</ItemGroup>
</Project>

View File

@@ -1,90 +0,0 @@
using Ryujinx.Graphics.GAL;
using SharpMetal.Metal;
using System;
using System.Runtime.Versioning;
namespace Ryujinx.Graphics.Metal
{
[SupportedOSPlatform("macos")]
class SamplerHolder : ISampler
{
private readonly MetalRenderer _renderer;
private readonly Auto<DisposableSampler> _sampler;
public SamplerHolder(MetalRenderer renderer, MTLDevice device, SamplerCreateInfo info)
{
_renderer = renderer;
renderer.Samplers.Add(this);
(MTLSamplerMinMagFilter minFilter, MTLSamplerMipFilter mipFilter) = info.MinFilter.Convert();
MTLSamplerBorderColor borderColor = GetConstrainedBorderColor(info.BorderColor, out _);
using MTLSamplerDescriptor descriptor = new()
{
BorderColor = borderColor,
MinFilter = minFilter,
MagFilter = info.MagFilter.Convert(),
MipFilter = mipFilter,
CompareFunction = info.CompareOp.Convert(),
LodMinClamp = info.MinLod,
LodMaxClamp = info.MaxLod,
LodAverage = false,
MaxAnisotropy = Math.Max((uint)info.MaxAnisotropy, 1),
SAddressMode = info.AddressU.Convert(),
TAddressMode = info.AddressV.Convert(),
RAddressMode = info.AddressP.Convert(),
SupportArgumentBuffers = true
};
MTLSamplerState sampler = device.NewSamplerState(descriptor);
_sampler = new Auto<DisposableSampler>(new DisposableSampler(sampler));
}
private static MTLSamplerBorderColor GetConstrainedBorderColor(ColorF arbitraryBorderColor, out bool cantConstrain)
{
float r = arbitraryBorderColor.Red;
float g = arbitraryBorderColor.Green;
float b = arbitraryBorderColor.Blue;
float a = arbitraryBorderColor.Alpha;
if (r == 0f && g == 0f && b == 0f)
{
if (a == 1f)
{
cantConstrain = false;
return MTLSamplerBorderColor.OpaqueBlack;
}
if (a == 0f)
{
cantConstrain = false;
return MTLSamplerBorderColor.TransparentBlack;
}
}
else if (r == 1f && g == 1f && b == 1f && a == 1f)
{
cantConstrain = false;
return MTLSamplerBorderColor.OpaqueWhite;
}
cantConstrain = true;
return MTLSamplerBorderColor.OpaqueBlack;
}
public Auto<DisposableSampler> GetSampler()
{
return _sampler;
}
public void Dispose()
{
if (_renderer.Samplers.Remove(this))
{
_sampler.Dispose();
}
}
}
}

View File

@@ -1,43 +0,0 @@
#include <metal_stdlib>
using namespace metal;
struct CopyVertexOut {
float4 position [[position]];
float2 uv;
};
struct TexCoords {
float data[4];
};
struct ConstantBuffers {
constant TexCoords* tex_coord;
};
struct Textures
{
texture2d<FORMAT, access::sample> texture;
sampler sampler;
};
vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
CopyVertexOut out;
int low = vid & 1;
int high = vid >> 1;
out.uv.x = constant_buffers.tex_coord->data[low];
out.uv.y = constant_buffers.tex_coord->data[2 + high];
out.position.x = (float(low) - 0.5f) * 2.0f;
out.position.y = (float(high) - 0.5f) * 2.0f;
out.position.z = 0.0f;
out.position.w = 1.0f;
return out;
}
fragment FORMAT4 fragmentMain(CopyVertexOut in [[stage_in]],
constant Textures &textures [[buffer(TEXTURES_INDEX)]]) {
return textures.texture.sample(textures.sampler, in.uv);
}

View File

@@ -1,45 +0,0 @@
#include <metal_stdlib>
using namespace metal;
struct CopyVertexOut {
float4 position [[position]];
float2 uv;
};
struct TexCoords {
float data[4];
};
struct ConstantBuffers {
constant TexCoords* tex_coord;
};
struct Textures
{
texture2d_ms<FORMAT, access::read> texture;
};
vertex CopyVertexOut vertexMain(uint vid [[vertex_id]],
constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
CopyVertexOut out;
int low = vid & 1;
int high = vid >> 1;
out.uv.x = constant_buffers.tex_coord->data[low];
out.uv.y = constant_buffers.tex_coord->data[2 + high];
out.position.x = (float(low) - 0.5f) * 2.0f;
out.position.y = (float(high) - 0.5f) * 2.0f;
out.position.z = 0.0f;
out.position.w = 1.0f;
return out;
}
fragment FORMAT4 fragmentMain(CopyVertexOut in [[stage_in]],
constant Textures &textures [[buffer(TEXTURES_INDEX)]],
uint sample_id [[sample_id]]) {
uint2 tex_size = uint2(textures.texture.get_width(), textures.texture.get_height());
uint2 tex_coord = uint2(in.uv * float2(tex_size));
return textures.texture.read(tex_coord, sample_id);
}

View File

@@ -1,72 +0,0 @@
#include <metal_stdlib>
using namespace metal;
struct StrideArguments {
int4 data;
};
struct InData {
uint8_t data[1];
};
struct OutData {
uint8_t data[1];
};
struct ConstantBuffers {
constant StrideArguments* stride_arguments;
};
struct StorageBuffers {
device InData* in_data;
device OutData* out_data;
};
kernel void kernelMain(constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]],
device StorageBuffers &storage_buffers [[buffer(STORAGE_BUFFERS_INDEX)]],
uint3 thread_position_in_grid [[thread_position_in_grid]],
uint3 threads_per_threadgroup [[threads_per_threadgroup]],
uint3 threadgroups_per_grid [[threadgroups_per_grid]])
{
// Determine what slice of the stride copies this invocation will perform.
int sourceStride = constant_buffers.stride_arguments->data.x;
int targetStride = constant_buffers.stride_arguments->data.y;
int bufferSize = constant_buffers.stride_arguments->data.z;
int sourceOffset = constant_buffers.stride_arguments->data.w;
int strideRemainder = targetStride - sourceStride;
int invocations = int(threads_per_threadgroup.x * threadgroups_per_grid.x);
int copiesRequired = bufferSize / sourceStride;
// Find the copies that this invocation should perform.
// - Copies that all invocations perform.
int allInvocationCopies = copiesRequired / invocations;
// - Extra remainder copy that this invocation performs.
int index = int(thread_position_in_grid.x);
int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
int copyCount = allInvocationCopies + extra;
// Finally, get the starting offset. Make sure to count extra copies.
int startCopy = allInvocationCopies * index + min(copiesRequired % invocations, index);
int srcOffset = sourceOffset + startCopy * sourceStride;
int dstOffset = startCopy * targetStride;
// Perform the copies for this region
for (int i = 0; i < copyCount; i++) {
for (int j = 0; j < sourceStride; j++) {
storage_buffers.out_data->data[dstOffset++] = storage_buffers.in_data->data[srcOffset++];
}
for (int j = 0; j < strideRemainder; j++) {
storage_buffers.out_data->data[dstOffset++] = uint8_t(0);
}
}
}

View File

@@ -1,38 +0,0 @@
#include <metal_stdlib>
using namespace metal;
struct VertexOut {
float4 position [[position]];
};
struct ClearColor {
FORMAT4 data;
};
struct ConstantBuffers {
constant ClearColor* clear_color;
};
vertex VertexOut vertexMain(ushort vid [[vertex_id]]) {
int low = vid & 1;
int high = vid >> 1;
VertexOut out;
out.position.x = (float(low) - 0.5f) * 2.0f;
out.position.y = (float(high) - 0.5f) * 2.0f;
out.position.z = 0.0f;
out.position.w = 1.0f;
return out;
}
struct FragmentOut {
FORMAT4 color [[color(COLOR_ATTACHMENT_INDEX)]];
};
fragment FragmentOut fragmentMain(VertexOut in [[stage_in]],
constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]]) {
return {constant_buffers.clear_color->data};
}

View File

@@ -1,66 +0,0 @@
#include <metal_stdlib>
using namespace metal;
struct StrideArguments {
int pixelCount;
int dstStartOffset;
};
struct InData {
uint data[1];
};
struct OutData {
uint data[1];
};
struct ConstantBuffers {
constant StrideArguments* stride_arguments;
};
struct StorageBuffers {
device InData* in_data;
device OutData* out_data;
};
kernel void kernelMain(constant ConstantBuffers &constant_buffers [[buffer(CONSTANT_BUFFERS_INDEX)]],
device StorageBuffers &storage_buffers [[buffer(STORAGE_BUFFERS_INDEX)]],
uint3 thread_position_in_grid [[thread_position_in_grid]],
uint3 threads_per_threadgroup [[threads_per_threadgroup]],
uint3 threadgroups_per_grid [[threadgroups_per_grid]])
{
// Determine what slice of the stride copies this invocation will perform.
int invocations = int(threads_per_threadgroup.x * threadgroups_per_grid.x);
int copiesRequired = constant_buffers.stride_arguments->pixelCount;
// Find the copies that this invocation should perform.
// - Copies that all invocations perform.
int allInvocationCopies = copiesRequired / invocations;
// - Extra remainder copy that this invocation performs.
int index = int(thread_position_in_grid.x);
int extra = (index < (copiesRequired % invocations)) ? 1 : 0;
int copyCount = allInvocationCopies + extra;
// Finally, get the starting offset. Make sure to count extra copies.
int startCopy = allInvocationCopies * index + min(copiesRequired % invocations, index);
int srcOffset = startCopy * 2;
int dstOffset = constant_buffers.stride_arguments->dstStartOffset + startCopy;
// Perform the conversion for this region.
for (int i = 0; i < copyCount; i++)
{
float depth = as_type<float>(storage_buffers.in_data->data[srcOffset++]);
uint stencil = storage_buffers.in_data->data[srcOffset++];
uint rescaledDepth = uint(clamp(depth, 0.0, 1.0) * 16777215.0);
storage_buffers.out_data->data[dstOffset++] = (rescaledDepth << 8) | (stencil & 0xff);
}
}

Some files were not shown because too many files have changed in this diff Show More