Merge remote-tracking branch 'origin/master' into feature/auto-load-extra-files

This commit is contained in:
Jimmy Reichley 2024-09-24 18:24:00 -04:00
commit 2d9841f4fa
No known key found for this signature in database
GPG Key ID: 67715DC5A329803C
74 changed files with 1425 additions and 599 deletions

View File

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

View File

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

View File

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

View File

@ -4,7 +4,6 @@ namespace Ryujinx.Graphics.GAL
{ {
public interface IImageArray : IDisposable public interface IImageArray : IDisposable
{ {
void SetFormats(int index, Format[] imageFormats);
void SetImages(int index, ITexture[] images); void SetImages(int index, ITexture[] images);
} }
} }

View File

@ -58,7 +58,7 @@ namespace Ryujinx.Graphics.GAL
void SetIndexBuffer(BufferRange buffer, IndexType type); void SetIndexBuffer(BufferRange buffer, IndexType type);
void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat); void SetImage(ShaderStage stage, int binding, ITexture texture);
void SetImageArray(ShaderStage stage, int binding, IImageArray array); void SetImageArray(ShaderStage stage, int binding, IImageArray array);
void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array); void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array);

View File

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

View File

@ -67,7 +67,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
Register<CounterEventFlushCommand>(CommandType.CounterEventFlush); Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose); Register<ImageArrayDisposeCommand>(CommandType.ImageArrayDispose);
Register<ImageArraySetFormatsCommand>(CommandType.ImageArraySetFormats);
Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages); Register<ImageArraySetImagesCommand>(CommandType.ImageArraySetImages);
Register<ProgramDisposeCommand>(CommandType.ProgramDispose); Register<ProgramDisposeCommand>(CommandType.ProgramDispose);

View File

@ -27,7 +27,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading
CounterEventFlush, CounterEventFlush,
ImageArrayDispose, ImageArrayDispose,
ImageArraySetFormats,
ImageArraySetImages, ImageArraySetImages,
ProgramDispose, ProgramDispose,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,12 +27,6 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetFormats(int index, Format[] imageFormats)
{
_renderer.New<ImageArraySetFormatsCommand>().Set(Ref(this), index, Ref(imageFormats));
_renderer.QueueCommand();
}
public void SetImages(int index, ITexture[] images) public void SetImages(int index, ITexture[] images)
{ {
_renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images)); _renderer.New<ImageArraySetImagesCommand>().Set(Ref(this), index, Ref(images));

View File

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

View File

@ -177,9 +177,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
_renderer.QueueCommand(); _renderer.QueueCommand();
} }
public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat) public void SetImage(ShaderStage stage, int binding, ITexture texture)
{ {
_renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture), imageFormat); _renderer.New<SetImageCommand>().Set(stage, binding, Ref(texture));
_renderer.QueueCommand(); _renderer.QueueCommand();
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -13,6 +13,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// </summary> /// </summary>
public bool IsDisposed { get; private set; } public bool IsDisposed { get; private set; }
/// <summary>
/// True if the sampler has sRGB conversion enabled, false otherwise.
/// </summary>
public bool IsSrgb { get; }
/// <summary> /// <summary>
/// Host sampler object. /// Host sampler object.
/// </summary> /// </summary>
@ -30,6 +35,8 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="descriptor">The Maxwell sampler descriptor</param> /// <param name="descriptor">The Maxwell sampler descriptor</param>
public Sampler(GpuContext context, SamplerDescriptor descriptor) public Sampler(GpuContext context, SamplerDescriptor descriptor)
{ {
IsSrgb = descriptor.UnpackSrgb();
MinFilter minFilter = descriptor.UnpackMinFilter(); MinFilter minFilter = descriptor.UnpackMinFilter();
MagFilter magFilter = descriptor.UnpackMagFilter(); MagFilter magFilter = descriptor.UnpackMagFilter();

View File

@ -113,6 +113,15 @@ namespace Ryujinx.Graphics.Gpu.Image
return (CompareOp)(((Word0 >> 10) & 7) + 1); return (CompareOp)(((Word0 >> 10) & 7) + 1);
} }
/// <summary>
/// Unpacks the sampler sRGB format flag.
/// </summary>
/// <returns>True if the has sampler is sRGB conversion enabled, false otherwise</returns>
public readonly bool UnpackSrgb()
{
return (Word0 & (1 << 13)) != 0;
}
/// <summary> /// <summary>
/// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering. /// Unpacks and converts the maximum anisotropy value used for texture anisotropic filtering.
/// </summary> /// </summary>

View File

@ -7,7 +7,6 @@ using Ryujinx.Graphics.Texture.Astc;
using Ryujinx.Memory; using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -662,7 +661,7 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
} }
IMemoryOwner<byte> result = ConvertToHostCompatibleFormat(data); MemoryOwner<byte> result = ConvertToHostCompatibleFormat(data);
if (ScaleFactor != 1f && AllowScaledSetData()) if (ScaleFactor != 1f && AllowScaledSetData())
{ {
@ -685,7 +684,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Uploads new texture data to the host GPU. /// Uploads new texture data to the host GPU.
/// </summary> /// </summary>
/// <param name="data">New data</param> /// <param name="data">New data</param>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
BlacklistScale(); BlacklistScale();
@ -704,7 +703,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="data">New data</param> /// <param name="data">New data</param>
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
BlacklistScale(); BlacklistScale();
@ -722,7 +721,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="layer">Target layer</param> /// <param name="layer">Target layer</param>
/// <param name="level">Target level</param> /// <param name="level">Target level</param>
/// <param name="region">Target sub-region of the texture to update</param> /// <param name="region">Target sub-region of the texture to update</param>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
BlacklistScale(); BlacklistScale();
@ -740,7 +739,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="level">Mip level to convert</param> /// <param name="level">Mip level to convert</param>
/// <param name="single">True to convert a single slice</param> /// <param name="single">True to convert a single slice</param>
/// <returns>Converted data</returns> /// <returns>Converted data</returns>
public IMemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false) public MemoryOwner<byte> ConvertToHostCompatibleFormat(ReadOnlySpan<byte> data, int level = 0, bool single = false)
{ {
int width = Info.Width; int width = Info.Width;
int height = Info.Height; int height = Info.Height;
@ -755,7 +754,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int sliceDepth = single ? 1 : depth; int sliceDepth = single ? 1 : depth;
IMemoryOwner<byte> linear; MemoryOwner<byte> linear;
if (Info.IsLinear) if (Info.IsLinear)
{ {
@ -788,7 +787,7 @@ namespace Ryujinx.Graphics.Gpu.Image
data); data);
} }
IMemoryOwner<byte> result = linear; MemoryOwner<byte> result = linear;
// Handle compressed cases not supported by the host: // Handle compressed cases not supported by the host:
// - ASTC is usually not supported on desktop cards. // - ASTC is usually not supported on desktop cards.
@ -832,19 +831,19 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.Etc2RgbaUnorm: case Format.Etc2RgbaUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodeRgba(result.Memory.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodeRgba(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Etc2RgbPtaSrgb: case Format.Etc2RgbPtaSrgb:
case Format.Etc2RgbPtaUnorm: case Format.Etc2RgbPtaUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodePta(result.Memory.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodePta(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Etc2RgbSrgb: case Format.Etc2RgbSrgb:
case Format.Etc2RgbUnorm: case Format.Etc2RgbUnorm:
using (result) using (result)
{ {
return ETC2Decoder.DecodeRgb(result.Memory.Span, width, height, sliceDepth, levels, layers); return ETC2Decoder.DecodeRgb(result.Span, width, height, sliceDepth, levels, layers);
} }
} }
} }
@ -856,43 +855,43 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.Bc1RgbaUnorm: case Format.Bc1RgbaUnorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC1(result.Memory.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC1(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc2Srgb: case Format.Bc2Srgb:
case Format.Bc2Unorm: case Format.Bc2Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC2(result.Memory.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC2(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc3Srgb: case Format.Bc3Srgb:
case Format.Bc3Unorm: case Format.Bc3Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC3(result.Memory.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC3(result.Span, width, height, sliceDepth, levels, layers);
} }
case Format.Bc4Snorm: case Format.Bc4Snorm:
case Format.Bc4Unorm: case Format.Bc4Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC4(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm); return BCnDecoder.DecodeBC4(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc4Snorm);
} }
case Format.Bc5Snorm: case Format.Bc5Snorm:
case Format.Bc5Unorm: case Format.Bc5Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC5(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm); return BCnDecoder.DecodeBC5(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc5Snorm);
} }
case Format.Bc6HSfloat: case Format.Bc6HSfloat:
case Format.Bc6HUfloat: case Format.Bc6HUfloat:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC6(result.Memory.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat); return BCnDecoder.DecodeBC6(result.Span, width, height, sliceDepth, levels, layers, Format == Format.Bc6HSfloat);
} }
case Format.Bc7Srgb: case Format.Bc7Srgb:
case Format.Bc7Unorm: case Format.Bc7Unorm:
using (result) using (result)
{ {
return BCnDecoder.DecodeBC7(result.Memory.Span, width, height, sliceDepth, levels, layers); return BCnDecoder.DecodeBC7(result.Span, width, height, sliceDepth, levels, layers);
} }
} }
} }
@ -900,7 +899,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (result) using (result)
{ {
var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Memory.Span, width); var converted = PixelConverter.ConvertR4G4ToR4G4B4A4(result.Span, width);
if (_context.Capabilities.SupportsR4G4B4A4Format) if (_context.Capabilities.SupportsR4G4B4A4Format)
{ {
@ -910,7 +909,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (converted) using (converted)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Memory.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(converted.Span, width);
} }
} }
} }
@ -921,7 +920,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
using (result) using (result)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width);
} }
} }
} }
@ -933,24 +932,24 @@ namespace Ryujinx.Graphics.Gpu.Image
case Format.R5G6B5Unorm: case Format.R5G6B5Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Memory.Span, width); return PixelConverter.ConvertR5G6B5ToR8G8B8A8(result.Span, width);
} }
case Format.B5G5R5A1Unorm: case Format.B5G5R5A1Unorm:
case Format.R5G5B5X1Unorm: case Format.R5G5B5X1Unorm:
case Format.R5G5B5A1Unorm: case Format.R5G5B5A1Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Memory.Span, width, Format == Format.R5G5B5X1Unorm); return PixelConverter.ConvertR5G5B5ToR8G8B8A8(result.Span, width, Format == Format.R5G5B5X1Unorm);
} }
case Format.A1B5G5R5Unorm: case Format.A1B5G5R5Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Memory.Span, width); return PixelConverter.ConvertA1B5G5R5ToR8G8B8A8(result.Span, width);
} }
case Format.R4G4B4A4Unorm: case Format.R4G4B4A4Unorm:
using (result) using (result)
{ {
return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Memory.Span, width); return PixelConverter.ConvertR4G4B4A4ToR8G8B8A8(result.Span, width);
} }
} }
} }

