Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
fbdd390f90 | |||
f33fea3287 | |||
5d3eea40be | |||
cd37c75b82 | |||
43705c2320 | |||
371e6fa24c | |||
1d9b63cc6a | |||
795539bc82 | |||
dd2e851e95 | |||
2ca70eb9a0 | |||
6575952432 | |||
9a28ba72b1 | |||
34a9922b57 |
@ -13,25 +13,25 @@
|
|||||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||||
<PackageVersion Include="Concentus" Version="1.1.7" />
|
<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="7.14.2" />
|
<PackageVersion Include="DynamicData" Version="8.3.27" />
|
||||||
<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="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
|
<PackageVersion Include="jp2masa.Avalonia.Flexbox" Version="0.3.0-beta.4" />
|
||||||
<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.7.0" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" />
|
||||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.2.0" />
|
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.2.0" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<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="7.0.0" />
|
<PackageVersion Include="NetCoreServer" Version="7.0.0" />
|
||||||
<PackageVersion Include="NUnit" Version="3.13.3" />
|
<PackageVersion Include="NUnit" Version="3.13.3" />
|
||||||
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
<PackageVersion Include="NUnit3TestAdapter" Version="4.1.0" />
|
||||||
<PackageVersion Include="OpenTK.Core" Version="4.8.1" />
|
<PackageVersion Include="OpenTK.Core" Version="4.8.2" />
|
||||||
<PackageVersion Include="OpenTK.Graphics" Version="4.8.1" />
|
<PackageVersion Include="OpenTK.Graphics" Version="4.8.2" />
|
||||||
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.1" />
|
<PackageVersion Include="OpenTK.Audio.OpenAL" Version="4.8.2" />
|
||||||
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.1" />
|
<PackageVersion Include="OpenTK.Windowing.GraphicsLibraryFramework" Version="4.8.2" />
|
||||||
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build13" />
|
||||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||||
@ -46,7 +46,7 @@
|
|||||||
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
|
<PackageVersion Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageVersion Include="System.Drawing.Common" Version="8.0.0" />
|
<PackageVersion Include="System.Drawing.Common" Version="8.0.1" />
|
||||||
<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" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
|
8
distribution/macos/shortcut-launch-script.sh
Normal file
8
distribution/macos/shortcut-launch-script.sh
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
launch_arch="$(uname -m)"
|
||||||
|
if [ "$(sysctl -in sysctl.proc_translated)" = "1" ]
|
||||||
|
then
|
||||||
|
launch_arch="arm64"
|
||||||
|
fi
|
||||||
|
|
||||||
|
arch -$launch_arch {0} {1}
|
@ -517,7 +517,10 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("0x00111100>>>xxx100111xxxxxxxxxx", InstName.Sqrshrn_V, InstEmit.Sqrshrn_V, OpCodeSimdShImm.Create);
|
SetA64("0x00111100>>>xxx100111xxxxxxxxxx", InstName.Sqrshrn_V, InstEmit.Sqrshrn_V, OpCodeSimdShImm.Create);
|
||||||
SetA64("0111111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_S, InstEmit.Sqrshrun_S, OpCodeSimdShImm.Create);
|
SetA64("0111111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_S, InstEmit.Sqrshrun_S, OpCodeSimdShImm.Create);
|
||||||
SetA64("0x10111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_V, InstEmit.Sqrshrun_V, OpCodeSimdShImm.Create);
|
SetA64("0x10111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_V, InstEmit.Sqrshrun_V, OpCodeSimdShImm.Create);
|
||||||
|
SetA64("010111110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Si, InstEmit.Sqshl_Si, OpCodeSimdShImm.Create);
|
||||||
SetA64("0>001110<<1xxxxx010011xxxxxxxxxx", InstName.Sqshl_V, InstEmit.Sqshl_V, OpCodeSimdReg.Create);
|
SetA64("0>001110<<1xxxxx010011xxxxxxxxxx", InstName.Sqshl_V, InstEmit.Sqshl_V, OpCodeSimdReg.Create);
|
||||||
|
SetA64("0000111100>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create);
|
||||||
|
SetA64("010011110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create);
|
||||||
SetA64("0101111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_S, InstEmit.Sqshrn_S, OpCodeSimdShImm.Create);
|
SetA64("0101111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_S, InstEmit.Sqshrn_S, OpCodeSimdShImm.Create);
|
||||||
SetA64("0x00111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_V, InstEmit.Sqshrn_V, OpCodeSimdShImm.Create);
|
SetA64("0x00111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_V, InstEmit.Sqshrn_V, OpCodeSimdShImm.Create);
|
||||||
SetA64("0111111100>>>xxx100001xxxxxxxxxx", InstName.Sqshrun_S, InstEmit.Sqshrun_S, OpCodeSimdShImm.Create);
|
SetA64("0111111100>>>xxx100001xxxxxxxxxx", InstName.Sqshrun_S, InstEmit.Sqshrun_S, OpCodeSimdShImm.Create);
|
||||||
|
@ -116,7 +116,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
else if (shift >= eSize)
|
else if (shift >= eSize)
|
||||||
{
|
{
|
||||||
if ((op.RegisterSize == RegisterSize.Simd64))
|
if (op.RegisterSize == RegisterSize.Simd64)
|
||||||
{
|
{
|
||||||
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
Operand res = context.VectorZeroUpper64(GetVec(op.Rd));
|
||||||
|
|
||||||
@ -359,6 +359,16 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Sqshl_Si(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Scalar | ShlRegFlags.Saturating);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sqshl_Vi(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Saturating);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Sqshrn_S(ArmEmitterContext context)
|
public static void Sqshrn_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
if (Optimizations.UseAdvSimd)
|
if (Optimizations.UseAdvSimd)
|
||||||
@ -1593,6 +1603,99 @@ namespace ARMeilleure.Instructions
|
|||||||
Saturating = 1 << 3,
|
Saturating = 1 << 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitShlImmOp(ArmEmitterContext context, bool signedDst, ShlRegFlags flags = ShlRegFlags.None)
|
||||||
|
{
|
||||||
|
bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
|
||||||
|
bool signed = flags.HasFlag(ShlRegFlags.Signed);
|
||||||
|
bool saturating = flags.HasFlag(ShlRegFlags.Saturating);
|
||||||
|
|
||||||
|
OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp;
|
||||||
|
|
||||||
|
Operand res = context.VectorZero();
|
||||||
|
|
||||||
|
int elems = !scalar ? op.GetBytesCount() >> op.Size : 1;
|
||||||
|
|
||||||
|
for (int index = 0; index < elems; index++)
|
||||||
|
{
|
||||||
|
Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed);
|
||||||
|
|
||||||
|
Operand e = !saturating
|
||||||
|
? EmitShlImm(context, ne, GetImmShl(op), op.Size)
|
||||||
|
: EmitShlImmSatQ(context, ne, GetImmShl(op), op.Size, signed, signedDst);
|
||||||
|
|
||||||
|
res = EmitVectorInsert(context, res, e, index, op.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitShlImm(ArmEmitterContext context, Operand op, int shiftLsB, int size)
|
||||||
|
{
|
||||||
|
int eSize = 8 << size;
|
||||||
|
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
||||||
|
|
||||||
|
Operand res = context.AllocateLocal(OperandType.I64);
|
||||||
|
|
||||||
|
if (shiftLsB >= eSize)
|
||||||
|
{
|
||||||
|
Operand shl = context.ShiftLeft(op, Const(shiftLsB));
|
||||||
|
context.Copy(res, shl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand zeroL = Const(0L);
|
||||||
|
context.Copy(res, zeroL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitShlImmSatQ(ArmEmitterContext context, Operand op, int shiftLsB, int size, bool signedSrc, bool signedDst)
|
||||||
|
{
|
||||||
|
int eSize = 8 << size;
|
||||||
|
|
||||||
|
Debug.Assert(op.Type == OperandType.I64);
|
||||||
|
Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64);
|
||||||
|
|
||||||
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
|
Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op);
|
||||||
|
|
||||||
|
if (shiftLsB >= eSize)
|
||||||
|
{
|
||||||
|
context.Copy(res, signedSrc
|
||||||
|
? EmitSignedSignSatQ(context, op, size)
|
||||||
|
: EmitUnsignedSignSatQ(context, op, size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand shl = context.ShiftLeft(op, Const(shiftLsB));
|
||||||
|
if (eSize == 64)
|
||||||
|
{
|
||||||
|
Operand sarOrShr = signedSrc
|
||||||
|
? context.ShiftRightSI(shl, Const(shiftLsB))
|
||||||
|
: context.ShiftRightUI(shl, Const(shiftLsB));
|
||||||
|
context.Copy(res, shl);
|
||||||
|
context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal);
|
||||||
|
context.Copy(res, signedSrc
|
||||||
|
? EmitSignedSignSatQ(context, op, size)
|
||||||
|
: EmitUnsignedSignSatQ(context, op, size));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Copy(res, signedSrc
|
||||||
|
? EmitSignedSrcSatQ(context, shl, size, signedDst)
|
||||||
|
: EmitUnsignedSrcSatQ(context, shl, size, signedDst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context.MarkLabel(lblEnd);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None)
|
private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None)
|
||||||
{
|
{
|
||||||
bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
|
bool scalar = flags.HasFlag(ShlRegFlags.Scalar);
|
||||||
|
@ -384,7 +384,9 @@ namespace ARMeilleure.Instructions
|
|||||||
Sqrshrn_V,
|
Sqrshrn_V,
|
||||||
Sqrshrun_S,
|
Sqrshrun_S,
|
||||||
Sqrshrun_V,
|
Sqrshrun_V,
|
||||||
|
Sqshl_Si,
|
||||||
Sqshl_V,
|
Sqshl_V,
|
||||||
|
Sqshl_Vi,
|
||||||
Sqshrn_S,
|
Sqshrn_S,
|
||||||
Sqshrn_V,
|
Sqshrn_V,
|
||||||
Sqshrun_S,
|
Sqshrun_S,
|
||||||
|
@ -12,7 +12,6 @@ using Ryujinx.Ui.Common.Configuration;
|
|||||||
using Ryujinx.Ui.Common.Helper;
|
using Ryujinx.Ui.Common.Helper;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava
|
namespace Ryujinx.Ava
|
||||||
{
|
{
|
||||||
@ -90,8 +89,6 @@ namespace Ryujinx.Ava
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
string baseStyle = ConfigurationState.Instance.Ui.BaseStyle;
|
string baseStyle = ConfigurationState.Instance.Ui.BaseStyle;
|
||||||
string themePath = ConfigurationState.Instance.Ui.CustomThemePath;
|
|
||||||
bool enableCustomTheme = ConfigurationState.Instance.Ui.EnableCustomTheme;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(baseStyle))
|
if (string.IsNullOrWhiteSpace(baseStyle))
|
||||||
{
|
{
|
||||||
@ -106,24 +103,6 @@ namespace Ryujinx.Ava
|
|||||||
"Dark" => ThemeVariant.Dark,
|
"Dark" => ThemeVariant.Dark,
|
||||||
_ => ThemeVariant.Default,
|
_ => ThemeVariant.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (enableCustomTheme)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(themePath))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var themeContent = File.ReadAllText(themePath);
|
|
||||||
var customStyle = AvaloniaRuntimeXamlLoader.Parse<IStyle>(themeContent);
|
|
||||||
|
|
||||||
Styles.Add(customStyle);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Error?.Print(LogClass.Application, $"Failed to Apply Custom Theme. Error: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
|
@ -294,13 +294,9 @@
|
|||||||
"GameListContextMenuRunApplication": "Run Application",
|
"GameListContextMenuRunApplication": "Run Application",
|
||||||
"GameListContextMenuToggleFavorite": "Toggle Favorite",
|
"GameListContextMenuToggleFavorite": "Toggle Favorite",
|
||||||
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
|
"GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game",
|
||||||
"SettingsTabGeneralTheme": "Theme",
|
"SettingsTabGeneralTheme": "Theme:",
|
||||||
"SettingsTabGeneralThemeCustomTheme": "Custom Theme Path",
|
"SettingsTabGeneralThemeDark": "Dark",
|
||||||
"SettingsTabGeneralThemeBaseStyle": "Base Style",
|
"SettingsTabGeneralThemeLight": "Light",
|
||||||
"SettingsTabGeneralThemeBaseStyleDark": "Dark",
|
|
||||||
"SettingsTabGeneralThemeBaseStyleLight": "Light",
|
|
||||||
"SettingsTabGeneralThemeEnableCustomTheme": "Enable Custom Theme",
|
|
||||||
"ButtonBrowse": "Browse",
|
|
||||||
"ControllerSettingsConfigureGeneral": "Configure",
|
"ControllerSettingsConfigureGeneral": "Configure",
|
||||||
"ControllerSettingsRumble": "Rumble",
|
"ControllerSettingsRumble": "Rumble",
|
||||||
"ControllerSettingsRumbleStrongMultiplier": "Strong Rumble Multiplier",
|
"ControllerSettingsRumbleStrongMultiplier": "Strong Rumble Multiplier",
|
||||||
|
@ -48,7 +48,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private readonly List<string> _gpuIds = new();
|
private readonly List<string> _gpuIds = new();
|
||||||
private KeyboardHotkeys _keyboardHotkeys;
|
private KeyboardHotkeys _keyboardHotkeys;
|
||||||
private int _graphicsBackendIndex;
|
private int _graphicsBackendIndex;
|
||||||
private string _customThemePath;
|
|
||||||
private int _scalingFilter;
|
private int _scalingFilter;
|
||||||
private int _scalingFilterLevel;
|
private int _scalingFilterLevel;
|
||||||
|
|
||||||
@ -160,7 +159,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
public bool IsOpenAlEnabled { get; set; }
|
public bool IsOpenAlEnabled { get; set; }
|
||||||
public bool IsSoundIoEnabled { get; set; }
|
public bool IsSoundIoEnabled { get; set; }
|
||||||
public bool IsSDL2Enabled { get; set; }
|
public bool IsSDL2Enabled { get; set; }
|
||||||
public bool EnableCustomTheme { get; set; }
|
|
||||||
public bool IsCustomResolutionScaleActive => _resolutionScale == 4;
|
public bool IsCustomResolutionScaleActive => _resolutionScale == 4;
|
||||||
public bool IsScalingFilterActive => _scalingFilter == (int)Ryujinx.Common.Configuration.ScalingFilter.Fsr;
|
public bool IsScalingFilterActive => _scalingFilter == (int)Ryujinx.Common.Configuration.ScalingFilter.Fsr;
|
||||||
|
|
||||||
@ -170,20 +168,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
public string TimeZone { get; set; }
|
public string TimeZone { get; set; }
|
||||||
public string ShaderDumpPath { get; set; }
|
public string ShaderDumpPath { get; set; }
|
||||||
|
|
||||||
public string CustomThemePath
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _customThemePath;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_customThemePath = value;
|
|
||||||
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Language { get; set; }
|
public int Language { get; set; }
|
||||||
public int Region { get; set; }
|
public int Region { get; set; }
|
||||||
public int FsGlobalAccessLogMode { get; set; }
|
public int FsGlobalAccessLogMode { get; set; }
|
||||||
@ -426,8 +410,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
GameDirectories.Clear();
|
GameDirectories.Clear();
|
||||||
GameDirectories.AddRange(config.Ui.GameDirs.Value);
|
GameDirectories.AddRange(config.Ui.GameDirs.Value);
|
||||||
|
|
||||||
EnableCustomTheme = config.Ui.EnableCustomTheme;
|
|
||||||
CustomThemePath = config.Ui.CustomThemePath;
|
|
||||||
BaseStyleIndex = config.Ui.BaseStyle == "Light" ? 0 : 1;
|
BaseStyleIndex = config.Ui.BaseStyle == "Light" ? 0 : 1;
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
@ -515,8 +497,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
config.Ui.GameDirs.Value = gameDirs;
|
config.Ui.GameDirs.Value = gameDirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Ui.EnableCustomTheme.Value = EnableCustomTheme;
|
|
||||||
config.Ui.CustomThemePath.Value = CustomThemePath;
|
|
||||||
config.Ui.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark";
|
config.Ui.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark";
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
<CheckBox IsChecked="{Binding ShowConfirmExit}">
|
<CheckBox IsChecked="{Binding ShowConfirmExit}">
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
<TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
<StackPanel Margin="0, 15, 0, 10" Orientation="Horizontal">
|
<StackPanel Margin="0, 15, 0, 0" Orientation="Horizontal">
|
||||||
<TextBlock VerticalAlignment="Center"
|
<TextBlock VerticalAlignment="Center"
|
||||||
Text="{locale:Locale SettingsTabGeneralHideCursor}"
|
Text="{locale:Locale SettingsTabGeneralHideCursor}"
|
||||||
Width="150" />
|
Width="150" />
|
||||||
@ -54,6 +54,22 @@
|
|||||||
</ComboBoxItem>
|
</ComboBoxItem>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<StackPanel Margin="0, 15, 0, 10" Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{locale:Locale SettingsTabGeneralTheme}"
|
||||||
|
Width="150" />
|
||||||
|
<ComboBox SelectedIndex="{Binding BaseStyleIndex}"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
MinWidth="100">
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeLight}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
<ComboBoxItem>
|
||||||
|
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeDark}" />
|
||||||
|
</ComboBoxItem>
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator Height="1" />
|
<Separator Height="1" />
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" />
|
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" />
|
||||||
@ -106,64 +122,6 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator Height="1" />
|
|
||||||
<TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralTheme}" />
|
|
||||||
<Grid Margin="10,0,0,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<CheckBox
|
|
||||||
IsChecked="{Binding EnableCustomTheme}"
|
|
||||||
ToolTip.Tip="{locale:Locale CustomThemeCheckTooltip}">
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeEnableCustomTheme}" />
|
|
||||||
</CheckBox>
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.Row="1"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
Text="{locale:Locale SettingsTabGeneralThemeCustomTheme}"
|
|
||||||
ToolTip.Tip="{locale:Locale CustomThemePathTooltip}" />
|
|
||||||
<TextBox
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
Text="{Binding CustomThemePath}" />
|
|
||||||
<Button
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="10,10,0,0"
|
|
||||||
Click="BrowseTheme"
|
|
||||||
ToolTip.Tip="{locale:Locale CustomThemeBrowseTooltip}"
|
|
||||||
Content="{locale:Locale ButtonBrowse}" />
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.Row="2"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
Text="{locale:Locale SettingsTabGeneralThemeBaseStyle}" />
|
|
||||||
<ComboBox
|
|
||||||
Grid.Column="1"
|
|
||||||
Grid.Row="2"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="0,10,0,0"
|
|
||||||
MinWidth="100"
|
|
||||||
SelectedIndex="{Binding BaseStyleIndex}">
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleLight}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
<ComboBoxItem>
|
|
||||||
<TextBlock Text="{locale:Locale SettingsTabGeneralThemeBaseStyleDark}" />
|
|
||||||
</ComboBoxItem>
|
|
||||||
</ComboBox>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
@ -61,29 +61,5 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
|||||||
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void BrowseTheme(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var window = this.GetVisualRoot() as Window;
|
|
||||||
var result = await window.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
|
||||||
{
|
|
||||||
Title = LocaleManager.Instance[LocaleKeys.SettingsSelectThemeFileDialogTitle],
|
|
||||||
AllowMultiple = false,
|
|
||||||
FileTypeFilter = new List<FilePickerFileType>
|
|
||||||
{
|
|
||||||
new("xml")
|
|
||||||
{
|
|
||||||
Patterns = new[] { "*.xaml" },
|
|
||||||
AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xaml" },
|
|
||||||
MimeTypes = new[] { "application/xaml+xml" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result.Count > 0)
|
|
||||||
{
|
|
||||||
ViewModel.CustomThemePath = result[0].Path.LocalPath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,6 +744,17 @@ namespace Ryujinx.Common.Memory
|
|||||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct Array65<T> : IArray<T> where T : unmanaged
|
||||||
|
{
|
||||||
|
T _e0;
|
||||||
|
Array64<T> _other;
|
||||||
|
public readonly int Length => 65;
|
||||||
|
public ref T this[int index] => ref AsSpan()[index];
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||||
|
}
|
||||||
|
|
||||||
public struct Array73<T> : IArray<T> where T : unmanaged
|
public struct Array73<T> : IArray<T> where T : unmanaged
|
||||||
{
|
{
|
||||||
T _e0;
|
T _e0;
|
||||||
|
@ -63,6 +63,18 @@ namespace Ryujinx.Common.Memory
|
|||||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)]
|
||||||
|
public struct ByteArray3000 : IArray<byte>
|
||||||
|
{
|
||||||
|
private const int Size = 3000;
|
||||||
|
|
||||||
|
byte _element;
|
||||||
|
|
||||||
|
public readonly int Length => Size;
|
||||||
|
public ref byte this[int index] => ref AsSpan()[index];
|
||||||
|
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||||
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)]
|
[StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)]
|
||||||
public struct ByteArray4096 : IArray<byte>
|
public struct ByteArray4096 : IArray<byte>
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@ using Silk.NET.Vulkan;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
||||||
using VkFormat = Silk.NET.Vulkan.Format;
|
using VkFormat = Silk.NET.Vulkan.Format;
|
||||||
@ -384,7 +385,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var baseData = new Span<byte>((void*)(_map + offset), size);
|
var baseData = new Span<byte>((void*)(_map + offset), size);
|
||||||
var modData = _pendingData.AsSpan(offset, size);
|
var modData = _pendingData.AsSpan(offset, size);
|
||||||
|
|
||||||
StagingBufferReserved? newMirror = _gd.BufferManager.StagingBuffer.TryReserveData(cbs, size, (int)_gd.Capabilities.MinResourceAlignment);
|
StagingBufferReserved? newMirror = _gd.BufferManager.StagingBuffer.TryReserveData(cbs, size);
|
||||||
|
|
||||||
if (newMirror != null)
|
if (newMirror != null)
|
||||||
{
|
{
|
||||||
@ -838,6 +839,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public unsafe void SetDataUnchecked<T>(int offset, ReadOnlySpan<T> data) where T : unmanaged
|
||||||
|
{
|
||||||
|
SetDataUnchecked(offset, MemoryMarshal.AsBytes(data));
|
||||||
|
}
|
||||||
|
|
||||||
public void SetDataInline(CommandBufferScoped cbs, Action endRenderPass, int dstOffset, ReadOnlySpan<byte> data)
|
public void SetDataInline(CommandBufferScoped cbs, Action endRenderPass, int dstOffset, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
if (!TryPushData(cbs, endRenderPass, dstOffset, data))
|
if (!TryPushData(cbs, endRenderPass, dstOffset, data))
|
||||||
|
@ -9,6 +9,36 @@ using VkFormat = Silk.NET.Vulkan.Format;
|
|||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
|
readonly struct ScopedTemporaryBuffer : IDisposable
|
||||||
|
{
|
||||||
|
private readonly BufferManager _bufferManager;
|
||||||
|
private readonly bool _isReserved;
|
||||||
|
|
||||||
|
public readonly BufferRange Range;
|
||||||
|
public readonly BufferHolder Holder;
|
||||||
|
|
||||||
|
public BufferHandle Handle => Range.Handle;
|
||||||
|
public int Offset => Range.Offset;
|
||||||
|
|
||||||
|
public ScopedTemporaryBuffer(BufferManager bufferManager, BufferHolder holder, BufferHandle handle, int offset, int size, bool isReserved)
|
||||||
|
{
|
||||||
|
_bufferManager = bufferManager;
|
||||||
|
|
||||||
|
Range = new BufferRange(handle, offset, size);
|
||||||
|
Holder = holder;
|
||||||
|
|
||||||
|
_isReserved = isReserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (!_isReserved)
|
||||||
|
{
|
||||||
|
_bufferManager.Delete(Range.Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class BufferManager : IDisposable
|
class BufferManager : IDisposable
|
||||||
{
|
{
|
||||||
public const MemoryPropertyFlags DefaultBufferMemoryFlags =
|
public const MemoryPropertyFlags DefaultBufferMemoryFlags =
|
||||||
@ -238,6 +268,23 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
return Unsafe.As<ulong, BufferHandle>(ref handle64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ScopedTemporaryBuffer ReserveOrCreate(VulkanRenderer gd, CommandBufferScoped cbs, int size)
|
||||||
|
{
|
||||||
|
StagingBufferReserved? result = StagingBuffer.TryReserveData(cbs, size);
|
||||||
|
|
||||||
|
if (result.HasValue)
|
||||||
|
{
|
||||||
|
return new ScopedTemporaryBuffer(this, result.Value.Buffer, StagingBuffer.Handle, result.Value.Offset, result.Value.Size, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create a temporary buffer.
|
||||||
|
BufferHandle handle = CreateWithHandle(gd, size, out BufferHolder holder);
|
||||||
|
|
||||||
|
return new ScopedTemporaryBuffer(this, holder, handle, 0, size, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe MemoryRequirements GetHostImportedUsageRequirements(VulkanRenderer gd)
|
public unsafe MemoryRequirements GetHostImportedUsageRequirements(VulkanRenderer gd)
|
||||||
{
|
{
|
||||||
var usage = HostImportedBufferUsageFlags;
|
var usage = HostImportedBufferUsageFlags;
|
||||||
@ -635,13 +682,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
|
StagingBuffer.Dispose();
|
||||||
|
|
||||||
foreach (BufferHolder buffer in _buffers)
|
foreach (BufferHolder buffer in _buffers)
|
||||||
{
|
{
|
||||||
buffer.Dispose();
|
buffer.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_buffers.Clear();
|
_buffers.Clear();
|
||||||
StagingBuffer.Dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,19 +142,18 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
|||||||
};
|
};
|
||||||
|
|
||||||
int rangeSize = dimensionsBuffer.Length * sizeof(float);
|
int rangeSize = dimensionsBuffer.Length * sizeof(float);
|
||||||
var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
|
||||||
_renderer.BufferManager.SetData(bufferHandle, 0, dimensionsBuffer);
|
buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer);
|
||||||
|
|
||||||
ReadOnlySpan<float> sharpeningBuffer = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) };
|
ReadOnlySpan<float> sharpeningBufferData = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) };
|
||||||
var sharpeningBufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, sizeof(float));
|
using var sharpeningBuffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, sizeof(float));
|
||||||
_renderer.BufferManager.SetData(sharpeningBufferHandle, 0, sharpeningBuffer);
|
sharpeningBuffer.Holder.SetDataUnchecked(sharpeningBuffer.Offset, sharpeningBufferData);
|
||||||
|
|
||||||
int threadGroupWorkRegionDim = 16;
|
int threadGroupWorkRegionDim = 16;
|
||||||
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||||
|
|
||||||
var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
|
|
||||||
_pipeline.SetImage(0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
_pipeline.SetImage(0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
@ -162,16 +161,12 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
|||||||
// Sharpening pass
|
// Sharpening pass
|
||||||
_pipeline.SetProgram(_sharpeningProgram);
|
_pipeline.SetProgram(_sharpeningProgram);
|
||||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler);
|
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler);
|
||||||
var sharpeningRange = new BufferRange(sharpeningBufferHandle, 0, sizeof(float));
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningBuffer.Range) });
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningRange) });
|
|
||||||
_pipeline.SetImage(0, destinationTexture);
|
_pipeline.SetImage(0, destinationTexture);
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
||||||
_renderer.BufferManager.Delete(bufferHandle);
|
|
||||||
_renderer.BufferManager.Delete(sharpeningBufferHandle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,12 +66,11 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
|||||||
|
|
||||||
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
|
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
|
||||||
int rangeSize = resolutionBuffer.Length * sizeof(float);
|
int rangeSize = resolutionBuffer.Length * sizeof(float);
|
||||||
var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
|
||||||
|
|
||||||
_renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer);
|
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
|
||||||
|
|
||||||
var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
|
|
||||||
|
|
||||||
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
|
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
|
||||||
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
|
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
|
||||||
@ -79,7 +78,6 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
|||||||
_pipeline.SetImage(0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
_pipeline.SetImage(0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
|
|
||||||
_renderer.BufferManager.Delete(bufferHandle);
|
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
|
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
@ -215,11 +215,10 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
|||||||
|
|
||||||
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
|
ReadOnlySpan<float> resolutionBuffer = stackalloc float[] { view.Width, view.Height };
|
||||||
int rangeSize = resolutionBuffer.Length * sizeof(float);
|
int rangeSize = resolutionBuffer.Length * sizeof(float);
|
||||||
var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize);
|
using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
|
||||||
|
|
||||||
_renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer);
|
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
|
||||||
var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize);
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) });
|
|
||||||
_pipeline.SetImage(0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
_pipeline.SetImage(0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format));
|
||||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||||
_pipeline.ComputeBarrier();
|
_pipeline.ComputeBarrier();
|
||||||
@ -245,8 +244,6 @@ namespace Ryujinx.Graphics.Vulkan.Effects
|
|||||||
|
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
||||||
_renderer.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
return _outputTexture;
|
return _outputTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,11 +430,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
(region[2], region[3]) = (region[3], region[2]);
|
(region[2], region[3]) = (region[3], region[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, RegionBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData<float>(bufferHandle, 0, region);
|
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, region);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) });
|
||||||
|
|
||||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
@ -490,8 +490,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BlitDepthStencil(
|
private void BlitDepthStencil(
|
||||||
@ -527,11 +525,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
(region[2], region[3]) = (region[3], region[2]);
|
(region[2], region[3]) = (region[3], region[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, RegionBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData<float>(bufferHandle, 0, region);
|
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, region);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) });
|
||||||
|
|
||||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
@ -582,8 +580,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TextureView CreateDepthOrStencilView(TextureView depthStencilTexture, DepthStencilMode depthStencilMode)
|
private static TextureView CreateDepthOrStencilView(TextureView depthStencilTexture, DepthStencilMode depthStencilMode)
|
||||||
@ -681,11 +677,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ClearColorBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData(bufferHandle, 0, clearColor);
|
buffer.Holder.SetDataUnchecked(buffer.Offset, clearColor);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) });
|
||||||
|
|
||||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
@ -721,8 +717,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear(
|
public void Clear(
|
||||||
@ -745,11 +739,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ClearColorBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData<float>(bufferHandle, 0, stackalloc float[] { depthValue });
|
buffer.Holder.SetDataUnchecked<float>(buffer.Offset, stackalloc float[] { depthValue });
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) });
|
||||||
|
|
||||||
Span<Viewport> viewports = stackalloc Viewport[1];
|
Span<Viewport> viewports = stackalloc Viewport[1];
|
||||||
|
|
||||||
@ -771,8 +765,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask));
|
_pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask));
|
||||||
_pipeline.Draw(4, 1, 0, 0);
|
_pipeline.Draw(4, 1, 0, 0);
|
||||||
_pipeline.Finish();
|
_pipeline.Finish();
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawTexture(
|
public void DrawTexture(
|
||||||
@ -878,13 +870,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
shaderParams[2] = size;
|
shaderParams[2] = size;
|
||||||
shaderParams[3] = srcOffset;
|
shaderParams[3] = srcOffset;
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||||
|
|
||||||
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||||
|
|
||||||
@ -896,8 +888,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_pipeline.SetProgram(_programStrideChange);
|
_pipeline.SetProgram(_programStrideChange);
|
||||||
_pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
|
_pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1025,7 +1015,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
const int ParamsBufferSize = 4;
|
const int ParamsBufferSize = 4;
|
||||||
|
|
||||||
Span<int> shaderParams = stackalloc int[sizeof(int)];
|
Span<int> shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)];
|
||||||
|
|
||||||
int srcBpp = src.Info.BytesPerPixel;
|
int srcBpp = src.Info.BytesPerPixel;
|
||||||
int dstBpp = dst.Info.BytesPerPixel;
|
int dstBpp = dst.Info.BytesPerPixel;
|
||||||
@ -1034,9 +1024,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
shaderParams[0] = BitOperations.Log2((uint)ratio);
|
shaderParams[0] = BitOperations.Log2((uint)ratio);
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
gd.Api,
|
gd.Api,
|
||||||
@ -1064,7 +1054,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var srcFormat = GetFormat(componentSize, srcBpp / componentSize);
|
var srcFormat = GetFormat(componentSize, srcBpp / componentSize);
|
||||||
var dstFormat = GetFormat(componentSize, dstBpp / componentSize);
|
var dstFormat = GetFormat(componentSize, dstBpp / componentSize);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||||
|
|
||||||
for (int l = 0; l < levels; l++)
|
for (int l = 0; l < levels; l++)
|
||||||
{
|
{
|
||||||
@ -1093,8 +1083,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
@ -1128,9 +1116,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
||||||
(shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples));
|
(shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples));
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
gd.Api,
|
gd.Api,
|
||||||
@ -1147,7 +1135,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
1);
|
1);
|
||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||||
|
|
||||||
if (isDepthOrStencil)
|
if (isDepthOrStencil)
|
||||||
{
|
{
|
||||||
@ -1226,8 +1214,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
@ -1261,9 +1247,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
(shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples);
|
||||||
(shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples));
|
(shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples));
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
gd.Api,
|
gd.Api,
|
||||||
@ -1299,7 +1285,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_pipeline.SetViewports(viewports);
|
_pipeline.SetViewports(viewports);
|
||||||
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
_pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||||
|
|
||||||
if (isDepthOrStencil)
|
if (isDepthOrStencil)
|
||||||
{
|
{
|
||||||
@ -1364,8 +1350,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
TextureView.InsertImageBarrier(
|
TextureView.InsertImageBarrier(
|
||||||
@ -1616,10 +1600,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
|
pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]);
|
||||||
|
|
||||||
var patternBufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, out var patternBuffer);
|
using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||||
|
var patternBuffer = patternScoped.Holder;
|
||||||
var patternBufferAuto = patternBuffer.GetBuffer();
|
var patternBufferAuto = patternBuffer.GetBuffer();
|
||||||
|
|
||||||
gd.BufferManager.SetData<int>(patternBufferHandle, 0, shaderParams);
|
patternBuffer.SetDataUnchecked<int>(patternScoped.Offset, shaderParams);
|
||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
|
|
||||||
@ -1635,7 +1620,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
indirectDataSize);
|
indirectDataSize);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, drawCountBufferAligned) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, drawCountBufferAligned) });
|
||||||
_pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer(), patternBuffer.GetBuffer() });
|
_pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer() });
|
||||||
|
_pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(3, patternScoped.Range) });
|
||||||
|
|
||||||
_pipeline.SetProgram(_programConvertIndirectData);
|
_pipeline.SetProgram(_programConvertIndirectData);
|
||||||
_pipeline.DispatchCompute(1, 1, 1);
|
_pipeline.DispatchCompute(1, 1, 1);
|
||||||
@ -1643,12 +1629,12 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
gd,
|
gd,
|
||||||
cbs.CommandBuffer,
|
cbs.CommandBuffer,
|
||||||
patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
|
patternBufferAuto.Get(cbs, patternScoped.Offset + ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value,
|
||||||
AccessFlags.ShaderWriteBit,
|
AccessFlags.ShaderWriteBit,
|
||||||
AccessFlags.IndirectCommandReadBit,
|
AccessFlags.IndirectCommandReadBit,
|
||||||
PipelineStageFlags.ComputeShaderBit,
|
PipelineStageFlags.ComputeShaderBit,
|
||||||
PipelineStageFlags.DrawIndirectBit,
|
PipelineStageFlags.DrawIndirectBit,
|
||||||
ParamsIndirectDispatchOffset,
|
patternScoped.Offset + ParamsIndirectDispatchOffset,
|
||||||
ParamsIndirectDispatchSize);
|
ParamsIndirectDispatchSize);
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
@ -1662,11 +1648,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
0,
|
0,
|
||||||
convertedCount * outputIndexSize);
|
convertedCount * outputIndexSize);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternBufferHandle, 0, ParamsBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternScoped.Handle, patternScoped.Offset, ParamsBufferSize)) });
|
||||||
_pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
|
_pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
|
||||||
|
|
||||||
_pipeline.SetProgram(_programConvertIndexBuffer);
|
_pipeline.SetProgram(_programConvertIndexBuffer);
|
||||||
_pipeline.DispatchComputeIndirect(patternBufferAuto, ParamsIndirectDispatchOffset);
|
_pipeline.DispatchComputeIndirect(patternBufferAuto, patternScoped.Offset + ParamsIndirectDispatchOffset);
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
gd,
|
gd,
|
||||||
@ -1679,8 +1665,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
0,
|
0,
|
||||||
convertedCount * outputIndexSize);
|
convertedCount * outputIndexSize);
|
||||||
|
|
||||||
gd.BufferManager.Delete(patternBufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1726,13 +1710,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
shaderParams[0] = pixelCount;
|
shaderParams[0] = pixelCount;
|
||||||
shaderParams[1] = dstOffset;
|
shaderParams[1] = dstOffset;
|
||||||
|
|
||||||
var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize);
|
using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize);
|
||||||
|
|
||||||
gd.BufferManager.SetData<int>(bufferHandle, 0, shaderParams);
|
buffer.Holder.SetDataUnchecked<int>(buffer.Offset, shaderParams);
|
||||||
|
|
||||||
_pipeline.SetCommandBuffer(cbs);
|
_pipeline.SetCommandBuffer(cbs);
|
||||||
|
|
||||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) });
|
||||||
|
|
||||||
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||||
|
|
||||||
@ -1744,8 +1728,6 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_pipeline.SetProgram(_programConvertD32S8ToD24S8);
|
_pipeline.SetProgram(_programConvertD32S8ToD24S8);
|
||||||
_pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1);
|
_pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1);
|
||||||
|
|
||||||
gd.BufferManager.Delete(bufferHandle);
|
|
||||||
|
|
||||||
_pipeline.Finish(gd, cbs);
|
_pipeline.Finish(gd, cbs);
|
||||||
|
|
||||||
BufferHolder.InsertBufferBarrier(
|
BufferHolder.InsertBufferBarrier(
|
||||||
|
@ -67,9 +67,18 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
|||||||
lock (_queryPool)
|
lock (_queryPool)
|
||||||
{
|
{
|
||||||
count = Math.Min(count, _queryPool.Count);
|
count = Math.Min(count, _queryPool.Count);
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
|
if (count > 0)
|
||||||
{
|
{
|
||||||
_queryPool.ElementAt(i).PoolReset(cmd, ResetSequence);
|
foreach (BufferedQuery query in _queryPool)
|
||||||
|
{
|
||||||
|
query.PoolReset(cmd, ResetSequence);
|
||||||
|
|
||||||
|
if (--count == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -29,6 +30,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private readonly VulkanRenderer _gd;
|
private readonly VulkanRenderer _gd;
|
||||||
private readonly BufferHolder _buffer;
|
private readonly BufferHolder _buffer;
|
||||||
|
private readonly int _resourceAlignment;
|
||||||
|
|
||||||
|
public readonly BufferHandle Handle;
|
||||||
|
|
||||||
private readonly struct PendingCopy
|
private readonly struct PendingCopy
|
||||||
{
|
{
|
||||||
@ -48,9 +52,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public StagingBuffer(VulkanRenderer gd, BufferManager bufferManager)
|
public StagingBuffer(VulkanRenderer gd, BufferManager bufferManager)
|
||||||
{
|
{
|
||||||
_gd = gd;
|
_gd = gd;
|
||||||
_buffer = bufferManager.Create(gd, BufferSize);
|
Handle = bufferManager.CreateWithHandle(gd, BufferSize, out _buffer);
|
||||||
_pendingCopies = new Queue<PendingCopy>();
|
_pendingCopies = new Queue<PendingCopy>();
|
||||||
_freeSize = BufferSize;
|
_freeSize = BufferSize;
|
||||||
|
_resourceAlignment = (int)gd.Capabilities.MinResourceAlignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PushData(CommandBufferPool cbp, CommandBufferScoped? cbs, Action endRenderPass, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
|
public void PushData(CommandBufferPool cbp, CommandBufferScoped? cbs, Action endRenderPass, BufferHolder dst, int dstOffset, ReadOnlySpan<byte> data)
|
||||||
@ -197,7 +202,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
/// Reserve a range on the staging buffer for the current command buffer and upload data to it.
|
/// Reserve a range on the staging buffer for the current command buffer and upload data to it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cbs">Command buffer to reserve the data on</param>
|
/// <param name="cbs">Command buffer to reserve the data on</param>
|
||||||
/// <param name="data">The data to upload</param>
|
/// <param name="size">The minimum size the reserved data requires</param>
|
||||||
/// <param name="alignment">The required alignment for the buffer offset</param>
|
/// <param name="alignment">The required alignment for the buffer offset</param>
|
||||||
/// <returns>The reserved range of the staging buffer</returns>
|
/// <returns>The reserved range of the staging buffer</returns>
|
||||||
public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size, int alignment)
|
public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size, int alignment)
|
||||||
@ -223,6 +228,18 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return ReserveDataImpl(cbs, size, alignment);
|
return ReserveDataImpl(cbs, size, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reserve a range on the staging buffer for the current command buffer and upload data to it.
|
||||||
|
/// Uses the most permissive byte alignment.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cbs">Command buffer to reserve the data on</param>
|
||||||
|
/// <param name="size">The minimum size the reserved data requires</param>
|
||||||
|
/// <returns>The reserved range of the staging buffer</returns>
|
||||||
|
public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size)
|
||||||
|
{
|
||||||
|
return TryReserveData(cbs, size, _resourceAlignment);
|
||||||
|
}
|
||||||
|
|
||||||
private bool WaitFreeCompleted(CommandBufferPool cbp)
|
private bool WaitFreeCompleted(CommandBufferPool cbp)
|
||||||
{
|
{
|
||||||
if (_pendingCopies.TryPeek(out var pc))
|
if (_pendingCopies.TryPeek(out var pc))
|
||||||
@ -263,7 +280,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
_buffer.Dispose();
|
_gd.BufferManager.Delete(Handle);
|
||||||
|
|
||||||
while (_pendingCopies.TryDequeue(out var pc))
|
while (_pendingCopies.TryDequeue(out var pc))
|
||||||
{
|
{
|
||||||
|
@ -186,7 +186,12 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient)
|
public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient)
|
||||||
{
|
{
|
||||||
LocalFileSystem serverBaseFs = new(AppDataManager.BaseDirPath);
|
LocalFileSystem serverBaseFs = new(useUnixTimeStamps: true);
|
||||||
|
Result result = serverBaseFs.Initialize(AppDataManager.BaseDirPath, LocalFileSystem.PathMode.DefaultCaseSensitivity, ensurePathExists: true);
|
||||||
|
if (result.IsFailure())
|
||||||
|
{
|
||||||
|
throw new HorizonResultException(result, "Error creating LocalFileSystem.");
|
||||||
|
}
|
||||||
|
|
||||||
fsServerClient = horizon.CreatePrivilegedHorizonClient();
|
fsServerClient = horizon.CreatePrivilegedHorizonClient();
|
||||||
var fsServer = new FileSystemServer(fsServerClient);
|
var fsServer = new FileSystemServer(fsServerClient);
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Services.Arp
|
|
||||||
{
|
|
||||||
[Service("arp:r")]
|
|
||||||
class IReader : IpcService
|
|
||||||
{
|
|
||||||
public IReader(ServiceCtx context) { }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
namespace Ryujinx.HLE.HOS.Services.Arp
|
|
||||||
{
|
|
||||||
[Service("arp:w")]
|
|
||||||
class IWriter : IpcService
|
|
||||||
{
|
|
||||||
public IWriter(ServiceCtx context) { }
|
|
||||||
}
|
|
||||||
}
|
|
@ -159,9 +159,7 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#pragma warning disable CS0162 // Unreachable code
|
|
||||||
return ResultCode.StereoVisionRestrictionConfigurableDisabled;
|
return ResultCode.StereoVisionRestrictionConfigurableDisabled;
|
||||||
#pragma warning restore CS0162
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl;
|
|||||||
using Ryujinx.HLE.HOS.Services.Ssl.Types;
|
using Ryujinx.HLE.HOS.Services.Ssl.Types;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Security.Authentication;
|
using System.Security.Authentication;
|
||||||
@ -83,10 +84,40 @@ namespace Ryujinx.HLE.HOS.Services.Ssl.SslService
|
|||||||
}
|
}
|
||||||
#pragma warning restore SYSLIB0039
|
#pragma warning restore SYSLIB0039
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve the hostname of the current remote in case the provided hostname is null or empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hostName">The current hostname</param>
|
||||||
|
/// <returns>Either the resolved or provided hostname</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This is done to avoid getting an <see cref="System.Security.Authentication.AuthenticationException"/>
|
||||||
|
/// as the remote certificate will be rejected with <c>RemoteCertificateNameMismatch</c> due to an empty hostname.
|
||||||
|
/// This is not what the switch does!
|
||||||
|
/// It might just skip remote hostname verification if the hostname wasn't set with <see cref="ISslConnection.SetHostName"/> before.
|
||||||
|
/// TODO: Remove this as soon as we know how the switch deals with empty hostnames
|
||||||
|
/// </remarks>
|
||||||
|
private string RetrieveHostName(string hostName)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(hostName))
|
||||||
|
{
|
||||||
|
return hostName;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Dns.GetHostEntry(Socket.RemoteEndPoint.Address).HostName;
|
||||||
|
}
|
||||||
|
catch (SocketException)
|
||||||
|
{
|
||||||
|
return hostName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public ResultCode Handshake(string hostName)
|
public ResultCode Handshake(string hostName)
|
||||||
{
|
{
|
||||||
StartSslOperation();
|
StartSslOperation();
|
||||||
_stream = new SslStream(new NetworkStream(((ManagedSocket)Socket).Socket, false), false, null, null);
|
_stream = new SslStream(new NetworkStream(((ManagedSocket)Socket).Socket, false), false, null, null);
|
||||||
|
hostName = RetrieveHostName(hostName);
|
||||||
_stream.AuthenticateAsClient(hostName, null, TranslateSslVersion(_sslVersion), false);
|
_stream.AuthenticateAsClient(hostName, null, TranslateSslVersion(_sslVersion), false);
|
||||||
EndSslOperation();
|
EndSslOperation();
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
return metaLoader;
|
return metaLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ProcessResult Load(this IFileSystem exeFs, Switch device, BlitStruct<ApplicationControlProperty> nacpData, MetaLoader metaLoader, bool isHomebrew = false)
|
public static ProcessResult Load(this IFileSystem exeFs, Switch device, BlitStruct<ApplicationControlProperty> nacpData, MetaLoader metaLoader, byte programIndex, bool isHomebrew = false)
|
||||||
{
|
{
|
||||||
ulong programId = metaLoader.GetProgramId();
|
ulong programId = metaLoader.GetProgramId();
|
||||||
|
|
||||||
@ -119,6 +119,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
true,
|
true,
|
||||||
programName,
|
programName,
|
||||||
metaLoader.GetProgramId(),
|
metaLoader.GetProgramId(),
|
||||||
|
programIndex,
|
||||||
null,
|
null,
|
||||||
nsoExecutables);
|
nsoExecutables);
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
ProcessLoaderHelper.EnsureSaveData(device, new ApplicationId(programId), nacpData);
|
ProcessLoaderHelper.EnsureSaveData(device, new ApplicationId(programId), nacpData);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader);
|
ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader, 0);
|
||||||
|
|
||||||
// Load RomFS.
|
// Load RomFS.
|
||||||
if (!string.IsNullOrEmpty(romFsPath))
|
if (!string.IsNullOrEmpty(romFsPath))
|
||||||
|
@ -61,7 +61,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader);
|
ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader, (byte)nca.GetProgramIndex());
|
||||||
|
|
||||||
// Load RomFS.
|
// Load RomFS.
|
||||||
if (romFs == null)
|
if (romFs == null)
|
||||||
|
@ -77,7 +77,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
if (processResult.ProcessId == 0)
|
if (processResult.ProcessId == 0)
|
||||||
{
|
{
|
||||||
// This is not a normal NSP, it's actually a ExeFS as a NSP
|
// This is not a normal NSP, it's actually a ExeFS as a NSP
|
||||||
processResult = partitionFileSystem.Load(_device, new BlitStruct<ApplicationControlProperty>(1), partitionFileSystem.GetNpdm(), true);
|
processResult = partitionFileSystem.Load(_device, new BlitStruct<ApplicationControlProperty>(1), partitionFileSystem.GetNpdm(), 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
||||||
@ -198,7 +198,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
programName = System.IO.Path.GetFileNameWithoutExtension(path);
|
programName = Path.GetFileNameWithoutExtension(path);
|
||||||
|
|
||||||
executable = new NsoExecutable(new LocalStorage(path, FileAccess.Read), programName);
|
executable = new NsoExecutable(new LocalStorage(path, FileAccess.Read), programName);
|
||||||
}
|
}
|
||||||
@ -215,6 +215,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
allowCodeMemoryForJit: true,
|
allowCodeMemoryForJit: true,
|
||||||
programName,
|
programName,
|
||||||
programId,
|
programId,
|
||||||
|
0,
|
||||||
null,
|
null,
|
||||||
executable);
|
executable);
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ using Ryujinx.HLE.HOS.Kernel.Process;
|
|||||||
using Ryujinx.HLE.Loaders.Executables;
|
using Ryujinx.HLE.Loaders.Executables;
|
||||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@ -229,6 +230,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
bool allowCodeMemoryForJit,
|
bool allowCodeMemoryForJit,
|
||||||
string name,
|
string name,
|
||||||
ulong programId,
|
ulong programId,
|
||||||
|
byte programIndex,
|
||||||
byte[] arguments = null,
|
byte[] arguments = null,
|
||||||
params IExecutable[] executables)
|
params IExecutable[] executables)
|
||||||
{
|
{
|
||||||
@ -421,7 +423,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
// Once everything is loaded, we can load cheats.
|
// Once everything is loaded, we can load cheats.
|
||||||
device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(programId, tamperInfo, device.TamperMachine);
|
device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(programId, tamperInfo, device.TamperMachine);
|
||||||
|
|
||||||
return new ProcessResult(
|
ProcessResult processResult = new(
|
||||||
metaLoader,
|
metaLoader,
|
||||||
applicationControlProperties,
|
applicationControlProperties,
|
||||||
diskCacheEnabled,
|
diskCacheEnabled,
|
||||||
@ -431,6 +433,25 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
meta.MainThreadPriority,
|
meta.MainThreadPriority,
|
||||||
meta.MainThreadStackSize,
|
meta.MainThreadStackSize,
|
||||||
device.System.State.DesiredTitleLanguage);
|
device.System.State.DesiredTitleLanguage);
|
||||||
|
|
||||||
|
// Register everything in arp service.
|
||||||
|
device.System.ServiceTable.ArpWriter.AcquireRegistrar(out IRegistrar registrar);
|
||||||
|
registrar.SetApplicationControlProperty(MemoryMarshal.Cast<byte, Horizon.Sdk.Ns.ApplicationControlProperty>(applicationControlProperties.ByteSpan)[0]);
|
||||||
|
// TODO: Handle Version and StorageId when it will be needed.
|
||||||
|
registrar.SetApplicationLaunchProperty(new ApplicationLaunchProperty()
|
||||||
|
{
|
||||||
|
ApplicationId = new Horizon.Sdk.Ncm.ApplicationId(programId),
|
||||||
|
Version = 0x00,
|
||||||
|
Storage = Horizon.Sdk.Ncm.StorageId.BuiltInUser,
|
||||||
|
PatchStorage = Horizon.Sdk.Ncm.StorageId.None,
|
||||||
|
ApplicationKind = ApplicationKind.Application,
|
||||||
|
});
|
||||||
|
|
||||||
|
device.System.ServiceTable.ArpReader.GetApplicationInstanceId(out ulong applicationInstanceId, process.Pid);
|
||||||
|
device.System.ServiceTable.ArpWriter.AcquireApplicationProcessPropertyUpdater(out IUpdater updater, applicationInstanceId);
|
||||||
|
updater.SetApplicationProcessProperty(process.Pid, new ApplicationProcessProperty() { ProgramIndex = programIndex });
|
||||||
|
|
||||||
|
return processResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
|
public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress)
|
||||||
|
61
src/Ryujinx.Horizon/Arp/ArpIpcServer.cs
Normal file
61
src/Ryujinx.Horizon/Arp/ArpIpcServer.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
using Ryujinx.Horizon.Arp.Ipc;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp.Detail;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sm;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Arp
|
||||||
|
{
|
||||||
|
class ArpIpcServer
|
||||||
|
{
|
||||||
|
private const int ArpRMaxSessionsCount = 16;
|
||||||
|
private const int ArpWMaxSessionsCount = 8;
|
||||||
|
private const int MaxSessionsCount = ArpRMaxSessionsCount + ArpWMaxSessionsCount;
|
||||||
|
|
||||||
|
private const int PointerBufferSize = 0x1000;
|
||||||
|
private const int MaxDomains = 24;
|
||||||
|
private const int MaxDomainObjects = 32;
|
||||||
|
private const int MaxPortsCount = 2;
|
||||||
|
|
||||||
|
private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
|
||||||
|
|
||||||
|
private SmApi _sm;
|
||||||
|
private ServerManager _serverManager;
|
||||||
|
private ApplicationInstanceManager _applicationInstanceManager;
|
||||||
|
|
||||||
|
public IReader Reader { get; private set; }
|
||||||
|
public IWriter Writer { get; private set; }
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
HeapAllocator allocator = new();
|
||||||
|
|
||||||
|
_sm = new SmApi();
|
||||||
|
_sm.Initialize().AbortOnFailure();
|
||||||
|
|
||||||
|
_serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount);
|
||||||
|
|
||||||
|
_applicationInstanceManager = new ApplicationInstanceManager();
|
||||||
|
|
||||||
|
Reader reader = new(_applicationInstanceManager);
|
||||||
|
Reader = reader;
|
||||||
|
|
||||||
|
Writer writer = new(_applicationInstanceManager);
|
||||||
|
Writer = writer;
|
||||||
|
|
||||||
|
_serverManager.RegisterObjectForServer(reader, ServiceName.Encode("arp:r"), ArpRMaxSessionsCount);
|
||||||
|
_serverManager.RegisterObjectForServer(writer, ServiceName.Encode("arp:w"), ArpWMaxSessionsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ServiceRequests()
|
||||||
|
{
|
||||||
|
_serverManager.ServiceRequests();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Shutdown()
|
||||||
|
{
|
||||||
|
_applicationInstanceManager.Dispose();
|
||||||
|
_serverManager.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/Ryujinx.Horizon/Arp/ArpMain.cs
Normal file
20
src/Ryujinx.Horizon/Arp/ArpMain.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace Ryujinx.Horizon.Arp
|
||||||
|
{
|
||||||
|
class ArpMain : IService
|
||||||
|
{
|
||||||
|
public static void Main(ServiceTable serviceTable)
|
||||||
|
{
|
||||||
|
ArpIpcServer arpIpcServer = new();
|
||||||
|
|
||||||
|
arpIpcServer.Initialize();
|
||||||
|
|
||||||
|
serviceTable.ArpReader = arpIpcServer.Reader;
|
||||||
|
serviceTable.ArpWriter = arpIpcServer.Writer;
|
||||||
|
|
||||||
|
serviceTable.SignalServiceReady();
|
||||||
|
|
||||||
|
arpIpcServer.ServiceRequests();
|
||||||
|
arpIpcServer.Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
135
src/Ryujinx.Horizon/Arp/Ipc/Reader.cs
Normal file
135
src/Ryujinx.Horizon/Arp/Ipc/Reader.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp.Detail;
|
||||||
|
using Ryujinx.Horizon.Sdk.Ns;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Arp.Ipc
|
||||||
|
{
|
||||||
|
partial class Reader : IReader, IServiceObject
|
||||||
|
{
|
||||||
|
private readonly ApplicationInstanceManager _applicationInstanceManager;
|
||||||
|
|
||||||
|
public Reader(ApplicationInstanceManager applicationInstanceManager)
|
||||||
|
{
|
||||||
|
_applicationInstanceManager = applicationInstanceManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(0)]
|
||||||
|
public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].LaunchProperty.HasValue)
|
||||||
|
{
|
||||||
|
applicationLaunchProperty = default;
|
||||||
|
|
||||||
|
return ArpResult.InvalidInstanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationLaunchProperty = _applicationInstanceManager.Entries[applicationInstanceId].LaunchProperty.Value;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(1)]
|
||||||
|
public Result GetApplicationControlProperty([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias, 0x4000)] out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].ControlProperty.HasValue)
|
||||||
|
{
|
||||||
|
applicationControlProperty = default;
|
||||||
|
|
||||||
|
return ArpResult.InvalidInstanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationControlProperty = _applicationInstanceManager.Entries[applicationInstanceId].ControlProperty.Value;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(2)]
|
||||||
|
public Result GetApplicationProcessProperty(out ApplicationProcessProperty applicationProcessProperty, ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].ProcessProperty.HasValue)
|
||||||
|
{
|
||||||
|
applicationProcessProperty = default;
|
||||||
|
|
||||||
|
return ArpResult.InvalidInstanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationProcessProperty = _applicationInstanceManager.Entries[applicationInstanceId].ProcessProperty.Value;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(3)]
|
||||||
|
public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong pid)
|
||||||
|
{
|
||||||
|
applicationInstanceId = 0;
|
||||||
|
|
||||||
|
if (pid == 0)
|
||||||
|
{
|
||||||
|
return ArpResult.InvalidPid;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _applicationInstanceManager.Entries.Length; i++)
|
||||||
|
{
|
||||||
|
if (_applicationInstanceManager.Entries[i] != null && _applicationInstanceManager.Entries[i].Pid == pid)
|
||||||
|
{
|
||||||
|
applicationInstanceId = (ulong)i;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ArpResult.InvalidPid;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(4)]
|
||||||
|
public Result GetApplicationInstanceUnregistrationNotifier(out IUnregistrationNotifier unregistrationNotifier)
|
||||||
|
{
|
||||||
|
unregistrationNotifier = new UnregistrationNotifier(_applicationInstanceManager);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(5)]
|
||||||
|
public Result ListApplicationInstanceId(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span<ulong> applicationInstanceIdList)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
if (_applicationInstanceManager.Entries[0] != null)
|
||||||
|
{
|
||||||
|
applicationInstanceIdList[count++] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_applicationInstanceManager.Entries[1] != null)
|
||||||
|
{
|
||||||
|
applicationInstanceIdList[count++] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(6)]
|
||||||
|
public Result GetMicroApplicationInstanceId(out ulong microApplicationInstanceId, [ClientProcessId] ulong pid)
|
||||||
|
{
|
||||||
|
return GetApplicationInstanceId(out microApplicationInstanceId, pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(7)]
|
||||||
|
public Result GetApplicationCertificate([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize, 0x528)] out ApplicationCertificate applicationCertificate, ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
if (_applicationInstanceManager.Entries[applicationInstanceId] == null)
|
||||||
|
{
|
||||||
|
applicationCertificate = default;
|
||||||
|
|
||||||
|
return ArpResult.InvalidInstanceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationCertificate = _applicationInstanceManager.Entries[applicationInstanceId].Certificate.Value;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs
Normal file
52
src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp.Detail;
|
||||||
|
using Ryujinx.Horizon.Sdk.Ns;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Arp.Ipc
|
||||||
|
{
|
||||||
|
partial class Registrar : IRegistrar, IServiceObject
|
||||||
|
{
|
||||||
|
private readonly ApplicationInstance _applicationInstance;
|
||||||
|
|
||||||
|
public Registrar(ApplicationInstance applicationInstance)
|
||||||
|
{
|
||||||
|
_applicationInstance = applicationInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(0)]
|
||||||
|
public Result Issue(out ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(1)]
|
||||||
|
public Result SetApplicationLaunchProperty(ApplicationLaunchProperty applicationLaunchProperty)
|
||||||
|
{
|
||||||
|
if (_applicationInstance.LaunchProperty != null)
|
||||||
|
{
|
||||||
|
return ArpResult.DataAlreadyBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
_applicationInstance.LaunchProperty = applicationLaunchProperty;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(2)]
|
||||||
|
public Result SetApplicationControlProperty([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize, 0x4000)] in ApplicationControlProperty applicationControlProperty)
|
||||||
|
{
|
||||||
|
if (_applicationInstance.ControlProperty != null)
|
||||||
|
{
|
||||||
|
return ArpResult.DataAlreadyBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
_applicationInstance.ControlProperty = applicationControlProperty;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs
Normal file
25
src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp.Detail;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Arp.Ipc
|
||||||
|
{
|
||||||
|
partial class UnregistrationNotifier : IUnregistrationNotifier, IServiceObject
|
||||||
|
{
|
||||||
|
private readonly ApplicationInstanceManager _applicationInstanceManager;
|
||||||
|
|
||||||
|
public UnregistrationNotifier(ApplicationInstanceManager applicationInstanceManager)
|
||||||
|
{
|
||||||
|
_applicationInstanceManager = applicationInstanceManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(0)]
|
||||||
|
public Result GetReadableHandle([CopyHandle] out int readableHandle)
|
||||||
|
{
|
||||||
|
readableHandle = _applicationInstanceManager.EventHandle;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
src/Ryujinx.Horizon/Arp/Ipc/Updater.cs
Normal file
74
src/Ryujinx.Horizon/Arp/Ipc/Updater.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp.Detail;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Arp.Ipc
|
||||||
|
{
|
||||||
|
partial class Updater : IUpdater, IServiceObject
|
||||||
|
{
|
||||||
|
private readonly ApplicationInstanceManager _applicationInstanceManager;
|
||||||
|
private readonly ulong _applicationInstanceId;
|
||||||
|
private readonly bool _forCertificate;
|
||||||
|
|
||||||
|
public Updater(ApplicationInstanceManager applicationInstanceManager, ulong applicationInstanceId, bool forCertificate)
|
||||||
|
{
|
||||||
|
_applicationInstanceManager = applicationInstanceManager;
|
||||||
|
_applicationInstanceId = applicationInstanceId;
|
||||||
|
_forCertificate = forCertificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(0)]
|
||||||
|
public Result Issue()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(1)]
|
||||||
|
public Result SetApplicationProcessProperty(ulong pid, ApplicationProcessProperty applicationProcessProperty)
|
||||||
|
{
|
||||||
|
if (_forCertificate)
|
||||||
|
{
|
||||||
|
return ArpResult.DataAlreadyBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid == 0)
|
||||||
|
{
|
||||||
|
return ArpResult.InvalidPid;
|
||||||
|
}
|
||||||
|
|
||||||
|
_applicationInstanceManager.Entries[_applicationInstanceId].Pid = pid;
|
||||||
|
_applicationInstanceManager.Entries[_applicationInstanceId].ProcessProperty = applicationProcessProperty;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(2)]
|
||||||
|
public Result DeleteApplicationProcessProperty()
|
||||||
|
{
|
||||||
|
if (_forCertificate)
|
||||||
|
{
|
||||||
|
return ArpResult.DataAlreadyBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
_applicationInstanceManager.Entries[_applicationInstanceId].ProcessProperty = new ApplicationProcessProperty();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(3)]
|
||||||
|
public Result SetApplicationCertificate([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ApplicationCertificate applicationCertificate)
|
||||||
|
{
|
||||||
|
if (!_forCertificate)
|
||||||
|
{
|
||||||
|
return ArpResult.DataAlreadyBound;
|
||||||
|
}
|
||||||
|
|
||||||
|
_applicationInstanceManager.Entries[_applicationInstanceId].Certificate = applicationCertificate;
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
src/Ryujinx.Horizon/Arp/Ipc/Writer.cs
Normal file
75
src/Ryujinx.Horizon/Arp/Ipc/Writer.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp.Detail;
|
||||||
|
using Ryujinx.Horizon.Sdk.OsTypes;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Arp.Ipc
|
||||||
|
{
|
||||||
|
partial class Writer : IWriter, IServiceObject
|
||||||
|
{
|
||||||
|
private readonly ApplicationInstanceManager _applicationInstanceManager;
|
||||||
|
|
||||||
|
public Writer(ApplicationInstanceManager applicationInstanceManager)
|
||||||
|
{
|
||||||
|
_applicationInstanceManager = applicationInstanceManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(0)]
|
||||||
|
public Result AcquireRegistrar(out IRegistrar registrar)
|
||||||
|
{
|
||||||
|
if (_applicationInstanceManager.Entries[0] != null)
|
||||||
|
{
|
||||||
|
if (_applicationInstanceManager.Entries[1] != null)
|
||||||
|
{
|
||||||
|
registrar = null;
|
||||||
|
|
||||||
|
return ArpResult.NoFreeInstance;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_applicationInstanceManager.Entries[1] = new ApplicationInstance();
|
||||||
|
|
||||||
|
registrar = new Registrar(_applicationInstanceManager.Entries[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_applicationInstanceManager.Entries[0] = new ApplicationInstance();
|
||||||
|
|
||||||
|
registrar = new Registrar(_applicationInstanceManager.Entries[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(1)]
|
||||||
|
public Result UnregisterApplicationInstance(ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
if (_applicationInstanceManager.Entries[applicationInstanceId] != null)
|
||||||
|
{
|
||||||
|
_applicationInstanceManager.Entries[applicationInstanceId] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Os.SignalSystemEvent(ref _applicationInstanceManager.SystemEvent);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(2)]
|
||||||
|
public Result AcquireApplicationProcessPropertyUpdater(out IUpdater updater, ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
updater = new Updater(_applicationInstanceManager, applicationInstanceId, false);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CmifCommand(3)]
|
||||||
|
public Result AcquireApplicationCertificateUpdater(out IUpdater updater, ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
updater = new Updater(_applicationInstanceManager, applicationInstanceId, true);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ using Ryujinx.Common.Utilities;
|
|||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
using Ryujinx.Horizon.Prepo.Types;
|
using Ryujinx.Horizon.Prepo.Types;
|
||||||
using Ryujinx.Horizon.Sdk.Account;
|
using Ryujinx.Horizon.Sdk.Account;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
using Ryujinx.Horizon.Sdk.Prepo;
|
using Ryujinx.Horizon.Sdk.Prepo;
|
||||||
using Ryujinx.Horizon.Sdk.Sf;
|
using Ryujinx.Horizon.Sdk.Sf;
|
||||||
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
@ -22,14 +23,16 @@ namespace Ryujinx.Horizon.Prepo.Ipc
|
|||||||
System,
|
System,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly ArpApi _arp;
|
||||||
private readonly PrepoServicePermissionLevel _permissionLevel;
|
private readonly PrepoServicePermissionLevel _permissionLevel;
|
||||||
private ulong _systemSessionId;
|
private ulong _systemSessionId;
|
||||||
|
|
||||||
private bool _immediateTransmissionEnabled;
|
private bool _immediateTransmissionEnabled;
|
||||||
private bool _userAgreementCheckEnabled = true;
|
private bool _userAgreementCheckEnabled = true;
|
||||||
|
|
||||||
public PrepoService(PrepoServicePermissionLevel permissionLevel)
|
public PrepoService(ArpApi arp, PrepoServicePermissionLevel permissionLevel)
|
||||||
{
|
{
|
||||||
|
_arp = arp;
|
||||||
_permissionLevel = permissionLevel;
|
_permissionLevel = permissionLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +168,7 @@ namespace Ryujinx.Horizon.Prepo.Ipc
|
|||||||
return PrepoResult.PermissionDenied;
|
return PrepoResult.PermissionDenied;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Result ProcessPlayReport(PlayReportKind playReportKind, ReadOnlySpan<byte> gameRoomBuffer, ReadOnlySpan<byte> reportBuffer, ulong pid, Uid userId, bool withUserId = false, ApplicationId applicationId = default)
|
private Result ProcessPlayReport(PlayReportKind playReportKind, ReadOnlySpan<byte> gameRoomBuffer, ReadOnlySpan<byte> reportBuffer, ulong pid, Uid userId, bool withUserId = false, ApplicationId applicationId = default)
|
||||||
{
|
{
|
||||||
if (withUserId)
|
if (withUserId)
|
||||||
{
|
{
|
||||||
@ -199,8 +202,8 @@ namespace Ryujinx.Horizon.Prepo.Ipc
|
|||||||
builder.AppendLine("PlayReport log:");
|
builder.AppendLine("PlayReport log:");
|
||||||
builder.AppendLine($" Kind: {playReportKind}");
|
builder.AppendLine($" Kind: {playReportKind}");
|
||||||
|
|
||||||
// NOTE: The service calls arp:r using the pid to get the application id, if it fails PrepoResult.InvalidPid is returned.
|
// NOTE: Reports are stored internally and an event is signaled to transmit them.
|
||||||
// Reports are stored internally and an event is signaled to transmit them.
|
|
||||||
if (pid != 0)
|
if (pid != 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine($" Pid: {pid}");
|
builder.AppendLine($" Pid: {pid}");
|
||||||
@ -210,6 +213,16 @@ namespace Ryujinx.Horizon.Prepo.Ipc
|
|||||||
builder.AppendLine($" ApplicationId: {applicationId}");
|
builder.AppendLine($" ApplicationId: {applicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result result = _arp.GetApplicationInstanceId(out ulong applicationInstanceId, pid);
|
||||||
|
if (result.IsFailure)
|
||||||
|
{
|
||||||
|
return PrepoResult.InvalidPid;
|
||||||
|
}
|
||||||
|
|
||||||
|
_arp.GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, applicationInstanceId).AbortOnFailure();
|
||||||
|
|
||||||
|
builder.AppendLine($" ApplicationVersion: {applicationLaunchProperty.Version}");
|
||||||
|
|
||||||
if (!userId.IsNull)
|
if (!userId.IsNull)
|
||||||
{
|
{
|
||||||
builder.AppendLine($" UserId: {userId}");
|
builder.AppendLine($" UserId: {userId}");
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Ryujinx.Horizon.Prepo.Types;
|
using Ryujinx.Horizon.Prepo.Types;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
using Ryujinx.Horizon.Sdk.Sm;
|
using Ryujinx.Horizon.Sdk.Sm;
|
||||||
|
|
||||||
@ -17,16 +18,19 @@ namespace Ryujinx.Horizon.Prepo
|
|||||||
private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
|
private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false);
|
||||||
|
|
||||||
private SmApi _sm;
|
private SmApi _sm;
|
||||||
|
private ArpApi _arp;
|
||||||
private PrepoServerManager _serverManager;
|
private PrepoServerManager _serverManager;
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
HeapAllocator allocator = new();
|
HeapAllocator allocator = new();
|
||||||
|
|
||||||
|
_arp = new ArpApi(allocator);
|
||||||
|
|
||||||
_sm = new SmApi();
|
_sm = new SmApi();
|
||||||
_sm.Initialize().AbortOnFailure();
|
_sm.Initialize().AbortOnFailure();
|
||||||
|
|
||||||
_serverManager = new PrepoServerManager(allocator, _sm, MaxPortsCount, _managerOptions, TotalMaxSessionsCount);
|
_serverManager = new PrepoServerManager(allocator, _sm, _arp, MaxPortsCount, _managerOptions, TotalMaxSessionsCount);
|
||||||
|
|
||||||
#pragma warning disable IDE0055 // Disable formatting
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
_serverManager.RegisterServer((int)PrepoPortIndex.Admin, ServiceName.Encode("prepo:a"), MaxSessionsCount); // 1.0.0-5.1.0
|
_serverManager.RegisterServer((int)PrepoPortIndex.Admin, ServiceName.Encode("prepo:a"), MaxSessionsCount); // 1.0.0-5.1.0
|
||||||
@ -45,6 +49,7 @@ namespace Ryujinx.Horizon.Prepo
|
|||||||
|
|
||||||
public void Shutdown()
|
public void Shutdown()
|
||||||
{
|
{
|
||||||
|
_arp.Dispose();
|
||||||
_serverManager.Dispose();
|
_serverManager.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Ryujinx.Horizon.Common;
|
using Ryujinx.Horizon.Common;
|
||||||
using Ryujinx.Horizon.Prepo.Ipc;
|
using Ryujinx.Horizon.Prepo.Ipc;
|
||||||
using Ryujinx.Horizon.Prepo.Types;
|
using Ryujinx.Horizon.Prepo.Types;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
using Ryujinx.Horizon.Sdk.Sm;
|
using Ryujinx.Horizon.Sdk.Sm;
|
||||||
using System;
|
using System;
|
||||||
@ -9,8 +10,11 @@ namespace Ryujinx.Horizon.Prepo
|
|||||||
{
|
{
|
||||||
class PrepoServerManager : ServerManager
|
class PrepoServerManager : ServerManager
|
||||||
{
|
{
|
||||||
public PrepoServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions)
|
private readonly ArpApi _arp;
|
||||||
|
|
||||||
|
public PrepoServerManager(HeapAllocator allocator, SmApi sm, ArpApi arp, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions)
|
||||||
{
|
{
|
||||||
|
_arp = arp;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Result OnNeedsToAccept(int portIndex, Server server)
|
protected override Result OnNeedsToAccept(int portIndex, Server server)
|
||||||
@ -18,12 +22,12 @@ namespace Ryujinx.Horizon.Prepo
|
|||||||
return (PrepoPortIndex)portIndex switch
|
return (PrepoPortIndex)portIndex switch
|
||||||
{
|
{
|
||||||
#pragma warning disable IDE0055 // Disable formatting
|
#pragma warning disable IDE0055 // Disable formatting
|
||||||
PrepoPortIndex.Admin => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Admin)),
|
PrepoPortIndex.Admin => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Admin)),
|
||||||
PrepoPortIndex.Admin2 => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Admin)),
|
PrepoPortIndex.Admin2 => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Admin)),
|
||||||
PrepoPortIndex.Manager => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Manager)),
|
PrepoPortIndex.Manager => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Manager)),
|
||||||
PrepoPortIndex.User => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.User)),
|
PrepoPortIndex.User => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.User)),
|
||||||
PrepoPortIndex.System => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.System)),
|
PrepoPortIndex.System => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.System)),
|
||||||
PrepoPortIndex.Debug => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Debug)),
|
PrepoPortIndex.Debug => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Debug)),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(portIndex)),
|
_ => throw new ArgumentOutOfRangeException(nameof(portIndex)),
|
||||||
#pragma warning restore IDE0055
|
#pragma warning restore IDE0055
|
||||||
};
|
};
|
||||||
|
9
src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs
Normal file
9
src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential, Size = 0x528)]
|
||||||
|
public struct ApplicationCertificate
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
8
src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs
Normal file
8
src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
public enum ApplicationKind : byte
|
||||||
|
{
|
||||||
|
Application,
|
||||||
|
MicroApplication,
|
||||||
|
}
|
||||||
|
}
|
14
src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs
Normal file
14
src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using Ryujinx.Horizon.Sdk.Ncm;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
public struct ApplicationLaunchProperty
|
||||||
|
{
|
||||||
|
public ApplicationId ApplicationId;
|
||||||
|
public uint Version;
|
||||||
|
public StorageId Storage;
|
||||||
|
public StorageId PatchStorage;
|
||||||
|
public ApplicationKind ApplicationKind;
|
||||||
|
public byte Padding;
|
||||||
|
}
|
||||||
|
}
|
10
src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs
Normal file
10
src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using Ryujinx.Common.Memory;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
public struct ApplicationProcessProperty
|
||||||
|
{
|
||||||
|
public byte ProgramIndex;
|
||||||
|
public Array15<byte> Unknown;
|
||||||
|
}
|
||||||
|
}
|
130
src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs
Normal file
130
src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Ns;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf.Cmif;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sf.Hipc;
|
||||||
|
using Ryujinx.Horizon.Sdk.Sm;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
class ArpApi : IDisposable
|
||||||
|
{
|
||||||
|
private const string ArpRName = "arp:r";
|
||||||
|
|
||||||
|
private readonly HeapAllocator _allocator;
|
||||||
|
private int _sessionHandle;
|
||||||
|
|
||||||
|
public ArpApi(HeapAllocator allocator)
|
||||||
|
{
|
||||||
|
_allocator = allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeArpRService()
|
||||||
|
{
|
||||||
|
if (_sessionHandle == 0)
|
||||||
|
{
|
||||||
|
using var smApi = new SmApi();
|
||||||
|
|
||||||
|
smApi.Initialize();
|
||||||
|
smApi.GetServiceHandle(out _sessionHandle, ServiceName.Encode(ArpRName)).AbortOnFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong applicationPid)
|
||||||
|
{
|
||||||
|
Span<byte> data = stackalloc byte[8];
|
||||||
|
SpanWriter writer = new(data);
|
||||||
|
|
||||||
|
writer.Write(applicationPid);
|
||||||
|
|
||||||
|
InitializeArpRService();
|
||||||
|
|
||||||
|
Result result = ServiceUtil.SendRequest(out CmifResponse response, _sessionHandle, 3, sendPid: false, data);
|
||||||
|
if (result.IsFailure)
|
||||||
|
{
|
||||||
|
applicationInstanceId = 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpanReader reader = new(response.Data);
|
||||||
|
|
||||||
|
applicationInstanceId = reader.Read<ulong>();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
applicationLaunchProperty = default;
|
||||||
|
|
||||||
|
Span<byte> data = stackalloc byte[8];
|
||||||
|
SpanWriter writer = new(data);
|
||||||
|
|
||||||
|
writer.Write(applicationInstanceId);
|
||||||
|
|
||||||
|
InitializeArpRService();
|
||||||
|
|
||||||
|
Result result = ServiceUtil.SendRequest(out CmifResponse response, _sessionHandle, 0, sendPid: false, data);
|
||||||
|
if (result.IsFailure)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpanReader reader = new(response.Data);
|
||||||
|
|
||||||
|
applicationLaunchProperty = reader.Read<ApplicationLaunchProperty>();
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result GetApplicationControlProperty(out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId)
|
||||||
|
{
|
||||||
|
applicationControlProperty = default;
|
||||||
|
|
||||||
|
Span<byte> data = stackalloc byte[8];
|
||||||
|
SpanWriter writer = new(data);
|
||||||
|
|
||||||
|
writer.Write(applicationInstanceId);
|
||||||
|
|
||||||
|
ulong bufferSize = (ulong)Unsafe.SizeOf<ApplicationControlProperty>();
|
||||||
|
ulong bufferAddress = _allocator.Allocate(bufferSize);
|
||||||
|
|
||||||
|
InitializeArpRService();
|
||||||
|
|
||||||
|
Result result = ServiceUtil.SendRequest(
|
||||||
|
out CmifResponse response,
|
||||||
|
_sessionHandle,
|
||||||
|
1,
|
||||||
|
sendPid: false,
|
||||||
|
data,
|
||||||
|
stackalloc[] { HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize },
|
||||||
|
stackalloc[] { new PointerAndSize(bufferAddress, bufferSize) });
|
||||||
|
|
||||||
|
if (result.IsFailure)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationControlProperty = HorizonStatic.AddressSpace.Read<ApplicationControlProperty>(bufferAddress);
|
||||||
|
|
||||||
|
_allocator.Free(bufferAddress, bufferSize);
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_sessionHandle != 0)
|
||||||
|
{
|
||||||
|
HorizonStatic.Syscall.CloseHandle(_sessionHandle);
|
||||||
|
|
||||||
|
_sessionHandle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs
Normal file
17
src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
static class ArpResult
|
||||||
|
{
|
||||||
|
private const int ModuleId = 157;
|
||||||
|
|
||||||
|
public static Result InvalidArgument => new(ModuleId, 30);
|
||||||
|
public static Result InvalidPid => new(ModuleId, 31);
|
||||||
|
public static Result InvalidPointer => new(ModuleId, 32);
|
||||||
|
public static Result DataAlreadyBound => new(ModuleId, 42);
|
||||||
|
public static Result AllocationFailed => new(ModuleId, 63);
|
||||||
|
public static Result NoFreeInstance => new(ModuleId, 101);
|
||||||
|
public static Result InvalidInstanceId => new(ModuleId, 102);
|
||||||
|
}
|
||||||
|
}
|
13
src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs
Normal file
13
src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using Ryujinx.Horizon.Sdk.Ns;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp.Detail
|
||||||
|
{
|
||||||
|
class ApplicationInstance
|
||||||
|
{
|
||||||
|
public ulong Pid { get; set; }
|
||||||
|
public ApplicationLaunchProperty? LaunchProperty { get; set; }
|
||||||
|
public ApplicationProcessProperty? ProcessProperty { get; set; }
|
||||||
|
public ApplicationControlProperty? ControlProperty { get; set; }
|
||||||
|
public ApplicationCertificate? Certificate { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
using Ryujinx.Horizon.Sdk.OsTypes;
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp.Detail
|
||||||
|
{
|
||||||
|
class ApplicationInstanceManager : IDisposable
|
||||||
|
{
|
||||||
|
private int _disposalState;
|
||||||
|
|
||||||
|
public SystemEventType SystemEvent;
|
||||||
|
public int EventHandle;
|
||||||
|
|
||||||
|
public readonly ApplicationInstance[] Entries = new ApplicationInstance[2];
|
||||||
|
|
||||||
|
public ApplicationInstanceManager()
|
||||||
|
{
|
||||||
|
Os.CreateSystemEvent(out SystemEvent, EventClearMode.ManualClear, true).AbortOnFailure();
|
||||||
|
|
||||||
|
EventHandle = Os.GetReadableHandleOfSystemEvent(ref SystemEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (EventHandle != 0 && Interlocked.Exchange(ref _disposalState, 1) == 0)
|
||||||
|
{
|
||||||
|
Os.DestroySystemEvent(ref SystemEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
src/Ryujinx.Horizon/Sdk/Arp/IReader.cs
Normal file
18
src/Ryujinx.Horizon/Sdk/Arp/IReader.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Ns;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
public interface IReader
|
||||||
|
{
|
||||||
|
public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId);
|
||||||
|
public Result GetApplicationControlProperty(out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId);
|
||||||
|
public Result GetApplicationProcessProperty(out ApplicationProcessProperty applicationControlProperty, ulong applicationInstanceId);
|
||||||
|
public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong pid);
|
||||||
|
public Result GetApplicationInstanceUnregistrationNotifier(out IUnregistrationNotifier unregistrationNotifier);
|
||||||
|
public Result ListApplicationInstanceId(out int count, Span<ulong> applicationInstanceIdList);
|
||||||
|
public Result GetMicroApplicationInstanceId(out ulong MicroApplicationInstanceId, ulong pid);
|
||||||
|
public Result GetApplicationCertificate(out ApplicationCertificate applicationCertificate, ulong applicationInstanceId);
|
||||||
|
}
|
||||||
|
}
|
12
src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs
Normal file
12
src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
using Ryujinx.Horizon.Sdk.Ns;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
public interface IRegistrar
|
||||||
|
{
|
||||||
|
public Result Issue(out ulong applicationInstanceId);
|
||||||
|
public Result SetApplicationLaunchProperty(ApplicationLaunchProperty applicationLaunchProperty);
|
||||||
|
public Result SetApplicationControlProperty(in ApplicationControlProperty applicationControlProperty);
|
||||||
|
}
|
||||||
|
}
|
9
src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs
Normal file
9
src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
public interface IUnregistrationNotifier
|
||||||
|
{
|
||||||
|
public Result GetReadableHandle(out int readableHandle);
|
||||||
|
}
|
||||||
|
}
|
12
src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs
Normal file
12
src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
public interface IUpdater
|
||||||
|
{
|
||||||
|
public Result Issue();
|
||||||
|
public Result SetApplicationProcessProperty(ulong pid, ApplicationProcessProperty applicationProcessProperty);
|
||||||
|
public Result DeleteApplicationProcessProperty();
|
||||||
|
public Result SetApplicationCertificate(ApplicationCertificate applicationCertificate);
|
||||||
|
}
|
||||||
|
}
|
12
src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs
Normal file
12
src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using Ryujinx.Horizon.Common;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Arp
|
||||||
|
{
|
||||||
|
public interface IWriter
|
||||||
|
{
|
||||||
|
public Result AcquireRegistrar(out IRegistrar registrar);
|
||||||
|
public Result UnregisterApplicationInstance(ulong applicationInstanceId);
|
||||||
|
public Result AcquireApplicationProcessPropertyUpdater(out IUpdater updater, ulong applicationInstanceId);
|
||||||
|
public Result AcquireApplicationCertificateUpdater(out IUpdater updater, ulong applicationInstanceId);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
namespace Ryujinx.Horizon.Sdk.Ncm
|
namespace Ryujinx.Horizon.Sdk.Ncm
|
||||||
{
|
{
|
||||||
readonly struct ApplicationId
|
public readonly struct ApplicationId
|
||||||
{
|
{
|
||||||
public readonly ulong Id;
|
public readonly ulong Id;
|
||||||
|
|
||||||
|
13
src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs
Normal file
13
src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Ryujinx.Horizon.Sdk.Ncm
|
||||||
|
{
|
||||||
|
public enum StorageId : byte
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Host,
|
||||||
|
GameCard,
|
||||||
|
BuiltInSystem,
|
||||||
|
BuiltInUser,
|
||||||
|
SdCard,
|
||||||
|
Any,
|
||||||
|
}
|
||||||
|
}
|
309
src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs
Normal file
309
src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp.Detail;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.Horizon.Sdk.Ns
|
||||||
|
{
|
||||||
|
public struct ApplicationControlProperty
|
||||||
|
{
|
||||||
|
public Array16<ApplicationTitle> Title;
|
||||||
|
public Array37<byte> Isbn;
|
||||||
|
public StartupUserAccountValue StartupUserAccount;
|
||||||
|
public UserAccountSwitchLockValue UserAccountSwitchLock;
|
||||||
|
public AddOnContentRegistrationTypeValue AddOnContentRegistrationType;
|
||||||
|
public AttributeFlagValue AttributeFlag;
|
||||||
|
public uint SupportedLanguageFlag;
|
||||||
|
public ParentalControlFlagValue ParentalControlFlag;
|
||||||
|
public ScreenshotValue Screenshot;
|
||||||
|
public VideoCaptureValue VideoCapture;
|
||||||
|
public DataLossConfirmationValue DataLossConfirmation;
|
||||||
|
public PlayLogPolicyValue PlayLogPolicy;
|
||||||
|
public ulong PresenceGroupId;
|
||||||
|
public Array32<sbyte> RatingAge;
|
||||||
|
public Array16<byte> DisplayVersion;
|
||||||
|
public ulong AddOnContentBaseId;
|
||||||
|
public ulong SaveDataOwnerId;
|
||||||
|
public long UserAccountSaveDataSize;
|
||||||
|
public long UserAccountSaveDataJournalSize;
|
||||||
|
public long DeviceSaveDataSize;
|
||||||
|
public long DeviceSaveDataJournalSize;
|
||||||
|
public long BcatDeliveryCacheStorageSize;
|
||||||
|
public Array8<byte> ApplicationErrorCodeCategory;
|
||||||
|
public Array8<ulong> LocalCommunicationId;
|
||||||
|
public LogoTypeValue LogoType;
|
||||||
|
public LogoHandlingValue LogoHandling;
|
||||||
|
public RuntimeAddOnContentInstallValue RuntimeAddOnContentInstall;
|
||||||
|
public RuntimeParameterDeliveryValue RuntimeParameterDelivery;
|
||||||
|
public Array2<byte> Reserved30F4;
|
||||||
|
public CrashReportValue CrashReport;
|
||||||
|
public HdcpValue Hdcp;
|
||||||
|
public ulong SeedForPseudoDeviceId;
|
||||||
|
public Array65<byte> BcatPassphrase;
|
||||||
|
public StartupUserAccountOptionFlagValue StartupUserAccountOption;
|
||||||
|
public Array6<byte> ReservedForUserAccountSaveDataOperation;
|
||||||
|
public long UserAccountSaveDataSizeMax;
|
||||||
|
public long UserAccountSaveDataJournalSizeMax;
|
||||||
|
public long DeviceSaveDataSizeMax;
|
||||||
|
public long DeviceSaveDataJournalSizeMax;
|
||||||
|
public long TemporaryStorageSize;
|
||||||
|
public long CacheStorageSize;
|
||||||
|
public long CacheStorageJournalSize;
|
||||||
|
public long CacheStorageDataAndJournalSizeMax;
|
||||||
|
public ushort CacheStorageIndexMax;
|
||||||
|
public byte Reserved318A;
|
||||||
|
public byte RuntimeUpgrade;
|
||||||
|
public uint SupportingLimitedLicenses;
|
||||||
|
public Array16<ulong> PlayLogQueryableApplicationId;
|
||||||
|
public PlayLogQueryCapabilityValue PlayLogQueryCapability;
|
||||||
|
public RepairFlagValue RepairFlag;
|
||||||
|
public byte ProgramIndex;
|
||||||
|
public RequiredNetworkServiceLicenseOnLaunchValue RequiredNetworkServiceLicenseOnLaunchFlag;
|
||||||
|
public Array4<byte> Reserved3214;
|
||||||
|
public ApplicationNeighborDetectionClientConfiguration NeighborDetectionClientConfiguration;
|
||||||
|
public ApplicationJitConfiguration JitConfiguration;
|
||||||
|
public RequiredAddOnContentsSetBinaryDescriptor RequiredAddOnContentsSetBinaryDescriptors;
|
||||||
|
public PlayReportPermissionValue PlayReportPermission;
|
||||||
|
public CrashScreenshotForProdValue CrashScreenshotForProd;
|
||||||
|
public CrashScreenshotForDevValue CrashScreenshotForDev;
|
||||||
|
public byte ContentsAvailabilityTransitionPolicy;
|
||||||
|
public Array4<byte> Reserved3404;
|
||||||
|
public AccessibleLaunchRequiredVersionValue AccessibleLaunchRequiredVersion;
|
||||||
|
public ByteArray3000 Reserved3448;
|
||||||
|
|
||||||
|
public readonly string IsbnString => Encoding.UTF8.GetString(Isbn.AsSpan()).TrimEnd('\0');
|
||||||
|
public readonly string DisplayVersionString => Encoding.UTF8.GetString(DisplayVersion.AsSpan()).TrimEnd('\0');
|
||||||
|
public readonly string ApplicationErrorCodeCategoryString => Encoding.UTF8.GetString(ApplicationErrorCodeCategory.AsSpan()).TrimEnd('\0');
|
||||||
|
public readonly string BcatPassphraseString => Encoding.UTF8.GetString(BcatPassphrase.AsSpan()).TrimEnd('\0');
|
||||||
|
|
||||||
|
public struct ApplicationTitle
|
||||||
|
{
|
||||||
|
public ByteArray512 Name;
|
||||||
|
public Array256<byte> Publisher;
|
||||||
|
|
||||||
|
public readonly string NameString => Encoding.UTF8.GetString(Name.AsSpan()).TrimEnd('\0');
|
||||||
|
public readonly string PublisherString => Encoding.UTF8.GetString(Publisher.AsSpan()).TrimEnd('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ApplicationNeighborDetectionClientConfiguration
|
||||||
|
{
|
||||||
|
public ApplicationNeighborDetectionGroupConfiguration SendGroupConfiguration;
|
||||||
|
public Array16<ApplicationNeighborDetectionGroupConfiguration> ReceivableGroupConfigurations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ApplicationNeighborDetectionGroupConfiguration
|
||||||
|
{
|
||||||
|
public ulong GroupId;
|
||||||
|
public Array16<byte> Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ApplicationJitConfiguration
|
||||||
|
{
|
||||||
|
public JitConfigurationFlag Flags;
|
||||||
|
public long MemorySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct RequiredAddOnContentsSetBinaryDescriptor
|
||||||
|
{
|
||||||
|
public Array32<ushort> Descriptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AccessibleLaunchRequiredVersionValue
|
||||||
|
{
|
||||||
|
public Array8<ulong> ApplicationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Language
|
||||||
|
{
|
||||||
|
AmericanEnglish = 0,
|
||||||
|
BritishEnglish = 1,
|
||||||
|
Japanese = 2,
|
||||||
|
French = 3,
|
||||||
|
German = 4,
|
||||||
|
LatinAmericanSpanish = 5,
|
||||||
|
Spanish = 6,
|
||||||
|
Italian = 7,
|
||||||
|
Dutch = 8,
|
||||||
|
CanadianFrench = 9,
|
||||||
|
Portuguese = 10,
|
||||||
|
Russian = 11,
|
||||||
|
Korean = 12,
|
||||||
|
TraditionalChinese = 13,
|
||||||
|
SimplifiedChinese = 14,
|
||||||
|
BrazilianPortuguese = 15,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Organization
|
||||||
|
{
|
||||||
|
CERO = 0,
|
||||||
|
GRACGCRB = 1,
|
||||||
|
GSRMR = 2,
|
||||||
|
ESRB = 3,
|
||||||
|
ClassInd = 4,
|
||||||
|
USK = 5,
|
||||||
|
PEGI = 6,
|
||||||
|
PEGIPortugal = 7,
|
||||||
|
PEGIBBFC = 8,
|
||||||
|
Russian = 9,
|
||||||
|
ACB = 10,
|
||||||
|
OFLC = 11,
|
||||||
|
IARCGeneric = 12,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum StartupUserAccountValue : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Required = 1,
|
||||||
|
RequiredWithNetworkServiceAccountAvailable = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum UserAccountSwitchLockValue : byte
|
||||||
|
{
|
||||||
|
Disable = 0,
|
||||||
|
Enable = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AddOnContentRegistrationTypeValue : byte
|
||||||
|
{
|
||||||
|
AllOnLaunch = 0,
|
||||||
|
OnDemand = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum AttributeFlagValue
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Demo = 1 << 0,
|
||||||
|
RetailInteractiveDisplay = 1 << 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ParentalControlFlagValue
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
FreeCommunication = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ScreenshotValue : byte
|
||||||
|
{
|
||||||
|
Allow = 0,
|
||||||
|
Deny = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum VideoCaptureValue : byte
|
||||||
|
{
|
||||||
|
Disable = 0,
|
||||||
|
Manual = 1,
|
||||||
|
Enable = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DataLossConfirmationValue : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Required = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlayLogPolicyValue : byte
|
||||||
|
{
|
||||||
|
Open = 0,
|
||||||
|
LogOnly = 1,
|
||||||
|
None = 2,
|
||||||
|
Closed = 3,
|
||||||
|
All = Open,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LogoTypeValue : byte
|
||||||
|
{
|
||||||
|
LicensedByNintendo = 0,
|
||||||
|
DistributedByNintendo = 1,
|
||||||
|
Nintendo = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LogoHandlingValue : byte
|
||||||
|
{
|
||||||
|
Auto = 0,
|
||||||
|
Manual = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RuntimeAddOnContentInstallValue : byte
|
||||||
|
{
|
||||||
|
Deny = 0,
|
||||||
|
AllowAppend = 1,
|
||||||
|
AllowAppendButDontDownloadWhenUsingNetwork = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RuntimeParameterDeliveryValue : byte
|
||||||
|
{
|
||||||
|
Always = 0,
|
||||||
|
AlwaysIfUserStateMatched = 1,
|
||||||
|
OnRestart = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CrashReportValue : byte
|
||||||
|
{
|
||||||
|
Deny = 0,
|
||||||
|
Allow = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum HdcpValue : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Required = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum StartupUserAccountOptionFlagValue : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
IsOptional = 1 << 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlayLogQueryCapabilityValue : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
WhiteList = 1,
|
||||||
|
All = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum RepairFlagValue : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
SuppressGameCardAccess = 1 << 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum RequiredNetworkServiceLicenseOnLaunchValue : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Common = 1 << 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum JitConfigurationFlag : ulong
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Enabled = 1 << 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum PlayReportPermissionValue : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
TargetMarketing = 1 << 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CrashScreenshotForProdValue : byte
|
||||||
|
{
|
||||||
|
Deny = 0,
|
||||||
|
Allow = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum CrashScreenshotForDevValue : byte
|
||||||
|
{
|
||||||
|
Deny = 0,
|
||||||
|
Allow = 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,5 +35,254 @@ namespace Ryujinx.Horizon.Sdk
|
|||||||
|
|
||||||
return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
|
return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Result SendRequest(
|
||||||
|
out CmifResponse response,
|
||||||
|
int sessionHandle,
|
||||||
|
uint requestId,
|
||||||
|
bool sendPid,
|
||||||
|
scoped ReadOnlySpan<byte> data,
|
||||||
|
ReadOnlySpan<HipcBufferFlags> bufferFlags,
|
||||||
|
ReadOnlySpan<PointerAndSize> buffers)
|
||||||
|
{
|
||||||
|
ulong tlsAddress = HorizonStatic.ThreadContext.TlsAddress;
|
||||||
|
int tlsSize = Api.TlsMessageBufferSize;
|
||||||
|
|
||||||
|
using (var tlsRegion = HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize))
|
||||||
|
{
|
||||||
|
CmifRequestFormat format = new()
|
||||||
|
{
|
||||||
|
DataSize = data.Length,
|
||||||
|
RequestId = requestId,
|
||||||
|
SendPid = sendPid,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int index = 0; index < bufferFlags.Length; index++)
|
||||||
|
{
|
||||||
|
FormatProcessBuffer(ref format, bufferFlags[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
CmifRequest request = CmifMessage.CreateRequest(tlsRegion.Memory.Span, format);
|
||||||
|
|
||||||
|
for (int index = 0; index < buffers.Length; index++)
|
||||||
|
{
|
||||||
|
RequestProcessBuffer(ref request, buffers[index], bufferFlags[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
data.CopyTo(request.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result result = HorizonStatic.Syscall.SendSyncRequest(sessionHandle);
|
||||||
|
|
||||||
|
if (result.IsFailure)
|
||||||
|
{
|
||||||
|
response = default;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FormatProcessBuffer(ref CmifRequestFormat format, HipcBufferFlags flags)
|
||||||
|
{
|
||||||
|
if (flags == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isIn = flags.HasFlag(HipcBufferFlags.In);
|
||||||
|
bool isOut = flags.HasFlag(HipcBufferFlags.Out);
|
||||||
|
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.AutoSelect))
|
||||||
|
{
|
||||||
|
if (isIn)
|
||||||
|
{
|
||||||
|
format.InAutoBuffersCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOut)
|
||||||
|
{
|
||||||
|
format.OutAutoBuffersCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (flags.HasFlag(HipcBufferFlags.Pointer))
|
||||||
|
{
|
||||||
|
if (isIn)
|
||||||
|
{
|
||||||
|
format.InPointersCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOut)
|
||||||
|
{
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.FixedSize))
|
||||||
|
{
|
||||||
|
format.OutFixedPointersCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
format.OutPointersCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (flags.HasFlag(HipcBufferFlags.MapAlias))
|
||||||
|
{
|
||||||
|
if (isIn && isOut)
|
||||||
|
{
|
||||||
|
format.InOutBuffersCount++;
|
||||||
|
}
|
||||||
|
else if (isIn)
|
||||||
|
{
|
||||||
|
format.InBuffersCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
format.OutBuffersCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestProcessBuffer(ref CmifRequest request, PointerAndSize buffer, HipcBufferFlags flags)
|
||||||
|
{
|
||||||
|
if (flags == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isIn = flags.HasFlag(HipcBufferFlags.In);
|
||||||
|
bool isOut = flags.HasFlag(HipcBufferFlags.Out);
|
||||||
|
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.AutoSelect))
|
||||||
|
{
|
||||||
|
HipcBufferMode mode = HipcBufferMode.Normal;
|
||||||
|
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
|
||||||
|
{
|
||||||
|
mode = HipcBufferMode.NonSecure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
|
||||||
|
{
|
||||||
|
mode = HipcBufferMode.NonDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isIn)
|
||||||
|
{
|
||||||
|
RequestInAutoBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOut)
|
||||||
|
{
|
||||||
|
RequestOutAutoBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (flags.HasFlag(HipcBufferFlags.Pointer))
|
||||||
|
{
|
||||||
|
if (isIn)
|
||||||
|
{
|
||||||
|
RequestInPointer(ref request, buffer.Address, buffer.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOut)
|
||||||
|
{
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.FixedSize))
|
||||||
|
{
|
||||||
|
RequestOutFixedPointer(ref request, buffer.Address, buffer.Size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RequestOutPointer(ref request, buffer.Address, buffer.Size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (flags.HasFlag(HipcBufferFlags.MapAlias))
|
||||||
|
{
|
||||||
|
HipcBufferMode mode = HipcBufferMode.Normal;
|
||||||
|
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure))
|
||||||
|
{
|
||||||
|
mode = HipcBufferMode.NonSecure;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice))
|
||||||
|
{
|
||||||
|
mode = HipcBufferMode.NonDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isIn && isOut)
|
||||||
|
{
|
||||||
|
RequestInOutBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||||
|
}
|
||||||
|
else if (isIn)
|
||||||
|
{
|
||||||
|
RequestInBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RequestOutBuffer(ref request, buffer.Address, buffer.Size, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestInAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize)
|
||||||
|
{
|
||||||
|
RequestInPointer(ref request, bufferAddress, bufferSize);
|
||||||
|
RequestInBuffer(ref request, 0UL, 0UL, mode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RequestInPointer(ref request, 0UL, 0UL);
|
||||||
|
RequestInBuffer(ref request, bufferAddress, bufferSize, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestOutAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize)
|
||||||
|
{
|
||||||
|
RequestOutPointer(ref request, bufferAddress, bufferSize);
|
||||||
|
RequestOutBuffer(ref request, 0UL, 0UL, mode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RequestOutPointer(ref request, 0UL, 0UL);
|
||||||
|
RequestOutBuffer(ref request, bufferAddress, bufferSize, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestInBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
request.Hipc.SendBuffers[request.SendBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
request.Hipc.ReceiveBuffers[request.RecvBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestInOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
request.Hipc.ExchangeBuffers[request.ExchBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestInPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
|
||||||
|
{
|
||||||
|
request.Hipc.SendStatics[request.SendStaticIndex++] = new HipcStaticDescriptor(bufferAddress, (ushort)bufferSize, request.CurrentInPointerId++);
|
||||||
|
request.ServerPointerSize -= (int)bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestOutFixedPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
|
||||||
|
{
|
||||||
|
request.Hipc.ReceiveList[request.RecvListIndex++] = new HipcReceiveListEntry(bufferAddress, (ushort)bufferSize);
|
||||||
|
request.ServerPointerSize -= (int)bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RequestOutPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize)
|
||||||
|
{
|
||||||
|
RequestOutFixedPointer(ref request, bufferAddress, bufferSize);
|
||||||
|
request.OutPointerSizes[request.OutPointerSizeIndex++] = (ushort)bufferSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,5 +10,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif
|
|||||||
public Span<ushort> OutPointerSizes;
|
public Span<ushort> OutPointerSizes;
|
||||||
public Span<uint> Objects;
|
public Span<uint> Objects;
|
||||||
public int ServerPointerSize;
|
public int ServerPointerSize;
|
||||||
|
public int CurrentInPointerId;
|
||||||
|
public int SendBufferIndex;
|
||||||
|
public int RecvBufferIndex;
|
||||||
|
public int ExchBufferIndex;
|
||||||
|
public int SendStaticIndex;
|
||||||
|
public int RecvListIndex;
|
||||||
|
public int OutPointerSizeIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc
|
|||||||
public ulong Address => _addressLow | (((ulong)_word2 << 4) & 0xf00000000UL) | (((ulong)_word2 << 34) & 0x7000000000UL);
|
public ulong Address => _addressLow | (((ulong)_word2 << 4) & 0xf00000000UL) | (((ulong)_word2 << 34) & 0x7000000000UL);
|
||||||
public ulong Size => _sizeLow | ((ulong)_word2 << 8) & 0xf00000000UL;
|
public ulong Size => _sizeLow | ((ulong)_word2 << 8) & 0xf00000000UL;
|
||||||
public HipcBufferMode Mode => (HipcBufferMode)(_word2 & 3);
|
public HipcBufferMode Mode => (HipcBufferMode)(_word2 & 3);
|
||||||
|
|
||||||
|
public HipcBufferDescriptor(ulong address, ulong size, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
_sizeLow = (uint)size;
|
||||||
|
_addressLow = (uint)address;
|
||||||
|
_word2 = (uint)mode | ((uint)(address >> 34) & 0x1c) | ((uint)(size >> 32) << 24) | ((uint)(address >> 4) & 0xf0000000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Horizon.Arp;
|
||||||
using Ryujinx.Horizon.Bcat;
|
using Ryujinx.Horizon.Bcat;
|
||||||
using Ryujinx.Horizon.Hshl;
|
using Ryujinx.Horizon.Hshl;
|
||||||
using Ryujinx.Horizon.Ins;
|
using Ryujinx.Horizon.Ins;
|
||||||
@ -8,6 +9,7 @@ using Ryujinx.Horizon.Ngc;
|
|||||||
using Ryujinx.Horizon.Ovln;
|
using Ryujinx.Horizon.Ovln;
|
||||||
using Ryujinx.Horizon.Prepo;
|
using Ryujinx.Horizon.Prepo;
|
||||||
using Ryujinx.Horizon.Psc;
|
using Ryujinx.Horizon.Psc;
|
||||||
|
using Ryujinx.Horizon.Sdk.Arp;
|
||||||
using Ryujinx.Horizon.Srepo;
|
using Ryujinx.Horizon.Srepo;
|
||||||
using Ryujinx.Horizon.Usb;
|
using Ryujinx.Horizon.Usb;
|
||||||
using Ryujinx.Horizon.Wlan;
|
using Ryujinx.Horizon.Wlan;
|
||||||
@ -23,6 +25,9 @@ namespace Ryujinx.Horizon
|
|||||||
|
|
||||||
private readonly ManualResetEvent _servicesReadyEvent = new(false);
|
private readonly ManualResetEvent _servicesReadyEvent = new(false);
|
||||||
|
|
||||||
|
public IReader ArpReader { get; internal set; }
|
||||||
|
public IWriter ArpWriter { get; internal set; }
|
||||||
|
|
||||||
public IEnumerable<ServiceEntry> GetServices(HorizonOptions options)
|
public IEnumerable<ServiceEntry> GetServices(HorizonOptions options)
|
||||||
{
|
{
|
||||||
List<ServiceEntry> entries = new();
|
List<ServiceEntry> entries = new();
|
||||||
@ -32,6 +37,7 @@ namespace Ryujinx.Horizon
|
|||||||
entries.Add(new ServiceEntry(T.Main, this, options));
|
entries.Add(new ServiceEntry(T.Main, this, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RegisterService<ArpMain>();
|
||||||
RegisterService<BcatMain>();
|
RegisterService<BcatMain>();
|
||||||
RegisterService<HshlMain>();
|
RegisterService<HshlMain>();
|
||||||
RegisterService<InsMain>();
|
RegisterService<InsMain>();
|
||||||
|
@ -311,6 +311,46 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static uint[] _ShlImm_S_D_()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
0x5F407400u, // SQSHL D0, D0, #0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint[] _ShlImm_V_8B_16B_()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
0x0F087400u, // SQSHL V0.8B, V0.8B, #0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint[] _ShlImm_V_4H_8H_()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
0x0F107400u, // SQSHL V0.4H, V0.4H, #0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint[] _ShlImm_V_2S_4S_()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
0x0F207400u, // SQSHL V0.2S, V0.2S, #0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint[] _ShlImm_V_2D_()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
0x4F407400u, // SQSHL V0.2D, V0.2D, #0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static uint[] _ShrImm_Sri_S_D_()
|
private static uint[] _ShrImm_Sri_S_D_()
|
||||||
{
|
{
|
||||||
return new[]
|
return new[]
|
||||||
@ -813,6 +853,117 @@ namespace Ryujinx.Tests.Cpu
|
|||||||
CompareAgainstUnicorn();
|
CompareAgainstUnicorn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise]
|
||||||
|
public void ShlImm_S_D([ValueSource(nameof(_ShlImm_S_D_))] uint opcodes,
|
||||||
|
[Values(0u)] uint rd,
|
||||||
|
[Values(1u, 0u)] uint rn,
|
||||||
|
[ValueSource(nameof(_1D_))] ulong z,
|
||||||
|
[ValueSource(nameof(_1D_))] ulong a,
|
||||||
|
[Values(1u, 64u)] uint shift)
|
||||||
|
{
|
||||||
|
uint immHb = (64 + shift) & 0x7F;
|
||||||
|
|
||||||
|
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||||
|
opcodes |= (immHb << 16);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1(z, z);
|
||||||
|
V128 v1 = MakeVectorE0(a);
|
||||||
|
|
||||||
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise]
|
||||||
|
public void ShlImm_V_8B_16B([ValueSource(nameof(_ShlImm_V_8B_16B_))] uint opcodes,
|
||||||
|
[Values(0u)] uint rd,
|
||||||
|
[Values(1u, 0u)] uint rn,
|
||||||
|
[ValueSource(nameof(_8B_))] ulong z,
|
||||||
|
[ValueSource(nameof(_8B_))] ulong a,
|
||||||
|
[Values(1u, 8u)] uint shift,
|
||||||
|
[Values(0b0u, 0b1u)] uint q) // <8B, 16B>
|
||||||
|
{
|
||||||
|
uint immHb = (8 + shift) & 0x7F;
|
||||||
|
|
||||||
|
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||||
|
opcodes |= (immHb << 16);
|
||||||
|
opcodes |= ((q & 1) << 30);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1(z, z);
|
||||||
|
V128 v1 = MakeVectorE0E1(a, a * q);
|
||||||
|
|
||||||
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise]
|
||||||
|
public void ShlImm_V_4H_8H([ValueSource(nameof(_ShlImm_V_4H_8H_))] uint opcodes,
|
||||||
|
[Values(0u)] uint rd,
|
||||||
|
[Values(1u, 0u)] uint rn,
|
||||||
|
[ValueSource(nameof(_4H_))] ulong z,
|
||||||
|
[ValueSource(nameof(_4H_))] ulong a,
|
||||||
|
[Values(1u, 16u)] uint shift,
|
||||||
|
[Values(0b0u, 0b1u)] uint q) // <4H, 8H>
|
||||||
|
{
|
||||||
|
uint immHb = (16 + shift) & 0x7F;
|
||||||
|
|
||||||
|
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||||
|
opcodes |= (immHb << 16);
|
||||||
|
opcodes |= ((q & 1) << 30);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1(z, z);
|
||||||
|
V128 v1 = MakeVectorE0E1(a, a * q);
|
||||||
|
|
||||||
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise]
|
||||||
|
public void ShlImm_V_2S_4S([ValueSource(nameof(_ShlImm_V_2S_4S_))] uint opcodes,
|
||||||
|
[Values(0u)] uint rd,
|
||||||
|
[Values(1u, 0u)] uint rn,
|
||||||
|
[ValueSource(nameof(_2S_))] ulong z,
|
||||||
|
[ValueSource(nameof(_2S_))] ulong a,
|
||||||
|
[Values(1u, 32u)] uint shift,
|
||||||
|
[Values(0b0u, 0b1u)] uint q) // <2S, 4S>
|
||||||
|
{
|
||||||
|
uint immHb = (32 + shift) & 0x7F;
|
||||||
|
|
||||||
|
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||||
|
opcodes |= (immHb << 16);
|
||||||
|
opcodes |= (((q | (immHb >> 6)) & 1) << 30);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1(z, z);
|
||||||
|
V128 v1 = MakeVectorE0E1(a, a * q);
|
||||||
|
|
||||||
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test, Pairwise]
|
||||||
|
public void ShlImm_V_2D([ValueSource(nameof(_ShlImm_V_2D_))] uint opcodes,
|
||||||
|
[Values(0u)] uint rd,
|
||||||
|
[Values(1u, 0u)] uint rn,
|
||||||
|
[ValueSource(nameof(_1D_))] ulong z,
|
||||||
|
[ValueSource(nameof(_1D_))] ulong a,
|
||||||
|
[Values(1u, 64u)] uint shift)
|
||||||
|
{
|
||||||
|
uint immHb = (64 + shift) & 0x7F;
|
||||||
|
|
||||||
|
opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0);
|
||||||
|
opcodes |= (immHb << 16);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1(z, z);
|
||||||
|
V128 v1 = MakeVectorE0E1(a, a);
|
||||||
|
|
||||||
|
SingleOpcode(opcodes, v0: v0, v1: v1);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
[Test, Pairwise]
|
[Test, Pairwise]
|
||||||
public void ShrImm_Sri_S_D([ValueSource(nameof(_ShrImm_Sri_S_D_))] uint opcodes,
|
public void ShrImm_Sri_S_D([ValueSource(nameof(_ShrImm_Sri_S_D_))] uint opcodes,
|
||||||
[Values(0u)] uint rd,
|
[Values(0u)] uint rd,
|
||||||
|
@ -54,6 +54,7 @@ namespace Ryujinx.Ui.Common.Helper
|
|||||||
{
|
{
|
||||||
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
|
string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx");
|
||||||
var plistFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.plist");
|
var plistFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.plist");
|
||||||
|
var shortcutScript = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-launch-script.sh");
|
||||||
// Macos .App folder
|
// Macos .App folder
|
||||||
string contentFolderPath = Path.Combine("/Applications", cleanedAppName + ".app", "Contents");
|
string contentFolderPath = Path.Combine("/Applications", cleanedAppName + ".app", "Contents");
|
||||||
string scriptFolderPath = Path.Combine(contentFolderPath, "MacOS");
|
string scriptFolderPath = Path.Combine(contentFolderPath, "MacOS");
|
||||||
@ -68,8 +69,7 @@ namespace Ryujinx.Ui.Common.Helper
|
|||||||
string scriptPath = Path.Combine(scriptFolderPath, ScriptName);
|
string scriptPath = Path.Combine(scriptFolderPath, ScriptName);
|
||||||
using StreamWriter scriptFile = new(scriptPath);
|
using StreamWriter scriptFile = new(scriptPath);
|
||||||
|
|
||||||
scriptFile.WriteLine("#!/bin/sh");
|
scriptFile.Write(shortcutScript, basePath, GetArgsString(appFilePath));
|
||||||
scriptFile.WriteLine($"{basePath} {GetArgsString(appFilePath)}");
|
|
||||||
|
|
||||||
// Set execute permission
|
// Set execute permission
|
||||||
FileInfo fileInfo = new(scriptPath);
|
FileInfo fileInfo = new(scriptPath);
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
|
|
||||||
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64' OR '$(RuntimeIdentifier)' == ''">
|
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64' OR '$(RuntimeIdentifier)' == ''">
|
||||||
<EmbeddedResource Include="..\..\distribution\macos\shortcut-template.plist" />
|
<EmbeddedResource Include="..\..\distribution\macos\shortcut-template.plist" />
|
||||||
|
<EmbeddedResource Include="..\..\distribution\macos\shortcut-launch-script.sh" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
Reference in New Issue
Block a user