Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
f39e89ece7 | |||
cf77c011e4 | |||
cd74ae1bbd | |||
62216782ca | |||
2f36a6665c | |||
ca59c3f499 | |||
fdd7ee791c | |||
398fa1c238 | |||
2c5c0392f9 | |||
e0acde04bb |
@ -39,11 +39,11 @@
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.16.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.16.0" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp" Version="2.1.9" />
|
||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.21.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.7" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="8.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="8.0.0" />
|
||||
|
@ -87,6 +87,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryuj
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -249,6 +251,10 @@ Global
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -746,6 +746,7 @@ namespace ARMeilleure.Decoders
|
||||
SetA32("<<<<01101000xxxxxxxxxxxxxx01xxxx", InstName.Pkh, InstEmit32.Pkh, OpCode32AluRsImm.Create);
|
||||
SetA32("11110101xx01xxxx1111xxxxxxxxxxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create);
|
||||
SetA32("11110111xx01xxxx1111xxxxxxx0xxxx", InstName.Pld, InstEmit32.Nop, OpCode32.Create);
|
||||
SetA32("<<<<01100010xxxxxxxx11110001xxxx", InstName.Qadd16, InstEmit32.Qadd16, OpCode32AluReg.Create);
|
||||
SetA32("<<<<011011111111xxxx11110011xxxx", InstName.Rbit, InstEmit32.Rbit, OpCode32AluReg.Create);
|
||||
SetA32("<<<<011010111111xxxx11110011xxxx", InstName.Rev, InstEmit32.Rev, OpCode32AluReg.Create);
|
||||
SetA32("<<<<011010111111xxxx11111011xxxx", InstName.Rev16, InstEmit32.Rev16, OpCode32AluReg.Create);
|
||||
@ -1034,6 +1035,7 @@ namespace ARMeilleure.Decoders
|
||||
SetAsimd("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||
SetAsimd("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create, OpCode32SimdReg.CreateT32);
|
||||
SetAsimd("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create, OpCode32SimdShImmLong.CreateT32); // A1 encoding.
|
||||
SetAsimd("111100111x11<<10xxxx001100x0xxxx", InstName.Vshll, InstEmit32.Vshll2, OpCode32SimdMovn.Create, OpCode32SimdMovn.CreateT32); // A2 encoding.
|
||||
SetAsimd("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||
SetAsimd("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create, OpCode32SimdShImmNarrow.CreateT32);
|
||||
SetAsimd("111100111x>>>xxxxxxx0101>xx1xxxx", InstName.Vsli, InstEmit32.Vsli_I, OpCode32SimdShImm.Create, OpCode32SimdShImm.CreateT32);
|
||||
|
@ -292,6 +292,16 @@ namespace ARMeilleure.Instructions
|
||||
EmitAluStore(context, res);
|
||||
}
|
||||
|
||||
public static void Qadd16(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
||||
|
||||
SetIntA32(context, op.Rd, EmitSigned16BitPair(context, GetIntA32(context, op.Rn), GetIntA32(context, op.Rm), (d, n, m) =>
|
||||
{
|
||||
EmitSaturateRange(context, d, context.Add(n, m), 16, unsigned: false, setQ: false);
|
||||
}));
|
||||
}
|
||||
|
||||
public static void Rbit(ArmEmitterContext context)
|
||||
{
|
||||
Operand m = GetAluM(context);
|
||||
@ -976,6 +986,94 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitSaturateRange(ArmEmitterContext context, Operand result, Operand value, uint saturateTo, bool unsigned, bool setQ = true)
|
||||
{
|
||||
Debug.Assert(saturateTo <= 32);
|
||||
Debug.Assert(!unsigned || saturateTo < 32);
|
||||
|
||||
if (!unsigned && saturateTo == 32)
|
||||
{
|
||||
// No saturation possible for this case.
|
||||
|
||||
context.Copy(result, value);
|
||||
|
||||
return;
|
||||
}
|
||||
else if (saturateTo == 0)
|
||||
{
|
||||
// Result is always zero if we saturate 0 bits.
|
||||
|
||||
context.Copy(result, Const(0));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Operand satValue;
|
||||
|
||||
if (unsigned)
|
||||
{
|
||||
// Negative values always saturate (to zero).
|
||||
// So we must always ignore the sign bit when masking, so that the truncated value will differ from the original one.
|
||||
|
||||
satValue = context.BitwiseAnd(value, Const((int)(uint.MaxValue >> (32 - (int)saturateTo))));
|
||||
}
|
||||
else
|
||||
{
|
||||
satValue = context.ShiftLeft(value, Const(32 - (int)saturateTo));
|
||||
satValue = context.ShiftRightSI(satValue, Const(32 - (int)saturateTo));
|
||||
}
|
||||
|
||||
// If the result is 0, the values are equal and we don't need saturation.
|
||||
Operand lblNoSat = Label();
|
||||
context.BranchIfFalse(lblNoSat, context.Subtract(value, satValue));
|
||||
|
||||
// Saturate and set Q flag.
|
||||
if (unsigned)
|
||||
{
|
||||
if (saturateTo == 31)
|
||||
{
|
||||
// Only saturation case possible when going from 32 bits signed to 32 or 31 bits unsigned
|
||||
// is when the signed input is negative, as all positive values are representable on a 31 bits range.
|
||||
|
||||
satValue = Const(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
satValue = context.ShiftRightSI(value, Const(31));
|
||||
satValue = context.BitwiseNot(satValue);
|
||||
satValue = context.ShiftRightUI(satValue, Const(32 - (int)saturateTo));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (saturateTo == 1)
|
||||
{
|
||||
satValue = context.ShiftRightSI(value, Const(31));
|
||||
}
|
||||
else
|
||||
{
|
||||
satValue = Const(uint.MaxValue >> (33 - (int)saturateTo));
|
||||
satValue = context.BitwiseExclusiveOr(satValue, context.ShiftRightSI(value, Const(31)));
|
||||
}
|
||||
}
|
||||
|
||||
if (setQ)
|
||||
{
|
||||
SetFlag(context, PState.QFlag, Const(1));
|
||||
}
|
||||
|
||||
context.Copy(result, satValue);
|
||||
|
||||
Operand lblExit = Label();
|
||||
context.Branch(lblExit);
|
||||
|
||||
context.MarkLabel(lblNoSat);
|
||||
|
||||
context.Copy(result, value);
|
||||
|
||||
context.MarkLabel(lblExit);
|
||||
}
|
||||
|
||||
private static void EmitSaturateUqadd(ArmEmitterContext context, Operand result, Operand value, uint saturateTo)
|
||||
{
|
||||
Debug.Assert(saturateTo <= 32);
|
||||
@ -1053,6 +1151,21 @@ namespace ARMeilleure.Instructions
|
||||
context.MarkLabel(lblExit);
|
||||
}
|
||||
|
||||
private static Operand EmitSigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
|
||||
{
|
||||
Operand tempD = context.AllocateLocal(OperandType.I32);
|
||||
|
||||
Operand tempN = context.SignExtend16(OperandType.I32, rn);
|
||||
Operand tempM = context.SignExtend16(OperandType.I32, rm);
|
||||
elementAction(tempD, tempN, tempM);
|
||||
Operand tempD2 = context.ZeroExtend16(OperandType.I32, tempD);
|
||||
|
||||
tempN = context.ShiftRightSI(rn, Const(16));
|
||||
tempM = context.ShiftRightSI(rm, Const(16));
|
||||
elementAction(tempD, tempN, tempM);
|
||||
return context.BitwiseOr(tempD2, context.ShiftLeft(tempD, Const(16)));
|
||||
}
|
||||
|
||||
private static Operand EmitUnsigned16BitPair(ArmEmitterContext context, Operand rn, Operand rm, Action<Operand, Operand, Operand> elementAction)
|
||||
{
|
||||
Operand tempD = context.AllocateLocal(OperandType.I32);
|
||||
|
@ -106,6 +106,38 @@ namespace ARMeilleure.Instructions
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
|
||||
public static void Vshll2(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
|
||||
Operand res = context.VectorZero();
|
||||
|
||||
int elems = op.GetBytesCount() >> op.Size;
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
Operand me = EmitVectorExtract32(context, op.Qm, op.Im + index, op.Size, !op.U);
|
||||
|
||||
if (op.Size == 2)
|
||||
{
|
||||
if (op.U)
|
||||
{
|
||||
me = context.ZeroExtend32(OperandType.I64, me);
|
||||
}
|
||||
else
|
||||
{
|
||||
me = context.SignExtend32(OperandType.I64, me);
|
||||
}
|
||||
}
|
||||
|
||||
me = context.ShiftLeft(me, Const(8 << op.Size));
|
||||
|
||||
res = EmitVectorInsert(context, res, me, index, op.Size + 1);
|
||||
}
|
||||
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
|
||||
public static void Vshr(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdShImm op = (OpCode32SimdShImm)context.CurrOp;
|
||||
|
@ -527,6 +527,7 @@ namespace ARMeilleure.Instructions
|
||||
Pld,
|
||||
Pop,
|
||||
Push,
|
||||
Qadd16,
|
||||
Rev,
|
||||
Revsh,
|
||||
Rsb,
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
@ -11,11 +10,10 @@ namespace ARMeilleure.Translation
|
||||
|
||||
public IntPtr FuncPtr { get; }
|
||||
|
||||
public DelegateInfo(Delegate dlg)
|
||||
public DelegateInfo(Delegate dlg, IntPtr funcPtr)
|
||||
{
|
||||
_dlg = dlg;
|
||||
|
||||
FuncPtr = Marshal.GetFunctionPointerForDelegate<Delegate>(dlg);
|
||||
FuncPtr = funcPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
@ -64,11 +65,11 @@ namespace ARMeilleure.Translation
|
||||
return index;
|
||||
}
|
||||
|
||||
private static void SetDelegateInfo(Delegate dlg)
|
||||
private static void SetDelegateInfo(Delegate dlg, IntPtr funcPtr)
|
||||
{
|
||||
string key = GetKey(dlg.Method);
|
||||
|
||||
_delegates.Add(key, new DelegateInfo(dlg)); // ArgumentException (key).
|
||||
_delegates.Add(key, new DelegateInfo(dlg, funcPtr)); // ArgumentException (key).
|
||||
}
|
||||
|
||||
private static string GetKey(MethodInfo info)
|
||||
@ -82,179 +83,353 @@ namespace ARMeilleure.Translation
|
||||
{
|
||||
_delegates = new SortedList<string, DelegateInfo>();
|
||||
|
||||
SetDelegateInfo(new MathAbs(Math.Abs));
|
||||
SetDelegateInfo(new MathCeiling(Math.Ceiling));
|
||||
SetDelegateInfo(new MathFloor(Math.Floor));
|
||||
SetDelegateInfo(new MathRound(Math.Round));
|
||||
SetDelegateInfo(new MathTruncate(Math.Truncate));
|
||||
var dlgMathAbs = new MathAbs(Math.Abs);
|
||||
var dlgMathCeiling = new MathCeiling(Math.Ceiling);
|
||||
var dlgMathFloor = new MathFloor(Math.Floor);
|
||||
var dlgMathRound = new MathRound(Math.Round);
|
||||
var dlgMathTruncate = new MathTruncate(Math.Truncate);
|
||||
|
||||
SetDelegateInfo(new MathFAbs(MathF.Abs));
|
||||
SetDelegateInfo(new MathFCeiling(MathF.Ceiling));
|
||||
SetDelegateInfo(new MathFFloor(MathF.Floor));
|
||||
SetDelegateInfo(new MathFRound(MathF.Round));
|
||||
SetDelegateInfo(new MathFTruncate(MathF.Truncate));
|
||||
var dlgMathFAbs = new MathFAbs(MathF.Abs);
|
||||
var dlgMathFCeiling = new MathFCeiling(MathF.Ceiling);
|
||||
var dlgMathFFloor = new MathFFloor(MathF.Floor);
|
||||
var dlgMathFRound = new MathFRound(MathF.Round);
|
||||
var dlgMathFTruncate = new MathFTruncate(MathF.Truncate);
|
||||
|
||||
SetDelegateInfo(new NativeInterfaceBreak(NativeInterface.Break));
|
||||
SetDelegateInfo(new NativeInterfaceCheckSynchronization(NativeInterface.CheckSynchronization));
|
||||
SetDelegateInfo(new NativeInterfaceEnqueueForRejit(NativeInterface.EnqueueForRejit));
|
||||
SetDelegateInfo(new NativeInterfaceGetCntfrqEl0(NativeInterface.GetCntfrqEl0));
|
||||
SetDelegateInfo(new NativeInterfaceGetCntpctEl0(NativeInterface.GetCntpctEl0));
|
||||
SetDelegateInfo(new NativeInterfaceGetCntvctEl0(NativeInterface.GetCntvctEl0));
|
||||
SetDelegateInfo(new NativeInterfaceGetCtrEl0(NativeInterface.GetCtrEl0));
|
||||
SetDelegateInfo(new NativeInterfaceGetDczidEl0(NativeInterface.GetDczidEl0));
|
||||
SetDelegateInfo(new NativeInterfaceGetFunctionAddress(NativeInterface.GetFunctionAddress));
|
||||
SetDelegateInfo(new NativeInterfaceInvalidateCacheLine(NativeInterface.InvalidateCacheLine));
|
||||
SetDelegateInfo(new NativeInterfaceReadByte(NativeInterface.ReadByte));
|
||||
SetDelegateInfo(new NativeInterfaceReadUInt16(NativeInterface.ReadUInt16));
|
||||
SetDelegateInfo(new NativeInterfaceReadUInt32(NativeInterface.ReadUInt32));
|
||||
SetDelegateInfo(new NativeInterfaceReadUInt64(NativeInterface.ReadUInt64));
|
||||
SetDelegateInfo(new NativeInterfaceReadVector128(NativeInterface.ReadVector128));
|
||||
SetDelegateInfo(new NativeInterfaceSignalMemoryTracking(NativeInterface.SignalMemoryTracking));
|
||||
SetDelegateInfo(new NativeInterfaceSupervisorCall(NativeInterface.SupervisorCall));
|
||||
SetDelegateInfo(new NativeInterfaceThrowInvalidMemoryAccess(NativeInterface.ThrowInvalidMemoryAccess));
|
||||
SetDelegateInfo(new NativeInterfaceUndefined(NativeInterface.Undefined));
|
||||
SetDelegateInfo(new NativeInterfaceWriteByte(NativeInterface.WriteByte));
|
||||
SetDelegateInfo(new NativeInterfaceWriteUInt16(NativeInterface.WriteUInt16));
|
||||
SetDelegateInfo(new NativeInterfaceWriteUInt32(NativeInterface.WriteUInt32));
|
||||
SetDelegateInfo(new NativeInterfaceWriteUInt64(NativeInterface.WriteUInt64));
|
||||
SetDelegateInfo(new NativeInterfaceWriteVector128(NativeInterface.WriteVector128));
|
||||
var dlgNativeInterfaceBreak = new NativeInterfaceBreak(NativeInterface.Break);
|
||||
var dlgNativeInterfaceCheckSynchronization = new NativeInterfaceCheckSynchronization(NativeInterface.CheckSynchronization);
|
||||
var dlgNativeInterfaceEnqueueForRejit = new NativeInterfaceEnqueueForRejit(NativeInterface.EnqueueForRejit);
|
||||
var dlgNativeInterfaceGetCntfrqEl0 = new NativeInterfaceGetCntfrqEl0(NativeInterface.GetCntfrqEl0);
|
||||
var dlgNativeInterfaceGetCntpctEl0 = new NativeInterfaceGetCntpctEl0(NativeInterface.GetCntpctEl0);
|
||||
var dlgNativeInterfaceGetCntvctEl0 = new NativeInterfaceGetCntvctEl0(NativeInterface.GetCntvctEl0);
|
||||
var dlgNativeInterfaceGetCtrEl0 = new NativeInterfaceGetCtrEl0(NativeInterface.GetCtrEl0);
|
||||
var dlgNativeInterfaceGetDczidEl0 = new NativeInterfaceGetDczidEl0(NativeInterface.GetDczidEl0);
|
||||
var dlgNativeInterfaceGetFunctionAddress = new NativeInterfaceGetFunctionAddress(NativeInterface.GetFunctionAddress);
|
||||
var dlgNativeInterfaceInvalidateCacheLine = new NativeInterfaceInvalidateCacheLine(NativeInterface.InvalidateCacheLine);
|
||||
var dlgNativeInterfaceReadByte = new NativeInterfaceReadByte(NativeInterface.ReadByte);
|
||||
var dlgNativeInterfaceReadUInt16 = new NativeInterfaceReadUInt16(NativeInterface.ReadUInt16);
|
||||
var dlgNativeInterfaceReadUInt32 = new NativeInterfaceReadUInt32(NativeInterface.ReadUInt32);
|
||||
var dlgNativeInterfaceReadUInt64 = new NativeInterfaceReadUInt64(NativeInterface.ReadUInt64);
|
||||
var dlgNativeInterfaceReadVector128 = new NativeInterfaceReadVector128(NativeInterface.ReadVector128);
|
||||
var dlgNativeInterfaceSignalMemoryTracking = new NativeInterfaceSignalMemoryTracking(NativeInterface.SignalMemoryTracking);
|
||||
var dlgNativeInterfaceSupervisorCall = new NativeInterfaceSupervisorCall(NativeInterface.SupervisorCall);
|
||||
var dlgNativeInterfaceThrowInvalidMemoryAccess = new NativeInterfaceThrowInvalidMemoryAccess(NativeInterface.ThrowInvalidMemoryAccess);
|
||||
var dlgNativeInterfaceUndefined = new NativeInterfaceUndefined(NativeInterface.Undefined);
|
||||
var dlgNativeInterfaceWriteByte = new NativeInterfaceWriteByte(NativeInterface.WriteByte);
|
||||
var dlgNativeInterfaceWriteUInt16 = new NativeInterfaceWriteUInt16(NativeInterface.WriteUInt16);
|
||||
var dlgNativeInterfaceWriteUInt32 = new NativeInterfaceWriteUInt32(NativeInterface.WriteUInt32);
|
||||
var dlgNativeInterfaceWriteUInt64 = new NativeInterfaceWriteUInt64(NativeInterface.WriteUInt64);
|
||||
var dlgNativeInterfaceWriteVector128 = new NativeInterfaceWriteVector128(NativeInterface.WriteVector128);
|
||||
|
||||
SetDelegateInfo(new SoftFallbackCountLeadingSigns(SoftFallback.CountLeadingSigns));
|
||||
SetDelegateInfo(new SoftFallbackCountLeadingZeros(SoftFallback.CountLeadingZeros));
|
||||
SetDelegateInfo(new SoftFallbackCrc32b(SoftFallback.Crc32b));
|
||||
SetDelegateInfo(new SoftFallbackCrc32cb(SoftFallback.Crc32cb));
|
||||
SetDelegateInfo(new SoftFallbackCrc32ch(SoftFallback.Crc32ch));
|
||||
SetDelegateInfo(new SoftFallbackCrc32cw(SoftFallback.Crc32cw));
|
||||
SetDelegateInfo(new SoftFallbackCrc32cx(SoftFallback.Crc32cx));
|
||||
SetDelegateInfo(new SoftFallbackCrc32h(SoftFallback.Crc32h));
|
||||
SetDelegateInfo(new SoftFallbackCrc32w(SoftFallback.Crc32w));
|
||||
SetDelegateInfo(new SoftFallbackCrc32x(SoftFallback.Crc32x));
|
||||
SetDelegateInfo(new SoftFallbackDecrypt(SoftFallback.Decrypt));
|
||||
SetDelegateInfo(new SoftFallbackEncrypt(SoftFallback.Encrypt));
|
||||
SetDelegateInfo(new SoftFallbackFixedRotate(SoftFallback.FixedRotate));
|
||||
SetDelegateInfo(new SoftFallbackHashChoose(SoftFallback.HashChoose));
|
||||
SetDelegateInfo(new SoftFallbackHashLower(SoftFallback.HashLower));
|
||||
SetDelegateInfo(new SoftFallbackHashMajority(SoftFallback.HashMajority));
|
||||
SetDelegateInfo(new SoftFallbackHashParity(SoftFallback.HashParity));
|
||||
SetDelegateInfo(new SoftFallbackHashUpper(SoftFallback.HashUpper));
|
||||
SetDelegateInfo(new SoftFallbackInverseMixColumns(SoftFallback.InverseMixColumns));
|
||||
SetDelegateInfo(new SoftFallbackMixColumns(SoftFallback.MixColumns));
|
||||
SetDelegateInfo(new SoftFallbackPolynomialMult64_128(SoftFallback.PolynomialMult64_128));
|
||||
SetDelegateInfo(new SoftFallbackSatF32ToS32(SoftFallback.SatF32ToS32));
|
||||
SetDelegateInfo(new SoftFallbackSatF32ToS64(SoftFallback.SatF32ToS64));
|
||||
SetDelegateInfo(new SoftFallbackSatF32ToU32(SoftFallback.SatF32ToU32));
|
||||
SetDelegateInfo(new SoftFallbackSatF32ToU64(SoftFallback.SatF32ToU64));
|
||||
SetDelegateInfo(new SoftFallbackSatF64ToS32(SoftFallback.SatF64ToS32));
|
||||
SetDelegateInfo(new SoftFallbackSatF64ToS64(SoftFallback.SatF64ToS64));
|
||||
SetDelegateInfo(new SoftFallbackSatF64ToU32(SoftFallback.SatF64ToU32));
|
||||
SetDelegateInfo(new SoftFallbackSatF64ToU64(SoftFallback.SatF64ToU64));
|
||||
SetDelegateInfo(new SoftFallbackSha1SchedulePart1(SoftFallback.Sha1SchedulePart1));
|
||||
SetDelegateInfo(new SoftFallbackSha1SchedulePart2(SoftFallback.Sha1SchedulePart2));
|
||||
SetDelegateInfo(new SoftFallbackSha256SchedulePart1(SoftFallback.Sha256SchedulePart1));
|
||||
SetDelegateInfo(new SoftFallbackSha256SchedulePart2(SoftFallback.Sha256SchedulePart2));
|
||||
SetDelegateInfo(new SoftFallbackSignedShrImm64(SoftFallback.SignedShrImm64));
|
||||
SetDelegateInfo(new SoftFallbackTbl1(SoftFallback.Tbl1));
|
||||
SetDelegateInfo(new SoftFallbackTbl2(SoftFallback.Tbl2));
|
||||
SetDelegateInfo(new SoftFallbackTbl3(SoftFallback.Tbl3));
|
||||
SetDelegateInfo(new SoftFallbackTbl4(SoftFallback.Tbl4));
|
||||
SetDelegateInfo(new SoftFallbackTbx1(SoftFallback.Tbx1));
|
||||
SetDelegateInfo(new SoftFallbackTbx2(SoftFallback.Tbx2));
|
||||
SetDelegateInfo(new SoftFallbackTbx3(SoftFallback.Tbx3));
|
||||
SetDelegateInfo(new SoftFallbackTbx4(SoftFallback.Tbx4));
|
||||
SetDelegateInfo(new SoftFallbackUnsignedShrImm64(SoftFallback.UnsignedShrImm64));
|
||||
var dlgSoftFallbackCountLeadingSigns = new SoftFallbackCountLeadingSigns(SoftFallback.CountLeadingSigns);
|
||||
var dlgSoftFallbackCountLeadingZeros = new SoftFallbackCountLeadingZeros(SoftFallback.CountLeadingZeros);
|
||||
var dlgSoftFallbackCrc32b = new SoftFallbackCrc32b(SoftFallback.Crc32b);
|
||||
var dlgSoftFallbackCrc32cb = new SoftFallbackCrc32cb(SoftFallback.Crc32cb);
|
||||
var dlgSoftFallbackCrc32ch = new SoftFallbackCrc32ch(SoftFallback.Crc32ch);
|
||||
var dlgSoftFallbackCrc32cw = new SoftFallbackCrc32cw(SoftFallback.Crc32cw);
|
||||
var dlgSoftFallbackCrc32cx = new SoftFallbackCrc32cx(SoftFallback.Crc32cx);
|
||||
var dlgSoftFallbackCrc32h = new SoftFallbackCrc32h(SoftFallback.Crc32h);
|
||||
var dlgSoftFallbackCrc32w = new SoftFallbackCrc32w(SoftFallback.Crc32w);
|
||||
var dlgSoftFallbackCrc32x = new SoftFallbackCrc32x(SoftFallback.Crc32x);
|
||||
var dlgSoftFallbackDecrypt = new SoftFallbackDecrypt(SoftFallback.Decrypt);
|
||||
var dlgSoftFallbackEncrypt = new SoftFallbackEncrypt(SoftFallback.Encrypt);
|
||||
var dlgSoftFallbackFixedRotate = new SoftFallbackFixedRotate(SoftFallback.FixedRotate);
|
||||
var dlgSoftFallbackHashChoose = new SoftFallbackHashChoose(SoftFallback.HashChoose);
|
||||
var dlgSoftFallbackHashLower = new SoftFallbackHashLower(SoftFallback.HashLower);
|
||||
var dlgSoftFallbackHashMajority = new SoftFallbackHashMajority(SoftFallback.HashMajority);
|
||||
var dlgSoftFallbackHashParity = new SoftFallbackHashParity(SoftFallback.HashParity);
|
||||
var dlgSoftFallbackHashUpper = new SoftFallbackHashUpper(SoftFallback.HashUpper);
|
||||
var dlgSoftFallbackInverseMixColumns = new SoftFallbackInverseMixColumns(SoftFallback.InverseMixColumns);
|
||||
var dlgSoftFallbackMixColumns = new SoftFallbackMixColumns(SoftFallback.MixColumns);
|
||||
var dlgSoftFallbackPolynomialMult64_128 = new SoftFallbackPolynomialMult64_128(SoftFallback.PolynomialMult64_128);
|
||||
var dlgSoftFallbackSatF32ToS32 = new SoftFallbackSatF32ToS32(SoftFallback.SatF32ToS32);
|
||||
var dlgSoftFallbackSatF32ToS64 = new SoftFallbackSatF32ToS64(SoftFallback.SatF32ToS64);
|
||||
var dlgSoftFallbackSatF32ToU32 = new SoftFallbackSatF32ToU32(SoftFallback.SatF32ToU32);
|
||||
var dlgSoftFallbackSatF32ToU64 = new SoftFallbackSatF32ToU64(SoftFallback.SatF32ToU64);
|
||||
var dlgSoftFallbackSatF64ToS32 = new SoftFallbackSatF64ToS32(SoftFallback.SatF64ToS32);
|
||||
var dlgSoftFallbackSatF64ToS64 = new SoftFallbackSatF64ToS64(SoftFallback.SatF64ToS64);
|
||||
var dlgSoftFallbackSatF64ToU32 = new SoftFallbackSatF64ToU32(SoftFallback.SatF64ToU32);
|
||||
var dlgSoftFallbackSatF64ToU64 = new SoftFallbackSatF64ToU64(SoftFallback.SatF64ToU64);
|
||||
var dlgSoftFallbackSha1SchedulePart1 = new SoftFallbackSha1SchedulePart1(SoftFallback.Sha1SchedulePart1);
|
||||
var dlgSoftFallbackSha1SchedulePart2 = new SoftFallbackSha1SchedulePart2(SoftFallback.Sha1SchedulePart2);
|
||||
var dlgSoftFallbackSha256SchedulePart1 = new SoftFallbackSha256SchedulePart1(SoftFallback.Sha256SchedulePart1);
|
||||
var dlgSoftFallbackSha256SchedulePart2 = new SoftFallbackSha256SchedulePart2(SoftFallback.Sha256SchedulePart2);
|
||||
var dlgSoftFallbackSignedShrImm64 = new SoftFallbackSignedShrImm64(SoftFallback.SignedShrImm64);
|
||||
var dlgSoftFallbackTbl1 = new SoftFallbackTbl1(SoftFallback.Tbl1);
|
||||
var dlgSoftFallbackTbl2 = new SoftFallbackTbl2(SoftFallback.Tbl2);
|
||||
var dlgSoftFallbackTbl3 = new SoftFallbackTbl3(SoftFallback.Tbl3);
|
||||
var dlgSoftFallbackTbl4 = new SoftFallbackTbl4(SoftFallback.Tbl4);
|
||||
var dlgSoftFallbackTbx1 = new SoftFallbackTbx1(SoftFallback.Tbx1);
|
||||
var dlgSoftFallbackTbx2 = new SoftFallbackTbx2(SoftFallback.Tbx2);
|
||||
var dlgSoftFallbackTbx3 = new SoftFallbackTbx3(SoftFallback.Tbx3);
|
||||
var dlgSoftFallbackTbx4 = new SoftFallbackTbx4(SoftFallback.Tbx4);
|
||||
var dlgSoftFallbackUnsignedShrImm64 = new SoftFallbackUnsignedShrImm64(SoftFallback.UnsignedShrImm64);
|
||||
|
||||
SetDelegateInfo(new SoftFloat16_32FPConvert(SoftFloat16_32.FPConvert));
|
||||
SetDelegateInfo(new SoftFloat16_64FPConvert(SoftFloat16_64.FPConvert));
|
||||
var dlgSoftFloat16_32FPConvert = new SoftFloat16_32FPConvert(SoftFloat16_32.FPConvert);
|
||||
var dlgSoftFloat16_64FPConvert = new SoftFloat16_64FPConvert(SoftFloat16_64.FPConvert);
|
||||
|
||||
SetDelegateInfo(new SoftFloat32FPAdd(SoftFloat32.FPAdd));
|
||||
SetDelegateInfo(new SoftFloat32FPAddFpscr(SoftFloat32.FPAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPCompare(SoftFloat32.FPCompare));
|
||||
SetDelegateInfo(new SoftFloat32FPCompareEQ(SoftFloat32.FPCompareEQ));
|
||||
SetDelegateInfo(new SoftFloat32FPCompareEQFpscr(SoftFloat32.FPCompareEQFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPCompareGE(SoftFloat32.FPCompareGE));
|
||||
SetDelegateInfo(new SoftFloat32FPCompareGEFpscr(SoftFloat32.FPCompareGEFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPCompareGT(SoftFloat32.FPCompareGT));
|
||||
SetDelegateInfo(new SoftFloat32FPCompareGTFpscr(SoftFloat32.FPCompareGTFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPCompareLE(SoftFloat32.FPCompareLE));
|
||||
SetDelegateInfo(new SoftFloat32FPCompareLEFpscr(SoftFloat32.FPCompareLEFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPCompareLT(SoftFloat32.FPCompareLT));
|
||||
SetDelegateInfo(new SoftFloat32FPCompareLTFpscr(SoftFloat32.FPCompareLTFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPDiv(SoftFloat32.FPDiv));
|
||||
SetDelegateInfo(new SoftFloat32FPMax(SoftFloat32.FPMax));
|
||||
SetDelegateInfo(new SoftFloat32FPMaxFpscr(SoftFloat32.FPMaxFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPMaxNum(SoftFloat32.FPMaxNum));
|
||||
SetDelegateInfo(new SoftFloat32FPMaxNumFpscr(SoftFloat32.FPMaxNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPMin(SoftFloat32.FPMin));
|
||||
SetDelegateInfo(new SoftFloat32FPMinFpscr(SoftFloat32.FPMinFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPMinNum(SoftFloat32.FPMinNum));
|
||||
SetDelegateInfo(new SoftFloat32FPMinNumFpscr(SoftFloat32.FPMinNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPMul(SoftFloat32.FPMul));
|
||||
SetDelegateInfo(new SoftFloat32FPMulFpscr(SoftFloat32.FPMulFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPMulAdd(SoftFloat32.FPMulAdd));
|
||||
SetDelegateInfo(new SoftFloat32FPMulAddFpscr(SoftFloat32.FPMulAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPMulSub(SoftFloat32.FPMulSub));
|
||||
SetDelegateInfo(new SoftFloat32FPMulSubFpscr(SoftFloat32.FPMulSubFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPMulX(SoftFloat32.FPMulX));
|
||||
SetDelegateInfo(new SoftFloat32FPNegMulAdd(SoftFloat32.FPNegMulAdd));
|
||||
SetDelegateInfo(new SoftFloat32FPNegMulSub(SoftFloat32.FPNegMulSub));
|
||||
SetDelegateInfo(new SoftFloat32FPRecipEstimate(SoftFloat32.FPRecipEstimate));
|
||||
SetDelegateInfo(new SoftFloat32FPRecipEstimateFpscr(SoftFloat32.FPRecipEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPRecipStep(SoftFloat32.FPRecipStep)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPRecipStepFused(SoftFloat32.FPRecipStepFused));
|
||||
SetDelegateInfo(new SoftFloat32FPRecpX(SoftFloat32.FPRecpX));
|
||||
SetDelegateInfo(new SoftFloat32FPRSqrtEstimate(SoftFloat32.FPRSqrtEstimate));
|
||||
SetDelegateInfo(new SoftFloat32FPRSqrtEstimateFpscr(SoftFloat32.FPRSqrtEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPRSqrtStep(SoftFloat32.FPRSqrtStep)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat32FPRSqrtStepFused(SoftFloat32.FPRSqrtStepFused));
|
||||
SetDelegateInfo(new SoftFloat32FPSqrt(SoftFloat32.FPSqrt));
|
||||
SetDelegateInfo(new SoftFloat32FPSub(SoftFloat32.FPSub));
|
||||
var dlgSoftFloat32FPAdd = new SoftFloat32FPAdd(SoftFloat32.FPAdd);
|
||||
var dlgSoftFloat32FPAddFpscr = new SoftFloat32FPAddFpscr(SoftFloat32.FPAddFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompare = new SoftFloat32FPCompare(SoftFloat32.FPCompare);
|
||||
var dlgSoftFloat32FPCompareEQ = new SoftFloat32FPCompareEQ(SoftFloat32.FPCompareEQ);
|
||||
var dlgSoftFloat32FPCompareEQFpscr = new SoftFloat32FPCompareEQFpscr(SoftFloat32.FPCompareEQFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompareGE = new SoftFloat32FPCompareGE(SoftFloat32.FPCompareGE);
|
||||
var dlgSoftFloat32FPCompareGEFpscr = new SoftFloat32FPCompareGEFpscr(SoftFloat32.FPCompareGEFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompareGT = new SoftFloat32FPCompareGT(SoftFloat32.FPCompareGT);
|
||||
var dlgSoftFloat32FPCompareGTFpscr = new SoftFloat32FPCompareGTFpscr(SoftFloat32.FPCompareGTFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompareLE = new SoftFloat32FPCompareLE(SoftFloat32.FPCompareLE);
|
||||
var dlgSoftFloat32FPCompareLEFpscr = new SoftFloat32FPCompareLEFpscr(SoftFloat32.FPCompareLEFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPCompareLT = new SoftFloat32FPCompareLT(SoftFloat32.FPCompareLT);
|
||||
var dlgSoftFloat32FPCompareLTFpscr = new SoftFloat32FPCompareLTFpscr(SoftFloat32.FPCompareLTFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPDiv = new SoftFloat32FPDiv(SoftFloat32.FPDiv);
|
||||
var dlgSoftFloat32FPMax = new SoftFloat32FPMax(SoftFloat32.FPMax);
|
||||
var dlgSoftFloat32FPMaxFpscr = new SoftFloat32FPMaxFpscr(SoftFloat32.FPMaxFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMaxNum = new SoftFloat32FPMaxNum(SoftFloat32.FPMaxNum);
|
||||
var dlgSoftFloat32FPMaxNumFpscr = new SoftFloat32FPMaxNumFpscr(SoftFloat32.FPMaxNumFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMin = new SoftFloat32FPMin(SoftFloat32.FPMin);
|
||||
var dlgSoftFloat32FPMinFpscr = new SoftFloat32FPMinFpscr(SoftFloat32.FPMinFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMinNum = new SoftFloat32FPMinNum(SoftFloat32.FPMinNum);
|
||||
var dlgSoftFloat32FPMinNumFpscr = new SoftFloat32FPMinNumFpscr(SoftFloat32.FPMinNumFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMul = new SoftFloat32FPMul(SoftFloat32.FPMul);
|
||||
var dlgSoftFloat32FPMulFpscr = new SoftFloat32FPMulFpscr(SoftFloat32.FPMulFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMulAdd = new SoftFloat32FPMulAdd(SoftFloat32.FPMulAdd);
|
||||
var dlgSoftFloat32FPMulAddFpscr = new SoftFloat32FPMulAddFpscr(SoftFloat32.FPMulAddFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMulSub = new SoftFloat32FPMulSub(SoftFloat32.FPMulSub);
|
||||
var dlgSoftFloat32FPMulSubFpscr = new SoftFloat32FPMulSubFpscr(SoftFloat32.FPMulSubFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPMulX = new SoftFloat32FPMulX(SoftFloat32.FPMulX);
|
||||
var dlgSoftFloat32FPNegMulAdd = new SoftFloat32FPNegMulAdd(SoftFloat32.FPNegMulAdd);
|
||||
var dlgSoftFloat32FPNegMulSub = new SoftFloat32FPNegMulSub(SoftFloat32.FPNegMulSub);
|
||||
var dlgSoftFloat32FPRecipEstimate = new SoftFloat32FPRecipEstimate(SoftFloat32.FPRecipEstimate);
|
||||
var dlgSoftFloat32FPRecipEstimateFpscr = new SoftFloat32FPRecipEstimateFpscr(SoftFloat32.FPRecipEstimateFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPRecipStep = new SoftFloat32FPRecipStep(SoftFloat32.FPRecipStep); // A32 only.
|
||||
var dlgSoftFloat32FPRecipStepFused = new SoftFloat32FPRecipStepFused(SoftFloat32.FPRecipStepFused);
|
||||
var dlgSoftFloat32FPRecpX = new SoftFloat32FPRecpX(SoftFloat32.FPRecpX);
|
||||
var dlgSoftFloat32FPRSqrtEstimate = new SoftFloat32FPRSqrtEstimate(SoftFloat32.FPRSqrtEstimate);
|
||||
var dlgSoftFloat32FPRSqrtEstimateFpscr = new SoftFloat32FPRSqrtEstimateFpscr(SoftFloat32.FPRSqrtEstimateFpscr); // A32 only.
|
||||
var dlgSoftFloat32FPRSqrtStep = new SoftFloat32FPRSqrtStep(SoftFloat32.FPRSqrtStep); // A32 only.
|
||||
var dlgSoftFloat32FPRSqrtStepFused = new SoftFloat32FPRSqrtStepFused(SoftFloat32.FPRSqrtStepFused);
|
||||
var dlgSoftFloat32FPSqrt = new SoftFloat32FPSqrt(SoftFloat32.FPSqrt);
|
||||
var dlgSoftFloat32FPSub = new SoftFloat32FPSub(SoftFloat32.FPSub);
|
||||
|
||||
SetDelegateInfo(new SoftFloat32_16FPConvert(SoftFloat32_16.FPConvert));
|
||||
var dlgSoftFloat32_16FPConvert = new SoftFloat32_16FPConvert(SoftFloat32_16.FPConvert);
|
||||
|
||||
SetDelegateInfo(new SoftFloat64FPAdd(SoftFloat64.FPAdd));
|
||||
SetDelegateInfo(new SoftFloat64FPAddFpscr(SoftFloat64.FPAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPCompare(SoftFloat64.FPCompare));
|
||||
SetDelegateInfo(new SoftFloat64FPCompareEQ(SoftFloat64.FPCompareEQ));
|
||||
SetDelegateInfo(new SoftFloat64FPCompareEQFpscr(SoftFloat64.FPCompareEQFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPCompareGE(SoftFloat64.FPCompareGE));
|
||||
SetDelegateInfo(new SoftFloat64FPCompareGEFpscr(SoftFloat64.FPCompareGEFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPCompareGT(SoftFloat64.FPCompareGT));
|
||||
SetDelegateInfo(new SoftFloat64FPCompareGTFpscr(SoftFloat64.FPCompareGTFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPCompareLE(SoftFloat64.FPCompareLE));
|
||||
SetDelegateInfo(new SoftFloat64FPCompareLEFpscr(SoftFloat64.FPCompareLEFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPCompareLT(SoftFloat64.FPCompareLT));
|
||||
SetDelegateInfo(new SoftFloat64FPCompareLTFpscr(SoftFloat64.FPCompareLTFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPDiv(SoftFloat64.FPDiv));
|
||||
SetDelegateInfo(new SoftFloat64FPMax(SoftFloat64.FPMax));
|
||||
SetDelegateInfo(new SoftFloat64FPMaxFpscr(SoftFloat64.FPMaxFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPMaxNum(SoftFloat64.FPMaxNum));
|
||||
SetDelegateInfo(new SoftFloat64FPMaxNumFpscr(SoftFloat64.FPMaxNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPMin(SoftFloat64.FPMin));
|
||||
SetDelegateInfo(new SoftFloat64FPMinFpscr(SoftFloat64.FPMinFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPMinNum(SoftFloat64.FPMinNum));
|
||||
SetDelegateInfo(new SoftFloat64FPMinNumFpscr(SoftFloat64.FPMinNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPMul(SoftFloat64.FPMul));
|
||||
SetDelegateInfo(new SoftFloat64FPMulFpscr(SoftFloat64.FPMulFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPMulAdd(SoftFloat64.FPMulAdd));
|
||||
SetDelegateInfo(new SoftFloat64FPMulAddFpscr(SoftFloat64.FPMulAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPMulSub(SoftFloat64.FPMulSub));
|
||||
SetDelegateInfo(new SoftFloat64FPMulSubFpscr(SoftFloat64.FPMulSubFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPMulX(SoftFloat64.FPMulX));
|
||||
SetDelegateInfo(new SoftFloat64FPNegMulAdd(SoftFloat64.FPNegMulAdd));
|
||||
SetDelegateInfo(new SoftFloat64FPNegMulSub(SoftFloat64.FPNegMulSub));
|
||||
SetDelegateInfo(new SoftFloat64FPRecipEstimate(SoftFloat64.FPRecipEstimate));
|
||||
SetDelegateInfo(new SoftFloat64FPRecipEstimateFpscr(SoftFloat64.FPRecipEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPRecipStep(SoftFloat64.FPRecipStep)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPRecipStepFused(SoftFloat64.FPRecipStepFused));
|
||||
SetDelegateInfo(new SoftFloat64FPRecpX(SoftFloat64.FPRecpX));
|
||||
SetDelegateInfo(new SoftFloat64FPRSqrtEstimate(SoftFloat64.FPRSqrtEstimate));
|
||||
SetDelegateInfo(new SoftFloat64FPRSqrtEstimateFpscr(SoftFloat64.FPRSqrtEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPRSqrtStep(SoftFloat64.FPRSqrtStep)); // A32 only.
|
||||
SetDelegateInfo(new SoftFloat64FPRSqrtStepFused(SoftFloat64.FPRSqrtStepFused));
|
||||
SetDelegateInfo(new SoftFloat64FPSqrt(SoftFloat64.FPSqrt));
|
||||
SetDelegateInfo(new SoftFloat64FPSub(SoftFloat64.FPSub));
|
||||
var dlgSoftFloat64FPAdd = new SoftFloat64FPAdd(SoftFloat64.FPAdd);
|
||||
var dlgSoftFloat64FPAddFpscr = new SoftFloat64FPAddFpscr(SoftFloat64.FPAddFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompare = new SoftFloat64FPCompare(SoftFloat64.FPCompare);
|
||||
var dlgSoftFloat64FPCompareEQ = new SoftFloat64FPCompareEQ(SoftFloat64.FPCompareEQ);
|
||||
var dlgSoftFloat64FPCompareEQFpscr = new SoftFloat64FPCompareEQFpscr(SoftFloat64.FPCompareEQFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompareGE = new SoftFloat64FPCompareGE(SoftFloat64.FPCompareGE);
|
||||
var dlgSoftFloat64FPCompareGEFpscr = new SoftFloat64FPCompareGEFpscr(SoftFloat64.FPCompareGEFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompareGT = new SoftFloat64FPCompareGT(SoftFloat64.FPCompareGT);
|
||||
var dlgSoftFloat64FPCompareGTFpscr = new SoftFloat64FPCompareGTFpscr(SoftFloat64.FPCompareGTFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompareLE = new SoftFloat64FPCompareLE(SoftFloat64.FPCompareLE);
|
||||
var dlgSoftFloat64FPCompareLEFpscr = new SoftFloat64FPCompareLEFpscr(SoftFloat64.FPCompareLEFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPCompareLT = new SoftFloat64FPCompareLT(SoftFloat64.FPCompareLT);
|
||||
var dlgSoftFloat64FPCompareLTFpscr = new SoftFloat64FPCompareLTFpscr(SoftFloat64.FPCompareLTFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPDiv = new SoftFloat64FPDiv(SoftFloat64.FPDiv);
|
||||
var dlgSoftFloat64FPMax = new SoftFloat64FPMax(SoftFloat64.FPMax);
|
||||
var dlgSoftFloat64FPMaxFpscr = new SoftFloat64FPMaxFpscr(SoftFloat64.FPMaxFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMaxNum = new SoftFloat64FPMaxNum(SoftFloat64.FPMaxNum);
|
||||
var dlgSoftFloat64FPMaxNumFpscr = new SoftFloat64FPMaxNumFpscr(SoftFloat64.FPMaxNumFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMin = new SoftFloat64FPMin(SoftFloat64.FPMin);
|
||||
var dlgSoftFloat64FPMinFpscr = new SoftFloat64FPMinFpscr(SoftFloat64.FPMinFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMinNum = new SoftFloat64FPMinNum(SoftFloat64.FPMinNum);
|
||||
var dlgSoftFloat64FPMinNumFpscr = new SoftFloat64FPMinNumFpscr(SoftFloat64.FPMinNumFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMul = new SoftFloat64FPMul(SoftFloat64.FPMul);
|
||||
var dlgSoftFloat64FPMulFpscr = new SoftFloat64FPMulFpscr(SoftFloat64.FPMulFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMulAdd = new SoftFloat64FPMulAdd(SoftFloat64.FPMulAdd);
|
||||
var dlgSoftFloat64FPMulAddFpscr = new SoftFloat64FPMulAddFpscr(SoftFloat64.FPMulAddFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMulSub = new SoftFloat64FPMulSub(SoftFloat64.FPMulSub);
|
||||
var dlgSoftFloat64FPMulSubFpscr = new SoftFloat64FPMulSubFpscr(SoftFloat64.FPMulSubFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPMulX = new SoftFloat64FPMulX(SoftFloat64.FPMulX);
|
||||
var dlgSoftFloat64FPNegMulAdd = new SoftFloat64FPNegMulAdd(SoftFloat64.FPNegMulAdd);
|
||||
var dlgSoftFloat64FPNegMulSub = new SoftFloat64FPNegMulSub(SoftFloat64.FPNegMulSub);
|
||||
var dlgSoftFloat64FPRecipEstimate = new SoftFloat64FPRecipEstimate(SoftFloat64.FPRecipEstimate);
|
||||
var dlgSoftFloat64FPRecipEstimateFpscr = new SoftFloat64FPRecipEstimateFpscr(SoftFloat64.FPRecipEstimateFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPRecipStep = new SoftFloat64FPRecipStep(SoftFloat64.FPRecipStep); // A32 only.
|
||||
var dlgSoftFloat64FPRecipStepFused = new SoftFloat64FPRecipStepFused(SoftFloat64.FPRecipStepFused);
|
||||
var dlgSoftFloat64FPRecpX = new SoftFloat64FPRecpX(SoftFloat64.FPRecpX);
|
||||
var dlgSoftFloat64FPRSqrtEstimate = new SoftFloat64FPRSqrtEstimate(SoftFloat64.FPRSqrtEstimate);
|
||||
var dlgSoftFloat64FPRSqrtEstimateFpscr = new SoftFloat64FPRSqrtEstimateFpscr(SoftFloat64.FPRSqrtEstimateFpscr); // A32 only.
|
||||
var dlgSoftFloat64FPRSqrtStep = new SoftFloat64FPRSqrtStep(SoftFloat64.FPRSqrtStep); // A32 only.
|
||||
var dlgSoftFloat64FPRSqrtStepFused = new SoftFloat64FPRSqrtStepFused(SoftFloat64.FPRSqrtStepFused);
|
||||
var dlgSoftFloat64FPSqrt = new SoftFloat64FPSqrt(SoftFloat64.FPSqrt);
|
||||
var dlgSoftFloat64FPSub = new SoftFloat64FPSub(SoftFloat64.FPSub);
|
||||
|
||||
SetDelegateInfo(new SoftFloat64_16FPConvert(SoftFloat64_16.FPConvert));
|
||||
var dlgSoftFloat64_16FPConvert = new SoftFloat64_16FPConvert(SoftFloat64_16.FPConvert);
|
||||
|
||||
SetDelegateInfo(dlgMathAbs, Marshal.GetFunctionPointerForDelegate<MathAbs>(dlgMathAbs));
|
||||
SetDelegateInfo(dlgMathCeiling, Marshal.GetFunctionPointerForDelegate<MathCeiling>(dlgMathCeiling));
|
||||
SetDelegateInfo(dlgMathFloor, Marshal.GetFunctionPointerForDelegate<MathFloor>(dlgMathFloor));
|
||||
SetDelegateInfo(dlgMathRound, Marshal.GetFunctionPointerForDelegate<MathRound>(dlgMathRound));
|
||||
SetDelegateInfo(dlgMathTruncate, Marshal.GetFunctionPointerForDelegate<MathTruncate>(dlgMathTruncate));
|
||||
|
||||
SetDelegateInfo(dlgMathFAbs, Marshal.GetFunctionPointerForDelegate<MathFAbs>(dlgMathFAbs));
|
||||
SetDelegateInfo(dlgMathFCeiling, Marshal.GetFunctionPointerForDelegate<MathFCeiling>(dlgMathFCeiling));
|
||||
SetDelegateInfo(dlgMathFFloor, Marshal.GetFunctionPointerForDelegate<MathFFloor>(dlgMathFFloor));
|
||||
SetDelegateInfo(dlgMathFRound, Marshal.GetFunctionPointerForDelegate<MathFRound>(dlgMathFRound));
|
||||
SetDelegateInfo(dlgMathFTruncate, Marshal.GetFunctionPointerForDelegate<MathFTruncate>(dlgMathFTruncate));
|
||||
|
||||
SetDelegateInfo(dlgNativeInterfaceBreak, Marshal.GetFunctionPointerForDelegate<NativeInterfaceBreak>(dlgNativeInterfaceBreak));
|
||||
SetDelegateInfo(dlgNativeInterfaceCheckSynchronization, Marshal.GetFunctionPointerForDelegate<NativeInterfaceCheckSynchronization>(dlgNativeInterfaceCheckSynchronization));
|
||||
SetDelegateInfo(dlgNativeInterfaceEnqueueForRejit, Marshal.GetFunctionPointerForDelegate<NativeInterfaceEnqueueForRejit>(dlgNativeInterfaceEnqueueForRejit));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetCntfrqEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntfrqEl0>(dlgNativeInterfaceGetCntfrqEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetCntpctEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntpctEl0>(dlgNativeInterfaceGetCntpctEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetCntvctEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCntvctEl0>(dlgNativeInterfaceGetCntvctEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetCtrEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetCtrEl0>(dlgNativeInterfaceGetCtrEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetDczidEl0, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetDczidEl0>(dlgNativeInterfaceGetDczidEl0));
|
||||
SetDelegateInfo(dlgNativeInterfaceGetFunctionAddress, Marshal.GetFunctionPointerForDelegate<NativeInterfaceGetFunctionAddress>(dlgNativeInterfaceGetFunctionAddress));
|
||||
SetDelegateInfo(dlgNativeInterfaceInvalidateCacheLine, Marshal.GetFunctionPointerForDelegate<NativeInterfaceInvalidateCacheLine>(dlgNativeInterfaceInvalidateCacheLine));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadByte, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadByte>(dlgNativeInterfaceReadByte));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadUInt16, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt16>(dlgNativeInterfaceReadUInt16));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadUInt32, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt32>(dlgNativeInterfaceReadUInt32));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadUInt64, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadUInt64>(dlgNativeInterfaceReadUInt64));
|
||||
SetDelegateInfo(dlgNativeInterfaceReadVector128, Marshal.GetFunctionPointerForDelegate<NativeInterfaceReadVector128>(dlgNativeInterfaceReadVector128));
|
||||
SetDelegateInfo(dlgNativeInterfaceSignalMemoryTracking, Marshal.GetFunctionPointerForDelegate<NativeInterfaceSignalMemoryTracking>(dlgNativeInterfaceSignalMemoryTracking));
|
||||
SetDelegateInfo(dlgNativeInterfaceSupervisorCall, Marshal.GetFunctionPointerForDelegate<NativeInterfaceSupervisorCall>(dlgNativeInterfaceSupervisorCall));
|
||||
SetDelegateInfo(dlgNativeInterfaceThrowInvalidMemoryAccess, Marshal.GetFunctionPointerForDelegate<NativeInterfaceThrowInvalidMemoryAccess>(dlgNativeInterfaceThrowInvalidMemoryAccess));
|
||||
SetDelegateInfo(dlgNativeInterfaceUndefined, Marshal.GetFunctionPointerForDelegate<NativeInterfaceUndefined>(dlgNativeInterfaceUndefined));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteByte, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteByte>(dlgNativeInterfaceWriteByte));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteUInt16, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt16>(dlgNativeInterfaceWriteUInt16));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteUInt32, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt32>(dlgNativeInterfaceWriteUInt32));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteUInt64, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteUInt64>(dlgNativeInterfaceWriteUInt64));
|
||||
SetDelegateInfo(dlgNativeInterfaceWriteVector128, Marshal.GetFunctionPointerForDelegate<NativeInterfaceWriteVector128>(dlgNativeInterfaceWriteVector128));
|
||||
|
||||
SetDelegateInfo(dlgSoftFallbackCountLeadingSigns, Marshal.GetFunctionPointerForDelegate<SoftFallbackCountLeadingSigns>(dlgSoftFallbackCountLeadingSigns));
|
||||
SetDelegateInfo(dlgSoftFallbackCountLeadingZeros, Marshal.GetFunctionPointerForDelegate<SoftFallbackCountLeadingZeros>(dlgSoftFallbackCountLeadingZeros));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32b, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32b>(dlgSoftFallbackCrc32b));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32cb, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cb>(dlgSoftFallbackCrc32cb));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32ch, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32ch>(dlgSoftFallbackCrc32ch));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32cw, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cw>(dlgSoftFallbackCrc32cw));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32cx, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32cx>(dlgSoftFallbackCrc32cx));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32h, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32h>(dlgSoftFallbackCrc32h));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32w, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32w>(dlgSoftFallbackCrc32w));
|
||||
SetDelegateInfo(dlgSoftFallbackCrc32x, Marshal.GetFunctionPointerForDelegate<SoftFallbackCrc32x>(dlgSoftFallbackCrc32x));
|
||||
SetDelegateInfo(dlgSoftFallbackDecrypt, Marshal.GetFunctionPointerForDelegate<SoftFallbackDecrypt>(dlgSoftFallbackDecrypt));
|
||||
SetDelegateInfo(dlgSoftFallbackEncrypt, Marshal.GetFunctionPointerForDelegate<SoftFallbackEncrypt>(dlgSoftFallbackEncrypt));
|
||||
SetDelegateInfo(dlgSoftFallbackFixedRotate, Marshal.GetFunctionPointerForDelegate<SoftFallbackFixedRotate>(dlgSoftFallbackFixedRotate));
|
||||
SetDelegateInfo(dlgSoftFallbackHashChoose, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashChoose>(dlgSoftFallbackHashChoose));
|
||||
SetDelegateInfo(dlgSoftFallbackHashLower, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashLower>(dlgSoftFallbackHashLower));
|
||||
SetDelegateInfo(dlgSoftFallbackHashMajority, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashMajority>(dlgSoftFallbackHashMajority));
|
||||
SetDelegateInfo(dlgSoftFallbackHashParity, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashParity>(dlgSoftFallbackHashParity));
|
||||
SetDelegateInfo(dlgSoftFallbackHashUpper, Marshal.GetFunctionPointerForDelegate<SoftFallbackHashUpper>(dlgSoftFallbackHashUpper));
|
||||
SetDelegateInfo(dlgSoftFallbackInverseMixColumns, Marshal.GetFunctionPointerForDelegate<SoftFallbackInverseMixColumns>(dlgSoftFallbackInverseMixColumns));
|
||||
SetDelegateInfo(dlgSoftFallbackMixColumns, Marshal.GetFunctionPointerForDelegate<SoftFallbackMixColumns>(dlgSoftFallbackMixColumns));
|
||||
SetDelegateInfo(dlgSoftFallbackPolynomialMult64_128, Marshal.GetFunctionPointerForDelegate<SoftFallbackPolynomialMult64_128>(dlgSoftFallbackPolynomialMult64_128));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF32ToS32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToS32>(dlgSoftFallbackSatF32ToS32));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF32ToS64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToS64>(dlgSoftFallbackSatF32ToS64));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF32ToU32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToU32>(dlgSoftFallbackSatF32ToU32));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF32ToU64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF32ToU64>(dlgSoftFallbackSatF32ToU64));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF64ToS32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToS32>(dlgSoftFallbackSatF64ToS32));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF64ToS64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToS64>(dlgSoftFallbackSatF64ToS64));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF64ToU32, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToU32>(dlgSoftFallbackSatF64ToU32));
|
||||
SetDelegateInfo(dlgSoftFallbackSatF64ToU64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSatF64ToU64>(dlgSoftFallbackSatF64ToU64));
|
||||
SetDelegateInfo(dlgSoftFallbackSha1SchedulePart1, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha1SchedulePart1>(dlgSoftFallbackSha1SchedulePart1));
|
||||
SetDelegateInfo(dlgSoftFallbackSha1SchedulePart2, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha1SchedulePart2>(dlgSoftFallbackSha1SchedulePart2));
|
||||
SetDelegateInfo(dlgSoftFallbackSha256SchedulePart1, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha256SchedulePart1>(dlgSoftFallbackSha256SchedulePart1));
|
||||
SetDelegateInfo(dlgSoftFallbackSha256SchedulePart2, Marshal.GetFunctionPointerForDelegate<SoftFallbackSha256SchedulePart2>(dlgSoftFallbackSha256SchedulePart2));
|
||||
SetDelegateInfo(dlgSoftFallbackSignedShrImm64, Marshal.GetFunctionPointerForDelegate<SoftFallbackSignedShrImm64>(dlgSoftFallbackSignedShrImm64));
|
||||
SetDelegateInfo(dlgSoftFallbackTbl1, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl1>(dlgSoftFallbackTbl1));
|
||||
SetDelegateInfo(dlgSoftFallbackTbl2, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl2>(dlgSoftFallbackTbl2));
|
||||
SetDelegateInfo(dlgSoftFallbackTbl3, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl3>(dlgSoftFallbackTbl3));
|
||||
SetDelegateInfo(dlgSoftFallbackTbl4, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbl4>(dlgSoftFallbackTbl4));
|
||||
SetDelegateInfo(dlgSoftFallbackTbx1, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx1>(dlgSoftFallbackTbx1));
|
||||
SetDelegateInfo(dlgSoftFallbackTbx2, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx2>(dlgSoftFallbackTbx2));
|
||||
SetDelegateInfo(dlgSoftFallbackTbx3, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx3>(dlgSoftFallbackTbx3));
|
||||
SetDelegateInfo(dlgSoftFallbackTbx4, Marshal.GetFunctionPointerForDelegate<SoftFallbackTbx4>(dlgSoftFallbackTbx4));
|
||||
SetDelegateInfo(dlgSoftFallbackUnsignedShrImm64, Marshal.GetFunctionPointerForDelegate<SoftFallbackUnsignedShrImm64>(dlgSoftFallbackUnsignedShrImm64));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat16_32FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat16_32FPConvert>(dlgSoftFloat16_32FPConvert));
|
||||
SetDelegateInfo(dlgSoftFloat16_64FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat16_64FPConvert>(dlgSoftFloat16_64FPConvert));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat32FPAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPAdd>(dlgSoftFloat32FPAdd));
|
||||
SetDelegateInfo(dlgSoftFloat32FPAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPAddFpscr>(dlgSoftFloat32FPAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompare, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompare>(dlgSoftFloat32FPCompare));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareEQ, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareEQ>(dlgSoftFloat32FPCompareEQ));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareEQFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareEQFpscr>(dlgSoftFloat32FPCompareEQFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareGE, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGE>(dlgSoftFloat32FPCompareGE));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareGEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGEFpscr>(dlgSoftFloat32FPCompareGEFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareGT, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGT>(dlgSoftFloat32FPCompareGT));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareGTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareGTFpscr>(dlgSoftFloat32FPCompareGTFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareLE, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLE>(dlgSoftFloat32FPCompareLE));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareLEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLEFpscr>(dlgSoftFloat32FPCompareLEFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareLT, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLT>(dlgSoftFloat32FPCompareLT));
|
||||
SetDelegateInfo(dlgSoftFloat32FPCompareLTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPCompareLTFpscr>(dlgSoftFloat32FPCompareLTFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPDiv, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPDiv>(dlgSoftFloat32FPDiv));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMax, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMax>(dlgSoftFloat32FPMax));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMaxFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxFpscr>(dlgSoftFloat32FPMaxFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMaxNum, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxNum>(dlgSoftFloat32FPMaxNum));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMaxNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMaxNumFpscr>(dlgSoftFloat32FPMaxNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMin, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMin>(dlgSoftFloat32FPMin));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMinFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinFpscr>(dlgSoftFloat32FPMinFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMinNum, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinNum>(dlgSoftFloat32FPMinNum));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMinNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMinNumFpscr>(dlgSoftFloat32FPMinNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMul, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMul>(dlgSoftFloat32FPMul));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulFpscr>(dlgSoftFloat32FPMulFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulAdd>(dlgSoftFloat32FPMulAdd));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulAddFpscr>(dlgSoftFloat32FPMulAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulSub>(dlgSoftFloat32FPMulSub));
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulSubFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulSubFpscr>(dlgSoftFloat32FPMulSubFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPMulX, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPMulX>(dlgSoftFloat32FPMulX));
|
||||
SetDelegateInfo(dlgSoftFloat32FPNegMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPNegMulAdd>(dlgSoftFloat32FPNegMulAdd));
|
||||
SetDelegateInfo(dlgSoftFloat32FPNegMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPNegMulSub>(dlgSoftFloat32FPNegMulSub));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecipEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipEstimate>(dlgSoftFloat32FPRecipEstimate));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecipEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipEstimateFpscr>(dlgSoftFloat32FPRecipEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecipStep, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipStep>(dlgSoftFloat32FPRecipStep)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecipStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecipStepFused>(dlgSoftFloat32FPRecipStepFused));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRecpX, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRecpX>(dlgSoftFloat32FPRecpX));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRSqrtEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtEstimate>(dlgSoftFloat32FPRSqrtEstimate));
|
||||
SetDelegateInfo(dlgSoftFloat32FPRSqrtEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtEstimateFpscr>(dlgSoftFloat32FPRSqrtEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPRSqrtStep, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtStep>(dlgSoftFloat32FPRSqrtStep)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat32FPRSqrtStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPRSqrtStepFused>(dlgSoftFloat32FPRSqrtStepFused));
|
||||
SetDelegateInfo(dlgSoftFloat32FPSqrt, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPSqrt>(dlgSoftFloat32FPSqrt));
|
||||
SetDelegateInfo(dlgSoftFloat32FPSub, Marshal.GetFunctionPointerForDelegate<SoftFloat32FPSub>(dlgSoftFloat32FPSub));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat32_16FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat32_16FPConvert>(dlgSoftFloat32_16FPConvert));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat64FPAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPAdd>(dlgSoftFloat64FPAdd));
|
||||
SetDelegateInfo(dlgSoftFloat64FPAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPAddFpscr>(dlgSoftFloat64FPAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompare, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompare>(dlgSoftFloat64FPCompare));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareEQ, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareEQ>(dlgSoftFloat64FPCompareEQ));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareEQFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareEQFpscr>(dlgSoftFloat64FPCompareEQFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareGE, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGE>(dlgSoftFloat64FPCompareGE));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareGEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGEFpscr>(dlgSoftFloat64FPCompareGEFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareGT, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGT>(dlgSoftFloat64FPCompareGT));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareGTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareGTFpscr>(dlgSoftFloat64FPCompareGTFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareLE, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLE>(dlgSoftFloat64FPCompareLE));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareLEFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLEFpscr>(dlgSoftFloat64FPCompareLEFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareLT, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLT>(dlgSoftFloat64FPCompareLT));
|
||||
SetDelegateInfo(dlgSoftFloat64FPCompareLTFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPCompareLTFpscr>(dlgSoftFloat64FPCompareLTFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPDiv, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPDiv>(dlgSoftFloat64FPDiv));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMax, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMax>(dlgSoftFloat64FPMax));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMaxFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxFpscr>(dlgSoftFloat64FPMaxFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMaxNum, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxNum>(dlgSoftFloat64FPMaxNum));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMaxNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMaxNumFpscr>(dlgSoftFloat64FPMaxNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMin, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMin>(dlgSoftFloat64FPMin));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMinFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinFpscr>(dlgSoftFloat64FPMinFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMinNum, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinNum>(dlgSoftFloat64FPMinNum));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMinNumFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMinNumFpscr>(dlgSoftFloat64FPMinNumFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMul, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMul>(dlgSoftFloat64FPMul));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulFpscr>(dlgSoftFloat64FPMulFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulAdd>(dlgSoftFloat64FPMulAdd));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulAddFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulAddFpscr>(dlgSoftFloat64FPMulAddFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulSub>(dlgSoftFloat64FPMulSub));
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulSubFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulSubFpscr>(dlgSoftFloat64FPMulSubFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPMulX, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPMulX>(dlgSoftFloat64FPMulX));
|
||||
SetDelegateInfo(dlgSoftFloat64FPNegMulAdd, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPNegMulAdd>(dlgSoftFloat64FPNegMulAdd));
|
||||
SetDelegateInfo(dlgSoftFloat64FPNegMulSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPNegMulSub>(dlgSoftFloat64FPNegMulSub));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecipEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipEstimate>(dlgSoftFloat64FPRecipEstimate));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecipEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipEstimateFpscr>(dlgSoftFloat64FPRecipEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecipStep, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipStep>(dlgSoftFloat64FPRecipStep)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecipStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecipStepFused>(dlgSoftFloat64FPRecipStepFused));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRecpX, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRecpX>(dlgSoftFloat64FPRecpX));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRSqrtEstimate, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtEstimate>(dlgSoftFloat64FPRSqrtEstimate));
|
||||
SetDelegateInfo(dlgSoftFloat64FPRSqrtEstimateFpscr, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtEstimateFpscr>(dlgSoftFloat64FPRSqrtEstimateFpscr)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPRSqrtStep, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtStep>(dlgSoftFloat64FPRSqrtStep)); // A32 only.
|
||||
SetDelegateInfo(dlgSoftFloat64FPRSqrtStepFused, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPRSqrtStepFused>(dlgSoftFloat64FPRSqrtStepFused));
|
||||
SetDelegateInfo(dlgSoftFloat64FPSqrt, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPSqrt>(dlgSoftFloat64FPSqrt));
|
||||
SetDelegateInfo(dlgSoftFloat64FPSub, Marshal.GetFunctionPointerForDelegate<SoftFloat64FPSub>(dlgSoftFloat64FPSub));
|
||||
|
||||
SetDelegateInfo(dlgSoftFloat64_16FPConvert, Marshal.GetFunctionPointerForDelegate<SoftFloat64_16FPConvert>(dlgSoftFloat64_16FPConvert));
|
||||
}
|
||||
|
||||
private delegate double MathAbs(double value);
|
||||
|
@ -1,13 +1,33 @@
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common.GraphicsDriver
|
||||
{
|
||||
public static class DriverUtilities
|
||||
{
|
||||
private static void AddMesaFlags(string envVar, string newFlags)
|
||||
{
|
||||
string existingFlags = Environment.GetEnvironmentVariable(envVar);
|
||||
|
||||
string flags = existingFlags == null ? newFlags : $"{existingFlags},{newFlags}";
|
||||
|
||||
OsUtils.SetEnvironmentVariableNoCaching(envVar, flags);
|
||||
}
|
||||
|
||||
public static void InitDriverConfig(bool oglThreading)
|
||||
{
|
||||
if (OperatingSystem.IsLinux())
|
||||
{
|
||||
AddMesaFlags("RADV_DEBUG", "nodcc");
|
||||
}
|
||||
|
||||
ToggleOGLThreading(oglThreading);
|
||||
}
|
||||
|
||||
public static void ToggleOGLThreading(bool enabled)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("mesa_glthread", enabled.ToString().ToLower());
|
||||
Environment.SetEnvironmentVariable("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
|
||||
OsUtils.SetEnvironmentVariableNoCaching("mesa_glthread", enabled.ToString().ToLower());
|
||||
OsUtils.SetEnvironmentVariableNoCaching("__GL_THREADED_OPTIMIZATIONS", enabled ? "1" : "0");
|
||||
|
||||
try
|
||||
{
|
||||
|
24
src/Ryujinx.Common/Utilities/OsUtils.cs
Normal file
24
src/Ryujinx.Common/Utilities/OsUtils.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common.Utilities
|
||||
{
|
||||
public partial class OsUtils
|
||||
{
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
|
||||
|
||||
public static void SetEnvironmentVariableNoCaching(string key, string value)
|
||||
{
|
||||
// Set the value in the cached environment variables, too.
|
||||
Environment.SetEnvironmentVariable(key, value);
|
||||
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
int res = setenv(key, value, 1);
|
||||
Debug.Assert(res != -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -39,7 +39,10 @@ namespace Ryujinx.Graphics.Device
|
||||
{
|
||||
var field = fields[fieldIndex];
|
||||
|
||||
int sizeOfField = SizeCalculator.SizeOf(field.FieldType);
|
||||
var currentFieldOffset = (int)Marshal.OffsetOf<TState>(field.Name);
|
||||
var nextFieldOffset = fieldIndex + 1 == fields.Length ? Unsafe.SizeOf<TState>() : (int)Marshal.OffsetOf<TState>(fields[fieldIndex + 1].Name);
|
||||
|
||||
int sizeOfField = nextFieldOffset - currentFieldOffset;
|
||||
|
||||
for (int i = 0; i < ((sizeOfField + 3) & ~3); i += 4)
|
||||
{
|
||||
|
@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ryujinx.Graphics.Device
|
||||
{
|
||||
public static class SizeCalculator
|
||||
{
|
||||
public static int SizeOf(Type type)
|
||||
{
|
||||
// Is type a enum type?
|
||||
if (type.IsEnum)
|
||||
{
|
||||
type = type.GetEnumUnderlyingType();
|
||||
}
|
||||
|
||||
// Is type a pointer type?
|
||||
if (type.IsPointer || type == typeof(IntPtr) || type == typeof(UIntPtr))
|
||||
{
|
||||
return IntPtr.Size;
|
||||
}
|
||||
|
||||
// Is type a struct type?
|
||||
if (type.IsValueType && !type.IsPrimitive)
|
||||
{
|
||||
// Check if the struct has a explicit size, if so, return that.
|
||||
if (type.StructLayoutAttribute.Size != 0)
|
||||
{
|
||||
return type.StructLayoutAttribute.Size;
|
||||
}
|
||||
|
||||
// Otherwise we calculate the sum of the sizes of all fields.
|
||||
int size = 0;
|
||||
var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
for (int fieldIndex = 0; fieldIndex < fields.Length; fieldIndex++)
|
||||
{
|
||||
size += SizeOf(fields[fieldIndex].FieldType);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// Primitive types.
|
||||
return (Type.GetTypeCode(type)) switch
|
||||
{
|
||||
TypeCode.SByte => sizeof(sbyte),
|
||||
TypeCode.Byte => sizeof(byte),
|
||||
TypeCode.Int16 => sizeof(short),
|
||||
TypeCode.UInt16 => sizeof(ushort),
|
||||
TypeCode.Int32 => sizeof(int),
|
||||
TypeCode.UInt32 => sizeof(uint),
|
||||
TypeCode.Int64 => sizeof(long),
|
||||
TypeCode.UInt64 => sizeof(ulong),
|
||||
TypeCode.Char => sizeof(char),
|
||||
TypeCode.Single => sizeof(float),
|
||||
TypeCode.Double => sizeof(double),
|
||||
TypeCode.Decimal => sizeof(decimal),
|
||||
TypeCode.Boolean => sizeof(bool),
|
||||
_ => throw new ArgumentException($"Length for type \"{type.Name}\" is unknown."),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -5,5 +5,6 @@ namespace Ryujinx.Graphics.GAL
|
||||
Bilinear,
|
||||
Nearest,
|
||||
Fsr,
|
||||
Area,
|
||||
}
|
||||
}
|
||||
|
@ -276,8 +276,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||
dstBaseOffset += dstStride * (yCount - 1);
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true);
|
||||
|
||||
// If remapping is disabled, we always copy the components directly, in order.
|
||||
// If it's enabled, but the mapping is just XYZW, we also copy them in order.
|
||||
bool isIdentityRemap = !remap ||
|
||||
@ -289,6 +287,52 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||
bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount);
|
||||
bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount);
|
||||
|
||||
// Check if the source texture exists on the GPU, if it does, do a GPU side copy.
|
||||
// Otherwise, we would need to flush the source texture which is costly.
|
||||
// We don't expect the source to be linear in such cases, as linear source usually indicates buffer or CPU written data.
|
||||
|
||||
if (completeSource && completeDest && !srcLinear && isIdentityRemap)
|
||||
{
|
||||
var source = memoryManager.Physical.TextureCache.FindTexture(
|
||||
memoryManager,
|
||||
srcGpuVa,
|
||||
srcBpp,
|
||||
srcStride,
|
||||
src.Height,
|
||||
xCount,
|
||||
yCount,
|
||||
srcLinear,
|
||||
src.MemoryLayout.UnpackGobBlocksInY(),
|
||||
src.MemoryLayout.UnpackGobBlocksInZ());
|
||||
|
||||
if (source != null && source.Height == yCount)
|
||||
{
|
||||
source.SynchronizeMemory();
|
||||
|
||||
var target = memoryManager.Physical.TextureCache.FindOrCreateTexture(
|
||||
memoryManager,
|
||||
source.Info.FormatInfo,
|
||||
dstGpuVa,
|
||||
xCount,
|
||||
yCount,
|
||||
dstStride,
|
||||
dstLinear,
|
||||
dst.MemoryLayout.UnpackGobBlocksInY(),
|
||||
dst.MemoryLayout.UnpackGobBlocksInZ());
|
||||
|
||||
if (source.ScaleFactor != target.ScaleFactor)
|
||||
{
|
||||
target.PropagateScale(source);
|
||||
}
|
||||
|
||||
source.HostTexture.CopyTo(target.HostTexture, 0, 0);
|
||||
target.SignalModified();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ReadOnlySpan<byte> srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true);
|
||||
|
||||
// Try to set the texture data directly,
|
||||
// but only if we are doing a complete copy,
|
||||
// and not for block linear to linear copies, since those are typically accessed from the CPU.
|
||||
|
@ -79,7 +79,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
{
|
||||
var field = fields[fieldIndex];
|
||||
|
||||
int sizeOfField = SizeCalculator.SizeOf(field.FieldType);
|
||||
var currentFieldOffset = (int)Marshal.OffsetOf<TState>(field.Name);
|
||||
var nextFieldOffset = fieldIndex + 1 == fields.Length ? Unsafe.SizeOf<TState>() : (int)Marshal.OffsetOf<TState>(fields[fieldIndex + 1].Name);
|
||||
|
||||
int sizeOfField = nextFieldOffset - currentFieldOffset;
|
||||
|
||||
if (fieldToDelegate.TryGetValue(field.Name, out int entryIndex))
|
||||
{
|
||||
|
@ -415,7 +415,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
public int Width;
|
||||
public int Height;
|
||||
public int Depth;
|
||||
public ushort Depth;
|
||||
public ushort Flags;
|
||||
|
||||
public readonly bool UnpackIsLayered()
|
||||
{
|
||||
return (Flags & 1) == 0;
|
||||
}
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
|
@ -347,6 +347,53 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find an existing texture, or create a new one if not found.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
|
||||
/// <param name="formatInfo">Format of the texture</param>
|
||||
/// <param name="gpuAddress">GPU virtual address of the texture</param>
|
||||
/// <param name="xCount">Texture width in bytes</param>
|
||||
/// <param name="yCount">Texture height</param>
|
||||
/// <param name="stride">Texture stride if linear, otherwise ignored</param>
|
||||
/// <param name="isLinear">Indicates if the texture is linear or block linear</param>
|
||||
/// <param name="gobBlocksInY">GOB blocks in Y for block linear textures</param>
|
||||
/// <param name="gobBlocksInZ">GOB blocks in Z for 3D block linear textures</param>
|
||||
/// <returns>The texture</returns>
|
||||
public Texture FindOrCreateTexture(
|
||||
MemoryManager memoryManager,
|
||||
FormatInfo formatInfo,
|
||||
ulong gpuAddress,
|
||||
int xCount,
|
||||
int yCount,
|
||||
int stride,
|
||||
bool isLinear,
|
||||
int gobBlocksInY,
|
||||
int gobBlocksInZ)
|
||||
{
|
||||
TextureInfo info = new(
|
||||
gpuAddress,
|
||||
xCount / formatInfo.BytesPerPixel,
|
||||
yCount,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
stride,
|
||||
isLinear,
|
||||
gobBlocksInY,
|
||||
gobBlocksInZ,
|
||||
1,
|
||||
Target.Texture2D,
|
||||
formatInfo);
|
||||
|
||||
Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.ForCopy, info, 0, sizeHint: new Size(xCount, yCount, 1));
|
||||
|
||||
texture?.SynchronizeMemory();
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find an existing texture, or create a new one if not found.
|
||||
/// </summary>
|
||||
@ -468,13 +515,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
int gobBlocksInY = dsState.MemoryLayout.UnpackGobBlocksInY();
|
||||
int gobBlocksInZ = dsState.MemoryLayout.UnpackGobBlocksInZ();
|
||||
|
||||
layered &= size.UnpackIsLayered();
|
||||
|
||||
Target target;
|
||||
|
||||
if (dsState.MemoryLayout.UnpackIsTarget3D())
|
||||
{
|
||||
target = Target.Texture3D;
|
||||
}
|
||||
else if ((samplesInX | samplesInY) != 1)
|
||||
if ((samplesInX | samplesInY) != 1)
|
||||
{
|
||||
target = size.Depth > 1 && layered
|
||||
? Target.Texture2DMultisampleArray
|
||||
|
106
src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs
Normal file
106
src/Ryujinx.Graphics.OpenGL/Effects/AreaScalingFilter.cs
Normal file
@ -0,0 +1,106 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.OpenGL.Image;
|
||||
using System;
|
||||
using static Ryujinx.Graphics.OpenGL.Effects.ShaderHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
{
|
||||
internal class AreaScalingFilter : IScalingFilter
|
||||
{
|
||||
private readonly OpenGLRenderer _renderer;
|
||||
private int _inputUniform;
|
||||
private int _outputUniform;
|
||||
private int _srcX0Uniform;
|
||||
private int _srcX1Uniform;
|
||||
private int _srcY0Uniform;
|
||||
private int _scalingShaderProgram;
|
||||
private int _srcY1Uniform;
|
||||
private int _dstX0Uniform;
|
||||
private int _dstX1Uniform;
|
||||
private int _dstY0Uniform;
|
||||
private int _dstY1Uniform;
|
||||
|
||||
public float Level { get; set; }
|
||||
|
||||
public AreaScalingFilter(OpenGLRenderer renderer)
|
||||
{
|
||||
Initialize();
|
||||
|
||||
_renderer = renderer;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_scalingShaderProgram != 0)
|
||||
{
|
||||
GL.DeleteProgram(_scalingShaderProgram);
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
var scalingShader = EmbeddedResources.ReadAllText("Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl");
|
||||
|
||||
_scalingShaderProgram = CompileProgram(scalingShader, ShaderType.ComputeShader);
|
||||
|
||||
_inputUniform = GL.GetUniformLocation(_scalingShaderProgram, "Source");
|
||||
_outputUniform = GL.GetUniformLocation(_scalingShaderProgram, "imgOutput");
|
||||
|
||||
_srcX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX0");
|
||||
_srcX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcX1");
|
||||
_srcY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY0");
|
||||
_srcY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "srcY1");
|
||||
_dstX0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX0");
|
||||
_dstX1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstX1");
|
||||
_dstY0Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY0");
|
||||
_dstY1Uniform = GL.GetUniformLocation(_scalingShaderProgram, "dstY1");
|
||||
}
|
||||
|
||||
public void Run(
|
||||
TextureView view,
|
||||
TextureView destinationTexture,
|
||||
int width,
|
||||
int height,
|
||||
Extents2D source,
|
||||
Extents2D destination)
|
||||
{
|
||||
int previousProgram = GL.GetInteger(GetPName.CurrentProgram);
|
||||
int previousUnit = GL.GetInteger(GetPName.ActiveTexture);
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
int previousTextureBinding = GL.GetInteger(GetPName.TextureBinding2D);
|
||||
|
||||
GL.BindImageTexture(0, destinationTexture.Handle, 0, false, 0, TextureAccess.ReadWrite, SizedInternalFormat.Rgba8);
|
||||
|
||||
int threadGroupWorkRegionDim = 16;
|
||||
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
|
||||
// Scaling pass
|
||||
GL.UseProgram(_scalingShaderProgram);
|
||||
view.Bind(0);
|
||||
GL.Uniform1(_inputUniform, 0);
|
||||
GL.Uniform1(_outputUniform, 0);
|
||||
GL.Uniform1(_srcX0Uniform, (float)source.X1);
|
||||
GL.Uniform1(_srcX1Uniform, (float)source.X2);
|
||||
GL.Uniform1(_srcY0Uniform, (float)source.Y1);
|
||||
GL.Uniform1(_srcY1Uniform, (float)source.Y2);
|
||||
GL.Uniform1(_dstX0Uniform, (float)destination.X1);
|
||||
GL.Uniform1(_dstX1Uniform, (float)destination.X2);
|
||||
GL.Uniform1(_dstY0Uniform, (float)destination.Y1);
|
||||
GL.Uniform1(_dstY1Uniform, (float)destination.Y2);
|
||||
GL.DispatchCompute(dispatchX, dispatchY, 1);
|
||||
|
||||
GL.UseProgram(previousProgram);
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.ShaderImageAccessBarrierBit);
|
||||
|
||||
(_renderer.Pipeline as Pipeline).RestoreImages1And2();
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
GL.BindTexture(TextureTarget.Texture2D, previousTextureBinding);
|
||||
|
||||
GL.ActiveTexture((TextureUnit)previousUnit);
|
||||
}
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
private int _srcY0Uniform;
|
||||
private int _scalingShaderProgram;
|
||||
private int _sharpeningShaderProgram;
|
||||
private float _scale = 1;
|
||||
private float _sharpeningLevel = 1;
|
||||
private int _srcY1Uniform;
|
||||
private int _dstX0Uniform;
|
||||
private int _dstX1Uniform;
|
||||
@ -30,10 +30,10 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
|
||||
public float Level
|
||||
{
|
||||
get => _scale;
|
||||
get => _sharpeningLevel;
|
||||
set
|
||||
{
|
||||
_scale = MathF.Max(0.01f, value);
|
||||
_sharpeningLevel = MathF.Max(0.01f, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
{
|
||||
@ -6,18 +7,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
{
|
||||
public static int CompileProgram(string shaderCode, ShaderType shaderType)
|
||||
{
|
||||
var shader = GL.CreateShader(shaderType);
|
||||
GL.ShaderSource(shader, shaderCode);
|
||||
GL.CompileShader(shader);
|
||||
|
||||
var program = GL.CreateProgram();
|
||||
GL.AttachShader(program, shader);
|
||||
GL.LinkProgram(program);
|
||||
|
||||
GL.DetachShader(program, shader);
|
||||
GL.DeleteShader(shader);
|
||||
|
||||
return program;
|
||||
return CompileProgram(new string[] { shaderCode }, shaderType);
|
||||
}
|
||||
|
||||
public static int CompileProgram(string[] shaders, ShaderType shaderType)
|
||||
@ -26,6 +16,15 @@ namespace Ryujinx.Graphics.OpenGL.Effects
|
||||
GL.ShaderSource(shader, shaders.Length, shaders, (int[])null);
|
||||
GL.CompileShader(shader);
|
||||
|
||||
GL.GetShader(shader, ShaderParameter.CompileStatus, out int isCompiled);
|
||||
if (isCompiled == 0)
|
||||
{
|
||||
string log = GL.GetShaderInfoLog(shader);
|
||||
Logger.Error?.Print(LogClass.Gpu, $"Failed to compile effect shader:\n\n{log}\n");
|
||||
GL.DeleteShader(shader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
var program = GL.CreateProgram();
|
||||
GL.AttachShader(program, shader);
|
||||
GL.LinkProgram(program);
|
||||
|
119
src/Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl
Normal file
119
src/Ryujinx.Graphics.OpenGL/Effects/Shaders/area_scaling.glsl
Normal file
@ -0,0 +1,119 @@
|
||||
#version 430 core
|
||||
precision mediump float;
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
layout(rgba8, binding = 0, location=0) uniform image2D imgOutput;
|
||||
layout( location=1 ) uniform sampler2D Source;
|
||||
layout( location=2 ) uniform float srcX0;
|
||||
layout( location=3 ) uniform float srcX1;
|
||||
layout( location=4 ) uniform float srcY0;
|
||||
layout( location=5 ) uniform float srcY1;
|
||||
layout( location=6 ) uniform float dstX0;
|
||||
layout( location=7 ) uniform float dstX1;
|
||||
layout( location=8 ) uniform float dstY0;
|
||||
layout( location=9 ) uniform float dstY1;
|
||||
|
||||
/***** Area Sampling *****/
|
||||
|
||||
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
|
||||
// Effectively a more accurate sharp bilinear filter when upscaling,
|
||||
// that also works as a mathematically perfect downscale filter.
|
||||
// https://entropymine.com/imageworsener/pixelmixing/
|
||||
// https://github.com/obsproject/obs-studio/pull/1715
|
||||
// https://legacy.imagemagick.org/Usage/filter/
|
||||
vec4 AreaSampling(vec2 xy)
|
||||
{
|
||||
// Determine the sizes of the source and target images.
|
||||
vec2 source_size = vec2(abs(srcX1 - srcX0), abs(srcY1 - srcY0));
|
||||
vec2 target_size = vec2(abs(dstX1 - dstX0), abs(dstY1 - dstY0));
|
||||
vec2 inverted_target_size = vec2(1.0) / target_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the target pixel box.
|
||||
vec2 t_beg = floor(xy - vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1));
|
||||
vec2 t_end = t_beg + vec2(1.0, 1.0);
|
||||
|
||||
// Convert the target pixel box to source pixel box.
|
||||
vec2 beg = t_beg * inverted_target_size * source_size;
|
||||
vec2 end = t_end * inverted_target_size * source_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the pixel box.
|
||||
ivec2 f_beg = ivec2(beg);
|
||||
ivec2 f_end = ivec2(end);
|
||||
|
||||
// Compute how much of the start and end pixels are covered horizontally & vertically.
|
||||
float area_w = 1.0 - fract(beg.x);
|
||||
float area_n = 1.0 - fract(beg.y);
|
||||
float area_e = fract(end.x);
|
||||
float area_s = fract(end.y);
|
||||
|
||||
// Compute the areas of the corner pixels in the pixel box.
|
||||
float area_nw = area_n * area_w;
|
||||
float area_ne = area_n * area_e;
|
||||
float area_sw = area_s * area_w;
|
||||
float area_se = area_s * area_e;
|
||||
|
||||
// Initialize the color accumulator.
|
||||
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// Accumulate corner pixels.
|
||||
avg_color += area_nw * texelFetch(Source, ivec2(f_beg.x, f_beg.y), 0);
|
||||
avg_color += area_ne * texelFetch(Source, ivec2(f_end.x, f_beg.y), 0);
|
||||
avg_color += area_sw * texelFetch(Source, ivec2(f_beg.x, f_end.y), 0);
|
||||
avg_color += area_se * texelFetch(Source, ivec2(f_end.x, f_end.y), 0);
|
||||
|
||||
// Determine the size of the pixel box.
|
||||
int x_range = int(f_end.x - f_beg.x - 0.5);
|
||||
int y_range = int(f_end.y - f_beg.y - 0.5);
|
||||
|
||||
// Accumulate top and bottom edge pixels.
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += area_n * texelFetch(Source, ivec2(x, f_beg.y), 0);
|
||||
avg_color += area_s * texelFetch(Source, ivec2(x, f_end.y), 0);
|
||||
}
|
||||
|
||||
// Accumulate left and right edge pixels and all the pixels in between.
|
||||
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y)
|
||||
{
|
||||
avg_color += area_w * texelFetch(Source, ivec2(f_beg.x, y), 0);
|
||||
avg_color += area_e * texelFetch(Source, ivec2(f_end.x, y), 0);
|
||||
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += texelFetch(Source, ivec2(x, y), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the area of the pixel box that was sampled.
|
||||
float area_corners = area_nw + area_ne + area_sw + area_se;
|
||||
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
|
||||
float area_center = float(x_range) * float(y_range);
|
||||
|
||||
// Return the normalized average color.
|
||||
return avg_color / (area_corners + area_edges + area_center);
|
||||
}
|
||||
|
||||
float insideBox(vec2 v, vec2 bLeft, vec2 tRight) {
|
||||
vec2 s = step(bLeft, v) - step(tRight, v);
|
||||
return s.x * s.y;
|
||||
}
|
||||
|
||||
vec2 translateDest(vec2 pos) {
|
||||
vec2 translatedPos = vec2(pos.x, pos.y);
|
||||
translatedPos.x = dstX1 < dstX0 ? dstX1 - translatedPos.x : translatedPos.x;
|
||||
translatedPos.y = dstY0 > dstY1 ? dstY0 + dstY1 - translatedPos.y - 1 : translatedPos.y;
|
||||
return translatedPos;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 bLeft = vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1);
|
||||
vec2 tRight = vec2(dstX1 > dstX0 ? dstX1 : dstX0, dstY1 > dstY0 ? dstY1 : dstY0);
|
||||
ivec2 loc = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y);
|
||||
if (insideBox(loc, bLeft, tRight) == 0) {
|
||||
imageStore(imgOutput, loc, vec4(0, 0, 0, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 outColor = AreaSampling(loc);
|
||||
imageStore(imgOutput, ivec2(translateDest(loc)), vec4(outColor.rgb, 1));
|
||||
}
|
@ -85,4 +85,4 @@ void main() {
|
||||
CurrFilter(gxy);
|
||||
gxy.x -= 8u;
|
||||
CurrFilter(gxy);
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
<EmbeddedResource Include="Effects\Shaders\ffx_fsr1.h" />
|
||||
<EmbeddedResource Include="Effects\Shaders\ffx_a.h" />
|
||||
<EmbeddedResource Include="Effects\Shaders\fsr_scaling.glsl" />
|
||||
<EmbeddedResource Include="Effects\Shaders\area_scaling.glsl" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -373,6 +373,16 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
_isLinear = false;
|
||||
_scalingFilter.Level = _scalingFilterLevel;
|
||||
|
||||
RecreateUpscalingTexture();
|
||||
break;
|
||||
case ScalingFilter.Area:
|
||||
if (_scalingFilter is not AreaScalingFilter)
|
||||
{
|
||||
_scalingFilter?.Dispose();
|
||||
_scalingFilter = new AreaScalingFilter(_renderer);
|
||||
}
|
||||
_isLinear = false;
|
||||
|
||||
RecreateUpscalingTexture();
|
||||
break;
|
||||
}
|
||||
|
@ -32,10 +32,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
CommandBuffer
|
||||
}
|
||||
|
||||
private bool _feedbackLoopActive;
|
||||
private PipelineStageFlags _incoherentBufferWriteStages;
|
||||
private PipelineStageFlags _incoherentTextureWriteStages;
|
||||
private PipelineStageFlags _extraStages;
|
||||
private IncoherentBarrierType _queuedIncoherentBarrier;
|
||||
private bool _queuedFeedbackLoopBarrier;
|
||||
|
||||
public BarrierBatch(VulkanRenderer gd)
|
||||
{
|
||||
@ -53,17 +55,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
stages |= PipelineStageFlags.TransformFeedbackBitExt;
|
||||
}
|
||||
|
||||
if (!gd.IsTBDR)
|
||||
{
|
||||
// Desktop GPUs can transform image barriers into memory barriers.
|
||||
|
||||
access |= AccessFlags.DepthStencilAttachmentWriteBit | AccessFlags.ColorAttachmentWriteBit;
|
||||
access |= AccessFlags.DepthStencilAttachmentReadBit | AccessFlags.ColorAttachmentReadBit;
|
||||
|
||||
stages |= PipelineStageFlags.EarlyFragmentTestsBit | PipelineStageFlags.LateFragmentTestsBit;
|
||||
stages |= PipelineStageFlags.ColorAttachmentOutputBit;
|
||||
}
|
||||
|
||||
return (access, stages);
|
||||
}
|
||||
|
||||
@ -178,16 +169,34 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
|
||||
_queuedIncoherentBarrier = IncoherentBarrierType.None;
|
||||
_queuedFeedbackLoopBarrier = false;
|
||||
}
|
||||
else if (_feedbackLoopActive && _queuedFeedbackLoopBarrier)
|
||||
{
|
||||
// Feedback loop barrier.
|
||||
|
||||
MemoryBarrier barrier = new MemoryBarrier()
|
||||
{
|
||||
SType = StructureType.MemoryBarrier,
|
||||
SrcAccessMask = AccessFlags.ShaderWriteBit,
|
||||
DstAccessMask = AccessFlags.ShaderReadBit
|
||||
};
|
||||
|
||||
QueueBarrier(barrier, PipelineStageFlags.FragmentShaderBit, PipelineStageFlags.AllGraphicsBit);
|
||||
|
||||
_queuedFeedbackLoopBarrier = false;
|
||||
}
|
||||
|
||||
_feedbackLoopActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void Flush(CommandBufferScoped cbs, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||
{
|
||||
Flush(cbs, null, inRenderPass, rpHolder, endRenderPass);
|
||||
Flush(cbs, null, false, inRenderPass, rpHolder, endRenderPass);
|
||||
}
|
||||
|
||||
public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||
public unsafe void Flush(CommandBufferScoped cbs, ShaderCollection program, bool feedbackLoopActive, bool inRenderPass, RenderPassHolder rpHolder, Action endRenderPass)
|
||||
{
|
||||
if (program != null)
|
||||
{
|
||||
@ -195,6 +204,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_incoherentTextureWriteStages |= program.IncoherentTextureWriteStages;
|
||||
}
|
||||
|
||||
_feedbackLoopActive |= feedbackLoopActive;
|
||||
|
||||
FlushMemoryBarrier(program, inRenderPass);
|
||||
|
||||
if (!inRenderPass && rpHolder != null)
|
||||
@ -406,6 +417,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
_queuedIncoherentBarrier = type;
|
||||
}
|
||||
|
||||
_queuedFeedbackLoopBarrier = true;
|
||||
}
|
||||
|
||||
public void QueueTextureBarrier()
|
||||
|
@ -122,7 +122,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Range = (uint)size,
|
||||
};
|
||||
|
||||
_gd.Api.CreateBufferView(_device, bufferViewCreateInfo, null, out var bufferView).ThrowOnError();
|
||||
_gd.Api.CreateBufferView(_device, in bufferViewCreateInfo, null, out var bufferView).ThrowOnError();
|
||||
|
||||
return new Auto<DisposableBufferView>(new DisposableBufferView(_gd.Api, _device, bufferView), this, _waitable, _buffer);
|
||||
}
|
||||
@ -153,7 +153,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PipelineStageFlags.AllCommandsBit,
|
||||
DependencyFlags.DeviceGroupBit,
|
||||
1,
|
||||
memoryBarrier,
|
||||
in memoryBarrier,
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
@ -770,7 +770,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
0,
|
||||
null,
|
||||
1,
|
||||
memoryBarrier,
|
||||
in memoryBarrier,
|
||||
0,
|
||||
null);
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PBufferBinds = &bufferBind
|
||||
};
|
||||
|
||||
gd.Api.QueueBindSparse(gd.Queue, 1, bindSparseInfo, default).ThrowOnError();
|
||||
gd.Api.QueueBindSparse(gd.Queue, 1, in bindSparseInfo, default).ThrowOnError();
|
||||
}
|
||||
|
||||
var holder = new BufferHolder(gd, _device, buffer, (int)size, storageAllocations);
|
||||
|
@ -25,7 +25,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
var buffer = _buffer.Get(cbs, _offset, _size, true).Value;
|
||||
|
||||
gd.TransformFeedbackApi.CmdBindTransformFeedbackBuffers(cbs.CommandBuffer, binding, 1, buffer, (ulong)_offset, (ulong)_size);
|
||||
ulong offset = (ulong)_offset;
|
||||
ulong size = (ulong)_size;
|
||||
|
||||
gd.TransformFeedbackApi.CmdBindTransformFeedbackBuffers(cbs.CommandBuffer, binding, 1, in buffer, in offset, in size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Level = CommandBufferLevel.Primary,
|
||||
};
|
||||
|
||||
api.AllocateCommandBuffers(device, allocateInfo, out CommandBuffer);
|
||||
api.AllocateCommandBuffers(device, in allocateInfo, out CommandBuffer);
|
||||
|
||||
Dependants = new List<IAuto>();
|
||||
Waitables = new List<MultiFenceHolder>();
|
||||
@ -83,7 +83,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
CommandPoolCreateFlags.ResetCommandBufferBit,
|
||||
};
|
||||
|
||||
api.CreateCommandPool(device, commandPoolCreateInfo, null, out _pool).ThrowOnError();
|
||||
api.CreateCommandPool(device, in commandPoolCreateInfo, null, out _pool).ThrowOnError();
|
||||
|
||||
// We need at least 2 command buffers to get texture data in some cases.
|
||||
_totalCommandBuffers = isLight ? 2 : MaxCommandBuffers;
|
||||
@ -253,7 +253,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.CommandBufferBeginInfo,
|
||||
};
|
||||
|
||||
_api.BeginCommandBuffer(entry.CommandBuffer, commandBufferBeginInfo).ThrowOnError();
|
||||
_api.BeginCommandBuffer(entry.CommandBuffer, in commandBufferBeginInfo).ThrowOnError();
|
||||
|
||||
return new CommandBufferScoped(this, entry.CommandBuffer, cursor);
|
||||
}
|
||||
@ -311,7 +311,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
lock (_queueLock)
|
||||
{
|
||||
_api.QueueSubmit(_queue, 1, sInfo, entry.Fence.GetUnsafe()).ThrowOnError();
|
||||
_api.QueueSubmit(_queue, 1, in sInfo, entry.Fence.GetUnsafe()).ThrowOnError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PBufferInfo = &bufferInfo,
|
||||
};
|
||||
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PBufferInfo = pBufferInfo,
|
||||
};
|
||||
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PImageInfo = &imageInfo,
|
||||
};
|
||||
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PImageInfo = pImageInfo,
|
||||
};
|
||||
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PImageInfo = pImageInfo,
|
||||
};
|
||||
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||
|
||||
i += count - 1;
|
||||
}
|
||||
@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PTexelBufferView = &texelBufferView,
|
||||
};
|
||||
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,7 +200,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PTexelBufferView = pTexelBufferView + i,
|
||||
};
|
||||
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||
}
|
||||
|
||||
i += count;
|
||||
|
@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PPoolSizes = pPoolsSize,
|
||||
};
|
||||
|
||||
Api.CreateDescriptorPool(device, descriptorPoolCreateInfo, null, out _pool).ThrowOnError();
|
||||
Api.CreateDescriptorPool(device, in descriptorPoolCreateInfo, null, out _pool).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ using Ryujinx.Graphics.Shader;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
|
||||
@ -42,15 +43,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private record struct TextureRef
|
||||
{
|
||||
public ShaderStage Stage;
|
||||
public TextureStorage Storage;
|
||||
public Auto<DisposableImageView> View;
|
||||
public TextureView View;
|
||||
public Auto<DisposableImageView> ImageView;
|
||||
public Auto<DisposableSampler> Sampler;
|
||||
|
||||
public TextureRef(ShaderStage stage, TextureStorage storage, Auto<DisposableImageView> view, Auto<DisposableSampler> sampler)
|
||||
public TextureRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView, Auto<DisposableSampler> sampler)
|
||||
{
|
||||
Stage = stage;
|
||||
Storage = storage;
|
||||
View = view;
|
||||
ImageView = imageView;
|
||||
Sampler = sampler;
|
||||
}
|
||||
}
|
||||
@ -58,14 +59,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private record struct ImageRef
|
||||
{
|
||||
public ShaderStage Stage;
|
||||
public TextureStorage Storage;
|
||||
public Auto<DisposableImageView> View;
|
||||
public TextureView View;
|
||||
public Auto<DisposableImageView> ImageView;
|
||||
|
||||
public ImageRef(ShaderStage stage, TextureStorage storage, Auto<DisposableImageView> view)
|
||||
public ImageRef(ShaderStage stage, TextureView view, Auto<DisposableImageView> imageView)
|
||||
{
|
||||
Stage = stage;
|
||||
Storage = storage;
|
||||
View = view;
|
||||
ImageView = imageView;
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,6 +125,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly TextureView _dummyTexture;
|
||||
private readonly SamplerHolder _dummySampler;
|
||||
|
||||
public List<TextureView> FeedbackLoopHazards { get; private set; }
|
||||
|
||||
public DescriptorSetUpdater(VulkanRenderer gd, Device device)
|
||||
{
|
||||
_gd = gd;
|
||||
@ -209,10 +212,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_templateUpdater = new();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
public void Initialize(bool isMainPipeline)
|
||||
{
|
||||
MemoryOwner<byte> dummyTextureData = MemoryOwner<byte>.RentCleared(4);
|
||||
_dummyTexture.SetData(dummyTextureData);
|
||||
|
||||
if (isMainPipeline)
|
||||
{
|
||||
FeedbackLoopHazards = new();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool BindingOverlaps(ref DescriptorBufferInfo info, int bindingOffset, int offset, int size)
|
||||
@ -275,6 +283,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void InsertBindingBarriers(CommandBufferScoped cbs)
|
||||
{
|
||||
if ((FeedbackLoopHazards?.Count ?? 0) > 0)
|
||||
{
|
||||
// Clear existing hazards - they will be rebuilt.
|
||||
|
||||
foreach (TextureView hazard in FeedbackLoopHazards)
|
||||
{
|
||||
hazard.DecrementHazardUses();
|
||||
}
|
||||
|
||||
FeedbackLoopHazards.Clear();
|
||||
}
|
||||
|
||||
foreach (ResourceBindingSegment segment in _program.BindingSegments[PipelineBase.TextureSetIndex])
|
||||
{
|
||||
if (segment.Type == ResourceType.TextureAndSampler)
|
||||
@ -284,7 +304,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
for (int i = 0; i < segment.Count; i++)
|
||||
{
|
||||
ref var texture = ref _textureRefs[segment.Binding + i];
|
||||
texture.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, texture.Stage.ConvertToPipelineStageFlags());
|
||||
texture.View?.PrepareForUsage(cbs, texture.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -305,7 +325,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
for (int i = 0; i < segment.Count; i++)
|
||||
{
|
||||
ref var image = ref _imageRefs[segment.Binding + i];
|
||||
image.Storage?.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, image.Stage.ConvertToPipelineStageFlags());
|
||||
image.View?.PrepareForUsage(cbs, image.Stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -385,9 +405,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
else if (image is TextureView view)
|
||||
{
|
||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||
ref ImageRef iRef = ref _imageRefs[binding];
|
||||
|
||||
_imageRefs[binding] = new(stage, view.Storage, view.GetView(imageFormat).GetIdentityImageView());
|
||||
iRef.View?.ClearUsage(FeedbackLoopHazards);
|
||||
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||
|
||||
iRef = new(stage, view, view.GetView(imageFormat).GetIdentityImageView());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -486,9 +509,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
else if (texture is TextureView view)
|
||||
{
|
||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||
ref TextureRef iRef = ref _textureRefs[binding];
|
||||
|
||||
_textureRefs[binding] = new(stage, view.Storage, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||
iRef.View?.ClearUsage(FeedbackLoopHazards);
|
||||
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
|
||||
|
||||
iRef = new(stage, view, view.GetImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -510,7 +536,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
view.Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, stage.ConvertToPipelineStageFlags());
|
||||
|
||||
_textureRefs[binding] = new(stage, view.Storage, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||
_textureRefs[binding] = new(stage, view, view.GetIdentityImageView(), ((SamplerHolder)sampler)?.GetSampler());
|
||||
|
||||
SignalDirty(DirtyFlags.Texture);
|
||||
}
|
||||
@ -836,7 +862,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ref var texture = ref textures[i];
|
||||
ref var refs = ref _textureRefs[binding + i];
|
||||
|
||||
texture.ImageView = refs.View?.Get(cbs).Value ?? default;
|
||||
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
||||
|
||||
if (texture.ImageView.Handle == 0)
|
||||
@ -886,7 +912,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
images[i].ImageView = _imageRefs[binding + i].View?.Get(cbs).Value ?? default;
|
||||
images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default;
|
||||
}
|
||||
|
||||
tu.Push<DescriptorImageInfo>(images[..count]);
|
||||
@ -957,7 +983,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ref var texture = ref textures[i];
|
||||
ref var refs = ref _textureRefs[binding + i];
|
||||
|
||||
texture.ImageView = refs.View?.Get(cbs).Value ?? default;
|
||||
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
||||
|
||||
if (texture.ImageView.Handle == 0)
|
||||
|
101
src/Ryujinx.Graphics.Vulkan/Effects/AreaScalingFilter.cs
Normal file
101
src/Ryujinx.Graphics.Vulkan/Effects/AreaScalingFilter.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using Extent2D = Ryujinx.Graphics.GAL.Extents2D;
|
||||
using Format = Silk.NET.Vulkan.Format;
|
||||
using SamplerCreateInfo = Ryujinx.Graphics.GAL.SamplerCreateInfo;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan.Effects
|
||||
{
|
||||
internal class AreaScalingFilter : IScalingFilter
|
||||
{
|
||||
private readonly VulkanRenderer _renderer;
|
||||
private PipelineHelperShader _pipeline;
|
||||
private ISampler _sampler;
|
||||
private ShaderCollection _scalingProgram;
|
||||
private Device _device;
|
||||
|
||||
public float Level { get; set; }
|
||||
|
||||
public AreaScalingFilter(VulkanRenderer renderer, Device device)
|
||||
{
|
||||
_device = device;
|
||||
_renderer = renderer;
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_pipeline.Dispose();
|
||||
_scalingProgram.Dispose();
|
||||
_sampler.Dispose();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_pipeline = new PipelineHelperShader(_renderer, _device);
|
||||
|
||||
_pipeline.Initialize();
|
||||
|
||||
var scalingShader = EmbeddedResources.Read("Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv");
|
||||
|
||||
var scalingResourceLayout = new ResourceLayoutBuilder()
|
||||
.Add(ResourceStages.Compute, ResourceType.UniformBuffer, 2)
|
||||
.Add(ResourceStages.Compute, ResourceType.TextureAndSampler, 1)
|
||||
.Add(ResourceStages.Compute, ResourceType.Image, 0, true).Build();
|
||||
|
||||
_sampler = _renderer.CreateSampler(SamplerCreateInfo.Create(MinFilter.Linear, MagFilter.Linear));
|
||||
|
||||
_scalingProgram = _renderer.CreateProgramWithMinimalLayout(new[]
|
||||
{
|
||||
new ShaderSource(scalingShader, ShaderStage.Compute, TargetLanguage.Spirv),
|
||||
}, scalingResourceLayout);
|
||||
}
|
||||
|
||||
public void Run(
|
||||
TextureView view,
|
||||
CommandBufferScoped cbs,
|
||||
Auto<DisposableImageView> destinationTexture,
|
||||
Format format,
|
||||
int width,
|
||||
int height,
|
||||
Extent2D source,
|
||||
Extent2D destination)
|
||||
{
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
_pipeline.SetProgram(_scalingProgram);
|
||||
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _sampler);
|
||||
|
||||
ReadOnlySpan<float> dimensionsBuffer = stackalloc float[]
|
||||
{
|
||||
source.X1,
|
||||
source.X2,
|
||||
source.Y1,
|
||||
source.Y2,
|
||||
destination.X1,
|
||||
destination.X2,
|
||||
destination.Y1,
|
||||
destination.Y2,
|
||||
};
|
||||
|
||||
int rangeSize = dimensionsBuffer.Length * sizeof(float);
|
||||
using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize);
|
||||
buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer);
|
||||
|
||||
int threadGroupWorkRegionDim = 16;
|
||||
int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
|
||||
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
|
||||
_pipeline.SetImage(0, destinationTexture);
|
||||
_pipeline.DispatchCompute(dispatchX, dispatchY, 1);
|
||||
_pipeline.ComputeBarrier();
|
||||
|
||||
_pipeline.Finish();
|
||||
}
|
||||
}
|
||||
}
|
122
src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.glsl
Normal file
122
src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.glsl
Normal file
@ -0,0 +1,122 @@
|
||||
// Scaling
|
||||
|
||||
#version 430 core
|
||||
layout (local_size_x = 16, local_size_y = 16) in;
|
||||
layout( rgba8, binding = 0, set = 3) uniform image2D imgOutput;
|
||||
layout( binding = 1, set = 2) uniform sampler2D Source;
|
||||
layout( binding = 2 ) uniform dimensions{
|
||||
float srcX0;
|
||||
float srcX1;
|
||||
float srcY0;
|
||||
float srcY1;
|
||||
float dstX0;
|
||||
float dstX1;
|
||||
float dstY0;
|
||||
float dstY1;
|
||||
};
|
||||
|
||||
/***** Area Sampling *****/
|
||||
|
||||
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
|
||||
// Effectively a more accurate sharp bilinear filter when upscaling,
|
||||
// that also works as a mathematically perfect downscale filter.
|
||||
// https://entropymine.com/imageworsener/pixelmixing/
|
||||
// https://github.com/obsproject/obs-studio/pull/1715
|
||||
// https://legacy.imagemagick.org/Usage/filter/
|
||||
vec4 AreaSampling(vec2 xy)
|
||||
{
|
||||
// Determine the sizes of the source and target images.
|
||||
vec2 source_size = vec2(abs(srcX1 - srcX0), abs(srcY1 - srcY0));
|
||||
vec2 target_size = vec2(abs(dstX1 - dstX0), abs(dstY1 - dstY0));
|
||||
vec2 inverted_target_size = vec2(1.0) / target_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the target pixel box.
|
||||
vec2 t_beg = floor(xy - vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1));
|
||||
vec2 t_end = t_beg + vec2(1.0, 1.0);
|
||||
|
||||
// Convert the target pixel box to source pixel box.
|
||||
vec2 beg = t_beg * inverted_target_size * source_size;
|
||||
vec2 end = t_end * inverted_target_size * source_size;
|
||||
|
||||
// Compute the top-left and bottom-right corners of the pixel box.
|
||||
ivec2 f_beg = ivec2(beg);
|
||||
ivec2 f_end = ivec2(end);
|
||||
|
||||
// Compute how much of the start and end pixels are covered horizontally & vertically.
|
||||
float area_w = 1.0 - fract(beg.x);
|
||||
float area_n = 1.0 - fract(beg.y);
|
||||
float area_e = fract(end.x);
|
||||
float area_s = fract(end.y);
|
||||
|
||||
// Compute the areas of the corner pixels in the pixel box.
|
||||
float area_nw = area_n * area_w;
|
||||
float area_ne = area_n * area_e;
|
||||
float area_sw = area_s * area_w;
|
||||
float area_se = area_s * area_e;
|
||||
|
||||
// Initialize the color accumulator.
|
||||
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
|
||||
// Accumulate corner pixels.
|
||||
avg_color += area_nw * texelFetch(Source, ivec2(f_beg.x, f_beg.y), 0);
|
||||
avg_color += area_ne * texelFetch(Source, ivec2(f_end.x, f_beg.y), 0);
|
||||
avg_color += area_sw * texelFetch(Source, ivec2(f_beg.x, f_end.y), 0);
|
||||
avg_color += area_se * texelFetch(Source, ivec2(f_end.x, f_end.y), 0);
|
||||
|
||||
// Determine the size of the pixel box.
|
||||
int x_range = int(f_end.x - f_beg.x - 0.5);
|
||||
int y_range = int(f_end.y - f_beg.y - 0.5);
|
||||
|
||||
// Accumulate top and bottom edge pixels.
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += area_n * texelFetch(Source, ivec2(x, f_beg.y), 0);
|
||||
avg_color += area_s * texelFetch(Source, ivec2(x, f_end.y), 0);
|
||||
}
|
||||
|
||||
// Accumulate left and right edge pixels and all the pixels in between.
|
||||
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y)
|
||||
{
|
||||
avg_color += area_w * texelFetch(Source, ivec2(f_beg.x, y), 0);
|
||||
avg_color += area_e * texelFetch(Source, ivec2(f_end.x, y), 0);
|
||||
|
||||
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x)
|
||||
{
|
||||
avg_color += texelFetch(Source, ivec2(x, y), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the area of the pixel box that was sampled.
|
||||
float area_corners = area_nw + area_ne + area_sw + area_se;
|
||||
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
|
||||
float area_center = float(x_range) * float(y_range);
|
||||
|
||||
// Return the normalized average color.
|
||||
return avg_color / (area_corners + area_edges + area_center);
|
||||
}
|
||||
|
||||
float insideBox(vec2 v, vec2 bLeft, vec2 tRight) {
|
||||
vec2 s = step(bLeft, v) - step(tRight, v);
|
||||
return s.x * s.y;
|
||||
}
|
||||
|
||||
vec2 translateDest(vec2 pos) {
|
||||
vec2 translatedPos = vec2(pos.x, pos.y);
|
||||
translatedPos.x = dstX1 < dstX0 ? dstX1 - translatedPos.x : translatedPos.x;
|
||||
translatedPos.y = dstY0 < dstY1 ? dstY1 + dstY0 - translatedPos.y - 1 : translatedPos.y;
|
||||
return translatedPos;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 bLeft = vec2(dstX0 < dstX1 ? dstX0 : dstX1, dstY0 < dstY1 ? dstY0 : dstY1);
|
||||
vec2 tRight = vec2(dstX1 > dstX0 ? dstX1 : dstX0, dstY1 > dstY0 ? dstY1 : dstY0);
|
||||
ivec2 loc = ivec2(gl_GlobalInvocationID.x, gl_GlobalInvocationID.y);
|
||||
if (insideBox(loc, bLeft, tRight) == 0) {
|
||||
imageStore(imgOutput, loc, vec4(0, 0, 0, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 outColor = AreaSampling(loc);
|
||||
imageStore(imgOutput, ivec2(translateDest(loc)), vec4(outColor.rgb, 1));
|
||||
}
|
BIN
src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv
Normal file
BIN
src/Ryujinx.Graphics.Vulkan/Effects/Shaders/AreaScaling.spv
Normal file
Binary file not shown.
12
src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs
Normal file
12
src/Ryujinx.Graphics.Vulkan/FeedbackLoopAspects.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
[Flags]
|
||||
internal enum FeedbackLoopAspects
|
||||
{
|
||||
None = 0,
|
||||
Color = 1 << 0,
|
||||
Depth = 1 << 1,
|
||||
}
|
||||
}
|
@ -250,7 +250,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Layers = Layers,
|
||||
};
|
||||
|
||||
api.CreateFramebuffer(_device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
|
||||
api.CreateFramebuffer(_device, in framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
|
||||
return new Auto<DisposableFramebuffer>(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments);
|
||||
}
|
||||
|
||||
@ -302,6 +302,27 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_depthStencil?.Storage?.AddStoreOpUsage(true);
|
||||
}
|
||||
|
||||
public void ClearBindings()
|
||||
{
|
||||
_depthStencil?.Storage.ClearBindings();
|
||||
|
||||
for (int i = 0; i < _colorsCanonical.Length; i++)
|
||||
{
|
||||
_colorsCanonical[i]?.Storage.ClearBindings();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBindings()
|
||||
{
|
||||
_depthStencil?.Storage.AddBinding(_depthStencil);
|
||||
|
||||
for (int i = 0; i < _colorsCanonical.Length; i++)
|
||||
{
|
||||
TextureView color = _colorsCanonical[i];
|
||||
color?.Storage.AddBinding(color);
|
||||
}
|
||||
}
|
||||
|
||||
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
||||
VulkanRenderer gd,
|
||||
Device device,
|
||||
|
@ -46,6 +46,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly bool SupportsViewportArray2;
|
||||
public readonly bool SupportsHostImportedMemory;
|
||||
public readonly bool SupportsDepthClipControl;
|
||||
public readonly bool SupportsAttachmentFeedbackLoop;
|
||||
public readonly bool SupportsDynamicAttachmentFeedbackLoop;
|
||||
public readonly uint SubgroupSize;
|
||||
public readonly SampleCountFlags SupportedSampleCounts;
|
||||
public readonly PortabilitySubsetFlags PortabilitySubset;
|
||||
@ -84,6 +86,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
bool supportsViewportArray2,
|
||||
bool supportsHostImportedMemory,
|
||||
bool supportsDepthClipControl,
|
||||
bool supportsAttachmentFeedbackLoop,
|
||||
bool supportsDynamicAttachmentFeedbackLoop,
|
||||
uint subgroupSize,
|
||||
SampleCountFlags supportedSampleCounts,
|
||||
PortabilitySubsetFlags portabilitySubset,
|
||||
@ -121,6 +125,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SupportsViewportArray2 = supportsViewportArray2;
|
||||
SupportsHostImportedMemory = supportsHostImportedMemory;
|
||||
SupportsDepthClipControl = supportsDepthClipControl;
|
||||
SupportsAttachmentFeedbackLoop = supportsAttachmentFeedbackLoop;
|
||||
SupportsDynamicAttachmentFeedbackLoop = supportsDynamicAttachmentFeedbackLoop;
|
||||
SubgroupSize = subgroupSize;
|
||||
SupportedSampleCounts = supportedSampleCounts;
|
||||
PortabilitySubset = portabilitySubset;
|
||||
|
@ -115,7 +115,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PNext = &importInfo,
|
||||
};
|
||||
|
||||
Result result = _api.AllocateMemory(_device, memoryAllocateInfo, null, out var deviceMemory);
|
||||
Result result = _api.AllocateMemory(_device, in memoryAllocateInfo, null, out var deviceMemory);
|
||||
|
||||
if (result < Result.Success)
|
||||
{
|
||||
|
@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
MemoryTypeIndex = (uint)MemoryTypeIndex,
|
||||
};
|
||||
|
||||
_api.AllocateMemory(_device, memoryAllocateInfo, null, out var deviceMemory).ThrowOnError();
|
||||
_api.AllocateMemory(_device, in memoryAllocateInfo, null, out var deviceMemory).ThrowOnError();
|
||||
|
||||
IntPtr hostPointer = IntPtr.Zero;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
using Silk.NET.Core.Loader;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -8,6 +9,8 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
[SupportedOSPlatform("macos")]
|
||||
public static partial class MVKInitialization
|
||||
{
|
||||
private const string VulkanLib = "libvulkan.dylib";
|
||||
|
||||
[LibraryImport("libMoltenVK.dylib")]
|
||||
private static partial Result vkGetMoltenVKConfigurationMVK(IntPtr unusedInstance, out MVKConfiguration config, in IntPtr configSize);
|
||||
|
||||
@ -29,5 +32,20 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
|
||||
|
||||
vkSetMoltenVKConfigurationMVK(IntPtr.Zero, config, configSize);
|
||||
}
|
||||
|
||||
private static string[] Resolver(string path)
|
||||
{
|
||||
if (path.EndsWith(VulkanLib))
|
||||
{
|
||||
path = path[..^VulkanLib.Length] + "libMoltenVK.dylib";
|
||||
return [path];
|
||||
}
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
public static void InitializeResolver()
|
||||
{
|
||||
((DefaultPathResolver)PathResolver.Default).Resolvers.Insert(0, Resolver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.Shader;
|
||||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
@ -33,6 +34,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
public readonly Action EndRenderPassDelegate;
|
||||
|
||||
protected PipelineDynamicState DynamicState;
|
||||
protected bool IsMainPipeline;
|
||||
private PipelineState _newState;
|
||||
private bool _graphicsStateDirty;
|
||||
private bool _computeStateDirty;
|
||||
@ -85,6 +87,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private bool _tfEnabled;
|
||||
private bool _tfActive;
|
||||
|
||||
private FeedbackLoopAspects _feedbackLoop;
|
||||
private bool _passWritesDepthStencil;
|
||||
|
||||
private readonly PipelineColorBlendAttachmentState[] _storedBlend;
|
||||
public ulong DrawCount { get; private set; }
|
||||
public bool RenderPassActive { get; private set; }
|
||||
@ -102,7 +107,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.PipelineCacheCreateInfo,
|
||||
};
|
||||
|
||||
gd.Api.CreatePipelineCache(device, pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError();
|
||||
gd.Api.CreatePipelineCache(device, in pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError();
|
||||
|
||||
_descriptorSetUpdater = new DescriptorSetUpdater(gd, device);
|
||||
_vertexBufferUpdater = new VertexBufferUpdater(gd);
|
||||
@ -126,7 +131,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_descriptorSetUpdater.Initialize();
|
||||
_descriptorSetUpdater.Initialize(IsMainPipeline);
|
||||
|
||||
QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false);
|
||||
TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true);
|
||||
@ -814,6 +819,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_newState.DepthTestEnable = depthTest.TestEnable;
|
||||
_newState.DepthWriteEnable = depthTest.WriteEnable;
|
||||
_newState.DepthCompareOp = depthTest.Func.Convert();
|
||||
|
||||
UpdatePassDepthStencil();
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
@ -1079,6 +1086,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
|
||||
_newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
|
||||
_newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
|
||||
|
||||
UpdatePassDepthStencil();
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
@ -1426,7 +1435,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
if (IsMainPipeline)
|
||||
{
|
||||
FramebufferParams?.ClearBindings();
|
||||
}
|
||||
|
||||
FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
|
||||
|
||||
if (IsMainPipeline)
|
||||
{
|
||||
FramebufferParams.AddBindings();
|
||||
|
||||
_newState.FeedbackLoopAspects = FeedbackLoopAspects.None;
|
||||
_bindingBarriersDirty = true;
|
||||
}
|
||||
|
||||
_passWritesDepthStencil = false;
|
||||
UpdatePassDepthStencil();
|
||||
UpdatePipelineAttachmentFormats();
|
||||
}
|
||||
|
||||
@ -1493,11 +1518,82 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
|
||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute);
|
||||
}
|
||||
|
||||
private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects)
|
||||
{
|
||||
if (_feedbackLoop != aspects)
|
||||
{
|
||||
if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
||||
{
|
||||
DynamicState.SetFeedbackLoop(aspects);
|
||||
}
|
||||
else
|
||||
{
|
||||
_newState.FeedbackLoopAspects = aspects;
|
||||
}
|
||||
|
||||
_feedbackLoop = aspects;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool UpdateFeedbackLoop()
|
||||
{
|
||||
List<TextureView> hazards = _descriptorSetUpdater.FeedbackLoopHazards;
|
||||
|
||||
if ((hazards?.Count ?? 0) > 0)
|
||||
{
|
||||
FeedbackLoopAspects aspects = 0;
|
||||
|
||||
foreach (TextureView view in hazards)
|
||||
{
|
||||
// May need to enforce feedback loop layout here in the future.
|
||||
// Though technically, it should always work with the general layout.
|
||||
|
||||
if (view.Info.Format.IsDepthOrStencil())
|
||||
{
|
||||
if (_passWritesDepthStencil)
|
||||
{
|
||||
// If depth/stencil isn't written in the pass, it doesn't count as a feedback loop.
|
||||
|
||||
aspects |= FeedbackLoopAspects.Depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aspects |= FeedbackLoopAspects.Color;
|
||||
}
|
||||
}
|
||||
|
||||
return ChangeFeedbackLoop(aspects);
|
||||
}
|
||||
else if (_feedbackLoop != 0)
|
||||
{
|
||||
return ChangeFeedbackLoop(FeedbackLoopAspects.None);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdatePassDepthStencil()
|
||||
{
|
||||
if (!RenderPassActive)
|
||||
{
|
||||
_passWritesDepthStencil = false;
|
||||
}
|
||||
|
||||
// Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check.
|
||||
_passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable;
|
||||
}
|
||||
|
||||
private bool RecreateGraphicsPipelineIfNeeded()
|
||||
{
|
||||
if (AutoFlush.ShouldFlushDraw(DrawCount))
|
||||
@ -1505,7 +1601,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Gd.FlushAllCommands();
|
||||
}
|
||||
|
||||
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
||||
|
||||
if (_needsIndexBufferRebind && _indexBufferPattern == null)
|
||||
{
|
||||
@ -1539,7 +1635,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_vertexBufferUpdater.Commit(Cbs);
|
||||
}
|
||||
|
||||
if (_graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
||||
if (_bindingBarriersDirty)
|
||||
{
|
||||
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
||||
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
||||
|
||||
_bindingBarriersDirty = false;
|
||||
}
|
||||
|
||||
if (UpdateFeedbackLoop() || _graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
|
||||
{
|
||||
if (!CreatePipeline(PipelineBindPoint.Graphics))
|
||||
{
|
||||
@ -1548,17 +1652,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_graphicsStateDirty = false;
|
||||
Pbp = PipelineBindPoint.Graphics;
|
||||
|
||||
if (_bindingBarriersDirty)
|
||||
{
|
||||
// Stale barriers may have been activated by switching program. Emit any that are relevant.
|
||||
_descriptorSetUpdater.InsertBindingBarriers(Cbs);
|
||||
|
||||
_bindingBarriersDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
Gd.Barriers.Flush(Cbs, _program, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
|
||||
|
||||
_descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics);
|
||||
|
||||
@ -1628,7 +1724,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
ClearValueCount = 1,
|
||||
};
|
||||
|
||||
Gd.Api.CmdBeginRenderPass(CommandBuffer, renderPassBeginInfo, SubpassContents.Inline);
|
||||
Gd.Api.CmdBeginRenderPass(CommandBuffer, in renderPassBeginInfo, SubpassContents.Inline);
|
||||
RenderPassActive = true;
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DependencyCount = 1,
|
||||
};
|
||||
|
||||
gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError();
|
||||
gd.Api.CreateRenderPass(device, in renderPassCreateInfo, null, out var renderPass).ThrowOnError();
|
||||
|
||||
return new DisposableRenderPass(gd.Api, device, renderPass);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Silk.NET.Vulkan;
|
||||
using Silk.NET.Vulkan.Extensions.EXT;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
@ -21,6 +22,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
private Array4<float> _blendConstants;
|
||||
|
||||
private FeedbackLoopAspects _feedbackLoopAspects;
|
||||
|
||||
public uint ViewportsCount;
|
||||
public Array16<Viewport> Viewports;
|
||||
|
||||
@ -32,7 +35,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Scissor = 1 << 2,
|
||||
Stencil = 1 << 3,
|
||||
Viewport = 1 << 4,
|
||||
All = Blend | DepthBias | Scissor | Stencil | Viewport,
|
||||
FeedbackLoop = 1 << 5,
|
||||
All = Blend | DepthBias | Scissor | Stencil | Viewport | FeedbackLoop,
|
||||
}
|
||||
|
||||
private DirtyFlags _dirty;
|
||||
@ -99,13 +103,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFeedbackLoop(FeedbackLoopAspects aspects)
|
||||
{
|
||||
_feedbackLoopAspects = aspects;
|
||||
|
||||
_dirty |= DirtyFlags.FeedbackLoop;
|
||||
}
|
||||
|
||||
public void ForceAllDirty()
|
||||
{
|
||||
_dirty = DirtyFlags.All;
|
||||
}
|
||||
|
||||
public void ReplayIfDirty(Vk api, CommandBuffer commandBuffer)
|
||||
public void ReplayIfDirty(VulkanRenderer gd, CommandBuffer commandBuffer)
|
||||
{
|
||||
Vk api = gd.Api;
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.Blend))
|
||||
{
|
||||
RecordBlend(api, commandBuffer);
|
||||
@ -131,6 +144,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
RecordViewport(api, commandBuffer);
|
||||
}
|
||||
|
||||
if (_dirty.HasFlag(DirtyFlags.FeedbackLoop) && gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
|
||||
{
|
||||
RecordFeedbackLoop(gd.DynamicFeedbackLoopApi, commandBuffer);
|
||||
}
|
||||
|
||||
_dirty = DirtyFlags.None;
|
||||
}
|
||||
|
||||
@ -169,5 +187,17 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
api.CmdSetViewport(commandBuffer, 0, ViewportsCount, Viewports.AsSpan());
|
||||
}
|
||||
}
|
||||
|
||||
private readonly void RecordFeedbackLoop(ExtAttachmentFeedbackLoopDynamicState api, CommandBuffer commandBuffer)
|
||||
{
|
||||
ImageAspectFlags aspects = (_feedbackLoopAspects & FeedbackLoopAspects.Color) != 0 ? ImageAspectFlags.ColorBit : 0;
|
||||
|
||||
if ((_feedbackLoopAspects & FeedbackLoopAspects.Depth) != 0)
|
||||
{
|
||||
aspects |= ImageAspectFlags.DepthBit | ImageAspectFlags.StencilBit;
|
||||
}
|
||||
|
||||
api.CmdSetAttachmentFeedbackLoopEnable(commandBuffer, aspects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_activeBufferMirrors = new();
|
||||
|
||||
CommandBuffer = (Cbs = gd.CommandBufferPool.Rent()).CommandBuffer;
|
||||
|
||||
IsMainPipeline = true;
|
||||
}
|
||||
|
||||
private void CopyPendingQuery()
|
||||
@ -235,7 +237,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (Pipeline != null && Pbp == PipelineBindPoint.Graphics)
|
||||
{
|
||||
DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer);
|
||||
DynamicState.ReplayIfDirty(Gd, CommandBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Flags = flags,
|
||||
};
|
||||
|
||||
gd.Api.CreateDescriptorSetLayout(device, descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError();
|
||||
gd.Api.CreateDescriptorSetLayout(device, in descriptorSetLayoutCreateInfo, null, out layouts[setIndex]).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
struct PipelineState : IDisposable
|
||||
{
|
||||
private const int RequiredSubgroupSize = 32;
|
||||
private const int MaxDynamicStatesCount = 9;
|
||||
|
||||
public PipelineUid Internal;
|
||||
|
||||
@ -299,6 +300,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
|
||||
}
|
||||
|
||||
public FeedbackLoopAspects FeedbackLoopAspects
|
||||
{
|
||||
readonly get => (FeedbackLoopAspects)((Internal.Id8 >> 7) & 0x3);
|
||||
set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFFFFFFFE7F) | (((ulong)value) << 7);
|
||||
}
|
||||
|
||||
public bool HasTessellationControlShader;
|
||||
public NativeArray<PipelineShaderStageCreateInfo> Stages;
|
||||
public PipelineLayout PipelineLayout;
|
||||
@ -564,9 +571,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
|
||||
bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
|
||||
int dynamicStatesCount = supportsExtDynamicState ? 8 : 7;
|
||||
bool supportsFeedbackLoopDynamicState = gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop;
|
||||
|
||||
DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
|
||||
DynamicState* dynamicStates = stackalloc DynamicState[MaxDynamicStatesCount];
|
||||
|
||||
int dynamicStatesCount = 7;
|
||||
|
||||
dynamicStates[0] = DynamicState.Viewport;
|
||||
dynamicStates[1] = DynamicState.Scissor;
|
||||
@ -578,7 +587,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (supportsExtDynamicState)
|
||||
{
|
||||
dynamicStates[7] = DynamicState.VertexInputBindingStrideExt;
|
||||
dynamicStates[dynamicStatesCount++] = DynamicState.VertexInputBindingStrideExt;
|
||||
}
|
||||
|
||||
if (supportsFeedbackLoopDynamicState)
|
||||
{
|
||||
dynamicStates[dynamicStatesCount++] = DynamicState.AttachmentFeedbackLoopEnableExt;
|
||||
}
|
||||
|
||||
var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo
|
||||
@ -588,9 +602,27 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PDynamicStates = dynamicStates,
|
||||
};
|
||||
|
||||
PipelineCreateFlags flags = 0;
|
||||
|
||||
if (gd.Capabilities.SupportsAttachmentFeedbackLoop)
|
||||
{
|
||||
FeedbackLoopAspects aspects = FeedbackLoopAspects;
|
||||
|
||||
if ((aspects & FeedbackLoopAspects.Color) != 0)
|
||||
{
|
||||
flags |= PipelineCreateFlags.CreateColorAttachmentFeedbackLoopBitExt;
|
||||
}
|
||||
|
||||
if ((aspects & FeedbackLoopAspects.Depth) != 0)
|
||||
{
|
||||
flags |= PipelineCreateFlags.CreateDepthStencilAttachmentFeedbackLoopBitExt;
|
||||
}
|
||||
}
|
||||
|
||||
var pipelineCreateInfo = new GraphicsPipelineCreateInfo
|
||||
{
|
||||
SType = StructureType.GraphicsPipelineCreateInfo,
|
||||
Flags = flags,
|
||||
StageCount = StagesCount,
|
||||
PStages = Stages.Pointer,
|
||||
PVertexInputState = &vertexInputState,
|
||||
|
@ -52,7 +52,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries
|
||||
PipelineStatistics = flags,
|
||||
};
|
||||
|
||||
gd.Api.CreateQueryPool(device, queryPoolCreateInfo, null, out _queryPool).ThrowOnError();
|
||||
gd.Api.CreateQueryPool(device, in queryPoolCreateInfo, null, out _queryPool).ThrowOnError();
|
||||
}
|
||||
|
||||
var buffer = gd.BufferManager.Create(gd, sizeof(long), forConditionalRendering: true);
|
||||
|
@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DependencyCount = 1,
|
||||
};
|
||||
|
||||
gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError();
|
||||
gd.Api.CreateRenderPass(device, in renderPassCreateInfo, null, out var renderPass).ThrowOnError();
|
||||
|
||||
_renderPass = new Auto<DisposableRenderPass>(new DisposableRenderPass(gd.Api, device, renderPass));
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Effects\Textures\SmaaAreaTexture.bin" />
|
||||
<EmbeddedResource Include="Effects\Textures\SmaaSearchTexture.bin" />
|
||||
<EmbeddedResource Include="Effects\Shaders\AreaScaling.spv" />
|
||||
<EmbeddedResource Include="Effects\Shaders\FsrScaling.spv" />
|
||||
<EmbeddedResource Include="Effects\Shaders\FsrSharpening.spv" />
|
||||
<EmbeddedResource Include="Effects\Shaders\Fxaa.spv" />
|
||||
|
@ -68,7 +68,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
samplerCreateInfo.BorderColor = BorderColor.FloatCustomExt;
|
||||
}
|
||||
|
||||
gd.Api.CreateSampler(device, samplerCreateInfo, null, out var sampler).ThrowOnError();
|
||||
gd.Api.CreateSampler(device, in samplerCreateInfo, null, out var sampler).ThrowOnError();
|
||||
|
||||
_sampler = new Auto<DisposableSampler>(new DisposableSampler(gd.Api, device, sampler));
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PCode = (uint*)pCode,
|
||||
};
|
||||
|
||||
api.CreateShaderModule(device, shaderModuleCreateInfo, null, out _module).ThrowOnError();
|
||||
api.CreateShaderModule(device, in shaderModuleCreateInfo, null, out _module).ThrowOnError();
|
||||
}
|
||||
|
||||
CompileStatus = ProgramLinkStatus.Success;
|
||||
|
@ -88,7 +88,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DstOffsets = dstOffsets,
|
||||
};
|
||||
|
||||
api.CmdBlitImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region, filter);
|
||||
api.CmdBlitImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, in region, filter);
|
||||
|
||||
copySrcLevel++;
|
||||
copyDstLevel++;
|
||||
@ -320,13 +320,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
var region = new ImageResolve(srcSl, new Offset3D(0, 0, srcZ), dstSl, new Offset3D(0, 0, dstZ), extent);
|
||||
|
||||
api.CmdResolveImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region);
|
||||
api.CmdResolveImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, in region);
|
||||
}
|
||||
else
|
||||
{
|
||||
var region = new ImageCopy(srcSl, new Offset3D(0, 0, srcZ), dstSl, new Offset3D(0, 0, dstZ), extent);
|
||||
|
||||
api.CmdCopyImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, region);
|
||||
api.CmdCopyImage(commandBuffer, srcImage, ImageLayout.General, dstImage, ImageLayout.General, 1, in region);
|
||||
}
|
||||
|
||||
width = Math.Max(1, width >> 1);
|
||||
@ -422,7 +422,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DependencyCount = 1,
|
||||
};
|
||||
|
||||
gd.Api.CreateRenderPass2(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError();
|
||||
gd.Api.CreateRenderPass2(device, in renderPassCreateInfo, null, out var renderPass).ThrowOnError();
|
||||
|
||||
using var rp = new Auto<DisposableRenderPass>(new DisposableRenderPass(gd.Api, device, renderPass));
|
||||
|
||||
@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Layers = (uint)src.Layers,
|
||||
};
|
||||
|
||||
gd.Api.CreateFramebuffer(device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
|
||||
gd.Api.CreateFramebuffer(device, in framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
|
||||
using var fb = new Auto<DisposableFramebuffer>(new DisposableFramebuffer(gd.Api, device, framebuffer), null, srcView, dstView);
|
||||
|
||||
var renderArea = new Rect2D(null, new Extent2D((uint)src.Info.Width, (uint)src.Info.Height));
|
||||
@ -465,7 +465,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
// to resolve the depth-stencil texture.
|
||||
// TODO: Do speculative resolve and part of the same render pass as the draw to avoid
|
||||
// ending the current render pass?
|
||||
gd.Api.CmdBeginRenderPass(cbs.CommandBuffer, renderPassBeginInfo, SubpassContents.Inline);
|
||||
gd.Api.CmdBeginRenderPass(cbs.CommandBuffer, in renderPassBeginInfo, SubpassContents.Inline);
|
||||
gd.Api.CmdEndRenderPass(cbs.CommandBuffer);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Format = Ryujinx.Graphics.GAL.Format;
|
||||
using VkBuffer = Silk.NET.Vulkan.Buffer;
|
||||
using VkFormat = Silk.NET.Vulkan.Format;
|
||||
@ -12,6 +13,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class TextureStorage : IDisposable
|
||||
{
|
||||
private struct TextureSliceInfo
|
||||
{
|
||||
public int BindCount;
|
||||
}
|
||||
|
||||
private const MemoryPropertyFlags DefaultImageMemoryFlags =
|
||||
MemoryPropertyFlags.DeviceLocalBit;
|
||||
|
||||
@ -43,6 +49,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly Image _image;
|
||||
private readonly Auto<DisposableImage> _imageAuto;
|
||||
private readonly Auto<MemoryAllocation> _allocationAuto;
|
||||
private readonly int _depthOrLayers;
|
||||
private Auto<MemoryAllocation> _foreignAllocationAuto;
|
||||
|
||||
private Dictionary<Format, TextureStorage> _aliasedStorages;
|
||||
@ -55,6 +62,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private int _viewsCount;
|
||||
private readonly ulong _size;
|
||||
|
||||
private int _bindCount;
|
||||
private readonly TextureSliceInfo[] _slices;
|
||||
|
||||
public VkFormat VkFormat { get; }
|
||||
|
||||
public unsafe TextureStorage(
|
||||
@ -73,6 +83,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1);
|
||||
|
||||
VkFormat = format;
|
||||
_depthOrLayers = info.GetDepthOrLayers();
|
||||
|
||||
var type = info.Target.Convert();
|
||||
|
||||
@ -80,7 +91,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples);
|
||||
|
||||
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample);
|
||||
var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities);
|
||||
|
||||
var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit;
|
||||
|
||||
@ -114,7 +125,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Flags = flags,
|
||||
};
|
||||
|
||||
gd.Api.CreateImage(device, imageCreateInfo, null, out _image).ThrowOnError();
|
||||
gd.Api.CreateImage(device, in imageCreateInfo, null, out _image).ThrowOnError();
|
||||
|
||||
if (foreignAllocation == null)
|
||||
{
|
||||
@ -148,6 +159,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
InitialTransition(ImageLayout.Preinitialized, ImageLayout.General);
|
||||
}
|
||||
|
||||
_slices = new TextureSliceInfo[levels * _depthOrLayers];
|
||||
}
|
||||
|
||||
public TextureStorage CreateAliasedColorForDepthStorageUnsafe(Format format)
|
||||
@ -284,7 +297,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
0,
|
||||
null,
|
||||
1,
|
||||
barrier);
|
||||
in barrier);
|
||||
|
||||
if (useTempCbs)
|
||||
{
|
||||
@ -292,7 +305,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public static ImageUsageFlags GetImageUsage(Format format, Target target, bool supportsMsStorage)
|
||||
public static ImageUsageFlags GetImageUsage(Format format, Target target, in HardwareCapabilities capabilities)
|
||||
{
|
||||
var usage = DefaultUsageFlags;
|
||||
|
||||
@ -305,11 +318,19 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
usage |= ImageUsageFlags.ColorAttachmentBit;
|
||||
}
|
||||
|
||||
bool supportsMsStorage = capabilities.SupportsShaderStorageImageMultisample;
|
||||
|
||||
if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample()))
|
||||
{
|
||||
usage |= ImageUsageFlags.StorageBit;
|
||||
}
|
||||
|
||||
if (capabilities.SupportsAttachmentFeedbackLoop &&
|
||||
(usage & (ImageUsageFlags.DepthStencilAttachmentBit | ImageUsageFlags.ColorAttachmentBit)) != 0)
|
||||
{
|
||||
usage |= ImageUsageFlags.AttachmentFeedbackLoopBitExt;
|
||||
}
|
||||
|
||||
return usage;
|
||||
}
|
||||
|
||||
@ -401,11 +422,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (to)
|
||||
{
|
||||
_gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
|
||||
_gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, in region);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
|
||||
_gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, in region);
|
||||
}
|
||||
|
||||
offset += mipSize;
|
||||
@ -510,6 +531,55 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBinding(TextureView view)
|
||||
{
|
||||
// Assumes a view only has a first level.
|
||||
|
||||
int index = view.FirstLevel * _depthOrLayers + view.FirstLayer;
|
||||
int layers = view.Layers;
|
||||
|
||||
for (int i = 0; i < layers; i++)
|
||||
{
|
||||
ref TextureSliceInfo info = ref _slices[index++];
|
||||
|
||||
info.BindCount++;
|
||||
}
|
||||
|
||||
_bindCount++;
|
||||
}
|
||||
|
||||
public void ClearBindings()
|
||||
{
|
||||
if (_bindCount != 0)
|
||||
{
|
||||
Array.Clear(_slices, 0, _slices.Length);
|
||||
|
||||
_bindCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool IsBound(TextureView view)
|
||||
{
|
||||
if (_bindCount != 0)
|
||||
{
|
||||
int index = view.FirstLevel * _depthOrLayers + view.FirstLayer;
|
||||
int layers = view.Layers;
|
||||
|
||||
for (int i = 0; i < layers; i++)
|
||||
{
|
||||
ref TextureSliceInfo info = ref _slices[index++];
|
||||
|
||||
if (info.BindCount != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void IncrementViewsCount()
|
||||
{
|
||||
_viewsCount++;
|
||||
|
@ -23,6 +23,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private readonly Auto<DisposableImageView> _imageView2dArray;
|
||||
private Dictionary<Format, TextureView> _selfManagedViews;
|
||||
|
||||
private int _hazardUses;
|
||||
|
||||
private readonly TextureCreateInfo _info;
|
||||
|
||||
private HashTableSlim<RenderPassCacheKey, RenderPassHolder> _renderPasses;
|
||||
@ -60,7 +62,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
gd.Textures.Add(this);
|
||||
|
||||
var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format);
|
||||
var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities.SupportsShaderStorageImageMultisample);
|
||||
var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities);
|
||||
var levels = (uint)info.Levels;
|
||||
var layers = (uint)info.GetLayers();
|
||||
|
||||
@ -117,7 +119,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
PNext = &imageViewUsage,
|
||||
};
|
||||
|
||||
gd.Api.CreateImageView(device, imageCreateInfo, null, out var imageView).ThrowOnError();
|
||||
gd.Api.CreateImageView(device, in imageCreateInfo, null, out var imageView).ThrowOnError();
|
||||
return new Auto<DisposableImageView>(new DisposableImageView(gd.Api, device, imageView), null, storage.GetImage());
|
||||
}
|
||||
|
||||
@ -492,7 +494,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
dstStageMask,
|
||||
DependencyFlags.None,
|
||||
1,
|
||||
memoryBarrier,
|
||||
in memoryBarrier,
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
@ -557,7 +559,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
0,
|
||||
null,
|
||||
1,
|
||||
memoryBarrier);
|
||||
in memoryBarrier);
|
||||
}
|
||||
|
||||
public TextureView GetView(Format format)
|
||||
@ -949,11 +951,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (to)
|
||||
{
|
||||
_gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
|
||||
_gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, in region);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
|
||||
_gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, in region);
|
||||
}
|
||||
|
||||
offset += mipSize;
|
||||
@ -1010,11 +1012,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
if (to)
|
||||
{
|
||||
_gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, region);
|
||||
_gd.Api.CmdCopyImageToBuffer(commandBuffer, image, ImageLayout.General, buffer, 1, in region);
|
||||
}
|
||||
else
|
||||
{
|
||||
_gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, region);
|
||||
_gd.Api.CmdCopyBufferToImage(commandBuffer, buffer, image, ImageLayout.General, 1, in region);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1034,6 +1036,34 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void PrepareForUsage(CommandBufferScoped cbs, PipelineStageFlags flags, List<TextureView> feedbackLoopHazards)
|
||||
{
|
||||
Storage.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, flags);
|
||||
|
||||
if (feedbackLoopHazards != null && Storage.IsBound(this))
|
||||
{
|
||||
feedbackLoopHazards.Add(this);
|
||||
_hazardUses++;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearUsage(List<TextureView> feedbackLoopHazards)
|
||||
{
|
||||
if (_hazardUses != 0 && feedbackLoopHazards != null)
|
||||
{
|
||||
feedbackLoopHazards.Remove(this);
|
||||
_hazardUses--;
|
||||
}
|
||||
}
|
||||
|
||||
public void DecrementHazardUses()
|
||||
{
|
||||
if (_hazardUses != 0)
|
||||
{
|
||||
_hazardUses--;
|
||||
}
|
||||
}
|
||||
|
||||
public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer(
|
||||
VulkanRenderer gd,
|
||||
Device device,
|
||||
|
@ -90,11 +90,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DriverId.SamsungProprietary => "Samsung",
|
||||
DriverId.MesaVenus => "Venus",
|
||||
DriverId.MesaDozen => "Dozen",
|
||||
|
||||
// TODO: Use real enum when we have an up to date Silk.NET.
|
||||
(DriverId)24 => "NVK",
|
||||
(DriverId)25 => "Imagination (Open)",
|
||||
(DriverId)26 => "Honeykrisp",
|
||||
DriverId.MesaNvk => "NVK",
|
||||
DriverId.ImaginationOpenSourceMesa => "Imagination (Open)",
|
||||
DriverId.MesaAgxv => "Honeykrisp",
|
||||
_ => id.ToString(),
|
||||
};
|
||||
}
|
||||
|
@ -44,6 +44,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
"VK_EXT_4444_formats",
|
||||
"VK_KHR_8bit_storage",
|
||||
"VK_KHR_maintenance2",
|
||||
"VK_EXT_attachment_feedback_loop_layout",
|
||||
"VK_EXT_attachment_feedback_loop_dynamic_state",
|
||||
};
|
||||
|
||||
private static readonly string[] _requiredExtensions = {
|
||||
@ -357,6 +359,28 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
features2.PNext = &supportedFeaturesDepthClipControl;
|
||||
}
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT supportedFeaturesAttachmentFeedbackLoopLayout = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||
PNext = features2.PNext,
|
||||
};
|
||||
|
||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout"))
|
||||
{
|
||||
features2.PNext = &supportedFeaturesAttachmentFeedbackLoopLayout;
|
||||
}
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT supportedFeaturesDynamicAttachmentFeedbackLoopLayout = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||
PNext = features2.PNext,
|
||||
};
|
||||
|
||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state"))
|
||||
{
|
||||
features2.PNext = &supportedFeaturesDynamicAttachmentFeedbackLoopLayout;
|
||||
}
|
||||
|
||||
PhysicalDeviceVulkan12Features supportedPhysicalDeviceVulkan12Features = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceVulkan12Features,
|
||||
@ -531,6 +555,36 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
pExtendedFeatures = &featuresDepthClipControl;
|
||||
}
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoopLayout;
|
||||
|
||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout") &&
|
||||
supportedFeaturesAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopLayout)
|
||||
{
|
||||
featuresAttachmentFeedbackLoopLayout = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||
PNext = pExtendedFeatures,
|
||||
AttachmentFeedbackLoopLayout = true,
|
||||
};
|
||||
|
||||
pExtendedFeatures = &featuresAttachmentFeedbackLoopLayout;
|
||||
}
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoopLayout;
|
||||
|
||||
if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state") &&
|
||||
supportedFeaturesDynamicAttachmentFeedbackLoopLayout.AttachmentFeedbackLoopDynamicState)
|
||||
{
|
||||
featuresDynamicAttachmentFeedbackLoopLayout = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||
PNext = pExtendedFeatures,
|
||||
AttachmentFeedbackLoopDynamicState = true,
|
||||
};
|
||||
|
||||
pExtendedFeatures = &featuresDynamicAttachmentFeedbackLoopLayout;
|
||||
}
|
||||
|
||||
var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray();
|
||||
|
||||
IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length];
|
||||
|
@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
internal KhrPushDescriptor PushDescriptorApi { get; private set; }
|
||||
internal ExtTransformFeedback TransformFeedbackApi { get; private set; }
|
||||
internal KhrDrawIndirectCount DrawIndirectCountApi { get; private set; }
|
||||
internal ExtAttachmentFeedbackLoopDynamicState DynamicFeedbackLoopApi { get; private set; }
|
||||
|
||||
internal uint QueueFamilyIndex { get; private set; }
|
||||
internal Queue Queue { get; private set; }
|
||||
@ -149,6 +150,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DrawIndirectCountApi = drawIndirectCountApi;
|
||||
}
|
||||
|
||||
if (Api.TryGetDeviceExtension(_instance.Instance, _device, out ExtAttachmentFeedbackLoopDynamicState dynamicFeedbackLoopApi))
|
||||
{
|
||||
DynamicFeedbackLoopApi = dynamicFeedbackLoopApi;
|
||||
}
|
||||
|
||||
if (maxQueueCount >= 2)
|
||||
{
|
||||
Api.GetDeviceQueue(_device, queueFamilyIndex, 1, out var backgroundQueue);
|
||||
@ -243,6 +249,16 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt,
|
||||
};
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT featuresAttachmentFeedbackLoop = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesExt,
|
||||
};
|
||||
|
||||
PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesEXT featuresDynamicAttachmentFeedbackLoop = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDeviceAttachmentFeedbackLoopDynamicStateFeaturesExt,
|
||||
};
|
||||
|
||||
PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new()
|
||||
{
|
||||
SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr,
|
||||
@ -279,6 +295,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
features2.PNext = &featuresDepthClipControl;
|
||||
}
|
||||
|
||||
bool supportsAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_layout");
|
||||
|
||||
if (supportsAttachmentFeedbackLoop)
|
||||
{
|
||||
featuresAttachmentFeedbackLoop.PNext = features2.PNext;
|
||||
features2.PNext = &featuresAttachmentFeedbackLoop;
|
||||
}
|
||||
|
||||
bool supportsDynamicAttachmentFeedbackLoop = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_attachment_feedback_loop_dynamic_state");
|
||||
|
||||
if (supportsDynamicAttachmentFeedbackLoop)
|
||||
{
|
||||
featuresDynamicAttachmentFeedbackLoop.PNext = features2.PNext;
|
||||
features2.PNext = &featuresDynamicAttachmentFeedbackLoop;
|
||||
}
|
||||
|
||||
bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset");
|
||||
|
||||
if (usePortability)
|
||||
@ -401,6 +433,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"),
|
||||
_physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName),
|
||||
supportsDepthClipControl && featuresDepthClipControl.DepthClipControl,
|
||||
supportsAttachmentFeedbackLoop && featuresAttachmentFeedbackLoop.AttachmentFeedbackLoopLayout,
|
||||
supportsDynamicAttachmentFeedbackLoop && featuresDynamicAttachmentFeedbackLoop.AttachmentFeedbackLoopDynamicState,
|
||||
propertiesSubgroup.SubgroupSize,
|
||||
supportedSampleCounts,
|
||||
portabilityFlags,
|
||||
|
@ -160,7 +160,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SwizzleComponent.Blue,
|
||||
SwizzleComponent.Alpha);
|
||||
|
||||
_gd.SwapchainApi.CreateSwapchain(_device, swapchainCreateInfo, null, out _swapchain).ThrowOnError();
|
||||
_gd.SwapchainApi.CreateSwapchain(_device, in swapchainCreateInfo, null, out _swapchain).ThrowOnError();
|
||||
|
||||
_gd.SwapchainApi.GetSwapchainImages(_device, _swapchain, &imageCount, null);
|
||||
|
||||
@ -187,14 +187,14 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
for (int i = 0; i < _imageAvailableSemaphores.Length; i++)
|
||||
{
|
||||
_gd.Api.CreateSemaphore(_device, semaphoreCreateInfo, null, out _imageAvailableSemaphores[i]).ThrowOnError();
|
||||
_gd.Api.CreateSemaphore(_device, in semaphoreCreateInfo, null, out _imageAvailableSemaphores[i]).ThrowOnError();
|
||||
}
|
||||
|
||||
_renderFinishedSemaphores = new Semaphore[imageCount];
|
||||
|
||||
for (int i = 0; i < _renderFinishedSemaphores.Length; i++)
|
||||
{
|
||||
_gd.Api.CreateSemaphore(_device, semaphoreCreateInfo, null, out _renderFinishedSemaphores[i]).ThrowOnError();
|
||||
_gd.Api.CreateSemaphore(_device, in semaphoreCreateInfo, null, out _renderFinishedSemaphores[i]).ThrowOnError();
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,7 +220,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SubresourceRange = subresourceRange,
|
||||
};
|
||||
|
||||
_gd.Api.CreateImageView(_device, imageCreateInfo, null, out var imageView).ThrowOnError();
|
||||
_gd.Api.CreateImageView(_device, in imageCreateInfo, null, out var imageView).ThrowOnError();
|
||||
|
||||
return new TextureView(_gd, _device, new DisposableImageView(_gd.Api, _device, imageView), info, format);
|
||||
}
|
||||
@ -479,7 +479,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
lock (_gd.QueueLock)
|
||||
{
|
||||
_gd.SwapchainApi.QueuePresent(_gd.Queue, presentInfo);
|
||||
_gd.SwapchainApi.QueuePresent(_gd.Queue, in presentInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@ -568,6 +568,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_scalingFilter.Level = _scalingFilterLevel;
|
||||
break;
|
||||
case ScalingFilter.Area:
|
||||
if (_scalingFilter is not AreaScalingFilter)
|
||||
{
|
||||
_scalingFilter?.Dispose();
|
||||
_scalingFilter = new AreaScalingFilter(_gd, _device);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -611,7 +618,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
0,
|
||||
null,
|
||||
1,
|
||||
barrier);
|
||||
in barrier);
|
||||
}
|
||||
|
||||
private void CaptureFrame(TextureView texture, int x, int y, int width, int height, bool isBgra, bool flipX, bool flipY)
|
||||
|
@ -4,6 +4,8 @@ using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.GraphicsDriver;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using Ryujinx.UI;
|
||||
@ -13,7 +15,6 @@ using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Helper;
|
||||
using Ryujinx.UI.Common.SystemInfo;
|
||||
using Ryujinx.UI.Widgets;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@ -41,9 +42,6 @@ namespace Ryujinx
|
||||
[LibraryImport("user32.dll", SetLastError = true)]
|
||||
public static partial int MessageBoxA(IntPtr hWnd, [MarshalAs(UnmanagedType.LPStr)] string text, [MarshalAs(UnmanagedType.LPStr)] string caption, uint type);
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int setenv([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value, int overwrite);
|
||||
|
||||
private const uint MbIconWarning = 0x30;
|
||||
|
||||
static Program()
|
||||
@ -105,12 +103,13 @@ namespace Ryujinx
|
||||
throw new NotSupportedException("Failed to initialize multi-threading support.");
|
||||
}
|
||||
|
||||
Environment.SetEnvironmentVariable("GDK_BACKEND", "x11");
|
||||
setenv("GDK_BACKEND", "x11", 1);
|
||||
OsUtils.SetEnvironmentVariableNoCaching("GDK_BACKEND", "x11");
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
MVKInitialization.InitializeResolver();
|
||||
|
||||
string baseDirectory = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
|
||||
string resourcesDataDir;
|
||||
|
||||
@ -123,19 +122,13 @@ namespace Ryujinx
|
||||
resourcesDataDir = baseDirectory;
|
||||
}
|
||||
|
||||
static void SetEnvironmentVariableNoCaching(string key, string value)
|
||||
{
|
||||
int res = setenv(key, value, 1);
|
||||
Debug.Assert(res != -1);
|
||||
}
|
||||
|
||||
// On macOS, GTK3 needs XDG_DATA_DIRS to be set, otherwise it will try searching for "gschemas.compiled" in system directories.
|
||||
SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share"));
|
||||
OsUtils.SetEnvironmentVariableNoCaching("XDG_DATA_DIRS", Path.Combine(resourcesDataDir, "share"));
|
||||
|
||||
// On macOS, GTK3 needs GDK_PIXBUF_MODULE_FILE to be set, otherwise it will try searching for "loaders.cache" in system directories.
|
||||
SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache"));
|
||||
OsUtils.SetEnvironmentVariableNoCaching("GDK_PIXBUF_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gdk-pixbuf-2.0", "2.10.0", "loaders.cache"));
|
||||
|
||||
SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache"));
|
||||
OsUtils.SetEnvironmentVariableNoCaching("GTK_IM_MODULE_FILE", Path.Combine(resourcesDataDir, "lib", "gtk-3.0", "3.0.0", "immodules.cache"));
|
||||
}
|
||||
|
||||
string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine);
|
||||
@ -162,12 +155,6 @@ namespace Ryujinx
|
||||
});
|
||||
};
|
||||
|
||||
// Sets ImageSharp Jpeg Encoder Quality.
|
||||
SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder()
|
||||
{
|
||||
Quality = 100,
|
||||
});
|
||||
|
||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
|
||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
|
||||
|
||||
@ -237,9 +224,9 @@ namespace Ryujinx
|
||||
// Logging system information.
|
||||
PrintSystemInfo();
|
||||
|
||||
// Enable OGL multithreading on the driver, when available.
|
||||
// Enable OGL multithreading on the driver, and some other flags.
|
||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||
DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off);
|
||||
DriverUtilities.InitDriverConfig(threadingMode == BackendThreading.Off);
|
||||
|
||||
// Initialize Gtk.
|
||||
Application.Init();
|
||||
|
@ -30,7 +30,6 @@
|
||||
<PackageReference Include="OpenTK.Graphics" />
|
||||
<PackageReference Include="SPB" />
|
||||
<PackageReference Include="SharpZipLib" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -647,7 +647,7 @@ namespace Ryujinx.UI
|
||||
}
|
||||
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value
|
||||
? HLE.MemoryConfiguration.MemoryConfiguration6GiB
|
||||
? HLE.MemoryConfiguration.MemoryConfiguration8GiB
|
||||
: HLE.MemoryConfiguration.MemoryConfiguration4GiB;
|
||||
|
||||
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;
|
||||
|
@ -13,16 +13,13 @@ using Ryujinx.Input.HLE;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.UI.Common.Helper;
|
||||
using Ryujinx.UI.Widgets;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
using Key = Ryujinx.Input.Key;
|
||||
using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter;
|
||||
using Switch = Ryujinx.HLE.Switch;
|
||||
@ -404,23 +401,31 @@ namespace Ryujinx.UI
|
||||
return;
|
||||
}
|
||||
|
||||
Image image = e.IsBgra ? Image.LoadPixelData<Bgra32>(e.Data, e.Width, e.Height)
|
||||
: Image.LoadPixelData<Rgba32>(e.Data, e.Width, e.Height);
|
||||
var colorType = e.IsBgra ? SKColorType.Bgra8888 : SKColorType.Rgba8888;
|
||||
using var image = new SKBitmap(new SKImageInfo(e.Width, e.Height, colorType, SKAlphaType.Premul));
|
||||
|
||||
if (e.FlipX)
|
||||
Marshal.Copy(e.Data, 0, image.GetPixels(), e.Data.Length);
|
||||
using var surface = SKSurface.Create(image.Info);
|
||||
var canvas = surface.Canvas;
|
||||
|
||||
if (e.FlipX || e.FlipY)
|
||||
{
|
||||
image.Mutate(x => x.Flip(FlipMode.Horizontal));
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
|
||||
float scaleX = e.FlipX ? -1 : 1;
|
||||
float scaleY = e.FlipY ? -1 : 1;
|
||||
|
||||
var matrix = SKMatrix.CreateScale(scaleX, scaleY, image.Width / 2f, image.Height / 2f);
|
||||
|
||||
canvas.SetMatrix(matrix);
|
||||
}
|
||||
canvas.DrawBitmap(image, new SKPoint());
|
||||
|
||||
if (e.FlipY)
|
||||
{
|
||||
image.Mutate(x => x.Flip(FlipMode.Vertical));
|
||||
}
|
||||
|
||||
image.SaveAsPng(path, new PngEncoder()
|
||||
{
|
||||
ColorType = PngColorType.Rgb,
|
||||
});
|
||||
surface.Flush();
|
||||
using var snapshot = surface.Snapshot();
|
||||
using var encoded = snapshot.Encode(SKEncodedImageFormat.Png, 80);
|
||||
using var file = File.OpenWrite(path);
|
||||
encoded.SaveTo(file);
|
||||
|
||||
image.Dispose();
|
||||
|
||||
|
@ -9,16 +9,13 @@ using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.UI.Windows
|
||||
{
|
||||
@ -144,9 +141,11 @@ namespace Ryujinx.UI.Windows
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256);
|
||||
using var avatarImage = new SKBitmap(new SKImageInfo(256, 256, SKColorType.Rgba8888));
|
||||
var data = DecompressYaz0(stream);
|
||||
Marshal.Copy(data, 0, avatarImage.GetPixels(), data.Length);
|
||||
|
||||
avatarImage.SaveAsPng(streamPng);
|
||||
avatarImage.Encode(streamPng, SKEncodedImageFormat.Png, 80);
|
||||
|
||||
_avatarDict.Add(item.FullPath, streamPng.ToArray());
|
||||
}
|
||||
@ -170,15 +169,23 @@ namespace Ryujinx.UI.Windows
|
||||
{
|
||||
using MemoryStream streamJpg = MemoryStreamManager.Shared.GetStream();
|
||||
|
||||
Image avatarImage = Image.Load(data, new PngDecoder());
|
||||
using var avatarImage = SKBitmap.Decode(data);
|
||||
using var surface = SKSurface.Create(avatarImage.Info);
|
||||
|
||||
avatarImage.Mutate(x => x.BackgroundColor(new Rgba32(
|
||||
var background = new SKColor(
|
||||
(byte)(_backgroundColor.Red * 255),
|
||||
(byte)(_backgroundColor.Green * 255),
|
||||
(byte)(_backgroundColor.Blue * 255),
|
||||
(byte)(_backgroundColor.Alpha * 255)
|
||||
)));
|
||||
avatarImage.SaveAsJpeg(streamJpg);
|
||||
);
|
||||
var canvas = surface.Canvas;
|
||||
canvas.Clear(background);
|
||||
canvas.DrawBitmap(avatarImage, new SKPoint());
|
||||
|
||||
surface.Flush();
|
||||
using var snapshot = surface.Snapshot();
|
||||
using var encoded = snapshot.Encode(SKEncodedImageFormat.Jpeg, 80);
|
||||
encoded.SaveTo(streamJpg);
|
||||
|
||||
return streamJpg.ToArray();
|
||||
}
|
||||
|
@ -4,15 +4,13 @@ using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.UI.Common.Configuration;
|
||||
using Ryujinx.UI.Widgets;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
|
||||
namespace Ryujinx.UI.Windows
|
||||
{
|
||||
@ -177,13 +175,13 @@ namespace Ryujinx.UI.Windows
|
||||
|
||||
private void ProcessProfileImage(byte[] buffer)
|
||||
{
|
||||
using Image image = Image.Load(buffer);
|
||||
using var image = SKBitmap.Decode(buffer);
|
||||
|
||||
image.Mutate(x => x.Resize(256, 256));
|
||||
image.Resize(new SKImageInfo(256, 256), SKFilterQuality.High);
|
||||
|
||||
using MemoryStream streamJpg = MemoryStreamManager.Shared.GetStream();
|
||||
|
||||
image.SaveAsJpeg(streamJpg);
|
||||
image.Encode(streamJpg, SKEncodedImageFormat.Jpeg, 80);
|
||||
|
||||
_bufferImageProfile = streamJpg.ToArray();
|
||||
}
|
||||
|
63
src/Ryujinx.HLE.Generators/CodeGenerator.cs
Normal file
63
src/Ryujinx.HLE.Generators/CodeGenerator.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.Generators
|
||||
{
|
||||
class CodeGenerator
|
||||
{
|
||||
private const int IndentLength = 4;
|
||||
|
||||
private readonly StringBuilder _sb;
|
||||
private int _currentIndentCount;
|
||||
|
||||
public CodeGenerator()
|
||||
{
|
||||
_sb = new StringBuilder();
|
||||
}
|
||||
|
||||
public void EnterScope(string header = null)
|
||||
{
|
||||
if (header != null)
|
||||
{
|
||||
AppendLine(header);
|
||||
}
|
||||
|
||||
AppendLine("{");
|
||||
IncreaseIndentation();
|
||||
}
|
||||
|
||||
public void LeaveScope(string suffix = "")
|
||||
{
|
||||
DecreaseIndentation();
|
||||
AppendLine($"}}{suffix}");
|
||||
}
|
||||
|
||||
public void IncreaseIndentation()
|
||||
{
|
||||
_currentIndentCount++;
|
||||
}
|
||||
|
||||
public void DecreaseIndentation()
|
||||
{
|
||||
if (_currentIndentCount - 1 >= 0)
|
||||
{
|
||||
_currentIndentCount--;
|
||||
}
|
||||
}
|
||||
|
||||
public void AppendLine()
|
||||
{
|
||||
_sb.AppendLine();
|
||||
}
|
||||
|
||||
public void AppendLine(string text)
|
||||
{
|
||||
_sb.Append(' ', IndentLength * _currentIndentCount);
|
||||
_sb.AppendLine(text);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
76
src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs
Normal file
76
src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs
Normal file
@ -0,0 +1,76 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.HLE.Generators
|
||||
{
|
||||
[Generator]
|
||||
public class IpcServiceGenerator : ISourceGenerator
|
||||
{
|
||||
public void Execute(GeneratorExecutionContext context)
|
||||
{
|
||||
var syntaxReceiver = (ServiceSyntaxReceiver)context.SyntaxReceiver;
|
||||
CodeGenerator generator = new CodeGenerator();
|
||||
|
||||
generator.AppendLine("using System;");
|
||||
generator.EnterScope($"namespace Ryujinx.HLE.HOS.Services.Sm");
|
||||
generator.EnterScope($"partial class IUserInterface");
|
||||
|
||||
generator.EnterScope($"public IpcService? GetServiceInstance(Type type, ServiceCtx context, object? parameter = null)");
|
||||
foreach (var className in syntaxReceiver.Types)
|
||||
{
|
||||
if (className.Modifiers.Any(SyntaxKind.AbstractKeyword) || className.Modifiers.Any(SyntaxKind.PrivateKeyword) || !className.AttributeLists.Any(x => x.Attributes.Any(y => y.ToString().StartsWith("Service"))))
|
||||
continue;
|
||||
var name = GetFullName(className, context).Replace("global::", "");
|
||||
if (!name.StartsWith("Ryujinx.HLE.HOS.Services"))
|
||||
continue;
|
||||
var constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax);
|
||||
|
||||
if (!constructors.Any(x => x.ParameterList.Parameters.Count >= 1))
|
||||
continue;
|
||||
|
||||
if (constructors.Where(x => x.ParameterList.Parameters.Count >= 1).FirstOrDefault().ParameterList.Parameters[0].Type.ToString() == "ServiceCtx")
|
||||
{
|
||||
generator.EnterScope($"if (type == typeof({GetFullName(className, context)}))");
|
||||
if (constructors.Any(x => x.ParameterList.Parameters.Count == 2))
|
||||
{
|
||||
var type = constructors.Where(x => x.ParameterList.Parameters.Count == 2).FirstOrDefault().ParameterList.Parameters[1].Type;
|
||||
var model = context.Compilation.GetSemanticModel(type.SyntaxTree);
|
||||
var typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol;
|
||||
var fullName = typeSymbol.ToString();
|
||||
generator.EnterScope("if (parameter != null)");
|
||||
generator.AppendLine($"return new {GetFullName(className, context)}(context, ({fullName})parameter);");
|
||||
generator.LeaveScope();
|
||||
}
|
||||
|
||||
if (constructors.Any(x => x.ParameterList.Parameters.Count == 1))
|
||||
{
|
||||
generator.AppendLine($"return new {GetFullName(className, context)}(context);");
|
||||
}
|
||||
|
||||
generator.LeaveScope();
|
||||
}
|
||||
}
|
||||
|
||||
generator.AppendLine("return null;");
|
||||
generator.LeaveScope();
|
||||
|
||||
generator.LeaveScope();
|
||||
generator.LeaveScope();
|
||||
context.AddSource($"IUserInterface.g.cs", generator.ToString());
|
||||
}
|
||||
|
||||
private string GetFullName(ClassDeclarationSyntax syntaxNode, GeneratorExecutionContext context)
|
||||
{
|
||||
var typeSymbol = context.Compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
|
||||
|
||||
return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||
}
|
||||
|
||||
public void Initialize(GeneratorInitializationContext context)
|
||||
{
|
||||
context.RegisterForSyntaxNotifications(() => new ServiceSyntaxReceiver());
|
||||
}
|
||||
}
|
||||
}
|
19
src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj
Normal file
19
src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj
Normal file
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
|
||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||
<CompilerGeneratedFilesOutputPath>Generated</CompilerGeneratedFilesOutputPath>
|
||||
<IsRoslynComponent>true</IsRoslynComponent>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
24
src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs
Normal file
24
src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.Generators
|
||||
{
|
||||
internal class ServiceSyntaxReceiver : ISyntaxReceiver
|
||||
{
|
||||
public HashSet<ClassDeclarationSyntax> Types = new HashSet<ClassDeclarationSyntax>();
|
||||
|
||||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
|
||||
{
|
||||
if (syntaxNode is ClassDeclarationSyntax classDeclaration)
|
||||
{
|
||||
if (classDeclaration.BaseList == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Types.Add(classDeclaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -8,27 +8,24 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
static class AppletManager
|
||||
{
|
||||
private static readonly Dictionary<AppletId, Type> _appletMapping;
|
||||
|
||||
static AppletManager()
|
||||
{
|
||||
_appletMapping = new Dictionary<AppletId, Type>
|
||||
{
|
||||
{ AppletId.Error, typeof(ErrorApplet) },
|
||||
{ AppletId.PlayerSelect, typeof(PlayerSelectApplet) },
|
||||
{ AppletId.Controller, typeof(ControllerApplet) },
|
||||
{ AppletId.SoftwareKeyboard, typeof(SoftwareKeyboardApplet) },
|
||||
{ AppletId.LibAppletWeb, typeof(BrowserApplet) },
|
||||
{ AppletId.LibAppletShop, typeof(BrowserApplet) },
|
||||
{ AppletId.LibAppletOff, typeof(BrowserApplet) },
|
||||
};
|
||||
}
|
||||
|
||||
public static IApplet Create(AppletId applet, Horizon system)
|
||||
{
|
||||
if (_appletMapping.TryGetValue(applet, out Type appletClass))
|
||||
switch (applet)
|
||||
{
|
||||
return (IApplet)Activator.CreateInstance(appletClass, system);
|
||||
case AppletId.Controller:
|
||||
return new ControllerApplet(system);
|
||||
case AppletId.Error:
|
||||
return new ErrorApplet(system);
|
||||
case AppletId.PlayerSelect:
|
||||
return new PlayerSelectApplet(system);
|
||||
case AppletId.SoftwareKeyboard:
|
||||
return new SoftwareKeyboardApplet(system);
|
||||
case AppletId.LibAppletWeb:
|
||||
return new BrowserApplet(system);
|
||||
case AppletId.LibAppletShop:
|
||||
return new BrowserApplet(system);
|
||||
case AppletId.LibAppletOff:
|
||||
return new BrowserApplet(system);
|
||||
}
|
||||
|
||||
throw new NotImplementedException($"{applet} applet is not implemented.");
|
||||
|
@ -112,11 +112,16 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
{
|
||||
// Update the parameters that were provided.
|
||||
_state.InputText = inputText ?? _state.InputText;
|
||||
_state.CursorBegin = cursorBegin.GetValueOrDefault(_state.CursorBegin);
|
||||
_state.CursorEnd = cursorEnd.GetValueOrDefault(_state.CursorEnd);
|
||||
_state.CursorBegin = Math.Max(0, cursorBegin.GetValueOrDefault(_state.CursorBegin));
|
||||
_state.CursorEnd = Math.Min(cursorEnd.GetValueOrDefault(_state.CursorEnd), _state.InputText.Length);
|
||||
_state.OverwriteMode = overwriteMode.GetValueOrDefault(_state.OverwriteMode);
|
||||
_state.TypingEnabled = typingEnabled.GetValueOrDefault(_state.TypingEnabled);
|
||||
|
||||
var begin = _state.CursorBegin;
|
||||
var end = _state.CursorEnd;
|
||||
_state.CursorBegin = Math.Min(begin, end);
|
||||
_state.CursorEnd = Math.Max(begin, end);
|
||||
|
||||
// Reset the cursor blink.
|
||||
_state.TextBoxBlinkCounter = 0;
|
||||
|
||||
|
@ -1,14 +1,9 @@
|
||||
using Ryujinx.HLE.UI;
|
||||
using Ryujinx.Memory;
|
||||
using SixLabors.Fonts;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Drawing.Processing;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@ -29,38 +24,39 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
private readonly object _bufferLock = new();
|
||||
|
||||
private RenderingSurfaceInfo _surfaceInfo = null;
|
||||
private Image<Argb32> _surface = null;
|
||||
private SKImageInfo _imageInfo;
|
||||
private SKSurface _surface = null;
|
||||
private byte[] _bufferData = null;
|
||||
|
||||
private readonly Image _ryujinxLogo = null;
|
||||
private readonly Image _padAcceptIcon = null;
|
||||
private readonly Image _padCancelIcon = null;
|
||||
private readonly Image _keyModeIcon = null;
|
||||
private readonly SKBitmap _ryujinxLogo = null;
|
||||
private readonly SKBitmap _padAcceptIcon = null;
|
||||
private readonly SKBitmap _padCancelIcon = null;
|
||||
private readonly SKBitmap _keyModeIcon = null;
|
||||
|
||||
private readonly float _textBoxOutlineWidth;
|
||||
private readonly float _padPressedPenWidth;
|
||||
|
||||
private readonly Color _textNormalColor;
|
||||
private readonly Color _textSelectedColor;
|
||||
private readonly Color _textOverCursorColor;
|
||||
private readonly SKColor _textNormalColor;
|
||||
private readonly SKColor _textSelectedColor;
|
||||
private readonly SKColor _textOverCursorColor;
|
||||
|
||||
private readonly Brush _panelBrush;
|
||||
private readonly Brush _disabledBrush;
|
||||
private readonly Brush _cursorBrush;
|
||||
private readonly Brush _selectionBoxBrush;
|
||||
private readonly SKPaint _panelBrush;
|
||||
private readonly SKPaint _disabledBrush;
|
||||
private readonly SKPaint _cursorBrush;
|
||||
private readonly SKPaint _selectionBoxBrush;
|
||||
|
||||
private readonly Pen _textBoxOutlinePen;
|
||||
private readonly Pen _cursorPen;
|
||||
private readonly Pen _selectionBoxPen;
|
||||
private readonly Pen _padPressedPen;
|
||||
private readonly SKPaint _textBoxOutlinePen;
|
||||
private readonly SKPaint _cursorPen;
|
||||
private readonly SKPaint _selectionBoxPen;
|
||||
private readonly SKPaint _padPressedPen;
|
||||
|
||||
private readonly int _inputTextFontSize;
|
||||
private Font _messageFont;
|
||||
private Font _inputTextFont;
|
||||
private Font _labelsTextFont;
|
||||
private SKFont _messageFont;
|
||||
private SKFont _inputTextFont;
|
||||
private SKFont _labelsTextFont;
|
||||
|
||||
private RectangleF _panelRectangle;
|
||||
private Point _logoPosition;
|
||||
private SKRect _panelRectangle;
|
||||
private SKPoint _logoPosition;
|
||||
private float _messagePositionY;
|
||||
|
||||
public SoftwareKeyboardRendererBase(IHostUITheme uiTheme)
|
||||
@ -78,10 +74,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
_padCancelIcon = LoadResource(typeof(SoftwareKeyboardRendererBase).Assembly, padCancelIconPath, 0, 0);
|
||||
_keyModeIcon = LoadResource(typeof(SoftwareKeyboardRendererBase).Assembly, keyModeIconPath, 0, 0);
|
||||
|
||||
Color panelColor = ToColor(uiTheme.DefaultBackgroundColor, 255);
|
||||
Color panelTransparentColor = ToColor(uiTheme.DefaultBackgroundColor, 150);
|
||||
Color borderColor = ToColor(uiTheme.DefaultBorderColor);
|
||||
Color selectionBackgroundColor = ToColor(uiTheme.SelectionBackgroundColor);
|
||||
var panelColor = ToColor(uiTheme.DefaultBackgroundColor, 255);
|
||||
var panelTransparentColor = ToColor(uiTheme.DefaultBackgroundColor, 150);
|
||||
var borderColor = ToColor(uiTheme.DefaultBorderColor);
|
||||
var selectionBackgroundColor = ToColor(uiTheme.SelectionBackgroundColor);
|
||||
|
||||
_textNormalColor = ToColor(uiTheme.DefaultForegroundColor);
|
||||
_textSelectedColor = ToColor(uiTheme.SelectionForegroundColor);
|
||||
@ -92,15 +88,29 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
_textBoxOutlineWidth = 2;
|
||||
_padPressedPenWidth = 2;
|
||||
|
||||
_panelBrush = new SolidBrush(panelColor);
|
||||
_disabledBrush = new SolidBrush(panelTransparentColor);
|
||||
_cursorBrush = new SolidBrush(_textNormalColor);
|
||||
_selectionBoxBrush = new SolidBrush(selectionBackgroundColor);
|
||||
_panelBrush = new SKPaint()
|
||||
{
|
||||
Color = panelColor,
|
||||
IsAntialias = true
|
||||
};
|
||||
_disabledBrush = new SKPaint()
|
||||
{
|
||||
Color = panelTransparentColor,
|
||||
IsAntialias = true
|
||||
};
|
||||
_cursorBrush = new SKPaint() { Color = _textNormalColor, IsAntialias = true };
|
||||
_selectionBoxBrush = new SKPaint() { Color = selectionBackgroundColor, IsAntialias = true };
|
||||
|
||||
_textBoxOutlinePen = Pens.Solid(borderColor, _textBoxOutlineWidth);
|
||||
_cursorPen = Pens.Solid(_textNormalColor, cursorWidth);
|
||||
_selectionBoxPen = Pens.Solid(selectionBackgroundColor, cursorWidth);
|
||||
_padPressedPen = Pens.Solid(borderColor, _padPressedPenWidth);
|
||||
_textBoxOutlinePen = new SKPaint()
|
||||
{
|
||||
Color = borderColor,
|
||||
StrokeWidth = _textBoxOutlineWidth,
|
||||
IsStroke = true,
|
||||
IsAntialias = true
|
||||
};
|
||||
_cursorPen = new SKPaint() { Color = _textNormalColor, StrokeWidth = cursorWidth, IsStroke = true, IsAntialias = true };
|
||||
_selectionBoxPen = new SKPaint() { Color = selectionBackgroundColor, StrokeWidth = cursorWidth, IsStroke = true, IsAntialias = true };
|
||||
_padPressedPen = new SKPaint() { Color = borderColor, StrokeWidth = _padPressedPenWidth, IsStroke = true, IsAntialias = true };
|
||||
|
||||
_inputTextFontSize = 20;
|
||||
|
||||
@ -123,9 +133,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
{
|
||||
try
|
||||
{
|
||||
_messageFont = SystemFonts.CreateFont(fontFamily, 26, FontStyle.Regular);
|
||||
_inputTextFont = SystemFonts.CreateFont(fontFamily, _inputTextFontSize, FontStyle.Regular);
|
||||
_labelsTextFont = SystemFonts.CreateFont(fontFamily, 24, FontStyle.Regular);
|
||||
using var typeface = SKTypeface.FromFamilyName(fontFamily, SKFontStyle.Normal);
|
||||
_messageFont = new SKFont(typeface, 26);
|
||||
_inputTextFont = new SKFont(typeface, _inputTextFontSize);
|
||||
_labelsTextFont = new SKFont(typeface, 24);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -137,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
throw new Exception($"None of these fonts were found in the system: {String.Join(", ", availableFonts)}!");
|
||||
}
|
||||
|
||||
private static Color ToColor(ThemeColor color, byte? overrideAlpha = null, bool flipRgb = false)
|
||||
private static SKColor ToColor(ThemeColor color, byte? overrideAlpha = null, bool flipRgb = false)
|
||||
{
|
||||
var a = (byte)(color.A * 255);
|
||||
var r = (byte)(color.R * 255);
|
||||
@ -151,34 +162,33 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
b = (byte)(255 - b);
|
||||
}
|
||||
|
||||
return Color.FromRgba(r, g, b, overrideAlpha.GetValueOrDefault(a));
|
||||
return new SKColor(r, g, b, overrideAlpha.GetValueOrDefault(a));
|
||||
}
|
||||
|
||||
private static Image LoadResource(Assembly assembly, string resourcePath, int newWidth, int newHeight)
|
||||
private static SKBitmap LoadResource(Assembly assembly, string resourcePath, int newWidth, int newHeight)
|
||||
{
|
||||
Stream resourceStream = assembly.GetManifestResourceStream(resourcePath);
|
||||
|
||||
return LoadResource(resourceStream, newWidth, newHeight);
|
||||
}
|
||||
|
||||
private static Image LoadResource(Stream resourceStream, int newWidth, int newHeight)
|
||||
private static SKBitmap LoadResource(Stream resourceStream, int newWidth, int newHeight)
|
||||
{
|
||||
Debug.Assert(resourceStream != null);
|
||||
|
||||
var image = Image.Load(resourceStream);
|
||||
var bitmap = SKBitmap.Decode(resourceStream);
|
||||
|
||||
if (newHeight != 0 && newWidth != 0)
|
||||
{
|
||||
image.Mutate(x => x.Resize(newWidth, newHeight, KnownResamplers.Lanczos3));
|
||||
var resized = bitmap.Resize(new SKImageInfo(newWidth, newHeight), SKFilterQuality.High);
|
||||
if (resized != null)
|
||||
{
|
||||
bitmap.Dispose();
|
||||
bitmap = resized;
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private static void SetGraphicsOptions(IImageProcessingContext context)
|
||||
{
|
||||
context.GetGraphicsOptions().Antialias = true;
|
||||
context.GetDrawingOptions().GraphicsOptions.Antialias = true;
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private void DrawImmutableElements()
|
||||
@ -187,22 +197,18 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
{
|
||||
return;
|
||||
}
|
||||
var canvas = _surface.Canvas;
|
||||
|
||||
_surface.Mutate(context =>
|
||||
{
|
||||
SetGraphicsOptions(context);
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
canvas.DrawRect(_panelRectangle, _panelBrush);
|
||||
canvas.DrawBitmap(_ryujinxLogo, _logoPosition);
|
||||
|
||||
context.Clear(Color.Transparent);
|
||||
context.Fill(_panelBrush, _panelRectangle);
|
||||
context.DrawImage(_ryujinxLogo, _logoPosition, 1);
|
||||
float halfWidth = _panelRectangle.Width / 2;
|
||||
float buttonsY = _panelRectangle.Top + 185;
|
||||
|
||||
float halfWidth = _panelRectangle.Width / 2;
|
||||
float buttonsY = _panelRectangle.Y + 185;
|
||||
SKPoint disableButtonPosition = new(halfWidth + 180, buttonsY);
|
||||
|
||||
PointF disableButtonPosition = new(halfWidth + 180, buttonsY);
|
||||
|
||||
DrawControllerToggle(context, disableButtonPosition);
|
||||
});
|
||||
DrawControllerToggle(canvas, disableButtonPosition);
|
||||
}
|
||||
|
||||
public void DrawMutableElements(SoftwareKeyboardUIState state)
|
||||
@ -212,40 +218,43 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
return;
|
||||
}
|
||||
|
||||
_surface.Mutate(context =>
|
||||
using var paint = new SKPaint(_messageFont)
|
||||
{
|
||||
var messageRectangle = MeasureString(MessageText, _messageFont);
|
||||
float messagePositionX = (_panelRectangle.Width - messageRectangle.Width) / 2 - messageRectangle.X;
|
||||
float messagePositionY = _messagePositionY - messageRectangle.Y;
|
||||
var messagePosition = new PointF(messagePositionX, messagePositionY);
|
||||
var messageBoundRectangle = new RectangleF(messagePositionX, messagePositionY, messageRectangle.Width, messageRectangle.Height);
|
||||
Color = _textNormalColor,
|
||||
IsAntialias = true
|
||||
};
|
||||
|
||||
SetGraphicsOptions(context);
|
||||
var canvas = _surface.Canvas;
|
||||
var messageRectangle = MeasureString(MessageText, paint);
|
||||
float messagePositionX = (_panelRectangle.Width - messageRectangle.Width) / 2 - messageRectangle.Left;
|
||||
float messagePositionY = _messagePositionY - messageRectangle.Top;
|
||||
var messagePosition = new SKPoint(messagePositionX, messagePositionY);
|
||||
var messageBoundRectangle = SKRect.Create(messagePositionX, messagePositionY, messageRectangle.Width, messageRectangle.Height);
|
||||
|
||||
context.Fill(_panelBrush, messageBoundRectangle);
|
||||
canvas.DrawRect(messageBoundRectangle, _panelBrush);
|
||||
|
||||
context.DrawText(MessageText, _messageFont, _textNormalColor, messagePosition);
|
||||
canvas.DrawText(MessageText, messagePosition.X, messagePosition.Y + _messageFont.Metrics.XHeight + _messageFont.Metrics.Descent, paint);
|
||||
|
||||
if (!state.TypingEnabled)
|
||||
{
|
||||
// Just draw a semi-transparent rectangle on top to fade the component with the background.
|
||||
// TODO (caian): This will not work if one decides to add make background semi-transparent as well.
|
||||
if (!state.TypingEnabled)
|
||||
{
|
||||
// Just draw a semi-transparent rectangle on top to fade the component with the background.
|
||||
// TODO (caian): This will not work if one decides to add make background semi-transparent as well.
|
||||
|
||||
context.Fill(_disabledBrush, messageBoundRectangle);
|
||||
}
|
||||
canvas.DrawRect(messageBoundRectangle, _disabledBrush);
|
||||
}
|
||||
|
||||
DrawTextBox(context, state);
|
||||
DrawTextBox(canvas, state);
|
||||
|
||||
float halfWidth = _panelRectangle.Width / 2;
|
||||
float buttonsY = _panelRectangle.Y + 185;
|
||||
float halfWidth = _panelRectangle.Width / 2;
|
||||
float buttonsY = _panelRectangle.Top + 185;
|
||||
|
||||
PointF acceptButtonPosition = new(halfWidth - 180, buttonsY);
|
||||
PointF cancelButtonPosition = new(halfWidth, buttonsY);
|
||||
PointF disableButtonPosition = new(halfWidth + 180, buttonsY);
|
||||
SKPoint acceptButtonPosition = new(halfWidth - 180, buttonsY);
|
||||
SKPoint cancelButtonPosition = new(halfWidth, buttonsY);
|
||||
SKPoint disableButtonPosition = new(halfWidth + 180, buttonsY);
|
||||
|
||||
DrawPadButton(canvas, acceptButtonPosition, _padAcceptIcon, AcceptText, state.AcceptPressed, state.ControllerEnabled);
|
||||
DrawPadButton(canvas, cancelButtonPosition, _padCancelIcon, CancelText, state.CancelPressed, state.ControllerEnabled);
|
||||
|
||||
DrawPadButton(context, acceptButtonPosition, _padAcceptIcon, AcceptText, state.AcceptPressed, state.ControllerEnabled);
|
||||
DrawPadButton(context, cancelButtonPosition, _padCancelIcon, CancelText, state.CancelPressed, state.ControllerEnabled);
|
||||
});
|
||||
}
|
||||
|
||||
public void CreateSurface(RenderingSurfaceInfo surfaceInfo)
|
||||
@ -268,7 +277,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
Debug.Assert(_surfaceInfo.Height <= totalHeight);
|
||||
Debug.Assert(_surfaceInfo.Pitch * _surfaceInfo.Height <= _surfaceInfo.Size);
|
||||
|
||||
_surface = new Image<Argb32>((int)totalWidth, (int)totalHeight);
|
||||
_imageInfo = new SKImageInfo((int)totalWidth, (int)totalHeight, SKColorType.Rgba8888);
|
||||
_surface = SKSurface.Create(_imageInfo);
|
||||
|
||||
ComputeConstants();
|
||||
DrawImmutableElements();
|
||||
@ -282,76 +292,81 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
int panelHeight = 240;
|
||||
int panelPositionY = totalHeight - panelHeight;
|
||||
|
||||
_panelRectangle = new RectangleF(0, panelPositionY, totalWidth, panelHeight);
|
||||
_panelRectangle = SKRect.Create(0, panelPositionY, totalWidth, panelHeight);
|
||||
|
||||
_messagePositionY = panelPositionY + 60;
|
||||
|
||||
int logoPositionX = (totalWidth - _ryujinxLogo.Width) / 2;
|
||||
int logoPositionY = panelPositionY + 18;
|
||||
|
||||
_logoPosition = new Point(logoPositionX, logoPositionY);
|
||||
_logoPosition = new SKPoint(logoPositionX, logoPositionY);
|
||||
}
|
||||
private static RectangleF MeasureString(string text, Font font)
|
||||
private static SKRect MeasureString(string text, SKPaint paint)
|
||||
{
|
||||
TextOptions options = new(font);
|
||||
SKRect bounds = SKRect.Empty;
|
||||
|
||||
if (text == "")
|
||||
{
|
||||
FontRectangle emptyRectangle = TextMeasurer.MeasureSize(" ", options);
|
||||
|
||||
return new RectangleF(0, emptyRectangle.Y, 0, emptyRectangle.Height);
|
||||
paint.MeasureText(" ", ref bounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
paint.MeasureText(text, ref bounds);
|
||||
}
|
||||
|
||||
FontRectangle rectangle = TextMeasurer.MeasureSize(text, options);
|
||||
|
||||
return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
private static RectangleF MeasureString(ReadOnlySpan<char> text, Font font)
|
||||
private static SKRect MeasureString(ReadOnlySpan<char> text, SKPaint paint)
|
||||
{
|
||||
TextOptions options = new(font);
|
||||
SKRect bounds = SKRect.Empty;
|
||||
|
||||
if (text == "")
|
||||
{
|
||||
FontRectangle emptyRectangle = TextMeasurer.MeasureSize(" ", options);
|
||||
return new RectangleF(0, emptyRectangle.Y, 0, emptyRectangle.Height);
|
||||
paint.MeasureText(" ", ref bounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
paint.MeasureText(text, ref bounds);
|
||||
}
|
||||
|
||||
FontRectangle rectangle = TextMeasurer.MeasureSize(text, options);
|
||||
|
||||
return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
private void DrawTextBox(IImageProcessingContext context, SoftwareKeyboardUIState state)
|
||||
private void DrawTextBox(SKCanvas canvas, SoftwareKeyboardUIState state)
|
||||
{
|
||||
var inputTextRectangle = MeasureString(state.InputText, _inputTextFont);
|
||||
using var textPaint = new SKPaint(_labelsTextFont)
|
||||
{
|
||||
IsAntialias = true,
|
||||
Color = _textNormalColor
|
||||
};
|
||||
var inputTextRectangle = MeasureString(state.InputText, textPaint);
|
||||
|
||||
float boxWidth = (int)(Math.Max(300, inputTextRectangle.Width + inputTextRectangle.X + 8));
|
||||
float boxWidth = (int)(Math.Max(300, inputTextRectangle.Width + inputTextRectangle.Left + 8));
|
||||
float boxHeight = 32;
|
||||
float boxY = _panelRectangle.Y + 110;
|
||||
float boxY = _panelRectangle.Top + 110;
|
||||
float boxX = (int)((_panelRectangle.Width - boxWidth) / 2);
|
||||
|
||||
RectangleF boxRectangle = new(boxX, boxY, boxWidth, boxHeight);
|
||||
SKRect boxRectangle = SKRect.Create(boxX, boxY, boxWidth, boxHeight);
|
||||
|
||||
RectangleF boundRectangle = new(_panelRectangle.X, boxY - _textBoxOutlineWidth,
|
||||
SKRect boundRectangle = SKRect.Create(_panelRectangle.Left, boxY - _textBoxOutlineWidth,
|
||||
_panelRectangle.Width, boxHeight + 2 * _textBoxOutlineWidth);
|
||||
|
||||
context.Fill(_panelBrush, boundRectangle);
|
||||
canvas.DrawRect(boundRectangle, _panelBrush);
|
||||
|
||||
context.Draw(_textBoxOutlinePen, boxRectangle);
|
||||
canvas.DrawRect(boxRectangle, _textBoxOutlinePen);
|
||||
|
||||
float inputTextX = (_panelRectangle.Width - inputTextRectangle.Width) / 2 - inputTextRectangle.X;
|
||||
float inputTextX = (_panelRectangle.Width - inputTextRectangle.Width) / 2 - inputTextRectangle.Left;
|
||||
float inputTextY = boxY + 5;
|
||||
|
||||
var inputTextPosition = new PointF(inputTextX, inputTextY);
|
||||
|
||||
context.DrawText(state.InputText, _inputTextFont, _textNormalColor, inputTextPosition);
|
||||
var inputTextPosition = new SKPoint(inputTextX, inputTextY);
|
||||
canvas.DrawText(state.InputText, inputTextPosition.X, inputTextPosition.Y + (_labelsTextFont.Metrics.XHeight + _labelsTextFont.Metrics.Descent), textPaint);
|
||||
|
||||
// Draw the cursor on top of the text and redraw the text with a different color if necessary.
|
||||
|
||||
Color cursorTextColor;
|
||||
Brush cursorBrush;
|
||||
Pen cursorPen;
|
||||
SKColor cursorTextColor;
|
||||
SKPaint cursorBrush;
|
||||
SKPaint cursorPen;
|
||||
|
||||
float cursorPositionYTop = inputTextY + 1;
|
||||
float cursorPositionYBottom = cursorPositionYTop + _inputTextFontSize + 1;
|
||||
@ -371,12 +386,12 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
ReadOnlySpan<char> textUntilBegin = state.InputText.AsSpan(0, state.CursorBegin);
|
||||
ReadOnlySpan<char> textUntilEnd = state.InputText.AsSpan(0, state.CursorEnd);
|
||||
|
||||
var selectionBeginRectangle = MeasureString(textUntilBegin, _inputTextFont);
|
||||
var selectionEndRectangle = MeasureString(textUntilEnd, _inputTextFont);
|
||||
var selectionBeginRectangle = MeasureString(textUntilBegin, textPaint);
|
||||
var selectionEndRectangle = MeasureString(textUntilEnd, textPaint);
|
||||
|
||||
cursorVisible = true;
|
||||
cursorPositionXLeft = inputTextX + selectionBeginRectangle.Width + selectionBeginRectangle.X;
|
||||
cursorPositionXRight = inputTextX + selectionEndRectangle.Width + selectionEndRectangle.X;
|
||||
cursorPositionXLeft = inputTextX + selectionBeginRectangle.Width + selectionBeginRectangle.Left;
|
||||
cursorPositionXRight = inputTextX + selectionEndRectangle.Width + selectionEndRectangle.Left;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -390,10 +405,10 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
int cursorBegin = Math.Min(state.InputText.Length, state.CursorBegin);
|
||||
ReadOnlySpan<char> textUntilCursor = state.InputText.AsSpan(0, cursorBegin);
|
||||
var cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);
|
||||
var cursorTextRectangle = MeasureString(textUntilCursor, textPaint);
|
||||
|
||||
cursorVisible = true;
|
||||
cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X;
|
||||
cursorPositionXLeft = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.Left;
|
||||
|
||||
if (state.OverwriteMode)
|
||||
{
|
||||
@ -402,8 +417,8 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
if (state.CursorBegin < state.InputText.Length)
|
||||
{
|
||||
textUntilCursor = state.InputText.AsSpan(0, cursorBegin + 1);
|
||||
cursorTextRectangle = MeasureString(textUntilCursor, _inputTextFont);
|
||||
cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.X;
|
||||
cursorTextRectangle = MeasureString(textUntilCursor, textPaint);
|
||||
cursorPositionXRight = inputTextX + cursorTextRectangle.Width + cursorTextRectangle.Left;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -430,29 +445,32 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
|
||||
if (cursorWidth == 0)
|
||||
{
|
||||
PointF[] points = {
|
||||
new PointF(cursorPositionXLeft, cursorPositionYTop),
|
||||
new PointF(cursorPositionXLeft, cursorPositionYBottom),
|
||||
};
|
||||
|
||||
context.DrawLine(cursorPen, points);
|
||||
canvas.DrawLine(new SKPoint(cursorPositionXLeft, cursorPositionYTop),
|
||||
new SKPoint(cursorPositionXLeft, cursorPositionYBottom),
|
||||
cursorPen);
|
||||
}
|
||||
else
|
||||
{
|
||||
var cursorRectangle = new RectangleF(cursorPositionXLeft, cursorPositionYTop, cursorWidth, cursorHeight);
|
||||
var cursorRectangle = SKRect.Create(cursorPositionXLeft, cursorPositionYTop, cursorWidth, cursorHeight);
|
||||
|
||||
context.Draw(cursorPen, cursorRectangle);
|
||||
context.Fill(cursorBrush, cursorRectangle);
|
||||
canvas.DrawRect(cursorRectangle, cursorPen);
|
||||
canvas.DrawRect(cursorRectangle, cursorBrush);
|
||||
|
||||
Image<Argb32> textOverCursor = new((int)cursorRectangle.Width, (int)cursorRectangle.Height);
|
||||
textOverCursor.Mutate(context =>
|
||||
using var textOverCursor = SKSurface.Create(new SKImageInfo((int)cursorRectangle.Width, (int)cursorRectangle.Height, SKColorType.Rgba8888));
|
||||
var textOverCanvas = textOverCursor.Canvas;
|
||||
var textRelativePosition = new SKPoint(inputTextPosition.X - cursorRectangle.Left, inputTextPosition.Y - cursorRectangle.Top);
|
||||
|
||||
using var cursorPaint = new SKPaint(_inputTextFont)
|
||||
{
|
||||
var textRelativePosition = new PointF(inputTextPosition.X - cursorRectangle.X, inputTextPosition.Y - cursorRectangle.Y);
|
||||
context.DrawText(state.InputText, _inputTextFont, cursorTextColor, textRelativePosition);
|
||||
});
|
||||
Color = cursorTextColor,
|
||||
IsAntialias = true
|
||||
};
|
||||
|
||||
var cursorPosition = new Point((int)cursorRectangle.X, (int)cursorRectangle.Y);
|
||||
context.DrawImage(textOverCursor, cursorPosition, 1);
|
||||
textOverCanvas.DrawText(state.InputText, textRelativePosition.X, textRelativePosition.Y + _inputTextFont.Metrics.XHeight + _inputTextFont.Metrics.Descent, cursorPaint);
|
||||
|
||||
var cursorPosition = new SKPoint((int)cursorRectangle.Left, (int)cursorRectangle.Top);
|
||||
textOverCursor.Flush();
|
||||
canvas.DrawSurface(textOverCursor, cursorPosition);
|
||||
}
|
||||
}
|
||||
else if (!state.TypingEnabled)
|
||||
@ -460,11 +478,11 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
// Just draw a semi-transparent rectangle on top to fade the component with the background.
|
||||
// TODO (caian): This will not work if one decides to add make background semi-transparent as well.
|
||||
|
||||
context.Fill(_disabledBrush, boundRectangle);
|
||||
canvas.DrawRect(boundRectangle, _disabledBrush);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawPadButton(IImageProcessingContext context, PointF point, Image icon, string label, bool pressed, bool enabled)
|
||||
private void DrawPadButton(SKCanvas canvas, SKPoint point, SKBitmap icon, string label, bool pressed, bool enabled)
|
||||
{
|
||||
// Use relative positions so we can center the entire drawing later.
|
||||
|
||||
@ -473,12 +491,18 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
float iconWidth = icon.Width;
|
||||
float iconHeight = icon.Height;
|
||||
|
||||
var labelRectangle = MeasureString(label, _labelsTextFont);
|
||||
using var paint = new SKPaint(_labelsTextFont)
|
||||
{
|
||||
Color = _textNormalColor,
|
||||
IsAntialias = true
|
||||
};
|
||||
|
||||
float labelPositionX = iconWidth + 8 - labelRectangle.X;
|
||||
var labelRectangle = MeasureString(label, paint);
|
||||
|
||||
float labelPositionX = iconWidth + 8 - labelRectangle.Left;
|
||||
float labelPositionY = 3;
|
||||
|
||||
float fullWidth = labelPositionX + labelRectangle.Width + labelRectangle.X;
|
||||
float fullWidth = labelPositionX + labelRectangle.Width + labelRectangle.Left;
|
||||
float fullHeight = iconHeight;
|
||||
|
||||
// Convert all relative positions into absolute.
|
||||
@ -489,24 +513,24 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
iconX += originX;
|
||||
iconY += originY;
|
||||
|
||||
var iconPosition = new Point((int)iconX, (int)iconY);
|
||||
var labelPosition = new PointF(labelPositionX + originX, labelPositionY + originY);
|
||||
var iconPosition = new SKPoint((int)iconX, (int)iconY);
|
||||
var labelPosition = new SKPoint(labelPositionX + originX, labelPositionY + originY);
|
||||
|
||||
var selectedRectangle = new RectangleF(originX - 2 * _padPressedPenWidth, originY - 2 * _padPressedPenWidth,
|
||||
var selectedRectangle = SKRect.Create(originX - 2 * _padPressedPenWidth, originY - 2 * _padPressedPenWidth,
|
||||
fullWidth + 4 * _padPressedPenWidth, fullHeight + 4 * _padPressedPenWidth);
|
||||
|
||||
var boundRectangle = new RectangleF(originX, originY, fullWidth, fullHeight);
|
||||
var boundRectangle = SKRect.Create(originX, originY, fullWidth, fullHeight);
|
||||
boundRectangle.Inflate(4 * _padPressedPenWidth, 4 * _padPressedPenWidth);
|
||||
|
||||
context.Fill(_panelBrush, boundRectangle);
|
||||
context.DrawImage(icon, iconPosition, 1);
|
||||
context.DrawText(label, _labelsTextFont, _textNormalColor, labelPosition);
|
||||
canvas.DrawRect(boundRectangle, _panelBrush);
|
||||
canvas.DrawBitmap(icon, iconPosition);
|
||||
canvas.DrawText(label, labelPosition.X, labelPosition.Y + _labelsTextFont.Metrics.XHeight + _labelsTextFont.Metrics.Descent, paint);
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
if (pressed)
|
||||
{
|
||||
context.Draw(_padPressedPen, selectedRectangle);
|
||||
canvas.DrawRect(selectedRectangle, _padPressedPen);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -514,21 +538,26 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
// Just draw a semi-transparent rectangle on top to fade the component with the background.
|
||||
// TODO (caian): This will not work if one decides to add make background semi-transparent as well.
|
||||
|
||||
context.Fill(_disabledBrush, boundRectangle);
|
||||
canvas.DrawRect(boundRectangle, _disabledBrush);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawControllerToggle(IImageProcessingContext context, PointF point)
|
||||
private void DrawControllerToggle(SKCanvas canvas, SKPoint point)
|
||||
{
|
||||
var labelRectangle = MeasureString(ControllerToggleText, _labelsTextFont);
|
||||
using var paint = new SKPaint(_labelsTextFont)
|
||||
{
|
||||
IsAntialias = true,
|
||||
Color = _textNormalColor
|
||||
};
|
||||
var labelRectangle = MeasureString(ControllerToggleText, paint);
|
||||
|
||||
// Use relative positions so we can center the entire drawing later.
|
||||
|
||||
float keyWidth = _keyModeIcon.Width;
|
||||
float keyHeight = _keyModeIcon.Height;
|
||||
|
||||
float labelPositionX = keyWidth + 8 - labelRectangle.X;
|
||||
float labelPositionY = -labelRectangle.Y - 1;
|
||||
float labelPositionX = keyWidth + 8 - labelRectangle.Left;
|
||||
float labelPositionY = -labelRectangle.Top - 1;
|
||||
|
||||
float keyX = 0;
|
||||
float keyY = (int)((labelPositionY + labelRectangle.Height - keyHeight) / 2);
|
||||
@ -544,14 +573,14 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
keyX += originX;
|
||||
keyY += originY;
|
||||
|
||||
var labelPosition = new PointF(labelPositionX + originX, labelPositionY + originY);
|
||||
var overlayPosition = new Point((int)keyX, (int)keyY);
|
||||
var labelPosition = new SKPoint(labelPositionX + originX, labelPositionY + originY);
|
||||
var overlayPosition = new SKPoint((int)keyX, (int)keyY);
|
||||
|
||||
context.DrawImage(_keyModeIcon, overlayPosition, 1);
|
||||
context.DrawText(ControllerToggleText, _labelsTextFont, _textNormalColor, labelPosition);
|
||||
canvas.DrawBitmap(_keyModeIcon, overlayPosition);
|
||||
canvas.DrawText(ControllerToggleText, labelPosition.X, labelPosition.Y + _labelsTextFont.Metrics.XHeight, paint);
|
||||
}
|
||||
|
||||
public void CopyImageToBuffer()
|
||||
public unsafe void CopyImageToBuffer()
|
||||
{
|
||||
lock (_bufferLock)
|
||||
{
|
||||
@ -561,21 +590,20 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
}
|
||||
|
||||
// Convert the pixel format used in the image to the one used in the Switch surface.
|
||||
_surface.Flush();
|
||||
|
||||
if (!_surface.DangerousTryGetSinglePixelMemory(out Memory<Argb32> pixels))
|
||||
var buffer = new byte[_imageInfo.BytesSize];
|
||||
fixed (byte* bufferPtr = buffer)
|
||||
{
|
||||
return;
|
||||
if (!_surface.ReadPixels(_imageInfo, (nint)bufferPtr, _imageInfo.RowBytes, 0, 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_bufferData = MemoryMarshal.AsBytes(pixels.Span).ToArray();
|
||||
Span<uint> dataConvert = MemoryMarshal.Cast<byte, uint>(_bufferData);
|
||||
_bufferData = buffer;
|
||||
|
||||
Debug.Assert(_bufferData.Length == _surfaceInfo.Size);
|
||||
|
||||
for (int i = 0; i < dataConvert.Length; i++)
|
||||
{
|
||||
dataConvert[i] = BitOperations.RotateRight(dataConvert[i], 8);
|
||||
}
|
||||
Debug.Assert(buffer.Length == _surfaceInfo.Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||
MemoryArrange.MemoryArrange4GiBSystemDev or
|
||||
MemoryArrange.MemoryArrange6GiBAppletDev => 3285 * MiB,
|
||||
MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiB or
|
||||
MemoryArrange.MemoryArrange8GiB => 4916 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiB => 4916 * MiB,
|
||||
MemoryArrange.MemoryArrange8GiB => 6964 * MiB,
|
||||
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
|
||||
};
|
||||
}
|
||||
@ -42,8 +42,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
|
||||
MemoryArrange.MemoryArrange4GiBAppletDev => 1554 * MiB,
|
||||
MemoryArrange.MemoryArrange4GiBSystemDev => 448 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiB => 562 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiBAppletDev or
|
||||
MemoryArrange.MemoryArrange8GiB => 2193 * MiB,
|
||||
MemoryArrange.MemoryArrange6GiBAppletDev => 2193 * MiB,
|
||||
MemoryArrange.MemoryArrange8GiB => 562 * MiB,
|
||||
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
|
||||
};
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Caps.Types;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
@ -118,7 +118,11 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
||||
}
|
||||
|
||||
// NOTE: The saved JPEG file doesn't have the limitation in the extra EXIF data.
|
||||
Image.LoadPixelData<Rgba32>(screenshotData, 1280, 720).SaveAsJpegAsync(filePath);
|
||||
using var bitmap = new SKBitmap(new SKImageInfo(1280, 720, SKColorType.Rgba8888));
|
||||
Marshal.Copy(screenshotData, 0, bitmap.GetPixels(), screenshotData.Length);
|
||||
using var data = bitmap.Encode(SKEncodedImageFormat.Jpeg, 80);
|
||||
using var file = File.OpenWrite(filePath);
|
||||
data.SaveTo(file);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
using Ryujinx.HLE.HOS.Services.Apm;
|
||||
using Ryujinx.Horizon.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -12,7 +13,7 @@ using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sm
|
||||
{
|
||||
class IUserInterface : IpcService
|
||||
partial class IUserInterface : IpcService
|
||||
{
|
||||
private static readonly Dictionary<string, Type> _services;
|
||||
|
||||
@ -95,9 +96,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm
|
||||
{
|
||||
ServiceAttribute serviceAttribute = (ServiceAttribute)type.GetCustomAttributes(typeof(ServiceAttribute)).First(service => ((ServiceAttribute)service).Name == name);
|
||||
|
||||
IpcService service = serviceAttribute.Parameter != null
|
||||
? (IpcService)Activator.CreateInstance(type, context, serviceAttribute.Parameter)
|
||||
: (IpcService)Activator.CreateInstance(type, context);
|
||||
IpcService service = GetServiceInstance(type, context, serviceAttribute.Parameter);
|
||||
|
||||
service.TrySetServer(_commonServer);
|
||||
service.Server.AddSessionObj(session.ServerSession, service);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -11,6 +12,7 @@
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||
<ProjectReference Include="..\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\Ryujinx.Horizon\Ryujinx.Horizon.csproj" />
|
||||
@ -24,8 +26,8 @@
|
||||
<PackageReference Include="LibHac" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" />
|
||||
<PackageReference Include="MsgPack.Cli" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" />
|
||||
<PackageReference Include="SkiaSharp" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux" />
|
||||
<PackageReference Include="NetCoreServer" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -219,7 +219,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
|
||||
// Hacks
|
||||
|
||||
[Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GiB to 6GiB.")]
|
||||
[Option("expand-ram", Required = false, Default = false, HelpText = "Expands the RAM amount on the emulated system from 4GiB to 8GiB.")]
|
||||
public bool ExpandRAM { get; set; }
|
||||
|
||||
[Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")]
|
||||
|
@ -7,6 +7,7 @@ using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
|
||||
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||
using Ryujinx.Common.GraphicsDriver;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.Logging.Targets;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
@ -18,6 +19,7 @@ using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.Graphics.Gpu.Shader;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.Graphics.Vulkan;
|
||||
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||
using Ryujinx.Headless.SDL2.OpenGL;
|
||||
using Ryujinx.Headless.SDL2.Vulkan;
|
||||
using Ryujinx.HLE;
|
||||
@ -88,6 +90,11 @@ namespace Ryujinx.Headless.SDL2
|
||||
};
|
||||
}
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
MVKInitialization.InitializeResolver();
|
||||
}
|
||||
|
||||
Parser.Default.ParseArguments<Options>(args)
|
||||
.WithParsed(Load)
|
||||
.WithNotParsed(errors => errors.Output());
|
||||
@ -457,6 +464,8 @@ namespace Ryujinx.Headless.SDL2
|
||||
GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath;
|
||||
GraphicsConfig.EnableMacroHLE = !option.DisableMacroHLE;
|
||||
|
||||
DriverUtilities.InitDriverConfig(option.BackendThreading == BackendThreading.Off);
|
||||
|
||||
while (true)
|
||||
{
|
||||
LoadApplication(option);
|
||||
@ -553,7 +562,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
_userChannelPersistence,
|
||||
renderer,
|
||||
new SDL2HardwareDeviceDriver(),
|
||||
options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB,
|
||||
options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration8GiB : MemoryConfiguration.MemoryConfiguration4GiB,
|
||||
window,
|
||||
options.SystemLanguage,
|
||||
options.SystemRegion,
|
||||
|
@ -29,6 +29,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
0xe6200f10u, // QADD16 R0, R0, R0
|
||||
0xe6600f10u, // UQADD16 R0, R0, R0
|
||||
0xe6600f70u, // UQSUB16 R0, R0, R0
|
||||
};
|
||||
|
@ -328,6 +328,29 @@ namespace Ryujinx.Tests.Cpu
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSHLL.<size> {<Vd>}, <Vm>, #<imm>")]
|
||||
public void Vshll([Values(0u, 2u)] uint rd,
|
||||
[Values(1u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b)
|
||||
{
|
||||
uint opcode = 0xf3b20300u; // VSHLL.I8 Q0, D0, #8
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= size << 18;
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSWP D0, D0")]
|
||||
public void Vswp([Values(0u, 1u)] uint rd,
|
||||
[Values(0u, 1u)] uint rm,
|
||||
|
@ -238,7 +238,7 @@ namespace Ryujinx.UI.Common.Configuration
|
||||
public MemoryManagerMode MemoryManagerMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Expands the RAM amount on the emulated system from 4GiB to 6GiB
|
||||
/// Expands the RAM amount on the emulated system from 4GiB to 8GiB
|
||||
/// </summary>
|
||||
public bool ExpandRam { get; set; }
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using ShellLink;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Formats.Png;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -21,8 +18,8 @@ namespace Ryujinx.UI.Common.Helper
|
||||
iconPath += ".ico";
|
||||
|
||||
MemoryStream iconDataStream = new(iconData);
|
||||
var image = Image.Load(iconDataStream);
|
||||
image.Mutate(x => x.Resize(128, 128));
|
||||
using var image = SKBitmap.Decode(iconDataStream);
|
||||
image.Resize(new SKImageInfo(128, 128), SKFilterQuality.High);
|
||||
SaveBitmapAsIcon(image, iconPath);
|
||||
|
||||
var shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath, applicationId), iconPath, 0);
|
||||
@ -37,8 +34,10 @@ namespace Ryujinx.UI.Common.Helper
|
||||
var desktopFile = EmbeddedResources.ReadAllText("Ryujinx.UI.Common/shortcut-template.desktop");
|
||||
iconPath += ".png";
|
||||
|
||||
var image = Image.Load<Rgba32>(iconData);
|
||||
image.SaveAsPng(iconPath);
|
||||
var image = SKBitmap.Decode(iconData);
|
||||
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
|
||||
using var file = File.OpenWrite(iconPath);
|
||||
data.SaveTo(file);
|
||||
|
||||
using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop"));
|
||||
outputFile.Write(desktopFile, cleanedAppName, iconPath, $"{basePath} {GetArgsString(applicationFilePath, applicationId)}");
|
||||
@ -78,8 +77,10 @@ namespace Ryujinx.UI.Common.Helper
|
||||
}
|
||||
|
||||
const string IconName = "icon.png";
|
||||
var image = Image.Load<Rgba32>(iconData);
|
||||
image.SaveAsPng(Path.Combine(resourceFolderPath, IconName));
|
||||
var image = SKBitmap.Decode(iconData);
|
||||
using var data = image.Encode(SKEncodedImageFormat.Png, 100);
|
||||
using var file = File.OpenWrite(Path.Combine(resourceFolderPath, IconName));
|
||||
data.SaveTo(file);
|
||||
|
||||
// plist file
|
||||
using StreamWriter outputFile = new(Path.Combine(contentFolderPath, "Info.plist"));
|
||||
@ -148,7 +149,7 @@ namespace Ryujinx.UI.Common.Helper
|
||||
/// <param name="source">The source bitmap image that will be saved as an .ico file</param>
|
||||
/// <param name="filePath">The location that the new .ico file will be saved too (Make sure to include '.ico' in the path).</param>
|
||||
[SupportedOSPlatform("windows")]
|
||||
private static void SaveBitmapAsIcon(Image source, string filePath)
|
||||
private static void SaveBitmapAsIcon(SKBitmap source, string filePath)
|
||||
{
|
||||
// Code Modified From https://stackoverflow.com/a/11448060/368354 by Benlitz
|
||||
byte[] header = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 32, 0, 0, 0, 0, 0, 22, 0, 0, 0 };
|
||||
@ -156,13 +157,16 @@ namespace Ryujinx.UI.Common.Helper
|
||||
|
||||
fs.Write(header);
|
||||
// Writing actual data
|
||||
source.Save(fs, PngFormat.Instance);
|
||||
using var data = source.Encode(SKEncodedImageFormat.Png, 100);
|
||||
data.SaveTo(fs);
|
||||
// Getting data length (file length minus header)
|
||||
long dataLength = fs.Length - header.Length;
|
||||
// Write it in the correct place
|
||||
fs.Seek(14, SeekOrigin.Begin);
|
||||
fs.WriteByte((byte)dataLength);
|
||||
fs.WriteByte((byte)(dataLength >> 8));
|
||||
fs.WriteByte((byte)(dataLength >> 16));
|
||||
fs.WriteByte((byte)(dataLength >> 24));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -845,7 +845,7 @@ namespace Ryujinx.Ava
|
||||
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
|
||||
|
||||
// Initialize Configuration.
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB;
|
||||
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value ? MemoryConfiguration.MemoryConfiguration8GiB : MemoryConfiguration.MemoryConfiguration4GiB;
|
||||
|
||||
HLEConfiguration configuration = new(VirtualFileSystem,
|
||||
_viewModel.LibHacHorizonManager,
|
||||
|
@ -145,7 +145,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": "May cause instability",
|
||||
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
|
||||
"SettingsTabSystemExpandDramSize": "Expand DRAM to 8GiB",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services",
|
||||
"SettingsTabGraphics": "Graphics",
|
||||
"SettingsTabGraphicsAPI": "Graphics API",
|
||||
@ -575,7 +575,7 @@
|
||||
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
|
||||
"MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.",
|
||||
"UseHypervisorTooltip": "Use Hypervisor instead of JIT. Greatly improves performance when available, but can be unstable in its current state.",
|
||||
"DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"DRamTooltip": "Utilizes an alternative memory mode with 8GiB of DRAM to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.",
|
||||
"GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
"GalThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
@ -758,10 +758,11 @@
|
||||
"GraphicsAATooltip": "Applies anti-aliasing to the game render.\n\nFXAA will blur most of the image, while SMAA will attempt to find jagged edges and smooth them out.\n\nNot recommended to use in conjunction with the FSR scaling filter.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on NONE if unsure.",
|
||||
"GraphicsAALabel": "Anti-Aliasing:",
|
||||
"GraphicsScalingFilterLabel": "Scaling Filter:",
|
||||
"GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.",
|
||||
"GraphicsScalingFilterTooltip": "Choose the scaling filter that will be applied when using resolution scale.\n\nBilinear works well for 3D games and is a safe default option.\n\nNearest is recommended for pixel art games.\n\nFSR 1.0 is merely a sharpening filter, not recommended for use with FXAA or SMAA.\n\nArea scaling is recommended when downscaling resolutions that are larger than the output window. It can be used to achieve a supersampled anti-aliasing effect when downscaling by more than 2x.\n\nThis option can be changed while a game is running by clicking \"Apply\" below; you can simply move the settings window aside and experiment until you find your preferred look for a game.\n\nLeave on BILINEAR if unsure.",
|
||||
"GraphicsScalingFilterBilinear": "Bilinear",
|
||||
"GraphicsScalingFilterNearest": "Nearest",
|
||||
"GraphicsScalingFilterFsr": "FSR",
|
||||
"GraphicsScalingFilterArea": "Area",
|
||||
"GraphicsScalingFilterLevelLabel": "Level",
|
||||
"GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.",
|
||||
"SmaaLow": "SMAA Low",
|
||||
|
@ -7,6 +7,7 @@ using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.GraphicsDriver;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Common.SystemInterop;
|
||||
using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using Ryujinx.UI.Common;
|
||||
@ -80,6 +81,11 @@ namespace Ryujinx.Ava
|
||||
// Parse arguments
|
||||
CommandLineState.ParseArguments(args);
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
MVKInitialization.InitializeResolver();
|
||||
}
|
||||
|
||||
// Delete backup files after updating.
|
||||
Task.Run(Updater.CleanupUpdate);
|
||||
|
||||
@ -111,8 +117,8 @@ namespace Ryujinx.Ava
|
||||
// Logging system information.
|
||||
PrintSystemInfo();
|
||||
|
||||
// Enable OGL multithreading on the driver, when available.
|
||||
DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
||||
// Enable OGL multithreading on the driver, and some other flags.
|
||||
DriverUtilities.InitDriverConfig(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
||||
|
||||
// Check if keys exists.
|
||||
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
||||
|
@ -41,17 +41,12 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
|
||||
private void TextChanged(string text)
|
||||
{
|
||||
TextChangedEvent?.Invoke(text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, true);
|
||||
TextChangedEvent?.Invoke(text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false);
|
||||
}
|
||||
|
||||
private void SelectionChanged(int selection)
|
||||
{
|
||||
if (_hiddenTextBox.SelectionEnd < _hiddenTextBox.SelectionStart)
|
||||
{
|
||||
_hiddenTextBox.SelectionStart = _hiddenTextBox.SelectionEnd;
|
||||
}
|
||||
|
||||
TextChangedEvent?.Invoke(_hiddenTextBox.Text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, true);
|
||||
TextChangedEvent?.Invoke(_hiddenTextBox.Text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, false);
|
||||
}
|
||||
|
||||
private void AvaloniaDynamicTextInputHandler_TextInput(object sender, string text)
|
||||
|
@ -1,11 +1,14 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public class OffscreenTextBox : TextBox
|
||||
{
|
||||
protected override Type StyleKeyOverride => typeof(TextBox);
|
||||
|
||||
public static RoutedEvent<KeyEventArgs> GetKeyDownRoutedEvent()
|
||||
{
|
||||
return KeyDownEvent;
|
||||
|
@ -1,4 +1,4 @@
|
||||
<UserControl
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsGraphicsView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@ -173,6 +173,9 @@
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale GraphicsScalingFilterFsr}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{locale:Locale GraphicsScalingFilterArea}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<controls:SliderScroll Value="{Binding ScalingFilterLevel}"
|
||||
ToolTip.Tip="{locale:Locale GraphicsScalingFilterLevelTooltip}"
|
||||
|
@ -42,12 +42,10 @@
|
||||
</Window.KeyBindings>
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<helpers:OffscreenTextBox Name="HiddenTextBox" Grid.Row="0" />
|
||||
<helpers:OffscreenTextBox IsEnabled="False" Opacity="0" Name="HiddenTextBox" IsHitTestVisible="False" IsTabStop="False" />
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
|
Reference in New Issue
Block a user