View File

@ -17,7 +17,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <summary> /// <summary>
/// For images, indicates the format specified on the shader. /// For images, indicates the format specified on the shader.
/// </summary> /// </summary>
public Format Format { get; } public FormatInfo FormatInfo { get; }
/// <summary> /// <summary>
/// Shader texture host set index. /// Shader texture host set index.
@ -58,17 +58,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// Constructs the texture binding information structure. /// Constructs the texture binding information structure.
/// </summary> /// </summary>
/// <param name="target">The shader sampler target type</param> /// <param name="target">The shader sampler target type</param>
/// <param name="format">Format of the image as declared on the shader</param> /// <param name="formatInfo">Format of the image as declared on the shader</param>
/// <param name="set">Shader texture host set index</param> /// <param name="set">Shader texture host set index</param>
/// <param name="binding">The shader texture binding point</param> /// <param name="binding">The shader texture binding point</param>
/// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param> /// <param name="arrayLength">For array of textures, this indicates the length of the array. A value of one indicates it is not an array</param>
/// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param> /// <param name="cbufSlot">Constant buffer slot where the texture handle is located</param>
/// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param> /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param>
/// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param>
public TextureBindingInfo(Target target, Format format, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags) public TextureBindingInfo(Target target, FormatInfo formatInfo, int set, int binding, int arrayLength, int cbufSlot, int handle, TextureUsageFlags flags)
{ {
Target = target; Target = target;
Format = format; FormatInfo = formatInfo;
Set = set; Set = set;
Binding = binding; Binding = binding;
ArrayLength = arrayLength; ArrayLength = arrayLength;
@ -96,7 +96,7 @@ namespace Ryujinx.Graphics.Gpu.Image
int cbufSlot, int cbufSlot,
int handle, int handle,
TextureUsageFlags flags, TextureUsageFlags flags,
bool isSamplerOnly) : this(target, 0, set, binding, arrayLength, cbufSlot, handle, flags) bool isSamplerOnly) : this(target, FormatInfo.Invalid, set, binding, arrayLength, cbufSlot, handle, flags)
{ {
IsSamplerOnly = isSamplerOnly; IsSamplerOnly = isSamplerOnly;
} }

View File

@ -659,7 +659,6 @@ namespace Ryujinx.Graphics.Gpu.Image
int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1; int length = (isSampler ? samplerPool.MaximumId : texturePool.MaximumId) + 1;
length = Math.Min(length, bindingInfo.ArrayLength); length = Math.Min(length, bindingInfo.ArrayLength);
Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength]; ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
ITexture[] textures = new ITexture[bindingInfo.ArrayLength]; ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
@ -674,7 +673,7 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
else else
{ {
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, out texture); ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(index, bindingInfo.FormatInfo, out texture);
if (texture != null) if (texture != null)
{ {
@ -697,8 +696,6 @@ namespace Ryujinx.Graphics.Gpu.Image
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
ISampler hostSampler = sampler?.GetHostSampler(texture); ISampler hostSampler = sampler?.GetHostSampler(texture);
Format format = bindingInfo.Format;
if (hostTexture != null && texture.Target == Target.TextureBuffer) if (hostTexture != null && texture.Target == Target.TextureBuffer)
{ {
// Ensure that the buffer texture is using the correct buffer as storage. // Ensure that the buffer texture is using the correct buffer as storage.
@ -706,26 +703,15 @@ namespace Ryujinx.Graphics.Gpu.Image
// to ensure we're not using a old buffer that was already deleted. // to ensure we're not using a old buffer that was already deleted.
if (isImage) if (isImage)
{ {
if (format == 0 && texture != null) _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
{
format = texture.Format;
}
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
} }
else else
{ {
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format); _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index);
} }
} }
else if (isImage) else if (isImage)
{ {
if (format == 0 && texture != null)
{
format = texture.Format;
}
formats[index] = format;
textures[index] = hostTexture; textures[index] = hostTexture;
} }
else else
@ -737,7 +723,6 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage) if (isImage)
{ {
entry.ImageArray.SetFormats(0, formats);
entry.ImageArray.SetImages(0, textures); entry.ImageArray.SetImages(0, textures);
SetImageArray(stage, bindingInfo, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);
@ -863,7 +848,6 @@ namespace Ryujinx.Graphics.Gpu.Image
entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer); entry.UpdateData(cachedTextureBuffer, cachedSamplerBuffer, separateSamplerBuffer);
Format[] formats = isImage ? new Format[bindingInfo.ArrayLength] : null;
ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength]; ISampler[] samplers = isImage ? null : new ISampler[bindingInfo.ArrayLength];
ITexture[] textures = new ITexture[bindingInfo.ArrayLength]; ITexture[] textures = new ITexture[bindingInfo.ArrayLength];
@ -883,7 +867,7 @@ namespace Ryujinx.Graphics.Gpu.Image
samplerId = TextureHandle.UnpackSamplerId(packedId); samplerId = TextureHandle.UnpackSamplerId(packedId);
} }
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture); ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture);
if (texture != null) if (texture != null)
{ {
@ -916,8 +900,6 @@ namespace Ryujinx.Graphics.Gpu.Image
hostSampler = sampler?.GetHostSampler(texture); hostSampler = sampler?.GetHostSampler(texture);
} }
Format format = bindingInfo.Format;
if (hostTexture != null && texture.Target == Target.TextureBuffer) if (hostTexture != null && texture.Target == Target.TextureBuffer)
{ {
// Ensure that the buffer texture is using the correct buffer as storage. // Ensure that the buffer texture is using the correct buffer as storage.
@ -925,26 +907,15 @@ namespace Ryujinx.Graphics.Gpu.Image
// to ensure we're not using a old buffer that was already deleted. // to ensure we're not using a old buffer that was already deleted.
if (isImage) if (isImage)
{ {
if (format == 0 && texture != null) _channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index);
{
format = texture.Format;
}
_channel.BufferManager.SetBufferTextureStorage(stage, entry.ImageArray, hostTexture, texture.Range, bindingInfo, index, format);
} }
else else
{ {
_channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index, format); _channel.BufferManager.SetBufferTextureStorage(stage, entry.TextureArray, hostTexture, texture.Range, bindingInfo, index);
} }
} }
else if (isImage) else if (isImage)
{ {
if (format == 0 && texture != null)
{
format = texture.Format;
}
formats[index] = format;
textures[index] = hostTexture; textures[index] = hostTexture;
} }
else else
@ -956,7 +927,6 @@ namespace Ryujinx.Graphics.Gpu.Image
if (isImage) if (isImage)
{ {
entry.ImageArray.SetFormats(0, formats);
entry.ImageArray.SetImages(0, textures); entry.ImageArray.SetImages(0, textures);
SetImageArray(stage, bindingInfo, entry.ImageArray); SetImageArray(stage, bindingInfo, entry.ImageArray);

View File

@ -187,7 +187,9 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
(TexturePool texturePool, SamplerPool samplerPool) = GetPools(); (TexturePool texturePool, SamplerPool samplerPool) = GetPools();
return (texturePool.Get(textureId), samplerPool.Get(samplerId)); Sampler sampler = samplerPool?.Get(samplerId);
return (texturePool.Get(textureId, sampler?.IsSrgb ?? true), sampler);
} }
/// <summary> /// <summary>
@ -508,12 +510,12 @@ namespace Ryujinx.Graphics.Gpu.Image
state.TextureHandle = textureId; state.TextureHandle = textureId;
state.SamplerHandle = samplerId; state.SamplerHandle = samplerId;
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, out Texture texture); Sampler sampler = samplerPool?.Get(samplerId);
ref readonly TextureDescriptor descriptor = ref texturePool.GetForBinding(textureId, sampler?.IsSrgb ?? true, out Texture texture);
specStateMatches &= specState.MatchesTexture(stage, index, descriptor); specStateMatches &= specState.MatchesTexture(stage, index, descriptor);
Sampler sampler = samplerPool?.Get(samplerId);
ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
ISampler hostSampler = sampler?.GetHostSampler(texture); ISampler hostSampler = sampler?.GetHostSampler(texture);
@ -522,7 +524,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Ensure that the buffer texture is using the correct buffer as storage. // Ensure that the buffer texture is using the correct buffer as storage.
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind // Buffers are frequently re-created to accommodate larger data, so we need to re-bind
// to ensure we're not using a old buffer that was already deleted. // to ensure we're not using a old buffer that was already deleted.
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, bindingInfo.Format, false); _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, false);
// Cache is not used for buffer texture, it must always rebind. // Cache is not used for buffer texture, it must always rebind.
state.CachedTexture = null; state.CachedTexture = null;
@ -616,6 +618,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!poolModified && if (!poolModified &&
state.TextureHandle == textureId && state.TextureHandle == textureId &&
state.ImageFormat == bindingInfo.FormatInfo.Format &&
state.CachedTexture != null && state.CachedTexture != null &&
state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence) state.CachedTexture.InvalidatedSequence == state.InvalidatedSequence)
{ {
@ -629,26 +632,22 @@ namespace Ryujinx.Graphics.Gpu.Image
cachedTexture.SignalModified(); cachedTexture.SignalModified();
} }
Format format = bindingInfo.Format == 0 ? cachedTexture.Format : bindingInfo.Format; if ((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 && UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage))
if (state.ImageFormat != format ||
((usageFlags & TextureUsageFlags.NeedsScaleValue) != 0 &&
UpdateScale(state.CachedTexture, usageFlags, scaleIndex, stage)))
{ {
ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target); ITexture hostTextureRebind = state.CachedTexture.GetTargetTexture(bindingInfo.Target);
state.Texture = hostTextureRebind; state.Texture = hostTextureRebind;
state.ImageFormat = format;
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind, format); _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTextureRebind);
} }
continue; continue;
} }
state.TextureHandle = textureId; state.TextureHandle = textureId;
state.ImageFormat = bindingInfo.FormatInfo.Format;
ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, out Texture texture); ref readonly TextureDescriptor descriptor = ref pool.GetForBinding(textureId, bindingInfo.FormatInfo, out Texture texture);
specStateMatches &= specState.MatchesImage(stage, index, descriptor); specStateMatches &= specState.MatchesImage(stage, index, descriptor);
@ -660,14 +659,7 @@ namespace Ryujinx.Graphics.Gpu.Image
// Buffers are frequently re-created to accommodate larger data, so we need to re-bind // Buffers are frequently re-created to accommodate larger data, so we need to re-bind
// to ensure we're not using a old buffer that was already deleted. // to ensure we're not using a old buffer that was already deleted.
Format format = bindingInfo.Format; _channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, true);
if (format == 0 && texture != null)
{
format = texture.Format;
}
_channel.BufferManager.SetBufferTextureStorage(stage, hostTexture, texture.Range, bindingInfo, format, true);
// Cache is not used for buffer texture, it must always rebind. // Cache is not used for buffer texture, it must always rebind.
state.CachedTexture = null; state.CachedTexture = null;
@ -689,16 +681,7 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
state.Texture = hostTexture; state.Texture = hostTexture;
Format format = bindingInfo.Format; _context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture);
if (format == 0 && texture != null)
{
format = texture.Format;
}
state.ImageFormat = format;
_context.Renderer.Pipeline.SetImage(stage, bindingInfo.Binding, hostTexture, format);
} }
state.CachedTexture = texture; state.CachedTexture = texture;

