Compare commits

..

No commits in common. "master" and "1.1.1315" have entirely different histories.

355 changed files with 4219 additions and 9781 deletions

View File

@ -23,7 +23,7 @@ body:
attributes: attributes:
label: Log file label: Log file
description: A log file will help our developers to better diagnose and fix the issue. description: A log file will help our developers to better diagnose and fix the issue.
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste). placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. You can drag and drop the log on to the text area
validations: validations:
required: true required: true
- type: input - type: input

40
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,40 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
labels:
- "infra"
reviewers:
- TSRBerry
commit-message:
prefix: "ci"
- package-ecosystem: nuget
directory: /
open-pull-requests-limit: 10
schedule:
interval: daily
labels:
- "infra"
reviewers:
- TSRBerry
commit-message:
prefix: nuget
groups:
Avalonia:
patterns:
- "*Avalonia*"
Silk.NET:
patterns:
- "Silk.NET*"
OpenTK:
patterns:
- "OpenTK*"
SixLabors:
patterns:
- "SixLabors*"
NUnit:
patterns:
- "NUnit*"

View File

@ -11,18 +11,18 @@
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.18" /> <PackageVersion Include="Avalonia.Svg" Version="11.0.0.18" />
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" /> <PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" />
<PackageVersion Include="CommandLineParser" Version="2.9.1" /> <PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="Concentus" Version="2.2.0" /> <PackageVersion Include="Concentus" Version="1.1.7" />
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" /> <PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageVersion Include="DynamicData" Version="9.0.4" /> <PackageVersion Include="DynamicData" Version="8.4.1" />
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" /> <PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" /> <PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" /> <PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
<PackageVersion Include="LibHac" Version="0.19.0" /> <PackageVersion Include="LibHac" Version="0.19.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" /> <PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" /> <PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.1" /> <PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.5.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" /> <PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" /> <PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
<PackageVersion Include="NetCoreServer" Version="8.0.7" /> <PackageVersion Include="NetCoreServer" Version="8.0.7" />
<PackageVersion Include="NUnit" Version="3.13.3" /> <PackageVersion Include="NUnit" Version="3.13.3" />
@ -39,11 +39,11 @@
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" /> <PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" /> <PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" /> <PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" /> <PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" /> <PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.21.0" /> <PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
<PackageVersion Include="SkiaSharp" Version="2.88.7" /> <PackageVersion Include="SixLabors.ImageSharp" Version="2.1.8" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" /> <PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0" />
<PackageVersion Include="SPB" Version="0.0.4-build32" /> <PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" /> <PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
<PackageVersion Include="System.Management" Version="8.0.0" /> <PackageVersion Include="System.Management" Version="8.0.0" />

View File