View File

@ -347,6 +347,53 @@ namespace Ryujinx.Graphics.Gpu.Image
return texture; 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> /// <summary>
/// Tries to find an existing texture, or create a new one if not found. /// Tries to find an existing texture, or create a new one if not found.
/// </summary> /// </summary>

View File

@ -739,7 +739,8 @@ namespace Ryujinx.Graphics.Gpu.Image
} }
return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) || return (lhsFormat.Format == Format.R8G8B8A8Unorm && rhsFormat.Format == Format.R32G32B32A32Float) ||
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm); (lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R8G8B8A8Unorm) ||
(lhsFormat.Format == Format.R8Unorm && rhsFormat.Format == Format.R32Uint);
} }
/// <summary> /// <summary>

View File

@ -1,3 +1,4 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Gpu.Memory;
using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Texture;
@ -5,7 +6,6 @@ using Ryujinx.Memory;
using Ryujinx.Memory.Range; using Ryujinx.Memory.Range;
using Ryujinx.Memory.Tracking; using Ryujinx.Memory.Tracking;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -445,7 +445,7 @@ namespace Ryujinx.Graphics.Gpu.Image
ReadOnlySpan<byte> data = dataSpan[(offset - spanBase)..]; ReadOnlySpan<byte> data = dataSpan[(offset - spanBase)..];
IMemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true); MemoryOwner<byte> result = Storage.ConvertToHostCompatibleFormat(data, info.BaseLevel + level, true);
Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level); Storage.SetData(result, info.BaseLayer + layer, info.BaseLevel + level);
} }

View File

@ -75,6 +75,76 @@ namespace Ryujinx.Graphics.Gpu.Image
private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new(); private readonly ConcurrentQueue<DereferenceRequest> _dereferenceQueue = new();
private TextureDescriptor _defaultDescriptor; private TextureDescriptor _defaultDescriptor;
/// <summary>
/// List of textures that shares the same memory region, but have different formats.
/// </summary>
private class TextureAliasList
{
/// <summary>
/// Alias texture.
/// </summary>
/// <param name="Format">Texture format</param>
/// <param name="Texture">Texture</param>
private readonly record struct Alias(Format Format, Texture Texture);
/// <summary>
/// List of texture aliases.
/// </summary>
private readonly List<Alias> _aliases;
/// <summary>
/// Creates a new instance of the texture alias list.
/// </summary>
public TextureAliasList()
{
_aliases = new List<Alias>();
}
/// <summary>
/// Adds a new texture alias.
/// </summary>
/// <param name="format">Alias format</param>
/// <param name="texture">Alias texture</param>
public void Add(Format format, Texture texture)
{
_aliases.Add(new Alias(format, texture));
texture.IncrementReferenceCount();
}
/// <summary>
/// Finds a texture with the requested format, or returns null if not found.
/// </summary>
/// <param name="format">Format to find</param>
/// <returns>Texture with the requested format, or null if not found</returns>
public Texture Find(Format format)
{
foreach (var alias in _aliases)
{
if (alias.Format == format)
{
return alias.Texture;
}
}
return null;
}
/// <summary>
/// Removes all alias textures.
/// </summary>
public void Destroy()
{
foreach (var entry in _aliases)
{
entry.Texture.DecrementReferenceCount();
}
_aliases.Clear();
}
}
private readonly Dictionary<Texture, TextureAliasList> _aliasLists;
/// <summary> /// <summary>
/// Linked list node used on the texture pool cache. /// Linked list node used on the texture pool cache.
/// </summary> /// </summary>
@ -95,6 +165,7 @@ namespace Ryujinx.Graphics.Gpu.Image
public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId) public TexturePool(GpuContext context, GpuChannel channel, ulong address, int maximumId) : base(context, channel.MemoryManager.Physical, address, maximumId)
{ {
_channel = channel; _channel = channel;
_aliasLists = new Dictionary<Texture, TextureAliasList>();
} }
/// <summary> /// <summary>
@ -115,14 +186,13 @@ namespace Ryujinx.Graphics.Gpu.Image
if (texture == null) if (texture == null)
{ {
TextureInfo info = GetInfo(descriptor, out int layerSize);
// The dereference queue can put our texture back on the cache. // The dereference queue can put our texture back on the cache.
if ((texture = ProcessDereferenceQueue(id)) != null) if ((texture = ProcessDereferenceQueue(id)) != null)
{ {
return ref descriptor; return ref descriptor;
} }
TextureInfo info = GetInfo(descriptor, out int layerSize);
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize); texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
// If this happens, then the texture address is invalid, we can't add it to the cache. // If this happens, then the texture address is invalid, we can't add it to the cache.
@ -157,6 +227,17 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="id">ID of the texture. This is effectively a zero-based index</param> /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
/// <returns>The texture with the given ID</returns> /// <returns>The texture with the given ID</returns>
public override Texture Get(int id) public override Texture Get(int id)
{
return Get(id, srgbSampler: true);
}
/// <summary>
/// Gets the texture with the given ID.
/// </summary>
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
/// <param name="srgbSampler">Whether the texture is being accessed with a sampler that has sRGB conversion enabled</param>
/// <returns>The texture with the given ID</returns>
public Texture Get(int id, bool srgbSampler)
{ {
if ((uint)id >= Items.Length) if ((uint)id >= Items.Length)
{ {
@ -170,7 +251,7 @@ namespace Ryujinx.Graphics.Gpu.Image
SynchronizeMemory(); SynchronizeMemory();
} }
GetInternal(id, out Texture texture); GetForBinding(id, srgbSampler, out Texture texture);
return texture; return texture;
} }
@ -182,9 +263,10 @@ namespace Ryujinx.Graphics.Gpu.Image
/// This method assumes that the pool has been manually synchronized before doing binding. /// This method assumes that the pool has been manually synchronized before doing binding.
/// </remarks> /// </remarks>
/// <param name="id">ID of the texture. This is effectively a zero-based index</param> /// <param name="id">ID of the texture. This is effectively a zero-based index</param>
/// <param name="srgbSampler">Whether the texture is being accessed with a sampler that has sRGB conversion enabled</param>
/// <param name="texture">The texture with the given ID</param> /// <param name="texture">The texture with the given ID</param>
/// <returns>The texture descriptor with the given ID</returns> /// <returns>The texture descriptor with the given ID</returns>
public ref readonly TextureDescriptor GetForBinding(int id, out Texture texture) public ref readonly TextureDescriptor GetForBinding(int id, bool srgbSampler, out Texture texture)
{ {
if ((uint)id >= Items.Length) if ((uint)id >= Items.Length)
{ {
@ -194,9 +276,66 @@ namespace Ryujinx.Graphics.Gpu.Image
// When getting for binding, assume the pool has already been synchronized. // When getting for binding, assume the pool has already been synchronized.
if (!srgbSampler)
{
// If the sampler does not have the sRGB bit enabled, then the texture can't use a sRGB format.
ref readonly TextureDescriptor tempDescriptor = ref GetDescriptorRef(id);
if (tempDescriptor.UnpackSrgb() && FormatTable.TryGetTextureFormat(tempDescriptor.UnpackFormat(), isSrgb: false, out FormatInfo formatInfo))
{
// Get a view of the texture with the right format.
return ref GetForBinding(id, formatInfo, out texture);
}
}
return ref GetInternal(id, out texture); return ref GetInternal(id, out texture);
} }
/// <summary>
/// Gets the texture descriptor and texture with the given ID.
/// </summary>
/// <remarks>
/// This method assumes that the pool has been manually synchronized before doing binding.
/// </remarks>
/// <param name="id">ID of the texture. This is effectively a zero-based index</param>
/// <param name="formatInfo">Texture format information</param>
/// <param name="texture">The texture with the given ID</param>
/// <returns>The texture descriptor with the given ID</returns>
public ref readonly TextureDescriptor GetForBinding(int id, FormatInfo formatInfo, out Texture texture)
{
if ((uint)id >= Items.Length)
{
texture = null;
return ref _defaultDescriptor;
}
ref readonly TextureDescriptor descriptor = ref GetInternal(id, out texture);
if (texture != null && formatInfo.Format != 0 && texture.Format != formatInfo.Format)
{
if (!_aliasLists.TryGetValue(texture, out TextureAliasList aliasList))
{
_aliasLists.Add(texture, aliasList = new TextureAliasList());
}
texture = aliasList.Find(formatInfo.Format);
if (texture == null)
{
TextureInfo info = GetInfo(descriptor, out int layerSize);
info = ChangeFormat(info, formatInfo);
texture = PhysicalMemory.TextureCache.FindOrCreateTexture(_channel.MemoryManager, TextureSearchFlags.ForSampler, info, layerSize);
if (texture != null)
{
aliasList.Add(formatInfo.Format, texture);
}
}
}
return ref descriptor;
}
/// <summary> /// <summary>
/// Checks if the pool was modified, and returns the last sequence number where a modification was detected. /// Checks if the pool was modified, and returns the last sequence number where a modification was detected.
/// </summary> /// </summary>
@ -234,6 +373,7 @@ namespace Ryujinx.Graphics.Gpu.Image
else else
{ {
texture.DecrementReferenceCount(); texture.DecrementReferenceCount();
RemoveAliasList(texture);
} }
} }
@ -327,6 +467,8 @@ namespace Ryujinx.Graphics.Gpu.Image
{ {
texture.DecrementReferenceCount(); texture.DecrementReferenceCount();
} }
RemoveAliasList(texture);
} }
return null; return null;
@ -369,6 +511,7 @@ namespace Ryujinx.Graphics.Gpu.Image
if (Interlocked.Exchange(ref Items[id], null) != null) if (Interlocked.Exchange(ref Items[id], null) != null)
{ {
texture.DecrementReferenceCount(this, id); texture.DecrementReferenceCount(this, id);
RemoveAliasList(texture);
} }
} }
} }
@ -622,6 +765,57 @@ namespace Ryujinx.Graphics.Gpu.Image
component == SwizzleComponent.Green; component == SwizzleComponent.Green;
} }
/// <summary>
/// Changes the format on the texture information structure, and also adjusts the width for the new format if needed.
/// </summary>
/// <param name="info">Texture information</param>
/// <param name="dstFormat">New format</param>
/// <returns>Texture information with the new format</returns>
private static TextureInfo ChangeFormat(in TextureInfo info, FormatInfo dstFormat)
{
int width = info.Width;
if (info.FormatInfo.BytesPerPixel != dstFormat.BytesPerPixel)
{
int stride = width * info.FormatInfo.BytesPerPixel;
width = stride / dstFormat.BytesPerPixel;
}
return new TextureInfo(
info.GpuAddress,
width,
info.Height,
info.DepthOrLayers,
info.Levels,
info.SamplesInX,
info.SamplesInY,
info.Stride,
info.IsLinear,
info.GobBlocksInY,
info.GobBlocksInZ,
info.GobBlocksInTileX,
info.Target,
dstFormat,
info.DepthStencilMode,
info.SwizzleR,
info.SwizzleG,
info.SwizzleB,
info.SwizzleA);
}
/// <summary>
/// Removes all aliases for a texture.
/// </summary>
/// <param name="texture">Texture to have the aliases removed</param>
private void RemoveAliasList(Texture texture)
{
if (_aliasLists.TryGetValue(texture, out TextureAliasList aliasList))
{
_aliasLists.Remove(texture);
aliasList.Destroy();
}
}
/// <summary> /// <summary>
/// Decrements the reference count of the texture. /// Decrements the reference count of the texture.
/// This indicates that the texture pool is not using it anymore. /// This indicates that the texture pool is not using it anymore.
@ -629,7 +823,11 @@ namespace Ryujinx.Graphics.Gpu.Image
/// <param name="item">The texture to be deleted</param> /// <param name="item">The texture to be deleted</param>
protected override void Delete(Texture item) protected override void Delete(Texture item)
{ {
item?.DecrementReferenceCount(this); if (item != null)
{
item.DecrementReferenceCount(this);
RemoveAliasList(item);
}
} }
public override void Dispose() public override void Dispose()

View File

@ -509,7 +509,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (binding.IsImage) if (binding.IsImage)
{ {
_context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture, binding.Format); _context.Renderer.Pipeline.SetImage(binding.Stage, binding.BindingInfo.Binding, binding.Texture);
} }
else else
{ {
@ -873,12 +873,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
Format format,
bool isImage) bool isImage)
{ {
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
_bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, format, isImage)); _bufferTextures.Add(new BufferTextureBinding(stage, texture, range, bindingInfo, isImage));
} }
/// <summary> /// <summary>
@ -897,12 +896,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
int index, int index)
Format format)
{ {
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
_bufferTextureArrays.Add(new BufferTextureArrayBinding<ITextureArray>(array, texture, range, bindingInfo, index, format)); _bufferTextureArrays.Add(new BufferTextureArrayBinding<ITextureArray>(array, texture, range, bindingInfo, index));
} }
/// <summary> /// <summary>
@ -921,12 +919,11 @@ namespace Ryujinx.Graphics.Gpu.Memory
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
int index, int index)
Format format)
{ {
_channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags)); _channel.MemoryManager.Physical.BufferCache.CreateBuffer(range, BufferStageUtils.TextureBuffer(stage, bindingInfo.Flags));
_bufferImageArrays.Add(new BufferTextureArrayBinding<IImageArray>(array, texture, range, bindingInfo, index, format)); _bufferImageArrays.Add(new BufferTextureArrayBinding<IImageArray>(array, texture, range, bindingInfo, index));
} }
/// <summary> /// <summary>

View File

@ -34,33 +34,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
public int Index { get; } public int Index { get; }
/// <summary>
/// The image format for the binding.
/// </summary>
public Format Format { get; }
/// <summary> /// <summary>
/// Create a new buffer texture binding. /// Create a new buffer texture binding.
/// </summary> /// </summary>
/// <param name="array">Array</param>
/// <param name="texture">Buffer texture</param> /// <param name="texture">Buffer texture</param>
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param> /// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
/// <param name="bindingInfo">Binding info</param> /// <param name="bindingInfo">Binding info</param>
/// <param name="index">Index of the binding on the array</param> /// <param name="index">Index of the binding on the array</param>
/// <param name="format">Binding format</param>
public BufferTextureArrayBinding( public BufferTextureArrayBinding(
T array, T array,
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
int index, int index)
Format format)
{ {
Array = array; Array = array;
Texture = texture; Texture = texture;
Range = range; Range = range;
BindingInfo = bindingInfo; BindingInfo = bindingInfo;
Index = index; Index = index;
Format = format;
} }
} }
} }

View File