@ -1,27 +1,24 @@
<h1 align="center"> <h1 align="center">
<br> <br>
<a href="https://ryujinx.org/"><img src="https://raw.githubusercontent.com/natesworksdev/Ryujinx/master/distribution/misc/Logo.svg" alt="Ryujinx" width="150"></a> <a href="https://ryujinx.org/"><img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx/master/distribution/misc/Logo.svg" alt="Ryujinx" width="150"></a>
<br> <br>
<b>Ryujinx Mirror</b> <b>Ryujinx</b>
<br> <br>
<sub><sup><b>(REE-YOU-JINX)</b></sup></sub> <sub><sup><b>(REE-YOU-JINX)</b></sup></sub>
<br> <br>
</h1> </h1>
<p> <p align="center">
Mirror of the Ryujinx open-source Nintendo Switch emulator, created by gdkchan, written in C#. It has been removed from github recently and this is a replica of it's state before being deleted with only readme changes.<a href= "https://www.reddit.com/r/pcgaming/comments/1ftvp49/ryujinx_a_nintendo_switch_emulator_has_ceased/">Learn more</a> Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#.
This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds. This emulator aims at providing excellent accuracy and performance, a user-friendly interface and consistent builds.
It was written from scratch and development on the project began in September 2017. It was written from scratch and development on the project began in September 2017.
Ryujinx is available on Github under the <a href="https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license</a>.
Ryujinx is available on Github under the <a href="https://github.com/natesworksdev/Ryujinx/blob/master/LICENSE.txt" target="_blank">MIT license</a>.
<br /> <br />
</p> </p>
<p align="center"> <p align="center">
<a href="https://github.com/natesworksdev/Ryujinx/actions/workflows/release.yml"> <a href="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml">
<img src="https://github.com/natesworksdev/Ryujinx/actions/workflows/release.yml/badge.svg" <img src="https://github.com/Ryujinx/Ryujinx/actions/workflows/release.yml/badge.svg"
alt=""> alt="">
</a> </a>
<a href="https://crwd.in/ryujinx"> <a href="https://crwd.in/ryujinx">
@ -34,7 +31,7 @@
</a> </a>
<br> <br>
<br> <br>
<img src="https://raw.githubusercontent.com/natesworksdev/Ryujinx-Website/master/public/assets/images/shell.png"> <img src="https://raw.githubusercontent.com/Ryujinx/Ryujinx-Website/master/public/assets/images/shell.png">
</p> </p>
## Compatibility ## Compatibility
@ -42,7 +39,7 @@
As of May 2024, Ryujinx has been tested on approximately 4,300 titles; As of May 2024, Ryujinx has been tested on approximately 4,300 titles;
over 4,100 boot past menus and into gameplay, with roughly 3,550 of those being considered playable. over 4,100 boot past menus and into gameplay, with roughly 3,550 of those being considered playable.
You can check out the compatibility list [here](https://github.com/natesworksdev/Ryujinx-Games-List/issues). You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues).
Anyone is free to submit a new game test or update an existing game test entry; Anyone is free to submit a new game test or update an existing game test entry;
simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue.
@ -53,10 +50,10 @@ Use the search function to see if a game has been tested already!
To run this emulator, your PC must be equipped with at least 8GiB of RAM; To run this emulator, your PC must be equipped with at least 8GiB of RAM;
failing to meet this requirement may result in a poor gameplay experience or unexpected crashes. failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
See our [Setup & Configuration Guide](https://github.com/natesworksdev/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator. See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator.
For our Local Wireless (LDN) builds, see our [Multiplayer: Local Play/Local Wireless Guide For our Local Wireless (LDN) builds, see our [Multiplayer: Local Play/Local Wireless Guide
](https://github.com/natesworksdev/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide). ](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide).
Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information. Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information.
@ -65,7 +62,7 @@ Avalonia UI comes with translations for various languages. See [Crowdin](https:/
These builds are compiled automatically for each commit on the master branch. These builds are compiled automatically for each commit on the master branch.
While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken**. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken**.
If you want to see details on updates to the emulator, you can visit our [Changelog](https://github.com/natesworksdev/Ryujinx/wiki/Changelog). If you want to see details on updates to the emulator, you can visit our [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog).
The latest automatic build for Windows, macOS, and Linux can be found on the [Official Website](https://ryujinx.org/download). The latest automatic build for Windows, macOS, and Linux can be found on the [Official Website](https://ryujinx.org/download).
@ -141,7 +138,7 @@ This folder is located in the user folder, which can be accessed by clicking `Op
## Contact ## Contact
If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx). If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx).
You may also review our [FAQ](https://github.com/natesworksdev/Ryujinx/wiki/Frequently-Asked-Questions). You may also review our [FAQ](https://github.com/Ryujinx/Ryujinx/wiki/Frequently-Asked-Questions).
## Donations ## Donations

View File

@ -87,8 +87,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryuj
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -251,10 +249,6 @@ Global
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU {7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|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}.Release|Any CPU.Build.0 = Release|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}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -237,7 +237,7 @@ namespace ARMeilleure.CodeGen.Arm64
long originalPosition = _stream.Position; long originalPosition = _stream.Position;
_stream.Seek(0, SeekOrigin.Begin); _stream.Seek(0, SeekOrigin.Begin);
_stream.ReadExactly(code, 0, code.Length); _stream.Read(code, 0, code.Length);
_stream.Seek(originalPosition, SeekOrigin.Begin); _stream.Seek(originalPosition, SeekOrigin.Begin);
RelocInfo relocInfo; RelocInfo relocInfo;

View File

@ -251,20 +251,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
} }
// If this is a copy destination variable, we prefer the register used for the copy source. int selectedReg = GetHighestValueIndex(freePositions);
// If the register is available, then the copy can be eliminated later as both source
// and destination will use the same register.
int selectedReg;
if (current.TryGetCopySourceRegister(out int preferredReg) && freePositions[preferredReg] >= current.GetEnd())
{
selectedReg = preferredReg;
}
else
{
selectedReg = GetHighestValueIndex(freePositions);
}
int selectedNextUse = freePositions[selectedReg]; int selectedNextUse = freePositions[selectedReg];
// Intervals starts and ends at odd positions, unless they span an entire // Intervals starts and ends at odd positions, unless they span an entire
@ -444,7 +431,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
} }
private static int GetHighestValueIndex(ReadOnlySpan<int> span) private static int GetHighestValueIndex(Span<int> span)
{ {
int highest = int.MinValue; int highest = int.MinValue;
@ -811,12 +798,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// The "visited" state is stored in the MSB of the local's value. // The "visited" state is stored in the MSB of the local's value.
const ulong VisitedMask = 1ul << 63; const ulong VisitedMask = 1ul << 63;
static bool IsVisited(Operand local) bool IsVisited(Operand local)
{ {
return (local.GetValueUnsafe() & VisitedMask) != 0; return (local.GetValueUnsafe() & VisitedMask) != 0;
} }
static void SetVisited(Operand local) void SetVisited(Operand local)
{ {
local.GetValueUnsafe() |= VisitedMask; local.GetValueUnsafe() |= VisitedMask;
} }
@ -839,25 +826,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
dest.NumberLocal(_intervals.Count); dest.NumberLocal(_intervals.Count);
LiveInterval interval = new LiveInterval(dest); _intervals.Add(new LiveInterval(dest));
_intervals.Add(interval);
SetVisited(dest); SetVisited(dest);
// If this is a copy (or copy-like operation), set the copy source interval as well.
// This is used for register preferencing later on, which allows the copy to be eliminated
// in some cases.
if (node.Instruction == Instruction.Copy || node.Instruction == Instruction.ZeroExtend32)
{
Operand source = node.GetSource(0);
if (source.Kind == OperandKind.LocalVariable &&
source.GetLocalNumber() > 0 &&
(node.Instruction == Instruction.Copy || source.Type == OperandType.I32))
{
interval.SetCopySource(_intervals[source.GetLocalNumber()]);
}
}
} }
} }
} }

View File

@ -19,7 +19,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public LiveRange CurrRange; public LiveRange CurrRange;
public LiveInterval Parent; public LiveInterval Parent;
public LiveInterval CopySource;
public UseList Uses; public UseList Uses;
public LiveIntervalList Children; public LiveIntervalList Children;
@ -38,7 +37,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private ref LiveRange CurrRange => ref _data->CurrRange; private ref LiveRange CurrRange => ref _data->CurrRange;
private ref LiveRange PrevRange => ref _data->PrevRange; private ref LiveRange PrevRange => ref _data->PrevRange;
private ref LiveInterval Parent => ref _data->Parent; private ref LiveInterval Parent => ref _data->Parent;
private ref LiveInterval CopySource => ref _data->CopySource;
private ref UseList Uses => ref _data->Uses; private ref UseList Uses => ref _data->Uses;
private ref LiveIntervalList Children => ref _data->Children; private ref LiveIntervalList Children => ref _data->Children;
@ -80,25 +78,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
Register = register; Register = register;
} }
public void SetCopySource(LiveInterval copySource)
{
CopySource = copySource;
}
public bool TryGetCopySourceRegister(out int copySourceRegIndex)
{
if (CopySource._data != null)
{
copySourceRegIndex = CopySource.Register.Index;
return true;
}
copySourceRegIndex = 0;
return false;
}
public void Reset() public void Reset()
{ {
PrevRange = default; PrevRange = default;

View File

@ -1444,7 +1444,7 @@ namespace ARMeilleure.CodeGen.X86
Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position]; Span<byte> buffer = new byte[jump.JumpPosition - _stream.Position];
_stream.ReadExactly(buffer); _stream.Read(buffer);
_stream.Seek(ReservedBytesForJump, SeekOrigin.Current); _stream.Seek(ReservedBytesForJump, SeekOrigin.Current);
codeStream.Write(buffer); codeStream.Write(buffer);

View File

@ -746,7 +746,6 @@ namespace ARMeilleure.Decoders
SetA32("<<<<01101000xxxxxxxxxxxxxx01xxxx", InstName.Pkh, InstEmit32.Pkh, OpCode32AluRsImm.Create); SetA32("<<<<01101000xxxxxxxxxxxxxx01xxxx", InstName.Pkh, InstEmit32.Pkh, OpCode32AluRsImm.Create);
SetA32("11110101xx01xxxx1111xxxxxxxxxxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create); SetA32("11110101xx01xxxx1111xxxxxxxxxxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create);
SetA32("11110111xx01xxxx1111xxxxxxx0xxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create); SetA32("11110111xx01xxxx1111xxxxxxx0xxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create);
SetA32("<<<<01100010xxxxxxxx11110001xxxx", InstName.Qadd16, InstEmit32.Qadd16, OpCode32AluReg.Create);
SetA32("<<<<011011111111xxxx11110011xxxx", InstName.Rbit, InstEmit32.Rbit, OpCode32AluReg.Create); SetA32("<<<<011011111111xxxx11110011xxxx", InstName.Rbit, InstEmit32.Rbit, OpCode32AluReg.Create);
SetA32("<<<<011010111111xxxx11110011xxxx", InstName.Rev, InstEmit32.Rev, OpCode32AluReg.Create); SetA32("<<<<011010111111xxxx11110011xxxx", InstName.Rev, InstEmit32.Rev, OpCode32AluReg.Create);
SetA32("<<<<011010111111xxxx11111011xxxx", InstName.Rev16, InstEmit32.Rev16, OpCode32AluReg.Create); SetA32("<<<<011010111111xxxx11111011xxxx", InstName.Rev16, InstEmit32.Rev16, OpCode32AluReg.Create);
@ -823,10 +822,6 @@ namespace ARMeilleure.Decoders
SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create); SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create);
SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create); SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create);
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create); SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
SetA32("<<<<01100110xxxxxxxx11110001xxxx", InstName.Uqadd16, InstEmit32.Uqadd16, OpCode32AluReg.Create);
SetA32("<<<<01100110xxxxxxxx11111001xxxx", InstName.Uqadd8, InstEmit32.Uqadd8, OpCode32AluReg.Create);
SetA32("<<<<01100110xxxxxxxx11110111xxxx", InstName.Uqsub16, InstEmit32.Uqsub16, OpCode32AluReg.Create);
SetA32("<<<<01100110xxxxxxxx11111111xxxx", InstName.Uqsub8, InstEmit32.Uqsub8, OpCode32AluReg.Create);
SetA32("<<<<0110111xxxxxxxxxxxxxxx01xxxx", InstName.Usat, InstEmit32.Usat, OpCode32Sat.Create); SetA32("<<<<0110111xxxxxxxxxxxxxxx01xxxx", InstName.Usat, InstEmit32.Usat, OpCode32Sat.Create);
SetA32("<<<<01101110xxxxxxxx11110011xxxx", InstName.Usat16, InstEmit32.Usat16, OpCode32Sat16.Create); SetA32("<<<<01101110xxxxxxxx11110011xxxx", InstName.Usat16, InstEmit32.Usat16, OpCode32Sat16.Create);
SetA32("<<<<01100101xxxxxxxx11111111xxxx", InstName.Usub8, InstEmit32.Usub8, OpCode32AluReg.Create); SetA32("<<<<01100101xxxxxxxx11111111xxxx", InstName.Usub8, InstEmit32.Usub8, OpCode32AluReg.Create);
@ -1012,8 +1007,6 @@ namespace ARMeilleure.Decoders
SetAsimd("111100100x10xxxxxxxx1011xxx0xxxx", InstName.Vqdmulh, InstEmit32.Vqdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32); SetAsimd("111100100x10xxxxxxxx1011xxx0xxxx", InstName.Vqdmulh, InstEmit32.Vqdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("111100111x11<<10xxxx00101xx0xxx0", InstName.Vqmovn, InstEmit32.Vqmovn, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32); SetAsimd("111100111x11<<10xxxx00101xx0xxx0", InstName.Vqmovn, InstEmit32.Vqmovn, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
SetAsimd("111100111x11<<10xxxx001001x0xxx0", InstName.Vqmovun, InstEmit32.Vqmovun, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32); SetAsimd("111100111x11<<10xxxx001001x0xxx0", InstName.Vqmovun, InstEmit32.Vqmovun, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32);
SetAsimd("111100110x01xxxxxxxx1011xxx0xxxx", InstName.Vqrdmulh, InstEmit32.Vqrdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("111100110x10xxxxxxxx1011xxx0xxxx", InstName.Vqrdmulh, InstEmit32.Vqrdmulh, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32); SetAsimd("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
SetAsimd("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32); SetAsimd("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
SetAsimd("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32); SetAsimd("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
@ -1035,10 +1028,8 @@ namespace ARMeilleure.Decoders
SetAsimd("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32); SetAsimd("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
SetAsimd("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32); SetAsimd("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create, OpCode32SimdShImmLong.CreateT32); // A1 encoding. SetAsimd("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create, OpCode32SimdShImmLong.CreateT32); // A1 encoding.
SetAsimd("111100111x11<<10xxxx001100x0xxxx", InstName.Vshll, InstEmit32.Vshll2, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32); // A2 encoding.
SetAsimd("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32); SetAsimd("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
SetAsimd("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32); SetAsimd("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
SetAsimd("111100111x>>>xxxxxxx0101>xx1xxxx", InstName.Vsli, InstEmit32.Vsli_I, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
SetAsimd("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32); SetAsimd("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
SetAsimd("111101001x00xxxxxxxx0000xxx0xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32); SetAsimd("111101001x00xxxxxxxx0000xxx0xxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
SetAsimd("111101001x00xxxxxxxx0100xx0xxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32); SetAsimd("111101001x00xxxxxxxx0100xx0xxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create, OpCode32SimdMemSingle.CreateT32);
@ -1063,7 +1054,6 @@ namespace ARMeilleure.Decoders
SetAsimd("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32); SetAsimd("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
SetAsimd("1111001x1x<<xxxxxxx00010x0x0xxxx", InstName.Vsubl, InstEmit32.Vsubl_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32); SetAsimd("1111001x1x<<xxxxxxx00010x0x0xxxx", InstName.Vsubl, InstEmit32.Vsubl_I, OpCode32SimdRegLong.Create, OpCode32SimdRegLong.CreateT32);
SetAsimd("1111001x1x<<xxxxxxx00011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create, OpCode32SimdRegWide.CreateT32); SetAsimd("1111001x1x<<xxxxxxx00011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create, OpCode32SimdRegWide.CreateT32);
SetAsimd("111100111x110010xxxx00000xx0xxxx", InstName.Vswp, InstEmit32.Vswp, OpCode32Simd.Create, OpCode32Simd.CreateT32);
SetAsimd("111100111x11xxxxxxxx10xxxxx0xxxx", InstName.Vtbl, InstEmit32.Vtbl, OpCode32SimdTbl.Create, OpCode32SimdTbl.CreateT32); SetAsimd("111100111x11xxxxxxxx10xxxxx0xxxx", InstName.Vtbl, InstEmit32.Vtbl, OpCode32SimdTbl.Create, OpCode32SimdTbl.CreateT32);
SetAsimd("111100111x11<<10xxxx00001xx0xxxx", InstName.Vtrn, InstEmit32.Vtrn, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32); SetAsimd("111100111x11<<10xxxx00001xx0xxxx", InstName.Vtrn, InstEmit32.Vtrn, OpCode32SimdCmpZ.Create, OpCode32SimdCmpZ.CreateT32);
SetAsimd("111100100x<<xxxxxxxx1000xxx1xxxx", InstName.Vtst, InstEmit32.Vtst, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32); SetAsimd("111100100x<<xxxxxxxx1000xxx1xxxx", InstName.Vtst, InstEmit32.Vtst, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);

View File

@ -2,8 +2,6 @@ using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation; using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State; using ARMeilleure.State;
using ARMeilleure.Translation; using ARMeilleure.Translation;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using static ARMeilleure.Instructions.InstEmitAluHelper; using static ARMeilleure.Instructions.InstEmitAluHelper;
using static ARMeilleure.Instructions.InstEmitHelper; using static ARMeilleure.Instructions.InstEmitHelper;
@ -292,16 +290,6 @@ namespace ARMeilleure.Instructions
EmitAluStore(context, res); EmitAluStore(context, res);
} }
public static void Qadd16(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitSigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateRange(context, d, context.Add(n, m), 16, unsigned: false, setQ: false);
}));
}
public static void Rbit(ArmEmitterContext context) public static void Rbit(ArmEmitterContext context)
{ {
Operand m = GetAluM(context); Operand m = GetAluM(context);
@ -570,46 +558,6 @@ namespace ARMeilleure.Instructions
EmitHsub8(context, unsigned: true); EmitHsub8(context, unsigned: true);
} }
public static void Uqadd16(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitUnsigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateUqadd(context, d, context.Add(n, m), 16);
}));
}
public static void Uqadd8(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitUnsigned8BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateUqadd(context, d, context.Add(n, m), 8);
}));
}
public static void Uqsub16(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitUnsigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateUqsub(context, d, context.Subtract(n, m), 16);
}));
}
public static void Uqsub8(ArmEmitterContext context)
{
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
SetIntA32(context, op.Rd, EmitUnsigned8BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
{
EmitSaturateUqsub(context, d, context.Subtract(n, m), 8);
}));
}
public static void Usat(ArmEmitterContext context) public static void Usat(ArmEmitterContext context)
{ {
OpCode32Sat op = (OpCode32Sat)context.CurrOp; OpCode32Sat op = (OpCode32Sat)context.CurrOp;
@ -986,251 +934,6 @@ namespace ARMeilleure.Instructions
} }
} }
private static void EmitSaturateRange(ArmEmitterContext context, Operand result, Operand value, uint saturateTo, bool unsigned, bool setQ = true)
{
Debug.Assert(saturateTo <= 32);
Debug.Assert(!unsigned || saturateTo < 32);
if (!unsigned && saturateTo == 32)
{
// No saturation possible for this case.
context.Copy(result, value);
return;
}
else if (saturateTo == 0)
{
// Result is always zero if we saturate 0 bits.
context.Copy(result, Const(0));
return;
}
Operand satValue;
if (unsigned)
{
// Negative values always saturate (to zero).
// So we must always ignore the sign bit when masking, so that the truncated value will differ from the original one.
satValue = context.BitwiseAnd(value, Const((int)(uint.MaxValue >> (32 - (int)saturateTo))));
}
else
{
satValue = context.ShiftLeft(value, Const(32 - (int)saturateTo));
satValue = context.ShiftRightSI(satValue, Const(32 - (int)saturateTo));
}
// If the result is 0, the values are equal and we don't need saturation.
Operand lblNoSat = Label();
context.BranchIfFalse(lblNoSat, context.Subtract(value, satValue));
// Saturate and set Q flag.
if (unsigned)
{
if (saturateTo == 31)
{
// Only saturation case possible when going from 32 bits signed to 32 or 31 bits unsigned
// is when the signed input is negative, as all positive values are representable on a 31 bits range.
satValue = Const(0);
}
else
{
satValue = context.ShiftRightSI(value, Const(31));
satValue = context.BitwiseNot(satValue);
satValue = context.ShiftRightUI(satValue, Const(32 - (int)saturateTo));
}
}
else
{
if (saturateTo == 1)
{
satValue = context.ShiftRightSI(value, Const(31));
}
else
{
satValue = Const(uint.MaxValue >> (33 - (int)saturateTo));
satValue = context.BitwiseExclusiveOr(satValue, context.ShiftRightSI(value, Const(31)));
}
}
if (setQ)
{
SetFlag(context, PState.QFlag, Const(1));
}
context.Copy(result, satValue);
Operand lblExit = Label();
context.Branch(lblExit);
context.MarkLabel(lblNoSat);
context.Copy(result, value);
context.MarkLabel(lblExit);
}
private static void EmitSaturateUqadd(ArmEmitterContext context, Operand result, Operand value, uint saturateTo)
{
Debug.Assert(saturateTo <= 32);
if (saturateTo == 32)
{
// No saturation possible for this case.
context.Copy(result, value);
return;
}
else if (saturateTo == 0)
{
// Result is always zero if we saturate 0 bits.
context.Copy(result, Const(0));
return;
}
// If the result is 0, the values are equal and we don't need saturation.
Operand lblNoSat = Label();
context.BranchIfFalse(lblNoSat, context.ShiftRightUI(value, Const((int)saturateTo)));
// Saturate.
context.Copy(result, Const(uint.MaxValue >> (32 - (int)saturateTo)));
Operand lblExit = Label();
context.Branch(lblExit);
context.MarkLabel(lblNoSat);
context.Copy(result, value);
context.MarkLabel(lblExit);
}
private static void EmitSaturateUqsub(ArmEmitterContext context, Operand result, Operand value, uint saturateTo)
{
Debug.Assert(saturateTo <= 32);
if (saturateTo == 32)
{
// No saturation possible for this case.
context.Copy(result, value);
return;
}
else if (saturateTo == 0)
{
// Result is always zero if we saturate 0 bits.
context.Copy(result, Const(0));
return;
}
// If the result is 0, the values are equal and we don't need saturation.
Operand lblNoSat = Label();
context.BranchIf(lblNoSat, value, Const(0), Comparison.GreaterOrEqual);
// Saturate.
// Assumes that the value can only underflow, since this is only used for unsigned subtraction.
context.Copy(result, Const(0));
Operand lblExit = Label();
context.Branch(lblExit);
context.MarkLabel(lblNoSat);
context.Copy(result, value);
context.MarkLabel(lblExit);
}
private static Operand EmitSigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
{
Operand tempD = context.AllocateLocal(OperandType.I32);
Operand tempN = context.SignExtend16(OperandType.I32, rn);
Operand tempM = context.SignExtend16(OperandType.I32, rm);
elementAction(tempD, tempN, tempM);
Operand tempD2 = context.ZeroExtend16(OperandType.I32, tempD);
tempN = context.ShiftRightSI(rn, Const(16));
tempM = context.ShiftRightSI(rm, Const(16));
elementAction(tempD, tempN, tempM);
return context.BitwiseOr(tempD2, context.ShiftLeft(tempD, Const(16)));
}
private static Operand EmitUnsigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
{
Operand tempD = context.AllocateLocal(OperandType.I32);
Operand tempN = context.ZeroExtend16(OperandType.I32, rn);
Operand tempM = context.ZeroExtend16(OperandType.I32, rm);
elementAction(tempD, tempN, tempM);
Operand tempD2 = context.ZeroExtend16(OperandType.I32, tempD);
tempN = context.ShiftRightUI(rn, Const(16));
tempM = context.ShiftRightUI(rm, Const(16));
elementAction(tempD, tempN, tempM);
return context.BitwiseOr(tempD2, context.ShiftLeft(tempD, Const(16)));
}
private static Operand EmitSigned8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
{
return Emit8BitPair(context, rn, rm, elementAction, unsigned: false);
}
private static Operand EmitUnsigned8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
{
return Emit8BitPair(context, rn, rm, elementAction, unsigned: true);
}
private static Operand Emit8BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction, bool unsigned)
{
Operand tempD = context.AllocateLocal(OperandType.I32);
Operand result = default;
for (int b = 0; b < 4; b++)
{
Operand nByte = b != 0 ? context.ShiftRightUI(rn, Const(b * 8)) : rn;
Operand mByte = b != 0 ? context.ShiftRightUI(rm, Const(b * 8)) : rm;
if (unsigned)
{
nByte = context.ZeroExtend8(OperandType.I32, nByte);
mByte = context.ZeroExtend8(OperandType.I32, mByte);
}
else
{
nByte = context.SignExtend8(OperandType.I32, nByte);
mByte = context.SignExtend8(OperandType.I32, mByte);
}
elementAction(tempD, nByte, mByte);
if (b == 0)
{
result = context.ZeroExtend8(OperandType.I32, tempD);
}
else if (b < 3)
{
result = context.BitwiseOr(result, context.ShiftLeft(context.ZeroExtend8(OperandType.I32, tempD), Const(b * 8)));
}
else
{
result = context.BitwiseOr(result, context.ShiftLeft(tempD, Const(24)));
}
}
return result;
}
private static void EmitAluStore(ArmEmitterContext context, Operand value) private static void EmitAluStore(ArmEmitterContext context, Operand value)
{ {
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;

View File

@ -1246,33 +1246,6 @@ namespace ARMeilleure.Instructions
EmitVectorUnaryNarrowOp32(context, (op1) => EmitSatQ(context, op1, 8 << op.Size, signedSrc: true, signedDst: false), signed: true); EmitVectorUnaryNarrowOp32(context, (op1) => EmitSatQ(context, op1, 8 << op.Size, signedSrc: true, signedDst: false), signed: true);
} }
public static void Vqrdmulh(ArmEmitterContext context)
{
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
int eSize = 8 << op.Size;
EmitVectorBinaryOpI32(context, (op1, op2) =>
{
if (op.Size == 2)
{
op1 = context.SignExtend32(OperandType.I64, op1);
op2 = context.SignExtend32(OperandType.I64, op2);
}
Operand res = context.Multiply(op1, op2);
res = context.Add(res, Const(res.Type, 1L << (eSize - 2)));
res = context.ShiftRightSI(res, Const(eSize - 1));
res = EmitSatQ(context, res, eSize, signedSrc: true, signedDst: true);
if (op.Size == 2)
{
res = context.ConvertI64ToI32(res);
}
return res;
}, signed: true);
}
public static void Vqsub(ArmEmitterContext context) public static void Vqsub(ArmEmitterContext context)
{ {
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp; OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;

View File

@ -191,26 +191,6 @@ namespace ARMeilleure.Instructions
context.Copy(GetVecA32(op.Qd), res); context.Copy(GetVecA32(op.Qd), res);
} }
public static void Vswp(ArmEmitterContext context)
{
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
if (op.Q)
{
Operand temp = context.Copy(GetVecA32(op.Qd));
context.Copy(GetVecA32(op.Qd), GetVecA32(op.Qm));
context.Copy(GetVecA32(op.Qm), temp);
}
else
{
Operand temp = ExtractScalar(context, OperandType.I64, op.Vd);
InsertScalar(context, op.Vd, ExtractScalar(context, OperandType.I64, op.Vm));
InsertScalar(context, op.Vm, temp);
}
}
public static void Vtbl(ArmEmitterContext context) public static void Vtbl(ArmEmitterContext context)
{ {
OpCode32SimdTbl op = (OpCode32SimdTbl)context.CurrOp; OpCode32SimdTbl op = (OpCode32SimdTbl)context.CurrOp;

View File

@ -106,38 +106,6 @@ namespace ARMeilleure.Instructions
context.Copy(GetVecA32(op.Qd), res); context.Copy(GetVecA32(op.Qd), res);
} }
public static void Vshll2(ArmEmitterContext context)
{
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
Operand res = context.VectorZero();
int elems = op.GetBytesCount() >> op.Size;
for (int index = 0; index < elems; index++)
{
Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, !op.U);
if (op.Size == 2)
{
if (op.U)
{
me = context.ZeroExtend32(OperandType.I64, me);
}
else
{
me = context.SignExtend32(OperandType.I64, me);
}
}
me = context.ShiftLeft(me, Const(8 << op.Size));
res = EmitVectorInsert(context, res, me, index, op.Size + 1);
}
context.Copy(GetVecA32(op.Qd), res);
}
public static void Vshr(ArmEmitterContext context) public static void Vshr(ArmEmitterContext context)
{ {
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp; OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
@ -162,36 +130,6 @@ namespace ARMeilleure.Instructions
EmitVectorUnaryNarrowOp32(context, (op1) => context.ShiftRightUI(op1, Const(shift))); EmitVectorUnaryNarrowOp32(context, (op1) => context.ShiftRightUI(op1, Const(shift)));
} }
public static void Vsli_I(ArmEmitterContext context)
{
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
int shift = op.Shift;
int eSize = 8 << op.Size;
ulong mask = shift != 0 ? ulong.MaxValue >> (64 - shift) : 0UL;
Operand res = GetVec(op.Qd);
int elems = op.GetBytesCount() >> op.Size;
for (int index = 0; index < elems; index++)
{
Operand me = EmitVectorExtractZx(context, op.Qm, op.Im + index, op.Size);
Operand neShifted = context.ShiftLeft(me, Const(shift));
Operand de = EmitVectorExtractZx(context, op.Qd, op.Id + index, op.Size);
Operand deMasked = context.BitwiseAnd(de, Const(mask));
Operand e = context.BitwiseOr(neShifted, deMasked);
res = EmitVectorInsert(context, res, e, op.Id + index, op.Size);
}
context.Copy(GetVec(op.Qd), res);
}
public static void Vsra(ArmEmitterContext context) public static void Vsra(ArmEmitterContext context)
{ {
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp; OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;

View File

@ -527,7 +527,6 @@ namespace ARMeilleure.Instructions
Pld, Pld,
Pop, Pop,
Push, Push,
Qadd16,
Rev, Rev,
Revsh, Revsh,
Rsb, Rsb,
@ -572,10 +571,6 @@ namespace ARMeilleure.Instructions
Umaal, Umaal,
Umlal, Umlal,
Umull, Umull,
Uqadd16,
Uqadd8,
Uqsub16,
Uqsub8,
Usat, Usat,
Usat16, Usat16,
Usub8, Usub8,
@ -650,7 +645,6 @@ namespace ARMeilleure.Instructions
Vqdmulh, Vqdmulh,
Vqmovn, Vqmovn,
Vqmovun, Vqmovun,
Vqrdmulh,
Vqrshrn, Vqrshrn,
Vqrshrun, Vqrshrun,
Vqshrn, Vqshrn,
@ -672,7 +666,6 @@ namespace ARMeilleure.Instructions
Vshll, Vshll,
Vshr, Vshr,
Vshrn, Vshrn,
Vsli,
Vst1, Vst1,
Vst2, Vst2,
Vst3, Vst3,
@ -689,7 +682,6 @@ namespace ARMeilleure.Instructions
Vsub, Vsub,
Vsubl, Vsubl,
Vsubw, Vsubw,
Vswp,
Vtbl, Vtbl,
Vtrn, Vtrn,
Vtst, Vtst,

View File

@ -11,7 +11,7 @@ namespace ARMeilleure.Translation
private int[] _postOrderMap; private int[] _postOrderMap;
public int LocalsCount { get; private set; } public int LocalsCount { get; private set; }
public BasicBlock Entry { get; private set; } public BasicBlock Entry { get; }
public IntrusiveList<BasicBlock> Blocks { get; } public IntrusiveList<BasicBlock> Blocks { get; }
public BasicBlock[] PostOrderBlocks => _postOrderBlocks; public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
public int[] PostOrderMap => _postOrderMap; public int[] PostOrderMap => _postOrderMap;
@ -34,15 +34,6 @@ namespace ARMeilleure.Translation
return result; return result;
} }
public void UpdateEntry(BasicBlock newEntry)
{
newEntry.AddSuccessor(Entry);
Entry = newEntry;
Blocks.AddFirst(newEntry);
Update();
}
public void Update() public void Update()
{ {
RemoveUnreachableBlocks(Blocks); RemoveUnreachableBlocks(Blocks);

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Runtime.InteropServices;
namespace ARMeilleure.Translation namespace ARMeilleure.Translation
{ {
@ -10,10 +11,11 @@ namespace ARMeilleure.Translation
public IntPtr FuncPtr { get; } public IntPtr FuncPtr { get; }
public DelegateInfo(Delegate dlg, IntPtr funcPtr) public DelegateInfo(Delegate dlg)
{ {
_dlg = dlg; _dlg = dlg;
FuncPtr = funcPtr;
FuncPtr = Marshal.GetFunctionPointerForDelegate<Delegate>(dlg);
} }
} }
} }

View File

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

View File

@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 6950; //! To be incremented manually for each change to the ARMeilleure project. private const uint InternalVersion = 6634; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0"; private const string ActualDir = "0";
private const string BackupDir = "1"; private const string BackupDir = "1";

View File

@ -89,17 +89,6 @@ namespace ARMeilleure.Translation
public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode) public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode)
{ {
if (cfg.Entry.Predecessors.Count != 0)
{
// We expect the entry block to have no predecessors.
// This is required because we have a implicit context load at the start of the function,
// but if there is a jump to the start of the function, the context load would trash the modified values.
// Here we insert a new entry block that will jump to the existing entry block.
BasicBlock newEntry = new BasicBlock(cfg.Blocks.Count);
cfg.UpdateEntry(newEntry);
}
// Compute local register inputs and outputs used inside blocks. // Compute local register inputs and outputs used inside blocks.
RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count];
RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];
@ -212,7 +201,7 @@ namespace ARMeilleure.Translation
// The only block without any predecessor should be the entry block. // The only block without any predecessor should be the entry block.
// It always needs a context load as it is the first block to run. // It always needs a context load as it is the first block to run.
if (block == cfg.Entry || hasContextLoad) if (block.Predecessors.Count == 0 || hasContextLoad)
{ {
long vecMask = globalInputs[block.Index].VecMask; long vecMask = globalInputs[block.Index].VecMask;
long intMask = globalInputs[block.Index].IntMask; long intMask = globalInputs[block.Index].IntMask;

View File

@ -80,10 +80,7 @@ namespace ARMeilleure.Translation
return true; return true;
} }
if (!_disposed) Monitor.Wait(Sync);
{
Monitor.Wait(Sync);
}
} }
} }

View File

@ -89,9 +89,9 @@ namespace Ryujinx.Audio.Backends.SDL2
return; return;
} }
using SpanOwner<byte> samplesOwner = SpanOwner<byte>.Rent(frameCount * _bytesPerFrame); using IMemoryOwner<byte> samplesOwner = ByteMemoryPool.Rent(frameCount * _bytesPerFrame);
Span<byte> samples = samplesOwner.Span; Span<byte> samples = samplesOwner.Memory.Span;
_ringBuffer.Read(samples, 0, samples.Length); _ringBuffer.Read(samples, 0, samples.Length);

View File

@ -122,9 +122,9 @@ namespace Ryujinx.Audio.Backends.SoundIo
int channelCount = areas.Length; int channelCount = areas.Length;
using SpanOwner<byte> samplesOwner = SpanOwner<byte>.Rent(frameCount * bytesPerFrame); using IMemoryOwner<byte> samplesOwner = ByteMemoryPool.Rent(frameCount * bytesPerFrame);
Span<byte> samples = samplesOwner.Span; Span<byte> samples = samplesOwner.Memory.Span;
_ringBuffer.Read(samples, 0, samples.Length); _ringBuffer.Read(samples, 0, samples.Length);

View File

@ -14,7 +14,7 @@ namespace Ryujinx.Audio.Backends.Common
private readonly object _lock = new(); private readonly object _lock = new();
private MemoryOwner<byte> _bufferOwner; private IMemoryOwner<byte> _bufferOwner;
private Memory<byte> _buffer; private Memory<byte> _buffer;
private int _size; private int _size;
private int _headOffset; private int _headOffset;
@ -24,7 +24,7 @@ namespace Ryujinx.Audio.Backends.Common
public DynamicRingBuffer(int initialCapacity = RingBufferAlignment) public DynamicRingBuffer(int initialCapacity = RingBufferAlignment)
{ {
_bufferOwner = MemoryOwner<byte>.RentCleared(initialCapacity); _bufferOwner = ByteMemoryPool.RentCleared(initialCapacity);
_buffer = _bufferOwner.Memory; _buffer = _bufferOwner.Memory;
} }
@ -62,7 +62,7 @@ namespace Ryujinx.Audio.Backends.Common
private void SetCapacityLocked(int capacity) private void SetCapacityLocked(int capacity)
{ {
MemoryOwner<byte> newBufferOwner = MemoryOwner<byte>.RentCleared(capacity); IMemoryOwner<byte> newBufferOwner = ByteMemoryPool.RentCleared(capacity);
Memory<byte> newBuffer = newBufferOwner.Memory; Memory<byte> newBuffer = newBufferOwner.Memory;
if (_size > 0) if (_size > 0)

View File

@ -1,11 +1,9 @@
using Ryujinx.Audio.Renderer.Dsp.Effect; using Ryujinx.Audio.Renderer.Dsp.Effect;
using Ryujinx.Audio.Renderer.Dsp.State; using Ryujinx.Audio.Renderer.Dsp.State;
using Ryujinx.Audio.Renderer.Parameter;
using Ryujinx.Audio.Renderer.Parameter.Effect; using Ryujinx.Audio.Renderer.Parameter.Effect;
using Ryujinx.Audio.Renderer.Server.Effect; using Ryujinx.Audio.Renderer.Server.Effect;
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Dsp.Command namespace Ryujinx.Audio.Renderer.Dsp.Command
{ {
@ -23,20 +21,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
public CompressorParameter Parameter => _parameter; public CompressorParameter Parameter => _parameter;
public Memory<CompressorState> State { get; } public Memory<CompressorState> State { get; }
public Memory<EffectResultState> ResultState { get; }
public ushort[] OutputBufferIndices { get; } public ushort[] OutputBufferIndices { get; }
public ushort[] InputBufferIndices { get; } public ushort[] InputBufferIndices { get; }
public bool IsEffectEnabled { get; } public bool IsEffectEnabled { get; }
private CompressorParameter _parameter; private CompressorParameter _parameter;
public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> resultState, bool isEnabled, int nodeId) public CompressorCommand(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
{ {
Enabled = true; Enabled = true;
NodeId = nodeId; NodeId = nodeId;
_parameter = parameter; _parameter = parameter;
State = state; State = state;
ResultState = resultState;
IsEffectEnabled = isEnabled; IsEffectEnabled = isEnabled;
@ -75,16 +71,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled && _parameter.IsChannelCountValid()) if (IsEffectEnabled && _parameter.IsChannelCountValid())
{ {
if (!ResultState.IsEmpty && _parameter.StatisticsReset) Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
{ Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(ResultState.Span[0].SpecificData)[0]; Span<float> channelInput = stackalloc float[Parameter.ChannelCount];
statistics.Reset(_parameter.ChannelCount);
}
Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount];
Span<float> channelInput = stackalloc float[_parameter.ChannelCount];
ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage; ExponentialMovingAverage inputMovingAverage = state.InputMovingAverage;
float unknown4 = state.Unknown4; float unknown4 = state.Unknown4;
ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage; ExponentialMovingAverage compressionGainAverage = state.CompressionGainAverage;
@ -103,8 +92,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex); channelInput[channelIndex] = *((float*)inputBuffers[channelIndex] + sampleIndex);
} }
float mean = FloatingPointHelper.MeanSquare(channelInput); float newMean = inputMovingAverage.Update(FloatingPointHelper.MeanSquare(channelInput), _parameter.InputGain);
float newMean = inputMovingAverage.Update(mean, _parameter.InputGain);
float y = FloatingPointHelper.Log10(newMean) * 10.0f; float y = FloatingPointHelper.Log10(newMean) * 10.0f;
float z = 1.0f; float z = 1.0f;
@ -123,7 +111,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (y >= state.Unknown14) if (y >= state.Unknown14)
{ {
tmpGain = ((1.0f / _parameter.Ratio) - 1.0f) * (y - _parameter.Threshold); tmpGain = ((1.0f / Parameter.Ratio) - 1.0f) * (y - Parameter.Threshold);
} }
else else
{ {
@ -138,7 +126,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if ((unknown4 - z) <= 0.08f) if ((unknown4 - z) <= 0.08f)
{ {
compressionEmaAlpha = _parameter.ReleaseCoefficient; compressionEmaAlpha = Parameter.ReleaseCoefficient;
if ((unknown4 - z) >= -0.08f) if ((unknown4 - z) >= -0.08f)
{ {
@ -152,31 +140,18 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
} }
else else
{ {
compressionEmaAlpha = _parameter.AttackCoefficient; compressionEmaAlpha = Parameter.AttackCoefficient;
} }
float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha); float compressionGain = compressionGainAverage.Update(z, compressionEmaAlpha);
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
{ {
*((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain; *((float*)outputBuffers[channelIndex] + sampleIndex) = channelInput[channelIndex] * compressionGain * state.OutputGain;
} }
unknown4 = unknown4New; unknown4 = unknown4New;
previousCompressionEmaAlpha = compressionEmaAlpha; previousCompressionEmaAlpha = compressionEmaAlpha;
if (!ResultState.IsEmpty)
{
ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(ResultState.Span[0].SpecificData)[0];
statistics.MinimumGain = MathF.Min(statistics.MinimumGain, compressionGain * state.OutputGain);
statistics.MaximumMean = MathF.Max(statistics.MaximumMean, mean);
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++)
{
statistics.LastSamples[channelIndex] = MathF.Abs(channelInput[channelIndex] * (1f / 32768f));
}
}
} }
state.InputMovingAverage = inputMovingAverage; state.InputMovingAverage = inputMovingAverage;
@ -186,7 +161,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
} }
else else
{ {
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
if (InputBufferIndices[i] != OutputBufferIndices[i]) if (InputBufferIndices[i] != OutputBufferIndices[i])
{ {

View File

@ -38,10 +38,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]); InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]); OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
} }
} }
@ -51,11 +51,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled) if (IsEffectEnabled)
{ {
if (_parameter.Status == UsageState.Invalid) if (Parameter.Status == UsageState.Invalid)
{ {
state = new LimiterState(ref _parameter, WorkBuffer); state = new LimiterState(ref _parameter, WorkBuffer);
} }
else if (_parameter.Status == UsageState.New) else if (Parameter.Status == UsageState.New)
{ {
LimiterState.UpdateParameter(ref _parameter); LimiterState.UpdateParameter(ref _parameter);
} }
@ -66,56 +66,56 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private unsafe void ProcessLimiter(CommandList context, ref LimiterState state) private unsafe void ProcessLimiter(CommandList context, ref LimiterState state)
{ {
Debug.Assert(_parameter.IsChannelCountValid()); Debug.Assert(Parameter.IsChannelCountValid());
if (IsEffectEnabled && _parameter.IsChannelCountValid()) if (IsEffectEnabled && Parameter.IsChannelCountValid())
{ {
Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]); inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]); outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
} }
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
{ {
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++) for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
{ {
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex); float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
float inputSample = (rawInputSample / short.MaxValue) * _parameter.InputGain; float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
float sampleInputMax = Math.Abs(inputSample); float sampleInputMax = Math.Abs(inputSample);
float inputCoefficient = _parameter.ReleaseCoefficient; float inputCoefficient = Parameter.ReleaseCoefficient;
if (sampleInputMax > state.DetectorAverage[channelIndex].Read()) if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
{ {
inputCoefficient = _parameter.AttackCoefficient; inputCoefficient = Parameter.AttackCoefficient;
} }
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient); float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
float attenuation = 1.0f; float attenuation = 1.0f;
if (detectorValue > _parameter.Threshold) if (detectorValue > Parameter.Threshold)
{ {
attenuation = _parameter.Threshold / detectorValue; attenuation = Parameter.Threshold / detectorValue;
} }
float outputCoefficient = _parameter.ReleaseCoefficient; float outputCoefficient = Parameter.ReleaseCoefficient;
if (state.CompressionGainAverage[channelIndex].Read() > attenuation) if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
{ {
outputCoefficient = _parameter.AttackCoefficient; outputCoefficient = Parameter.AttackCoefficient;
} }
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient); float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * _parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
float outputSample = delayedSample * compressionGain * _parameter.OutputGain; float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue; *((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
@ -123,16 +123,16 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
state.DelayedSampleBufferPosition[channelIndex]++; state.DelayedSampleBufferPosition[channelIndex]++;
while (state.DelayedSampleBufferPosition[channelIndex] >= _parameter.DelayBufferSampleCountMin) while (state.DelayedSampleBufferPosition[channelIndex] >= Parameter.DelayBufferSampleCountMin)
{ {
state.DelayedSampleBufferPosition[channelIndex] -= _parameter.DelayBufferSampleCountMin; state.DelayedSampleBufferPosition[channelIndex] -= Parameter.DelayBufferSampleCountMin;
} }
} }
} }
} }
else else
{ {
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
if (InputBufferIndices[i] != OutputBufferIndices[i]) if (InputBufferIndices[i] != OutputBufferIndices[i])
{ {

View File

@ -49,10 +49,10 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
InputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; InputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax]; OutputBufferIndices = new ushort[Constants.VoiceChannelCountMax];
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
InputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Input[i]); InputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Input[i]);
OutputBufferIndices[i] = (ushort)(bufferOffset + _parameter.Output[i]); OutputBufferIndices[i] = (ushort)(bufferOffset + Parameter.Output[i]);
} }
} }
@ -62,11 +62,11 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
if (IsEffectEnabled) if (IsEffectEnabled)
{ {
if (_parameter.Status == UsageState.Invalid) if (Parameter.Status == UsageState.Invalid)
{ {
state = new LimiterState(ref _parameter, WorkBuffer); state = new LimiterState(ref _parameter, WorkBuffer);
} }
else if (_parameter.Status == UsageState.New) else if (Parameter.Status == UsageState.New)
{ {
LimiterState.UpdateParameter(ref _parameter); LimiterState.UpdateParameter(ref _parameter);
} }
@ -77,63 +77,63 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
private unsafe void ProcessLimiter(CommandList context, ref LimiterState state) private unsafe void ProcessLimiter(CommandList context, ref LimiterState state)
{ {
Debug.Assert(_parameter.IsChannelCountValid()); Debug.Assert(Parameter.IsChannelCountValid());
if (IsEffectEnabled && _parameter.IsChannelCountValid()) if (IsEffectEnabled && Parameter.IsChannelCountValid())
{ {
if (!ResultState.IsEmpty && _parameter.StatisticsReset) if (!ResultState.IsEmpty && Parameter.StatisticsReset)
{ {
ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0]; ref LimiterStatistics statistics = ref MemoryMarshal.Cast<byte, LimiterStatistics>(ResultState.Span[0].SpecificData)[0];
statistics.Reset(); statistics.Reset();
} }
Span<IntPtr> inputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; Span<IntPtr> inputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
Span<IntPtr> outputBuffers = stackalloc IntPtr[_parameter.ChannelCount]; Span<IntPtr> outputBuffers = stackalloc IntPtr[Parameter.ChannelCount];
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]); inputBuffers[i] = context.GetBufferPointer(InputBufferIndices[i]);
outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]); outputBuffers[i] = context.GetBufferPointer(OutputBufferIndices[i]);
} }
for (int channelIndex = 0; channelIndex < _parameter.ChannelCount; channelIndex++) for (int channelIndex = 0; channelIndex < Parameter.ChannelCount; channelIndex++)
{ {
for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++) for (int sampleIndex = 0; sampleIndex < context.SampleCount; sampleIndex++)
{ {
float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex); float rawInputSample = *((float*)inputBuffers[channelIndex] + sampleIndex);
float inputSample = (rawInputSample / short.MaxValue) * _parameter.InputGain; float inputSample = (rawInputSample / short.MaxValue) * Parameter.InputGain;
float sampleInputMax = Math.Abs(inputSample); float sampleInputMax = Math.Abs(inputSample);
float inputCoefficient = _parameter.ReleaseCoefficient; float inputCoefficient = Parameter.ReleaseCoefficient;
if (sampleInputMax > state.DetectorAverage[channelIndex].Read()) if (sampleInputMax > state.DetectorAverage[channelIndex].Read())
{ {
inputCoefficient = _parameter.AttackCoefficient; inputCoefficient = Parameter.AttackCoefficient;
} }
float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient); float detectorValue = state.DetectorAverage[channelIndex].Update(sampleInputMax, inputCoefficient);
float attenuation = 1.0f; float attenuation = 1.0f;
if (detectorValue > _parameter.Threshold) if (detectorValue > Parameter.Threshold)
{ {
attenuation = _parameter.Threshold / detectorValue; attenuation = Parameter.Threshold / detectorValue;
} }
float outputCoefficient = _parameter.ReleaseCoefficient; float outputCoefficient = Parameter.ReleaseCoefficient;
if (state.CompressionGainAverage[channelIndex].Read() > attenuation) if (state.CompressionGainAverage[channelIndex].Read() > attenuation)
{ {
outputCoefficient = _parameter.AttackCoefficient; outputCoefficient = Parameter.AttackCoefficient;
} }
float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient); float compressionGain = state.CompressionGainAverage[channelIndex].Update(attenuation, outputCoefficient);
ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * _parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]]; ref float delayedSample = ref state.DelayedSampleBuffer[channelIndex * Parameter.DelayBufferSampleCountMax + state.DelayedSampleBufferPosition[channelIndex]];
float outputSample = delayedSample * compressionGain * _parameter.OutputGain; float outputSample = delayedSample * compressionGain * Parameter.OutputGain;
*((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue; *((float*)outputBuffers[channelIndex] + sampleIndex) = outputSample * short.MaxValue;
@ -141,9 +141,9 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
state.DelayedSampleBufferPosition[channelIndex]++; state.DelayedSampleBufferPosition[channelIndex]++;
while (state.DelayedSampleBufferPosition[channelIndex] >= _parameter.DelayBufferSampleCountMin) while (state.DelayedSampleBufferPosition[channelIndex] >= Parameter.DelayBufferSampleCountMin)
{ {
state.DelayedSampleBufferPosition[channelIndex] -= _parameter.DelayBufferSampleCountMin; state.DelayedSampleBufferPosition[channelIndex] -= Parameter.DelayBufferSampleCountMin;
} }
if (!ResultState.IsEmpty) if (!ResultState.IsEmpty)
@ -158,7 +158,7 @@ namespace Ryujinx.Audio.Renderer.Dsp.Command
} }
else else
{ {
for (int i = 0; i < _parameter.ChannelCount; i++) for (int i = 0; i < Parameter.ChannelCount; i++)
{ {
if (InputBufferIndices[i] != OutputBufferIndices[i]) if (InputBufferIndices[i] != OutputBufferIndices[i])
{ {

View File

@ -90,16 +90,9 @@ namespace Ryujinx.Audio.Renderer.Parameter.Effect
public bool MakeupGainEnabled; public bool MakeupGainEnabled;
/// <summary> /// <summary>
/// Indicate if the compressor effect should output statistics. /// Reserved/padding.
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.I1)] private Array2<byte> _reserved;
public bool StatisticsEnabled;
/// <summary>
/// Indicate to the DSP that the user did a statistics reset.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool StatisticsReset;
/// <summary> /// <summary>
/// Check if the <see cref="ChannelCount"/> is valid. /// Check if the <see cref="ChannelCount"/> is valid.

View File

@ -1,38 +0,0 @@
using Ryujinx.Common.Memory;
using System.Runtime.InteropServices;
namespace Ryujinx.Audio.Renderer.Parameter.Effect
{
/// <summary>
/// Effect result state for <seealso cref="Common.EffectType.Compressor"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CompressorStatistics
{
/// <summary>
/// Maximum input mean value since last reset.
/// </summary>
public float MaximumMean;
/// <summary>
/// Minimum output gain since last reset.
/// </summary>
public float MinimumGain;
/// <summary>
/// Last processed input sample, per channel.
/// </summary>
public Array6<float> LastSamples;
/// <summary>
/// Reset the statistics.
/// </summary>
/// <param name="channelCount">Number of channels to reset.</param>
public void Reset(ushort channelCount)
{
MaximumMean = 0.0f;
MinimumGain = 1.0f;
LastSamples.AsSpan()[..channelCount].Clear();
}
}
}

View File

@ -28,11 +28,6 @@ namespace Ryujinx.Audio.Renderer.Parameter
/// </summary> /// </summary>
bool IsUsed { get; } bool IsUsed { get; }
/// <summary>
/// Set to true to force resetting the previous mix volumes.
/// </summary>
bool ResetPrevVolume { get; }
/// <summary> /// <summary>
/// Mix buffer volumes. /// Mix buffer volumes.
/// </summary> /// </summary>

View File

@ -37,16 +37,10 @@ namespace Ryujinx.Audio.Renderer.Parameter
[MarshalAs(UnmanagedType.I1)] [MarshalAs(UnmanagedType.I1)]
public bool IsUsed; public bool IsUsed;
/// <summary>
/// Set to true to force resetting the previous mix volumes.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool ResetPrevVolume;
/// <summary> /// <summary>
/// Reserved/padding. /// Reserved/padding.
/// </summary> /// </summary>
private unsafe fixed byte _reserved[2]; private unsafe fixed byte _reserved[3];
[StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)]
private struct MixArray { } private struct MixArray { }
@ -64,7 +58,6 @@ namespace Ryujinx.Audio.Renderer.Parameter
readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => default; readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => default;
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
/// <summary> /// <summary>
/// The expected constant of any input header. /// The expected constant of any input header.

View File

@ -42,16 +42,10 @@ namespace Ryujinx.Audio.Renderer.Parameter
[MarshalAs(UnmanagedType.I1)] [MarshalAs(UnmanagedType.I1)]
public bool IsUsed; public bool IsUsed;
/// <summary>
/// Set to true to force resetting the previous mix volumes.
/// </summary>
[MarshalAs(UnmanagedType.I1)]
public bool ResetPrevVolume;
/// <summary> /// <summary>
/// Reserved/padding. /// Reserved/padding.
/// </summary> /// </summary>
private unsafe fixed byte _reserved[10]; private unsafe fixed byte _reserved[11];
[StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)] [StructLayout(LayoutKind.Sequential, Size = sizeof(float) * Constants.MixBufferCountMax, Pack = 1)]
private struct MixArray { } private struct MixArray { }
@ -69,7 +63,6 @@ namespace Ryujinx.Audio.Renderer.Parameter
readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => BiquadFilters; readonly Array2<BiquadFilterParameter> ISplitterDestinationInParameter.BiquadFilters => BiquadFilters;
readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed; readonly bool ISplitterDestinationInParameter.IsUsed => IsUsed;
readonly bool ISplitterDestinationInParameter.ResetPrevVolume => ResetPrevVolume;
/// <summary> /// <summary>
/// The expected constant of any input header. /// The expected constant of any input header.

View File

@ -108,18 +108,10 @@ namespace Ryujinx.Audio.Renderer.Server
/// <remarks>This was added in system update 17.0.0</remarks> /// <remarks>This was added in system update 17.0.0</remarks>
public const int Revision12 = 12 << 24; public const int Revision12 = 12 << 24;
/// <summary>
/// REV13:
/// The compressor effect can now output statistics.
/// Splitter destinations now explicitly reset the previous mix volume, instead of doing so on first use.
/// </summary>
/// <remarks>This was added in system update 18.0.0</remarks>
public const int Revision13 = 13 << 24;
/// <summary> /// <summary>
/// Last revision supported by the implementation. /// Last revision supported by the implementation.
/// </summary> /// </summary>
public const int LastRevision = Revision13; public const int LastRevision = Revision12;
/// <summary> /// <summary>
/// Target revision magic supported by the implementation. /// Target revision magic supported by the implementation.
@ -392,15 +384,6 @@ namespace Ryujinx.Audio.Renderer.Server
return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision12); return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision12);
} }
/// <summary>
/// Check if the audio renderer should support explicit previous mix volume reset on splitter.
/// </summary>
/// <returns>True if the audio renderer support explicit previous mix volume reset on splitter</returns>
public bool IsSplitterPrevVolumeResetSupported()
{
return CheckFeatureSupported(UserRevision, BaseRevisionMagic + Revision13);
}
/// <summary> /// <summary>
/// Get the version of the <see cref="ICommandProcessingTimeEstimator"/>. /// Get the version of the <see cref="ICommandProcessingTimeEstimator"/>.
/// </summary> /// </summary>

View File

@ -583,20 +583,11 @@ namespace Ryujinx.Audio.Renderer.Server
} }
} }
/// <summary> public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, bool isEnabled, int nodeId)
/// Generate a new <see cref="CompressorCommand"/>.
/// </summary>
/// <param name="bufferOffset">The target buffer offset.</param>
/// <param name="parameter">The compressor parameter.</param>
/// <param name="state">The compressor state.</param>
/// <param name="effectResultState">The DSP effect result state.</param>
/// <param name="isEnabled">Set to true if the effect should be active.</param>
/// <param name="nodeId">The node id associated to this command.</param>
public void GenerateCompressorEffect(uint bufferOffset, CompressorParameter parameter, Memory<CompressorState> state, Memory<EffectResultState> effectResultState, bool isEnabled, int nodeId)
{ {
if (parameter.IsChannelCountValid()) if (parameter.IsChannelCountValid())
{ {
CompressorCommand command = new(bufferOffset, parameter, state, effectResultState, isEnabled, nodeId); CompressorCommand command = new(bufferOffset, parameter, state, isEnabled, nodeId);
command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command); command.EstimatedProcessingTime = _commandProcessingTimeEstimator.Estimate(command);

View File

@ -735,26 +735,14 @@ namespace Ryujinx.Audio.Renderer.Server
} }
} }
private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId, int effectId) private void GenerateCompressorEffect(uint bufferOffset, CompressorEffect effect, int nodeId)
{ {
Debug.Assert(effect.Type == EffectType.Compressor); Debug.Assert(effect.Type == EffectType.Compressor);
Memory<EffectResultState> dspResultState;
if (effect.Parameter.StatisticsEnabled)
{
dspResultState = _effectContext.GetDspStateMemory(effectId);
}
else
{
dspResultState = Memory<EffectResultState>.Empty;
}
_commandBuffer.GenerateCompressorEffect( _commandBuffer.GenerateCompressorEffect(
bufferOffset, bufferOffset,
effect.Parameter, effect.Parameter,
effect.State, effect.State,
dspResultState,
effect.IsEnabled, effect.IsEnabled,
nodeId); nodeId);
} }
@ -807,7 +795,7 @@ namespace Ryujinx.Audio.Renderer.Server
GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId); GenerateCaptureEffect(mix.BufferOffset, (CaptureBufferEffect)effect, nodeId);
break; break;
case EffectType.Compressor: case EffectType.Compressor:
GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId, effectId); GenerateCompressorEffect(mix.BufferOffset, (CompressorEffect)effect, nodeId);
break; break;
default: default:
throw new NotImplementedException($"Unsupported effect type {effect.Type}"); throw new NotImplementedException($"Unsupported effect type {effect.Type}");

View File

@ -169,28 +169,14 @@ namespace Ryujinx.Audio.Renderer.Server
{ {
if (command.Enabled) if (command.Enabled)
{ {
if (command.Parameter.StatisticsEnabled) return command.Parameter.ChannelCount switch
{ {
return command.Parameter.ChannelCount switch 1 => 34431,
{ 2 => 44253,
1 => 22100, 4 => 63827,
2 => 33211, 6 => 83361,
4 => 41587, _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
6 => 58819, };
_ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
};
}
else
{
return command.Parameter.ChannelCount switch
{
1 => 19052,
2 => 29852,
4 => 37904,
6 => 55020,
_ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
};
}
} }
return command.Parameter.ChannelCount switch return command.Parameter.ChannelCount switch
@ -205,28 +191,14 @@ namespace Ryujinx.Audio.Renderer.Server
if (command.Enabled) if (command.Enabled)
{ {
if (command.Parameter.StatisticsEnabled) return command.Parameter.ChannelCount switch
{ {
return command.Parameter.ChannelCount switch 1 => 51095,
{ 2 => 65693,
1 => 32518, 4 => 95383,
2 => 49102, 6 => 124510,
4 => 61685, _ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
6 => 87250, };
_ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
};
}
else
{
return command.Parameter.ChannelCount switch
{
1 => 27963,
2 => 44016,
4 => 56183,
6 => 81862,
_ => throw new NotImplementedException($"{command.Parameter.ChannelCount}"),
};
}
} }
return command.Parameter.ChannelCount switch return command.Parameter.ChannelCount switch

View File

@ -62,19 +62,6 @@ namespace Ryujinx.Audio.Renderer.Server.Effect
UpdateUsageStateForCommandGeneration(); UpdateUsageStateForCommandGeneration();
Parameter.Status = UsageState.Enabled; Parameter.Status = UsageState.Enabled;
Parameter.StatisticsReset = false;
}
public override void InitializeResultState(ref EffectResultState state)
{
ref CompressorStatistics statistics = ref MemoryMarshal.Cast<byte, CompressorStatistics>(state.SpecificData)[0];
statistics.Reset(Parameter.ChannelCount);
}
public override void UpdateResultState(ref EffectResultState destState, ref EffectResultState srcState)
{
destState = srcState;
} }
} }
} }

View File

@ -18,12 +18,16 @@ namespace Ryujinx.Audio.Renderer.Server.Performance
if (version == 2) if (version == 2)
{ {
return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion2, PerformanceEntryVersion2, PerformanceDetailVersion2>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion2,
PerformanceEntryVersion2,
PerformanceDetailVersion2>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter);
} }
if (version == 1) if (version == 1)
{ {
return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion1, PerformanceEntryVersion1, PerformanceDetailVersion1>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter); return (ulong)PerformanceManagerGeneric<PerformanceFrameHeaderVersion1,
PerformanceEntryVersion1,
PerformanceDetailVersion1>.GetRequiredBufferSizeForPerformanceMetricsPerFrame(ref parameter);
} }
throw new NotImplementedException($"Unknown Performance metrics data format version {version}"); throw new NotImplementedException($"Unknown Performance metrics data format version {version}");

View File

@ -234,7 +234,7 @@ namespace Ryujinx.Audio.Renderer.Server.Performance
{ {
performanceEntry = null; performanceEntry = null;
if (_entryDetailIndex >= MaxFrameDetailCount) if (_entryDetailIndex > MaxFrameDetailCount)
{ {
return false; return false;
} }
@ -245,7 +245,7 @@ namespace Ryujinx.Audio.Renderer.Server.Performance
EntryCountOffset = (uint)CurrentHeader.GetEntryCountOffset(), EntryCountOffset = (uint)CurrentHeader.GetEntryCountOffset(),
}; };
uint baseEntryOffset = (uint)(Unsafe.SizeOf<THeader>() + GetEntriesSize() + Unsafe.SizeOf<TEntryDetail>() * _entryDetailIndex); uint baseEntryOffset = (uint)(Unsafe.SizeOf<THeader>() + GetEntriesSize() + Unsafe.SizeOf<IPerformanceDetailEntry>() * _entryDetailIndex);
ref TEntryDetail entryDetail = ref EntriesDetail[_entryDetailIndex]; ref TEntryDetail entryDetail = ref EntriesDetail[_entryDetailIndex];

View File

@ -51,11 +51,6 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// </summary> /// </summary>
public bool IsBugFixed { get; private set; } public bool IsBugFixed { get; private set; }
/// <summary>
/// If set to true, the previous mix volume is explicitly resetted using the input parameter, instead of implicitly on first use.
/// </summary>
public bool IsSplitterPrevVolumeResetSupported { get; private set; }
/// <summary> /// <summary>
/// Initialize <see cref="SplitterContext"/>. /// Initialize <see cref="SplitterContext"/>.
/// </summary> /// </summary>
@ -144,8 +139,6 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
} }
} }
IsSplitterPrevVolumeResetSupported = behaviourContext.IsSplitterPrevVolumeResetSupported();
SplitterState.InitializeSplitters(splitters.Span); SplitterState.InitializeSplitters(splitters.Span);
Setup(splitters, splitterDestinationsV1, splitterDestinationsV2, behaviourContext.IsSplitterBugFixed()); Setup(splitters, splitterDestinationsV1, splitterDestinationsV2, behaviourContext.IsSplitterBugFixed());
@ -284,7 +277,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
{ {
SplitterDestination destination = GetDestination(parameter.Id); SplitterDestination destination = GetDestination(parameter.Id);
destination.Update(parameter, IsSplitterPrevVolumeResetSupported); destination.Update(parameter);
} }
return true; return true;

View File

@ -184,16 +184,15 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the splitter destination data from user parameter. /// Update the splitter destination data from user parameter.
/// </summary> /// </summary>
/// <param name="parameter">The user parameter.</param> /// <param name="parameter">The user parameter.</param>
/// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param> public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{ {
if (Unsafe.IsNullRef(ref _v2)) if (Unsafe.IsNullRef(ref _v2))
{ {
_v1.Update(parameter, isPrevVolumeResetSupported); _v1.Update(parameter);
} }
else else
{ {
_v2.Update(parameter, isPrevVolumeResetSupported); _v2.Update(parameter);
} }
} }

View File

@ -93,8 +93,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the <see cref="SplitterDestinationVersion1"/> from user parameter. /// Update the <see cref="SplitterDestinationVersion1"/> from user parameter.
/// </summary> /// </summary>
/// <param name="parameter">The user parameter.</param> /// <param name="parameter">The user parameter.</param>
/// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param> public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{ {
Debug.Assert(Id == parameter.Id); Debug.Assert(Id == parameter.Id);
@ -104,8 +103,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
parameter.MixBufferVolume.CopyTo(MixBufferVolume); parameter.MixBufferVolume.CopyTo(MixBufferVolume);
bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed; if (!IsUsed && parameter.IsUsed)
if (resetPrevVolume)
{ {
MixBufferVolume.CopyTo(PreviousMixBufferVolume); MixBufferVolume.CopyTo(PreviousMixBufferVolume);

View File

@ -98,8 +98,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
/// Update the <see cref="SplitterDestinationVersion2"/> from user parameter. /// Update the <see cref="SplitterDestinationVersion2"/> from user parameter.
/// </summary> /// </summary>
/// <param name="parameter">The user parameter.</param> /// <param name="parameter">The user parameter.</param>
/// <param name="isPrevVolumeResetSupported">Indicates that the audio renderer revision in use supports explicitly resetting the volume.</param> public void Update<T>(in T parameter) where T : ISplitterDestinationInParameter
public void Update<T>(in T parameter, bool isPrevVolumeResetSupported) where T : ISplitterDestinationInParameter
{ {
Debug.Assert(Id == parameter.Id); Debug.Assert(Id == parameter.Id);
@ -111,8 +110,7 @@ namespace Ryujinx.Audio.Renderer.Server.Splitter
_biquadFilters = parameter.BiquadFilters; _biquadFilters = parameter.BiquadFilters;
bool resetPrevVolume = isPrevVolumeResetSupported ? parameter.ResetPrevVolume : !IsUsed && parameter.IsUsed; if (!IsUsed && parameter.IsUsed)
if (resetPrevVolume)
{ {
MixBufferVolume.CopyTo(PreviousMixBufferVolume); MixBufferVolume.CopyTo(PreviousMixBufferVolume);

View File

@ -1,33 +1,13 @@
using Ryujinx.Common.Utilities;
using System; using System;
namespace Ryujinx.Common.GraphicsDriver namespace Ryujinx.Common.GraphicsDriver
{ {
public static class DriverUtilities public static class DriverUtilities
{ {
private static void AddMesaFlags(string envVar, string newFlags)
{
string existingFlags = Environment.GetEnvironmentVariable(envVar);
string flags = existingFlags == null ? newFlags : $"{existingFlags},{newFlags}";
OsUtils.SetEnvironmentVariableNoCaching(envVar, flags);
}
public static void InitDriverConfig(bool oglThreading)
{
if (OperatingSystem.IsLinux())
{
AddMesaFlags("RADV_DEBUG", "nodcc");
}
ToggleOGLThreading(oglThreading);
}
public static void ToggleOGLThreading(bool enabled) public static void ToggleOGLThreading(bool enabled)
{ {
OsUtils.SetEnvironmentVariableNoCaching("mesa_glthread", enabled.ToString().ToLower()); Environment.SetEnvironmentVariable("mesa_glthread", enabled.ToString().ToLower());
OsUtils.SetEnvironmentVariableNoCaching("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0"); Environment.SetEnvironmentVariable("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
try try
{ {

View File

@ -0,0 +1,51 @@
using System;
using System.Buffers;
using System.Threading;
namespace Ryujinx.Common.Memory
{
public partial class ByteMemoryPool
{
/// <summary>
/// Represents a <see cref="IMemoryOwner{Byte}"/> that wraps an array rented from
/// <see cref="ArrayPool{Byte}.Shared"/> and exposes it as <see cref="Memory{Byte}"/>
/// with a length of the requested size.
/// </summary>
private sealed class ByteMemoryPoolBuffer : IMemoryOwner<byte>
{
private byte[] _array;
private readonly int _length;
public ByteMemoryPoolBuffer(int length)
{
_array = ArrayPool<byte>.Shared.Rent(length);
_length = length;
}
/// <summary>
/// Returns a <see cref="Memory{Byte}"/> belonging to this owner.
/// </summary>
public Memory<byte> Memory
{
get
{
byte[] array = _array;
ObjectDisposedException.ThrowIf(array is null, this);
return new Memory<byte>(array, 0, _length);
}
}
public void Dispose()
{
var array = Interlocked.Exchange(ref _array, null);
if (array != null)
{
ArrayPool<byte>.Shared.Return(array);
}
}
}
}
}

View File

@ -0,0 +1,106 @@
using System;
using System.Buffers;
namespace Ryujinx.Common.Memory
{
/// <summary>
/// Provides a pool of re-usable byte array instances.
/// </summary>
public static partial class ByteMemoryPool
{
/// <summary>
/// Returns the maximum buffer size supported by this pool.
/// </summary>
public static int MaxBufferSize => Array.MaxLength;
/// <summary>
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
/// The buffer may contain data from a prior use.
/// </summary>
/// <param name="length">The buffer's required length in bytes</param>
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static IMemoryOwner<byte> Rent(long length)
=> RentImpl(checked((int)length));
/// <summary>
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
/// The buffer may contain data from a prior use.
/// </summary>
/// <param name="length">The buffer's required length in bytes</param>
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static IMemoryOwner<byte> Rent(ulong length)
=> RentImpl(checked((int)length));
/// <summary>
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
/// The buffer may contain data from a prior use.
/// </summary>
/// <param name="length">The buffer's required length in bytes</param>
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static IMemoryOwner<byte> Rent(int length)
=> RentImpl(length);
/// <summary>
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
/// The buffer's contents are cleared (set to all 0s) before returning.
/// </summary>
/// <param name="length">The buffer's required length in bytes</param>
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static IMemoryOwner<byte> RentCleared(long length)
=> RentCleared(checked((int)length));
/// <summary>
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
/// The buffer's contents are cleared (set to all 0s) before returning.
/// </summary>
/// <param name="length">The buffer's required length in bytes</param>
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static IMemoryOwner<byte> RentCleared(ulong length)
=> RentCleared(checked((int)length));
/// <summary>
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
/// The buffer's contents are cleared (set to all 0s) before returning.
/// </summary>
/// <param name="length">The buffer's required length in bytes</param>
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
public static IMemoryOwner<byte> RentCleared(int length)
{
var buffer = RentImpl(length);
buffer.Memory.Span.Clear();
return buffer;
}
/// <summary>
/// Copies <paramref name="buffer"/> into a newly rented byte memory buffer.
/// </summary>
/// <param name="buffer">The byte buffer to copy</param>
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory with <paramref name="buffer"/> copied to it</returns>
public static IMemoryOwner<byte> RentCopy(ReadOnlySpan<byte> buffer)
{
var copy = RentImpl(buffer.Length);
buffer.CopyTo(copy.Memory.Span);
return copy;
}
private static ByteMemoryPoolBuffer RentImpl(int length)
{
if ((uint)length > Array.MaxLength)
{
throw new ArgumentOutOfRangeException(nameof(length), length, null);
}
return new ByteMemoryPoolBuffer(length);
}
}
}

View File

@ -1,140 +0,0 @@
#nullable enable
using System;
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.Common.Memory
{
/// <summary>
/// An <see cref="IMemoryOwner{T}"/> implementation with an embedded length and fast <see cref="Span{T}"/>
/// accessor, with memory allocated from <seealso cref="ArrayPool{T}.Shared"/>.
/// </summary>
/// <typeparam name="T">The type of item to store.</typeparam>
public sealed class MemoryOwner<T> : IMemoryOwner<T>
{
private readonly int _length;
private T[]? _array;
/// <summary>
/// Initializes a new instance of the <see cref="MemoryOwner{T}"/> class with the specified parameters.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
private MemoryOwner(int length)
{
_length = length;
_array = ArrayPool<T>.Shared.Rent(length);
}
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the specified length.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
/// <returns>A <see cref="MemoryOwner{T}"/> instance of the requested length</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryOwner<T> Rent(int length) => new(length);
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the specified length and the content cleared.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
/// <returns>A <see cref="MemoryOwner{T}"/> instance of the requested length and the content cleared</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MemoryOwner<T> RentCleared(int length)
{
MemoryOwner<T> result = new(length);
result._array.AsSpan(0, length).Clear();
return result;
}
/// <summary>
/// Creates a new <see cref="MemoryOwner{T}"/> instance with the content copied from the specified buffer.
/// </summary>
/// <param name="buffer">The buffer to copy</param>
/// <returns>A <see cref="MemoryOwner{T}"/> instance with the same length and content as <paramref name="buffer"/></returns>
public static MemoryOwner<T> RentCopy(ReadOnlySpan<T> buffer)
{
MemoryOwner<T> result = new(buffer.Length);
buffer.CopyTo(result._array);
return result;
}
/// <summary>
/// Gets the number of items in the current instance.
/// </summary>
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _length;
}
/// <inheritdoc/>
public Memory<T> Memory
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
T[]? array = _array;
if (array is null)
{
ThrowObjectDisposedException();
}
return new(array, 0, _length);
}
}
/// <summary>
/// Gets a <see cref="Span{T}"/> wrapping the memory belonging to the current instance.
/// </summary>
/// <remarks>
/// Uses a trick made possible by the .NET 6+ runtime array layout.
/// </remarks>
public Span<T> Span
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
T[]? array = _array;
if (array is null)
{
ThrowObjectDisposedException();
}
ref T firstElementRef = ref MemoryMarshal.GetArrayDataReference(array);
return MemoryMarshal.CreateSpan(ref firstElementRef, _length);
}
}
/// <inheritdoc/>
public void Dispose()
{
T[]? array = Interlocked.Exchange(ref _array, null);
if (array is not null)
{
ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
}
}
/// <summary>
/// Throws an <see cref="ObjectDisposedException"/> when <see cref="_array"/> is <see langword="null"/>.
/// </summary>
[DoesNotReturn]
private static void ThrowObjectDisposedException()
{
throw new ObjectDisposedException(nameof(MemoryOwner<T>), "The buffer has already been disposed.");
}
}
}

View File

@ -1,114 +0,0 @@
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Ryujinx.Common.Memory
{
/// <summary>
/// A stack-only type that rents a buffer of a specified length from <seealso cref="ArrayPool{T}.Shared"/>.
/// It does not implement <see cref="IDisposable"/> to avoid being boxed, but should still be disposed. This
/// is easy since C# 8, which allows use of C# `using` constructs on any type that has a public Dispose() method.
/// To keep this type simple, fast, and read-only, it does not check or guard against multiple disposals.
/// For all these reasons, all usage should be with a `using` block or statement.
/// </summary>
/// <typeparam name="T">The type of item to store.</typeparam>
public readonly ref struct SpanOwner<T>
{
private readonly int _length;
private readonly T[] _array;
/// <summary>
/// Initializes a new instance of the <see cref="SpanOwner{T}"/> struct with the specified parameters.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
private SpanOwner(int length)
{
_length = length;
_array = ArrayPool<T>.Shared.Rent(length);
}
/// <summary>
/// Gets an empty <see cref="SpanOwner{T}"/> instance.
/// </summary>
public static SpanOwner<T> Empty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(0);
}
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the specified length.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
/// <returns>A <see cref="SpanOwner{T}"/> instance of the requested length</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanOwner<T> Rent(int length) => new(length);
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the length and the content cleared.
/// </summary>
/// <param name="length">The length of the new memory buffer to use</param>
/// <returns>A <see cref="SpanOwner{T}"/> instance of the requested length and the content cleared</returns>
/// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="length"/> is not valid</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static SpanOwner<T> RentCleared(int length)
{
SpanOwner<T> result = new(length);
result._array.AsSpan(0, length).Clear();
return result;
}
/// <summary>
/// Creates a new <see cref="SpanOwner{T}"/> instance with the content copied from the specified buffer.
/// </summary>
/// <param name="buffer">The buffer to copy</param>
/// <returns>A <see cref="SpanOwner{T}"/> instance with the same length and content as <paramref name="buffer"/></returns>
public static SpanOwner<T> RentCopy(ReadOnlySpan<T> buffer)
{
SpanOwner<T> result = new(buffer.Length);
buffer.CopyTo(result._array);
return result;
}
/// <summary>
/// Gets the number of items in the current instance
/// </summary>
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _length;
}
/// <summary>
/// Gets a <see cref="Span{T}"/> wrapping the memory belonging to the current instance.
/// </summary>
/// <remarks>
/// Uses a trick made possible by the .NET 6+ runtime array layout.
/// </remarks>
public Span<T> Span
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ref T firstElementRef = ref MemoryMarshal.GetArrayDataReference(_array);
return MemoryMarshal.CreateSpan(ref firstElementRef, _length);
}
}
/// <summary>
/// Implements the duck-typed <see cref="IDisposable.Dispose"/> method.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
ArrayPool<T>.Shared.Return(_array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
}
}
}

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -42,14 +42,14 @@ namespace Ryujinx.Common
return StreamUtils.StreamToBytes(stream); return StreamUtils.StreamToBytes(stream);
} }
public static MemoryOwner<byte> ReadFileToRentedMemory(string filename) public static IMemoryOwner<byte> ReadFileToRentedMemory(string filename)
{ {
var (assembly, path) = ResolveManifestPath(filename); var (assembly, path) = ResolveManifestPath(filename);
return ReadFileToRentedMemory(assembly, path); return ReadFileToRentedMemory(assembly, path);
} }
public static MemoryOwner<byte> ReadFileToRentedMemory(Assembly assembly, string filename) public static IMemoryOwner<byte> ReadFileToRentedMemory(Assembly assembly, string filename)
{ {
using var stream = GetStream(assembly, filename); using var stream = GetStream(assembly, filename);

View File

@ -1,24 +0,0 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Ryujinx.Common.Utilities
{
public partial class OsUtils
{
[LibraryImport("libc", SetLastError = true)]
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
public static void SetEnvironmentVariableNoCaching(string key, string value)
{
// Set the value in the cached environment variables, too.
Environment.SetEnvironmentVariable(key, value);
if (!OperatingSystem.IsWindows())
{
int res = setenv(key, value, 1);
Debug.Assert(res != -1);
}
}
}
}

View File

@ -1,5 +1,6 @@
using Microsoft.IO; using Microsoft.IO;
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using System.Buffers;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -15,7 +16,7 @@ namespace Ryujinx.Common.Utilities
return output.ToArray(); return output.ToArray();
} }
public static MemoryOwner<byte> StreamToRentedMemory(Stream input) public static IMemoryOwner<byte> StreamToRentedMemory(Stream input)
{ {
if (input is MemoryStream inputMemoryStream) if (input is MemoryStream inputMemoryStream)
{ {
@ -25,9 +26,9 @@ namespace Ryujinx.Common.Utilities
{ {
long bytesExpected = input.Length; long bytesExpected = input.Length;
MemoryOwner<byte> ownedMemory = MemoryOwner<byte>.Rent(checked((int)bytesExpected)); IMemoryOwner<byte> ownedMemory = ByteMemoryPool.Rent(bytesExpected);
var destSpan = ownedMemory.Span; var destSpan = ownedMemory.Memory.Span;
int totalBytesRead = 0; int totalBytesRead = 0;
@ -65,14 +66,14 @@ namespace Ryujinx.Common.Utilities
return stream.ToArray(); return stream.ToArray();
} }
private static MemoryOwner<byte> MemoryStreamToRentedMemory(MemoryStream input) private static IMemoryOwner<byte> MemoryStreamToRentedMemory(MemoryStream input)
{ {
input.Position = 0; input.Position = 0;
MemoryOwner<byte> ownedMemory = MemoryOwner<byte>.Rent(checked((int)input.Length)); IMemoryOwner<byte> ownedMemory = ByteMemoryPool.Rent(input.Length);
// Discard the return value because we assume reading a MemoryStream always succeeds completely. // Discard the return value because we assume reading a MemoryStream always succeeds completely.
_ = input.Read(ownedMemory.Span); _ = input.Read(ownedMemory.Memory.Span);
return ownedMemory; return ownedMemory;
} }

View File

@ -303,9 +303,9 @@ namespace Ryujinx.Cpu.Jit
} }
else else
{ {
MemoryOwner<byte> memoryOwner = MemoryOwner<byte>.Rent(size); IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
Read(va, memoryOwner.Span); Read(va, memoryOwner.Memory.Span);
return new WritableRegion(this, va, memoryOwner); return new WritableRegion(this, va, memoryOwner);
} }

View File

@ -1,5 +1,6 @@
using Ryujinx.Cpu.LightningJit.CodeGen; using Ryujinx.Cpu.LightningJit.CodeGen;
using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
using System.Diagnostics;
namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
{ {

View File

@ -114,7 +114,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, (d, n, m) => InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, (d, n, m) =>
{ {
context.Arm64Assembler.Add(d, n, m); context.Arm64Assembler.Add(d, n, m);
EmitSaturateUqadd(context, d, 16); EmitSaturateUnsignedRange(context, d, 16);
}); });
} }
@ -123,7 +123,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, (d, n, m) => InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, (d, n, m) =>
{ {
context.Arm64Assembler.Add(d, n, m); context.Arm64Assembler.Add(d, n, m);
EmitSaturateUqadd(context, d, 8); EmitSaturateUnsignedRange(context, d, 8);
}); });
} }
@ -140,7 +140,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
context.Arm64Assembler.Add(d, n, m); context.Arm64Assembler.Add(d, n, m);
} }
EmitSaturateUq(context, d, 16, e == 0); EmitSaturateUnsignedRange(context, d, 16);
}); });
} }
@ -157,25 +157,25 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
context.Arm64Assembler.Sub(d, n, m); context.Arm64Assembler.Sub(d, n, m);
} }
EmitSaturateUq(context, d, 16, e != 0); EmitSaturateUnsignedRange(context, d, 16);
}); });
} }
public static void Uqsub16(CodeGenContext context, uint rd, uint rn, uint rm) public static void Uqsub16(CodeGenContext context, uint rd, uint rn, uint rm)
{ {
InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, (d, n, m) => InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, (d, n, m) =>
{ {
context.Arm64Assembler.Sub(d, n, m); context.Arm64Assembler.Sub(d, n, m);
EmitSaturateUqsub(context, d, 16); EmitSaturateUnsignedRange(context, d, 16);
}); });
} }
public static void Uqsub8(CodeGenContext context, uint rd, uint rn, uint rm) public static void Uqsub8(CodeGenContext context, uint rd, uint rn, uint rm)
{ {
InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, (d, n, m) => InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, (d, n, m) =>
{ {
context.Arm64Assembler.Sub(d, n, m); context.Arm64Assembler.Sub(d, n, m);
EmitSaturateUqsub(context, d, 8); EmitSaturateUnsignedRange(context, d, 8);
}); });
} }
@ -358,17 +358,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
} }
} }
private static void EmitSaturateUqadd(CodeGenContext context, Operand value, uint saturateTo) private static void EmitSaturateUnsignedRange(CodeGenContext context, Operand value, uint saturateTo)
{
EmitSaturateUq(context, value, saturateTo, isSub: false);
}
private static void EmitSaturateUqsub(CodeGenContext context, Operand value, uint saturateTo)
{
EmitSaturateUq(context, value, saturateTo, isSub: true);
}
private static void EmitSaturateUq(CodeGenContext context, Operand value, uint saturateTo, bool isSub)
{ {
Debug.Assert(saturateTo <= 32); Debug.Assert(saturateTo <= 32);
@ -389,7 +379,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
return; return;
} }
context.Arm64Assembler.Lsr(tempRegister.Operand, value, InstEmitCommon.Const((int)saturateTo)); context.Arm64Assembler.Lsr(tempRegister.Operand, value, InstEmitCommon.Const(32 - (int)saturateTo));
int branchIndex = context.CodeWriter.InstructionPointer; int branchIndex = context.CodeWriter.InstructionPointer;
@ -397,7 +387,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
context.Arm64Assembler.Cbz(tempRegister.Operand, 0); context.Arm64Assembler.Cbz(tempRegister.Operand, 0);
// Saturate. // Saturate.
context.Arm64Assembler.Mov(value, isSub ? 0u : uint.MaxValue >> (32 - (int)saturateTo)); context.Arm64Assembler.Mov(value, uint.MaxValue >> (32 - (int)saturateTo));
int delta = context.CodeWriter.InstructionPointer - branchIndex; int delta = context.CodeWriter.InstructionPointer - branchIndex;
context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5)); context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5));

View File

@ -1,6 +1,7 @@
using Ryujinx.Common.Memory; using Ryujinx.Common.Memory;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -144,9 +145,9 @@ namespace Ryujinx.Graphics.Device
} }
else else
{ {
MemoryOwner<byte> memoryOwner = MemoryOwner<byte>.Rent(size); IMemoryOwner<byte> memoryOwner = ByteMemoryPool.Rent(size);
ReadImpl(va, memoryOwner.Span); GetSpan(va, size).CopyTo(memoryOwner.Memory.Span);
return new WritableRegion(this, va, memoryOwner, tracked: true); return new WritableRegion(this, va, memoryOwner, tracked: true);
} }

View File

@ -39,10 +39,7 @@ namespace Ryujinx.Graphics.Device
{ {
var field = fields[fieldIndex]; var field = fields[fieldIndex];
var currentFieldOffset = (int)Marshal.OffsetOf<TState>(field.Name); int sizeOfField = SizeCalculator.SizeOf(field.FieldType);
var nextFieldOffset = fieldIndex + 1 == fields.Length ? Unsafe.SizeOf<TState>() : (int)Marshal.OffsetOf<TState>(fields[fieldIndex + 1].Name);
int sizeOfField = nextFieldOffset - currentFieldOffset;
for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4) for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4)
{ {

View File

@ -0,0 +1,63 @@
using System;
using System.Reflection;
namespace Ryujinx.Graphics.Device
{
public static class SizeCalculator
{
public static int SizeOf(Type type)
{
// Is type a enum type?
if (type.IsEnum)
{
type = type.GetEnumUnderlyingType();
}
// Is type a pointer type?
if (type.IsPointer || type == typeof(IntPtr) || type == typeof(UIntPtr))
{
return IntPtr.Size;
}
// Is type a struct type?
if (type.IsValueType && !type.IsPrimitive)
{
// Check if the struct has a explicit size, if so, return that.
if (type.StructLayoutAttribute.Size != 0)
{
return type.StructLayoutAttribute.Size;
}
// Otherwise we calculate the sum of the sizes of all fields.
int size = 0;
var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
{
size += SizeOf(fields[fieldIndex].FieldType);
}
return size;
}
// Primitive types.
return (Type.GetTypeCode(type)) switch
{
TypeCode.SByte => sizeof(sbyte),
TypeCode.Byte => sizeof(byte),
TypeCode.Int16 => sizeof(short),
TypeCode.UInt16 => sizeof(ushort),
TypeCode.Int32 => sizeof(int),
TypeCode.UInt32 => sizeof(uint),
TypeCode.Int64 => sizeof(long),
TypeCode.UInt64 => sizeof(ulong),
TypeCode.Char => sizeof(char),
TypeCode.Single => sizeof(float),
TypeCode.Double => sizeof(double),
TypeCode.Decimal => sizeof(decimal),
TypeCode.Boolean => sizeof(bool),
_ => throw new ArgumentException($"Length for type \"{type.Name}\" is unknown."),
};
}
}
}

View File

@ -6,13 +6,8 @@ namespace Ryujinx.Graphics.GAL
public enum BufferAccess public enum BufferAccess
{ {
Default = 0, Default = 0,
HostMemory = 1, FlushPersistent = 1 << 0,
DeviceMemory = 2, Stream = 1 << 1,
DeviceMemoryMapped = 3, SparseCompatible = 1 << 2,
MemoryTypeMask = 0xf,
Stream = 1 << 4,
SparseCompatible = 1 << 5,
} }
} }

View File

@ -6,7 +6,6 @@ namespace Ryujinx.Graphics.GAL
{ {
public readonly TargetApi Api; public readonly TargetApi Api;
public readonly string VendorName; public readonly string VendorName;
public readonly SystemMemoryType MemoryType;
public readonly bool HasFrontFacingBug; public readonly bool HasFrontFacingBug;
public readonly bool HasVectorIndexingBug; public readonly bool HasVectorIndexingBug;
@ -51,13 +50,6 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsIndirectParameters; public readonly bool SupportsIndirectParameters;
public readonly bool SupportsDepthClipControl; public readonly bool SupportsDepthClipControl;
public readonly int UniformBufferSetIndex;
public readonly int StorageBufferSetIndex;
public readonly int TextureSetIndex;
public readonly int ImageSetIndex;
public readonly int ExtraSetBaseIndex;
public readonly int MaximumExtraSets;
public readonly uint MaximumUniformBuffersPerStage; public readonly uint MaximumUniformBuffersPerStage;
public readonly uint MaximumStorageBuffersPerStage; public readonly uint MaximumStorageBuffersPerStage;
public readonly uint MaximumTexturesPerStage; public readonly uint MaximumTexturesPerStage;
@ -71,12 +63,9 @@ namespace Ryujinx.Graphics.GAL
public readonly int GatherBiasPrecision; public readonly int GatherBiasPrecision;
public readonly ulong MaximumGpuMemory;
public Capabilities( public Capabilities(
TargetApi api, TargetApi api,
string vendorName, string vendorName,
SystemMemoryType memoryType,
bool hasFrontFacingBug, bool hasFrontFacingBug,
bool hasVectorIndexingBug, bool hasVectorIndexingBug,
bool needsFragmentOutputSpecialization, bool needsFragmentOutputSpecialization,
@ -118,12 +107,6 @@ namespace Ryujinx.Graphics.GAL
bool supportsViewportSwizzle, bool supportsViewportSwizzle,
bool supportsIndirectParameters, bool supportsIndirectParameters,
bool supportsDepthClipControl, bool supportsDepthClipControl,
int uniformBufferSetIndex,
int storageBufferSetIndex,
int textureSetIndex,
int imageSetIndex,
int extraSetBaseIndex,
int maximumExtraSets,
uint maximumUniformBuffersPerStage, uint maximumUniformBuffersPerStage,
uint maximumStorageBuffersPerStage, uint maximumStorageBuffersPerStage,
uint maximumTexturesPerStage, uint maximumTexturesPerStage,
@ -133,12 +116,10 @@ namespace Ryujinx.Graphics.GAL
int shaderSubgroupSize, int shaderSubgroupSize,
int storageBufferOffsetAlignment, int storageBufferOffsetAlignment,
int textureBufferOffsetAlignment, int textureBufferOffsetAlignment,
int gatherBiasPrecision, int gatherBiasPrecision)
ulong maximumGpuMemory)
{ {
Api = api; Api = api;
VendorName = vendorName; VendorName = vendorName;
MemoryType = memoryType;
HasFrontFacingBug = hasFrontFacingBug; HasFrontFacingBug = hasFrontFacingBug;
HasVectorIndexingBug = hasVectorIndexingBug; HasVectorIndexingBug = hasVectorIndexingBug;
NeedsFragmentOutputSpecialization = needsFragmentOutputSpecialization; NeedsFragmentOutputSpecialization = needsFragmentOutputSpecialization;
@ -180,12 +161,6 @@ namespace Ryujinx.Graphics.GAL
SupportsViewportSwizzle = supportsViewportSwizzle; SupportsViewportSwizzle = supportsViewportSwizzle;
SupportsIndirectParameters = supportsIndirectParameters; SupportsIndirectParameters = supportsIndirectParameters;
SupportsDepthClipControl = supportsDepthClipControl; SupportsDepthClipControl = supportsDepthClipControl;
UniformBufferSetIndex = uniformBufferSetIndex;
StorageBufferSetIndex = storageBufferSetIndex;
TextureSetIndex = textureSetIndex;
ImageSetIndex = imageSetIndex;
ExtraSetBaseIndex = extraSetBaseIndex;
MaximumExtraSets = maximumExtraSets;
MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage; MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage; MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage;
MaximumTexturesPerStage = maximumTexturesPerStage; MaximumTexturesPerStage = maximumTexturesPerStage;
@ -196,7 +171,6 @@ namespace Ryujinx.Graphics.GAL
StorageBufferOffsetAlignment = storageBufferOffsetAlignment; StorageBufferOffsetAlignment = storageBufferOffsetAlignment;
TextureBufferOffsetAlignment = textureBufferOffsetAlignment; TextureBufferOffsetAlignment = textureBufferOffsetAlignment;
GatherBiasPrecision = gatherBiasPrecision; GatherBiasPrecision = gatherBiasPrecision;
MaximumGpuMemory = maximumGpuMemory;
} }
} }
} }

View File

@ -711,36 +711,5 @@ namespace Ryujinx.Graphics.GAL
{ {
return format.IsUint() || format.IsSint(); return format.IsUint() || format.IsSint();
} }
/// <summary>
/// Checks if the texture format is a float or sRGB color format.
/// </summary>
/// <remarks>
/// Does not include normalized, compressed or depth formats.
/// Float and sRGB formats do not participate in logical operations.
/// </remarks>
/// <param name="format">Texture format</param>
/// <returns>True if the format is a float or sRGB color format, false otherwise</returns>
public static bool IsFloatOrSrgb(this Format format)
{
switch (format)
{
case Format.R8G8B8A8Srgb:
case Format.B8G8R8A8Srgb:
case Format.R16Float:
case Format.R16G16Float:
case Format.R16G16B16Float:
case Format.R16G16B16A16Float:
case Format.R32Float:
case Format.R32G32Float:
case Format.R32G32B32Float:
case Format.R32G32B32A32Float:
case Format.R11G11B10Float:
case Format.R9G9B9E5Float:
return true;
}
return false;
}
} }
} }

View File

@ -1,9 +1,8 @@
using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
public interface IImageArray : IDisposable public interface IImageArray
{ {
void SetFormats(int index, Format[] imageFormats);
void SetImages(int index, ITexture[] images); void SetImages(int index, ITexture[] images);
} }
} }

View File

@ -58,9 +58,8 @@ namespace Ryujinx.Graphics.GAL
void SetIndexBuffer(BufferRange buffer, IndexType type); void SetIndexBuffer(BufferRange buffer, IndexType type);
void SetImage(ShaderStage stage, int binding, ITexture texture); void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat);
void SetImageArray(ShaderStage stage, int binding, IImageArray array); void SetImageArray(ShaderStage stage, int binding, IImageArray array);
void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);
void SetLineParameters(float width, bool smooth); void SetLineParameters(float width, bool smooth);
@ -92,7 +91,6 @@ namespace Ryujinx.Graphics.GAL
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler); void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
void SetTextureArray(ShaderStage stage, int binding, ITextureArray array); void SetTextureArray(ShaderStage stage, int binding, ITextureArray array);
void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array);
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers); void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers); void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);

View File

@ -17,6 +17,7 @@ namespace Ryujinx.Graphics.GAL
void BackgroundContextAction(Action action, bool alwaysBackground = false); void BackgroundContextAction(Action action, bool alwaysBackground = false);
BufferHandle CreateBuffer(int size, BufferAccess access = BufferAccess.Default); BufferHandle CreateBuffer(int size, BufferAccess access = BufferAccess.Default);
BufferHandle CreateBuffer(int size, BufferAccess access, BufferHandle storageHint);
BufferHandle CreateBuffer(nint pointer, int size); BufferHandle CreateBuffer(nint pointer, int size);
BufferHandle CreateBufferSparse(ReadOnlySpan<BufferRange> storageBuffers); BufferHandle CreateBufferSparse(ReadOnlySpan<BufferRange> storageBuffers);

View File

@ -1,4 +1,4 @@
using Ryujinx.Common.Memory; using System.Buffers;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
@ -18,30 +18,30 @@ namespace Ryujinx.Graphics.GAL
PinnedSpan<byte> GetData(int layer, int level); PinnedSpan<byte> GetData(int layer, int level);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
void SetData(MemoryOwner<byte> data); void SetData(IMemoryOwner<byte> data);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
void SetData(MemoryOwner<byte> data, int layer, int level); void SetData(IMemoryOwner<byte> data, int layer, int level);
/// <summary> /// <summary>
/// Sets the texture data. The data passed as a <see cref="MemoryOwner{Byte}" /> will be disposed when /// Sets the texture data. The data passed as a <see cref="IMemoryOwner{Byte}" /> will be disposed when
/// the operation completes. /// the operation completes.
/// </summary> /// </summary>
/// <param name="data">Texture data bytes</param> /// <param name="data">Texture data bytes</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param> /// <param name="region">Target sub-region of the texture to update</param>
void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region); void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region);
void SetStorage(BufferRange buffer); void SetStorage(BufferRange buffer);

View File

@ -1,8 +1,6 @@
using System;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
public interface ITextureArray : IDisposable public interface ITextureArray
{ {
void SetSamplers(int index, ISampler[] samplers); void SetSamplers(int index, ISampler[] samplers);
void SetTextures(int index, ITexture[] textures); void SetTextures(int index, ITexture[] textures);

View File

@ -44,6 +44,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
} }
Register<ActionCommand>(CommandType.Action); Register<ActionCommand>(CommandType.Action);
Register<CreateBufferCommand>(CommandType.CreateBuffer);
Register<CreateBufferAccessCommand>(CommandType.CreateBufferAccess); Register<CreateBufferAccessCommand>(CommandType.CreateBufferAccess);
Register<CreateBufferSparseCommand>(CommandType.CreateBufferSparse); Register<CreateBufferSparseCommand>(CommandType.CreateBufferSparse);
Register<CreateHostBufferCommand>(CommandType.CreateHostBuffer); Register<CreateHostBufferCommand>(CommandType.CreateHostBuffer);
@ -66,7 +67,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<CounterEventDisposeCommand>(CommandType.CounterEventDispose); Register<CounterEventDisposeCommand>(CommandType.CounterEventDispose);
Register<CounterEventFlushCommand>(CommandType.CounterEventFlush); Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose); Register<ImageArraySetFormatsCommand>(CommandType.ImageArraySetFormats);
Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages); Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages);
Register<ProgramDisposeCommand>(CommandType.ProgramDispose); Register<ProgramDisposeCommand>(CommandType.ProgramDispose);
@ -88,7 +89,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<TextureSetDataSliceRegionCommand>(CommandType.TextureSetDataSliceRegion); Register<TextureSetDataSliceRegionCommand>(CommandType.TextureSetDataSliceRegion);
Register<TextureSetStorageCommand>(CommandType.TextureSetStorage); Register<TextureSetStorageCommand>(CommandType.TextureSetStorage);
Register<TextureArrayDisposeCommand>(CommandType.TextureArrayDispose);
Register<TextureArraySetSamplersCommand>(CommandType.TextureArraySetSamplers); Register<TextureArraySetSamplersCommand>(CommandType.TextureArraySetSamplers);
Register<TextureArraySetTexturesCommand>(CommandType.TextureArraySetTextures); Register<TextureArraySetTexturesCommand>(CommandType.TextureArraySetTextures);
@ -125,7 +125,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<SetUniformBuffersCommand>(CommandType.SetUniformBuffers); Register<SetUniformBuffersCommand>(CommandType.SetUniformBuffers);
Register<SetImageCommand>(CommandType.SetImage); Register<SetImageCommand>(CommandType.SetImage);
Register<SetImageArrayCommand>(CommandType.SetImageArray); Register<SetImageArrayCommand>(CommandType.SetImageArray);
Register<SetImageArraySeparateCommand>(CommandType.SetImageArraySeparate);
Register<SetIndexBufferCommand>(CommandType.SetIndexBuffer); Register<SetIndexBufferCommand>(CommandType.SetIndexBuffer);
Register<SetLineParametersCommand>(CommandType.SetLineParameters); Register<SetLineParametersCommand>(CommandType.SetLineParameters);
Register<SetLogicOpStateCommand>(CommandType.SetLogicOpState); Register<SetLogicOpStateCommand>(CommandType.SetLogicOpState);
@ -143,7 +142,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<SetStencilTestCommand>(CommandType.SetStencilTest); Register<SetStencilTestCommand>(CommandType.SetStencilTest);
Register<SetTextureAndSamplerCommand>(CommandType.SetTextureAndSampler); Register<SetTextureAndSamplerCommand>(CommandType.SetTextureAndSampler);
Register<SetTextureArrayCommand>(CommandType.SetTextureArray); Register<SetTextureArrayCommand>(CommandType.SetTextureArray);
Register<SetTextureArraySeparateCommand>(CommandType.SetTextureArraySeparate);
Register<SetUserClipDistanceCommand>(CommandType.SetUserClipDistance); Register<SetUserClipDistanceCommand>(CommandType.SetUserClipDistance);
Register<SetVertexAttribsCommand>(CommandType.SetVertexAttribs); Register<SetVertexAttribsCommand>(CommandType.SetVertexAttribs);
Register<SetVertexBuffersCommand>(CommandType.SetVertexBuffers); Register<SetVertexBuffersCommand>(CommandType.SetVertexBuffers);

View File

@ -3,6 +3,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
enum CommandType : byte enum CommandType : byte
{ {
Action, Action,
CreateBuffer,
CreateBufferAccess, CreateBufferAccess,
CreateBufferSparse, CreateBufferSparse,
CreateHostBuffer, CreateHostBuffer,
@ -26,7 +27,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading
CounterEventDispose, CounterEventDispose,
CounterEventFlush, CounterEventFlush,
ImageArrayDispose, ImageArraySetFormats,
ImageArraySetImages, ImageArraySetImages,
ProgramDispose, ProgramDispose,
@ -48,7 +49,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
TextureSetDataSliceRegion, TextureSetDataSliceRegion,
TextureSetStorage, TextureSetStorage,
TextureArrayDispose,
TextureArraySetSamplers, TextureArraySetSamplers,
TextureArraySetTextures, TextureArraySetTextures,
@ -85,7 +85,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
SetUniformBuffers, SetUniformBuffers,
SetImage, SetImage,
SetImageArray, SetImageArray,
SetImageArraySeparate,
SetIndexBuffer, SetIndexBuffer,
SetLineParameters, SetLineParameters,
SetLogicOpState, SetLogicOpState,
@ -103,7 +102,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
SetStencilTest, SetStencilTest,
SetTextureAndSampler, SetTextureAndSampler,
SetTextureArray, SetTextureArray,
SetTextureArraySeparate,
SetUserClipDistance, SetUserClipDistance,
SetVertexAttribs, SetVertexAttribs,
SetVertexBuffers, SetVertexBuffers,

View File

@ -1,21 +0,0 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray
{
struct ImageArrayDisposeCommand : IGALCommand, IGALCommand<ImageArrayDisposeCommand>
{
public readonly CommandType CommandType => CommandType.ImageArrayDispose;
private TableRef<ThreadedImageArray> _imageArray;
public void Set(TableRef<ThreadedImageArray> imageArray)
{
_imageArray = imageArray;
}
public static void Run(ref ImageArrayDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._imageArray.Get(threaded).Base.Dispose();
}
}
}

View File

@ -0,0 +1,26 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray
{
struct ImageArraySetFormatsCommand : IGALCommand, IGALCommand<ImageArraySetFormatsCommand>
{
public readonly CommandType CommandType => CommandType.ImageArraySetFormats;
private TableRef<ThreadedImageArray> _imageArray;
private int _index;
private TableRef<Format[]> _imageFormats;
public void Set(TableRef<ThreadedImageArray> imageArray, int index, TableRef<Format[]> imageFormats)
{
_imageArray = imageArray;
_index = index;
_imageFormats = imageFormats;
}
public static void Run(ref ImageArraySetFormatsCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
ThreadedImageArray imageArray = command._imageArray.Get(threaded);
imageArray.Base.SetFormats(command._index, command._imageFormats.Get(threaded));
}
}
}

View File

@ -0,0 +1,31 @@
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
{
struct CreateBufferCommand : IGALCommand, IGALCommand<CreateBufferCommand>
{
public readonly CommandType CommandType => CommandType.CreateBuffer;
private BufferHandle _threadedHandle;
private int _size;
private BufferAccess _access;
private BufferHandle _storageHint;
public void Set(BufferHandle threadedHandle, int size, BufferAccess access, BufferHandle storageHint)
{
_threadedHandle = threadedHandle;
_size = size;
_access = access;
_storageHint = storageHint;
}
public static void Run(ref CreateBufferCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
BufferHandle hint = BufferHandle.Null;
if (command._storageHint != BufferHandle.Null)
{
hint = threaded.Buffers.MapBuffer(command._storageHint);
}
threaded.Buffers.AssignBuffer(command._threadedHandle, renderer.CreateBuffer(command._size, command._access, hint));
}
}
}

View File

@ -1,26 +0,0 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetImageArraySeparateCommand : IGALCommand, IGALCommand<SetImageArraySeparateCommand>
{
public readonly CommandType CommandType => CommandType.SetImageArraySeparate;
private ShaderStage _stage;
private int _setIndex;
private TableRef<IImageArray> _array;
public void Set(ShaderStage stage, int setIndex, TableRef<IImageArray> array)
{
_stage = stage;
_setIndex = setIndex;
_array = array;
}
public static void Run(ref SetImageArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetImageArraySeparate(command._stage, command._setIndex, command._array.GetAs<ThreadedImageArray>(threaded)?.Base);
}
}
}

View File

@ -10,17 +10,19 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
private ShaderStage _stage; private ShaderStage _stage;
private int _binding; private int _binding;
private TableRef<ITexture> _texture; private TableRef<ITexture> _texture;
private Format _imageFormat;
public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture) public void Set(ShaderStage stage, int binding, TableRef<ITexture> texture, Format imageFormat)
{ {
_stage = stage; _stage = stage;
_binding = binding; _binding = binding;
_texture = texture; _texture = texture;
_imageFormat = imageFormat;
} }
public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer) public static void Run(ref SetImageCommand command, ThreadedRenderer threaded, IRenderer renderer)
{ {
renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base); renderer.Pipeline.SetImage(command._stage, command._binding, command._texture.GetAs<ThreadedTexture>(threaded)?.Base, command._imageFormat);
} }
} }
} }

View File

@ -1,26 +0,0 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands
{
struct SetTextureArraySeparateCommand : IGALCommand, IGALCommand<SetTextureArraySeparateCommand>
{
public readonly CommandType CommandType => CommandType.SetTextureArraySeparate;
private ShaderStage _stage;
private int _setIndex;
private TableRef<ITextureArray> _array;
public void Set(ShaderStage stage, int setIndex, TableRef<ITextureArray> array)
{
_stage = stage;
_setIndex = setIndex;
_array = array;
}
public static void Run(ref SetTextureArraySeparateCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
renderer.Pipeline.SetTextureArraySeparate(command._stage, command._setIndex, command._array.GetAs<ThreadedTextureArray>(threaded)?.Base);
}
}
}

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,9 +8,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetData; public readonly CommandType CommandType => CommandType.TextureSetData;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<MemoryOwner<byte>> _data; private TableRef<IMemoryOwner<byte>> _data;
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,11 +8,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetDataSlice; public readonly CommandType CommandType => CommandType.TextureSetDataSlice;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<MemoryOwner<byte>> _data; private TableRef<IMemoryOwner<byte>> _data;
private int _layer; private int _layer;
private int _level; private int _level;
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data, int layer, int level) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources; using Ryujinx.Graphics.GAL.Multithreading.Resources;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
@ -8,12 +8,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
{ {
public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion; public readonly CommandType CommandType => CommandType.TextureSetDataSliceRegion;
private TableRef<ThreadedTexture> _texture; private TableRef<ThreadedTexture> _texture;
private TableRef<MemoryOwner<byte>> _data; private TableRef<IMemoryOwner<byte>> _data;
private int _layer; private int _layer;
private int _level; private int _level;
private Rectangle<int> _region; private Rectangle<int> _region;
public void Set(TableRef<ThreadedTexture> texture, TableRef<MemoryOwner<byte>> data, int layer, int level, Rectangle<int> region) public void Set(TableRef<ThreadedTexture> texture, TableRef<IMemoryOwner<byte>> data, int layer, int level, Rectangle<int> region)
{ {
_texture = texture; _texture = texture;
_data = data; _data = data;

View File

@ -1,21 +0,0 @@
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray
{
struct TextureArrayDisposeCommand : IGALCommand, IGALCommand<TextureArrayDisposeCommand>
{
public readonly CommandType CommandType => CommandType.TextureArrayDispose;
private TableRef<ThreadedTextureArray> _textureArray;
public void Set(TableRef<ThreadedTextureArray> textureArray)
{
_textureArray = textureArray;
}
public static void Run(ref TextureArrayDisposeCommand command, ThreadedRenderer threaded, IRenderer renderer)
{
command._textureArray.Get(threaded).Base.Dispose();
}
}
}

View File

@ -21,9 +21,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Dispose() public void SetFormats(int index, Format[] imageFormats)
{ {
_renderer.New<ImageArrayDisposeCommand>().Set(Ref(this)); _renderer.New<ImageArraySetFormatsCommand>().Set(Ref(this), index, Ref(imageFormats));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }

View File

@ -1,6 +1,6 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture; using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture;
using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Model;
using System.Buffers;
namespace Ryujinx.Graphics.GAL.Multithreading.Resources namespace Ryujinx.Graphics.GAL.Multithreading.Resources
{ {
@ -111,21 +111,21 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data) public void SetData(IMemoryOwner<byte> data)
{ {
_renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data)); _renderer.New<TextureSetDataCommand>().Set(Ref(this), Ref(data));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level) public void SetData(IMemoryOwner<byte> data, int layer, int level)
{ {
_renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level); _renderer.New<TextureSetDataSliceCommand>().Set(Ref(this), Ref(data), layer, level);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region); _renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data), layer, level, region);
_renderer.QueueCommand(); _renderer.QueueCommand();

View File

@ -22,12 +22,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
return new TableRef<T>(_renderer, reference); return new TableRef<T>(_renderer, reference);
} }
public void Dispose()
{
_renderer.New<TextureArrayDisposeCommand>().Set(Ref(this));
_renderer.QueueCommand();
}
public void SetSamplers(int index, ISampler[] samplers) public void SetSamplers(int index, ISampler[] samplers)
{ {
_renderer.New<TextureArraySetSamplersCommand>().Set(Ref(this), index, Ref(samplers.ToArray())); _renderer.New<TextureArraySetSamplersCommand>().Set(Ref(this), index, Ref(samplers.ToArray()));

View File

@ -177,9 +177,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImage(ShaderStage stage, int binding, ITexture texture) public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat)
{ {
_renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture)); _renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture), imageFormat);
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
@ -189,12 +189,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
{
_renderer.New<SetImageArraySeparateCommand>().Set(stage, setIndex, Ref(array));
_renderer.QueueCommand();
}
public void SetIndexBuffer(BufferRange buffer, IndexType type) public void SetIndexBuffer(BufferRange buffer, IndexType type)
{ {
_renderer.New<SetIndexBufferCommand>().Set(buffer, type); _renderer.New<SetIndexBufferCommand>().Set(buffer, type);
@ -303,12 +297,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
{
_renderer.New<SetTextureArraySeparateCommand>().Set(stage, setIndex, Ref(array));
_renderer.QueueCommand();
}
public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers) public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
{ {
_renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers)); _renderer.New<SetTransformFeedbackBuffersCommand>().Set(_renderer.CopySpan(buffers));

View File

@ -272,6 +272,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading
return handle; return handle;
} }
public BufferHandle CreateBuffer(int size, BufferAccess access, BufferHandle storageHint)
{
BufferHandle handle = Buffers.CreateBufferHandle();
New<CreateBufferCommand>().Set(handle, size, access, storageHint);
QueueCommand();
return handle;
}
public BufferHandle CreateBuffer(nint pointer, int size) public BufferHandle CreateBuffer(nint pointer, int size)
{ {
BufferHandle handle = Buffers.CreateBufferHandle(); BufferHandle handle = Buffers.CreateBufferHandle();

View File

@ -74,15 +74,13 @@ namespace Ryujinx.Graphics.GAL
public int ArrayLength { get; } public int ArrayLength { get; }
public ResourceType Type { get; } public ResourceType Type { get; }
public ResourceStages Stages { get; } public ResourceStages Stages { get; }
public bool Write { get; }
public ResourceUsage(int binding, int arrayLength, ResourceType type, ResourceStages stages, bool write) public ResourceUsage(int binding, int arrayLength, ResourceType type, ResourceStages stages)
{ {
Binding = binding; Binding = binding;
ArrayLength = arrayLength; ArrayLength = arrayLength;
Type = type; Type = type;
Stages = stages; Stages = stages;
Write = write;
} }
public override int GetHashCode() public override int GetHashCode()

View File

@ -1,29 +0,0 @@
namespace Ryujinx.Graphics.GAL
{
public enum SystemMemoryType
{
/// <summary>
/// The backend manages the ownership of memory. This mode never supports host imported memory.
/// </summary>
BackendManaged,
/// <summary>
/// Device memory has similar performance to host memory, usually because it's shared between CPU/GPU.
/// Use host memory whenever possible.
/// </summary>
UnifiedMemory,
/// <summary>
/// GPU storage to host memory goes though a slow interconnect, but it would still be preferable to use it if the data is flushed back often.
/// Assumes constant buffer access to host memory is rather fast.
/// </summary>
DedicatedMemory,
/// <summary>
/// GPU storage to host memory goes though a slow interconnect, that is very slow when doing access from storage.
/// When frequently accessed, copy buffers to host memory using DMA.
/// Assumes constant buffer access to host memory is rather fast.
/// </summary>
DedicatedMemorySlowStorage
}
}

View File

@ -1,5 +1,6 @@
using Ryujinx.Common; using Ryujinx.Common;
using System; using System;
using System.Numerics;
namespace Ryujinx.Graphics.GAL namespace Ryujinx.Graphics.GAL
{ {
@ -112,6 +113,25 @@ namespace Ryujinx.Graphics.GAL
return 1; return 1;
} }
public int GetLevelsClamped()
{
int maxSize = Width;
if (Target != Target.Texture1D &&
Target != Target.Texture1DArray)
{
maxSize = Math.Max(maxSize, Height);
}
if (Target == Target.Texture3D)
{
maxSize = Math.Max(maxSize, Depth);
}
int maxLevels = BitOperations.Log2((uint)maxSize) + 1;
return Math.Min(Levels, maxLevels);
}
private static int GetLevelSize(int size, int level) private static int GetLevelSize(int size, int level)
{ {
return Math.Max(1, size >> level); return Math.Max(1, size >> level);

View File

@ -5,6 +5,5 @@ namespace Ryujinx.Graphics.GAL
Bilinear, Bilinear,
Nearest, Nearest,
Fsr, Fsr,
Area,
} }
} }

View File

@ -1,10 +1,10 @@
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -276,6 +276,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
dstBaseOffset += dstStride * (yCount - 1); dstBaseOffset += dstStride * (yCount - 1);
} }
ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true);
// If remapping is disabled, we always copy the components directly, in order. // If remapping is disabled, we always copy the components directly, in order.
// If it's enabled, but the mapping is just XYZW, we also copy them in order. // If it's enabled, but the mapping is just XYZW, we also copy them in order.
bool isIdentityRemap = !remap || bool isIdentityRemap = !remap ||
@ -287,52 +289,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount); bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount); bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount);
// Check if the source texture exists on the GPU, if it does, do a GPU side copy.
// Otherwise, we would need to flush the source texture which is costly.
// We don't expect the source to be linear in such cases, as linear source usually indicates buffer or CPU written data.
if (completeSource && completeDest && !srcLinear && isIdentityRemap)
{
var source = memoryManager.Physical.TextureCache.FindTexture(
memoryManager,
srcGpuVa,
srcBpp,
srcStride,
src.Height,
xCount,
yCount,
srcLinear,
src.MemoryLayout.UnpackGobBlocksInY(),
src.MemoryLayout.UnpackGobBlocksInZ());
if (source != null && source.Height == yCount)
{
source.SynchronizeMemory();
var target = memoryManager.Physical.TextureCache.FindOrCreateTexture(
memoryManager,
source.Info.FormatInfo,
dstGpuVa,
xCount,
yCount,
dstStride,
dstLinear,
dst.MemoryLayout.UnpackGobBlocksInY(),
dst.MemoryLayout.UnpackGobBlocksInZ());
if (source.ScaleFactor != target.ScaleFactor)
{
target.PropagateScale(source);
}
source.HostTexture.CopyTo(target.HostTexture, 0, 0);
target.SignalModified();
return;
}
}
ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true);
// Try to set the texture data directly, // Try to set the texture data directly,
// but only if we are doing a complete copy, // but only if we are doing a complete copy,
// and not for block linear to linear copies, since those are typically accessed from the CPU. // and not for block linear to linear copies, since those are typically accessed from the CPU.
@ -353,7 +309,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
if (target != null) if (target != null)
{ {
MemoryOwner<byte> data; IMemoryOwner<byte> data;
if (srcLinear) if (srcLinear)
{ {
data = LayoutConverter.ConvertLinearStridedToLinear( data = LayoutConverter.ConvertLinearStridedToLinear(

View File

@ -199,7 +199,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
if (target != null) if (target != null)
{ {
target.SynchronizeMemory(); target.SynchronizeMemory();
var dataCopy = MemoryOwner<byte>.RentCopy(data); var dataCopy = ByteMemoryPool.RentCopy(data);
target.SetData(dataCopy, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount)); target.SetData(dataCopy, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
target.SignalModified(); target.SignalModified();

View File

@ -5,7 +5,6 @@ using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.GPFifo; using Ryujinx.Graphics.Gpu.Engine.GPFifo;
using Ryujinx.Graphics.Gpu.Engine.Threed; using Ryujinx.Graphics.Gpu.Engine.Threed;
using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -496,8 +495,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.MME
ulong indirectBufferSize = (ulong)maxDrawCount * (ulong)stride; ulong indirectBufferSize = (ulong)maxDrawCount * (ulong)stride;
MultiRange indirectBufferRange = bufferCache.TranslateAndCreateMultiBuffers(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize, BufferStage.Indirect); MultiRange indirectBufferRange = bufferCache.TranslateAndCreateMultiBuffers(_processor.MemoryManager, indirectBufferGpuVa, indirectBufferSize);
MultiRange parameterBufferRange = bufferCache.TranslateAndCreateMultiBuffers(_processor.MemoryManager, parameterBufferGpuVa, 4, BufferStage.Indirect); MultiRange parameterBufferRange = bufferCache.TranslateAndCreateMultiBuffers(_processor.MemoryManager, parameterBufferGpuVa, 4);
_processor.ThreedClass.DrawIndirect( _processor.ThreedClass.DrawIndirect(
topology, topology,

View File

@ -1,6 +1,5 @@
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
namespace Ryujinx.Graphics.Gpu.Engine namespace Ryujinx.Graphics.Gpu.Engine
@ -62,51 +61,51 @@ namespace Ryujinx.Graphics.Gpu.Engine
/// </summary> /// </summary>
/// <param name="format">Shader image format</param> /// <param name="format">Shader image format</param>
/// <returns>Texture format</returns> /// <returns>Texture format</returns>
public static FormatInfo GetFormatInfo(TextureFormat format) public static Format GetFormat(TextureFormat format)
{ {
return format switch return format switch
{ {
#pragma warning disable IDE0055 // Disable formatting #pragma warning disable IDE0055 // Disable formatting
TextureFormat.R8Unorm => new(Format.R8Unorm, 1, 1, 1, 1), TextureFormat.R8Unorm => Format.R8Unorm,
TextureFormat.R8Snorm => new(Format.R8Snorm, 1, 1, 1, 1), TextureFormat.R8Snorm => Format.R8Snorm,
TextureFormat.R8Uint => new(Format.R8Uint, 1, 1, 1, 1), TextureFormat.R8Uint => Format.R8Uint,
TextureFormat.R8Sint => new(Format.R8Sint, 1, 1, 1, 1), TextureFormat.R8Sint => Format.R8Sint,
TextureFormat.R16Float => new(Format.R16Float, 1, 1, 2, 1), TextureFormat.R16Float => Format.R16Float,
TextureFormat.R16Unorm => new(Format.R16Unorm, 1, 1, 2, 1), TextureFormat.R16Unorm => Format.R16Unorm,
TextureFormat.R16Snorm => new(Format.R16Snorm, 1, 1, 2, 1), TextureFormat.R16Snorm => Format.R16Snorm,
TextureFormat.R16Uint => new(Format.R16Uint, 1, 1, 2, 1), TextureFormat.R16Uint => Format.R16Uint,
TextureFormat.R16Sint => new(Format.R16Sint, 1, 1, 2, 1), TextureFormat.R16Sint => Format.R16Sint,
TextureFormat.R32Float => new(Format.R32Float, 1, 1, 4, 1), TextureFormat.R32Float => Format.R32Float,
TextureFormat.R32Uint => new(Format.R32Uint, 1, 1, 4, 1), TextureFormat.R32Uint => Format.R32Uint,
TextureFormat.R32Sint => new(Format.R32Sint, 1, 1, 4, 1), TextureFormat.R32Sint => Format.R32Sint,
TextureFormat.R8G8Unorm => new(Format.R8G8Unorm, 1, 1, 2, 2), TextureFormat.R8G8Unorm => Format.R8G8Unorm,
TextureFormat.R8G8Snorm => new(Format.R8G8Snorm, 1, 1, 2, 2), TextureFormat.R8G8Snorm => Format.R8G8Snorm,
TextureFormat.R8G8Uint => new(Format.R8G8Uint, 1, 1, 2, 2), TextureFormat.R8G8Uint => Format.R8G8Uint,
TextureFormat.R8G8Sint => new(Format.R8G8Sint, 1, 1, 2, 2), TextureFormat.R8G8Sint => Format.R8G8Sint,
TextureFormat.R16G16Float => new(Format.R16G16Float, 1, 1, 4, 2), TextureFormat.R16G16Float => Format.R16G16Float,
TextureFormat.R16G16Unorm => new(Format.R16G16Unorm, 1, 1, 4, 2), TextureFormat.R16G16Unorm => Format.R16G16Unorm,
TextureFormat.R16G16Snorm => new(Format.R16G16Snorm, 1, 1, 4, 2), TextureFormat.R16G16Snorm => Format.R16G16Snorm,
TextureFormat.R16G16Uint => new(Format.R16G16Uint, 1, 1, 4, 2), TextureFormat.R16G16Uint => Format.R16G16Uint,
TextureFormat.R16G16Sint => new(Format.R16G16Sint, 1, 1, 4, 2), TextureFormat.R16G16Sint => Format.R16G16Sint,
TextureFormat.R32G32Float => new(Format.R32G32Float, 1, 1, 8, 2), TextureFormat.R32G32Float => Format.R32G32Float,
TextureFormat.R32G32Uint => new(Format.R32G32Uint, 1, 1, 8, 2), TextureFormat.R32G32Uint => Format.R32G32Uint,
TextureFormat.R32G32Sint => new(Format.R32G32Sint, 1, 1, 8, 2), TextureFormat.R32G32Sint => Format.R32G32Sint,
TextureFormat.R8G8B8A8Unorm => new(Format.R8G8B8A8Unorm, 1, 1, 4, 4), TextureFormat.R8G8B8A8Unorm => Format.R8G8B8A8Unorm,
TextureFormat.R8G8B8A8Snorm => new(Format.R8G8B8A8Snorm, 1, 1, 4, 4), TextureFormat.R8G8B8A8Snorm => Format.R8G8B8A8Snorm,
TextureFormat.R8G8B8A8Uint => new(Format.R8G8B8A8Uint, 1, 1, 4, 4), TextureFormat.R8G8B8A8Uint => Format.R8G8B8A8Uint,
TextureFormat.R8G8B8A8Sint => new(Format.R8G8B8A8Sint, 1, 1, 4, 4), TextureFormat.R8G8B8A8Sint => Format.R8G8B8A8Sint,
TextureFormat.R16G16B16A16Float => new(Format.R16G16B16A16Float, 1, 1, 8, 4), TextureFormat.R16G16B16A16Float => Format.R16G16B16A16Float,
TextureFormat.R16G16B16A16Unorm => new(Format.R16G16B16A16Unorm, 1, 1, 8, 4), TextureFormat.R16G16B16A16Unorm => Format.R16G16B16A16Unorm,
TextureFormat.R16G16B16A16Snorm => new(Format.R16G16B16A16Snorm, 1, 1, 8, 4), TextureFormat.R16G16B16A16Snorm => Format.R16G16B16A16Snorm,
TextureFormat.R16G16B16A16Uint => new(Format.R16G16B16A16Uint, 1, 1, 8, 4), TextureFormat.R16G16B16A16Uint => Format.R16G16B16A16Uint,
TextureFormat.R16G16B16A16Sint => new(Format.R16G16B16A16Sint, 1, 1, 8, 4), TextureFormat.R16G16B16A16Sint => Format.R16G16B16A16Sint,
TextureFormat.R32G32B32A32Float => new(Format.R32G32B32A32Float, 1, 1, 16, 4), TextureFormat.R32G32B32A32Float => Format.R32G32B32A32Float,
TextureFormat.R32G32B32A32Uint => new(Format.R32G32B32A32Uint, 1, 1, 16, 4), TextureFormat.R32G32B32A32Uint => Format.R32G32B32A32Uint,
TextureFormat.R32G32B32A32Sint => new(Format.R32G32B32A32Sint, 1, 1, 16, 4), TextureFormat.R32G32B32A32Sint => Format.R32G32B32A32Sint,
TextureFormat.R10G10B10A2Unorm => new(Format.R10G10B10A2Unorm, 1, 1, 4, 4), TextureFormat.R10G10B10A2Unorm => Format.R10G10B10A2Unorm,
TextureFormat.R10G10B10A2Uint => new(Format.R10G10B10A2Uint, 1, 1, 4, 4), TextureFormat.R10G10B10A2Uint => Format.R10G10B10A2Uint,
TextureFormat.R11G11B10Float => new(Format.R11G11B10Float, 1, 1, 4, 3), TextureFormat.R11G11B10Float => Format.R11G11B10Float,
_ => FormatInfo.Invalid, _ => 0,
#pragma warning restore IDE0055 #pragma warning restore IDE0055
}; };
} }

View File

@ -438,7 +438,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
ReadOnlySpan<byte> dataBytes = MemoryMarshal.Cast<int, byte>(data); ReadOnlySpan<byte> dataBytes = MemoryMarshal.Cast<int, byte>(data);
BufferHandle buffer = _context.Renderer.CreateBuffer(dataBytes.Length, BufferAccess.DeviceMemory); BufferHandle buffer = _context.Renderer.CreateBuffer(dataBytes.Length);
_context.Renderer.SetBufferData(buffer, 0, dataBytes); _context.Renderer.SetBufferData(buffer, 0, dataBytes);
return new IndexBuffer(buffer, count, dataBytes.Length); return new IndexBuffer(buffer, count, dataBytes.Length);
@ -529,7 +529,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
{ {
if (_dummyBuffer == BufferHandle.Null) if (_dummyBuffer == BufferHandle.Null)
{ {
_dummyBuffer = _context.Renderer.CreateBuffer(DummyBufferSize, BufferAccess.DeviceMemory); _dummyBuffer = _context.Renderer.CreateBuffer(DummyBufferSize);
_context.Renderer.Pipeline.ClearBuffer(_dummyBuffer, 0, DummyBufferSize, 0); _context.Renderer.Pipeline.ClearBuffer(_dummyBuffer, 0, DummyBufferSize, 0);
} }
@ -550,7 +550,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
_context.Renderer.DeleteBuffer(_sequentialIndexBuffer); _context.Renderer.DeleteBuffer(_sequentialIndexBuffer);
} }
_sequentialIndexBuffer = _context.Renderer.CreateBuffer(count * sizeof(uint), BufferAccess.DeviceMemory); _sequentialIndexBuffer = _context.Renderer.CreateBuffer(count * sizeof(uint));
_sequentialIndexBufferCount = count; _sequentialIndexBufferCount = count;
Span<int> data = new int[count]; Span<int> data = new int[count];
@ -583,7 +583,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
_context.Renderer.DeleteBuffer(buffer.Handle); _context.Renderer.DeleteBuffer(buffer.Handle);
} }
buffer.Handle = _context.Renderer.CreateBuffer(newSize, BufferAccess.DeviceMemory); buffer.Handle = _context.Renderer.CreateBuffer(newSize);
buffer.Size = newSize; buffer.Size = newSize;
} }

View File

@ -3,7 +3,6 @@ using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.Types; using Ryujinx.Graphics.Gpu.Engine.Types;
using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Image;
using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.Translation; using Ryujinx.Graphics.Shader.Translation;
@ -371,7 +370,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
{ {
var memoryManager = _channel.MemoryManager; var memoryManager = _channel.MemoryManager;
BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange(memoryManager.GetPhysicalRegions(address, size), BufferStage.VertexBuffer); BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange(memoryManager.GetPhysicalRegions(address, size));
ITexture bufferTexture = _vacContext.EnsureBufferTexture(index + 2, format); ITexture bufferTexture = _vacContext.EnsureBufferTexture(index + 2, format);
bufferTexture.SetStorage(range); bufferTexture.SetStorage(range);
@ -413,9 +412,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw
var memoryManager = _channel.MemoryManager; var memoryManager = _channel.MemoryManager;
ulong misalign = address & ((ulong)_context.Capabilities.TextureBufferOffsetAlignment - 1); ulong misalign = address & ((ulong)_context.Capabilities.TextureBufferOffsetAlignment - 1);
BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange( BufferRange range = memoryManager.Physical.BufferCache.GetBufferRange(memoryManager.GetPhysicalRegions(address + indexOffset - misalign, size + misalign));
memoryManager.GetPhysicalRegions(address + indexOffset - misalign, size + misalign),
BufferStage.IndexBuffer);
misalignedOffset = (int)misalign >> shift; misalignedOffset = (int)misalign >> shift;
SetIndexBufferTexture(reservations, range, format); SetIndexBufferTexture(reservations, range, format);

View File

@ -684,8 +684,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
if (hasCount) if (hasCount)
{ {
var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferRange, BufferStage.Indirect); var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferRange);
var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferRange, BufferStage.Indirect); var parameterBuffer = memory.BufferCache.GetBufferRange(parameterBufferRange);
if (indexed) if (indexed)
{ {
@ -698,7 +698,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
} }
else else
{ {
var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferRange, BufferStage.Indirect); var indirectBuffer = memory.BufferCache.GetBufferRange(indirectBufferRange);
if (indexed) if (indexed)
{ {

View File

@ -79,10 +79,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{ {
var field = fields[fieldIndex]; var field = fields[fieldIndex];
var currentFieldOffset = (int)Marshal.OffsetOf<TState>(field.Name); int sizeOfField = SizeCalculator.SizeOf(field.FieldType);
var nextFieldOffset = fieldIndex + 1 == fields.Length ? Unsafe.SizeOf<TState>() : (int)Marshal.OffsetOf<TState>(fields[fieldIndex + 1].Name);
int sizeOfField = nextFieldOffset - currentFieldOffset;
if (fieldToDelegate.TryGetValue(field.Name, out int entryIndex)) if (fieldToDelegate.TryGetValue(field.Name, out int entryIndex))
{ {

View File

@ -415,13 +415,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
#pragma warning disable CS0649 // Field is never assigned to #pragma warning disable CS0649 // Field is never assigned to
public int Width; public int Width;
public int Height; public int Height;
public ushort Depth; public int Depth;
public ushort Flags;
public readonly bool UnpackIsLayered()
{
return (Flags & 1) == 0;
}
#pragma warning restore CS0649 #pragma warning restore CS0649
} }

View File

@ -393,18 +393,17 @@ namespace Ryujinx.Graphics.Gpu
if (force || _pendingSync || (syncpoint && SyncpointActions.Count > 0)) if (force || _pendingSync || (syncpoint && SyncpointActions.Count > 0))
{ {
Renderer.CreateSync(SyncNumber, strict);
foreach (var action in SyncActions) foreach (var action in SyncActions)
{ {
action.SyncPreAction(syncpoint); action.SyncPreAction(syncpoint);
} }
foreach (var action in SyncpointActions) foreach (var action in SyncpointActions)
{ {
action.SyncPreAction(syncpoint); action.SyncPreAction(syncpoint);
} }
Renderer.CreateSync(SyncNumber, strict);
SyncNumber++; SyncNumber++;
SyncActions.RemoveAll(action => action.SyncAction(syncpoint)); SyncActions.RemoveAll(action => action.SyncAction(syncpoint));

View File

@ -1,4 +1,3 @@
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -47,11 +46,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
private const int MinCountForDeletion = 32; private const int MinCountForDeletion = 32;
private const int MaxCapacity = 2048; private const int MaxCapacity = 2048;
private const ulong MinTextureSizeCapacity = 512 * 1024 * 1024; private const ulong MaxTextureSizeCapacity = 1024 * 1024 * 1024; // MB;
private const ulong MaxTextureSizeCapacity = 4UL * 1024 * 1024 * 1024;
private const ulong DefaultTextureSizeCapacity = 1UL * 1024 * 1024 * 1024;
private const float MemoryScaleFactor = 0.50f;
private ulong _maxCacheMemoryUsage = 0;
private readonly LinkedList<Texture> _textures; private readonly LinkedList<Texture> _textures;
private ulong _totalSize; private ulong _totalSize;
@ -61,25 +56,6 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly Dictionary<TextureDescriptor, ShortTextureCacheEntry> _shortCacheLookup; private readonly Dictionary<TextureDescriptor, ShortTextureCacheEntry> _shortCacheLookup;
/// <summary>
/// Initializes the cache, setting the maximum texture capacity for the specified GPU context.
/// </summary>
/// <remarks>
/// If the backend GPU has 0 memory capacity, the cache size defaults to `DefaultTextureSizeCapacity`.
/// </remarks>
/// <param name="context">The GPU context that the cache belongs to</param>
public void Initialize(GpuContext context)
{
var cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor);
_maxCacheMemoryUsage = Math.Clamp(cacheMemory, MinTextureSizeCapacity, MaxTextureSizeCapacity);
if (context.Capabilities.MaximumGpuMemory == 0)
{
_maxCacheMemoryUsage = DefaultTextureSizeCapacity;
}
}
/// <summary> /// <summary>
/// Creates a new instance of the automatic deletion cache. /// Creates a new instance of the automatic deletion cache.
/// </summary> /// </summary>
@ -109,7 +85,7 @@ namespace Ryujinx.Graphics.Gpu.Image
texture.CacheNode = _textures.AddLast(texture); texture.CacheNode = _textures.AddLast(texture);
if (_textures.Count > MaxCapacity || if (_textures.Count > MaxCapacity ||
(_totalSize > _maxCacheMemoryUsage && _textures.Count >= MinCountForDeletion)) (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion))
{ {
RemoveLeastUsedTexture(); RemoveLeastUsedTexture();
} }
@ -134,7 +110,7 @@ namespace Ryujinx.Graphics.Gpu.Image
_textures.AddLast(texture.CacheNode); _textures.AddLast(texture.CacheNode);
} }
if (_totalSize > _maxCacheMemoryUsage && _textures.Count >= MinCountForDeletion) if (_totalSize > MaxTextureSizeCapacity && _textures.Count >= MinCountForDeletion)
{ {
RemoveLeastUsedTexture(); RemoveLeastUsedTexture();
} }

View File

@ -7,11 +7,6 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
readonly struct FormatInfo readonly struct FormatInfo
{ {
/// <summary>
/// An invalid texture format.
/// </summary>
public static FormatInfo Invalid { get; } = new(0, 0, 0, 0, 0);
/// <summary> /// <summary>
/// A default, generic RGBA8 texture format. /// A default, generic RGBA8 texture format.
/// </summary> /// </summary>
@ -28,7 +23,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <remarks> /// <remarks>
/// Must be 1 for non-compressed formats. /// Must be 1 for non-compressed formats.
/// </remarks> /// </remarks>
public byte BlockWidth { get; } public int BlockWidth { get; }
/// <summary> /// <summary>
/// The block height for compressed formats. /// The block height for compressed formats.
@ -36,17 +31,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <remarks> /// <remarks>
/// Must be 1 for non-compressed formats. /// Must be 1 for non-compressed formats.
/// </remarks> /// </remarks>
public byte BlockHeight { get; } public int BlockHeight { get; }
/// <summary> /// <summary>
/// The number of bytes occupied by a single pixel in memory of the texture data. /// The number of bytes occupied by a single pixel in memory of the texture data.
/// </summary> /// </summary>
public byte BytesPerPixel { get; } public int BytesPerPixel { get; }
/// <summary> /// <summary>
/// The maximum number of components this format has defined (in RGBA order). /// The maximum number of components this format has defined (in RGBA order).
/// </summary> /// </summary>
public byte Components { get; } public int Components { get; }
/// <summary> /// <summary>
/// Whenever or not the texture format is a compressed format. Determined from block size. /// Whenever or not the texture format is a compressed format. Determined from block size.
@ -62,10 +57,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="bytesPerPixel">The number of bytes occupied by a single pixel in memory of the texture data</param> /// <param name="bytesPerPixel">The number of bytes occupied by a single pixel in memory of the texture data</param>
public FormatInfo( public FormatInfo(
Format format, Format format,
byte blockWidth, int blockWidth,
byte blockHeight, int blockHeight,
byte bytesPerPixel, int bytesPerPixel,
byte components) int components)
{ {
Format = format; Format = format;
BlockWidth = blockWidth; BlockWidth = blockWidth;

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