@ -30,11 +30,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary> /// </summary>
public TextureBindingInfo BindingInfo { get; } public TextureBindingInfo BindingInfo { get; }
/// <summary>
/// The image format for the binding.
/// </summary>
public Format Format { get; }
/// <summary> /// <summary>
/// Whether the binding is for an image or a sampler. /// Whether the binding is for an image or a sampler.
/// </summary> /// </summary>
@ -47,21 +42,18 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="texture">Buffer texture</param> /// <param name="texture">Buffer texture</param>
/// <param name="range">Physical ranges of memory where the buffer texture data is located</param> /// <param name="range">Physical ranges of memory where the buffer texture data is located</param>
/// <param name="bindingInfo">Binding info</param> /// <param name="bindingInfo">Binding info</param>
/// <param name="format">Binding format</param>
/// <param name="isImage">Whether the binding is for an image or a sampler</param> /// <param name="isImage">Whether the binding is for an image or a sampler</param>
public BufferTextureBinding( public BufferTextureBinding(
ShaderStage stage, ShaderStage stage,
ITexture texture, ITexture texture,
MultiRange range, MultiRange range,
TextureBindingInfo bindingInfo, TextureBindingInfo bindingInfo,
Format format,
bool isImage) bool isImage)
{ {
Stage = stage; Stage = stage;
Texture = texture; Texture = texture;
Range = range; Range = range;
BindingInfo = bindingInfo; BindingInfo = bindingInfo;
Format = format;
IsImage = isImage; IsImage = isImage;
} }
} }

View File

@ -86,11 +86,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
ImageBindings[i] = stage.Info.Images.Select(descriptor => ImageBindings[i] = stage.Info.Images.Select(descriptor =>
{ {
Target target = ShaderTexture.GetTarget(descriptor.Type); Target target = ShaderTexture.GetTarget(descriptor.Type);
Format format = ShaderTexture.GetFormat(descriptor.Format); FormatInfo formatInfo = ShaderTexture.GetFormatInfo(descriptor.Format);
var result = new TextureBindingInfo( var result = new TextureBindingInfo(
target, target,
format, formatInfo,
descriptor.Set, descriptor.Set,
descriptor.Binding, descriptor.Binding,
descriptor.ArrayLength, descriptor.ArrayLength,

View File

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2; private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 7131; private const uint CodeGenVersion = 7331;
private const string SharedTocFileName = "shared.toc"; private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data"; private const string SharedDataFileName = "shared.data";

View File

@ -131,7 +131,7 @@ namespace Ryujinx.Graphics.Gpu
bool isLinear, bool isLinear,
int gobBlocksInY, int gobBlocksInY,
Format format, Format format,
int bytesPerPixel, byte bytesPerPixel,
ImageCrop crop, ImageCrop crop,
Action<GpuContext, object> acquireCallback, Action<GpuContext, object> acquireCallback,
Action<object> releaseCallback, Action<object> releaseCallback,

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

View File

@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
private int _srcY0Uniform; private int _srcY0Uniform;
private int _scalingShaderProgram; private int _scalingShaderProgram;
private int _sharpeningShaderProgram; private int _sharpeningShaderProgram;
private float _scale = 1; private float _sharpeningLevel = 1;
private int _srcY1Uniform; private int _srcY1Uniform;
private int _dstX0Uniform; private int _dstX0Uniform;
private int _dstX1Uniform; private int _dstX1Uniform;
@ -30,10 +30,10 @@ namespace Ryujinx.Graphics.OpenGL.Effects
public float Level public float Level
{ {
get => _scale; get => _sharpeningLevel;
set set
{ {
_scale = MathF.Max(0.01f, value); _sharpeningLevel = MathF.Max(0.01f, value);
} }
} }

View File

@ -1,4 +1,5 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging;
namespace Ryujinx.Graphics.OpenGL.Effects namespace Ryujinx.Graphics.OpenGL.Effects
{ {
@ -6,18 +7,7 @@ namespace Ryujinx.Graphics.OpenGL.Effects
{ {
public static int CompileProgram(string shaderCode, ShaderType shaderType) public static int CompileProgram(string shaderCode, ShaderType shaderType)
{ {
var shader = GL.CreateShader(shaderType); return CompileProgram(new string[] { shaderCode }, 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;
} }
public static int CompileProgram(string[] shaders, ShaderType 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.ShaderSource(shader, shaders.Length, shaders, (int[])null);
GL.CompileShader(shader); 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(); var program = GL.CreateProgram();
GL.AttachShader(program, shader); GL.AttachShader(program, shader);
GL.LinkProgram(program); GL.LinkProgram(program);

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

View File

@ -85,4 +85,4 @@ void main() {
CurrFilter(gxy); CurrFilter(gxy);
gxy.x -= 8u; gxy.x -= 8u;
CurrFilter(gxy); CurrFilter(gxy);
} }

View File

@ -1,6 +1,5 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
{ {
@ -19,14 +18,6 @@ namespace Ryujinx.Graphics.OpenGL.Image
_images = new TextureRef[size]; _images = new TextureRef[size];
} }
public void SetFormats(int index, GAL.Format[] imageFormats)
{
for (int i = 0; i < imageFormats.Length; i++)
{
_images[index + i].Format = imageFormats[i];
}
}
public void SetImages(int index, ITexture[] images) public void SetImages(int index, ITexture[] images)
{ {
for (int i = 0; i < images.Length; i++) for (int i = 0; i < images.Length; i++)
@ -36,6 +27,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
if (image is TextureBase imageBase) if (image is TextureBase imageBase)
{ {
_images[index + i].Handle = imageBase.Handle; _images[index + i].Handle = imageBase.Handle;
_images[index + i].Format = imageBase.Format;
} }
else else
{ {

View File

@ -1,7 +1,7 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Buffers;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
{ {
@ -55,9 +55,9 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
var dataSpan = data.Memory.Span; var dataSpan = data.Span;
Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]); Buffer.SetData(_buffer, _bufferOffset, dataSpan[..Math.Min(dataSpan.Length, _bufferSize)]);
@ -65,13 +65,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

View File

@ -1,8 +1,8 @@
using OpenTK.Graphics.OpenGL; using OpenTK.Graphics.OpenGL;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using System; using System;
using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
namespace Ryujinx.Graphics.OpenGL.Image namespace Ryujinx.Graphics.OpenGL.Image
@ -448,13 +448,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
unsafe unsafe
{ {
var dataSpan = data.Memory.Span; var dataSpan = data.Span;
fixed (byte* ptr = dataSpan) fixed (byte* ptr = dataSpan)
{ {
ReadFrom((IntPtr)ptr, dataSpan.Length); ReadFrom((IntPtr)ptr, dataSpan.Length);
@ -463,13 +463,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
unsafe unsafe
{ {
fixed (byte* ptr = data.Memory.Span) fixed (byte* ptr = data.Span)
{ {
int width = Math.Max(Info.Width >> level, 1); int width = Math.Max(Info.Width >> level, 1);
int height = Math.Max(Info.Height >> level, 1); int height = Math.Max(Info.Height >> level, 1);
@ -480,7 +480,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
} }
} }
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
using (data = EnsureDataFormat(data)) using (data = EnsureDataFormat(data))
{ {
@ -489,7 +489,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
unsafe unsafe
{ {
fixed (byte* ptr = data.Memory.Span) fixed (byte* ptr = data.Span)
{ {
ReadFrom2D( ReadFrom2D(
(IntPtr)ptr, (IntPtr)ptr,
@ -522,13 +522,13 @@ namespace Ryujinx.Graphics.OpenGL.Image
ReadFrom2D(data, layer, level, x, y, width, height, mipSize); ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
} }
private IMemoryOwner<byte> EnsureDataFormat(IMemoryOwner<byte> data) private MemoryOwner<byte> EnsureDataFormat(MemoryOwner<byte> data)
{ {
if (Format == Format.S8UintD24Unorm) if (Format == Format.S8UintD24Unorm)
{ {
using (data) using (data)
{ {
return FormatConverter.ConvertS8D24ToD24S8(data.Memory.Span); return FormatConverter.ConvertS8D24ToD24S8(data.Span);
} }
} }

View File

@ -45,7 +45,7 @@ namespace Ryujinx.Graphics.OpenGL
private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount]; private readonly Vector4<int>[] _fpIsBgra = new Vector4<int>[SupportBuffer.FragmentIsBgraCount];
private readonly (TextureBase, Format)[] _images; private readonly TextureBase[] _images;
private TextureBase _unit0Texture; private TextureBase _unit0Texture;
private Sampler _unit0Sampler; private Sampler _unit0Sampler;
@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.OpenGL
_fragmentOutputMap = uint.MaxValue; _fragmentOutputMap = uint.MaxValue;
_componentMasks = uint.MaxValue; _componentMasks = uint.MaxValue;
_images = new (TextureBase, Format)[SavedImages]; _images = new TextureBase[SavedImages];
_tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers]; _tfbs = new BufferHandle[Constants.MaxTransformFeedbackBuffers];
_tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers]; _tfbTargets = new BufferRange[Constants.MaxTransformFeedbackBuffers];
@ -935,11 +935,11 @@ namespace Ryujinx.Graphics.OpenGL
SetFrontFace(_frontFace = frontFace.Convert()); SetFrontFace(_frontFace = frontFace.Convert());
} }
public void SetImage(ShaderStage stage, int binding, ITexture texture, Format imageFormat) public void SetImage(ShaderStage stage, int binding, ITexture texture)
{ {
if ((uint)binding < SavedImages) if ((uint)binding < SavedImages)
{ {
_images[binding] = (texture as TextureBase, imageFormat); _images[binding] = texture as TextureBase;
} }
if (texture == null) if (texture == null)
@ -950,7 +950,7 @@ namespace Ryujinx.Graphics.OpenGL
TextureBase texBase = (TextureBase)texture; TextureBase texBase = (TextureBase)texture;
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
if (format != 0) if (format != 0)
{ {
@ -1622,11 +1622,11 @@ namespace Ryujinx.Graphics.OpenGL
{ {
for (int i = 0; i < SavedImages; i++) for (int i = 0; i < SavedImages; i++)
{ {
(TextureBase texBase, Format imageFormat) = _images[i]; TextureBase texBase = _images[i];
if (texBase != null) if (texBase != null)
{ {
SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat); SizedInternalFormat format = FormatTable.GetImageFormat(texBase.Format);
if (format != 0) if (format != 0)
{ {

View File

@ -21,6 +21,7 @@
<EmbeddedResource Include="Effects\Shaders\ffx_fsr1.h" /> <EmbeddedResource Include="Effects\Shaders\ffx_fsr1.h" />
<EmbeddedResource Include="Effects\Shaders\ffx_a.h" /> <EmbeddedResource Include="Effects\Shaders\ffx_a.h" />
<EmbeddedResource Include="Effects\Shaders\fsr_scaling.glsl" /> <EmbeddedResource Include="Effects\Shaders\fsr_scaling.glsl" />
<EmbeddedResource Include="Effects\Shaders\area_scaling.glsl" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -373,6 +373,16 @@ namespace Ryujinx.Graphics.OpenGL
_isLinear = false; _isLinear = false;
_scalingFilter.Level = _scalingFilterLevel; _scalingFilter.Level = _scalingFilterLevel;
RecreateUpscalingTexture();
break;
case ScalingFilter.Area:
if (_scalingFilter is not AreaScalingFilter)
{
_scalingFilter?.Dispose();
_scalingFilter = new AreaScalingFilter(_renderer);
}
_isLinear = false;
RecreateUpscalingTexture(); RecreateUpscalingTexture();
break; break;
} }

View File

@ -222,30 +222,14 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
} }
break; break;
case AtomOp.And: case AtomOp.Min:
if (type == AtomSize.S32 || type == AtomSize.U32) if (type == AtomSize.S32)
{ {
res = context.AtomicAnd(storageKind, e0, e1, value); res = context.AtomicMinS32(storageKind, e0, e1, value);
} }
else else if (type == AtomSize.U32)
{ {
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); res = context.AtomicMinU32(storageKind, e0, e1, value);
}
break;
case AtomOp.Xor:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicXor(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Or:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicOr(storageKind, e0, e1, value);
} }
else else
{ {
@ -266,20 +250,49 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
} }
break; break;
case AtomOp.Min: case AtomOp.And:
if (type == AtomSize.S32) if (type == AtomSize.S32 || type == AtomSize.U32)
{ {
res = context.AtomicMinS32(storageKind, e0, e1, value); res = context.AtomicAnd(storageKind, e0, e1, value);
}
else if (type == AtomSize.U32)
{
res = context.AtomicMinU32(storageKind, e0, e1, value);
} }
else else
{ {
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}."); context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
} }
break; break;
case AtomOp.Or:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicOr(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Xor:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicXor(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
case AtomOp.Exch:
if (type == AtomSize.S32 || type == AtomSize.U32)
{
res = context.AtomicSwap(storageKind, e0, e1, value);
}
else
{
context.TranslatorContext.GpuAccessor.Log($"Invalid reduction type: {type}.");
}
break;
default:
context.TranslatorContext.GpuAccessor.Log($"Invalid atomic operation: {op}.");
break;
} }
return res; return res;

View File

@ -138,6 +138,8 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
// Ensure that conditions met for that branch are also met for the current one. // Ensure that conditions met for that branch are also met for the current one.
// Prefer the latest sources for the phi node. // Prefer the latest sources for the phi node.
int undefCount = 0;
for (int i = phiNode.SourcesCount - 1; i >= 0; i--) for (int i = phiNode.SourcesCount - 1; i >= 0; i--)
{ {
BasicBlock phiBlock = phiNode.GetBlock(i); BasicBlock phiBlock = phiNode.GetBlock(i);
@ -159,6 +161,26 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
return match; return match;
} }
} }
else if (phiSource.Type == OperandType.Undefined)
{
undefCount++;
}
}
// If all sources but one are undefined, we can assume that the one
// that is not undefined is the right one.
if (undefCount == phiNode.SourcesCount - 1)
{
for (int i = phiNode.SourcesCount - 1; i >= 0; i--)
{
Operand phiSource = phiNode.GetSource(i);
if (phiSource.Type != OperandType.Undefined)
{
return phiSource;
}
}
} }
} }

View File

@ -82,7 +82,6 @@ namespace Ryujinx.Graphics.Vulkan
private readonly ImageRef[] _imageRefs; private readonly ImageRef[] _imageRefs;
private readonly TextureBuffer[] _bufferTextureRefs; private readonly TextureBuffer[] _bufferTextureRefs;
private readonly TextureBuffer[] _bufferImageRefs; private readonly TextureBuffer[] _bufferImageRefs;
private readonly Format[] _bufferImageFormats;
private ArrayRef<TextureArray>[] _textureArrayRefs; private ArrayRef<TextureArray>[] _textureArrayRefs;
private ArrayRef<ImageArray>[] _imageArrayRefs; private ArrayRef<ImageArray>[] _imageArrayRefs;
@ -141,7 +140,6 @@ namespace Ryujinx.Graphics.Vulkan
_imageRefs = new ImageRef[Constants.MaxImageBindings * 2]; _imageRefs = new ImageRef[Constants.MaxImageBindings * 2];
_bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2]; _bufferTextureRefs = new TextureBuffer[Constants.MaxTextureBindings * 2];
_bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2]; _bufferImageRefs = new TextureBuffer[Constants.MaxImageBindings * 2];
_bufferImageFormats = new Format[Constants.MaxImageBindings * 2];
_textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>(); _textureArrayRefs = Array.Empty<ArrayRef<TextureArray>>();
_imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>(); _imageArrayRefs = Array.Empty<ArrayRef<ImageArray>>();
@ -391,17 +389,11 @@ namespace Ryujinx.Graphics.Vulkan
_dirty = DirtyFlags.All; _dirty = DirtyFlags.All;
} }
public void SetImage( public void SetImage(CommandBufferScoped cbs, ShaderStage stage, int binding, ITexture image)
CommandBufferScoped cbs,
ShaderStage stage,
int binding,
ITexture image,
Format imageFormat)
{ {
if (image is TextureBuffer imageBuffer) if (image is TextureBuffer imageBuffer)
{ {
_bufferImageRefs[binding] = imageBuffer; _bufferImageRefs[binding] = imageBuffer;
_bufferImageFormats[binding] = imageFormat;
} }
else if (image is TextureView view) else if (image is TextureView view)
{ {
@ -410,13 +402,12 @@ namespace Ryujinx.Graphics.Vulkan
iRef.View?.ClearUsage(FeedbackLoopHazards); iRef.View?.ClearUsage(FeedbackLoopHazards);
view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards); view?.PrepareForUsage(cbs, stage.ConvertToPipelineStageFlags(), FeedbackLoopHazards);
iRef = new(stage, view, view.GetView(imageFormat).GetIdentityImageView()); iRef = new(stage, view, view.GetIdentityImageView());
} }
else else
{ {
_imageRefs[binding] = default; _imageRefs[binding] = default;
_bufferImageRefs[binding] = null; _bufferImageRefs[binding] = null;
_bufferImageFormats[binding] = default;
} }
SignalDirty(DirtyFlags.Image); SignalDirty(DirtyFlags.Image);
@ -923,7 +914,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, _bufferImageFormats[binding + i], true) ?? default; bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default;
} }
tu.Push<BufferView>(bufferImages[..count]); tu.Push<BufferView>(bufferImages[..count]);

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

View File

@ -154,7 +154,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim;
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
_pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _intermediaryTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();

View File

@ -75,7 +75,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize); var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize);
var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize); var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize);
_pipeline.SetImage(ShaderStage.Compute, 0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _texture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();

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

View File

@ -219,7 +219,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer); buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer);
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) });
_pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _edgeOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();
@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _edgeOutputTexture, _samplerLinear);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _areaTexture, _samplerLinear);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 4, _searchTexture, _samplerLinear);
_pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _blendOutputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();
@ -238,7 +238,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects
_pipeline.Specialize(_specConstants); _pipeline.Specialize(_specConstants);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 3, _blendOutputTexture, _samplerLinear);
_pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, view, _samplerLinear);
_pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.SetImage(ShaderStage.Compute, 0, _outputTexture.GetView(FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);
_pipeline.ComputeBarrier(); _pipeline.ComputeBarrier();

View File

@ -1039,7 +1039,7 @@ namespace Ryujinx.Graphics.Vulkan
var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l); var dstView = Create2DLayerView(dst, dstLayer + z, dstLevel + l);
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null); _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
_pipeline.SetImage(ShaderStage.Compute, 0, dstView, dstFormat); _pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(dstFormat));
int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32; int dispatchX = (Math.Min(srcView.Info.Width, dstView.Info.Width) + 31) / 32;
int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32; int dispatchY = (Math.Min(srcView.Info.Height, dstView.Info.Height) + 31) / 32;
@ -1168,7 +1168,7 @@ namespace Ryujinx.Graphics.Vulkan
var dstView = Create2DLayerView(dst, dstLayer + z, 0); var dstView = Create2DLayerView(dst, dstLayer + z, 0);
_pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null); _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Compute, 0, srcView, null);
_pipeline.SetImage(ShaderStage.Compute, 0, dstView, format); _pipeline.SetImage(ShaderStage.Compute, 0, dstView.GetView(format));
_pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.DispatchCompute(dispatchX, dispatchY, 1);

View File

@ -13,7 +13,6 @@ namespace Ryujinx.Graphics.Vulkan
{ {
public TextureStorage Storage; public TextureStorage Storage;
public TextureView View; public TextureView View;
public GAL.Format ImageFormat;
} }
private readonly TextureRef[] _textureRefs; private readonly TextureRef[] _textureRefs;
@ -52,16 +51,6 @@ namespace Ryujinx.Graphics.Vulkan
_isBuffer = isBuffer; _isBuffer = isBuffer;
} }
public void SetFormats(int index, GAL.Format[] imageFormats)
{
for (int i = 0; i < imageFormats.Length; i++)
{
_textureRefs[index + i].ImageFormat = imageFormats[i];
}
SetDirty();
}
public void SetImages(int index, ITexture[] images) public void SetImages(int index, ITexture[] images)
{ {
for (int i = 0; i < images.Length; i++) for (int i = 0; i < images.Length; i++)
@ -142,7 +131,7 @@ namespace Ryujinx.Graphics.Vulkan
ref var texture = ref textures[i]; ref var texture = ref textures[i];
ref var refs = ref _textureRefs[i]; ref var refs = ref _textureRefs[i];
if (i > 0 && _textureRefs[i - 1].View == refs.View && _textureRefs[i - 1].ImageFormat == refs.ImageFormat) if (i > 0 && _textureRefs[i - 1].View == refs.View)
{ {
texture = textures[i - 1]; texture = textures[i - 1];
@ -150,7 +139,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
texture.ImageLayout = ImageLayout.General; texture.ImageLayout = ImageLayout.General;
texture.ImageView = refs.View?.GetView(refs.ImageFormat).GetIdentityImageView().Get(cbs).Value ?? default; texture.ImageView = refs.View?.GetIdentityImageView().Get(cbs).Value ?? default;
if (texture.ImageView.Handle == 0) if (texture.ImageView.Handle == 0)
{ {
@ -167,7 +156,7 @@ namespace Ryujinx.Graphics.Vulkan
for (int i = 0; i < bufferTextures.Length; i++) for (int i = 0; i < bufferTextures.Length; i++)
{ {
bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, _textureRefs[i].ImageFormat, true) ?? default; bufferTextures[i] = _bufferTextureRefs[i]?.GetBufferView(cbs, true) ?? default;
} }
return bufferTextures; return bufferTextures;

View File

@ -636,9 +636,9 @@ namespace Ryujinx.Graphics.Vulkan
var oldStencilTestEnable = _newState.StencilTestEnable; var oldStencilTestEnable = _newState.StencilTestEnable;
var oldDepthTestEnable = _newState.DepthTestEnable; var oldDepthTestEnable = _newState.DepthTestEnable;
var oldDepthWriteEnable = _newState.DepthWriteEnable; var oldDepthWriteEnable = _newState.DepthWriteEnable;
var oldTopology = _newState.Topology;
var oldViewports = DynamicState.Viewports; var oldViewports = DynamicState.Viewports;
var oldViewportsCount = _newState.ViewportsCount; var oldViewportsCount = _newState.ViewportsCount;
var oldTopology = _topology;
_newState.CullMode = CullModeFlags.None; _newState.CullMode = CullModeFlags.None;
_newState.StencilTestEnable = false; _newState.StencilTestEnable = false;
@ -658,7 +658,7 @@ namespace Ryujinx.Graphics.Vulkan
_newState.StencilTestEnable = oldStencilTestEnable; _newState.StencilTestEnable = oldStencilTestEnable;
_newState.DepthTestEnable = oldDepthTestEnable; _newState.DepthTestEnable = oldDepthTestEnable;
_newState.DepthWriteEnable = oldDepthWriteEnable; _newState.DepthWriteEnable = oldDepthWriteEnable;
_newState.Topology = oldTopology; SetPrimitiveTopology(oldTopology);
DynamicState.SetViewports(ref oldViewports, oldViewportsCount); DynamicState.SetViewports(ref oldViewports, oldViewportsCount);
@ -836,9 +836,9 @@ namespace Ryujinx.Graphics.Vulkan
SignalStateChange(); SignalStateChange();
} }
public void SetImage(ShaderStage stage, int binding, ITexture image, Format imageFormat) public void SetImage(ShaderStage stage, int binding, ITexture image)
{ {
_descriptorSetUpdater.SetImage(Cbs, stage, binding, image, imageFormat); _descriptorSetUpdater.SetImage(Cbs, stage, binding, image);
} }
public void SetImage(int binding, Auto<DisposableImageView> image) public void SetImage(int binding, Auto<DisposableImageView> image)

View File

@ -15,6 +15,7 @@
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Effects\Textures\SmaaAreaTexture.bin" /> <EmbeddedResource Include="Effects\Textures\SmaaAreaTexture.bin" />
<EmbeddedResource Include="Effects\Textures\SmaaSearchTexture.bin" /> <EmbeddedResource Include="Effects\Textures\SmaaSearchTexture.bin" />
<EmbeddedResource Include="Effects\Shaders\AreaScaling.spv" />
<EmbeddedResource Include="Effects\Shaders\FsrScaling.spv" /> <EmbeddedResource Include="Effects\Shaders\FsrScaling.spv" />
<EmbeddedResource Include="Effects\Shaders\FsrSharpening.spv" /> <EmbeddedResource Include="Effects\Shaders\FsrSharpening.spv" />
<EmbeddedResource Include="Effects\Shaders\Fxaa.spv" /> <EmbeddedResource Include="Effects\Shaders\Fxaa.spv" />

View File

@ -1,7 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using Format = Ryujinx.Graphics.GAL.Format; using Format = Ryujinx.Graphics.GAL.Format;
using VkFormat = Silk.NET.Vulkan.Format; using VkFormat = Silk.NET.Vulkan.Format;
@ -16,7 +16,6 @@ namespace Ryujinx.Graphics.Vulkan
private int _offset; private int _offset;
private int _size; private int _size;
private Auto<DisposableBufferView> _bufferView; private Auto<DisposableBufferView> _bufferView;
private Dictionary<Format, Auto<DisposableBufferView>> _selfManagedViews;
private int _bufferCount; private int _bufferCount;
@ -80,35 +79,25 @@ namespace Ryujinx.Graphics.Vulkan
private void ReleaseImpl() private void ReleaseImpl()
{ {
if (_selfManagedViews != null)
{
foreach (var bufferView in _selfManagedViews.Values)
{
bufferView.Dispose();
}
_selfManagedViews = null;
}
_bufferView?.Dispose(); _bufferView?.Dispose();
_bufferView = null; _bufferView = null;
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
_gd.SetBufferData(_bufferHandle, _offset, data.Memory.Span); _gd.SetBufferData(_bufferHandle, _offset, data.Span);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
@ -137,28 +126,5 @@ namespace Ryujinx.Graphics.Vulkan
return _bufferView?.Get(cbs, _offset, _size, write).Value ?? default; return _bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
} }
public BufferView GetBufferView(CommandBufferScoped cbs, Format format, bool write)
{
var vkFormat = FormatTable.GetFormat(format);
if (vkFormat == VkFormat)
{
return GetBufferView(cbs, write);
}
if (_selfManagedViews != null && _selfManagedViews.TryGetValue(format, out var bufferView))
{
return bufferView.Get(cbs, _offset, _size, write).Value;
}
bufferView = _gd.BufferManager.CreateView(_bufferHandle, vkFormat, _offset, _size, ReleaseImpl);
if (bufferView != null)
{
(_selfManagedViews ??= new Dictionary<Format, Auto<DisposableBufferView>>()).Add(format, bufferView);
}
return bufferView?.Get(cbs, _offset, _size, write).Value ?? default;
}
} }
} }

View File

@ -1,7 +1,7 @@
using Ryujinx.Common.Memory;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan; using Silk.NET.Vulkan;
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -746,23 +746,23 @@ namespace Ryujinx.Graphics.Vulkan
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data) public void SetData(MemoryOwner<byte> data)
{ {
SetData(data.Memory.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false); SetData(data.Span, 0, 0, Info.GetLayers(), Info.Levels, singleSlice: false);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level) public void SetData(MemoryOwner<byte> data, int layer, int level)
{ {
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true); SetData(data.Span, layer, level, 1, 1, singleSlice: true);
data.Dispose(); data.Dispose();
} }
/// <inheritdoc/> /// <inheritdoc/>
public void SetData(IMemoryOwner<byte> data, int layer, int level, Rectangle<int> region) public void SetData(MemoryOwner<byte> data, int layer, int level, Rectangle<int> region)
{ {
SetData(data.Memory.Span, layer, level, 1, 1, singleSlice: true, region); SetData(data.Span, layer, level, 1, 1, singleSlice: true, region);
data.Dispose(); data.Dispose();
} }

View File

@ -568,6 +568,13 @@ namespace Ryujinx.Graphics.Vulkan
_scalingFilter.Level = _scalingFilterLevel; _scalingFilter.Level = _scalingFilterLevel;
break; break;
case ScalingFilter.Area:
if (_scalingFilter is not AreaScalingFilter)
{
_scalingFilter?.Dispose();
_scalingFilter = new AreaScalingFilter(_gd, _device);
}
break;
} }
} }
} }

View File

@ -647,7 +647,7 @@ namespace Ryujinx.UI
} }
var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value var memoryConfiguration = ConfigurationState.Instance.System.ExpandRam.Value
? HLE.MemoryConfiguration.MemoryConfiguration6GiB ? HLE.MemoryConfiguration.MemoryConfiguration8GiB
: HLE.MemoryConfiguration.MemoryConfiguration4GiB; : HLE.MemoryConfiguration.MemoryConfiguration4GiB;
IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; IntegrityCheckLevel fsIntegrityCheckLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None;

View File

@ -28,8 +28,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
MemoryArrange.MemoryArrange4GiBSystemDev or MemoryArrange.MemoryArrange4GiBSystemDev or
MemoryArrange.MemoryArrange6GiBAppletDev => 3285 * MiB, MemoryArrange.MemoryArrange6GiBAppletDev => 3285 * MiB,
MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB, MemoryArrange.MemoryArrange4GiBAppletDev => 2048 * MiB,
MemoryArrange.MemoryArrange6GiB or MemoryArrange.MemoryArrange6GiB => 4916 * MiB,
MemoryArrange.MemoryArrange8GiB => 4916 * MiB, MemoryArrange.MemoryArrange8GiB => 6964 * MiB,
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."), _ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
}; };
} }
@ -42,8 +42,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common
MemoryArrange.MemoryArrange4GiBAppletDev => 1554 * MiB, MemoryArrange.MemoryArrange4GiBAppletDev => 1554 * MiB,
MemoryArrange.MemoryArrange4GiBSystemDev => 448 * MiB, MemoryArrange.MemoryArrange4GiBSystemDev => 448 * MiB,
MemoryArrange.MemoryArrange6GiB => 562 * MiB, MemoryArrange.MemoryArrange6GiB => 562 * MiB,
MemoryArrange.MemoryArrange6GiBAppletDev or MemoryArrange.MemoryArrange6GiBAppletDev => 2193 * MiB,
MemoryArrange.MemoryArrange8GiB => 2193 * MiB, MemoryArrange.MemoryArrange8GiB => 562 * MiB,
_ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."), _ => throw new ArgumentException($"Invalid memory arrange \"{arrange}\"."),
}; };
} }

View File

@ -14,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{ {
private readonly MemoryOwner<byte> _rawDataOwner; private readonly MemoryOwner<byte> _rawDataOwner;
private Span<byte> Raw => _rawDataOwner.Memory.Span; private Span<byte> Raw => _rawDataOwner.Span;
private ref ParcelHeader Header => ref MemoryMarshal.Cast<byte, ParcelHeader>(Raw)[0]; private ref ParcelHeader Header => ref MemoryMarshal.Cast<byte, ParcelHeader>(Raw)[0];

View File

@ -412,9 +412,9 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat); Format format = ConvertColorFormat(item.GraphicBuffer.Object.Buffer.Surfaces[0].ColorFormat);
int bytesPerPixel = byte bytesPerPixel =
format == Format.B5G6R5Unorm || format == Format.B5G6R5Unorm ||
format == Format.R4G4B4A4Unorm ? 2 : 4; format == Format.R4G4B4A4Unorm ? (byte)2 : (byte)4;
int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2; int gobBlocksInY = 1 << item.GraphicBuffer.Object.Buffer.Surfaces[0].BlockHeightLog2;

View File

@ -219,7 +219,7 @@ namespace Ryujinx.Headless.SDL2
// Hacks // 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; } public bool ExpandRAM { get; set; }
[Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")] [Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")]

View File

@ -562,7 +562,7 @@ namespace Ryujinx.Headless.SDL2
_userChannelPersistence, _userChannelPersistence,
renderer, renderer,
new SDL2HardwareDeviceDriver(), new SDL2HardwareDeviceDriver(),
options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration6GiB : MemoryConfiguration.MemoryConfiguration4GiB, options.ExpandRAM ? MemoryConfiguration.MemoryConfiguration8GiB : MemoryConfiguration.MemoryConfiguration4GiB,
window, window,
options.SystemLanguage, options.SystemLanguage,
options.SystemRegion, options.SystemRegion,

View File

@ -1,5 +1,5 @@
using Ryujinx.Common.Memory;
using System; using System;
using System.Buffers;
namespace Ryujinx.Memory namespace Ryujinx.Memory
{ {
@ -7,7 +7,7 @@ namespace Ryujinx.Memory
{ {
private readonly IWritableBlock _block; private readonly IWritableBlock _block;
private readonly ulong _va; private readonly ulong _va;
private readonly IMemoryOwner<byte> _memoryOwner; private readonly MemoryOwner<byte> _memoryOwner;
private readonly bool _tracked; private readonly bool _tracked;
private bool NeedsWriteback => _block != null; private bool NeedsWriteback => _block != null;
@ -22,7 +22,7 @@ namespace Ryujinx.Memory
Memory = memory; Memory = memory;
} }
public WritableRegion(IWritableBlock block, ulong va, IMemoryOwner<byte> memoryOwner, bool tracked = false) public WritableRegion(IWritableBlock block, ulong va, MemoryOwner<byte> memoryOwner, bool tracked = false)
: this(block, va, memoryOwner.Memory, tracked) : this(block, va, memoryOwner.Memory, tracked)
{ {
_memoryOwner = memoryOwner; _memoryOwner = memoryOwner;

View File

@ -238,7 +238,7 @@ namespace Ryujinx.UI.Common.Configuration
public MemoryManagerMode MemoryManagerMode { get; set; } public MemoryManagerMode MemoryManagerMode { get; set; }
/// <summary> /// <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> /// </summary>
public bool ExpandRam { get; set; } public bool ExpandRam { get; set; }

View File

@ -845,7 +845,7 @@ namespace Ryujinx.Ava
Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}"); Logger.Info?.PrintMsg(LogClass.Gpu, $"Backend Threading ({threadingMode}): {isGALThreaded}");
// Initialize Configuration. // 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, HLEConfiguration configuration = new(VirtualFileSystem,
_viewModel.LibHacHorizonManager, _viewModel.LibHacHorizonManager,

View File

@ -148,7 +148,7 @@
"SettingsTabSystemAudioBackendSDL2": "SDL2", "SettingsTabSystemAudioBackendSDL2": "SDL2",
"SettingsTabSystemHacks": "Hacks", "SettingsTabSystemHacks": "Hacks",
"SettingsTabSystemHacksNote": "May cause instability", "SettingsTabSystemHacksNote": "May cause instability",
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)", "SettingsTabSystemExpandDramSize": "Expand DRAM to 8GiB",
"SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services", "SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services",
"SettingsTabGraphics": "Graphics", "SettingsTabGraphics": "Graphics",
"SettingsTabGraphicsAPI": "Graphics API", "SettingsTabGraphicsAPI": "Graphics API",
@ -581,7 +581,7 @@
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.", "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.", "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.", "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.", "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.", "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.", "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.",
@ -773,10 +773,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.", "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:", "GraphicsAALabel": "Anti-Aliasing:",
"GraphicsScalingFilterLabel": "Scaling Filter:", "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", "GraphicsScalingFilterBilinear": "Bilinear",
"GraphicsScalingFilterNearest": "Nearest", "GraphicsScalingFilterNearest": "Nearest",
"GraphicsScalingFilterFsr": "FSR", "GraphicsScalingFilterFsr": "FSR",
"GraphicsScalingFilterArea": "Area",
"GraphicsScalingFilterLevelLabel": "Level", "GraphicsScalingFilterLevelLabel": "Level",
"GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.", "GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.",
"SmaaLow": "SMAA Low", "SmaaLow": "SMAA Low",

View File

@ -1,4 +1,4 @@
<UserControl <UserControl
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsGraphicsView" x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsGraphicsView"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@ -173,6 +173,9 @@
<ComboBoxItem> <ComboBoxItem>
<TextBlock Text="{locale:Locale GraphicsScalingFilterFsr}" /> <TextBlock Text="{locale:Locale GraphicsScalingFilterFsr}" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="{locale:Locale GraphicsScalingFilterArea}" />
</ComboBoxItem>
</ComboBox> </ComboBox>
<controls:SliderScroll Value="{Binding ScalingFilterLevel}" <controls:SliderScroll Value="{Binding ScalingFilterLevel}"
ToolTip.Tip="{locale:Locale GraphicsScalingFilterLevelTooltip}" ToolTip.Tip="{locale:Locale GraphicsScalingFilterLevelTooltip}"