From b5fcf883e863c5f449855dc1113db07383b914b5 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 15 Feb 2019 12:44:25 -0300 Subject: [PATCH 01/36] Implement IStorage GetSize (#585) --- Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs index d000635de3..85ab2cf65e 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs @@ -16,7 +16,8 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv { _commands = new Dictionary { - { 0, Read } + { 0, Read }, + { 4, GetSize } }; _baseStream = baseStream; @@ -51,5 +52,13 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv return 0; } + + // GetSize() -> u64 size + public long GetSize(ServiceCtx context) + { + context.ResponseData.Write(_baseStream.Length); + + return 0; + } } } From f8a9faa1b96e9612e835f05e8536b274963b6ab0 Mon Sep 17 00:00:00 2001 From: jduncanator <1518948+jduncanator@users.noreply.github.com> Date: Sat, 16 Feb 2019 19:37:22 +1100 Subject: [PATCH 02/36] Config: Correct MulticoreSched casing (#588) --- Ryujinx/Configuration.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs index 96f4d66f4b..dbbec1cbc6 100644 --- a/Ryujinx/Configuration.cs +++ b/Ryujinx/Configuration.cs @@ -79,7 +79,7 @@ namespace Ryujinx /// /// Enables or disables multi-core scheduling of threads /// - public bool EnableMultiCoreScheduling { get; private set; } + public bool EnableMulticoreScheduling { get; private set; } /// /// Enables integrity checks on Game content files @@ -188,7 +188,7 @@ namespace Ryujinx device.System.State.SetLanguage(Instance.SystemLanguage); - if (Instance.EnableMultiCoreScheduling) + if (Instance.EnableMulticoreScheduling) { device.System.EnableMultiCoreScheduling(); } From 17ac118946dd607d466dd17ea75aaa8a66560c94 Mon Sep 17 00:00:00 2001 From: AlexLavoie42 Date: Sun, 17 Feb 2019 01:52:16 -0800 Subject: [PATCH 03/36] Added "ROM not found." message if specified file is invalid. (#592) * Added "ROM not found." message if specified file is invalid. * Fixed styling * Made message more specific and changed both cases to warnings. --- Ryujinx/Program.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index c73ff9b9c2..52c85d568c 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -75,10 +75,14 @@ namespace Ryujinx break; } } + else + { + Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file"); + } } else { - Logger.PrintInfo(LogClass.Application, "Please specify the folder with the NSOs/IStorage or a NSO/NRO."); + Logger.PrintWarning(LogClass.Application, "Please specify the folder with the NSOs/IStorage or a NSO/NRO."); } using (GlScreen screen = new GlScreen(device, renderer)) From 1b4809bde1fc2a0265bfa6082e17821a08fbce7f Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Mon, 18 Feb 2019 00:52:01 +0100 Subject: [PATCH 04/36] Update CpuTestMisc.cs --- Ryujinx.Tests/Cpu/CpuTestMisc.cs | 122 ++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 2 deletions(-) diff --git a/Ryujinx.Tests/Cpu/CpuTestMisc.cs b/Ryujinx.Tests/Cpu/CpuTestMisc.cs index 4d6783f71e..89ea47a920 100644 --- a/Ryujinx.Tests/Cpu/CpuTestMisc.cs +++ b/Ryujinx.Tests/Cpu/CpuTestMisc.cs @@ -1,3 +1,5 @@ +#define Misc + using ChocolArm64.State; using NUnit.Framework; @@ -6,9 +8,120 @@ using System.Runtime.Intrinsics.X86; namespace Ryujinx.Tests.Cpu { - [Category("Misc"), Explicit] + [Category("Misc")] public sealed class CpuTestMisc : CpuTest { +#if Misc + private const int RndCnt = 2; + private const int RndCntImm = 2; + +#region "AluImm & Csel" + [Test, Pairwise] + public void Adds_Csinc_64bit([Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul, + 0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn, + [Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm, + [Values(0b00u, 0b01u)] uint shift, // + [Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // + { + uint opCmn = 0xB100001F; // ADDS X31, X0, #0, LSL #0 -> CMN X0, #0, LSL #0 + uint opCset = 0x9A9F07E0; // CSINC X0, X31, X31, EQ -> CSET X0, NE + + opCmn |= ((shift & 3) << 22) | ((imm & 4095) << 10); + opCset |= ((cond & 15) << 12); + + SetThreadState(x0: xn); + Opcode(opCmn); + Opcode(opCset); + Opcode(0xD4200000); // BRK #0 + Opcode(0xD65F03C0); // RET + ExecuteOpcodes(); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Adds_Csinc_32bit([Values(0x00000000u, 0x7FFFFFFFu, + 0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn, + [Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm, + [Values(0b00u, 0b01u)] uint shift, // + [Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // + { + uint opCmn = 0x3100001F; // ADDS W31, W0, #0, LSL #0 -> CMN W0, #0, LSL #0 + uint opCset = 0x1A9F07E0; // CSINC W0, W31, W31, EQ -> CSET W0, NE + + opCmn |= ((shift & 3) << 22) | ((imm & 4095) << 10); + opCset |= ((cond & 15) << 12); + + SetThreadState(x0: wn); + Opcode(opCmn); + Opcode(opCset); + Opcode(0xD4200000); // BRK #0 + Opcode(0xD65F03C0); // RET + ExecuteOpcodes(); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Subs_Csinc_64bit([Values(0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul, + 0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul)] [Random(RndCnt)] ulong xn, + [Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm, + [Values(0b00u, 0b01u)] uint shift, // + [Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // + { + uint opCmp = 0xF100001F; // SUBS X31, X0, #0, LSL #0 -> CMP X0, #0, LSL #0 + uint opCset = 0x9A9F07E0; // CSINC X0, X31, X31, EQ -> CSET X0, NE + + opCmp |= ((shift & 3) << 22) | ((imm & 4095) << 10); + opCset |= ((cond & 15) << 12); + + SetThreadState(x0: xn); + Opcode(opCmp); + Opcode(opCset); + Opcode(0xD4200000); // BRK #0 + Opcode(0xD65F03C0); // RET + ExecuteOpcodes(); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Subs_Csinc_32bit([Values(0x00000000u, 0x7FFFFFFFu, + 0x80000000u, 0xFFFFFFFFu)] [Random(RndCnt)] uint wn, + [Values(0u, 4095u)] [Random(0u, 4095u, RndCntImm)] uint imm, + [Values(0b00u, 0b01u)] uint shift, // + [Values(0b0000u, 0b0001u, 0b0010u, 0b0011u, // + { + uint opCmp = 0x7100001F; // SUBS W31, W0, #0, LSL #0 -> CMP W0, #0, LSL #0 + uint opCset = 0x1A9F07E0; // CSINC W0, W31, W31, EQ -> CSET W0, NE + + opCmp |= ((shift & 3) << 22) | ((imm & 4095) << 10); + opCset |= ((cond & 15) << 12); + + SetThreadState(x0: wn); + Opcode(opCmp); + Opcode(opCset); + Opcode(0xD4200000); // BRK #0 + Opcode(0xD65F03C0); // RET + ExecuteOpcodes(); + + CompareAgainstUnicorn(); + } +#endregion + + [Explicit] [TestCase(0xFFFFFFFDu)] // Roots. [TestCase(0x00000005u)] public void Misc1(uint a) @@ -42,6 +155,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetThreadState().X0, Is.Zero); } + [Explicit] [TestCase(-20f, -5f)] // 18 integer solutions. [TestCase(-12f, -6f)] [TestCase(-12f, 3f)] @@ -91,6 +205,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(Sse41.Extract(GetThreadState().V0, (byte)0), Is.EqualTo(16f)); } + [Explicit] [TestCase(-20d, -5d)] // 18 integer solutions. [TestCase(-12d, -6d)] [TestCase(-12d, 3d)] @@ -140,7 +255,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(VectorExtractDouble(GetThreadState().V0, (byte)0), Is.EqualTo(16d)); } - [Test] + [Test, Ignore("The Tester supports only one return point.")] public void MiscF([Range(0u, 92u, 1u)] uint a) { ulong Fn(uint n) @@ -213,6 +328,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetThreadState().X0, Is.EqualTo(Fn(a))); } + [Explicit] [Test] public void MiscR() { @@ -255,6 +371,7 @@ namespace Ryujinx.Tests.Cpu Assert.That(GetThreadState().X0, Is.EqualTo(result)); } + [Explicit] [TestCase( 0ul)] [TestCase( 1ul)] [TestCase( 2ul)] @@ -266,5 +383,6 @@ namespace Ryujinx.Tests.Cpu Assert.That(threadState.X0, Is.EqualTo(a)); } +#endif } } From 948a758270cf1259fd79d7508c105202396c877e Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 18 Feb 2019 01:17:34 -0300 Subject: [PATCH 05/36] Optimize CMN/ADDS to do a single comparision like CMP/SUBS (#576) --- ChocolArm64/Instructions/InstEmitAlu.cs | 2 + ChocolArm64/Translation/ILEmitterCtx.cs | 56 +++++++++++++++++++++---- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitAlu.cs b/ChocolArm64/Instructions/InstEmitAlu.cs index d5d9cd6541..bd49124e49 100644 --- a/ChocolArm64/Instructions/InstEmitAlu.cs +++ b/ChocolArm64/Instructions/InstEmitAlu.cs @@ -51,6 +51,8 @@ namespace ChocolArm64.Instructions public static void Adds(ILEmitterCtx context) { + context.TryOptMarkCondWithoutCmp(); + EmitAluLoadOpers(context); context.Emit(OpCodes.Add); diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs index ef63e60cd3..fa65bbf989 100644 --- a/ChocolArm64/Translation/ILEmitterCtx.cs +++ b/ChocolArm64/Translation/ILEmitterCtx.cs @@ -312,19 +312,57 @@ namespace ChocolArm64.Translation public void EmitCondBranch(ILLabel target, Condition cond) { + if (_optOpLastCompare != null && + _optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond)) + { + if (_optOpLastCompare.Emitter == InstEmit.Subs) + { + Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize); + Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize); + + Emit(_branchOps[cond], target); + + return; + } + else if (_optOpLastCompare.Emitter == InstEmit.Adds && cond != Condition.GeUn + && cond != Condition.LtUn + && cond != Condition.GtUn + && cond != Condition.LeUn) + { + //There are several limitations that needs to be taken into account for CMN comparisons: + //* The unsigned comparisons are not valid, as they depend on the + //carry flag value, and they will have different values for addition and + //subtraction. For addition, it's carry, and for subtraction, it's borrow. + //So, we need to make sure we're not doing a unsigned compare for the CMN case. + //* We can only do the optimization for the immediate variants, + //because when the second operand value is exactly INT_MIN, we can't + //negate the value as theres no positive counterpart. + //Such invalid values can't be encoded on the immediate encodings. + if (_optOpLastCompare is IOpCodeAluImm64 op) + { + Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize); + + if (_optOpLastCompare.RegisterSize == RegisterSize.Int32) + { + EmitLdc_I4((int)-op.Imm); + } + else + { + EmitLdc_I8(-op.Imm); + } + + Emit(_branchOps[cond], target); + + return; + } + } + } + OpCode ilOp; int intCond = (int)cond; - if (_optOpLastCompare != null && - _optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond)) - { - Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize); - Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize); - - ilOp = _branchOps[cond]; - } - else if (intCond < 14) + if (intCond < 14) { int condTrue = intCond >> 1; From 932224f05112180aa5f52162cbbc3a17c339075f Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 18 Feb 2019 20:52:06 -0300 Subject: [PATCH 06/36] ARM exclusive monitor and multicore fixes (#589) * Implement ARM exclusive load/store with compare exchange insts, and enable multicore by default * Fix comment typo * Support Linux and OSX on MemoryAlloc and CompareExchange128, some cleanup * Use intel syntax on assembly code * Adjust identation * Add CPUID check and fix exclusive reservation granule size * Update schema multicore scheduling default value * Make the cpu id check code lower case aswell --- ChocolArm64/ChocolArm64.csproj | 1 + ChocolArm64/CpuThread.cs | 2 - ChocolArm64/Instructions/InstEmitMemoryEx.cs | 281 ++++++++++++++---- ChocolArm64/Memory/CompareExchange128.cs | 151 ++++++++++ ChocolArm64/Memory/MemoryAlloc.cs | 114 +++++++ ChocolArm64/Memory/MemoryAllocUnix.cs | 70 +++++ ChocolArm64/Memory/MemoryAllocWindows.cs | 155 ++++++++++ ChocolArm64/Memory/MemoryManager.cs | 194 ++++++------ ChocolArm64/Memory/MemoryProtection.cs | 16 + .../Memory/MemoryProtectionException.cs | 10 + ChocolArm64/State/CpuThreadState.cs | 31 +- ChocolArm64/Translation/ILEmitterCtx.cs | 34 +++ .../HOS/Kernel/Common/KernelTransfer.cs | 2 +- .../HOS/Kernel/Threading/HleScheduler.cs | 2 - .../HOS/Kernel/Threading/KAddressArbiter.cs | 141 +++------ .../HOS/Kernel/Threading/KCoreContext.cs | 2 - Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs | 5 - Ryujinx/Config.jsonc | 2 +- Ryujinx/_schema.json | 2 +- 19 files changed, 954 insertions(+), 261 deletions(-) create mode 100644 ChocolArm64/Memory/CompareExchange128.cs create mode 100644 ChocolArm64/Memory/MemoryAlloc.cs create mode 100644 ChocolArm64/Memory/MemoryAllocUnix.cs create mode 100644 ChocolArm64/Memory/MemoryAllocWindows.cs create mode 100644 ChocolArm64/Memory/MemoryProtection.cs create mode 100644 ChocolArm64/Memory/MemoryProtectionException.cs diff --git a/ChocolArm64/ChocolArm64.csproj b/ChocolArm64/ChocolArm64.csproj index 1156e361f5..0b4051b051 100644 --- a/ChocolArm64/ChocolArm64.csproj +++ b/ChocolArm64/ChocolArm64.csproj @@ -14,6 +14,7 @@ + diff --git a/ChocolArm64/CpuThread.cs b/ChocolArm64/CpuThread.cs index 6cd34f8127..ad1fd6f3c1 100644 --- a/ChocolArm64/CpuThread.cs +++ b/ChocolArm64/CpuThread.cs @@ -32,8 +32,6 @@ namespace ChocolArm64 { translator.ExecuteSubroutine(this, entrypoint); - memory.RemoveMonitor(ThreadState.Core); - WorkFinished?.Invoke(this, EventArgs.Empty); }); } diff --git a/ChocolArm64/Instructions/InstEmitMemoryEx.cs b/ChocolArm64/Instructions/InstEmitMemoryEx.cs index 42daca63b7..215fcffdd5 100644 --- a/ChocolArm64/Instructions/InstEmitMemoryEx.cs +++ b/ChocolArm64/Instructions/InstEmitMemoryEx.cs @@ -23,7 +23,9 @@ namespace ChocolArm64.Instructions public static void Clrex(ILEmitterCtx context) { - EmitMemoryCall(context, nameof(MemoryManager.ClearExclusive)); + context.EmitLdarg(TranslatedSub.StateArgIdx); + + context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.ClearExclusiveAddress)); } public static void Dmb(ILEmitterCtx context) => EmitBarrier(context); @@ -37,12 +39,12 @@ namespace ChocolArm64.Instructions private static void EmitLdr(ILEmitterCtx context, AccessType accType) { - EmitLoad(context, accType, false); + EmitLoad(context, accType, pair: false); } private static void EmitLdp(ILEmitterCtx context, AccessType accType) { - EmitLoad(context, accType, true); + EmitLoad(context, accType, pair: true); } private static void EmitLoad(ILEmitterCtx context, AccessType accType, bool pair) @@ -57,32 +59,128 @@ namespace ChocolArm64.Instructions EmitBarrier(context); } - if (exclusive) - { - EmitMemoryCall(context, nameof(MemoryManager.SetExclusive), op.Rn); - } - context.EmitLdint(op.Rn); context.EmitSttmp(); - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdtmp(); + if (exclusive) + { + context.EmitLdarg(TranslatedSub.StateArgIdx); + context.EmitLdtmp(); - EmitReadZxCall(context, op.Size); + context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.SetExclusiveAddress)); + } - context.EmitStintzr(op.Rt); + void WriteExclusiveValue(string propName) + { + if (op.Size < 3) + { + context.Emit(OpCodes.Conv_U8); + } + + context.EmitSttmp2(); + context.EmitLdarg(TranslatedSub.StateArgIdx); + context.EmitLdtmp2(); + + context.EmitCallPrivatePropSet(typeof(CpuThreadState), propName); + + context.EmitLdtmp2(); + + if (op.Size < 3) + { + context.Emit(OpCodes.Conv_U4); + } + } if (pair) { + //Exclusive loads should be atomic. For pairwise loads, we need to + //read all the data at once. For a 32-bits pairwise load, we do a + //simple 64-bits load, for a 128-bits load, we need to call a special + //method to read 128-bits atomically. + if (op.Size == 2) + { + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + context.EmitLdtmp(); + + EmitReadZxCall(context, 3); + + context.Emit(OpCodes.Dup); + + //Mask low half. + context.Emit(OpCodes.Conv_U4); + + if (exclusive) + { + WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); + } + + context.EmitStintzr(op.Rt); + + //Shift high half. + context.EmitLsr(32); + context.Emit(OpCodes.Conv_U4); + + if (exclusive) + { + WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueHigh)); + } + + context.EmitStintzr(op.Rt2); + } + else if (op.Size == 3) + { + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + context.EmitLdtmp(); + + context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicReadInt128)); + + context.Emit(OpCodes.Dup); + + //Load low part of the vector. + context.EmitLdc_I4(0); + context.EmitLdc_I4(3); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractIntZx)); + + if (exclusive) + { + WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); + } + + context.EmitStintzr(op.Rt); + + //Load high part of the vector. + context.EmitLdc_I4(1); + context.EmitLdc_I4(3); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorExtractIntZx)); + + if (exclusive) + { + WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueHigh)); + } + + context.EmitStintzr(op.Rt2); + } + else + { + throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes."); + } + } + else + { + //8, 16, 32 or 64-bits (non-pairwise) load. context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); - context.EmitLdc_I8(1 << op.Size); - - context.Emit(OpCodes.Add); EmitReadZxCall(context, op.Size); - context.EmitStintzr(op.Rt2); + if (exclusive) + { + WriteExclusiveValue(nameof(CpuThreadState.ExclusiveValueLow)); + } + + context.EmitStintzr(op.Rt); } } @@ -99,12 +197,12 @@ namespace ChocolArm64.Instructions private static void EmitStr(ILEmitterCtx context, AccessType accType) { - EmitStore(context, accType, false); + EmitStore(context, accType, pair: false); } private static void EmitStp(ILEmitterCtx context, AccessType accType) { - EmitStore(context, accType, true); + EmitStore(context, accType, pair: true); } private static void EmitStore(ILEmitterCtx context, AccessType accType, bool pair) @@ -119,66 +217,133 @@ namespace ChocolArm64.Instructions EmitBarrier(context); } - ILLabel lblEx = new ILLabel(); - ILLabel lblEnd = new ILLabel(); - if (exclusive) { - EmitMemoryCall(context, nameof(MemoryManager.TestExclusive), op.Rn); + ILLabel lblEx = new ILLabel(); + ILLabel lblEnd = new ILLabel(); + + context.EmitLdarg(TranslatedSub.StateArgIdx); + context.EmitLdint(op.Rn); + + context.EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.CheckExclusiveAddress)); context.Emit(OpCodes.Brtrue_S, lblEx); - context.EmitLdc_I8(1); + //Address check failed, set error right away and do not store anything. + context.EmitLdc_I4(1); context.EmitStintzr(op.Rs); - context.Emit(OpCodes.Br_S, lblEnd); - } + context.Emit(OpCodes.Br, lblEnd); - context.MarkLabel(lblEx); + //Address check passsed. + context.MarkLabel(lblEx); - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdint(op.Rn); - context.EmitLdintzr(op.Rt); - - EmitWriteCall(context, op.Size); - - if (pair) - { context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdint(op.Rn); - context.EmitLdc_I8(1 << op.Size); - context.Emit(OpCodes.Add); + context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdintzr(op.Rt2); + context.EmitCallPrivatePropGet(typeof(CpuThreadState), nameof(CpuThreadState.ExclusiveValueLow)); - EmitWriteCall(context, op.Size); - } + void EmitCast() + { + //The input should be always int64. + switch (op.Size) + { + case 0: context.Emit(OpCodes.Conv_U1); break; + case 1: context.Emit(OpCodes.Conv_U2); break; + case 2: context.Emit(OpCodes.Conv_U4); break; + } + } + + EmitCast(); + + if (pair) + { + context.EmitLdarg(TranslatedSub.StateArgIdx); + + context.EmitCallPrivatePropGet(typeof(CpuThreadState), nameof(CpuThreadState.ExclusiveValueHigh)); + + EmitCast(); + + context.EmitLdintzr(op.Rt); + + EmitCast(); + + context.EmitLdintzr(op.Rt2); + + EmitCast(); + + switch (op.Size) + { + case 2: context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchange2xInt32)); break; + case 3: context.EmitPrivateCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt128)); break; + + default: throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes."); + } + } + else + { + context.EmitLdintzr(op.Rt); + + EmitCast(); + + switch (op.Size) + { + case 0: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeByte)); break; + case 1: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt16)); break; + case 2: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt32)); break; + case 3: context.EmitCall(typeof(MemoryManager), nameof(MemoryManager.AtomicCompareExchangeInt64)); break; + + default: throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes."); + } + } + + //The value returned is a bool, true if the values compared + //were equal and the new value was written, false otherwise. + //We need to invert this result, as on ARM 1 indicates failure, + //and 0 success on those instructions. + context.EmitLdc_I4(1); + + context.Emit(OpCodes.Xor); + context.Emit(OpCodes.Dup); + context.Emit(OpCodes.Conv_U8); - if (exclusive) - { - context.EmitLdc_I8(0); context.EmitStintzr(op.Rs); - EmitMemoryCall(context, nameof(MemoryManager.ClearExclusiveForStore)); + //Only clear the exclusive monitor if the store was successful (Rs = false). + context.Emit(OpCodes.Brtrue_S, lblEnd); + + Clrex(context); + + context.MarkLabel(lblEnd); } - - context.MarkLabel(lblEnd); - } - - private static void EmitMemoryCall(ILEmitterCtx context, string name, int rn = -1) - { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitCallPropGet(typeof(CpuThreadState), nameof(CpuThreadState.Core)); - - if (rn != -1) + else { - context.EmitLdint(rn); - } + void EmitWrite(int rt, long offset) + { + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + context.EmitLdint(op.Rn); - context.EmitCall(typeof(MemoryManager), name); + if (offset != 0) + { + context.EmitLdc_I8(offset); + + context.Emit(OpCodes.Add); + } + + context.EmitLdintzr(rt); + + EmitWriteCall(context, op.Size); + } + + EmitWrite(op.Rt, 0); + + if (pair) + { + EmitWrite(op.Rt2, 1 << op.Size); + } + } } private static void EmitBarrier(ILEmitterCtx context) diff --git a/ChocolArm64/Memory/CompareExchange128.cs b/ChocolArm64/Memory/CompareExchange128.cs new file mode 100644 index 0000000000..0fbe10f2cf --- /dev/null +++ b/ChocolArm64/Memory/CompareExchange128.cs @@ -0,0 +1,151 @@ +using System; +using System.Runtime.InteropServices; + +namespace ChocolArm64.Memory +{ + static class CompareExchange128 + { + private struct Int128 + { + public ulong Low { get; } + public ulong High { get; } + + public Int128(ulong low, ulong high) + { + Low = low; + High = high; + } + } + + private delegate Int128 InterlockedCompareExchange(IntPtr address, Int128 expected, Int128 desired); + + private delegate int GetCpuId(); + + private static InterlockedCompareExchange _interlockedCompareExchange; + + static CompareExchange128() + { + if (RuntimeInformation.OSArchitecture != Architecture.X64 || !IsCmpxchg16bSupported()) + { + throw new PlatformNotSupportedException(); + } + + byte[] interlockedCompareExchange128Code; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + interlockedCompareExchange128Code = new byte[] + { + 0x53, // push rbx + 0x49, 0x8b, 0x00, // mov rax, [r8] + 0x49, 0x8b, 0x19, // mov rbx, [r9] + 0x49, 0x89, 0xca, // mov r10, rcx + 0x49, 0x89, 0xd3, // mov r11, rdx + 0x49, 0x8b, 0x49, 0x08, // mov rcx, [r9+8] + 0x49, 0x8b, 0x50, 0x08, // mov rdx, [r8+8] + 0xf0, 0x49, 0x0f, 0xc7, 0x0b, // lock cmpxchg16b [r11] + 0x49, 0x89, 0x02, // mov [r10], rax + 0x4c, 0x89, 0xd0, // mov rax, r10 + 0x49, 0x89, 0x52, 0x08, // mov [r10+8], rdx + 0x5b, // pop rbx + 0xc3 // ret + }; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + interlockedCompareExchange128Code = new byte[] + { + 0x53, // push rbx + 0x49, 0x89, 0xd1, // mov r9, rdx + 0x48, 0x89, 0xcb, // mov rbx, rcx + 0x48, 0x89, 0xf0, // mov rax, rsi + 0x4c, 0x89, 0xca, // mov rdx, r9 + 0x4c, 0x89, 0xc1, // mov rcx, r8 + 0xf0, 0x48, 0x0f, 0xc7, 0x0f, // lock cmpxchg16b [rdi] + 0x5b, // pop rbx + 0xc3 // ret + }; + } + else + { + throw new PlatformNotSupportedException(); + } + + IntPtr funcPtr = MapCodeAsExecutable(interlockedCompareExchange128Code); + + _interlockedCompareExchange = Marshal.GetDelegateForFunctionPointer(funcPtr); + } + + private static bool IsCmpxchg16bSupported() + { + byte[] getCpuIdCode = new byte[] + { + 0x53, // push rbx + 0xb8, 0x01, 0x00, 0x00, 0x00, // mov eax, 0x1 + 0x0f, 0xa2, // cpuid + 0x89, 0xc8, // mov eax, ecx + 0x5b, // pop rbx + 0xc3 // ret + }; + + IntPtr funcPtr = MapCodeAsExecutable(getCpuIdCode); + + GetCpuId getCpuId = Marshal.GetDelegateForFunctionPointer(funcPtr); + + int cpuId = getCpuId(); + + MemoryAlloc.Free(funcPtr); + + return (cpuId & (1 << 13)) != 0; + } + + private static IntPtr MapCodeAsExecutable(byte[] code) + { + ulong codeLength = (ulong)code.Length; + + IntPtr funcPtr = MemoryAlloc.Allocate(codeLength); + + unsafe + { + fixed (byte* codePtr = code) + { + byte* dest = (byte*)funcPtr; + + long size = (long)codeLength; + + Buffer.MemoryCopy(codePtr, dest, size, size); + } + } + + MemoryAlloc.Reprotect(funcPtr, codeLength, MemoryProtection.Execute); + + return funcPtr; + } + + public static bool InterlockedCompareExchange128( + IntPtr address, + ulong expectedLow, + ulong expectedHigh, + ulong desiredLow, + ulong desiredHigh) + { + Int128 expected = new Int128(expectedLow, expectedHigh); + Int128 desired = new Int128(desiredLow, desiredHigh); + + Int128 old = _interlockedCompareExchange(address, expected, desired); + + return old.Low == expected.Low && old.High == expected.High; + } + + public static void InterlockedRead128(IntPtr address, out ulong low, out ulong high) + { + Int128 zero = new Int128(0, 0); + + Int128 old = _interlockedCompareExchange(address, zero, zero); + + low = old.Low; + high = old.High; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryAlloc.cs b/ChocolArm64/Memory/MemoryAlloc.cs new file mode 100644 index 0000000000..a24299cd70 --- /dev/null +++ b/ChocolArm64/Memory/MemoryAlloc.cs @@ -0,0 +1,114 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ChocolArm64.Memory +{ + public static class MemoryAlloc + { + public static bool HasWriteWatchSupport => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + public static IntPtr Allocate(ulong size) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + IntPtr sizeNint = new IntPtr((long)size); + + return MemoryAllocWindows.Allocate(sizeNint); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return MemoryAllocUnix.Allocate(size); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + public static IntPtr AllocateWriteTracked(ulong size) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + IntPtr sizeNint = new IntPtr((long)size); + + return MemoryAllocWindows.AllocateWriteTracked(sizeNint); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return MemoryAllocUnix.Allocate(size); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + public static void Reprotect(IntPtr address, ulong size, MemoryProtection permission) + { + bool result; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + IntPtr sizeNint = new IntPtr((long)size); + + result = MemoryAllocWindows.Reprotect(address, sizeNint, permission); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + result = MemoryAllocUnix.Reprotect(address, size, permission); + } + else + { + throw new PlatformNotSupportedException(); + } + + if (!result) + { + throw new MemoryProtectionException(permission); + } + } + + public static bool Free(IntPtr address) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return MemoryAllocWindows.Free(address); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return MemoryAllocUnix.Free(address); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool GetModifiedPages( + IntPtr address, + IntPtr size, + IntPtr[] addresses, + out ulong count) + { + //This is only supported on windows, but returning + //false (failed) is also valid for platforms without + //write tracking support on the OS. + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return MemoryAllocWindows.GetModifiedPages(address, size, addresses, out count); + } + else + { + count = 0; + + return false; + } + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryAllocUnix.cs b/ChocolArm64/Memory/MemoryAllocUnix.cs new file mode 100644 index 0000000000..857c1c5042 --- /dev/null +++ b/ChocolArm64/Memory/MemoryAllocUnix.cs @@ -0,0 +1,70 @@ +using Mono.Unix.Native; +using System; + +namespace ChocolArm64.Memory +{ + static class MemoryAllocUnix + { + public static IntPtr Allocate(ulong size) + { + ulong pageSize = (ulong)Syscall.sysconf(SysconfName._SC_PAGESIZE); + + const MmapProts prot = MmapProts.PROT_READ | MmapProts.PROT_WRITE; + + const MmapFlags flags = MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS; + + IntPtr ptr = Syscall.mmap(IntPtr.Zero, size + pageSize, prot, flags, -1, 0); + + if (ptr == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + + unsafe + { + ptr = new IntPtr(ptr.ToInt64() + (long)pageSize); + + *((ulong*)ptr - 1) = size; + } + + return ptr; + } + + public static bool Reprotect(IntPtr address, ulong size, Memory.MemoryProtection protection) + { + MmapProts prot = GetProtection(protection); + + return Syscall.mprotect(address, size, prot) == 0; + } + + private static MmapProts GetProtection(Memory.MemoryProtection protection) + { + switch (protection) + { + case Memory.MemoryProtection.None: return MmapProts.PROT_NONE; + case Memory.MemoryProtection.Read: return MmapProts.PROT_READ; + case Memory.MemoryProtection.ReadAndWrite: return MmapProts.PROT_READ | MmapProts.PROT_WRITE; + case Memory.MemoryProtection.ReadAndExecute: return MmapProts.PROT_READ | MmapProts.PROT_EXEC; + case Memory.MemoryProtection.Execute: return MmapProts.PROT_EXEC; + + default: throw new ArgumentException($"Invalid permission \"{protection}\"."); + } + } + + public static bool Free(IntPtr address) + { + ulong pageSize = (ulong)Syscall.sysconf(SysconfName._SC_PAGESIZE); + + ulong size; + + unsafe + { + size = *((ulong*)address - 1); + + address = new IntPtr(address.ToInt64() - (long)pageSize); + } + + return Syscall.munmap(address, size + pageSize) == 0; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryAllocWindows.cs b/ChocolArm64/Memory/MemoryAllocWindows.cs new file mode 100644 index 0000000000..82be8b1e4f --- /dev/null +++ b/ChocolArm64/Memory/MemoryAllocWindows.cs @@ -0,0 +1,155 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ChocolArm64.Memory +{ + static class MemoryAllocWindows + { + [Flags] + private enum AllocationType : uint + { + Commit = 0x1000, + Reserve = 0x2000, + Decommit = 0x4000, + Release = 0x8000, + Reset = 0x80000, + Physical = 0x400000, + TopDown = 0x100000, + WriteWatch = 0x200000, + LargePages = 0x20000000 + } + + [Flags] + private enum MemoryProtection + { + NoAccess = 0x01, + ReadOnly = 0x02, + ReadWrite = 0x04, + WriteCopy = 0x08, + Execute = 0x10, + ExecuteRead = 0x20, + ExecuteReadWrite = 0x40, + ExecuteWriteCopy = 0x80, + GuardModifierflag = 0x100, + NoCacheModifierflag = 0x200, + WriteCombineModifierflag = 0x400 + } + + private enum WriteWatchFlags : uint + { + None = 0, + Reset = 1 + } + + [DllImport("kernel32.dll")] + private static extern IntPtr VirtualAlloc( + IntPtr lpAddress, + IntPtr dwSize, + AllocationType flAllocationType, + MemoryProtection flProtect); + + [DllImport("kernel32.dll")] + private static extern bool VirtualProtect( + IntPtr lpAddress, + IntPtr dwSize, + MemoryProtection flNewProtect, + out MemoryProtection lpflOldProtect); + + [DllImport("kernel32.dll")] + private static extern bool VirtualFree( + IntPtr lpAddress, + uint dwSize, + AllocationType dwFreeType); + + [DllImport("kernel32.dll")] + private static extern int GetWriteWatch( + WriteWatchFlags dwFlags, + IntPtr lpBaseAddress, + IntPtr dwRegionSize, + IntPtr[] lpAddresses, + ref ulong lpdwCount, + out uint lpdwGranularity); + + public static IntPtr Allocate(IntPtr size) + { + const AllocationType flags = + AllocationType.Reserve | + AllocationType.Commit; + + IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite); + + if (ptr == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + + return ptr; + } + + public static IntPtr AllocateWriteTracked(IntPtr size) + { + const AllocationType flags = + AllocationType.Reserve | + AllocationType.Commit | + AllocationType.WriteWatch; + + IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite); + + if (ptr == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + + return ptr; + } + + public static bool Reprotect(IntPtr address, IntPtr size, Memory.MemoryProtection protection) + { + MemoryProtection prot = GetProtection(protection); + + return VirtualProtect(address, size, prot, out _); + } + + private static MemoryProtection GetProtection(Memory.MemoryProtection protection) + { + switch (protection) + { + case Memory.MemoryProtection.None: return MemoryProtection.NoAccess; + case Memory.MemoryProtection.Read: return MemoryProtection.ReadOnly; + case Memory.MemoryProtection.ReadAndWrite: return MemoryProtection.ReadWrite; + case Memory.MemoryProtection.ReadAndExecute: return MemoryProtection.ExecuteRead; + case Memory.MemoryProtection.Execute: return MemoryProtection.Execute; + + default: throw new ArgumentException($"Invalid permission \"{protection}\"."); + } + } + + public static bool Free(IntPtr address) + { + return VirtualFree(address, 0, AllocationType.Release); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool GetModifiedPages( + IntPtr address, + IntPtr size, + IntPtr[] addresses, + out ulong count) + { + ulong pagesCount = (ulong)addresses.Length; + + int result = GetWriteWatch( + WriteWatchFlags.Reset, + address, + size, + addresses, + ref pagesCount, + out uint granularity); + + count = pagesCount; + + return result == 0; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryManager.cs b/ChocolArm64/Memory/MemoryManager.cs index 1f21256807..afb0f65143 100644 --- a/ChocolArm64/Memory/MemoryManager.cs +++ b/ChocolArm64/Memory/MemoryManager.cs @@ -1,16 +1,16 @@ using ChocolArm64.Events; using ChocolArm64.Exceptions; using ChocolArm64.Instructions; -using ChocolArm64.State; using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using System.Threading; +using static ChocolArm64.Memory.CompareExchange128; + namespace ChocolArm64.Memory { public unsafe class MemoryManager : IMemory, IDisposable @@ -30,21 +30,6 @@ namespace ChocolArm64.Memory private const int PtLvl0Bit = PageBits + PtLvl1Bits; private const int PtLvl1Bit = PageBits; - private const long ErgMask = (4 << CpuThreadState.ErgSizeLog2) - 1; - - private class ArmMonitor - { - public long Position; - public bool ExState; - - public bool HasExclusiveAccess(long position) - { - return Position == position && ExState; - } - } - - private Dictionary _monitors; - private ConcurrentDictionary _observedPages; public IntPtr Ram { get; private set; } @@ -59,8 +44,6 @@ namespace ChocolArm64.Memory public MemoryManager(IntPtr ram) { - _monitors = new Dictionary(); - _observedPages = new ConcurrentDictionary(); Ram = ram; @@ -75,104 +58,139 @@ namespace ChocolArm64.Memory } } - public void RemoveMonitor(int core) + internal bool AtomicCompareExchange2xInt32( + long position, + int expectedLow, + int expectedHigh, + int desiredLow, + int desiredHigh) { - lock (_monitors) - { - ClearExclusive(core); + long expected = (uint)expectedLow; + long desired = (uint)desiredLow; - _monitors.Remove(core); - } + expected |= (long)expectedHigh << 32; + desired |= (long)desiredHigh << 32; + + return AtomicCompareExchangeInt64(position, expected, desired); } - public void SetExclusive(int core, long position) + internal bool AtomicCompareExchangeInt128( + long position, + ulong expectedLow, + ulong expectedHigh, + ulong desiredLow, + ulong desiredHigh) { - position &= ~ErgMask; - - lock (_monitors) + if ((position & 0xf) != 0) { - foreach (ArmMonitor mon in _monitors.Values) - { - if (mon.Position == position && mon.ExState) - { - mon.ExState = false; - } - } - - if (!_monitors.TryGetValue(core, out ArmMonitor threadMon)) - { - threadMon = new ArmMonitor(); - - _monitors.Add(core, threadMon); - } - - threadMon.Position = position; - threadMon.ExState = true; + AbortWithAlignmentFault(position); } + + IntPtr ptr = new IntPtr(TranslateWrite(position)); + + return InterlockedCompareExchange128(ptr, expectedLow, expectedHigh, desiredLow, desiredHigh); } - public bool TestExclusive(int core, long position) + internal Vector128 AtomicReadInt128(long position) { - //Note: Any call to this method also should be followed by a - //call to ClearExclusiveForStore if this method returns true. - position &= ~ErgMask; - - Monitor.Enter(_monitors); - - if (!_monitors.TryGetValue(core, out ArmMonitor threadMon)) + if ((position & 0xf) != 0) { - Monitor.Exit(_monitors); - - return false; + AbortWithAlignmentFault(position); } - bool exState = threadMon.HasExclusiveAccess(position); + IntPtr ptr = new IntPtr(Translate(position)); - if (!exState) - { - Monitor.Exit(_monitors); - } + InterlockedRead128(ptr, out ulong low, out ulong high); - return exState; + Vector128 vector = default(Vector128); + + vector = VectorHelper.VectorInsertInt(low, vector, 0, 3); + vector = VectorHelper.VectorInsertInt(high, vector, 1, 3); + + return vector; } - public void ClearExclusiveForStore(int core) + public bool AtomicCompareExchangeByte(long position, byte expected, byte desired) { - if (_monitors.TryGetValue(core, out ArmMonitor threadMon)) - { - threadMon.ExState = false; - } + int* ptr = (int*)Translate(position); - Monitor.Exit(_monitors); + int currentValue = *ptr; + + int expected32 = (currentValue & ~byte.MaxValue) | expected; + int desired32 = (currentValue & ~byte.MaxValue) | desired; + + return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32; } - public void ClearExclusive(int core) + public bool AtomicCompareExchangeInt16(long position, short expected, short desired) { - lock (_monitors) + if ((position & 1) != 0) { - if (_monitors.TryGetValue(core, out ArmMonitor threadMon)) - { - threadMon.ExState = false; - } + AbortWithAlignmentFault(position); } + + int* ptr = (int*)Translate(position); + + int currentValue = *ptr; + + int expected32 = (currentValue & ~ushort.MaxValue) | (ushort)expected; + int desired32 = (currentValue & ~ushort.MaxValue) | (ushort)desired; + + return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32; } - public void WriteInt32ToSharedAddr(long position, int value) + public bool AtomicCompareExchangeInt32(long position, int expected, int desired) { - long maskedPosition = position & ~ErgMask; - - lock (_monitors) + if ((position & 3) != 0) { - foreach (ArmMonitor mon in _monitors.Values) - { - if (mon.Position == maskedPosition && mon.ExState) - { - mon.ExState = false; - } - } - - WriteInt32(position, value); + AbortWithAlignmentFault(position); } + + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; + } + + public bool AtomicCompareExchangeInt64(long position, long expected, long desired) + { + if ((position & 7) != 0) + { + AbortWithAlignmentFault(position); + } + + long* ptr = (long*)TranslateWrite(position); + + return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; + } + + public int AtomicIncrementInt32(long position) + { + if ((position & 3) != 0) + { + AbortWithAlignmentFault(position); + } + + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.Increment(ref *ptr); + } + + public int AtomicDecrementInt32(long position) + { + if ((position & 3) != 0) + { + AbortWithAlignmentFault(position); + } + + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.Decrement(ref *ptr); + } + + private void AbortWithAlignmentFault(long position) + { + //TODO: Abort mode and exception support on the CPU. + throw new InvalidOperationException($"Tried to compare exchange a misaligned address 0x{position:X16}."); } public sbyte ReadSByte(long position) diff --git a/ChocolArm64/Memory/MemoryProtection.cs b/ChocolArm64/Memory/MemoryProtection.cs new file mode 100644 index 0000000000..d0874bfc0f --- /dev/null +++ b/ChocolArm64/Memory/MemoryProtection.cs @@ -0,0 +1,16 @@ +using System; + +namespace ChocolArm64.Memory +{ + [Flags] + public enum MemoryProtection + { + None = 0, + Read = 1 << 0, + Write = 1 << 1, + Execute = 1 << 2, + + ReadAndWrite = Read | Write, + ReadAndExecute = Read | Execute + } +} \ No newline at end of file diff --git a/ChocolArm64/Memory/MemoryProtectionException.cs b/ChocolArm64/Memory/MemoryProtectionException.cs new file mode 100644 index 0000000000..3d2cebad33 --- /dev/null +++ b/ChocolArm64/Memory/MemoryProtectionException.cs @@ -0,0 +1,10 @@ +using System; + +namespace ChocolArm64.Memory +{ + class MemoryProtectionException : Exception + { + public MemoryProtectionException(MemoryProtection protection) : + base($"Failed to set memory protection to \"{protection}\".") { } + } +} \ No newline at end of file diff --git a/ChocolArm64/State/CpuThreadState.cs b/ChocolArm64/State/CpuThreadState.cs index abec60bb2e..caf73deb1f 100644 --- a/ChocolArm64/State/CpuThreadState.cs +++ b/ChocolArm64/State/CpuThreadState.cs @@ -37,7 +37,6 @@ namespace ChocolArm64.State public int ElrHyp; public bool Running { get; set; } - public int Core { get; set; } private bool _interrupted; @@ -85,6 +84,16 @@ namespace ChocolArm64.State internal Translator CurrentTranslator; + private ulong _exclusiveAddress; + + internal ulong ExclusiveValueLow { get; set; } + internal ulong ExclusiveValueHigh { get; set; } + + public CpuThreadState() + { + ClearExclusiveAddress(); + } + static CpuThreadState() { _hostTickFreq = 1.0 / Stopwatch.Frequency; @@ -94,6 +103,26 @@ namespace ChocolArm64.State _tickCounter.Start(); } + internal void SetExclusiveAddress(ulong address) + { + _exclusiveAddress = GetMaskedExclusiveAddress(address); + } + + internal bool CheckExclusiveAddress(ulong address) + { + return GetMaskedExclusiveAddress(address) == _exclusiveAddress; + } + + internal void ClearExclusiveAddress() + { + _exclusiveAddress = ulong.MaxValue; + } + + private ulong GetMaskedExclusiveAddress(ulong address) + { + return address & ~((4UL << ErgSizeLog2) - 1); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal bool Synchronize(int bbWeight) { diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs index fa65bbf989..5490123774 100644 --- a/ChocolArm64/Translation/ILEmitterCtx.cs +++ b/ChocolArm64/Translation/ILEmitterCtx.cs @@ -49,6 +49,7 @@ namespace ChocolArm64.Translation private const int CmpOptTmp2Index = -4; private const int VecTmp1Index = -5; private const int VecTmp2Index = -6; + private const int IntTmp2Index = -7; public ILEmitterCtx(TranslatorCache cache, TranslatorQueue queue, TranslationTier tier, Block graph) { @@ -562,6 +563,9 @@ namespace ChocolArm64.Translation public void EmitLdtmp() => EmitLdint(IntTmpIndex); public void EmitSttmp() => EmitStint(IntTmpIndex); + public void EmitLdtmp2() => EmitLdint(IntTmp2Index); + public void EmitSttmp2() => EmitStint(IntTmp2Index); + public void EmitLdvectmp() => EmitLdvec(VecTmp1Index); public void EmitStvectmp() => EmitStvec(VecTmp1Index); @@ -635,6 +639,36 @@ namespace ChocolArm64.Translation EmitCall(objType.GetMethod($"set_{propName}")); } + public void EmitCallPrivatePropGet(Type objType, string propName) + { + if (objType == null) + { + throw new ArgumentNullException(nameof(objType)); + } + + if (propName == null) + { + throw new ArgumentNullException(nameof(propName)); + } + + EmitPrivateCall(objType, $"get_{propName}"); + } + + public void EmitCallPrivatePropSet(Type objType, string propName) + { + if (objType == null) + { + throw new ArgumentNullException(nameof(objType)); + } + + if (propName == null) + { + throw new ArgumentNullException(nameof(propName)); + } + + EmitPrivateCall(objType, $"set_{propName}"); + } + public void EmitCall(Type objType, string mthdName) { if (objType == null) diff --git a/Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs b/Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs index 2b7591406f..0fcb31483a 100644 --- a/Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs +++ b/Ryujinx.HLE/HOS/Kernel/Common/KernelTransfer.cs @@ -66,7 +66,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common if (currentProcess.CpuMemory.IsMapped((long)address) && currentProcess.CpuMemory.IsMapped((long)address + 3)) { - currentProcess.CpuMemory.WriteInt32ToSharedAddr((long)address, value); + currentProcess.CpuMemory.WriteInt32((long)address, value); return true; } diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/HleScheduler.cs b/Ryujinx.HLE/HOS/Kernel/Threading/HleScheduler.cs index 835c2a2f83..d5dbb4d8e4 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/HleScheduler.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/HleScheduler.cs @@ -92,8 +92,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading if (coreContext.CurrentThread != null) { - coreContext.CurrentThread.ClearExclusive(); - CoreManager.Set(coreContext.CurrentThread.Context.Work); coreContext.CurrentThread.Context.Execute(); diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs index faeea5c54b..b11df61ed9 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KAddressArbiter.cs @@ -228,43 +228,31 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); - currentProcess.CpuMemory.SetExclusive(0, (long)address); + int mutexValue, newMutexValue; - if (!KernelTransfer.UserToKernelInt32(_system, address, out int mutexValue)) + do { - //Invalid address. - currentProcess.CpuMemory.ClearExclusive(0); - - requester.SignaledObj = null; - requester.ObjSyncResult = KernelResult.InvalidMemState; - - return null; - } - - while (true) - { - if (currentProcess.CpuMemory.TestExclusive(0, (long)address)) + if (!KernelTransfer.UserToKernelInt32(_system, address, out mutexValue)) { - if (mutexValue != 0) - { - //Update value to indicate there is a mutex waiter now. - currentProcess.CpuMemory.WriteInt32((long)address, mutexValue | HasListenersMask); - } - else - { - //No thread owning the mutex, assign to requesting thread. - currentProcess.CpuMemory.WriteInt32((long)address, requester.ThreadHandleForUserMutex); - } + //Invalid address. + requester.SignaledObj = null; + requester.ObjSyncResult = KernelResult.InvalidMemState; - currentProcess.CpuMemory.ClearExclusiveForStore(0); - - break; + return null; } - currentProcess.CpuMemory.SetExclusive(0, (long)address); - - mutexValue = currentProcess.CpuMemory.ReadInt32((long)address); + if (mutexValue != 0) + { + //Update value to indicate there is a mutex waiter now. + newMutexValue = mutexValue | HasListenersMask; + } + else + { + //No thread owning the mutex, assign to requesting thread. + newMutexValue = requester.ThreadHandleForUserMutex; + } } + while (!currentProcess.CpuMemory.AtomicCompareExchangeInt32((long)address, mutexValue, newMutexValue)); if (mutexValue == 0) { @@ -392,9 +380,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); - //If ShouldDecrement is true, do atomic decrement of the value at Address. - currentProcess.CpuMemory.SetExclusive(0, (long)address); - if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) { _system.CriticalSection.Leave(); @@ -404,25 +389,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading if (shouldDecrement) { - while (currentValue < value) - { - if (currentProcess.CpuMemory.TestExclusive(0, (long)address)) - { - currentProcess.CpuMemory.WriteInt32((long)address, currentValue - 1); - - currentProcess.CpuMemory.ClearExclusiveForStore(0); - - break; - } - - currentProcess.CpuMemory.SetExclusive(0, (long)address); - - currentValue = currentProcess.CpuMemory.ReadInt32((long)address); - } + currentValue = currentProcess.CpuMemory.AtomicDecrementInt32((long)address) + 1; } - currentProcess.CpuMemory.ClearExclusive(0); - if (currentValue < value) { if (timeout == 0) @@ -511,39 +480,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); - currentProcess.CpuMemory.SetExclusive(0, (long)address); + int currentValue; - if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) + do { - _system.CriticalSection.Leave(); - - return KernelResult.InvalidMemState; - } - - while (currentValue == value) - { - if (currentProcess.CpuMemory.TestExclusive(0, (long)address)) + if (!KernelTransfer.UserToKernelInt32(_system, address, out currentValue)) { - currentProcess.CpuMemory.WriteInt32((long)address, currentValue + 1); + _system.CriticalSection.Leave(); - currentProcess.CpuMemory.ClearExclusiveForStore(0); - - break; + return KernelResult.InvalidMemState; } - currentProcess.CpuMemory.SetExclusive(0, (long)address); + if (currentValue != value) + { + _system.CriticalSection.Leave(); - currentValue = currentProcess.CpuMemory.ReadInt32((long)address); - } - - currentProcess.CpuMemory.ClearExclusive(0); - - if (currentValue != value) - { - _system.CriticalSection.Leave(); - - return KernelResult.InvalidState; + return KernelResult.InvalidState; + } } + while (!currentProcess.CpuMemory.AtomicCompareExchangeInt32((long)address, currentValue, currentValue + 1)); WakeArbiterThreads(address, count); @@ -582,39 +537,25 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading KProcess currentProcess = _system.Scheduler.GetCurrentProcess(); - currentProcess.CpuMemory.SetExclusive(0, (long)address); + int currentValue; - if (!KernelTransfer.UserToKernelInt32(_system, address, out int currentValue)) + do { - _system.CriticalSection.Leave(); - - return KernelResult.InvalidMemState; - } - - while (currentValue == value) - { - if (currentProcess.CpuMemory.TestExclusive(0, (long)address)) + if (!KernelTransfer.UserToKernelInt32(_system, address, out currentValue)) { - currentProcess.CpuMemory.WriteInt32((long)address, currentValue + offset); + _system.CriticalSection.Leave(); - currentProcess.CpuMemory.ClearExclusiveForStore(0); - - break; + return KernelResult.InvalidMemState; } - currentProcess.CpuMemory.SetExclusive(0, (long)address); + if (currentValue != value) + { + _system.CriticalSection.Leave(); - currentValue = currentProcess.CpuMemory.ReadInt32((long)address); - } - - currentProcess.CpuMemory.ClearExclusive(0); - - if (currentValue != value) - { - _system.CriticalSection.Leave(); - - return KernelResult.InvalidState; + return KernelResult.InvalidState; + } } + while (!currentProcess.CpuMemory.AtomicCompareExchangeInt32((long)address, currentValue, currentValue + offset)); WakeArbiterThreads(address, count); diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KCoreContext.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KCoreContext.cs index 81cd88834f..9790717729 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KCoreContext.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KCoreContext.cs @@ -70,8 +70,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading CurrentThread.TotalTimeRunning += currentTime - CurrentThread.LastScheduledTime; CurrentThread.LastScheduledTime = currentTime; - CurrentThread.ClearExclusive(); - _coreManager.Set(CurrentThread.Context.Work); CurrentThread.Context.Execute(); diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs index 7eb27efc12..17e0f3c3bf 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs @@ -1004,11 +1004,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading Context.ThreadState.X1 = (ulong)threadHandle; } - public void ClearExclusive() - { - Owner.CpuMemory.ClearExclusive(CurrentCore); - } - public void TimeUp() { ReleaseAndResume(); diff --git a/Ryujinx/Config.jsonc b/Ryujinx/Config.jsonc index 1ba601647a..8b5ebe0328 100644 --- a/Ryujinx/Config.jsonc +++ b/Ryujinx/Config.jsonc @@ -36,7 +36,7 @@ "enable_vsync": true, // Enable or Disable Multi-core scheduling of threads - "enable_multicore_scheduling": false, + "enable_multicore_scheduling": true, // Enable integrity checks on Switch content files "enable_fs_integrity_checks": true, diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json index 28f3511181..0e586671d6 100644 --- a/Ryujinx/_schema.json +++ b/Ryujinx/_schema.json @@ -382,7 +382,7 @@ "type": "boolean", "title": "Enable Multicore Scheduling", "description": "Enables or disables multi-core scheduling of threads", - "default": false, + "default": true, "examples": [ true, false From 6335753e382eec1cf9037545851f1de2459b94cc Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 18 Feb 2019 21:12:53 -0300 Subject: [PATCH 07/36] Implement ConvertScalingMode properly (#596) * Implement ConvertScalingMode properly * Fix up the naming * Only values 2 and 4 are allowed * Return a nullable enum from ConvetScalingMode * Fix typo on method name * Use convertedScalingMode --- .../Services/Vi/IApplicationDisplayService.cs | 21 +++++++++++++----- Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs | 22 ++++++++----------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs index b272e0788d..48cf328806 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/IApplicationDisplayService.cs @@ -180,22 +180,31 @@ namespace Ryujinx.HLE.HOS.Services.Vi public long ConvertScalingMode(ServiceCtx context) { - SrcScalingMode scalingMode = (SrcScalingMode)context.RequestData.ReadInt32(); - DstScalingMode? destScalingMode = ConvetScalingModeImpl(scalingMode); + SrcScalingMode scalingMode = (SrcScalingMode)context.RequestData.ReadInt32(); - if (!destScalingMode.HasValue) + DstScalingMode? convertedScalingMode = ConvertScalingMode(scalingMode); + + if (!convertedScalingMode.HasValue) { + //Scaling mode out of the range of valid values. return MakeError(ErrorModule.Vi, 1); } - context.ResponseData.Write((ulong)destScalingMode); + if (scalingMode != SrcScalingMode.ScaleToWindow && + scalingMode != SrcScalingMode.PreserveAspectRatio) + { + //Invalid scaling mode specified. + return MakeError(ErrorModule.Vi, 6); + } + + context.ResponseData.Write((ulong)convertedScalingMode); return 0; } - private DstScalingMode? ConvetScalingModeImpl(SrcScalingMode srcScalingMode) + private DstScalingMode? ConvertScalingMode(SrcScalingMode source) { - switch (srcScalingMode) + switch (source) { case SrcScalingMode.None: return DstScalingMode.None; case SrcScalingMode.Freeze: return DstScalingMode.Freeze; diff --git a/Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs b/Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs index 824a27b70a..7b555b5999 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/ScalingMode.cs @@ -1,24 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Vi +namespace Ryujinx.HLE.HOS.Services.Vi { enum SrcScalingMode { - Freeze = 0, - ScaleToWindow = 1, - ScaleAndCrop = 2, - None = 3, + None = 0, + Freeze = 1, + ScaleToWindow = 2, + ScaleAndCrop = 3, PreserveAspectRatio = 4 } enum DstScalingMode { - None = 0, - Freeze = 1, - ScaleToWindow = 2, - ScaleAndCrop = 3, + Freeze = 0, + ScaleToWindow = 1, + ScaleAndCrop = 2, + None = 3, PreserveAspectRatio = 4 } } From 7ed2b4cc39ca286a03589cd3768a419c5ed9941f Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 22 Feb 2019 02:14:02 -0300 Subject: [PATCH 08/36] Initialize FrontFace register with a default value (#601) --- Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs index 1ca3ca1ce1..6120053dae 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs @@ -66,6 +66,8 @@ namespace Ryujinx.Graphics.Graphics3d WriteRegister(NvGpuEngine3dReg.FrameBufferSrgb, 1); + WriteRegister(NvGpuEngine3dReg.FrontFace, (int)GalFrontFace.CW); + for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) { WriteRegister(NvGpuEngine3dReg.IBlendNEquationRgb + Index * 8, (int)GalBlendEquation.FuncAdd); From 9679896b9471afdebf860c016d3fd360b9af7f80 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sat, 23 Feb 2019 20:52:48 -0300 Subject: [PATCH 09/36] Implement fixed-point variant of the UCVTF and SCVTF instructions (#578) * Add fixed-point variant of the UCVTF instruction * Change encoding of some fixed-point instructions to not allow invalid encodings * Fix Fcvtzu_Gp_Fixed encoding * Add SCVTF (fixed-point GP to Scalar) instruction * Simplify *Fixed encodings --- ChocolArm64/Decoders/OpCodeSimdCvt64.cs | 9 -- ChocolArm64/Instructions/InstEmitSimdCvt.cs | 108 +++++++++++++------- ChocolArm64/OpCodeTable.cs | 6 +- 3 files changed, 76 insertions(+), 47 deletions(-) diff --git a/ChocolArm64/Decoders/OpCodeSimdCvt64.cs b/ChocolArm64/Decoders/OpCodeSimdCvt64.cs index eacd594099..3181a85a34 100644 --- a/ChocolArm64/Decoders/OpCodeSimdCvt64.cs +++ b/ChocolArm64/Decoders/OpCodeSimdCvt64.cs @@ -8,18 +8,9 @@ namespace ChocolArm64.Decoders public OpCodeSimdCvt64(Inst inst, long position, int opCode) : base(inst, position, opCode) { - //TODO: - //Und of Fixed Point variants. int scale = (opCode >> 10) & 0x3f; int sf = (opCode >> 31) & 0x1; - /*if (Type != SF && !(Type == 2 && SF == 1)) - { - Emitter = AInstEmit.Und; - - return; - }*/ - FBits = 64 - scale; RegisterSize = sf != 0 diff --git a/ChocolArm64/Instructions/InstEmitSimdCvt.cs b/ChocolArm64/Instructions/InstEmitSimdCvt.cs index 2eac3194d6..11105d891f 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCvt.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCvt.cs @@ -244,7 +244,7 @@ namespace ChocolArm64.Instructions public static void Fcvtzs_Gp_Fixed(ILEmitterCtx context) { - EmitFcvtzs_Gp_Fix(context); + EmitFcvtzs_Gp_Fixed(context); } public static void Fcvtzs_S(ILEmitterCtx context) @@ -264,7 +264,7 @@ namespace ChocolArm64.Instructions public static void Fcvtzu_Gp_Fixed(ILEmitterCtx context) { - EmitFcvtzu_Gp_Fix(context); + EmitFcvtzu_Gp_Fixed(context); } public static void Fcvtzu_S(ILEmitterCtx context) @@ -293,6 +293,24 @@ namespace ChocolArm64.Instructions EmitScalarSetF(context, op.Rd, op.Size); } + public static void Scvtf_Gp_Fixed(ILEmitterCtx context) + { + OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; + + context.EmitLdintzr(op.Rn); + + if (context.CurrOp.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Conv_I4); + } + + EmitFloatCast(context, op.Size); + + EmitI2fFBitsMul(context, op.Size, op.FBits); + + EmitScalarSetF(context, op.Rd, op.Size); + } + public static void Scvtf_S(ILEmitterCtx context) { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; @@ -349,6 +367,26 @@ namespace ChocolArm64.Instructions EmitScalarSetF(context, op.Rd, op.Size); } + public static void Ucvtf_Gp_Fixed(ILEmitterCtx context) + { + OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; + + context.EmitLdintzr(op.Rn); + + if (context.CurrOp.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Conv_U4); + } + + context.Emit(OpCodes.Conv_R_Un); + + EmitFloatCast(context, op.Size); + + EmitI2fFBitsMul(context, op.Size, op.FBits); + + EmitScalarSetF(context, op.Rd, op.Size); + } + public static void Ucvtf_S(ILEmitterCtx context) { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; @@ -367,32 +405,6 @@ namespace ChocolArm64.Instructions EmitVectorCvtf(context, signed: false); } - private static int GetFBits(ILEmitterCtx context) - { - if (context.CurrOp is OpCodeSimdShImm64 op) - { - return GetImmShr(op); - } - - return 0; - } - - private static void EmitFloatCast(ILEmitterCtx context, int size) - { - if (size == 0) - { - context.Emit(OpCodes.Conv_R4); - } - else if (size == 1) - { - context.Emit(OpCodes.Conv_R8); - } - else - { - throw new ArgumentOutOfRangeException(nameof(size)); - } - } - private static void EmitFcvtn(ILEmitterCtx context, bool signed, bool scalar) { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; @@ -476,17 +488,17 @@ namespace ChocolArm64.Instructions context.EmitStintzr(op.Rd); } - private static void EmitFcvtzs_Gp_Fix(ILEmitterCtx context) + private static void EmitFcvtzs_Gp_Fixed(ILEmitterCtx context) { - EmitFcvtz__Gp_Fix(context, true); + EmitFcvtz__Gp_Fixed(context, true); } - private static void EmitFcvtzu_Gp_Fix(ILEmitterCtx context) + private static void EmitFcvtzu_Gp_Fixed(ILEmitterCtx context) { - EmitFcvtz__Gp_Fix(context, false); + EmitFcvtz__Gp_Fixed(context, false); } - private static void EmitFcvtz__Gp_Fix(ILEmitterCtx context, bool signed) + private static void EmitFcvtz__Gp_Fixed(ILEmitterCtx context, bool signed) { OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; @@ -530,9 +542,7 @@ namespace ChocolArm64.Instructions context.Emit(OpCodes.Conv_R_Un); } - context.Emit(sizeF == 0 - ? OpCodes.Conv_R4 - : OpCodes.Conv_R8); + EmitFloatCast(context, sizeF); EmitI2fFBitsMul(context, sizeF, fBits); @@ -644,6 +654,32 @@ namespace ChocolArm64.Instructions } } + private static int GetFBits(ILEmitterCtx context) + { + if (context.CurrOp is OpCodeSimdShImm64 op) + { + return GetImmShr(op); + } + + return 0; + } + + private static void EmitFloatCast(ILEmitterCtx context, int size) + { + if (size == 0) + { + context.Emit(OpCodes.Conv_R4); + } + else if (size == 1) + { + context.Emit(OpCodes.Conv_R8); + } + else + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + } + private static void EmitScalarFcvts(ILEmitterCtx context, int size, int fBits) { if (size < 0 || size > 1) diff --git a/ChocolArm64/OpCodeTable.cs b/ChocolArm64/OpCodeTable.cs index 3a8d3948d8..9fdda87b42 100644 --- a/ChocolArm64/OpCodeTable.cs +++ b/ChocolArm64/OpCodeTable.cs @@ -310,12 +310,12 @@ namespace ChocolArm64 SetA64("x00111100x101000000000xxxxxxxxxx", InstEmit.Fcvtps_Gp, typeof(OpCodeSimdCvt64)); SetA64("x00111100x101001000000xxxxxxxxxx", InstEmit.Fcvtpu_Gp, typeof(OpCodeSimdCvt64)); SetA64("x00111100x111000000000xxxxxxxxxx", InstEmit.Fcvtzs_Gp, typeof(OpCodeSimdCvt64)); - SetA64("x00111100x011000xxxxxxxxxxxxxxxx", InstEmit.Fcvtzs_Gp_Fixed, typeof(OpCodeSimdCvt64)); + SetA64(">00111100x011000>xxxxxxxxxxxxxxx", InstEmit.Fcvtzs_Gp_Fixed, typeof(OpCodeSimdCvt64)); SetA64("010111101x100001101110xxxxxxxxxx", InstEmit.Fcvtzs_S, typeof(OpCodeSimd64)); SetA64("0>0011101<100001101110xxxxxxxxxx", InstEmit.Fcvtzs_V, typeof(OpCodeSimd64)); SetA64("0x0011110>>xxxxx111111xxxxxxxxxx", InstEmit.Fcvtzs_V, typeof(OpCodeSimdShImm64)); SetA64("x00111100x111001000000xxxxxxxxxx", InstEmit.Fcvtzu_Gp, typeof(OpCodeSimdCvt64)); - SetA64("x00111100x011001xxxxxxxxxxxxxxxx", InstEmit.Fcvtzu_Gp_Fixed, typeof(OpCodeSimdCvt64)); + SetA64(">00111100x011001>xxxxxxxxxxxxxxx", InstEmit.Fcvtzu_Gp_Fixed, typeof(OpCodeSimdCvt64)); SetA64("011111101x100001101110xxxxxxxxxx", InstEmit.Fcvtzu_S, typeof(OpCodeSimd64)); SetA64("0>1011101<100001101110xxxxxxxxxx", InstEmit.Fcvtzu_V, typeof(OpCodeSimd64)); SetA64("0x1011110>>xxxxx111111xxxxxxxxxx", InstEmit.Fcvtzu_V, typeof(OpCodeSimdShImm64)); @@ -434,6 +434,7 @@ namespace ChocolArm64 SetA64("0x001110<<100000001010xxxxxxxxxx", InstEmit.Saddlp_V, typeof(OpCodeSimd64)); SetA64("0x001110<<1xxxxx000100xxxxxxxxxx", InstEmit.Saddw_V, typeof(OpCodeSimdReg64)); SetA64("x00111100x100010000000xxxxxxxxxx", InstEmit.Scvtf_Gp, typeof(OpCodeSimdCvt64)); + SetA64(">00111100x000010>xxxxxxxxxxxxxxx", InstEmit.Scvtf_Gp_Fixed, typeof(OpCodeSimdCvt64)); SetA64("010111100x100001110110xxxxxxxxxx", InstEmit.Scvtf_S, typeof(OpCodeSimd64)); SetA64("0>0011100<100001110110xxxxxxxxxx", InstEmit.Scvtf_V, typeof(OpCodeSimd64)); SetA64("01011110000xxxxx000000xxxxxxxxxx", InstEmit.Sha1c_V, typeof(OpCodeSimdReg64)); @@ -542,6 +543,7 @@ namespace ChocolArm64 SetA64("01101110<<110000001110xxxxxxxxxx", InstEmit.Uaddlv_V, typeof(OpCodeSimd64)); SetA64("0x101110<<1xxxxx000100xxxxxxxxxx", InstEmit.Uaddw_V, typeof(OpCodeSimdReg64)); SetA64("x00111100x100011000000xxxxxxxxxx", InstEmit.Ucvtf_Gp, typeof(OpCodeSimdCvt64)); + SetA64(">00111100x000011>xxxxxxxxxxxxxxx", InstEmit.Ucvtf_Gp_Fixed, typeof(OpCodeSimdCvt64)); SetA64("011111100x100001110110xxxxxxxxxx", InstEmit.Ucvtf_S, typeof(OpCodeSimd64)); SetA64("0>1011100<100001110110xxxxxxxxxx", InstEmit.Ucvtf_V, typeof(OpCodeSimd64)); SetA64("0x101110<<1xxxxx000001xxxxxxxxxx", InstEmit.Uhadd_V, typeof(OpCodeSimdReg64)); From a3d46e41335efd049042cc2e38b35c4077e8ed41 Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Sun, 24 Feb 2019 00:53:27 +0100 Subject: [PATCH 10/36] Add Tests for instructions Fcvtzs_Gp_Fixed & Fcvtzu_Gp_Fixed, Scvtf_Gp_Fixed & Ucvtf_Gp_Fixed. (#603) * Create CpuTestSimdCvt.cs * Update CpuTestMisc.cs * Update CpuTestSimdCvt.cs --- Ryujinx.Tests/Cpu/CpuTestMisc.cs | 4 +- Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs | 360 ++++++++++++++++++++++++++++ 2 files changed, 362 insertions(+), 2 deletions(-) create mode 100644 Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs diff --git a/Ryujinx.Tests/Cpu/CpuTestMisc.cs b/Ryujinx.Tests/Cpu/CpuTestMisc.cs index 89ea47a920..e976c2c00a 100644 --- a/Ryujinx.Tests/Cpu/CpuTestMisc.cs +++ b/Ryujinx.Tests/Cpu/CpuTestMisc.cs @@ -12,8 +12,8 @@ namespace Ryujinx.Tests.Cpu public sealed class CpuTestMisc : CpuTest { #if Misc - private const int RndCnt = 2; - private const int RndCntImm = 2; + private const int RndCnt = 2; + private const int RndCntImm = 2; #region "AluImm & Csel" [Test, Pairwise] diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs new file mode 100644 index 0000000000..ecf90b0aa7 --- /dev/null +++ b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs @@ -0,0 +1,360 @@ +#define SimdCvt + +using NUnit.Framework; + +using System.Collections.Generic; +using System.Runtime.Intrinsics; + +namespace Ryujinx.Tests.Cpu +{ + [Category("SimdCvt")] + public sealed class CpuTestSimdCvt : CpuTest + { +#if SimdCvt + +#region "ValueSource (Types)" + private static IEnumerable _1S_F_() + { + yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue) + yield return 0x0000000080800000ul; // -Min Normal + yield return 0x00000000807FFFFFul; // -Max Subnormal + yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon) + yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue) + yield return 0x0000000000800000ul; // +Min Normal + yield return 0x00000000007FFFFFul; // +Max Subnormal + yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon) + + if (!NoZeros) + { + yield return 0x0000000080000000ul; // -Zero + yield return 0x0000000000000000ul; // +Zero + } + + if (!NoInfs) + { + yield return 0x00000000FF800000ul; // -Infinity + yield return 0x000000007F800000ul; // +Infinity + } + + if (!NoNaNs) + { + yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN) + yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload) + yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN) + yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload) + } + + for (int cnt = 1; cnt <= RndCnt; cnt++) + { + ulong grbg = TestContext.CurrentContext.Random.NextUInt(); + ulong rnd1 = GenNormalS(); + ulong rnd2 = GenSubnormalS(); + + yield return (grbg << 32) | rnd1; + yield return (grbg << 32) | rnd2; + } + } + + private static IEnumerable _1D_F_() + { + yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) + yield return 0x8010000000000000ul; // -Min Normal + yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal + yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon) + yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue) + yield return 0x0010000000000000ul; // +Min Normal + yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal + yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon) + + if (!NoZeros) + { + yield return 0x8000000000000000ul; // -Zero + yield return 0x0000000000000000ul; // +Zero + } + + if (!NoInfs) + { + yield return 0xFFF0000000000000ul; // -Infinity + yield return 0x7FF0000000000000ul; // +Infinity + } + + if (!NoNaNs) + { + yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN) + yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload) + yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN) + yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload) + } + + for (int cnt = 1; cnt <= RndCnt; cnt++) + { + ulong rnd1 = GenNormalD(); + ulong rnd2 = GenSubnormalD(); + + yield return rnd1; + yield return rnd2; + } + } + + private static uint[] _W_() + { + return new uint[] { 0x00000000u, 0x7FFFFFFFu, + 0x80000000u, 0xFFFFFFFFu }; + } + + private static ulong[] _X_() + { + return new ulong[] { 0x0000000000000000ul, 0x7FFFFFFFFFFFFFFFul, + 0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul }; + } +#endregion + +#region "ValueSource (Opcodes)" + private static uint[] _F_Cvt_Z_SU_S_SW_() + { + return new uint[] + { + 0x1E188000u, // FCVTZS W0, S0, #32 + 0x1E198000u // FCVTZU W0, S0, #32 + }; + } + + private static uint[] _F_Cvt_Z_SU_S_SX_() + { + return new uint[] + { + 0x9E180000u, // FCVTZS X0, S0, #64 + 0x9E190000u // FCVTZU X0, S0, #64 + }; + } + + private static uint[] _F_Cvt_Z_SU_S_DW_() + { + return new uint[] + { + 0x1E588000u, // FCVTZS W0, D0, #32 + 0x1E598000u // FCVTZU W0, D0, #32 + }; + } + + private static uint[] _F_Cvt_Z_SU_S_DX_() + { + return new uint[] + { + 0x9E580000u, // FCVTZS X0, D0, #64 + 0x9E590000u // FCVTZU X0, D0, #64 + }; + } + + private static uint[] _SU_Cvt_F_S_WS_() + { + return new uint[] + { + 0x1E028000u, // SCVTF S0, W0, #32 + 0x1E038000u // UCVTF S0, W0, #32 + }; + } + + private static uint[] _SU_Cvt_F_S_WD_() + { + return new uint[] + { + 0x1E428000u, // SCVTF D0, W0, #32 + 0x1E438000u // UCVTF D0, W0, #32 + }; + } + + private static uint[] _SU_Cvt_F_S_XS_() + { + return new uint[] + { + 0x9E020000u, // SCVTF S0, X0, #64 + 0x9E030000u // UCVTF S0, X0, #64 + }; + } + + private static uint[] _SU_Cvt_F_S_XD_() + { + return new uint[] + { + 0x9E420000u, // SCVTF D0, X0, #64 + 0x9E430000u // UCVTF D0, X0, #64 + }; + } +#endregion + + private const int RndCnt = 2; + private const int RndCntFbits = 2; + + private static readonly bool NoZeros = false; + private static readonly bool NoInfs = false; + private static readonly bool NoNaNs = false; + + [Test, Pairwise] [Explicit] + public void F_Cvt_Z_SU_S_SW([ValueSource("_F_Cvt_Z_SU_S_SW_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1S_F_")] ulong a, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFbits)] uint fbits) + { + uint scale = (64u - fbits) & 0x3Fu; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (scale << 10); + + ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; + uint w31 = TestContext.CurrentContext.Random.NextUInt(); + Vector128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void F_Cvt_Z_SU_S_SX([ValueSource("_F_Cvt_Z_SU_S_SX_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1S_F_")] ulong a, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFbits)] uint fbits) + { + uint scale = (64u - fbits) & 0x3Fu; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (scale << 10); + + ulong x31 = TestContext.CurrentContext.Random.NextULong(); + Vector128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, x31: x31, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void F_Cvt_Z_SU_S_DW([ValueSource("_F_Cvt_Z_SU_S_DW_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1D_F_")] ulong a, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFbits)] uint fbits) + { + uint scale = (64u - fbits) & 0x3Fu; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (scale << 10); + + ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; + uint w31 = TestContext.CurrentContext.Random.NextUInt(); + Vector128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void F_Cvt_Z_SU_S_DX([ValueSource("_F_Cvt_Z_SU_S_DX_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1D_F_")] ulong a, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFbits)] uint fbits) + { + uint scale = (64u - fbits) & 0x3Fu; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (scale << 10); + + ulong x31 = TestContext.CurrentContext.Random.NextULong(); + Vector128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, x31: x31, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_S_WS([ValueSource("_SU_Cvt_F_S_WS_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_W_")] [Random(RndCnt)] uint wn, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFbits)] uint fbits) + { + uint scale = (64u - fbits) & 0x3Fu; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (scale << 10); + + uint w31 = TestContext.CurrentContext.Random.NextUInt(); + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE0E1(z, z); + + SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_S_WD([ValueSource("_SU_Cvt_F_S_WD_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_W_")] [Random(RndCnt)] uint wn, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFbits)] uint fbits) + { + uint scale = (64u - fbits) & 0x3Fu; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (scale << 10); + + uint w31 = TestContext.CurrentContext.Random.NextUInt(); + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(z); + + SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_S_XS([ValueSource("_SU_Cvt_F_S_XS_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_X_")] [Random(RndCnt)] ulong xn, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFbits)] uint fbits) + { + uint scale = (64u - fbits) & 0x3Fu; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (scale << 10); + + ulong x31 = TestContext.CurrentContext.Random.NextULong(); + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE0E1(z, z); + + SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_S_XD([ValueSource("_SU_Cvt_F_S_XD_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_X_")] [Random(RndCnt)] ulong xn, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFbits)] uint fbits) + { + uint scale = (64u - fbits) & 0x3Fu; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (scale << 10); + + ulong x31 = TestContext.CurrentContext.Random.NextULong(); + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(z); + + SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0); + + CompareAgainstUnicorn(); + } +#endif + } +} From 5001f78b1d07b988709dd5f5d1009ebe9b44c669 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Sun, 24 Feb 2019 04:24:35 -0300 Subject: [PATCH 11/36] Optimize address translation and write tracking on the MMU (#571) * Implement faster address translation and write tracking on the MMU * Rename MemoryAlloc to MemoryManagement, and other nits * Support multi-level page tables * Fix typo * Reword comment a bit * Support scalar vector loads/stores on the memory fast path, and minor fixes * Add missing cast * Alignment * Fix VirtualFree function signature * Change MemoryProtection enum to uint aswell for consistency --- ChocolArm64/Events/InvalidAccessEventArgs.cs | 14 - .../Exceptions/VmmPageFaultException.cs | 13 - ChocolArm64/Instructions/InstEmitMemory.cs | 11 - ChocolArm64/Instructions/InstEmitMemory32.cs | 6 - ChocolArm64/Instructions/InstEmitMemoryEx.cs | 22 +- .../Instructions/InstEmitMemoryHelper.cs | 419 ++++++++++- .../Instructions/InstEmitSimdMemory.cs | 3 - ChocolArm64/Instructions/InstEmitSystem.cs | 1 - ChocolArm64/Memory/CompareExchange128.cs | 6 +- .../{MemoryAlloc.cs => MemoryManagement.cs} | 20 +- ...ryAllocUnix.cs => MemoryManagementUnix.cs} | 2 +- ...cWindows.cs => MemoryManagementWindows.cs} | 8 +- ChocolArm64/Memory/MemoryManager.cs | 704 ++++++++++-------- ChocolArm64/Translation/ILEmitterCtx.cs | 132 ++-- ChocolArm64/Translation/Translator.cs | 4 +- Ryujinx.Graphics/Memory/NvGpuVmmCache.cs | 34 +- Ryujinx.HLE/DeviceMemory.cs | 8 +- Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs | 46 +- .../HOS/Kernel/SupervisorCall/SvcHandler.cs | 3 - .../HOS/Kernel/SupervisorCall/SvcIpc.cs | 4 +- .../HOS/Kernel/SupervisorCall/SvcMemory.cs | 21 +- .../HOS/Kernel/SupervisorCall/SvcSystem.cs | 2 +- .../HOS/Kernel/SupervisorCall/SvcThread.cs | 141 ++-- .../Kernel/SupervisorCall/SvcThreadSync.cs | 2 +- 24 files changed, 1005 insertions(+), 621 deletions(-) delete mode 100644 ChocolArm64/Events/InvalidAccessEventArgs.cs delete mode 100644 ChocolArm64/Exceptions/VmmPageFaultException.cs rename ChocolArm64/Memory/{MemoryAlloc.cs => MemoryManagement.cs} (81%) rename ChocolArm64/Memory/{MemoryAllocUnix.cs => MemoryManagementUnix.cs} (98%) rename ChocolArm64/Memory/{MemoryAllocWindows.cs => MemoryManagementWindows.cs} (95%) diff --git a/ChocolArm64/Events/InvalidAccessEventArgs.cs b/ChocolArm64/Events/InvalidAccessEventArgs.cs deleted file mode 100644 index 9c349755f0..0000000000 --- a/ChocolArm64/Events/InvalidAccessEventArgs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace ChocolArm64.Events -{ - public class MemoryAccessEventArgs : EventArgs - { - public long Position { get; private set; } - - public MemoryAccessEventArgs(long position) - { - Position = position; - } - } -} \ No newline at end of file diff --git a/ChocolArm64/Exceptions/VmmPageFaultException.cs b/ChocolArm64/Exceptions/VmmPageFaultException.cs deleted file mode 100644 index f33aafc013..0000000000 --- a/ChocolArm64/Exceptions/VmmPageFaultException.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace ChocolArm64.Exceptions -{ - public class VmmPageFaultException : Exception - { - private const string ExMsg = "Tried to access unmapped address 0x{0:x16}!"; - - public VmmPageFaultException() { } - - public VmmPageFaultException(long position) : base(string.Format(ExMsg, position)) { } - } -} \ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitMemory.cs b/ChocolArm64/Instructions/InstEmitMemory.cs index 96f782df64..ea779c8da4 100644 --- a/ChocolArm64/Instructions/InstEmitMemory.cs +++ b/ChocolArm64/Instructions/InstEmitMemory.cs @@ -31,8 +31,6 @@ namespace ChocolArm64.Instructions { OpCodeMem64 op = (OpCodeMem64)context.CurrOp; - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - EmitLoadAddress(context); if (signed && op.Extend64) @@ -69,7 +67,6 @@ namespace ChocolArm64.Instructions return; } - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdc_I8(op.Imm); if (op.Signed) @@ -116,13 +113,10 @@ namespace ChocolArm64.Instructions } } - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - EmitLoadAddress(context); EmitReadAndStore(op.Rt); - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); context.EmitLdc_I8(1 << op.Size); @@ -137,8 +131,6 @@ namespace ChocolArm64.Instructions { OpCodeMem64 op = (OpCodeMem64)context.CurrOp; - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - EmitLoadAddress(context); if (op is IOpCodeSimd64) @@ -159,8 +151,6 @@ namespace ChocolArm64.Instructions { OpCodeMemPair64 op = (OpCodeMemPair64)context.CurrOp; - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - EmitLoadAddress(context); if (op is IOpCodeSimd64) @@ -174,7 +164,6 @@ namespace ChocolArm64.Instructions EmitWriteCall(context, op.Size); - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); context.EmitLdc_I8(1 << op.Size); diff --git a/ChocolArm64/Instructions/InstEmitMemory32.cs b/ChocolArm64/Instructions/InstEmitMemory32.cs index 4d6a57a472..1e1419e65e 100644 --- a/ChocolArm64/Instructions/InstEmitMemory32.cs +++ b/ChocolArm64/Instructions/InstEmitMemory32.cs @@ -64,9 +64,7 @@ namespace ChocolArm64.Instructions { if ((mask & 1) != 0) { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); - context.EmitLdc_I4(offset); context.Emit(OpCodes.Add); @@ -129,9 +127,7 @@ namespace ChocolArm64.Instructions { if ((mask & 1) != 0) { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); - context.EmitLdc_I4(offset); context.Emit(OpCodes.Add); @@ -198,8 +194,6 @@ namespace ChocolArm64.Instructions context.EmitSttmp(); } - context.EmitLdarg(TranslatedSub.MemoryArgIdx); - if (op.Index) { context.EmitLdtmp(); diff --git a/ChocolArm64/Instructions/InstEmitMemoryEx.cs b/ChocolArm64/Instructions/InstEmitMemoryEx.cs index 215fcffdd5..920c695fff 100644 --- a/ChocolArm64/Instructions/InstEmitMemoryEx.cs +++ b/ChocolArm64/Instructions/InstEmitMemoryEx.cs @@ -72,6 +72,8 @@ namespace ChocolArm64.Instructions void WriteExclusiveValue(string propName) { + context.Emit(OpCodes.Dup); + if (op.Size < 3) { context.Emit(OpCodes.Conv_U8); @@ -82,13 +84,6 @@ namespace ChocolArm64.Instructions context.EmitLdtmp2(); context.EmitCallPrivatePropSet(typeof(CpuThreadState), propName); - - context.EmitLdtmp2(); - - if (op.Size < 3) - { - context.Emit(OpCodes.Conv_U4); - } } if (pair) @@ -99,7 +94,6 @@ namespace ChocolArm64.Instructions //method to read 128-bits atomically. if (op.Size == 2) { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); EmitReadZxCall(context, 3); @@ -164,13 +158,12 @@ namespace ChocolArm64.Instructions } else { - throw new InvalidOperationException($"Invalid store size of {1 << op.Size} bytes."); + throw new InvalidOperationException($"Invalid load size of {1 << op.Size} bytes."); } } else { //8, 16, 32 or 64-bits (non-pairwise) load. - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdtmp(); EmitReadZxCall(context, op.Size); @@ -320,9 +313,8 @@ namespace ChocolArm64.Instructions } else { - void EmitWrite(int rt, long offset) + void EmitWriteCall(int rt, long offset) { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdint(op.Rn); if (offset != 0) @@ -334,14 +326,14 @@ namespace ChocolArm64.Instructions context.EmitLdintzr(rt); - EmitWriteCall(context, op.Size); + InstEmitMemoryHelper.EmitWriteCall(context, op.Size); } - EmitWrite(op.Rt, 0); + EmitWriteCall(op.Rt, 0); if (pair) { - EmitWrite(op.Rt2, 1 << op.Size); + EmitWriteCall(op.Rt2, 1 << op.Size); } } } diff --git a/ChocolArm64/Instructions/InstEmitMemoryHelper.cs b/ChocolArm64/Instructions/InstEmitMemoryHelper.cs index f953564c46..7645e36316 100644 --- a/ChocolArm64/Instructions/InstEmitMemoryHelper.cs +++ b/ChocolArm64/Instructions/InstEmitMemoryHelper.cs @@ -1,13 +1,20 @@ using ChocolArm64.Decoders; using ChocolArm64.Memory; +using ChocolArm64.State; using ChocolArm64.Translation; using System; using System.Reflection.Emit; +using System.Runtime.Intrinsics.X86; namespace ChocolArm64.Instructions { static class InstEmitMemoryHelper { + private static int _tempIntAddress = ILEmitterCtx.GetIntTempIndex(); + private static int _tempIntValue = ILEmitterCtx.GetIntTempIndex(); + private static int _tempIntPtAddr = ILEmitterCtx.GetIntTempIndex(); + private static int _tempVecValue = ILEmitterCtx.GetVecTempIndex(); + private enum Extension { Zx, @@ -32,9 +39,10 @@ namespace ChocolArm64.Instructions private static void EmitReadCall(ILEmitterCtx context, Extension ext, int size) { - bool isSimd = GetIsSimd(context); + //Save the address into a temp. + context.EmitStint(_tempIntAddress); - string name = null; + bool isSimd = IsSimd(context); if (size < 0 || size > (isSimd ? 4 : 3)) { @@ -43,28 +51,27 @@ namespace ChocolArm64.Instructions if (isSimd) { - switch (size) + if (context.Tier == TranslationTier.Tier0 || !Sse2.IsSupported || size < 2) { - case 0: name = nameof(MemoryManager.ReadVector8); break; - case 1: name = nameof(MemoryManager.ReadVector16); break; - case 2: name = nameof(MemoryManager.ReadVector32); break; - case 3: name = nameof(MemoryManager.ReadVector64); break; - case 4: name = nameof(MemoryManager.ReadVector128); break; + EmitReadVectorFallback(context, size); + } + else + { + EmitReadVector(context, size); } } else { - switch (size) + if (context.Tier == TranslationTier.Tier0) { - case 0: name = nameof(MemoryManager.ReadByte); break; - case 1: name = nameof(MemoryManager.ReadUInt16); break; - case 2: name = nameof(MemoryManager.ReadUInt32); break; - case 3: name = nameof(MemoryManager.ReadUInt64); break; + EmitReadIntFallback(context, size); + } + else + { + EmitReadInt(context, size); } } - context.EmitCall(typeof(MemoryManager), name); - if (!isSimd) { if (ext == Extension.Sx32 || @@ -89,50 +96,390 @@ namespace ChocolArm64.Instructions public static void EmitWriteCall(ILEmitterCtx context, int size) { - bool isSimd = GetIsSimd(context); + bool isSimd = IsSimd(context); - string name = null; + //Save the value into a temp. + if (isSimd) + { + context.EmitStvec(_tempVecValue); + } + else + { + context.EmitStint(_tempIntValue); + } + + //Save the address into a temp. + context.EmitStint(_tempIntAddress); if (size < 0 || size > (isSimd ? 4 : 3)) { throw new ArgumentOutOfRangeException(nameof(size)); } - if (size < 3 && !isSimd) - { - context.Emit(OpCodes.Conv_I4); - } - if (isSimd) { - switch (size) + if (context.Tier == TranslationTier.Tier0 || !Sse2.IsSupported || size < 2) { - case 0: name = nameof(MemoryManager.WriteVector8); break; - case 1: name = nameof(MemoryManager.WriteVector16); break; - case 2: name = nameof(MemoryManager.WriteVector32); break; - case 3: name = nameof(MemoryManager.WriteVector64); break; - case 4: name = nameof(MemoryManager.WriteVector128); break; + EmitWriteVectorFallback(context, size); + } + else + { + EmitWriteVector(context, size); } } else { - switch (size) + if (context.Tier == TranslationTier.Tier0) { - case 0: name = nameof(MemoryManager.WriteByte); break; - case 1: name = nameof(MemoryManager.WriteUInt16); break; - case 2: name = nameof(MemoryManager.WriteUInt32); break; - case 3: name = nameof(MemoryManager.WriteUInt64); break; + EmitWriteIntFallback(context, size); + } + else + { + EmitWriteInt(context, size); } } - - context.EmitCall(typeof(MemoryManager), name); } - private static bool GetIsSimd(ILEmitterCtx context) + private static bool IsSimd(ILEmitterCtx context) { return context.CurrOp is IOpCodeSimd64 && !(context.CurrOp is OpCodeSimdMemMs64 || context.CurrOp is OpCodeSimdMemSs64); } + + private static void EmitReadInt(ILEmitterCtx context, int size) + { + EmitAddressCheck(context, size); + + ILLabel lblFastPath = new ILLabel(); + ILLabel lblSlowPath = new ILLabel(); + ILLabel lblEnd = new ILLabel(); + + context.Emit(OpCodes.Brfalse_S, lblFastPath); + + context.MarkLabel(lblSlowPath); + + EmitReadIntFallback(context, size); + + context.Emit(OpCodes.Br, lblEnd); + + context.MarkLabel(lblFastPath); + + EmitPtPointerLoad(context, lblSlowPath); + + switch (size) + { + case 0: context.Emit(OpCodes.Ldind_U1); break; + case 1: context.Emit(OpCodes.Ldind_U2); break; + case 2: context.Emit(OpCodes.Ldind_U4); break; + case 3: context.Emit(OpCodes.Ldind_I8); break; + } + + context.MarkLabel(lblEnd); + } + + private static void EmitReadVector(ILEmitterCtx context, int size) + { + EmitAddressCheck(context, size); + + ILLabel lblFastPath = new ILLabel(); + ILLabel lblSlowPath = new ILLabel(); + ILLabel lblEnd = new ILLabel(); + + context.Emit(OpCodes.Brfalse_S, lblFastPath); + + context.MarkLabel(lblSlowPath); + + EmitReadVectorFallback(context, size); + + context.Emit(OpCodes.Br, lblEnd); + + context.MarkLabel(lblFastPath); + + EmitPtPointerLoad(context, lblSlowPath); + + switch (size) + { + case 2: context.EmitCall(typeof(Sse), nameof(Sse.LoadScalarVector128)); break; + + case 3: + { + Type[] types = new Type[] { typeof(double*) }; + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.LoadScalarVector128), types)); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleToSingle)); + + break; + } + + case 4: context.EmitCall(typeof(Sse), nameof(Sse.LoadAlignedVector128)); break; + + throw new InvalidOperationException($"Invalid vector load size of {1 << size} bytes."); + } + + context.MarkLabel(lblEnd); + } + + private static void EmitWriteInt(ILEmitterCtx context, int size) + { + EmitAddressCheck(context, size); + + ILLabel lblFastPath = new ILLabel(); + ILLabel lblSlowPath = new ILLabel(); + ILLabel lblEnd = new ILLabel(); + + context.Emit(OpCodes.Brfalse_S, lblFastPath); + + context.MarkLabel(lblSlowPath); + + EmitWriteIntFallback(context, size); + + context.Emit(OpCodes.Br, lblEnd); + + context.MarkLabel(lblFastPath); + + EmitPtPointerLoad(context, lblSlowPath); + + context.EmitLdint(_tempIntValue); + + if (size < 3) + { + context.Emit(OpCodes.Conv_U4); + } + + switch (size) + { + case 0: context.Emit(OpCodes.Stind_I1); break; + case 1: context.Emit(OpCodes.Stind_I2); break; + case 2: context.Emit(OpCodes.Stind_I4); break; + case 3: context.Emit(OpCodes.Stind_I8); break; + } + + context.MarkLabel(lblEnd); + } + + private static void EmitWriteVector(ILEmitterCtx context, int size) + { + EmitAddressCheck(context, size); + + ILLabel lblFastPath = new ILLabel(); + ILLabel lblSlowPath = new ILLabel(); + ILLabel lblEnd = new ILLabel(); + + context.Emit(OpCodes.Brfalse_S, lblFastPath); + + context.MarkLabel(lblSlowPath); + + EmitWriteVectorFallback(context, size); + + context.Emit(OpCodes.Br, lblEnd); + + context.MarkLabel(lblFastPath); + + EmitPtPointerLoad(context, lblSlowPath); + + context.EmitLdvec(_tempVecValue); + + switch (size) + { + case 2: context.EmitCall(typeof(Sse), nameof(Sse.StoreScalar)); break; + + case 3: + { + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToDouble)); + + context.EmitCall(typeof(Sse2), nameof(Sse2.StoreScalar)); + + break; + } + + case 4: context.EmitCall(typeof(Sse), nameof(Sse.StoreAligned)); break; + + default: throw new InvalidOperationException($"Invalid vector store size of {1 << size} bytes."); + } + + context.MarkLabel(lblEnd); + } + + private static void EmitAddressCheck(ILEmitterCtx context, int size) + { + long addressCheckMask = ~(context.Memory.AddressSpaceSize - 1); + + addressCheckMask |= (1u << size) - 1; + + context.EmitLdint(_tempIntAddress); + + context.EmitLdc_I(addressCheckMask); + + context.Emit(OpCodes.And); + } + + private static void EmitPtPointerLoad(ILEmitterCtx context, ILLabel lblFallbackPath) + { + context.EmitLdc_I8(context.Memory.PageTable.ToInt64()); + + context.Emit(OpCodes.Conv_I); + + int bit = MemoryManager.PageBits; + + do + { + context.EmitLdint(_tempIntAddress); + + if (context.CurrOp.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Conv_U8); + } + + context.EmitLsr(bit); + + bit += context.Memory.PtLevelBits; + + if (bit < context.Memory.AddressSpaceBits) + { + context.EmitLdc_I8(context.Memory.PtLevelMask); + + context.Emit(OpCodes.And); + } + + context.EmitLdc_I8(IntPtr.Size); + + context.Emit(OpCodes.Mul); + context.Emit(OpCodes.Conv_I); + context.Emit(OpCodes.Add); + context.Emit(OpCodes.Ldind_I); + } + while (bit < context.Memory.AddressSpaceBits); + + if (!context.Memory.HasWriteWatchSupport) + { + context.Emit(OpCodes.Conv_U8); + + context.EmitStint(_tempIntPtAddr); + context.EmitLdint(_tempIntPtAddr); + + context.EmitLdc_I8(MemoryManager.PteFlagsMask); + + context.Emit(OpCodes.And); + + context.Emit(OpCodes.Brtrue, lblFallbackPath); + + context.EmitLdint(_tempIntPtAddr); + + context.Emit(OpCodes.Conv_I); + } + + context.EmitLdint(_tempIntAddress); + + context.EmitLdc_I(MemoryManager.PageMask); + + context.Emit(OpCodes.And); + context.Emit(OpCodes.Conv_I); + context.Emit(OpCodes.Add); + } + + private static void EmitReadIntFallback(ILEmitterCtx context, int size) + { + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + context.EmitLdint(_tempIntAddress); + + if (context.CurrOp.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Conv_U8); + } + + string fallbackMethodName = null; + + switch (size) + { + case 0: fallbackMethodName = nameof(MemoryManager.ReadByte); break; + case 1: fallbackMethodName = nameof(MemoryManager.ReadUInt16); break; + case 2: fallbackMethodName = nameof(MemoryManager.ReadUInt32); break; + case 3: fallbackMethodName = nameof(MemoryManager.ReadUInt64); break; + } + + context.EmitCall(typeof(MemoryManager), fallbackMethodName); + } + + private static void EmitReadVectorFallback(ILEmitterCtx context, int size) + { + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + context.EmitLdint(_tempIntAddress); + + if (context.CurrOp.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Conv_U8); + } + + string fallbackMethodName = null; + + switch (size) + { + case 0: fallbackMethodName = nameof(MemoryManager.ReadVector8); break; + case 1: fallbackMethodName = nameof(MemoryManager.ReadVector16); break; + case 2: fallbackMethodName = nameof(MemoryManager.ReadVector32); break; + case 3: fallbackMethodName = nameof(MemoryManager.ReadVector64); break; + case 4: fallbackMethodName = nameof(MemoryManager.ReadVector128); break; + } + + context.EmitCall(typeof(MemoryManager), fallbackMethodName); + } + + private static void EmitWriteIntFallback(ILEmitterCtx context, int size) + { + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + context.EmitLdint(_tempIntAddress); + + if (context.CurrOp.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Conv_U8); + } + + context.EmitLdint(_tempIntValue); + + if (size < 3) + { + context.Emit(OpCodes.Conv_U4); + } + + string fallbackMethodName = null; + + switch (size) + { + case 0: fallbackMethodName = nameof(MemoryManager.WriteByte); break; + case 1: fallbackMethodName = nameof(MemoryManager.WriteUInt16); break; + case 2: fallbackMethodName = nameof(MemoryManager.WriteUInt32); break; + case 3: fallbackMethodName = nameof(MemoryManager.WriteUInt64); break; + } + + context.EmitCall(typeof(MemoryManager), fallbackMethodName); + } + + private static void EmitWriteVectorFallback(ILEmitterCtx context, int size) + { + context.EmitLdarg(TranslatedSub.MemoryArgIdx); + context.EmitLdint(_tempIntAddress); + + if (context.CurrOp.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Conv_U8); + } + + context.EmitLdvec(_tempVecValue); + + string fallbackMethodName = null; + + switch (size) + { + case 0: fallbackMethodName = nameof(MemoryManager.WriteVector8); break; + case 1: fallbackMethodName = nameof(MemoryManager.WriteVector16); break; + case 2: fallbackMethodName = nameof(MemoryManager.WriteVector32); break; + case 3: fallbackMethodName = nameof(MemoryManager.WriteVector64); break; + case 4: fallbackMethodName = nameof(MemoryManager.WriteVector128); break; + } + + context.EmitCall(typeof(MemoryManager), fallbackMethodName); + } } } \ No newline at end of file diff --git a/ChocolArm64/Instructions/InstEmitSimdMemory.cs b/ChocolArm64/Instructions/InstEmitSimdMemory.cs index 9b84eb8681..18ec1d33ea 100644 --- a/ChocolArm64/Instructions/InstEmitSimdMemory.cs +++ b/ChocolArm64/Instructions/InstEmitSimdMemory.cs @@ -45,7 +45,6 @@ namespace ChocolArm64.Instructions if (isLoad) { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdint(op.Rn); context.EmitLdc_I8(offset); @@ -62,7 +61,6 @@ namespace ChocolArm64.Instructions } else { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdint(op.Rn); context.EmitLdc_I8(offset); @@ -90,7 +88,6 @@ namespace ChocolArm64.Instructions void EmitMemAddress() { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdint(op.Rn); context.EmitLdc_I8(offset); diff --git a/ChocolArm64/Instructions/InstEmitSystem.cs b/ChocolArm64/Instructions/InstEmitSystem.cs index 0e61d5bded..5687768a88 100644 --- a/ChocolArm64/Instructions/InstEmitSystem.cs +++ b/ChocolArm64/Instructions/InstEmitSystem.cs @@ -102,7 +102,6 @@ namespace ChocolArm64.Instructions //DC ZVA for (int offs = 0; offs < (4 << CpuThreadState.DczSizeLog2); offs += 8) { - context.EmitLdarg(TranslatedSub.MemoryArgIdx); context.EmitLdintzr(op.Rt); context.EmitLdc_I(offs); diff --git a/ChocolArm64/Memory/CompareExchange128.cs b/ChocolArm64/Memory/CompareExchange128.cs index 0fbe10f2cf..1618ff0fbc 100644 --- a/ChocolArm64/Memory/CompareExchange128.cs +++ b/ChocolArm64/Memory/CompareExchange128.cs @@ -95,7 +95,7 @@ namespace ChocolArm64.Memory int cpuId = getCpuId(); - MemoryAlloc.Free(funcPtr); + MemoryManagement.Free(funcPtr); return (cpuId & (1 << 13)) != 0; } @@ -104,7 +104,7 @@ namespace ChocolArm64.Memory { ulong codeLength = (ulong)code.Length; - IntPtr funcPtr = MemoryAlloc.Allocate(codeLength); + IntPtr funcPtr = MemoryManagement.Allocate(codeLength); unsafe { @@ -118,7 +118,7 @@ namespace ChocolArm64.Memory } } - MemoryAlloc.Reprotect(funcPtr, codeLength, MemoryProtection.Execute); + MemoryManagement.Reprotect(funcPtr, codeLength, MemoryProtection.Execute); return funcPtr; } diff --git a/ChocolArm64/Memory/MemoryAlloc.cs b/ChocolArm64/Memory/MemoryManagement.cs similarity index 81% rename from ChocolArm64/Memory/MemoryAlloc.cs rename to ChocolArm64/Memory/MemoryManagement.cs index a24299cd70..fa4bc4fac2 100644 --- a/ChocolArm64/Memory/MemoryAlloc.cs +++ b/ChocolArm64/Memory/MemoryManagement.cs @@ -4,7 +4,7 @@ using System.Runtime.InteropServices; namespace ChocolArm64.Memory { - public static class MemoryAlloc + public static class MemoryManagement { public static bool HasWriteWatchSupport => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); @@ -14,12 +14,12 @@ namespace ChocolArm64.Memory { IntPtr sizeNint = new IntPtr((long)size); - return MemoryAllocWindows.Allocate(sizeNint); + return MemoryManagementWindows.Allocate(sizeNint); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - return MemoryAllocUnix.Allocate(size); + return MemoryManagementUnix.Allocate(size); } else { @@ -33,12 +33,12 @@ namespace ChocolArm64.Memory { IntPtr sizeNint = new IntPtr((long)size); - return MemoryAllocWindows.AllocateWriteTracked(sizeNint); + return MemoryManagementWindows.AllocateWriteTracked(sizeNint); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - return MemoryAllocUnix.Allocate(size); + return MemoryManagementUnix.Allocate(size); } else { @@ -54,12 +54,12 @@ namespace ChocolArm64.Memory { IntPtr sizeNint = new IntPtr((long)size); - result = MemoryAllocWindows.Reprotect(address, sizeNint, permission); + result = MemoryManagementWindows.Reprotect(address, sizeNint, permission); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - result = MemoryAllocUnix.Reprotect(address, size, permission); + result = MemoryManagementUnix.Reprotect(address, size, permission); } else { @@ -76,12 +76,12 @@ namespace ChocolArm64.Memory { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - return MemoryAllocWindows.Free(address); + return MemoryManagementWindows.Free(address); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - return MemoryAllocUnix.Free(address); + return MemoryManagementUnix.Free(address); } else { @@ -101,7 +101,7 @@ namespace ChocolArm64.Memory //write tracking support on the OS. if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - return MemoryAllocWindows.GetModifiedPages(address, size, addresses, out count); + return MemoryManagementWindows.GetModifiedPages(address, size, addresses, out count); } else { diff --git a/ChocolArm64/Memory/MemoryAllocUnix.cs b/ChocolArm64/Memory/MemoryManagementUnix.cs similarity index 98% rename from ChocolArm64/Memory/MemoryAllocUnix.cs rename to ChocolArm64/Memory/MemoryManagementUnix.cs index 857c1c5042..9fe1aef094 100644 --- a/ChocolArm64/Memory/MemoryAllocUnix.cs +++ b/ChocolArm64/Memory/MemoryManagementUnix.cs @@ -3,7 +3,7 @@ using System; namespace ChocolArm64.Memory { - static class MemoryAllocUnix + static class MemoryManagementUnix { public static IntPtr Allocate(ulong size) { diff --git a/ChocolArm64/Memory/MemoryAllocWindows.cs b/ChocolArm64/Memory/MemoryManagementWindows.cs similarity index 95% rename from ChocolArm64/Memory/MemoryAllocWindows.cs rename to ChocolArm64/Memory/MemoryManagementWindows.cs index 82be8b1e4f..6cee134279 100644 --- a/ChocolArm64/Memory/MemoryAllocWindows.cs +++ b/ChocolArm64/Memory/MemoryManagementWindows.cs @@ -4,7 +4,7 @@ using System.Runtime.InteropServices; namespace ChocolArm64.Memory { - static class MemoryAllocWindows + static class MemoryManagementWindows { [Flags] private enum AllocationType : uint @@ -21,7 +21,7 @@ namespace ChocolArm64.Memory } [Flags] - private enum MemoryProtection + private enum MemoryProtection : uint { NoAccess = 0x01, ReadOnly = 0x02, @@ -59,7 +59,7 @@ namespace ChocolArm64.Memory [DllImport("kernel32.dll")] private static extern bool VirtualFree( IntPtr lpAddress, - uint dwSize, + IntPtr dwSize, AllocationType dwFreeType); [DllImport("kernel32.dll")] @@ -127,7 +127,7 @@ namespace ChocolArm64.Memory public static bool Free(IntPtr address) { - return VirtualFree(address, 0, AllocationType.Release); + return VirtualFree(address, IntPtr.Zero, AllocationType.Release); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/ChocolArm64/Memory/MemoryManager.cs b/ChocolArm64/Memory/MemoryManager.cs index afb0f65143..ce102e096c 100644 --- a/ChocolArm64/Memory/MemoryManager.cs +++ b/ChocolArm64/Memory/MemoryManager.cs @@ -1,8 +1,5 @@ -using ChocolArm64.Events; -using ChocolArm64.Exceptions; using ChocolArm64.Instructions; using System; -using System.Collections.Concurrent; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; @@ -10,52 +7,399 @@ using System.Runtime.Intrinsics.X86; using System.Threading; using static ChocolArm64.Memory.CompareExchange128; +using static ChocolArm64.Memory.MemoryManagement; namespace ChocolArm64.Memory { public unsafe class MemoryManager : IMemory, IDisposable { - private const int PtLvl0Bits = 13; - private const int PtLvl1Bits = 14; - public const int PageBits = 12; + public const int PageBits = 12; + public const int PageSize = 1 << PageBits; + public const int PageMask = PageSize - 1; - private const int PtLvl0Size = 1 << PtLvl0Bits; - private const int PtLvl1Size = 1 << PtLvl1Bits; - public const int PageSize = 1 << PageBits; + private const long PteFlagNotModified = 1; - private const int PtLvl0Mask = PtLvl0Size - 1; - private const int PtLvl1Mask = PtLvl1Size - 1; - public const int PageMask = PageSize - 1; - - private const int PtLvl0Bit = PageBits + PtLvl1Bits; - private const int PtLvl1Bit = PageBits; - - private ConcurrentDictionary _observedPages; + internal const long PteFlagsMask = 7; public IntPtr Ram { get; private set; } private byte* _ramPtr; - private byte*** _pageTable; + private IntPtr _pageTable; - public event EventHandler InvalidAccess; + internal IntPtr PageTable => _pageTable; - public event EventHandler ObservedAccess; + internal int PtLevelBits { get; } + internal int PtLevelSize { get; } + internal int PtLevelMask { get; } - public MemoryManager(IntPtr ram) + public bool HasWriteWatchSupport => MemoryManagement.HasWriteWatchSupport; + + public int AddressSpaceBits { get; } + public long AddressSpaceSize { get; } + + public MemoryManager( + IntPtr ram, + int addressSpaceBits = 48, + bool useFlatPageTable = false) { - _observedPages = new ConcurrentDictionary(); - Ram = ram; _ramPtr = (byte*)ram; - _pageTable = (byte***)Marshal.AllocHGlobal(PtLvl0Size * IntPtr.Size); + AddressSpaceBits = addressSpaceBits; + AddressSpaceSize = 1L << addressSpaceBits; - for (int l0 = 0; l0 < PtLvl0Size; l0++) + //When flat page table is requested, we use a single + //array for the mappings of the entire address space. + //This has better performance, but also high memory usage. + //The multi level page table uses 9 bits per level, so + //the memory usage is lower, but the performance is also + //lower, since each address translation requires multiple reads. + if (useFlatPageTable) { - _pageTable[l0] = null; + PtLevelBits = addressSpaceBits - PageBits; } + else + { + PtLevelBits = 9; + } + + PtLevelSize = 1 << PtLevelBits; + PtLevelMask = PtLevelSize - 1; + + _pageTable = Allocate((ulong)(PtLevelSize * IntPtr.Size)); + } + + public void Map(long va, long pa, long size) + { + SetPtEntries(va, _ramPtr + pa, size); + } + + public void Unmap(long position, long size) + { + SetPtEntries(position, null, size); + } + + public bool IsMapped(long position) + { + return Translate(position) != IntPtr.Zero; + } + + public long GetPhysicalAddress(long virtualAddress) + { + byte* ptr = (byte*)Translate(virtualAddress); + + return (long)(ptr - _ramPtr); + } + + private IntPtr Translate(long position) + { + if (!IsValidPosition(position)) + { + return IntPtr.Zero; + } + + byte* ptr = GetPtEntry(position); + + ulong ptrUlong = (ulong)ptr; + + if ((ptrUlong & PteFlagsMask) != 0) + { + ptrUlong &= ~(ulong)PteFlagsMask; + + ptr = (byte*)ptrUlong; + } + + return new IntPtr(ptr + (position & PageMask)); + } + + private IntPtr TranslateWrite(long position) + { + if (!IsValidPosition(position)) + { + return IntPtr.Zero; + } + + byte* ptr = GetPtEntry(position); + + ulong ptrUlong = (ulong)ptr; + + if ((ptrUlong & PteFlagsMask) != 0) + { + if ((ptrUlong & PteFlagNotModified) != 0) + { + ClearPtEntryFlag(position, PteFlagNotModified); + } + + ptrUlong &= ~(ulong)PteFlagsMask; + + ptr = (byte*)ptrUlong; + } + + return new IntPtr(ptr + (position & PageMask)); + } + + private byte* GetPtEntry(long position) + { + return *(byte**)GetPtPtr(position); + } + + private void SetPtEntries(long va, byte* ptr, long size) + { + long endPosition = (va + size + PageMask) & ~PageMask; + + while ((ulong)va < (ulong)endPosition) + { + SetPtEntry(va, ptr); + + va += PageSize; + + if (ptr != null) + { + ptr += PageSize; + } + } + } + + private void SetPtEntry(long position, byte* ptr) + { + *(byte**)GetPtPtr(position) = ptr; + } + + private void SetPtEntryFlag(long position, long flag) + { + ModifyPtEntryFlag(position, flag, setFlag: true); + } + + private void ClearPtEntryFlag(long position, long flag) + { + ModifyPtEntryFlag(position, flag, setFlag: false); + } + + private void ModifyPtEntryFlag(long position, long flag, bool setFlag) + { + IntPtr* pt = (IntPtr*)_pageTable; + + while (true) + { + IntPtr* ptPtr = GetPtPtr(position); + + IntPtr old = *ptPtr; + + long modified = old.ToInt64(); + + if (setFlag) + { + modified |= flag; + } + else + { + modified &= ~flag; + } + + IntPtr origValue = Interlocked.CompareExchange(ref *ptPtr, new IntPtr(modified), old); + + if (origValue == old) + { + break; + } + } + } + + private IntPtr* GetPtPtr(long position) + { + if (!IsValidPosition(position)) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + IntPtr nextPtr = _pageTable; + + IntPtr* ptePtr = null; + + int bit = PageBits; + + while (true) + { + long index = (position >> bit) & PtLevelMask; + + ptePtr = &((IntPtr*)nextPtr)[index]; + + bit += PtLevelBits; + + if (bit >= AddressSpaceBits) + { + break; + } + + nextPtr = *ptePtr; + + if (nextPtr == IntPtr.Zero) + { + //Entry does not yet exist, allocate a new one. + IntPtr newPtr = Allocate((ulong)(PtLevelSize * IntPtr.Size)); + + //Try to swap the current pointer (should be zero), with the allocated one. + nextPtr = Interlocked.Exchange(ref *ptePtr, newPtr); + + //If the old pointer is not null, then another thread already has set it. + if (nextPtr != IntPtr.Zero) + { + Free(newPtr); + } + else + { + nextPtr = newPtr; + } + } + } + + return ptePtr; + } + + public bool IsRegionModified(long position, long size) + { + if (!HasWriteWatchSupport) + { + return IsRegionModifiedFallback(position, size); + } + + IntPtr address = Translate(position); + + IntPtr baseAddr = address; + IntPtr expectedAddr = address; + + long pendingPages = 0; + + long pages = size / PageSize; + + bool modified = false; + + bool IsAnyPageModified() + { + IntPtr pendingSize = new IntPtr(pendingPages * PageSize); + + IntPtr[] addresses = new IntPtr[pendingPages]; + + bool result = GetModifiedPages(baseAddr, pendingSize, addresses, out ulong count); + + if (result) + { + return count != 0; + } + else + { + return true; + } + } + + while (pages-- > 0) + { + if (address != expectedAddr) + { + modified |= IsAnyPageModified(); + + baseAddr = address; + + pendingPages = 0; + } + + expectedAddr = address + PageSize; + + pendingPages++; + + if (pages == 0) + { + break; + } + + position += PageSize; + + address = Translate(position); + } + + if (pendingPages != 0) + { + modified |= IsAnyPageModified(); + } + + return modified; + } + + private unsafe bool IsRegionModifiedFallback(long position, long size) + { + long endAddr = (position + size + PageMask) & ~PageMask; + + bool modified = false; + + while ((ulong)position < (ulong)endAddr) + { + if (IsValidPosition(position)) + { + byte* ptr = ((byte**)_pageTable)[position >> PageBits]; + + ulong ptrUlong = (ulong)ptr; + + if ((ptrUlong & PteFlagNotModified) == 0) + { + modified = true; + + SetPtEntryFlag(position, PteFlagNotModified); + } + } + else + { + modified = true; + } + + position += PageSize; + } + + return modified; + } + + public bool TryGetHostAddress(long position, long size, out IntPtr ptr) + { + if (IsContiguous(position, size)) + { + ptr = (IntPtr)Translate(position); + + return true; + } + + ptr = IntPtr.Zero; + + return false; + } + + private bool IsContiguous(long position, long size) + { + long endPos = position + size; + + position &= ~PageMask; + + long expectedPa = GetPhysicalAddress(position); + + while ((ulong)position < (ulong)endPos) + { + long pa = GetPhysicalAddress(position); + + if (pa != expectedPa) + { + return false; + } + + position += PageSize; + expectedPa += PageSize; + } + + return true; + } + + public bool IsValidPosition(long position) + { + return (ulong)position < (ulong)AddressSpaceSize; } internal bool AtomicCompareExchange2xInt32( @@ -86,7 +430,7 @@ namespace ChocolArm64.Memory AbortWithAlignmentFault(position); } - IntPtr ptr = new IntPtr(TranslateWrite(position)); + IntPtr ptr = TranslateWrite(position); return InterlockedCompareExchange128(ptr, expectedLow, expectedHigh, desiredLow, desiredHigh); } @@ -98,7 +442,7 @@ namespace ChocolArm64.Memory AbortWithAlignmentFault(position); } - IntPtr ptr = new IntPtr(Translate(position)); + IntPtr ptr = Translate(position); InterlockedRead128(ptr, out ulong low, out ulong high); @@ -371,7 +715,7 @@ namespace ChocolArm64.Memory int copySize = (int)(pageLimit - position); - Marshal.Copy((IntPtr)Translate(position), data, offset, copySize); + Marshal.Copy(Translate(position), data, offset, copySize); position += copySize; offset += copySize; @@ -408,7 +752,7 @@ namespace ChocolArm64.Memory int copySize = (int)(pageLimit - position); - Marshal.Copy((IntPtr)Translate(position), data, offset, copySize); + Marshal.Copy(Translate(position), data, offset, copySize); position += copySize; offset += copySize; @@ -571,7 +915,7 @@ namespace ChocolArm64.Memory int copySize = (int)(pageLimit - position); - Marshal.Copy(data, offset, (IntPtr)TranslateWrite(position), copySize); + Marshal.Copy(data, offset, TranslateWrite(position), copySize); position += copySize; offset += copySize; @@ -601,7 +945,7 @@ namespace ChocolArm64.Memory int copySize = (int)(pageLimit - position); - Marshal.Copy(data, offset, (IntPtr)TranslateWrite(position), copySize); + Marshal.Copy(data, offset, Translate(position), copySize); position += copySize; offset += copySize; @@ -614,8 +958,8 @@ namespace ChocolArm64.Memory if (IsContiguous(src, size) && IsContiguous(dst, size)) { - byte* srcPtr = Translate(src); - byte* dstPtr = TranslateWrite(dst); + byte* srcPtr = (byte*)Translate(src); + byte* dstPtr = (byte*)Translate(dst); Buffer.MemoryCopy(srcPtr, dstPtr, size, size); } @@ -625,266 +969,6 @@ namespace ChocolArm64.Memory } } - public void Map(long va, long pa, long size) - { - SetPtEntries(va, _ramPtr + pa, size); - } - - public void Unmap(long position, long size) - { - SetPtEntries(position, null, size); - - StopObservingRegion(position, size); - } - - public bool IsMapped(long position) - { - if (!(IsValidPosition(position))) - { - return false; - } - - long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; - long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; - - if (_pageTable[l0] == null) - { - return false; - } - - return _pageTable[l0][l1] != null || _observedPages.ContainsKey(position >> PageBits); - } - - public long GetPhysicalAddress(long virtualAddress) - { - byte* ptr = Translate(virtualAddress); - - return (long)(ptr - _ramPtr); - } - - internal byte* Translate(long position) - { - long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; - long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; - - long old = position; - - byte** lvl1 = _pageTable[l0]; - - if ((position >> (PtLvl0Bit + PtLvl0Bits)) != 0) - { - goto Unmapped; - } - - if (lvl1 == null) - { - goto Unmapped; - } - - position &= PageMask; - - byte* ptr = lvl1[l1]; - - if (ptr == null) - { - goto Unmapped; - } - - return ptr + position; - -Unmapped: - return HandleNullPte(old); - } - - private byte* HandleNullPte(long position) - { - long key = position >> PageBits; - - if (_observedPages.TryGetValue(key, out IntPtr ptr)) - { - return (byte*)ptr + (position & PageMask); - } - - InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position)); - - throw new VmmPageFaultException(position); - } - - internal byte* TranslateWrite(long position) - { - long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; - long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; - - long old = position; - - byte** lvl1 = _pageTable[l0]; - - if ((position >> (PtLvl0Bit + PtLvl0Bits)) != 0) - { - goto Unmapped; - } - - if (lvl1 == null) - { - goto Unmapped; - } - - position &= PageMask; - - byte* ptr = lvl1[l1]; - - if (ptr == null) - { - goto Unmapped; - } - - return ptr + position; - -Unmapped: - return HandleNullPteWrite(old); - } - - private byte* HandleNullPteWrite(long position) - { - long key = position >> PageBits; - - MemoryAccessEventArgs e = new MemoryAccessEventArgs(position); - - if (_observedPages.TryGetValue(key, out IntPtr ptr)) - { - SetPtEntry(position, (byte*)ptr); - - ObservedAccess?.Invoke(this, e); - - return (byte*)ptr + (position & PageMask); - } - - InvalidAccess?.Invoke(this, e); - - throw new VmmPageFaultException(position); - } - - private void SetPtEntries(long va, byte* ptr, long size) - { - long endPosition = (va + size + PageMask) & ~PageMask; - - while ((ulong)va < (ulong)endPosition) - { - SetPtEntry(va, ptr); - - va += PageSize; - - if (ptr != null) - { - ptr += PageSize; - } - } - } - - private void SetPtEntry(long position, byte* ptr) - { - if (!IsValidPosition(position)) - { - throw new ArgumentOutOfRangeException(nameof(position)); - } - - long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; - long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; - - if (_pageTable[l0] == null) - { - byte** lvl1 = (byte**)Marshal.AllocHGlobal(PtLvl1Size * IntPtr.Size); - - for (int zl1 = 0; zl1 < PtLvl1Size; zl1++) - { - lvl1[zl1] = null; - } - - Thread.MemoryBarrier(); - - _pageTable[l0] = lvl1; - } - - _pageTable[l0][l1] = ptr; - } - - public void StartObservingRegion(long position, long size) - { - long endPosition = (position + size + PageMask) & ~PageMask; - - position &= ~PageMask; - - while ((ulong)position < (ulong)endPosition) - { - _observedPages[position >> PageBits] = (IntPtr)Translate(position); - - SetPtEntry(position, null); - - position += PageSize; - } - } - - public void StopObservingRegion(long position, long size) - { - long endPosition = (position + size + PageMask) & ~PageMask; - - while (position < endPosition) - { - lock (_observedPages) - { - if (_observedPages.TryRemove(position >> PageBits, out IntPtr ptr)) - { - SetPtEntry(position, (byte*)ptr); - } - } - - position += PageSize; - } - } - - public bool TryGetHostAddress(long position, long size, out IntPtr ptr) - { - if (IsContiguous(position, size)) - { - ptr = (IntPtr)Translate(position); - - return true; - } - - ptr = IntPtr.Zero; - - return false; - } - - private bool IsContiguous(long position, long size) - { - long endPos = position + size; - - position &= ~PageMask; - - long expectedPa = GetPhysicalAddress(position); - - while ((ulong)position < (ulong)endPos) - { - long pa = GetPhysicalAddress(position); - - if (pa != expectedPa) - { - return false; - } - - position += PageSize; - expectedPa += PageSize; - } - - return true; - } - - public bool IsValidPosition(long position) - { - return position >> (PtLvl0Bits + PtLvl1Bits + PageBits) == 0; - } - public void Dispose() { Dispose(true); @@ -892,24 +976,36 @@ Unmapped: protected virtual void Dispose(bool disposing) { - if (_pageTable == null) + IntPtr ptr = Interlocked.Exchange(ref _pageTable, IntPtr.Zero); + + if (ptr != IntPtr.Zero) { + FreePageTableEntry(ptr, PageBits); + } + } + + private void FreePageTableEntry(IntPtr ptr, int levelBitEnd) + { + levelBitEnd += PtLevelBits; + + if (levelBitEnd >= AddressSpaceBits) + { + Free(ptr); + return; } - for (int l0 = 0; l0 < PtLvl0Size; l0++) + for (int index = 0; index < PtLevelSize; index++) { - if (_pageTable[l0] != null) - { - Marshal.FreeHGlobal((IntPtr)_pageTable[l0]); - } + IntPtr ptePtr = ((IntPtr*)ptr)[index]; - _pageTable[l0] = null; + if (ptePtr != IntPtr.Zero) + { + FreePageTableEntry(ptePtr, levelBitEnd); + } } - Marshal.FreeHGlobal((IntPtr)_pageTable); - - _pageTable = null; + Free(ptr); } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs index 5490123774..f7e61bc999 100644 --- a/ChocolArm64/Translation/ILEmitterCtx.cs +++ b/ChocolArm64/Translation/ILEmitterCtx.cs @@ -1,5 +1,6 @@ using ChocolArm64.Decoders; using ChocolArm64.Instructions; +using ChocolArm64.Memory; using ChocolArm64.State; using System; using System.Collections.Generic; @@ -10,6 +11,8 @@ namespace ChocolArm64.Translation { class ILEmitterCtx { + public MemoryManager Memory { get; } + private TranslatorCache _cache; private TranslatorQueue _queue; @@ -43,19 +46,34 @@ namespace ChocolArm64.Translation //values needed by some functions, since IL doesn't have a swap instruction. //You can use any value here as long it doesn't conflict with the indices //for the other registers. Any value >= 64 or < 0 will do. - private const int IntTmpIndex = -1; - private const int RorTmpIndex = -2; - private const int CmpOptTmp1Index = -3; - private const int CmpOptTmp2Index = -4; - private const int VecTmp1Index = -5; - private const int VecTmp2Index = -6; - private const int IntTmp2Index = -7; + private const int ReservedLocalsCount = 64; - public ILEmitterCtx(TranslatorCache cache, TranslatorQueue queue, TranslationTier tier, Block graph) + private const int RorTmpIndex = ReservedLocalsCount + 0; + private const int CmpOptTmp1Index = ReservedLocalsCount + 1; + private const int CmpOptTmp2Index = ReservedLocalsCount + 2; + private const int IntGpTmp1Index = ReservedLocalsCount + 3; + private const int IntGpTmp2Index = ReservedLocalsCount + 4; + private const int UserIntTempStart = ReservedLocalsCount + 5; + + //Vectors are part of another "set" of locals. + private const int VecGpTmp1Index = ReservedLocalsCount + 0; + private const int VecGpTmp2Index = ReservedLocalsCount + 1; + private const int UserVecTempStart = ReservedLocalsCount + 2; + + private static int _userIntTempCount; + private static int _userVecTempCount; + + public ILEmitterCtx( + MemoryManager memory, + TranslatorCache cache, + TranslatorQueue queue, + TranslationTier tier, + Block graph) { - _cache = cache ?? throw new ArgumentNullException(nameof(cache)); - _queue = queue ?? throw new ArgumentNullException(nameof(queue)); - _currBlock = graph ?? throw new ArgumentNullException(nameof(graph)); + Memory = memory ?? throw new ArgumentNullException(nameof(memory)); + _cache = cache ?? throw new ArgumentNullException(nameof(cache)); + _queue = queue ?? throw new ArgumentNullException(nameof(queue)); + _currBlock = graph ?? throw new ArgumentNullException(nameof(graph)); Tier = tier; @@ -76,6 +94,16 @@ namespace ChocolArm64.Translation AdvanceOpCode(); } + public static int GetIntTempIndex() + { + return UserIntTempStart + _userIntTempCount++; + } + + public static int GetVecTempIndex() + { + return UserVecTempStart + _userVecTempCount++; + } + public ILBlock[] GetILBlocks() { EmitAllOpCodes(); @@ -145,7 +173,7 @@ namespace ChocolArm64.Translation _ilBlock.Add(new ILBarrier()); } - private Condition GetInverseCond(Condition cond) + private static Condition GetInverseCond(Condition cond) { //Bit 0 of all conditions is basically a negation bit, so //inverting this bit has the effect of inverting the condition. @@ -560,17 +588,17 @@ namespace ChocolArm64.Translation _ilBlock.Add(new ILOpCodeStoreState(_ilBlock)); } - public void EmitLdtmp() => EmitLdint(IntTmpIndex); - public void EmitSttmp() => EmitStint(IntTmpIndex); + public void EmitLdtmp() => EmitLdint(IntGpTmp1Index); + public void EmitSttmp() => EmitStint(IntGpTmp1Index); - public void EmitLdtmp2() => EmitLdint(IntTmp2Index); - public void EmitSttmp2() => EmitStint(IntTmp2Index); + public void EmitLdtmp2() => EmitLdint(IntGpTmp2Index); + public void EmitSttmp2() => EmitStint(IntGpTmp2Index); - public void EmitLdvectmp() => EmitLdvec(VecTmp1Index); - public void EmitStvectmp() => EmitStvec(VecTmp1Index); + public void EmitLdvectmp() => EmitLdvec(VecGpTmp1Index); + public void EmitStvectmp() => EmitStvec(VecGpTmp1Index); - public void EmitLdvectmp2() => EmitLdvec(VecTmp2Index); - public void EmitStvectmp2() => EmitStvec(VecTmp2Index); + public void EmitLdvectmp2() => EmitLdvec(VecGpTmp2Index); + public void EmitStvectmp2() => EmitStvec(VecGpTmp2Index); public void EmitLdint(int index) => Ldloc(index, IoType.Int); public void EmitStint(int index) => Stloc(index, IoType.Int); @@ -611,62 +639,12 @@ namespace ChocolArm64.Translation public void EmitCallPropGet(Type objType, string propName) { - if (objType == null) - { - throw new ArgumentNullException(nameof(objType)); - } - - if (propName == null) - { - throw new ArgumentNullException(nameof(propName)); - } - - EmitCall(objType.GetMethod($"get_{propName}")); + EmitCall(objType, $"get_{propName}"); } public void EmitCallPropSet(Type objType, string propName) { - if (objType == null) - { - throw new ArgumentNullException(nameof(objType)); - } - - if (propName == null) - { - throw new ArgumentNullException(nameof(propName)); - } - - EmitCall(objType.GetMethod($"set_{propName}")); - } - - public void EmitCallPrivatePropGet(Type objType, string propName) - { - if (objType == null) - { - throw new ArgumentNullException(nameof(objType)); - } - - if (propName == null) - { - throw new ArgumentNullException(nameof(propName)); - } - - EmitPrivateCall(objType, $"get_{propName}"); - } - - public void EmitCallPrivatePropSet(Type objType, string propName) - { - if (objType == null) - { - throw new ArgumentNullException(nameof(objType)); - } - - if (propName == null) - { - throw new ArgumentNullException(nameof(propName)); - } - - EmitPrivateCall(objType, $"set_{propName}"); + EmitCall(objType, $"set_{propName}"); } public void EmitCall(Type objType, string mthdName) @@ -684,6 +662,16 @@ namespace ChocolArm64.Translation EmitCall(objType.GetMethod(mthdName)); } + public void EmitCallPrivatePropGet(Type objType, string propName) + { + EmitPrivateCall(objType, $"get_{propName}"); + } + + public void EmitCallPrivatePropSet(Type objType, string propName) + { + EmitPrivateCall(objType, $"set_{propName}"); + } + public void EmitPrivateCall(Type objType, string mthdName) { if (objType == null) diff --git a/ChocolArm64/Translation/Translator.cs b/ChocolArm64/Translation/Translator.cs index 7f7df6e5b2..dd1215f50c 100644 --- a/ChocolArm64/Translation/Translator.cs +++ b/ChocolArm64/Translation/Translator.cs @@ -138,7 +138,7 @@ namespace ChocolArm64.Translation { Block block = Decoder.DecodeBasicBlock(_memory, position, mode); - ILEmitterCtx context = new ILEmitterCtx(_cache, _queue, TranslationTier.Tier0, block); + ILEmitterCtx context = new ILEmitterCtx(_memory, _cache, _queue, TranslationTier.Tier0, block); string subName = GetSubroutineName(position); @@ -153,7 +153,7 @@ namespace ChocolArm64.Translation { Block graph = Decoder.DecodeSubroutine(_memory, position, mode); - ILEmitterCtx context = new ILEmitterCtx(_cache, _queue, TranslationTier.Tier1, graph); + ILEmitterCtx context = new ILEmitterCtx(_memory, _cache, _queue, TranslationTier.Tier1, graph); ILBlock[] ilBlocks = context.GetILBlocks(); diff --git a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs index 2f50463ded..053c216137 100644 --- a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs +++ b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs @@ -1,4 +1,3 @@ -using ChocolArm64.Events; using ChocolArm64.Memory; using System.Collections.Concurrent; @@ -19,35 +18,28 @@ namespace Ryujinx.Graphics.Memory { _memory = memory; - _memory.ObservedAccess += MemoryAccessHandler; - CachedPages = new ConcurrentDictionary[1 << 20]; } - private void MemoryAccessHandler(object sender, MemoryAccessEventArgs e) - { - long pa = _memory.GetPhysicalAddress(e.Position); - - CachedPages[pa >> PageBits]?.Clear(); - } - public bool IsRegionModified(long position, long size, NvGpuBufferType bufferType) { - long pa = _memory.GetPhysicalAddress(position); + long va = position; - long addr = pa; + long pa = _memory.GetPhysicalAddress(va); - long endAddr = (addr + size + PageMask) & ~PageMask; + long endAddr = (va + size + PageMask) & ~PageMask; + + long addrTruncated = va & ~PageMask; + + bool modified = _memory.IsRegionModified(addrTruncated, endAddr - addrTruncated); int newBuffMask = 1 << (int)bufferType; - _memory.StartObservingRegion(position, size); - long cachedPagesCount = 0; - while (addr < endAddr) + while (va < endAddr) { - long page = addr >> PageBits; + long page = _memory.GetPhysicalAddress(va) >> PageBits; ConcurrentDictionary dictionary = CachedPages[page]; @@ -57,6 +49,10 @@ namespace Ryujinx.Graphics.Memory CachedPages[page] = dictionary; } + else if (modified) + { + CachedPages[page].Clear(); + } if (dictionary.TryGetValue(pa, out int currBuffMask)) { @@ -74,10 +70,10 @@ namespace Ryujinx.Graphics.Memory dictionary[pa] = newBuffMask; } - addr += PageSize; + va += PageSize; } - return cachedPagesCount != (endAddr - pa + PageMask) >> PageBits; + return cachedPagesCount != (endAddr - addrTruncated) >> PageBits; } } } \ No newline at end of file diff --git a/Ryujinx.HLE/DeviceMemory.cs b/Ryujinx.HLE/DeviceMemory.cs index 310942b872..524adb8466 100644 --- a/Ryujinx.HLE/DeviceMemory.cs +++ b/Ryujinx.HLE/DeviceMemory.cs @@ -1,5 +1,5 @@ +using ChocolArm64.Memory; using System; -using System.Runtime.InteropServices; namespace Ryujinx.HLE { @@ -7,13 +7,13 @@ namespace Ryujinx.HLE { public const long RamSize = 4L * 1024 * 1024 * 1024; - public IntPtr RamPointer { get; private set; } + public IntPtr RamPointer { get; } private unsafe byte* _ramPtr; public unsafe DeviceMemory() { - RamPointer = Marshal.AllocHGlobal(new IntPtr(RamSize)); + RamPointer = MemoryManagement.AllocateWriteTracked(RamSize); _ramPtr = (byte*)RamPointer; } @@ -177,7 +177,7 @@ namespace Ryujinx.HLE protected virtual void Dispose(bool disposing) { - Marshal.FreeHGlobal(RamPointer); + MemoryManagement.Free(RamPointer); } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs index 338e5543d7..909f6333a9 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs @@ -80,12 +80,14 @@ namespace Ryujinx.HLE.HOS.Kernel.Process public bool IsPaused { get; private set; } - public Translator Translator { get; private set; } - public MemoryManager CpuMemory { get; private set; } + public Translator Translator { get; private set; } + private SvcHandler _svcHandler; + private Horizon _system; + public HleProcessDebugger Debugger { get; private set; } public KProcess(Horizon system) : base(system) @@ -93,14 +95,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process _processLock = new object(); _threadingLock = new object(); - CpuMemory = new MemoryManager(system.Device.Memory.RamPointer); - - CpuMemory.InvalidAccess += InvalidAccessHandler; + _system = system; AddressArbiter = new KAddressArbiter(system); - MemoryManager = new KMemoryManager(system, CpuMemory); - _fullTlsPages = new SortedDictionary(); _freeTlsPages = new SortedDictionary(); @@ -110,10 +108,6 @@ namespace Ryujinx.HLE.HOS.Kernel.Process _threads = new LinkedList(); - Translator = new Translator(CpuMemory); - - Translator.CpuTrace += CpuTraceHandler; - _svcHandler = new SvcHandler(system.Device, this); Debugger = new HleProcessDebugger(this); @@ -131,6 +125,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7); + InitializeMemoryManager(addrSpaceType, memRegion); + bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0; ulong codeAddress = creationInfo.CodeAddress; @@ -238,6 +234,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process AddressSpaceType addrSpaceType = (AddressSpaceType)((creationInfo.MmuFlags >> 1) & 7); + InitializeMemoryManager(addrSpaceType, memRegion); + bool aslrEnabled = ((creationInfo.MmuFlags >> 5) & 1) != 0; ulong codeAddress = creationInfo.CodeAddress; @@ -405,7 +403,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process case AddressSpaceType.Addr36Bits: case AddressSpaceType.Addr39Bits: _memoryUsageCapacity = MemoryManager.HeapRegionEnd - - MemoryManager.HeapRegionStart; + MemoryManager.HeapRegionStart; break; case AddressSpaceType.Addr32BitsNoMap: @@ -1010,9 +1008,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Process } } - private void InvalidAccessHandler(object sender, MemoryAccessEventArgs e) + private void InitializeMemoryManager(AddressSpaceType addrSpaceType, MemoryRegion memRegion) { - PrintCurrentThreadStackTrace(); + int addrSpaceBits; + + switch (addrSpaceType) + { + case AddressSpaceType.Addr32Bits: addrSpaceBits = 32; break; + case AddressSpaceType.Addr36Bits: addrSpaceBits = 36; break; + case AddressSpaceType.Addr32BitsNoMap: addrSpaceBits = 32; break; + case AddressSpaceType.Addr39Bits: addrSpaceBits = 39; break; + + default: throw new ArgumentException(nameof(addrSpaceType)); + } + + bool useFlatPageTable = memRegion == MemoryRegion.Application; + + CpuMemory = new MemoryManager(_system.Device.Memory.RamPointer, addrSpaceBits, useFlatPageTable); + + MemoryManager = new KMemoryManager(_system, CpuMemory); + + Translator = new Translator(CpuMemory); + + Translator.CpuTrace += CpuTraceHandler; } public void PrintCurrentThreadStackTrace() diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcHandler.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcHandler.cs index 071b3c2019..cf881a7932 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcHandler.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcHandler.cs @@ -1,5 +1,4 @@ using ChocolArm64.Events; -using ChocolArm64.Memory; using ChocolArm64.State; using Ryujinx.HLE.HOS.Kernel.Process; using System; @@ -11,14 +10,12 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall private Switch _device; private KProcess _process; private Horizon _system; - private MemoryManager _memory; public SvcHandler(Switch device, KProcess process) { _device = device; _process = process; _system = device.System; - _memory = process.CpuMemory; } public void SvcCall(object sender, InstExceptionEventArgs e) diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs index 5493941894..e19d9d2687 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs @@ -93,7 +93,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall private KernelResult SendSyncRequest(ulong messagePtr, ulong size, int handle) { - byte[] messageData = _memory.ReadBytes((long)messagePtr, (long)size); + byte[] messageData = _process.CpuMemory.ReadBytes((long)messagePtr, (long)size); KClientSession clientSession = _process.HandleTable.GetObject(handle); @@ -142,7 +142,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall ipcMessage.Thread.ObjSyncResult = IpcHandler.IpcCall( _device, _process, - _memory, + _process.CpuMemory, ipcMessage.Session, ipcMessage.Message, ipcMessage.MessagePtr); diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcMemory.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcMemory.cs index 6f8180c507..f794d13073 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcMemory.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcMemory.cs @@ -62,11 +62,6 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall attributeMask, attributeValue); - if (result == KernelResult.Success) - { - _memory.StopObservingRegion((long)position, (long)size); - } - return result; } @@ -157,14 +152,14 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall { KMemoryInfo blkInfo = _process.MemoryManager.QueryMemory(position); - _memory.WriteUInt64((long)infoPtr + 0x00, blkInfo.Address); - _memory.WriteUInt64((long)infoPtr + 0x08, blkInfo.Size); - _memory.WriteInt32 ((long)infoPtr + 0x10, (int)blkInfo.State & 0xff); - _memory.WriteInt32 ((long)infoPtr + 0x14, (int)blkInfo.Attribute); - _memory.WriteInt32 ((long)infoPtr + 0x18, (int)blkInfo.Permission); - _memory.WriteInt32 ((long)infoPtr + 0x1c, blkInfo.IpcRefCount); - _memory.WriteInt32 ((long)infoPtr + 0x20, blkInfo.DeviceRefCount); - _memory.WriteInt32 ((long)infoPtr + 0x24, 0); + _process.CpuMemory.WriteUInt64((long)infoPtr + 0x00, blkInfo.Address); + _process.CpuMemory.WriteUInt64((long)infoPtr + 0x08, blkInfo.Size); + _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x10, (int)blkInfo.State & 0xff); + _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x14, (int)blkInfo.Attribute); + _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x18, (int)blkInfo.Permission); + _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x1c, blkInfo.IpcRefCount); + _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x20, blkInfo.DeviceRefCount); + _process.CpuMemory.WriteInt32 ((long)infoPtr + 0x24, 0); return KernelResult.Success; } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs index be136ff0a5..efc10512ab 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcSystem.cs @@ -201,7 +201,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall private void OutputDebugString(ulong strPtr, ulong size) { - string str = MemoryHelper.ReadAsciiString(_memory, (long)strPtr, (long)size); + string str = MemoryHelper.ReadAsciiString(_process.CpuMemory, (long)strPtr, (long)size); Logger.PrintWarning(LogClass.KernelSvc, str); } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThread.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThread.cs index 64268ff23d..fa0b3a6c88 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThread.cs @@ -1,3 +1,4 @@ +using ChocolArm64.Memory; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.HOS.Kernel.Threading; @@ -346,79 +347,81 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall return KernelResult.InvalidThread; } - _memory.WriteUInt64((long)address + 0x0, thread.Context.ThreadState.X0); - _memory.WriteUInt64((long)address + 0x8, thread.Context.ThreadState.X1); - _memory.WriteUInt64((long)address + 0x10, thread.Context.ThreadState.X2); - _memory.WriteUInt64((long)address + 0x18, thread.Context.ThreadState.X3); - _memory.WriteUInt64((long)address + 0x20, thread.Context.ThreadState.X4); - _memory.WriteUInt64((long)address + 0x28, thread.Context.ThreadState.X5); - _memory.WriteUInt64((long)address + 0x30, thread.Context.ThreadState.X6); - _memory.WriteUInt64((long)address + 0x38, thread.Context.ThreadState.X7); - _memory.WriteUInt64((long)address + 0x40, thread.Context.ThreadState.X8); - _memory.WriteUInt64((long)address + 0x48, thread.Context.ThreadState.X9); - _memory.WriteUInt64((long)address + 0x50, thread.Context.ThreadState.X10); - _memory.WriteUInt64((long)address + 0x58, thread.Context.ThreadState.X11); - _memory.WriteUInt64((long)address + 0x60, thread.Context.ThreadState.X12); - _memory.WriteUInt64((long)address + 0x68, thread.Context.ThreadState.X13); - _memory.WriteUInt64((long)address + 0x70, thread.Context.ThreadState.X14); - _memory.WriteUInt64((long)address + 0x78, thread.Context.ThreadState.X15); - _memory.WriteUInt64((long)address + 0x80, thread.Context.ThreadState.X16); - _memory.WriteUInt64((long)address + 0x88, thread.Context.ThreadState.X17); - _memory.WriteUInt64((long)address + 0x90, thread.Context.ThreadState.X18); - _memory.WriteUInt64((long)address + 0x98, thread.Context.ThreadState.X19); - _memory.WriteUInt64((long)address + 0xa0, thread.Context.ThreadState.X20); - _memory.WriteUInt64((long)address + 0xa8, thread.Context.ThreadState.X21); - _memory.WriteUInt64((long)address + 0xb0, thread.Context.ThreadState.X22); - _memory.WriteUInt64((long)address + 0xb8, thread.Context.ThreadState.X23); - _memory.WriteUInt64((long)address + 0xc0, thread.Context.ThreadState.X24); - _memory.WriteUInt64((long)address + 0xc8, thread.Context.ThreadState.X25); - _memory.WriteUInt64((long)address + 0xd0, thread.Context.ThreadState.X26); - _memory.WriteUInt64((long)address + 0xd8, thread.Context.ThreadState.X27); - _memory.WriteUInt64((long)address + 0xe0, thread.Context.ThreadState.X28); - _memory.WriteUInt64((long)address + 0xe8, thread.Context.ThreadState.X29); - _memory.WriteUInt64((long)address + 0xf0, thread.Context.ThreadState.X30); - _memory.WriteUInt64((long)address + 0xf8, thread.Context.ThreadState.X31); + MemoryManager memory = currentProcess.CpuMemory; - _memory.WriteInt64((long)address + 0x100, thread.LastPc); + memory.WriteUInt64((long)address + 0x0, thread.Context.ThreadState.X0); + memory.WriteUInt64((long)address + 0x8, thread.Context.ThreadState.X1); + memory.WriteUInt64((long)address + 0x10, thread.Context.ThreadState.X2); + memory.WriteUInt64((long)address + 0x18, thread.Context.ThreadState.X3); + memory.WriteUInt64((long)address + 0x20, thread.Context.ThreadState.X4); + memory.WriteUInt64((long)address + 0x28, thread.Context.ThreadState.X5); + memory.WriteUInt64((long)address + 0x30, thread.Context.ThreadState.X6); + memory.WriteUInt64((long)address + 0x38, thread.Context.ThreadState.X7); + memory.WriteUInt64((long)address + 0x40, thread.Context.ThreadState.X8); + memory.WriteUInt64((long)address + 0x48, thread.Context.ThreadState.X9); + memory.WriteUInt64((long)address + 0x50, thread.Context.ThreadState.X10); + memory.WriteUInt64((long)address + 0x58, thread.Context.ThreadState.X11); + memory.WriteUInt64((long)address + 0x60, thread.Context.ThreadState.X12); + memory.WriteUInt64((long)address + 0x68, thread.Context.ThreadState.X13); + memory.WriteUInt64((long)address + 0x70, thread.Context.ThreadState.X14); + memory.WriteUInt64((long)address + 0x78, thread.Context.ThreadState.X15); + memory.WriteUInt64((long)address + 0x80, thread.Context.ThreadState.X16); + memory.WriteUInt64((long)address + 0x88, thread.Context.ThreadState.X17); + memory.WriteUInt64((long)address + 0x90, thread.Context.ThreadState.X18); + memory.WriteUInt64((long)address + 0x98, thread.Context.ThreadState.X19); + memory.WriteUInt64((long)address + 0xa0, thread.Context.ThreadState.X20); + memory.WriteUInt64((long)address + 0xa8, thread.Context.ThreadState.X21); + memory.WriteUInt64((long)address + 0xb0, thread.Context.ThreadState.X22); + memory.WriteUInt64((long)address + 0xb8, thread.Context.ThreadState.X23); + memory.WriteUInt64((long)address + 0xc0, thread.Context.ThreadState.X24); + memory.WriteUInt64((long)address + 0xc8, thread.Context.ThreadState.X25); + memory.WriteUInt64((long)address + 0xd0, thread.Context.ThreadState.X26); + memory.WriteUInt64((long)address + 0xd8, thread.Context.ThreadState.X27); + memory.WriteUInt64((long)address + 0xe0, thread.Context.ThreadState.X28); + memory.WriteUInt64((long)address + 0xe8, thread.Context.ThreadState.X29); + memory.WriteUInt64((long)address + 0xf0, thread.Context.ThreadState.X30); + memory.WriteUInt64((long)address + 0xf8, thread.Context.ThreadState.X31); - _memory.WriteUInt64((long)address + 0x108, (ulong)thread.Context.ThreadState.Psr); + memory.WriteInt64((long)address + 0x100, thread.LastPc); - _memory.WriteVector128((long)address + 0x110, thread.Context.ThreadState.V0); - _memory.WriteVector128((long)address + 0x120, thread.Context.ThreadState.V1); - _memory.WriteVector128((long)address + 0x130, thread.Context.ThreadState.V2); - _memory.WriteVector128((long)address + 0x140, thread.Context.ThreadState.V3); - _memory.WriteVector128((long)address + 0x150, thread.Context.ThreadState.V4); - _memory.WriteVector128((long)address + 0x160, thread.Context.ThreadState.V5); - _memory.WriteVector128((long)address + 0x170, thread.Context.ThreadState.V6); - _memory.WriteVector128((long)address + 0x180, thread.Context.ThreadState.V7); - _memory.WriteVector128((long)address + 0x190, thread.Context.ThreadState.V8); - _memory.WriteVector128((long)address + 0x1a0, thread.Context.ThreadState.V9); - _memory.WriteVector128((long)address + 0x1b0, thread.Context.ThreadState.V10); - _memory.WriteVector128((long)address + 0x1c0, thread.Context.ThreadState.V11); - _memory.WriteVector128((long)address + 0x1d0, thread.Context.ThreadState.V12); - _memory.WriteVector128((long)address + 0x1e0, thread.Context.ThreadState.V13); - _memory.WriteVector128((long)address + 0x1f0, thread.Context.ThreadState.V14); - _memory.WriteVector128((long)address + 0x200, thread.Context.ThreadState.V15); - _memory.WriteVector128((long)address + 0x210, thread.Context.ThreadState.V16); - _memory.WriteVector128((long)address + 0x220, thread.Context.ThreadState.V17); - _memory.WriteVector128((long)address + 0x230, thread.Context.ThreadState.V18); - _memory.WriteVector128((long)address + 0x240, thread.Context.ThreadState.V19); - _memory.WriteVector128((long)address + 0x250, thread.Context.ThreadState.V20); - _memory.WriteVector128((long)address + 0x260, thread.Context.ThreadState.V21); - _memory.WriteVector128((long)address + 0x270, thread.Context.ThreadState.V22); - _memory.WriteVector128((long)address + 0x280, thread.Context.ThreadState.V23); - _memory.WriteVector128((long)address + 0x290, thread.Context.ThreadState.V24); - _memory.WriteVector128((long)address + 0x2a0, thread.Context.ThreadState.V25); - _memory.WriteVector128((long)address + 0x2b0, thread.Context.ThreadState.V26); - _memory.WriteVector128((long)address + 0x2c0, thread.Context.ThreadState.V27); - _memory.WriteVector128((long)address + 0x2d0, thread.Context.ThreadState.V28); - _memory.WriteVector128((long)address + 0x2e0, thread.Context.ThreadState.V29); - _memory.WriteVector128((long)address + 0x2f0, thread.Context.ThreadState.V30); - _memory.WriteVector128((long)address + 0x300, thread.Context.ThreadState.V31); + memory.WriteUInt64((long)address + 0x108, (ulong)thread.Context.ThreadState.Psr); - _memory.WriteInt32((long)address + 0x310, thread.Context.ThreadState.Fpcr); - _memory.WriteInt32((long)address + 0x314, thread.Context.ThreadState.Fpsr); - _memory.WriteInt64((long)address + 0x318, thread.Context.ThreadState.Tpidr); + memory.WriteVector128((long)address + 0x110, thread.Context.ThreadState.V0); + memory.WriteVector128((long)address + 0x120, thread.Context.ThreadState.V1); + memory.WriteVector128((long)address + 0x130, thread.Context.ThreadState.V2); + memory.WriteVector128((long)address + 0x140, thread.Context.ThreadState.V3); + memory.WriteVector128((long)address + 0x150, thread.Context.ThreadState.V4); + memory.WriteVector128((long)address + 0x160, thread.Context.ThreadState.V5); + memory.WriteVector128((long)address + 0x170, thread.Context.ThreadState.V6); + memory.WriteVector128((long)address + 0x180, thread.Context.ThreadState.V7); + memory.WriteVector128((long)address + 0x190, thread.Context.ThreadState.V8); + memory.WriteVector128((long)address + 0x1a0, thread.Context.ThreadState.V9); + memory.WriteVector128((long)address + 0x1b0, thread.Context.ThreadState.V10); + memory.WriteVector128((long)address + 0x1c0, thread.Context.ThreadState.V11); + memory.WriteVector128((long)address + 0x1d0, thread.Context.ThreadState.V12); + memory.WriteVector128((long)address + 0x1e0, thread.Context.ThreadState.V13); + memory.WriteVector128((long)address + 0x1f0, thread.Context.ThreadState.V14); + memory.WriteVector128((long)address + 0x200, thread.Context.ThreadState.V15); + memory.WriteVector128((long)address + 0x210, thread.Context.ThreadState.V16); + memory.WriteVector128((long)address + 0x220, thread.Context.ThreadState.V17); + memory.WriteVector128((long)address + 0x230, thread.Context.ThreadState.V18); + memory.WriteVector128((long)address + 0x240, thread.Context.ThreadState.V19); + memory.WriteVector128((long)address + 0x250, thread.Context.ThreadState.V20); + memory.WriteVector128((long)address + 0x260, thread.Context.ThreadState.V21); + memory.WriteVector128((long)address + 0x270, thread.Context.ThreadState.V22); + memory.WriteVector128((long)address + 0x280, thread.Context.ThreadState.V23); + memory.WriteVector128((long)address + 0x290, thread.Context.ThreadState.V24); + memory.WriteVector128((long)address + 0x2a0, thread.Context.ThreadState.V25); + memory.WriteVector128((long)address + 0x2b0, thread.Context.ThreadState.V26); + memory.WriteVector128((long)address + 0x2c0, thread.Context.ThreadState.V27); + memory.WriteVector128((long)address + 0x2d0, thread.Context.ThreadState.V28); + memory.WriteVector128((long)address + 0x2e0, thread.Context.ThreadState.V29); + memory.WriteVector128((long)address + 0x2f0, thread.Context.ThreadState.V30); + memory.WriteVector128((long)address + 0x300, thread.Context.ThreadState.V31); + + memory.WriteInt32((long)address + 0x310, thread.Context.ThreadState.Fpcr); + memory.WriteInt32((long)address + 0x314, thread.Context.ThreadState.Fpsr); + memory.WriteInt64((long)address + 0x318, thread.Context.ThreadState.Tpidr); return KernelResult.Success; } diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs index ecda9e2d00..6e5b478251 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcThreadSync.cs @@ -25,7 +25,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall for (int index = 0; index < handlesCount; index++) { - int handle = _memory.ReadInt32((long)handlesPtr + index * 4); + int handle = _process.CpuMemory.ReadInt32((long)handlesPtr + index * 4); KSynchronizationObject syncObj = _process.HandleTable.GetObject(handle); From 504f4f4abfd34696699fbf484264404f3011ec17 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 25 Feb 2019 20:46:34 -0300 Subject: [PATCH 12/36] Remove all the calls to StaticCast methods (#605) --- .../Instructions/InstEmitMemoryHelper.cs | 21 +- .../Instructions/InstEmitSimdArithmetic.cs | 342 ++++++++---------- ChocolArm64/Instructions/InstEmitSimdCmp.cs | 12 +- ChocolArm64/Instructions/InstEmitSimdCvt.cs | 10 +- .../Instructions/InstEmitSimdHelper.cs | 113 +----- .../Instructions/InstEmitSimdLogical.cs | 46 +-- ChocolArm64/Instructions/InstEmitSimdMove.cs | 36 +- ChocolArm64/Instructions/InstEmitSimdShift.cs | 56 +-- ChocolArm64/Instructions/VectorHelper.cs | 198 ---------- 9 files changed, 245 insertions(+), 589 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitMemoryHelper.cs b/ChocolArm64/Instructions/InstEmitMemoryHelper.cs index 7645e36316..c225cdd8cc 100644 --- a/ChocolArm64/Instructions/InstEmitMemoryHelper.cs +++ b/ChocolArm64/Instructions/InstEmitMemoryHelper.cs @@ -200,7 +200,7 @@ namespace ChocolArm64.Instructions switch (size) { - case 2: context.EmitCall(typeof(Sse), nameof(Sse.LoadScalarVector128)); break; + case 2: context.EmitCall(typeof(Sse), nameof(Sse.LoadScalarVector128)); break; case 3: { @@ -208,12 +208,10 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.LoadScalarVector128), types)); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleToSingle)); - break; } - case 4: context.EmitCall(typeof(Sse), nameof(Sse.LoadAlignedVector128)); break; + case 4: context.EmitCall(typeof(Sse), nameof(Sse.LoadAlignedVector128)); break; throw new InvalidOperationException($"Invalid vector load size of {1 << size} bytes."); } @@ -283,18 +281,9 @@ namespace ChocolArm64.Instructions switch (size) { - case 2: context.EmitCall(typeof(Sse), nameof(Sse.StoreScalar)); break; - - case 3: - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToDouble)); - - context.EmitCall(typeof(Sse2), nameof(Sse2.StoreScalar)); - - break; - } - - case 4: context.EmitCall(typeof(Sse), nameof(Sse.StoreAligned)); break; + case 2: context.EmitCall(typeof(Sse), nameof(Sse.StoreScalar)); break; + case 3: context.EmitCall(typeof(Sse2), nameof(Sse2.StoreScalar)); break; + case 4: context.EmitCall(typeof(Sse), nameof(Sse.StoreAligned)); break; default: throw new InvalidOperationException($"Invalid vector store size of {1 << size} bytes."); } diff --git a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs index acb9f7f093..f7236e9a4a 100644 --- a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs +++ b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs @@ -194,8 +194,7 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), typesSubAndNot)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAndNot)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAndNot)); context.EmitStvec(op.Rd); @@ -209,14 +208,13 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesSubAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAndNot)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAndNot)); - - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); EmitVectorZeroUpper(context, op.Rd); } @@ -252,8 +250,7 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesSubAndNot)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAndNot)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAndNot)); context.EmitStvec(op.Rd); @@ -270,14 +267,13 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSubAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAndNot)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAndNot)); - - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -321,11 +317,11 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNot)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); EmitVectorZeroUpper(context, op.Rd); } @@ -374,11 +370,11 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNot)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -445,12 +441,12 @@ namespace ChocolArm64.Instructions { Type[] typesAddH = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitCall(typeof(Sse3).GetMethod(nameof(Sse3.HorizontalAdd), typesAddH)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); EmitVectorZeroUpper(context, op.Rd); } @@ -536,14 +532,14 @@ namespace ChocolArm64.Instructions { Type[] typesMulAdd = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Ra); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Ra); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulAdd)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AddScalar), typesMulAdd)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); EmitVectorZeroUpper(context, op.Rd); } @@ -718,14 +714,14 @@ namespace ChocolArm64.Instructions { Type[] typesMulAdd = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Rd); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulAdd)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -751,18 +747,14 @@ namespace ChocolArm64.Instructions Type[] typesMulAdd = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulAdd)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Add), typesMulAdd)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Add), typesMulAdd)); context.EmitStvec(op.Rd); @@ -776,21 +768,17 @@ namespace ChocolArm64.Instructions Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }; Type[] typesMulAdd = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Rd); - - EmitLdvecWithCastToDouble(context, op.Rn); - - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); - + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulAdd)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -841,14 +829,14 @@ namespace ChocolArm64.Instructions { Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Rd); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -874,17 +862,13 @@ namespace ChocolArm64.Instructions Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rd); - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesMulSub)); context.EmitStvec(op.Rd); @@ -899,21 +883,17 @@ namespace ChocolArm64.Instructions Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }; Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Rd); - - EmitLdvecWithCastToDouble(context, op.Rn); - - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); - + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -950,14 +930,14 @@ namespace ChocolArm64.Instructions { Type[] typesMulSub = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Ra); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Ra); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesMulSub)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); EmitVectorZeroUpper(context, op.Rd); } @@ -1020,13 +1000,11 @@ namespace ChocolArm64.Instructions Type[] typesMul = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMul)); context.EmitStvec(op.Rd); @@ -1041,17 +1019,15 @@ namespace ChocolArm64.Instructions Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128), typeof(byte) }; Type[] typesMul = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Rn); - - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); - + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMul)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -1125,11 +1101,11 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXor)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); EmitVectorZeroUpper(context, op.Rd); } @@ -1175,11 +1151,11 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXor)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -1242,8 +1218,7 @@ namespace ChocolArm64.Instructions int sizeF = op.Size & 1; - if (Optimizations.FastFP && Optimizations.UseSse - && sizeF == 0) + if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) { EmitScalarSseOrSse2OpF(context, nameof(Sse.ReciprocalScalar)); } @@ -1262,8 +1237,7 @@ namespace ChocolArm64.Instructions int sizeF = op.Size & 1; - if (Optimizations.FastFP && Optimizations.UseSse - && sizeF == 0) + if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) { EmitVectorSseOrSse2OpF(context, nameof(Sse.Reciprocal)); } @@ -1310,13 +1284,13 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(2d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesMulSub)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); EmitVectorZeroUpper(context, op.Rd); } @@ -1367,13 +1341,13 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(2d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -1579,8 +1553,7 @@ namespace ChocolArm64.Instructions int sizeF = op.Size & 1; - if (Optimizations.FastFP && Optimizations.UseSse - && sizeF == 0) + if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) { EmitScalarSseOrSse2OpF(context, nameof(Sse.ReciprocalSqrtScalar)); } @@ -1599,8 +1572,7 @@ namespace ChocolArm64.Instructions int sizeF = op.Size & 1; - if (Optimizations.FastFP && Optimizations.UseSse - && sizeF == 0) + if (Optimizations.FastFP && Optimizations.UseSse && sizeF == 0) { EmitVectorSseOrSse2OpF(context, nameof(Sse.ReciprocalSqrt)); } @@ -1654,14 +1626,14 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(3d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyScalar), typesMulSub)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); EmitVectorZeroUpper(context, op.Rd); } @@ -1719,14 +1691,14 @@ namespace ChocolArm64.Instructions context.EmitLdc_R8(3d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - EmitLdvecWithCastToDouble(context, op.Rn); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } else @@ -1864,11 +1836,11 @@ namespace ChocolArm64.Instructions VectorHelper.EmitCall(context, namesSzv[op.Size]); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -1953,14 +1925,14 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -1969,7 +1941,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithSignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -1999,9 +1971,8 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithSignedCast(context, op.Rn, op.Size + 1); - - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2010,7 +1981,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithSignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -2027,12 +1998,12 @@ namespace ChocolArm64.Instructions Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAndXorAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitStvectmp2(); @@ -2046,10 +2017,9 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(1); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesSra)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); - - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2083,23 +2053,21 @@ namespace ChocolArm64.Instructions context.EmitStvectmp(); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAddSub)); context.Emit(OpCodes.Dup); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdvectmp(); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAddSub)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvg)); - + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAddSub)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvg)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesAddSub)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2128,12 +2096,12 @@ namespace ChocolArm64.Instructions Type typeSse = op.Size == 1 ? typeof(Sse2) : typeof(Sse41); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2169,12 +2137,12 @@ namespace ChocolArm64.Instructions Type typeSse = op.Size == 1 ? typeof(Sse2) : typeof(Sse41); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeSse.GetMethod(nameof(Sse2.Min), typesMin)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2219,16 +2187,15 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithSignedCast(context, op.Rd, op.Size + 1); - - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2239,7 +2206,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - EmitStvecWithSignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -2279,16 +2246,15 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithSignedCast(context, op.Rd, op.Size + 1); - - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2299,7 +2265,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - EmitStvecWithSignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -2426,20 +2392,19 @@ namespace ChocolArm64.Instructions context.Emit(OpCodes.Dup); context.EmitStvectmp(); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSubAdd)); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSubAdd)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvg)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesSubAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvg)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesSubAdd)); - - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2478,14 +2443,14 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2494,7 +2459,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - EmitStvecWithSignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -2519,9 +2484,8 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithSignedCast(context, op.Rn, op.Size + 1); - - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2530,7 +2494,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - EmitStvecWithSignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -2632,14 +2596,14 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2648,7 +2612,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -2697,9 +2661,8 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size + 1); - - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2708,7 +2671,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -2725,12 +2688,12 @@ namespace ChocolArm64.Instructions Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAndXorAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitStvectmp2(); @@ -2744,10 +2707,9 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(1); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); - - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2774,16 +2736,15 @@ namespace ChocolArm64.Instructions { Type[] typesAvgSub = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvgSub)); + context.EmitLdvec(op.Rm); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvgSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesAvgSub)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2812,12 +2773,12 @@ namespace ChocolArm64.Instructions Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2853,12 +2814,12 @@ namespace ChocolArm64.Instructions Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeSse.GetMethod(nameof(Sse2.Min), typesMin)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -2903,16 +2864,15 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithUnsignedCast(context, op.Rd, op.Size + 1); - - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2923,7 +2883,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -2963,16 +2923,15 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithUnsignedCast(context, op.Rd, op.Size + 1); - - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -2983,7 +2942,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -3052,12 +3011,12 @@ namespace ChocolArm64.Instructions { Type[] typesAvg = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvg)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -3106,14 +3065,14 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -3122,7 +3081,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -3147,9 +3106,8 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size + 1); - - EmitLdvecWithUnsignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); @@ -3158,7 +3116,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { diff --git a/ChocolArm64/Instructions/InstEmitSimdCmp.cs b/ChocolArm64/Instructions/InstEmitSimdCmp.cs index fdf3951e64..c29dcd9dc5 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCmp.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCmp.cs @@ -382,7 +382,7 @@ namespace ChocolArm64.Instructions ILLabel lblNaN = new ILLabel(); ILLabel lblEnd = new ILLabel(); - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); @@ -393,7 +393,7 @@ namespace ChocolArm64.Instructions } else { - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rm); } context.Emit(OpCodes.Dup); @@ -656,12 +656,12 @@ namespace ChocolArm64.Instructions if (!isLeOrLt) { - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); } if (op is OpCodeSimdReg64 binOp) { - EmitLdvecWithCastToDouble(context, binOp.Rm); + context.EmitLdvec(binOp.Rm); } else { @@ -670,12 +670,12 @@ namespace ChocolArm64.Instructions if (isLeOrLt) { - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); } context.EmitCall(typeof(Sse2).GetMethod(name, types)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); if (scalar) { diff --git a/ChocolArm64/Instructions/InstEmitSimdCvt.cs b/ChocolArm64/Instructions/InstEmitSimdCvt.cs index 11105d891f..78a86a33eb 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCvt.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCvt.cs @@ -23,7 +23,7 @@ namespace ChocolArm64.Instructions //Double -> Single. VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; @@ -42,7 +42,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), types)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } else { @@ -91,7 +91,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Double), typesCvt)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } else { @@ -154,7 +154,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); context.Emit(OpCodes.Dup); @@ -332,7 +332,7 @@ namespace ChocolArm64.Instructions { Type[] typesCvt = new Type[] { typeof(Vector128) }; - EmitLdvecWithSignedCast(context, op.Rn, 2); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); diff --git a/ChocolArm64/Instructions/InstEmitSimdHelper.cs b/ChocolArm64/Instructions/InstEmitSimdHelper.cs index 5a44e1a148..b7dd09b4bb 100644 --- a/ChocolArm64/Instructions/InstEmitSimdHelper.cs +++ b/ChocolArm64/Instructions/InstEmitSimdHelper.cs @@ -86,13 +86,13 @@ namespace ChocolArm64.Instructions { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); Type baseType = VectorIntTypesPerSizeLog2[op.Size]; if (op is OpCodeSimdReg64 binOp) { - EmitLdvecWithSignedCast(context, binOp.Rm, op.Size); + context.EmitLdvec(binOp.Rm); context.EmitCall(type.GetMethod(name, new Type[] { baseType, baseType })); } @@ -101,7 +101,7 @@ namespace ChocolArm64.Instructions context.EmitCall(type.GetMethod(name, new Type[] { baseType })); } - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -109,80 +109,6 @@ namespace ChocolArm64.Instructions } } - public static void EmitLdvecWithSignedCast(ILEmitterCtx context, int reg, int size) - { - context.EmitLdvec(reg); - - switch (size) - { - case 0: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToSByte)); break; - case 1: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToInt16)); break; - case 2: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToInt32)); break; - case 3: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToInt64)); break; - - default: throw new ArgumentOutOfRangeException(nameof(size)); - } - } - - public static void EmitLdvecWithCastToDouble(ILEmitterCtx context, int reg) - { - context.EmitLdvec(reg); - - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToDouble)); - } - - public static void EmitStvecWithCastFromDouble(ILEmitterCtx context, int reg) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleToSingle)); - - context.EmitStvec(reg); - } - - public static void EmitLdvecWithUnsignedCast(ILEmitterCtx context, int reg, int size) - { - context.EmitLdvec(reg); - - switch (size) - { - case 0: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToByte)); break; - case 1: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToUInt16)); break; - case 2: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToUInt32)); break; - case 3: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToUInt64)); break; - - default: throw new ArgumentOutOfRangeException(nameof(size)); - } - } - - public static void EmitStvecWithSignedCast(ILEmitterCtx context, int reg, int size) - { - switch (size) - { - case 0: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSByteToSingle)); break; - case 1: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInt16ToSingle)); break; - case 2: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInt32ToSingle)); break; - case 3: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInt64ToSingle)); break; - - default: throw new ArgumentOutOfRangeException(nameof(size)); - } - - context.EmitStvec(reg); - } - - public static void EmitStvecWithUnsignedCast(ILEmitterCtx context, int reg, int size) - { - switch (size) - { - case 0: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorByteToSingle)); break; - case 1: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorUInt16ToSingle)); break; - case 2: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorUInt32ToSingle)); break; - case 3: VectorHelper.EmitCall(context, nameof(VectorHelper.VectorUInt64ToSingle)); break; - - default: throw new ArgumentOutOfRangeException(nameof(size)); - } - - context.EmitStvec(reg); - } - public static void EmitScalarSseOrSse2OpF(ILEmitterCtx context, string name) { EmitSseOrSse2OpF(context, name, true); @@ -199,17 +125,7 @@ namespace ChocolArm64.Instructions int sizeF = op.Size & 1; - void Ldvec(int reg) - { - context.EmitLdvec(reg); - - if (sizeF == 1) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleToDouble)); - } - } - - Ldvec(op.Rn); + context.EmitLdvec(op.Rn); Type type; Type baseType; @@ -227,7 +143,7 @@ namespace ChocolArm64.Instructions if (op is OpCodeSimdReg64 binOp) { - Ldvec(binOp.Rm); + context.EmitLdvec(binOp.Rm); context.EmitCall(type.GetMethod(name, new Type[] { baseType, baseType })); } @@ -236,11 +152,6 @@ namespace ChocolArm64.Instructions context.EmitCall(type.GetMethod(name, new Type[] { baseType })); } - if (sizeF == 1) - { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleToSingle)); - } - context.EmitStvec(op.Rd); if (scalar) @@ -1014,12 +925,12 @@ namespace ChocolArm64.Instructions { Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithCastToDouble(context, op.Rn); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); - EmitLdvecWithCastToDouble(context, op.Rm); + context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); context.EmitStvectmp2(); @@ -1033,7 +944,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(name, types)); - EmitStvecWithCastFromDouble(context, op.Rd); + context.EmitStvec(op.Rd); } } @@ -1277,13 +1188,9 @@ namespace ChocolArm64.Instructions } // TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned). - public static void EmitSatQ( - ILEmitterCtx context, - int sizeDst, - bool signedSrc, - bool signedDst) + public static void EmitSatQ(ILEmitterCtx context, int sizeDst, bool signedSrc, bool signedDst) { - if (sizeDst > 2) + if ((uint)sizeDst > 2) { throw new ArgumentOutOfRangeException(nameof(sizeDst)); } diff --git a/ChocolArm64/Instructions/InstEmitSimdLogical.cs b/ChocolArm64/Instructions/InstEmitSimdLogical.cs index 3473fc5d98..6c718182db 100644 --- a/ChocolArm64/Instructions/InstEmitSimdLogical.cs +++ b/ChocolArm64/Instructions/InstEmitSimdLogical.cs @@ -32,12 +32,12 @@ namespace ChocolArm64.Instructions Type[] typesAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithUnsignedCast(context, op.Rm, 0); - EmitLdvecWithUnsignedCast(context, op.Rn, 0); + context.EmitLdvec(op.Rm); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNot)); - EmitStvecWithUnsignedCast(context, op.Rd, 0); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -83,16 +83,16 @@ namespace ChocolArm64.Instructions string nameAndNot = notRm ? nameof(Sse2.AndNot) : nameof(Sse2.And); - EmitLdvecWithUnsignedCast(context, op.Rd, 0); - EmitLdvecWithUnsignedCast(context, op.Rm, 0); - EmitLdvecWithUnsignedCast(context, op.Rn, 0); - EmitLdvecWithUnsignedCast(context, op.Rd, 0); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rm); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rd); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAndNot)); context.EmitCall(typeof(Sse2).GetMethod(nameAndNot, typesXorAndNot)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAndNot)); - EmitStvecWithUnsignedCast(context, op.Rd, 0); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -141,20 +141,20 @@ namespace ChocolArm64.Instructions Type[] typesXorAnd = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithUnsignedCast(context, op.Rm, 0); + context.EmitLdvec(op.Rm); context.Emit(OpCodes.Dup); - EmitLdvecWithUnsignedCast(context, op.Rn, 0); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); - EmitLdvecWithUnsignedCast(context, op.Rd, 0); + context.EmitLdvec(op.Rd); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesXorAnd)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); - EmitStvecWithUnsignedCast(context, op.Rd, 0); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -199,14 +199,14 @@ namespace ChocolArm64.Instructions Type[] typesSav = new Type[] { typeof(byte) }; Type[] typesAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithUnsignedCast(context, op.Rn, 0); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(byte.MaxValue); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNot)); - EmitStvecWithUnsignedCast(context, op.Rd, 0); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -228,8 +228,8 @@ namespace ChocolArm64.Instructions Type[] typesSav = new Type[] { typeof(byte) }; Type[] typesAndNotOr = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithUnsignedCast(context, op.Rn, 0); - EmitLdvecWithUnsignedCast(context, op.Rm, 0); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(byte.MaxValue); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); @@ -237,7 +237,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNotOr)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndNotOr)); - EmitStvecWithUnsignedCast(context, op.Rd, 0); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -305,7 +305,7 @@ namespace ChocolArm64.Instructions Type[] typesSve = new Type[] { typeof(long), typeof(long) }; Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithSignedCast(context, op.Rn, 0); // value + context.EmitLdvec(op.Rn); // value context.EmitLdc_I8(14L << 56 | 15L << 48 | 12L << 40 | 13L << 32 | 10L << 24 | 11L << 16 | 08L << 8 | 09L << 0); // maskE1 context.EmitLdc_I8(06L << 56 | 07L << 48 | 04L << 40 | 05L << 32 | 02L << 24 | 03L << 16 | 00L << 8 | 01L << 0); // maskE0 @@ -314,7 +314,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); - EmitStvecWithSignedCast(context, op.Rd, 0); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -336,7 +336,7 @@ namespace ChocolArm64.Instructions Type[] typesSve = new Type[] { typeof(long), typeof(long) }; Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); // value + context.EmitLdvec(op.Rn); // value if (op.Size == 0) { @@ -353,7 +353,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -375,7 +375,7 @@ namespace ChocolArm64.Instructions Type[] typesSve = new Type[] { typeof(long), typeof(long) }; Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); // value + context.EmitLdvec(op.Rn); // value if (op.Size == 0) { @@ -397,7 +397,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { diff --git a/ChocolArm64/Instructions/InstEmitSimdMove.cs b/ChocolArm64/Instructions/InstEmitSimdMove.cs index 2844dfdf4c..7145263d38 100644 --- a/ChocolArm64/Instructions/InstEmitSimdMove.cs +++ b/ChocolArm64/Instructions/InstEmitSimdMove.cs @@ -59,7 +59,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); } else { @@ -108,7 +108,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); } else { @@ -138,7 +138,7 @@ namespace ChocolArm64.Instructions Type[] typesShs = new Type[] { typeof(Vector128), typeof(byte) }; Type[] typesOr = new Type[] { typeof(Vector128), typeof(Vector128) }; - EmitLdvecWithUnsignedCast(context, op.Rn, 0); + context.EmitLdvec(op.Rn); if (op.RegisterSize == RegisterSize.Simd64) { @@ -150,7 +150,7 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(op.Imm4); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesShs)); - EmitLdvecWithUnsignedCast(context, op.Rm, 0); + context.EmitLdvec(op.Rm); context.EmitLdc_I4((op.RegisterSize == RegisterSize.Simd64 ? 8 : 16) - op.Imm4); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical128BitLane), typesShs)); @@ -164,7 +164,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); - EmitStvecWithUnsignedCast(context, op.Rd, 0); + context.EmitStvec(op.Rd); } else { @@ -418,7 +418,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); - EmitLdvecWithSignedCast(context, op.Rn, 0); // value + context.EmitLdvec(op.Rn); // value context.EmitLdc_I8(_masksE0_TrnUzpXtn[op.Size]); // mask context.Emit(OpCodes.Dup); // mask @@ -492,7 +492,7 @@ namespace ChocolArm64.Instructions ? nameof(Sse2.UnpackLow) : nameof(Sse2.UnpackHigh); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); // value + context.EmitLdvec(op.Rn); // value if (op.Size < 3) { @@ -504,7 +504,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); } - EmitLdvecWithSignedCast(context, op.Rm, op.Size); // value + context.EmitLdvec(op.Rm); // value if (op.Size < 3) { @@ -518,7 +518,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(op.Size))); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); } else { @@ -560,7 +560,7 @@ namespace ChocolArm64.Instructions if (op.RegisterSize == RegisterSize.Simd128) { - EmitLdvecWithSignedCast(context, op.Rn, op.Size); // value + context.EmitLdvec(op.Rn); // value if (op.Size < 3) { @@ -572,7 +572,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); } - EmitLdvecWithSignedCast(context, op.Rm, op.Size); // value + context.EmitLdvec(op.Rm); // value if (op.Size < 3) { @@ -586,12 +586,12 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(3))); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); } else { - EmitLdvecWithSignedCast(context, op.Rn, op.Size); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackLow), GetTypesSflUpk(op.Size))); // value @@ -609,7 +609,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(3))); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); } } else @@ -648,8 +648,8 @@ namespace ChocolArm64.Instructions ? nameof(Sse2.UnpackLow) : nameof(Sse2.UnpackHigh); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); - EmitLdvecWithSignedCast(context, op.Rm, op.Size); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); if (op.RegisterSize == RegisterSize.Simd128) { @@ -663,7 +663,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(3))); } - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); } else { diff --git a/ChocolArm64/Instructions/InstEmitSimdShift.cs b/ChocolArm64/Instructions/InstEmitSimdShift.cs index 843052110f..c0b20d7ea6 100644 --- a/ChocolArm64/Instructions/InstEmitSimdShift.cs +++ b/ChocolArm64/Instructions/InstEmitSimdShift.cs @@ -42,12 +42,12 @@ namespace ChocolArm64.Instructions { Type[] typesSll = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -82,7 +82,7 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); @@ -92,7 +92,7 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -280,7 +280,7 @@ namespace ChocolArm64.Instructions int shift = GetImmShr(op); int eSize = 8 << op.Size; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); @@ -298,7 +298,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -329,8 +329,8 @@ namespace ChocolArm64.Instructions int shift = GetImmShr(op); int eSize = 8 << op.Size; - EmitLdvecWithSignedCast(context, op.Rd, op.Size); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); @@ -349,7 +349,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -405,7 +405,7 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); @@ -415,7 +415,7 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); - EmitStvecWithSignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -437,12 +437,12 @@ namespace ChocolArm64.Instructions { Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(GetImmShr(op)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesSra)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -470,15 +470,15 @@ namespace ChocolArm64.Instructions Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - EmitLdvecWithSignedCast(context, op.Rd, op.Size); - EmitLdvecWithSignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(GetImmShr(op)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesSra)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithSignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -610,7 +610,7 @@ namespace ChocolArm64.Instructions int shift = GetImmShr(op); int eSize = 8 << op.Size; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); @@ -628,7 +628,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -658,8 +658,8 @@ namespace ChocolArm64.Instructions int shift = GetImmShr(op); int eSize = 8 << op.Size; - EmitLdvecWithUnsignedCast(context, op.Rd, op.Size); - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); context.Emit(OpCodes.Dup); context.EmitStvectmp(); @@ -678,7 +678,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -734,7 +734,7 @@ namespace ChocolArm64.Instructions int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(numBytes); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); @@ -744,7 +744,7 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size + 1); + context.EmitStvec(op.Rd); } else { @@ -765,12 +765,12 @@ namespace ChocolArm64.Instructions { Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(GetImmShr(op)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { @@ -797,15 +797,15 @@ namespace ChocolArm64.Instructions Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; - EmitLdvecWithUnsignedCast(context, op.Rd, op.Size); - EmitLdvecWithUnsignedCast(context, op.Rn, op.Size); + context.EmitLdvec(op.Rd); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(GetImmShr(op)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); - EmitStvecWithUnsignedCast(context, op.Rd, op.Size); + context.EmitStvec(op.Rd); if (op.RegisterSize == RegisterSize.Simd64) { diff --git a/ChocolArm64/Instructions/VectorHelper.cs b/ChocolArm64/Instructions/VectorHelper.cs index f02c131e68..edb3428d85 100644 --- a/ChocolArm64/Instructions/VectorHelper.cs +++ b/ChocolArm64/Instructions/VectorHelper.cs @@ -565,203 +565,5 @@ namespace ChocolArm64.Instructions throw new PlatformNotSupportedException(); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToSByte(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToInt16(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToInt32(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToInt64(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToByte(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToUInt16(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToUInt32(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToUInt64(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSingleToDouble(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSByteToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorInt16ToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorInt32ToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorInt64ToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorByteToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorUInt16ToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorUInt32ToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorUInt64ToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorDoubleToSingle(Vector128 vector) - { - if (Sse.IsSupported) - { - return Sse.StaticCast(vector); - } - - throw new PlatformNotSupportedException(); - } } } From ef3f9a2abe85cfd572ab6bec73481e3526762dcc Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 26 Feb 2019 06:16:50 -0300 Subject: [PATCH 13/36] Optmize BFM instruction (#607) --- ChocolArm64/Instructions/InstEmitBfm.cs | 55 ++++++++++++++++++++----- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitBfm.cs b/ChocolArm64/Instructions/InstEmitBfm.cs index d25af8be8a..4a03959940 100644 --- a/ChocolArm64/Instructions/InstEmitBfm.cs +++ b/ChocolArm64/Instructions/InstEmitBfm.cs @@ -11,21 +11,56 @@ namespace ChocolArm64.Instructions { OpCodeBfm64 op = (OpCodeBfm64)context.CurrOp; - EmitBfmLoadRn(context); + if (op.Pos < op.Shift) + { + //BFI. + context.EmitLdintzr(op.Rn); - context.EmitLdintzr(op.Rd); - context.EmitLdc_I(~op.WMask & op.TMask); + int shift = op.GetBitsCount() - op.Shift; - context.Emit(OpCodes.And); - context.Emit(OpCodes.Or); + int width = op.Pos + 1; - context.EmitLdintzr(op.Rd); - context.EmitLdc_I(~op.TMask); + long mask = (long)(ulong.MaxValue >> (64 - width)); - context.Emit(OpCodes.And); - context.Emit(OpCodes.Or); + context.EmitLdc_I(mask); - context.EmitStintzr(op.Rd); + context.Emit(OpCodes.And); + + context.EmitLsl(shift); + + context.EmitLdintzr(op.Rd); + + context.EmitLdc_I(~(mask << shift)); + + context.Emit(OpCodes.And); + context.Emit(OpCodes.Or); + + context.EmitStintzr(op.Rd); + } + else + { + //BFXIL. + context.EmitLdintzr(op.Rn); + + context.EmitLsr(op.Shift); + + int width = op.Pos - op.Shift + 1; + + long mask = (long)(ulong.MaxValue >> (64 - width)); + + context.EmitLdc_I(mask); + + context.Emit(OpCodes.And); + + context.EmitLdintzr(op.Rd); + + context.EmitLdc_I(~mask); + + context.Emit(OpCodes.And); + context.Emit(OpCodes.Or); + + context.EmitStintzr(op.Rd); + } } public static void Sbfm(ILEmitterCtx context) From 81aa50feb0899e73ee62e5113b786efe0ff6b7a9 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 26 Feb 2019 09:50:36 -0300 Subject: [PATCH 14/36] Optimize MOVI/MVNI instructions using intrinsics (#606) --- ChocolArm64/Instructions/InstEmitSimdMove.cs | 50 +++++++++++++++++++- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitSimdMove.cs b/ChocolArm64/Instructions/InstEmitSimdMove.cs index 7145263d38..20647ce09d 100644 --- a/ChocolArm64/Instructions/InstEmitSimdMove.cs +++ b/ChocolArm64/Instructions/InstEmitSimdMove.cs @@ -318,12 +318,26 @@ namespace ChocolArm64.Instructions public static void Movi_V(ILEmitterCtx context) { - EmitVectorImmUnaryOp(context, () => { }); + if (Optimizations.UseSse2) + { + EmitMoviMvni(context, not: false); + } + else + { + EmitVectorImmUnaryOp(context, () => { }); + } } public static void Mvni_V(ILEmitterCtx context) { - EmitVectorImmUnaryOp(context, () => context.Emit(OpCodes.Not)); + if (Optimizations.UseSse2) + { + EmitMoviMvni(context, not: true); + } + else + { + EmitVectorImmUnaryOp(context, () => context.Emit(OpCodes.Not)); + } } public static void Smov_S(ILEmitterCtx context) @@ -480,6 +494,38 @@ namespace ChocolArm64.Instructions } } + private static void EmitMoviMvni(ILEmitterCtx context, bool not) + { + OpCodeSimdImm64 op = (OpCodeSimdImm64)context.CurrOp; + + Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size] }; + + long imm = op.Imm; + + if (not) + { + imm = ~imm; + } + + if (op.Size < 3) + { + context.EmitLdc_I4((int)imm); + } + else + { + context.EmitLdc_I8(imm); + } + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + private static void EmitVectorTranspose(ILEmitterCtx context, int part) { OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; From 884b4e5fd3c2a54ebb796b7f995c0eda9c4d0038 Mon Sep 17 00:00:00 2001 From: Thomas Guillemard Date: Thu, 28 Feb 2019 02:12:24 +0100 Subject: [PATCH 15/36] Initial non 2D textures support (#525) * Initial non 2D textures support - Shaders still need to be changed - Some types aren't yet implemented * Start implementing texture instructions suffixes Fix wrong texture type with cube and TEXS Also support array textures in TEX and TEX.B Clean up TEX and TEXS coords managment Fix TEXS.LL with non-2d textures Implement TEX.AOFFI Get the right arguments for TEX, TEXS and TLDS Also, store suffix operands in appropriate values to support multiple suffix combinaisons * Support depth in read/writeTexture Also support WrapR and detect mipmap * Proper cube map textures support + fix TEXS.LZ * Implement depth compare * some code clean up * Implement CubeMap textures in OGLTexture.Create * Implement TLD4 and TLD4S * Add Texture 1D support * updates comments * fix some code style issues * Fix some nits + rename some things to be less confusing * Remove GetSuffix local functions * AOFFI => AOffI * TextureType => GalTextureTarget * finish renaming TextureType to TextureTarget * Disable LL, LZ and LB support in the decompiler This needs more work at the GL level (GLSL implementation should be right) * Revert "Disable LL, LZ and LB support in the decompiler" This reverts commit 64536c3d9f673645faff3152838d1413c3203395. * Fix TEXS ARRAY_2D index * ImageFormat depth should be 1 for all image format * Fix shader build issues with sampler1DShadow and texture * Fix DC & AOFFI combinaison with TEX/TEXS * Support AOFFI with TLD4 and TLD4S * Fix shader compilation error for TLD4.AOFFI with no DC * Fix binding isuses on the 2d copy engine TODO: support 2d array copy * Support 2D array copy operation in the 2D engine This make every copy right in the GPU side. Thie CPU copy probably needs to be updated * Implement GetGpuSize + fix somes issues with 2d engine copies TODO: mipmap level in it * Don't throw an exception in the layer handling * Fix because of rebase * Reject 2d layers of non textures in 2d copy engine * Add 3D textures and mipmap support on BlockLinearSwizzle * Fix naming on new BitUtils methods * gpu cache: Make sure to invalidate textures that doesn't have the same target * Add the concept of layer count for array instead of using depth Also cleanup GetGpuSize as Swizzle can compute the size with mipmap * Support multi layer with mip map in ReadTexture * Add more check for cache invalidation & remove cubemap and cubemap array code for now Also fix compressed 2d array * Fix texelFetchOffset shader build error * Start looking into cube map again Also add some way to log write in register in engines * fix write register log levles * Remove debug logs in WriteRegister * Disable AOFFI support on non NVIDIA drivers * Fix code align --- Ryujinx.Common/Utilities/BitUtils.cs | 35 + Ryujinx.Graphics/DepthCompareFunc.cs | 14 + Ryujinx.Graphics/Gal/GalImage.cs | 36 +- Ryujinx.Graphics/Gal/GalTextureSampler.cs | 10 +- Ryujinx.Graphics/Gal/GalTextureTarget.cs | 15 + Ryujinx.Graphics/Gal/IGalRenderTarget.cs | 24 +- Ryujinx.Graphics/Gal/IGalTexture.cs | 2 +- Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs | 1 + .../Gal/OpenGL/OGLEnumConverter.cs | 25 + Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs | 7 + .../Gal/OpenGL/OGLRenderTarget.cs | 55 +- Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs | 2 +- Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs | 256 ++++++-- Ryujinx.Graphics/Gal/Shader/GlslDecl.cs | 26 +- Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 322 ++++++++- .../Gal/Shader/ShaderDecodeMem.cs | 613 +++++++++++++++++- .../Gal/Shader/ShaderDecodeOpCode.cs | 5 + Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs | 1 + .../Gal/Shader/ShaderIrMetaTex.cs | 18 +- .../Gal/Shader/ShaderOpCodeTable.cs | 2 + Ryujinx.Graphics/Gal/ShaderDeclInfo.cs | 23 +- Ryujinx.Graphics/GpuResourceManager.cs | 33 +- Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs | 96 ++- .../Graphics3d/NvGpuEngine2dReg.cs | 2 + Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs | 14 +- .../Graphics3d/NvGpuEngine3dReg.cs | 217 ++++--- .../Graphics3d/NvGpuEngineM2mf.cs | 21 +- .../Graphics3d/NvGpuEngineP2mf.cs | 8 +- .../Graphics3d/Texture/ASTCDecoder.cs | 1 + .../Graphics3d/Texture/BlockLinearSwizzle.cs | 171 ++++- .../Graphics3d/Texture/ISwizzle.cs | 8 +- .../Graphics3d/Texture/ImageUtils.cs | 239 +++++-- .../Graphics3d/Texture/LinearSwizzle.cs | 36 +- .../Graphics3d/Texture/TextureFactory.cs | 65 +- .../Graphics3d/Texture/TextureHelper.cs | 17 +- .../Texture/TextureInstructionSuffix.cs | 19 + Ryujinx.Graphics/VDec/VideoDecoder.cs | 7 +- Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs | 6 +- Ryujinx.ShaderTools/Program.cs | 2 +- 39 files changed, 2084 insertions(+), 370 deletions(-) create mode 100644 Ryujinx.Graphics/DepthCompareFunc.cs create mode 100644 Ryujinx.Graphics/Gal/GalTextureTarget.cs create mode 100644 Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs diff --git a/Ryujinx.Common/Utilities/BitUtils.cs b/Ryujinx.Common/Utilities/BitUtils.cs index 135b397d3d..b6fba4fba1 100644 --- a/Ryujinx.Common/Utilities/BitUtils.cs +++ b/Ryujinx.Common/Utilities/BitUtils.cs @@ -34,6 +34,11 @@ namespace Ryujinx.Common return value & -(long)size; } + public static int DivRoundUp(int value, int dividend) + { + return (value + dividend - 1) / dividend; + } + public static ulong DivRoundUp(ulong value, uint dividend) { return (value + dividend - 1) / dividend; @@ -44,6 +49,24 @@ namespace Ryujinx.Common return (value + dividend - 1) / dividend; } + public static int Pow2RoundUp(int value) + { + value--; + + value |= (value >> 1); + value |= (value >> 2); + value |= (value >> 4); + value |= (value >> 8); + value |= (value >> 16); + + return ++value; + } + + public static int Pow2RoundDown(int value) + { + return IsPowerOfTwo32(value) ? value : Pow2RoundUp(value) >> 1; + } + public static bool IsPowerOfTwo32(int value) { return value != 0 && (value & (value - 1)) == 0; @@ -85,6 +108,18 @@ namespace Ryujinx.Common return (ulong)count; } + public static int CountTrailingZeros32(int value) + { + int count = 0; + + while (((value >> count) & 1) == 0) + { + count++; + } + + return count; + } + public static long ReverseBits64(long value) { return (long)ReverseBits64((ulong)value); diff --git a/Ryujinx.Graphics/DepthCompareFunc.cs b/Ryujinx.Graphics/DepthCompareFunc.cs new file mode 100644 index 0000000000..24c8854a4b --- /dev/null +++ b/Ryujinx.Graphics/DepthCompareFunc.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.Graphics +{ + public enum DepthCompareFunc + { + Never = 0, + Less = 1, + Equal = 2, + LEqual = 3, + Greater = 4, + NotEqual = 5, + GEqual = 6, + Always = 7 + } +} diff --git a/Ryujinx.Graphics/Gal/GalImage.cs b/Ryujinx.Graphics/Gal/GalImage.cs index 92f43cc9d4..fb904b0925 100644 --- a/Ryujinx.Graphics/Gal/GalImage.cs +++ b/Ryujinx.Graphics/Gal/GalImage.cs @@ -6,9 +6,15 @@ namespace Ryujinx.Graphics.Gal { public int Width; public int Height; + + // FIXME: separate layer and depth + public int Depth; + public int LayerCount; public int TileWidth; public int GobBlockHeight; + public int GobBlockDepth; public int Pitch; + public int MaxMipmapLevel; public GalImageFormat Format; public GalMemoryLayout Layout; @@ -16,34 +22,45 @@ namespace Ryujinx.Graphics.Gal public GalTextureSource YSource; public GalTextureSource ZSource; public GalTextureSource WSource; + public GalTextureTarget TextureTarget; public GalImage( int Width, int Height, + int Depth, + int LayerCount, int TileWidth, int GobBlockHeight, + int GobBlockDepth, GalMemoryLayout Layout, GalImageFormat Format, - GalTextureSource XSource = GalTextureSource.Red, - GalTextureSource YSource = GalTextureSource.Green, - GalTextureSource ZSource = GalTextureSource.Blue, - GalTextureSource WSource = GalTextureSource.Alpha) + GalTextureTarget TextureTarget, + int MaxMipmapLevel = 1, + GalTextureSource XSource = GalTextureSource.Red, + GalTextureSource YSource = GalTextureSource.Green, + GalTextureSource ZSource = GalTextureSource.Blue, + GalTextureSource WSource = GalTextureSource.Alpha) { this.Width = Width; this.Height = Height; + this.LayerCount = LayerCount; + this.Depth = Depth; this.TileWidth = TileWidth; this.GobBlockHeight = GobBlockHeight; + this.GobBlockDepth = GobBlockDepth; this.Layout = Layout; this.Format = Format; + this.MaxMipmapLevel = MaxMipmapLevel; this.XSource = XSource; this.YSource = YSource; this.ZSource = ZSource; this.WSource = WSource; + this.TextureTarget = TextureTarget; Pitch = ImageUtils.GetPitch(Format, Width); } - public bool SizeMatches(GalImage Image) + public bool SizeMatches(GalImage Image, bool IgnoreLayer = false) { if (ImageUtils.GetBytesPerPixel(Format) != ImageUtils.GetBytesPerPixel(Image.Format)) @@ -57,7 +74,14 @@ namespace Ryujinx.Graphics.Gal return false; } - return Height == Image.Height; + bool Result = Height == Image.Height && Depth == Image.Depth; + + if (!IgnoreLayer) + { + Result = Result && LayerCount == Image.LayerCount; + } + + return Result; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalTextureSampler.cs b/Ryujinx.Graphics/Gal/GalTextureSampler.cs index b9e5c7658d..1d658cea85 100644 --- a/Ryujinx.Graphics/Gal/GalTextureSampler.cs +++ b/Ryujinx.Graphics/Gal/GalTextureSampler.cs @@ -12,6 +12,9 @@ namespace Ryujinx.Graphics.Gal public GalColorF BorderColor { get; private set; } + public bool DepthCompare { get; private set; } + public DepthCompareFunc DepthCompareFunc { get; private set; } + public GalTextureSampler( GalTextureWrap AddressU, GalTextureWrap AddressV, @@ -19,7 +22,9 @@ namespace Ryujinx.Graphics.Gal GalTextureFilter MinFilter, GalTextureFilter MagFilter, GalTextureMipFilter MipFilter, - GalColorF BorderColor) + GalColorF BorderColor, + bool DepthCompare, + DepthCompareFunc DepthCompareFunc) { this.AddressU = AddressU; this.AddressV = AddressV; @@ -28,6 +33,9 @@ namespace Ryujinx.Graphics.Gal this.MagFilter = MagFilter; this.MipFilter = MipFilter; this.BorderColor = BorderColor; + + this.DepthCompare = DepthCompare; + this.DepthCompareFunc = DepthCompareFunc; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalTextureTarget.cs b/Ryujinx.Graphics/Gal/GalTextureTarget.cs new file mode 100644 index 0000000000..bcc0c49a51 --- /dev/null +++ b/Ryujinx.Graphics/Gal/GalTextureTarget.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Graphics.Gal +{ + public enum GalTextureTarget + { + OneD = 0, + TwoD = 1, + ThreeD = 2, + CubeMap = 3, + OneDArray = 4, + TwoDArray = 5, + OneDBuffer = 6, + TwoDNoMipMap = 7, + CubeArray = 8, + } +} diff --git a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs index f941ccd584..90cad856d9 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs @@ -25,16 +25,20 @@ namespace Ryujinx.Graphics.Gal void Render(); void Copy( - long SrcKey, - long DstKey, - int SrcX0, - int SrcY0, - int SrcX1, - int SrcY1, - int DstX0, - int DstY0, - int DstX1, - int DstY1); + GalImage SrcImage, + GalImage DstImage, + long SrcKey, + long DstKey, + int SrcLayer, + int DstLayer, + int SrcX0, + int SrcY0, + int SrcX1, + int SrcY1, + int DstX0, + int DstY0, + int DstX1, + int DstY1); void Reinterpret(long Key, GalImage NewImage); } diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs index aeecdf1ac5..de4ba9cba7 100644 --- a/Ryujinx.Graphics/Gal/IGalTexture.cs +++ b/Ryujinx.Graphics/Gal/IGalTexture.cs @@ -13,6 +13,6 @@ namespace Ryujinx.Graphics.Gal void Bind(long Key, int Index, GalImage Image); - void SetSampler(GalTextureSampler Sampler); + void SetSampler(GalImage Image, GalTextureSampler Sampler); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs index 8db0b8a8c9..5714f3d891 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL public int Width => Image.Width; public int Height => Image.Height; + public int Depth => Image.Depth; public GalImageFormat Format => Image.Format; diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs index f2afe7b556..3a25fff7a5 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs @@ -189,6 +189,31 @@ namespace Ryujinx.Graphics.Gal.OpenGL throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}"); } + public static All GetDepthCompareFunc(DepthCompareFunc DepthCompareFunc) + { + switch (DepthCompareFunc) + { + case DepthCompareFunc.LEqual: + return All.Lequal; + case DepthCompareFunc.GEqual: + return All.Gequal; + case DepthCompareFunc.Less: + return All.Less; + case DepthCompareFunc.Greater: + return All.Greater; + case DepthCompareFunc.Equal: + return All.Equal; + case DepthCompareFunc.NotEqual: + return All.Notequal; + case DepthCompareFunc.Always: + return All.Always; + case DepthCompareFunc.Never: + return All.Never; + default: + throw new ArgumentException(nameof(DepthCompareFunc) + " \"" + DepthCompareFunc + "\" is not valid!"); + } + } + public static InternalFormat GetCompressedImageFormat(GalImageFormat Format) { switch (Format) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs index 11daeb593c..52b3d0ce31 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs @@ -9,9 +9,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL private static Lazy s_TextureMirrorClamp = new Lazy(() => HasExtension("GL_EXT_texture_mirror_clamp")); private static Lazy s_ViewportArray = new Lazy(() => HasExtension("GL_ARB_viewport_array")); + private static Lazy s_NvidiaDriver = new Lazy(() => IsNvidiaDriver()); + public static bool EnhancedLayouts => s_EnhancedLayouts.Value; public static bool TextureMirrorClamp => s_TextureMirrorClamp.Value; public static bool ViewportArray => s_ViewportArray.Value; + public static bool NvidiaDrvier => s_NvidiaDriver.Value; private static bool HasExtension(string Name) { @@ -27,5 +30,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL return false; } + + private static bool IsNvidiaDriver() { + return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation"); + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs index 0d7bb3cd0a..8dd3b37fc2 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs @@ -389,16 +389,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL } public void Copy( - long SrcKey, - long DstKey, - int SrcX0, - int SrcY0, - int SrcX1, - int SrcY1, - int DstX0, - int DstY0, - int DstX1, - int DstY1) + GalImage SrcImage, + GalImage DstImage, + long SrcKey, + long DstKey, + int SrcLayer, + int DstLayer, + int SrcX0, + int SrcY0, + int SrcX1, + int SrcY1, + int DstX0, + int DstY0, + int DstX1, + int DstY1) { if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) && Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex)) @@ -425,8 +429,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL FramebufferAttachment Attachment = GetAttachment(SrcTex); - GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0); - GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0); + if (ImageUtils.IsArray(SrcImage.TextureTarget) && SrcLayer > 0) + { + GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0, SrcLayer); + } + else + { + GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0); + } + + if (ImageUtils.IsArray(DstImage.TextureTarget) && DstLayer > 0) + { + GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0, DstLayer); + } + else + { + GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0); + } + BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest; @@ -452,7 +472,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL if (NewImage.Format == OldImage.Format && NewImage.Width == OldImage.Width && - NewImage.Height == OldImage.Height) + NewImage.Height == OldImage.Height && + NewImage.Depth == OldImage.Depth && + NewImage.LayerCount == OldImage.LayerCount && + NewImage.TextureTarget == OldImage.TextureTarget) { return; } @@ -477,9 +500,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format); - GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle); + TextureTarget Target = ImageUtils.GetTextureTarget(NewImage.TextureTarget); - GL.GetTexImage(TextureTarget.Texture2D, 0, Format, Type, IntPtr.Zero); + GL.BindTexture(Target, CachedImage.Handle); + + GL.GetTexImage(Target, 0, Format, Type, IntPtr.Zero); GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs index 10a9120df2..dc168ff919 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs @@ -53,7 +53,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GlslProgram Program; - GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize); + GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize, OGLExtension.NvidiaDrvier); int ShaderDumpIndex = ShaderDumper.DumpIndex; diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index ef984b1ed3..4fef11d296 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -38,7 +38,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL { int Handle = GL.GenTexture(); - GL.BindTexture(TextureTarget.Texture2D, Handle); + TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget); + + GL.BindTexture(Target, Handle); const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; @@ -54,23 +56,70 @@ namespace Ryujinx.Graphics.Gal.OpenGL PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); - GL.TexImage2D( - TextureTarget.Texture2D, - Level, - InternalFmt, - Image.Width, - Image.Height, - Border, - Format, - Type, - IntPtr.Zero); + switch (Target) + { + case TextureTarget.Texture1D: + GL.TexImage1D( + Target, + Level, + InternalFmt, + Image.Width, + Border, + Format, + Type, + IntPtr.Zero); + break; + + case TextureTarget.Texture2D: + GL.TexImage2D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Border, + Format, + Type, + IntPtr.Zero); + break; + case TextureTarget.Texture3D: + GL.TexImage3D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Image.Depth, + Border, + Format, + Type, + IntPtr.Zero); + break; + case TextureTarget.Texture2DArray: + GL.TexImage3D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Image.LayerCount, + Border, + Format, + Type, + IntPtr.Zero); + break; + default: + throw new NotImplementedException($"Unsupported texture target type: {Target}"); + } } public void Create(long Key, byte[] Data, GalImage Image) { int Handle = GL.GenTexture(); - GL.BindTexture(TextureTarget.Texture2D, Handle); + TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget); + + GL.BindTexture(Target, Handle); const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; @@ -81,15 +130,56 @@ namespace Ryujinx.Graphics.Gal.OpenGL { InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format); - GL.CompressedTexImage2D( - TextureTarget.Texture2D, - Level, - InternalFmt, - Image.Width, - Image.Height, - Border, - Data.Length, - Data); + switch (Target) + { + case TextureTarget.Texture1D: + GL.CompressedTexImage1D( + Target, + Level, + InternalFmt, + Image.Width, + Border, + Data.Length, + Data); + break; + case TextureTarget.Texture2D: + GL.CompressedTexImage2D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Border, + Data.Length, + Data); + break; + case TextureTarget.Texture3D: + GL.CompressedTexImage3D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Image.Depth, + Border, + Data.Length, + Data); + break; + case TextureTarget.Texture2DArray: + GL.CompressedTexImage3D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Image.LayerCount, + Border, + Data.Length, + Data); + break; + default: + throw new NotImplementedException($"Unsupported texture target type: {Target}"); + } } else { @@ -98,13 +188,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL { int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format); int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format); + int TextureBlockDepth = ImageUtils.GetBlockDepth(Image.Format); Data = ASTCDecoder.DecodeToRGBA8888( Data, TextureBlockWidth, - TextureBlockHeight, 1, + TextureBlockHeight, + TextureBlockDepth, Image.Width, - Image.Height, 1); + Image.Height, + Image.Depth); Image.Format = GalImageFormat.RGBA8 | (Image.Format & GalImageFormat.TypeMask); } @@ -113,16 +206,80 @@ namespace Ryujinx.Graphics.Gal.OpenGL PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); - GL.TexImage2D( - TextureTarget.Texture2D, - Level, - InternalFmt, - Image.Width, - Image.Height, - Border, - Format, - Type, - Data); + + switch (Target) + { + case TextureTarget.Texture1D: + GL.TexImage1D( + Target, + Level, + InternalFmt, + Image.Width, + Border, + Format, + Type, + Data); + break; + case TextureTarget.Texture2D: + GL.TexImage2D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Border, + Format, + Type, + Data); + break; + case TextureTarget.Texture3D: + GL.TexImage3D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Image.Depth, + Border, + Format, + Type, + Data); + break; + case TextureTarget.Texture2DArray: + GL.TexImage3D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Image.LayerCount, + Border, + Format, + Type, + Data); + break; + case TextureTarget.TextureCubeMap: + Span Array = new Span(Data); + + int FaceSize = ImageUtils.GetSize(Image) / 6; + + for (int Face = 0; Face < 6; Face++) + { + GL.TexImage2D( + TextureTarget.TextureCubeMapPositiveX + Face, + Level, + InternalFmt, + Image.Width, + Image.Height, + Border, + Format, + Type, + Array.Slice(Face * FaceSize, FaceSize).ToArray()); + } + break; + default: + throw new NotImplementedException($"Unsupported texture target type: {Target}"); + } } } @@ -165,7 +322,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GL.ActiveTexture(TextureUnit.Texture0 + Index); - GL.BindTexture(TextureTarget.Texture2D, CachedImage.Handle); + TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget); + + GL.BindTexture(Target, CachedImage.Handle); int[] SwizzleRgba = new int[] { @@ -175,23 +334,27 @@ namespace Ryujinx.Graphics.Gal.OpenGL (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource) }; - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, SwizzleRgba); + GL.TexParameter(Target, TextureParameterName.TextureSwizzleRgba, SwizzleRgba); } } - public void SetSampler(GalTextureSampler Sampler) + public void SetSampler(GalImage Image, GalTextureSampler Sampler) { int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU); int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV); + int WrapR = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressP); int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter); int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, WrapS); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, WrapT); + TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, MinFilter); - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, MagFilter); + GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS); + GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT); + GL.TexParameter(Target, TextureParameterName.TextureWrapR, WrapR); + + GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter); + GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter); float[] Color = new float[] { @@ -201,7 +364,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL Sampler.BorderColor.Alpha }; - GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, Color); + GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color); + + if (Sampler.DepthCompare) + { + GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture); + GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)OGLEnumConverter.GetDepthCompareFunc(Sampler.DepthCompareFunc)); + } + else + { + GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.None); + GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)All.Never); + } } } } diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index 43923da742..f7ae34faa5 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -1,3 +1,5 @@ +using Ryujinx.Graphics.Gal.OpenGL; +using Ryujinx.Graphics.Texture; using System; using System.Collections.Generic; @@ -224,6 +226,7 @@ namespace Ryujinx.Graphics.Gal.Shader if (Op.Inst == ShaderIrInst.Texq || Op.Inst == ShaderIrInst.Texs || + Op.Inst == ShaderIrInst.Tld4 || Op.Inst == ShaderIrInst.Txlf) { int Handle = ((ShaderIrOperImm)Op.OperandC).Value; @@ -232,7 +235,25 @@ namespace Ryujinx.Graphics.Gal.Shader string Name = StagePrefix + TextureName + Index; - m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle)); + GalTextureTarget TextureTarget; + + TextureInstructionSuffix TextureInstructionSuffix; + + // TODO: Non 2D texture type for TEXQ? + if (Op.Inst == ShaderIrInst.Texq) + { + TextureTarget = GalTextureTarget.TwoD; + TextureInstructionSuffix = TextureInstructionSuffix.None; + } + else + { + ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData); + + TextureTarget = Meta.TextureTarget; + TextureInstructionSuffix = Meta.TextureInstructionSuffix; + } + + m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle, false, 0, 1, TextureTarget, TextureInstructionSuffix)); } else if (Op.Inst == ShaderIrInst.Texb) { @@ -257,9 +278,10 @@ namespace Ryujinx.Graphics.Gal.Shader if (HandleSrc != null && HandleSrc is ShaderIrOperCbuf Cbuf) { + ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData); string Name = StagePrefix + TextureName + "_cb" + Cbuf.Index + "_" + Cbuf.Pos; - m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index)); + m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index, 1, Meta.TextureTarget, Meta.TextureInstructionSuffix)); } else { diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 854c827ee0..5f809525f9 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -1,3 +1,5 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Texture; using System; using System.Collections.Generic; using System.Globalization; @@ -33,7 +35,9 @@ namespace Ryujinx.Graphics.Gal.Shader public int MaxUboSize { get; } - public GlslDecompiler(int MaxUboSize) + private bool IsNvidiaDriver; + + public GlslDecompiler(int MaxUboSize, bool IsNvidiaDriver) { InstsExpr = new Dictionary() { @@ -103,6 +107,7 @@ namespace Ryujinx.Graphics.Gal.Shader { ShaderIrInst.Texb, GetTexbExpr }, { ShaderIrInst.Texq, GetTexqExpr }, { ShaderIrInst.Texs, GetTexsExpr }, + { ShaderIrInst.Tld4, GetTld4Expr }, { ShaderIrInst.Trunc, GetTruncExpr }, { ShaderIrInst.Txlf, GetTxlfExpr }, { ShaderIrInst.Utof, GetUtofExpr }, @@ -110,6 +115,7 @@ namespace Ryujinx.Graphics.Gal.Shader }; this.MaxUboSize = MaxUboSize / 16; + this.IsNvidiaDriver = IsNvidiaDriver; } public GlslProgram Decompile( @@ -219,14 +225,70 @@ namespace Ryujinx.Graphics.Gal.Shader } } + private string GetSamplerType(TextureTarget TextureTarget, bool HasShadow) + { + string Result; + + switch (TextureTarget) + { + case TextureTarget.Texture1D: + Result = "sampler1D"; + break; + case TextureTarget.Texture2D: + Result = "sampler2D"; + break; + case TextureTarget.Texture3D: + Result = "sampler3D"; + break; + case TextureTarget.TextureCubeMap: + Result = "samplerCube"; + break; + case TextureTarget.TextureRectangle: + Result = "sampler2DRect"; + break; + case TextureTarget.Texture1DArray: + Result = "sampler1DArray"; + break; + case TextureTarget.Texture2DArray: + Result = "sampler2DArray"; + break; + case TextureTarget.TextureCubeMapArray: + Result = "samplerCubeArray"; + break; + case TextureTarget.TextureBuffer: + Result = "samplerBuffer"; + break; + case TextureTarget.Texture2DMultisample: + Result = "sampler2DMS"; + break; + case TextureTarget.Texture2DMultisampleArray: + Result = "sampler2DMSArray"; + break; + default: + throw new NotSupportedException(); + } + + if (HasShadow) + Result += "Shadow"; + + return Result; + } + private void PrintDeclTextures() { foreach (ShaderDeclInfo DeclInfo in IterateCbTextures()) { - SB.AppendLine("uniform sampler2D " + DeclInfo.Name + ";"); + TextureTarget Target = ImageUtils.GetTextureTarget(DeclInfo.TextureTarget); + SB.AppendLine($"// {DeclInfo.TextureSuffix}"); + SB.AppendLine("uniform " + GetSamplerType(Target, (DeclInfo.TextureSuffix & TextureInstructionSuffix.DC) != 0) + " " + DeclInfo.Name + ";"); } - PrintDecls(Decl.Textures, "uniform sampler2D"); + foreach (ShaderDeclInfo DeclInfo in Decl.Textures.Values.OrderBy(DeclKeySelector)) + { + TextureTarget Target = ImageUtils.GetTextureTarget(DeclInfo.TextureTarget); + SB.AppendLine($"// {DeclInfo.TextureSuffix}"); + SB.AppendLine("uniform " + GetSamplerType(Target, (DeclInfo.TextureSuffix & TextureInstructionSuffix.DC) != 0) + " " + DeclInfo.Name + ";"); + } } private IEnumerable IterateCbTextures() @@ -778,6 +840,7 @@ namespace Ryujinx.Graphics.Gal.Shader case ShaderIrInst.Ipa: case ShaderIrInst.Texq: case ShaderIrInst.Texs: + case ShaderIrInst.Tld4: case ShaderIrInst.Txlf: return false; } @@ -1124,7 +1187,7 @@ namespace Ryujinx.Graphics.Gal.Shader string Ch = "rgba".Substring(Meta.Elem, 1); - return "texture(" + DeclInfo.Name + ", " + Coords + ")." + Ch; + return GetTextureOperation(Op, DeclInfo.Name, Coords, Ch); } private string GetTexqExpr(ShaderIrOp Op) @@ -1157,20 +1220,50 @@ namespace Ryujinx.Graphics.Gal.Shader string Ch = "rgba".Substring(Meta.Elem, 1); - return "texture(" + Sampler + ", " + Coords + ")." + Ch; + return GetTextureOperation(Op, Sampler, Coords, Ch); } - private string GetTxlfExpr(ShaderIrOp Op) + private string GetTld4Expr(ShaderIrOp Op) { ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; string Sampler = GetTexSamplerName(Op); + string Coords = GetTexSamplerCoords(Op); + + string Ch = "rgba".Substring(Meta.Elem, 1); + + return GetTextureGatherOperation(Op, Sampler, Coords, Ch); + } + + // TODO: support AOFFI on non nvidia drivers + private string GetTxlfExpr(ShaderIrOp Op) + { + // TODO: Support all suffixes + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + + string Sampler = GetTexSamplerName(Op); + string Coords = GetITexSamplerCoords(Op); string Ch = "rgba".Substring(Meta.Elem, 1); - return "texelFetch(" + Sampler + ", " + Coords + ", 0)." + Ch; + string Lod = "0"; + + if (Meta.LevelOfDetail != null) + { + Lod = GetOperExpr(Op, Meta.LevelOfDetail); + } + + if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + { + string Offset = GetTextureOffset(Meta, GetOperExpr(Op, Meta.Offset)); + return "texelFetchOffset(" + Sampler + ", " + Coords + ", " + Lod + ", " + Offset + ")." + Ch; + } + + return "texelFetch(" + Sampler + ", " + Coords + ", " + Lod + ")." + Ch; } private string GetTruncExpr(ShaderIrOp Op) => GetUnaryCall(Op, "trunc"); @@ -1246,14 +1339,205 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetTexSamplerCoords(ShaderIrOp Op) { - return "vec2(" + GetOperExpr(Op, Op.OperandA) + ", " + - GetOperExpr(Op, Op.OperandB) + ")"; + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + bool HasDepth = (Meta.TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0; + + int Coords = ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget); + + bool IsArray = ImageUtils.IsArray(Meta.TextureTarget); + + + string GetLastArgument(ShaderIrNode Node) + { + string Result = GetOperExpr(Op, Node); + + // array index is actually an integer so we need to pass it correctly + if (IsArray) + { + Result = "float(floatBitsToInt(" + Result + "))"; + } + + return Result; + } + + string LastArgument; + string DepthArgument = ""; + + int VecSize = Coords; + if (HasDepth && Op.Inst != ShaderIrInst.Tld4) + { + VecSize++; + DepthArgument = $", {GetOperExpr(Op, Meta.DepthCompare)}"; + } + + switch (Coords) + { + case 1: + if (HasDepth) + { + return $"vec3({GetOperExpr(Op, Meta.Coordinates[0])}, 0.0{DepthArgument})"; + } + + return GetOperExpr(Op, Meta.Coordinates[0]); + case 2: + LastArgument = GetLastArgument(Meta.Coordinates[1]); + + return $"vec{VecSize}({GetOperExpr(Op, Meta.Coordinates[0])}, {LastArgument}{DepthArgument})"; + case 3: + LastArgument = GetLastArgument(Meta.Coordinates[2]); + + return $"vec{VecSize}({GetOperExpr(Op, Meta.Coordinates[0])}, {GetOperExpr(Op, Meta.Coordinates[1])}, {LastArgument}{DepthArgument})"; + case 4: + LastArgument = GetLastArgument(Meta.Coordinates[3]); + + return $"vec4({GetOperExpr(Op, Meta.Coordinates[0])}, {GetOperExpr(Op, Meta.Coordinates[1])}, {GetOperExpr(Op, Meta.Coordinates[2])}, {LastArgument}){DepthArgument}"; + default: + throw new InvalidOperationException(); + } + + } + + private string GetTextureOffset(ShaderIrMetaTex Meta, string Oper, int Shift = 4, int Mask = 0xF) + { + string GetOffset(string Operation, int Index) + { + return $"({Operation} >> {Index * Shift}) & 0x{Mask:x}"; + } + + int Coords = ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget); + + if (ImageUtils.IsArray(Meta.TextureTarget)) + Coords -= 1; + + switch (Coords) + { + case 1: + return GetOffset(Oper, 0); + case 2: + return "ivec2(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ")"; + case 3: + return "ivec3(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ")"; + case 4: + return "ivec4(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ", " + GetOffset(Oper, 3) + ")"; + default: + throw new InvalidOperationException(); + } + } + + // TODO: support AOFFI on non nvidia drivers + private string GetTextureGatherOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch) + { + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + + string ChString = "." + Ch; + + string Comp = Meta.Component.ToString(); + + if ((Suffix & TextureInstructionSuffix.DC) != 0) + { + Comp = GetOperExpr(Op, Meta.DepthCompare); + } + + if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))", 8, 0x3F); + + if ((Suffix & TextureInstructionSuffix.DC) != 0) + { + return "textureGatherOffset(" + Sampler + ", " + Coords + ", " + Comp + ", " + Offset + ")" + ChString; + } + + return "textureGatherOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + Comp + ")" + ChString; + } + // TODO: Support PTP + else if ((Suffix & TextureInstructionSuffix.PTP) != 0) + { + throw new NotImplementedException(); + } + + return "textureGather(" + Sampler + ", " + Coords + ", " + Comp + ")" + ChString; + } + + // TODO: support AOFFI on non nvidia drivers + private string GetTextureOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch) + { + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + + string ChString = "." + Ch; + + if ((Suffix & TextureInstructionSuffix.DC) != 0) + { + ChString = ""; + } + + // TODO: Support LBA and LLA + if ((Suffix & TextureInstructionSuffix.LZ) != 0) + { + if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + + return "textureLodOffset(" + Sampler + ", " + Coords + ", 0.0, " + Offset + ")" + ChString; + } + + return "textureLod(" + Sampler + ", " + Coords + ", 0.0)" + ChString; + } + else if ((Suffix & TextureInstructionSuffix.LB) != 0) + { + if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + + return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; + } + + return "texture(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; + } + else if ((Suffix & TextureInstructionSuffix.LL) != 0) + { + if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + + return "textureLodOffset(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ", " + Offset + ")" + ChString; + } + + return "textureLod(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; + } + else if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + { + string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + + return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ")" + ChString; + } + else + { + return "texture(" + Sampler + ", " + Coords + ")" + ChString; + } + throw new NotImplementedException($"Texture Suffix {Meta.TextureInstructionSuffix} is not implemented"); + } private string GetITexSamplerCoords(ShaderIrOp Op) { - return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " + - GetOperExpr(Op, Op.OperandB) + ")"; + ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + + switch (ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget)) + { + case 1: + return GetOperExpr(Op, Meta.Coordinates[0]); + case 2: + return "ivec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ")"; + case 3: + return "ivec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ")"; + default: + throw new InvalidOperationException(); + } } private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper) @@ -1292,22 +1576,6 @@ namespace Ryujinx.Graphics.Gal.Shader } break; } - - case ShaderIrOperImm Imm: - { - //For integer immediates being used as float, - //it's better (for readability) to just return the float value. - if (DstType == OperType.F32) - { - float Value = BitConverter.Int32BitsToSingle(Imm.Value); - - if (!float.IsNaN(Value) && !float.IsInfinity(Value)) - { - return GetFloatConst(Value); - } - } - break; - } } switch (DstType) diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index adcc47b955..8b4eacdf20 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs @@ -1,3 +1,4 @@ +using Ryujinx.Graphics.Texture; using System; using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; @@ -29,6 +30,75 @@ namespace Ryujinx.Graphics.Gal.Shader { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ } }; + private static GalTextureTarget TexToTextureTarget(int TexType, bool IsArray) + { + switch (TexType) + { + case 0: + return IsArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD; + case 2: + return IsArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD; + case 4: + if (IsArray) + throw new InvalidOperationException($"ARRAY bit set on a TEX with 3D texture!"); + return GalTextureTarget.ThreeD; + case 6: + return IsArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap; + default: + throw new InvalidOperationException(); + } + } + + private static GalTextureTarget TexsToTextureTarget(int TexType) + { + switch (TexType) + { + case 0: + return GalTextureTarget.OneD; + case 2: + case 4: + case 6: + case 8: + case 0xa: + case 0xc: + return GalTextureTarget.TwoD; + case 0xe: + case 0x10: + case 0x12: + return GalTextureTarget.TwoDArray; + case 0x14: + case 0x16: + return GalTextureTarget.ThreeD; + case 0x18: + case 0x1a: + return GalTextureTarget.CubeMap; + default: + throw new InvalidOperationException(); + } + } + + public static GalTextureTarget TldsToTextureTarget(int TexType) + { + switch (TexType) + { + case 0: + case 2: + return GalTextureTarget.OneD; + case 4: + case 8: + case 0xa: + case 0xc: + case 0x18: + return GalTextureTarget.TwoD; + case 0x10: + return GalTextureTarget.TwoDArray; + case 0xe: + return GalTextureTarget.ThreeD; + default: + throw new InvalidOperationException(); + } + } + public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position) { ShaderIrNode[] Opers = OpCode.Abuf20(); @@ -132,43 +202,166 @@ namespace Ryujinx.Graphics.Gal.Shader public static void Tex(ShaderIrBlock Block, long OpCode, int Position) { - EmitTex(Block, OpCode, GprHandle: false); + TextureInstructionSuffix Suffix; + + int RawSuffix = OpCode.Read(0x34, 0x38); + + switch (RawSuffix) + { + case 0: + Suffix = TextureInstructionSuffix.None; + break; + case 0x8: + Suffix = TextureInstructionSuffix.LZ; + break; + case 0x10: + Suffix = TextureInstructionSuffix.LB; + break; + case 0x18: + Suffix = TextureInstructionSuffix.LL; + break; + case 0x30: + Suffix = TextureInstructionSuffix.LBA; + break; + case 0x38: + Suffix = TextureInstructionSuffix.LLA; + break; + default: + throw new InvalidOperationException($"Invalid Suffix for TEX instruction {RawSuffix}"); + } + + bool IsOffset = OpCode.Read(0x36); + + if (IsOffset) + Suffix |= TextureInstructionSuffix.AOffI; + + EmitTex(Block, OpCode, Suffix, GprHandle: false); } public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position) { - EmitTex(Block, OpCode, GprHandle: true); + TextureInstructionSuffix Suffix; + + int RawSuffix = OpCode.Read(0x24, 0xe); + + switch (RawSuffix) + { + case 0: + Suffix = TextureInstructionSuffix.None; + break; + case 0x2: + Suffix = TextureInstructionSuffix.LZ; + break; + case 0x4: + Suffix = TextureInstructionSuffix.LB; + break; + case 0x6: + Suffix = TextureInstructionSuffix.LL; + break; + case 0xc: + Suffix = TextureInstructionSuffix.LBA; + break; + case 0xe: + Suffix = TextureInstructionSuffix.LLA; + break; + default: + throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {RawSuffix}"); + } + + bool IsOffset = OpCode.Read(0x23); + + if (IsOffset) + Suffix |= TextureInstructionSuffix.AOffI; + + EmitTex(Block, OpCode, Suffix, GprHandle: true); } - private static void EmitTex(ShaderIrBlock Block, long OpCode, bool GprHandle) + private static void EmitTex(ShaderIrBlock Block, long OpCode, TextureInstructionSuffix TextureInstructionSuffix, bool GprHandle) { - //TODO: Support other formats. - ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[2]; + bool IsArray = OpCode.HasArray(); - for (int Index = 0; Index < Coords.Length; Index++) + GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray); + + bool HasDepthCompare = OpCode.Read(0x32); + + if (HasDepthCompare) + { + TextureInstructionSuffix |= TextureInstructionSuffix.DC; + } + + ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)]; + + int IndexExtraCoord = 0; + + if (IsArray) + { + IndexExtraCoord++; + + Coords[Coords.Length - 1] = OpCode.Gpr8(); + } + + + for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++) { ShaderIrOperGpr CoordReg = OpCode.Gpr8(); CoordReg.Index += Index; + CoordReg.Index += IndexExtraCoord; + if (!CoordReg.IsValidRegister) { CoordReg.Index = ShaderIrOperGpr.ZRIndex; } - Coords[Index] = ShaderIrOperGpr.MakeTemporary(Index); - - Block.AddNode(new ShaderIrAsg(Coords[Index], CoordReg)); + Coords[Index] = CoordReg; } int ChMask = OpCode.Read(31, 0xf); + ShaderIrOperGpr LevelOfDetail = null; + ShaderIrOperGpr Offset = null; + ShaderIrOperGpr DepthCompare = null; + + // TODO: determine first argument when TEX.B is used + int OperBIndex = GprHandle ? 1 : 0; + + if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0 || + (TextureInstructionSuffix & TextureInstructionSuffix.LB) != 0 || + (TextureInstructionSuffix & TextureInstructionSuffix.LBA) != 0 || + (TextureInstructionSuffix & TextureInstructionSuffix.LLA) != 0) + { + LevelOfDetail = OpCode.Gpr20(); + LevelOfDetail.Index += OperBIndex; + + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) + { + Offset = OpCode.Gpr20(); + Offset.Index += OperBIndex; + + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + { + DepthCompare = OpCode.Gpr20(); + DepthCompare.Index += OperBIndex; + + OperBIndex++; + } + + // ??? ShaderIrNode OperC = GprHandle ? (ShaderIrNode)OpCode.Gpr20() : (ShaderIrNode)OpCode.Imm13_36(); ShaderIrInst Inst = GprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs; + Coords = CoordsRegistersToTempRegisters(Block, Coords); + int RegInc = 0; for (int Ch = 0; Ch < 4; Ch++) @@ -187,9 +380,14 @@ namespace Ryujinx.Graphics.Gal.Shader continue; } - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); + ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords) + { + LevelOfDetail = LevelOfDetail, + Offset = Offset, + DepthCompare = DepthCompare + }; - ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], OperC, Meta); + ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords.Length > 1 ? Coords[1] : null, OperC, Meta); Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); } @@ -197,17 +395,238 @@ namespace Ryujinx.Graphics.Gal.Shader public static void Texs(ShaderIrBlock Block, long OpCode, int Position) { - EmitTexs(Block, OpCode, ShaderIrInst.Texs); + TextureInstructionSuffix Suffix; + + int RawSuffix = OpCode.Read(0x34, 0x1e); + + switch (RawSuffix) + { + case 0: + case 0x4: + case 0x10: + case 0x16: + Suffix = TextureInstructionSuffix.LZ; + break; + case 0x6: + case 0x1a: + Suffix = TextureInstructionSuffix.LL; + break; + case 0x8: + Suffix = TextureInstructionSuffix.DC; + break; + case 0x2: + case 0xe: + case 0x14: + case 0x18: + Suffix = TextureInstructionSuffix.None; + break; + case 0xa: + Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.DC; + break; + case 0xc: + case 0x12: + Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.DC; + break; + default: + throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {RawSuffix}"); + } + + GalTextureTarget TextureTarget = TexsToTextureTarget(OpCode.Read(52, 0x1e)); + + EmitTexs(Block, OpCode, ShaderIrInst.Texs, TextureTarget, Suffix); } public static void Tlds(ShaderIrBlock Block, long OpCode, int Position) { - EmitTexs(Block, OpCode, ShaderIrInst.Txlf); + TextureInstructionSuffix Suffix; + + int RawSuffix = OpCode.Read(0x34, 0x1e); + + switch (RawSuffix) + { + case 0: + case 0x4: + case 0x8: + Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.AOffI; + break; + case 0xc: + Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.MZ; + break; + case 0xe: + case 0x10: + Suffix = TextureInstructionSuffix.LZ; + break; + case 0x2: + case 0xa: + Suffix = TextureInstructionSuffix.LL; + break; + case 0x18: + Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.AOffI; + break; + default: + throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {RawSuffix}"); + } + + GalTextureTarget TextureTarget = TldsToTextureTarget(OpCode.Read(52, 0x1e)); + + EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureTarget, Suffix); } - private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) + public static void Tld4(ShaderIrBlock Block, long OpCode, int Position) { - //TODO: Support other formats. + TextureInstructionSuffix Suffix; + + int RawSuffix = OpCode.Read(0x34, 0xc); + + switch (RawSuffix) + { + case 0: + Suffix = TextureInstructionSuffix.None; + break; + case 0x4: + Suffix = TextureInstructionSuffix.AOffI; + break; + case 0x8: + Suffix = TextureInstructionSuffix.PTP; + break; + default: + throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {RawSuffix}"); + } + + bool IsShadow = OpCode.Read(0x32); + + bool IsArray = OpCode.HasArray(); + int ChMask = OpCode.Read(31, 0xf); + + GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray); + + if (IsShadow) + { + Suffix |= TextureInstructionSuffix.DC; + } + + EmitTld4(Block, OpCode, TextureTarget, Suffix, ChMask, OpCode.Read(0x38, 0x3), false); + } + + public static void Tld4s(ShaderIrBlock Block, long OpCode, int Position) + { + TextureInstructionSuffix Suffix = TextureInstructionSuffix.None; + + bool IsOffset = OpCode.Read(0x33); + bool IsShadow = OpCode.Read(0x32); + + if (IsOffset) + { + Suffix |= TextureInstructionSuffix.AOffI; + } + + if (IsShadow) + { + Suffix |= TextureInstructionSuffix.DC; + } + + // TLD4S seems to only support 2D textures with RGBA mask? + EmitTld4(Block, OpCode, GalTextureTarget.TwoD, Suffix, RGBA, OpCode.Read(0x34, 0x3), true); + } + + private static void EmitTexs(ShaderIrBlock Block, + long OpCode, + ShaderIrInst Inst, + GalTextureTarget TextureTarget, + TextureInstructionSuffix TextureInstructionSuffix) + { + if (Inst == ShaderIrInst.Txlf && TextureTarget == GalTextureTarget.CubeArray) + { + throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!"); + } + + bool IsArray = ImageUtils.IsArray(TextureTarget); + + ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)]; + + ShaderIrOperGpr OperA = OpCode.Gpr8(); + ShaderIrOperGpr OperB = OpCode.Gpr20(); + + ShaderIrOperGpr SuffixExtra = OpCode.Gpr20(); + SuffixExtra.Index += 1; + + int CoordStartIndex = 0; + + if (IsArray) + { + CoordStartIndex++; + Coords[Coords.Length - 1] = OpCode.Gpr8(); + } + + switch (Coords.Length - CoordStartIndex) + { + case 1: + Coords[0] = OpCode.Gpr8(); + + break; + case 2: + Coords[0] = OpCode.Gpr8(); + Coords[0].Index += CoordStartIndex; + + break; + case 3: + Coords[0] = OpCode.Gpr8(); + Coords[0].Index += CoordStartIndex; + + Coords[1] = OpCode.Gpr8(); + Coords[1].Index += 1 + CoordStartIndex; + + break; + default: + throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TEXS"); + } + + int OperBIndex = 0; + + ShaderIrOperGpr LevelOfDetail = null; + ShaderIrOperGpr Offset = null; + ShaderIrOperGpr DepthCompare = null; + + // OperB is always the last value + // Not applicable to 1d textures + if (Coords.Length - CoordStartIndex != 1) + { + Coords[Coords.Length - CoordStartIndex - 1] = OperB; + OperBIndex++; + } + + // Encoding of TEXS/TLDS is a bit special and change for 2d textures + // NOTE: OperA seems to hold at best two args. + // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB. + if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureInstructionSuffix != TextureInstructionSuffix.LZ && TextureTarget == GalTextureTarget.TwoD) + { + Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8(); + Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1; + OperBIndex--; + } + + // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?) + if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0) + { + LevelOfDetail = OpCode.Gpr20(); + LevelOfDetail.Index += OperBIndex; + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) + { + Offset = OpCode.Gpr20(); + Offset.Index += OperBIndex; + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + { + DepthCompare = OpCode.Gpr20(); + DepthCompare.Index += OperBIndex; + OperBIndex++; + } + int LutIndex; LutIndex = !OpCode.Gpr0().IsConst ? 1 : 0; @@ -276,12 +695,7 @@ namespace Ryujinx.Graphics.Gal.Shader } ShaderIrNode OperC = OpCode.Imm13_36(); - - ShaderIrOperGpr Coord0 = ShaderIrOperGpr.MakeTemporary(0); - ShaderIrOperGpr Coord1 = ShaderIrOperGpr.MakeTemporary(1); - - Block.AddNode(new ShaderIrAsg(Coord0, OpCode.Gpr8())); - Block.AddNode(new ShaderIrAsg(Coord1, OpCode.Gpr20())); + Coords = CoordsRegistersToTempRegisters(Block, Coords); for (int Ch = 0; Ch < 4; Ch++) { @@ -290,9 +704,13 @@ namespace Ryujinx.Graphics.Gal.Shader continue; } - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch); - - ShaderIrOp Op = new ShaderIrOp(Inst, Coord0, Coord1, OperC, Meta); + ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords) + { + LevelOfDetail = LevelOfDetail, + Offset = Offset, + DepthCompare = DepthCompare + }; + ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta); ShaderIrOperGpr Dst = GetDst(); @@ -303,9 +721,156 @@ namespace Ryujinx.Graphics.Gal.Shader } } + private static void EmitTld4(ShaderIrBlock Block, long OpCode, GalTextureTarget TextureType, TextureInstructionSuffix TextureInstructionSuffix, int ChMask, int Component, bool Scalar) + { + ShaderIrOperGpr OperA = OpCode.Gpr8(); + ShaderIrOperGpr OperB = OpCode.Gpr20(); + ShaderIrOperImm OperC = OpCode.Imm13_36(); + + ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureType)]; + + ShaderIrOperGpr Offset = null; + ShaderIrOperGpr DepthCompare = null; + + bool IsArray = ImageUtils.IsArray(TextureType); + + int OperBIndex = 0; + + if (Scalar) + { + int CoordStartIndex = 0; + + if (IsArray) + { + CoordStartIndex++; + Coords[Coords.Length - 1] = OperB; + } + + switch (Coords.Length - CoordStartIndex) + { + case 1: + Coords[0] = OpCode.Gpr8(); + + break; + case 2: + Coords[0] = OpCode.Gpr8(); + Coords[0].Index += CoordStartIndex; + + break; + case 3: + Coords[0] = OpCode.Gpr8(); + Coords[0].Index += CoordStartIndex; + + Coords[1] = OpCode.Gpr8(); + Coords[1].Index += 1 + CoordStartIndex; + + break; + default: + throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TLD4S"); + } + + if (Coords.Length - CoordStartIndex != 1) + { + Coords[Coords.Length - CoordStartIndex - 1] = OperB; + OperBIndex++; + } + + if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureType == GalTextureTarget.TwoD) + { + Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8(); + Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1; + OperBIndex--; + } + } + else + { + int IndexExtraCoord = 0; + + if (IsArray) + { + IndexExtraCoord++; + + Coords[Coords.Length - 1] = OpCode.Gpr8(); + } + + for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++) + { + Coords[Index] = OpCode.Gpr8(); + + Coords[Index].Index += Index; + + Coords[Index].Index += IndexExtraCoord; + + if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex) + { + Coords[Index].Index = ShaderIrOperGpr.ZRIndex; + } + } + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) + { + Offset = OpCode.Gpr20(); + Offset.Index += OperBIndex; + OperBIndex++; + } + + if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + { + DepthCompare = OpCode.Gpr20(); + DepthCompare.Index += OperBIndex; + OperBIndex++; + } + + Coords = CoordsRegistersToTempRegisters(Block, Coords); + + int RegInc = 0; + + for (int Ch = 0; Ch < 4; Ch++) + { + if (!IsChannelUsed(ChMask, Ch)) + { + continue; + } + + ShaderIrOperGpr Dst = OpCode.Gpr0(); + + Dst.Index += RegInc++; + + if (!Dst.IsValidRegister || Dst.IsConst) + { + continue; + } + + ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords) + { + Component = Component, + Offset = Offset, + DepthCompare = DepthCompare + }; + + ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Tld4, OperA, OperB, OperC, Meta); + + Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); + } + } + private static bool IsChannelUsed(int ChMask, int Ch) { return (ChMask & (1 << Ch)) != 0; } + + private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock Block, params ShaderIrOperGpr[] Registers) + { + ShaderIrOperGpr[] Res = new ShaderIrOperGpr[Registers.Length]; + + for (int Index = 0; Index < Res.Length; Index++) + { + Res[Index] = ShaderIrOperGpr.MakeTemporary(Index); + Block.AddNode(new ShaderIrAsg(Res[Index], Registers[Index])); + } + + return Res; + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs index f0f92148e6..e241e1ca58 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs @@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gal.Shader return ((int)(OpCode >> 20) << 8) >> 8; } + private static bool HasArray(this long OpCode) + { + return OpCode.Read(0x1c); + } + private static ShaderIrOperAbuf[] Abuf20(this long OpCode) { int Abuf = OpCode.Read(20, 0x3ff); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs index 35dea61216..68ff214e4e 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs @@ -49,6 +49,7 @@ namespace Ryujinx.Graphics.Gal.Shader Ipa, Texb, Texs, + Tld4, Trunc, F_End, diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs index 82f3bb774a..72ea221ad3 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs @@ -1,12 +1,24 @@ +using Ryujinx.Graphics.Texture; + namespace Ryujinx.Graphics.Gal.Shader { class ShaderIrMetaTex : ShaderIrMeta { - public int Elem { get; private set; } + public int Elem { get; private set; } + public GalTextureTarget TextureTarget { get; private set; } + public ShaderIrNode[] Coordinates { get; private set; } + public TextureInstructionSuffix TextureInstructionSuffix { get; private set; } + public ShaderIrOperGpr LevelOfDetail; + public ShaderIrOperGpr Offset; + public ShaderIrOperGpr DepthCompare; + public int Component; // for TLD4(S) - public ShaderIrMetaTex(int Elem) + public ShaderIrMetaTex(int Elem, GalTextureTarget TextureTarget, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates) { - this.Elem = Elem; + this.Elem = Elem; + this.TextureTarget = TextureTarget; + this.TextureInstructionSuffix = TextureInstructionSuffix; + this.Coordinates = Coordinates; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index 177e36c3e1..d2bbd38c6b 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -122,6 +122,8 @@ namespace Ryujinx.Graphics.Gal.Shader Set("1101111101001x", ShaderDecode.Texq); Set("1101x00xxxxxxx", ShaderDecode.Texs); Set("1101101xxxxxxx", ShaderDecode.Tlds); + Set("110010xxxx111x", ShaderDecode.Tld4); + Set("1101111100xxxx", ShaderDecode.Tld4s); Set("01011111xxxxxx", ShaderDecode.Vmad); Set("0100111xxxxxxx", ShaderDecode.Xmad_CR); Set("0011011x00xxxx", ShaderDecode.Xmad_I); diff --git a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs index ef47ca2e1b..ed1955cdbb 100644 --- a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs +++ b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs @@ -1,3 +1,5 @@ +using Ryujinx.Graphics.Texture; + namespace Ryujinx.Graphics.Gal { public class ShaderDeclInfo @@ -9,18 +11,27 @@ namespace Ryujinx.Graphics.Gal public int Cbuf { get; private set; } public int Size { get; private set; } + public GalTextureTarget TextureTarget { get; private set; } + + public TextureInstructionSuffix TextureSuffix { get; private set; } + public ShaderDeclInfo( string Name, int Index, bool IsCb = false, int Cbuf = 0, - int Size = 1) + int Size = 1, + GalTextureTarget TextureTarget = GalTextureTarget.TwoD, + TextureInstructionSuffix TextureSuffix = TextureInstructionSuffix.None) { - this.Name = Name; - this.Index = Index; - this.IsCb = IsCb; - this.Cbuf = Cbuf; - this.Size = Size; + this.Name = Name; + this.Index = Index; + this.IsCb = IsCb; + this.Cbuf = Cbuf; + this.Size = Size; + + this.TextureTarget = TextureTarget; + this.TextureSuffix = TextureSuffix; } internal void Enlarge(int NewSize) diff --git a/Ryujinx.Graphics/GpuResourceManager.cs b/Ryujinx.Graphics/GpuResourceManager.cs index d46129516d..4f2d92b03a 100644 --- a/Ryujinx.Graphics/GpuResourceManager.cs +++ b/Ryujinx.Graphics/GpuResourceManager.cs @@ -1,6 +1,8 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; +using System; using System.Collections.Generic; namespace Ryujinx.Graphics @@ -11,6 +13,7 @@ namespace Ryujinx.Graphics { None, Texture, + TextureArrayLayer, ColorBuffer, ZetaBuffer } @@ -20,6 +23,7 @@ namespace Ryujinx.Graphics private HashSet[] UploadedKeys; private Dictionary ImageTypes; + private Dictionary MirroredTextures; public GpuResourceManager(NvGpu Gpu) { @@ -33,6 +37,7 @@ namespace Ryujinx.Graphics } ImageTypes = new Dictionary(); + MirroredTextures = new Dictionary(); } public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage) @@ -70,6 +75,32 @@ namespace Ryujinx.Graphics ImageTypes[Position] = ImageType.Texture; } + public bool TryGetTextureLayer(long Position, out int LayerIndex) + { + if (MirroredTextures.TryGetValue(Position, out LayerIndex)) + { + ImageType Type = ImageTypes[Position]; + + // FIXME(thog): I'm actually unsure if we should deny all other image type, gpu testing needs to be done here. + if (Type != ImageType.Texture && Type != ImageType.TextureArrayLayer) + { + LayerIndex = -1; + return false; + } + + return true; + } + + LayerIndex = -1; + return false; + } + + public void SetTextureArrayLayer(long Position, int LayerIndex) + { + ImageTypes[Position] = ImageType.TextureArrayLayer; + MirroredTextures[Position] = LayerIndex; + } + private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage) { long Size = ImageUtils.GetSize(NewImage); @@ -102,7 +133,7 @@ namespace Ryujinx.Graphics private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage) { - if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.SizeMatches(NewImage)) + if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.TextureTarget == NewImage.TextureTarget && CachedImage.SizeMatches(NewImage)) { Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs index 55e3ebd4c4..3295f6da05 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; @@ -46,6 +47,8 @@ namespace Ryujinx.Graphics.Graphics3d bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0; int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth); int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight); + int DstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth); + int DstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer); int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch); int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions); @@ -53,6 +56,8 @@ namespace Ryujinx.Graphics.Graphics3d bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0; int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth); int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight); + int SrcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth); + int SrcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer); int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch); int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions); @@ -82,26 +87,99 @@ namespace Ryujinx.Graphics.Graphics3d long SrcKey = Vmm.GetPhysicalAddress(SrcAddress); long DstKey = Vmm.GetPhysicalAddress(DstAddress); + bool IsSrcLayered = false; + bool IsDstLayered = false; + + GalTextureTarget SrcTarget = GalTextureTarget.TwoD; + + if (SrcDepth != 0) + { + SrcTarget = GalTextureTarget.TwoDArray; + SrcDepth++; + IsSrcLayered = true; + } + else + { + SrcDepth = 1; + } + + GalTextureTarget DstTarget = GalTextureTarget.TwoD; + + if (DstDepth != 0) + { + DstTarget = GalTextureTarget.TwoDArray; + DstDepth++; + IsDstLayered = true; + } + else + { + DstDepth = 1; + } + GalImage SrcTexture = new GalImage( SrcWidth, - SrcHeight, 1, - SrcBlockHeight, + SrcHeight, + 1, SrcDepth, 1, + SrcBlockHeight, 1, SrcLayout, - SrcImgFormat); + SrcImgFormat, + SrcTarget); GalImage DstTexture = new GalImage( DstWidth, - DstHeight, 1, - DstBlockHeight, + DstHeight, + 1, DstDepth, 1, + DstBlockHeight, 1, DstLayout, - DstImgFormat); + DstImgFormat, + DstTarget); SrcTexture.Pitch = SrcPitch; DstTexture.Pitch = DstPitch; + long GetLayerOffset(GalImage Image, int Layer) + { + int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1; + return ImageUtils.GetLayerOffset(Image, TargetMipLevel) * Layer; + } + + int SrcLayerIndex = -1; + + if (IsSrcLayered && Gpu.ResourceManager.TryGetTextureLayer(SrcKey, out SrcLayerIndex) && SrcLayerIndex != 0) + { + SrcKey = SrcKey - GetLayerOffset(SrcTexture, SrcLayerIndex); + } + + int DstLayerIndex = -1; + + if (IsDstLayered && Gpu.ResourceManager.TryGetTextureLayer(DstKey, out DstLayerIndex) && DstLayerIndex != 0) + { + DstKey = DstKey - GetLayerOffset(DstTexture, DstLayerIndex); + } + Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture); Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture); + if (IsSrcLayered && SrcLayerIndex == -1) + { + for (int Layer = 0; Layer < SrcTexture.LayerCount; Layer++) + { + Gpu.ResourceManager.SetTextureArrayLayer(SrcKey + GetLayerOffset(SrcTexture, Layer), Layer); + } + + SrcLayerIndex = 0; + } + + if (IsDstLayered && DstLayerIndex == -1) + { + for (int Layer = 0; Layer < DstTexture.LayerCount; Layer++) + { + Gpu.ResourceManager.SetTextureArrayLayer(DstKey + GetLayerOffset(DstTexture, Layer), Layer); + } + + DstLayerIndex = 0; + } + int SrcBlitX1 = (int)(SrcBlitX >> 32); int SrcBlitY1 = (int)(SrcBlitY >> 32); @@ -109,8 +187,12 @@ namespace Ryujinx.Graphics.Graphics3d int SrcBlitY2 = (int)(SrcBlitY + DstBlitH * BlitDvDy >> 32); Gpu.Renderer.RenderTarget.Copy( + SrcTexture, + DstTexture, SrcKey, DstKey, + SrcLayerIndex, + DstLayerIndex, SrcBlitX1, SrcBlitY1, SrcBlitX2, @@ -124,6 +206,8 @@ namespace Ryujinx.Graphics.Graphics3d //the texture is modified by the guest, however it doesn't //work when resources that the gpu can write to are copied, //like framebuffers. + + // FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer) ImageUtils.CopyTexture( Vmm, SrcTexture, diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs index c1c0dba29f..7747b5a3ab 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2dReg.cs @@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Graphics3d DstWidth = 0x86, DstHeight = 0x87, DstAddress = 0x88, + DstAddressLow = 0x89, SrcFormat = 0x8c, SrcLinear = 0x8d, SrcBlockDimensions = 0x8e, @@ -20,6 +21,7 @@ namespace Ryujinx.Graphics.Graphics3d SrcWidth = 0x92, SrcHeight = 0x93, SrcAddress = 0x94, + SrcAddressLow = 0x95, ClipEnable = 0xa4, CopyOperation = 0xab, BlitControl = 0x223, diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs index 6120053dae..eb6289fbdb 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; @@ -190,7 +191,11 @@ namespace Ryujinx.Graphics.Graphics3d int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10); int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10); - int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10); + int ArrayMode = ReadRegister(NvGpuEngine3dReg.FrameBufferNArrayMode + FbIndex * 0x10); + int LayerCount = ArrayMode & 0xFFFF; + int LayerStride = ReadRegister(NvGpuEngine3dReg.FrameBufferNLayerStride + FbIndex * 0x10); + int BaseLayer = ReadRegister(NvGpuEngine3dReg.FrameBufferNBaseLayer + FbIndex * 0x10); + int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10); int GobBlockHeight = 1 << ((BlockDim >> 4) & 7); @@ -210,7 +215,7 @@ namespace Ryujinx.Graphics.Graphics3d GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat); - GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format); + GalImage Image = new GalImage(Width, Height, 1, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD); Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image); @@ -264,7 +269,8 @@ namespace Ryujinx.Graphics.Graphics3d GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat); - GalImage Image = new GalImage(Width, Height, 1, GobBlockHeight, Layout, Format); + // TODO: Support non 2D? + GalImage Image = new GalImage(Width, Height, 1, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD); Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image); } @@ -600,7 +606,7 @@ namespace Ryujinx.Graphics.Graphics3d } Gpu.Renderer.Texture.Bind(Key, Index, Image); - Gpu.Renderer.Texture.SetSampler(Sampler); + Gpu.Renderer.Texture.SetSampler(Image, Sampler); } } diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs index 026b0cd198..9134646403 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs @@ -2,112 +2,115 @@ namespace Ryujinx.Graphics.Graphics3d { enum NvGpuEngine3dReg { - FrameBufferNAddress = 0x200, - FrameBufferNWidth = 0x202, - FrameBufferNHeight = 0x203, - FrameBufferNFormat = 0x204, - FrameBufferNBlockDim = 0x205, - ViewportNScaleX = 0x280, - ViewportNScaleY = 0x281, - ViewportNScaleZ = 0x282, - ViewportNTranslateX = 0x283, - ViewportNTranslateY = 0x284, - ViewportNTranslateZ = 0x285, - ViewportNHoriz = 0x300, - ViewportNVert = 0x301, - DepthRangeNNear = 0x302, - DepthRangeNFar = 0x303, - VertexArrayFirst = 0x35d, - VertexArrayCount = 0x35e, - ClearNColor = 0x360, - ClearDepth = 0x364, - ClearStencil = 0x368, - ScissorEnable = 0x380, - ScissorHorizontal = 0x381, - ScissorVertical = 0x382, - StencilBackFuncRef = 0x3d5, - StencilBackMask = 0x3d6, - StencilBackFuncMask = 0x3d7, - ColorMaskCommon = 0x3e4, - RTSeparateFragData = 0x3eb, - ZetaAddress = 0x3f8, - ZetaFormat = 0x3fa, - ZetaBlockDimensions = 0x3fb, - ZetaLayerStride = 0x3fc, - VertexAttribNFormat = 0x458, - RTControl = 0x487, - ZetaHoriz = 0x48a, - ZetaVert = 0x48b, - ZetaArrayMode = 0x48c, - LinkedTsc = 0x48d, - DepthTestEnable = 0x4b3, - BlendIndependent = 0x4b9, - DepthWriteEnable = 0x4ba, - DepthTestFunction = 0x4c3, - BlendSeparateAlpha = 0x4cf, - BlendEquationRgb = 0x4d0, - BlendFuncSrcRgb = 0x4d1, - BlendFuncDstRgb = 0x4d2, - BlendEquationAlpha = 0x4d3, - BlendFuncSrcAlpha = 0x4d4, - BlendFuncDstAlpha = 0x4d6, - BlendEnable = 0x4d7, - IBlendNEnable = 0x4d8, - StencilEnable = 0x4e0, - StencilFrontOpFail = 0x4e1, - StencilFrontOpZFail = 0x4e2, - StencilFrontOpZPass = 0x4e3, - StencilFrontFuncFunc = 0x4e4, - StencilFrontFuncRef = 0x4e5, - StencilFrontFuncMask = 0x4e6, - StencilFrontMask = 0x4e7, - ScreenYControl = 0x4eb, - VertexArrayElemBase = 0x50d, - VertexArrayInstBase = 0x50e, - ZetaEnable = 0x54e, - TexHeaderPoolOffset = 0x55d, - TexSamplerPoolOffset = 0x557, - StencilTwoSideEnable = 0x565, - StencilBackOpFail = 0x566, - StencilBackOpZFail = 0x567, - StencilBackOpZPass = 0x568, - StencilBackFuncFunc = 0x569, - FrameBufferSrgb = 0x56e, - ShaderAddress = 0x582, - VertexBeginGl = 0x586, - PrimRestartEnable = 0x591, - PrimRestartIndex = 0x592, - IndexArrayAddress = 0x5f2, - IndexArrayEndAddr = 0x5f4, - IndexArrayFormat = 0x5f6, - IndexBatchFirst = 0x5f7, - IndexBatchCount = 0x5f8, - VertexArrayNInstance = 0x620, - CullFaceEnable = 0x646, - FrontFace = 0x647, - CullFace = 0x648, - ColorMaskN = 0x680, - QueryAddress = 0x6c0, - QuerySequence = 0x6c2, - QueryControl = 0x6c3, - VertexArrayNControl = 0x700, - VertexArrayNAddress = 0x701, - VertexArrayNDivisor = 0x703, - IBlendNSeparateAlpha = 0x780, - IBlendNEquationRgb = 0x781, - IBlendNFuncSrcRgb = 0x782, - IBlendNFuncDstRgb = 0x783, - IBlendNEquationAlpha = 0x784, - IBlendNFuncSrcAlpha = 0x785, - IBlendNFuncDstAlpha = 0x786, - VertexArrayNEndAddr = 0x7c0, - ShaderNControl = 0x800, - ShaderNOffset = 0x801, - ShaderNMaxGprs = 0x803, - ShaderNType = 0x804, - ConstBufferSize = 0x8e0, - ConstBufferAddress = 0x8e1, - ConstBufferOffset = 0x8e3, - TextureCbIndex = 0x982 + FrameBufferNAddress = 0x200, + FrameBufferNWidth = 0x202, + FrameBufferNHeight = 0x203, + FrameBufferNFormat = 0x204, + FrameBufferNBlockDim = 0x205, + FrameBufferNArrayMode = 0x206, + FrameBufferNLayerStride = 0x207, + FrameBufferNBaseLayer = 0x208, + ViewportNScaleX = 0x280, + ViewportNScaleY = 0x281, + ViewportNScaleZ = 0x282, + ViewportNTranslateX = 0x283, + ViewportNTranslateY = 0x284, + ViewportNTranslateZ = 0x285, + ViewportNHoriz = 0x300, + ViewportNVert = 0x301, + DepthRangeNNear = 0x302, + DepthRangeNFar = 0x303, + VertexArrayFirst = 0x35d, + VertexArrayCount = 0x35e, + ClearNColor = 0x360, + ClearDepth = 0x364, + ClearStencil = 0x368, + ScissorEnable = 0x380, + ScissorHorizontal = 0x381, + ScissorVertical = 0x382, + StencilBackFuncRef = 0x3d5, + StencilBackMask = 0x3d6, + StencilBackFuncMask = 0x3d7, + ColorMaskCommon = 0x3e4, + RTSeparateFragData = 0x3eb, + ZetaAddress = 0x3f8, + ZetaFormat = 0x3fa, + ZetaBlockDimensions = 0x3fb, + ZetaLayerStride = 0x3fc, + VertexAttribNFormat = 0x458, + RTControl = 0x487, + ZetaHoriz = 0x48a, + ZetaVert = 0x48b, + ZetaArrayMode = 0x48c, + LinkedTsc = 0x48d, + DepthTestEnable = 0x4b3, + BlendIndependent = 0x4b9, + DepthWriteEnable = 0x4ba, + DepthTestFunction = 0x4c3, + BlendSeparateAlpha = 0x4cf, + BlendEquationRgb = 0x4d0, + BlendFuncSrcRgb = 0x4d1, + BlendFuncDstRgb = 0x4d2, + BlendEquationAlpha = 0x4d3, + BlendFuncSrcAlpha = 0x4d4, + BlendFuncDstAlpha = 0x4d6, + BlendEnable = 0x4d7, + IBlendNEnable = 0x4d8, + StencilEnable = 0x4e0, + StencilFrontOpFail = 0x4e1, + StencilFrontOpZFail = 0x4e2, + StencilFrontOpZPass = 0x4e3, + StencilFrontFuncFunc = 0x4e4, + StencilFrontFuncRef = 0x4e5, + StencilFrontFuncMask = 0x4e6, + StencilFrontMask = 0x4e7, + ScreenYControl = 0x4eb, + VertexArrayElemBase = 0x50d, + VertexArrayInstBase = 0x50e, + ZetaEnable = 0x54e, + TexHeaderPoolOffset = 0x55d, + TexSamplerPoolOffset = 0x557, + StencilTwoSideEnable = 0x565, + StencilBackOpFail = 0x566, + StencilBackOpZFail = 0x567, + StencilBackOpZPass = 0x568, + StencilBackFuncFunc = 0x569, + FrameBufferSrgb = 0x56e, + ShaderAddress = 0x582, + VertexBeginGl = 0x586, + PrimRestartEnable = 0x591, + PrimRestartIndex = 0x592, + IndexArrayAddress = 0x5f2, + IndexArrayEndAddr = 0x5f4, + IndexArrayFormat = 0x5f6, + IndexBatchFirst = 0x5f7, + IndexBatchCount = 0x5f8, + VertexArrayNInstance = 0x620, + CullFaceEnable = 0x646, + FrontFace = 0x647, + CullFace = 0x648, + ColorMaskN = 0x680, + QueryAddress = 0x6c0, + QuerySequence = 0x6c2, + QueryControl = 0x6c3, + VertexArrayNControl = 0x700, + VertexArrayNAddress = 0x701, + VertexArrayNDivisor = 0x703, + IBlendNSeparateAlpha = 0x780, + IBlendNEquationRgb = 0x781, + IBlendNFuncSrcRgb = 0x782, + IBlendNFuncDstRgb = 0x783, + IBlendNEquationAlpha = 0x784, + IBlendNFuncSrcAlpha = 0x785, + IBlendNFuncDstAlpha = 0x786, + VertexArrayNEndAddr = 0x7c0, + ShaderNControl = 0x800, + ShaderNOffset = 0x801, + ShaderNMaxGprs = 0x803, + ShaderNType = 0x804, + ConstBufferSize = 0x8e0, + ConstBufferAddress = 0x8e1, + ConstBufferOffset = 0x8e3, + TextureCbIndex = 0x982 } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs index d89059c0c5..2f1df3d377 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; using System.Collections.Generic; @@ -125,29 +126,37 @@ namespace Ryujinx.Graphics.Graphics3d if (SrcLinear) { - SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp); + SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp, SrcSizeX, SrcSizeY); } else { - SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcCpp, SrcBlockHeight); + SrcSwizzle = new BlockLinearSwizzle( + SrcSizeX, + SrcSizeY, 1, + SrcBlockHeight, 1, + SrcCpp); } ISwizzle DstSwizzle; if (DstLinear) { - DstSwizzle = new LinearSwizzle(DstPitch, DstCpp); + DstSwizzle = new LinearSwizzle(DstPitch, DstCpp, SrcSizeX, SrcSizeY); } else { - DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstCpp, DstBlockHeight); + DstSwizzle = new BlockLinearSwizzle( + DstSizeX, + DstSizeY, 1, + DstBlockHeight, 1, + DstCpp); } for (int Y = 0; Y < YCount; Y++) for (int X = 0; X < XCount; X++) { - int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y); - int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y); + int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y, 0); + int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y, 0); long Src = SrcPA + (uint)SrcOffset; long Dst = DstPA + (uint)DstOffset; diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs index 681552556c..62872ba15c 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Logging; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; using System.Collections.Generic; @@ -119,14 +120,17 @@ namespace Ryujinx.Graphics.Graphics3d } else { - BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(CopyWidth, 1, CopyGobBlockHeight); + BlockLinearSwizzle Swizzle = new BlockLinearSwizzle( + CopyWidth, + CopyHeight, 1, + CopyGobBlockHeight, 1, 1); int SrcOffset = 0; for (int Y = CopyStartY; Y < CopyHeight && SrcOffset < CopySize; Y++) for (int X = CopyStartX; X < CopyWidth && SrcOffset < CopySize; X++) { - int DstOffset = Swizzle.GetSwizzleOffset(X, Y); + int DstOffset = Swizzle.GetSwizzleOffset(X, Y, 0); Vmm.WriteByte(CopyAddress + DstOffset, Buffer[SrcOffset++]); } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs index 1efa025523..00158dc103 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs @@ -72,6 +72,7 @@ namespace Ryujinx.Graphics.Texture if (BlockZ != 1 || Z != 1) { + // TODO: Support 3D textures? throw new ASTCDecoderException("3D compressed textures unsupported!"); } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs index 9451291e9a..1be0644283 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs @@ -1,51 +1,178 @@ +using Ryujinx.Common; using System; namespace Ryujinx.Graphics.Texture { class BlockLinearSwizzle : ISwizzle { - private int BhShift; - private int BppShift; + private const int GobWidth = 64; + private const int GobHeight = 8; + + private const int GobSize = GobWidth * GobHeight; + + private int TexWidth; + private int TexHeight; + private int TexDepth; + private int TexGobBlockHeight; + private int TexGobBlockDepth; + private int TexBpp; + private int BhMask; + private int BdMask; + + private int BhShift; + private int BdShift; + private int BppShift; private int XShift; - private int GobStride; - public BlockLinearSwizzle(int Width, int Bpp, int BlockHeight = 16) + private int RobSize; + private int SliceSize; + + private int BaseOffset; + + public BlockLinearSwizzle( + int Width, + int Height, + int Depth, + int GobBlockHeight, + int GobBlockDepth, + int Bpp) { - BhMask = (BlockHeight * 8) - 1; + TexWidth = Width; + TexHeight = Height; + TexDepth = Depth; + TexGobBlockHeight = GobBlockHeight; + TexGobBlockDepth = GobBlockDepth; + TexBpp = Bpp; - BhShift = CountLsbZeros(BlockHeight * 8); - BppShift = CountLsbZeros(Bpp); + BppShift = BitUtils.CountTrailingZeros32(Bpp); - int WidthInGobs = (int)MathF.Ceiling(Width * Bpp / 64f); - - GobStride = 512 * BlockHeight * WidthInGobs; - - XShift = CountLsbZeros(512 * BlockHeight); + SetMipLevel(0); } - private int CountLsbZeros(int Value) + public void SetMipLevel(int Level) { - int Count = 0; + BaseOffset = GetMipOffset(Level); - while (((Value >> Count) & 1) == 0) + int Width = Math.Max(1, TexWidth >> Level); + int Height = Math.Max(1, TexHeight >> Level); + int Depth = Math.Max(1, TexDepth >> Level); + + GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth); + + BhMask = GbSizes.Height - 1; + BdMask = GbSizes.Depth - 1; + + BhShift = BitUtils.CountTrailingZeros32(GbSizes.Height); + BdShift = BitUtils.CountTrailingZeros32(GbSizes.Depth); + + XShift = BitUtils.CountTrailingZeros32(GobSize * GbSizes.Height * GbSizes.Depth); + + RobAndSliceSizes GsSizes = GetRobAndSliceSizes(Width, Height, GbSizes); + + RobSize = GsSizes.RobSize; + SliceSize = GsSizes.SliceSize; + } + + public int GetImageSize(int MipsCount) + { + int Size = GetMipOffset(MipsCount); + + Size = (Size + 0x1fff) & ~0x1fff; + + return Size; + } + + public int GetMipOffset(int Level) + { + int TotalSize = 0; + + for (int Index = 0; Index < Level; Index++) { - Count++; + int Width = Math.Max(1, TexWidth >> Index); + int Height = Math.Max(1, TexHeight >> Index); + int Depth = Math.Max(1, TexDepth >> Index); + + GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth); + + RobAndSliceSizes RsSizes = GetRobAndSliceSizes(Width, Height, GbSizes); + + TotalSize += BitUtils.DivRoundUp(Depth, GbSizes.Depth) * RsSizes.SliceSize; } - return Count; + return TotalSize; } - public int GetSwizzleOffset(int X, int Y) + private struct GobBlockSizes + { + public int Height; + public int Depth; + + public GobBlockSizes(int GobBlockHeight, int GobBlockDepth) + { + this.Height = GobBlockHeight; + this.Depth = GobBlockDepth; + } + } + + private GobBlockSizes AdjustGobBlockSizes(int Height, int Depth) + { + int GobBlockHeight = TexGobBlockHeight; + int GobBlockDepth = TexGobBlockDepth; + + int Pow2Height = BitUtils.Pow2RoundUp(Height); + int Pow2Depth = BitUtils.Pow2RoundUp(Depth); + + while (GobBlockHeight * GobHeight > Pow2Height && GobBlockHeight > 1) + { + GobBlockHeight >>= 1; + } + + while (GobBlockDepth > Pow2Depth && GobBlockDepth > 1) + { + GobBlockDepth >>= 1; + } + + return new GobBlockSizes(GobBlockHeight, GobBlockDepth); + } + + private struct RobAndSliceSizes + { + public int RobSize; + public int SliceSize; + + public RobAndSliceSizes(int RobSize, int SliceSize) + { + this.RobSize = RobSize; + this.SliceSize = SliceSize; + } + } + + private RobAndSliceSizes GetRobAndSliceSizes(int Width, int Height, GobBlockSizes GbSizes) + { + int WidthInGobs = BitUtils.DivRoundUp(Width * TexBpp, GobWidth); + + int RobSize = GobSize * GbSizes.Height * GbSizes.Depth * WidthInGobs; + + int SliceSize = BitUtils.DivRoundUp(Height, GbSizes.Height * GobHeight) * RobSize; + + return new RobAndSliceSizes(RobSize, SliceSize); + } + + public int GetSwizzleOffset(int X, int Y, int Z) { X <<= BppShift; - int Position = (Y >> BhShift) * GobStride; + int YH = Y / GobHeight; - Position += (X >> 6) << XShift; + int Position = (Z >> BdShift) * SliceSize + (YH >> BhShift) * RobSize; - Position += ((Y & BhMask) >> 3) << 9; + Position += (X / GobWidth) << XShift; + + Position += (YH & BhMask) * GobSize; + + Position += ((Z & BdMask) * GobSize) << BhShift; Position += ((X & 0x3f) >> 5) << 8; Position += ((Y & 0x07) >> 1) << 6; @@ -53,7 +180,7 @@ namespace Ryujinx.Graphics.Texture Position += ((Y & 0x01) >> 0) << 4; Position += ((X & 0x0f) >> 0) << 0; - return Position; + return BaseOffset + Position; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs index 583fc20c53..2e0e8aedd4 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs @@ -2,6 +2,12 @@ namespace Ryujinx.Graphics.Texture { interface ISwizzle { - int GetSwizzleOffset(int X, int Y); + int GetSwizzleOffset(int X, int Y, int Z); + + void SetMipLevel(int Level); + + int GetMipOffset(int Level); + + int GetImageSize(int MipsCount); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs index f958e1de81..c4208935c3 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs @@ -1,4 +1,6 @@ using ChocolArm64.Memory; +using OpenTK.Graphics.OpenGL; +using Ryujinx.Common; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using System; @@ -23,14 +25,16 @@ namespace Ryujinx.Graphics.Texture public int BytesPerPixel { get; private set; } public int BlockWidth { get; private set; } public int BlockHeight { get; private set; } + public int BlockDepth { get; private set; } public TargetBuffer Target { get; private set; } - public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, TargetBuffer Target) + public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, int BlockDepth, TargetBuffer Target) { this.BytesPerPixel = BytesPerPixel; this.BlockWidth = BlockWidth; this.BlockHeight = BlockHeight; + this.BlockDepth = BlockDepth; this.Target = Target; } } @@ -92,52 +96,52 @@ namespace Ryujinx.Graphics.Texture private static readonly Dictionary s_ImageTable = new Dictionary() { - { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) }, - { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) }, - { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) }, - { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) }, - { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) }, - { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) }, - { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) }, - { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) }, - { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) }, - { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) }, - { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) }, - { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) }, - { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) }, - { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) }, + { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, 1, TargetBuffer.Color) }, + { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, 1, TargetBuffer.Color) }, - { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) }, - { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) }, - { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) }, - { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) }, - { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) } + { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Depth) }, + { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) }, + { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.DepthStencil) }, + { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) }, + { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.DepthStencil) } }; public static GalImageFormat ConvertTexture( @@ -241,26 +245,37 @@ namespace Ryujinx.Graphics.Texture ImageDescriptor Desc = GetImageDescriptor(Image.Format); - (int Width, int Height) = GetImageSizeInBlocks(Image); + (int Width, int Height, int Depth) = GetImageSizeInBlocks(Image); int BytesPerPixel = Desc.BytesPerPixel; //Note: Each row of the texture needs to be aligned to 4 bytes. int Pitch = (Width * BytesPerPixel + 3) & ~3; - byte[] Data = new byte[Height * Pitch]; - for (int Y = 0; Y < Height; Y++) + int DataLayerSize = Height * Pitch * Depth; + byte[] Data = new byte[DataLayerSize * Image.LayerCount]; + + int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1; + int LayerOffset = ImageUtils.GetLayerOffset(Image, TargetMipLevel); + + for (int Layer = 0; Layer < Image.LayerCount; Layer++) { - int OutOffs = Y * Pitch; - - for (int X = 0; X < Width; X++) + for (int Z = 0; Z < Depth; Z++) { - long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); + for (int Y = 0; Y < Height; Y++) + { + int OutOffs = (DataLayerSize * Layer) + Y * Pitch + (Z * Width * Height * BytesPerPixel); - CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel); + for (int X = 0; X < Width; X++) + { + long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z); - OutOffs += BytesPerPixel; + CpuMemory.ReadBytes(Position + (LayerOffset * Layer) + Offset, Data, OutOffs, BytesPerPixel); + + OutOffs += BytesPerPixel; + } + } } } @@ -273,16 +288,17 @@ namespace Ryujinx.Graphics.Texture ImageDescriptor Desc = GetImageDescriptor(Image.Format); - (int Width, int Height) = ImageUtils.GetImageSizeInBlocks(Image); + (int Width, int Height, int Depth) = ImageUtils.GetImageSizeInBlocks(Image); int BytesPerPixel = Desc.BytesPerPixel; int InOffs = 0; + for (int Z = 0; Z < Depth; Z++) for (int Y = 0; Y < Height; Y++) for (int X = 0; X < Width; X++) { - long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); + long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z); Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel); @@ -290,6 +306,7 @@ namespace Ryujinx.Graphics.Texture } } + // TODO: Support non 2D public static bool CopyTexture( NvGpuVmm Vmm, GalImage SrcImage, @@ -318,8 +335,8 @@ namespace Ryujinx.Graphics.Texture for (int Y = 0; Y < Height; Y++) for (int X = 0; X < Width; X++) { - long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y); - long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y); + long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y, 0); + long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y, 0); byte[] Texel = Vmm.ReadBytes(SrcAddress + SrcOffset, BytesPerPixel); @@ -333,10 +350,41 @@ namespace Ryujinx.Graphics.Texture { ImageDescriptor Desc = GetImageDescriptor(Image.Format); + int ComponentCount = GetCoordsCountTextureTarget(Image.TextureTarget); + + if (IsArray(Image.TextureTarget)) + ComponentCount--; + int Width = DivRoundUp(Image.Width, Desc.BlockWidth); int Height = DivRoundUp(Image.Height, Desc.BlockHeight); + int Depth = DivRoundUp(Image.Depth, Desc.BlockDepth); - return Desc.BytesPerPixel * Width * Height; + switch (ComponentCount) + { + case 1: + return Desc.BytesPerPixel * Width * Image.LayerCount; + case 2: + return Desc.BytesPerPixel * Width * Height * Image.LayerCount; + case 3: + return Desc.BytesPerPixel * Width * Height * Depth * Image.LayerCount; + default: + throw new InvalidOperationException($"Invalid component count: {ComponentCount}"); + } + } + + public static int GetGpuSize(GalImage Image, bool forcePitch = false) + { + return TextureHelper.GetSwizzle(Image).GetImageSize(Image.MaxMipmapLevel) * Image.LayerCount; + } + + public static int GetLayerOffset(GalImage Image, int MipLevel) + { + if (MipLevel <= 0) + { + MipLevel = 1; + } + + return TextureHelper.GetSwizzle(Image).GetMipOffset(MipLevel); } public static int GetPitch(GalImageFormat Format, int Width) @@ -360,6 +408,11 @@ namespace Ryujinx.Graphics.Texture return GetImageDescriptor(Format).BlockHeight; } + public static int GetBlockDepth(GalImageFormat Format) + { + return GetImageDescriptor(Format).BlockDepth; + } + public static int GetAlignedWidth(GalImage Image) { ImageDescriptor Desc = GetImageDescriptor(Image.Format); @@ -378,12 +431,13 @@ namespace Ryujinx.Graphics.Texture return (Image.Width + AlignMask) & ~AlignMask; } - public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image) + public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage Image) { ImageDescriptor Desc = GetImageDescriptor(Image.Format); return (DivRoundUp(Image.Width, Desc.BlockWidth), - DivRoundUp(Image.Height, Desc.BlockHeight)); + DivRoundUp(Image.Height, Desc.BlockHeight), + DivRoundUp(Image.Depth, Desc.BlockDepth)); } public static int GetBytesPerPixel(GalImageFormat Format) @@ -443,5 +497,66 @@ namespace Ryujinx.Graphics.Texture default: throw new NotImplementedException(((int)Type).ToString()); } } + + public static TextureTarget GetTextureTarget(GalTextureTarget GalTextureTarget) + { + switch (GalTextureTarget) + { + case GalTextureTarget.OneD: + return TextureTarget.Texture1D; + case GalTextureTarget.TwoD: + case GalTextureTarget.TwoDNoMipMap: + return TextureTarget.Texture2D; + case GalTextureTarget.ThreeD: + return TextureTarget.Texture3D; + case GalTextureTarget.OneDArray: + return TextureTarget.Texture1DArray; + case GalTextureTarget.OneDBuffer: + return TextureTarget.TextureBuffer; + case GalTextureTarget.TwoDArray: + return TextureTarget.Texture2DArray; + case GalTextureTarget.CubeMap: + return TextureTarget.TextureCubeMap; + case GalTextureTarget.CubeArray: + return TextureTarget.TextureCubeMapArray; + default: + throw new NotSupportedException($"Texture target {GalTextureTarget} currently not supported!"); + } + } + + public static bool IsArray(GalTextureTarget TextureTarget) + { + switch (TextureTarget) + { + case GalTextureTarget.OneDArray: + case GalTextureTarget.TwoDArray: + case GalTextureTarget.CubeArray: + return true; + default: + return false; + } + } + + public static int GetCoordsCountTextureTarget(GalTextureTarget TextureTarget) + { + switch (TextureTarget) + { + case GalTextureTarget.OneD: + return 1; + case GalTextureTarget.OneDArray: + case GalTextureTarget.OneDBuffer: + case GalTextureTarget.TwoD: + case GalTextureTarget.TwoDNoMipMap: + return 2; + case GalTextureTarget.ThreeD: + case GalTextureTarget.TwoDArray: + case GalTextureTarget.CubeMap: + return 3; + case GalTextureTarget.CubeArray: + return 4; + default: + throw new NotImplementedException($"TextureTarget.{TextureTarget} not implemented yet."); + } + } } } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs index ef468e27b5..e6509baa6a 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs @@ -1,3 +1,5 @@ +using System; + namespace Ryujinx.Graphics.Texture { class LinearSwizzle : ISwizzle @@ -5,15 +7,39 @@ namespace Ryujinx.Graphics.Texture private int Pitch; private int Bpp; - public LinearSwizzle(int Pitch, int Bpp) + private int SliceSize; + + public LinearSwizzle(int Pitch, int Bpp, int Width, int Height) { - this.Pitch = Pitch; - this.Bpp = Bpp; + this.Pitch = Pitch; + this.Bpp = Bpp; + SliceSize = Width * Height * Bpp; } - public int GetSwizzleOffset(int X, int Y) + public void SetMipLevel(int Level) { - return X * Bpp + Y * Pitch; + throw new NotImplementedException(); + } + + public int GetMipOffset(int Level) + { + if (Level == 1) + return SliceSize; + throw new NotImplementedException(); + } + + public int GetImageSize(int MipsCount) + { + int Size = GetMipOffset(MipsCount); + + Size = (Size + 0x1fff) & ~0x1fff; + + return Size; + } + + public int GetSwizzleOffset(int X, int Y, int Z) + { + return Z * SliceSize + X * Bpp + Y * Pitch; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs index 1f2d625ec4..a2ce86f56d 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs @@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.Texture GalImageFormat Format = GetImageFormat(Tic); + GalTextureTarget TextureTarget = (GalTextureTarget)((Tic[4] >> 23) & 0xF); + GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7); GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7); GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7); @@ -19,6 +21,8 @@ namespace Ryujinx.Graphics.Texture TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7); + int MaxMipmapLevel = (Tic[3] >> 28) & 0xF + 1; + GalMemoryLayout Layout; if (Swizzle == TextureSwizzle.BlockLinear || @@ -31,22 +35,61 @@ namespace Ryujinx.Graphics.Texture Layout = GalMemoryLayout.Pitch; } - int BlockHeightLog2 = (Tic[3] >> 3) & 7; - int TileWidthLog2 = (Tic[3] >> 10) & 7; + int GobBlockHeightLog2 = (Tic[3] >> 3) & 7; + int GobBlockDepthLog2 = (Tic[3] >> 6) & 7; + int TileWidthLog2 = (Tic[3] >> 10) & 7; - int BlockHeight = 1 << BlockHeightLog2; - int TileWidth = 1 << TileWidthLog2; + int GobBlockHeight = 1 << GobBlockHeightLog2; + int GobBlockDepth = 1 << GobBlockDepthLog2; + int TileWidth = 1 << TileWidthLog2; - int Width = (Tic[4] & 0xffff) + 1; - int Height = (Tic[5] & 0xffff) + 1; + int Width = ((Tic[4] >> 0) & 0xffff) + 1; + int Height = ((Tic[5] >> 0) & 0xffff) + 1; + int Depth = ((Tic[5] >> 16) & 0x3fff) + 1; + + int LayoutCount = 1; + + // TODO: check this + if (ImageUtils.IsArray(TextureTarget)) + { + LayoutCount = Depth; + Depth = 1; + } + + if (TextureTarget == GalTextureTarget.OneD) + { + Height = 1; + } + + if (TextureTarget == GalTextureTarget.TwoD || TextureTarget == GalTextureTarget.OneD) + { + Depth = 1; + } + else if (TextureTarget == GalTextureTarget.CubeMap) + { + // FIXME: This is a bit hacky but I guess it's fine for now + LayoutCount = 6; + Depth = 1; + } + else if (TextureTarget == GalTextureTarget.CubeArray) + { + // FIXME: This is a really really hacky but I guess it's fine for now + LayoutCount *= 6; + Depth = 1; + } GalImage Image = new GalImage( Width, Height, + Depth, + LayoutCount, TileWidth, - BlockHeight, + GobBlockHeight, + GobBlockDepth, Layout, Format, + TextureTarget, + MaxMipmapLevel, XSource, YSource, ZSource, @@ -68,6 +111,10 @@ namespace Ryujinx.Graphics.Texture GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7); GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7); + bool DepthCompare = ((Tsc[0] >> 9) & 1) == 1; + + DepthCompareFunc DepthCompareFunc = (DepthCompareFunc)((Tsc[0] >> 10) & 7); + GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3); GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3); GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3); @@ -85,7 +132,9 @@ namespace Ryujinx.Graphics.Texture MinFilter, MagFilter, MipFilter, - BorderColor); + BorderColor, + DepthCompare, + DepthCompareFunc); } private static GalImageFormat GetImageFormat(int[] Tic) diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs index 6ac91d8b59..33ccb0aa51 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs @@ -1,4 +1,5 @@ using ChocolArm64.Memory; +using Ryujinx.Common; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; @@ -9,9 +10,13 @@ namespace Ryujinx.Graphics.Texture public static ISwizzle GetSwizzle(GalImage Image) { int BlockWidth = ImageUtils.GetBlockWidth (Image.Format); + int BlockHeight = ImageUtils.GetBlockHeight (Image.Format); + int BlockDepth = ImageUtils.GetBlockDepth (Image.Format); int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format); - int Width = (Image.Width + (BlockWidth - 1)) / BlockWidth; + int Width = BitUtils.DivRoundUp(Image.Width, BlockWidth); + int Height = BitUtils.DivRoundUp(Image.Height, BlockHeight); + int Depth = BitUtils.DivRoundUp(Image.Depth, BlockDepth); if (Image.Layout == GalMemoryLayout.BlockLinear) { @@ -19,11 +24,17 @@ namespace Ryujinx.Graphics.Texture Width = (Width + AlignMask) & ~AlignMask; - return new BlockLinearSwizzle(Width, BytesPerPixel, Image.GobBlockHeight); + return new BlockLinearSwizzle( + Width, + Height, + Depth, + Image.GobBlockHeight, + Image.GobBlockDepth, + BytesPerPixel); } else { - return new LinearSwizzle(Image.Pitch, BytesPerPixel); + return new LinearSwizzle(Image.Pitch, BytesPerPixel, Width, Height); } } diff --git a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs new file mode 100644 index 0000000000..bcb64af0be --- /dev/null +++ b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs @@ -0,0 +1,19 @@ +using System; + +namespace Ryujinx.Graphics.Texture +{ + [Flags] + public enum TextureInstructionSuffix + { + None = 0x00, // No Modifier + LZ = 0x02, // Load LOD Zero + LB = 0x08, // Load Bias + LL = 0x10, // Load LOD + LBA = 0x20, // Load Bias with OperA? Auto? + LLA = 0x40, // Load LOD with OperA? Auto? + DC = 0x80, // Depth Compare + AOffI = 0x100, // Offset + MZ = 0x200, // Multisample Zero? + PTP = 0x400 // ??? + } +} diff --git a/Ryujinx.Graphics/VDec/VideoDecoder.cs b/Ryujinx.Graphics/VDec/VideoDecoder.cs index 847392b0d9..be53b1a02c 100644 --- a/Ryujinx.Graphics/VDec/VideoDecoder.cs +++ b/Ryujinx.Graphics/VDec/VideoDecoder.cs @@ -216,10 +216,11 @@ namespace Ryujinx.Graphics.VDec GalImage Image = new GalImage( OutputConfig.SurfaceWidth, - OutputConfig.SurfaceHeight, 1, - OutputConfig.GobBlockHeight, + OutputConfig.SurfaceHeight, 1, 1, 1, + OutputConfig.GobBlockHeight, 1, GalMemoryLayout.BlockLinear, - GalImageFormat.RGBA8 | GalImageFormat.Unorm); + GalImageFormat.RGBA8 | GalImageFormat.Unorm, + GalTextureTarget.TwoD); ImageUtils.WriteTexture(Vmm, Image, Vmm.GetPhysicalAddress(OutputConfig.SurfaceLumaAddress), Frame.Data); } diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs index db04f47cd0..dbf255beee 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs @@ -1,6 +1,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; +using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Services.Nv.NvGpuAS; using Ryujinx.HLE.HOS.Services.Nv.NvMap; @@ -415,9 +416,10 @@ namespace Ryujinx.HLE.HOS.Services.Android { image = new GalImage( fbWidth, - fbHeight, 1, BlockHeight, + fbHeight, 1, 1, 1, BlockHeight, 1, GalMemoryLayout.BlockLinear, - imageFormat); + imageFormat, + GalTextureTarget.TwoD); } context.Device.Gpu.ResourceManager.ClearPbCache(); diff --git a/Ryujinx.ShaderTools/Program.cs b/Ryujinx.ShaderTools/Program.cs index 30fa71aea2..77aba0abe6 100644 --- a/Ryujinx.ShaderTools/Program.cs +++ b/Ryujinx.ShaderTools/Program.cs @@ -13,7 +13,7 @@ namespace Ryujinx.ShaderTools { if (args.Length == 2) { - GlslDecompiler Decompiler = new GlslDecompiler(MaxUboSize); + GlslDecompiler Decompiler = new GlslDecompiler(MaxUboSize, true); GalShaderType ShaderType = GalShaderType.Vertex; From e21ebbf666f10d39d44a0856e5a44143d3d69d0d Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 27 Feb 2019 23:03:31 -0300 Subject: [PATCH 16/36] Misc. CPU optimizations (#575) * Add optimizations related to caller/callee saved registers, thread synchronization and disable tier 0 * Refactoring * Add a config entry to enable or disable the reg load/store opt. * Remove unnecessary register state stores for calls when the callee is know * Rename IoType to VarType * Enable tier 0 while fixing some perf issues related to tier 0 * Small tweak -- Compile before adding to the cache, to avoid lags * Add required config entry --- ChocolArm64/Instructions/InstEmitFlow.cs | 3 +- ChocolArm64/Instructions/InstEmitFlow32.cs | 1 - .../Instructions/InstEmitFlowHelper.cs | 26 +-- ChocolArm64/Optimizations.cs | 32 +-- ChocolArm64/Translation/CallType.cs | 9 + ChocolArm64/Translation/ILBlock.cs | 32 +-- ChocolArm64/Translation/ILEmitterCtx.cs | 89 +++++--- ChocolArm64/Translation/ILLabel.cs | 6 +- ChocolArm64/Translation/ILMethodBuilder.cs | 45 ++-- ChocolArm64/Translation/ILOpCode.cs | 6 +- ChocolArm64/Translation/ILOpCodeBranch.cs | 10 +- ChocolArm64/Translation/ILOpCodeCall.cs | 4 +- ChocolArm64/Translation/ILOpCodeConst.cs | 2 + ChocolArm64/Translation/ILOpCodeLoad.cs | 20 +- ChocolArm64/Translation/ILOpCodeLoadField.cs | 2 +- ChocolArm64/Translation/ILOpCodeLoadState.cs | 17 +- ChocolArm64/Translation/ILOpCodeLog.cs | 6 +- ChocolArm64/Translation/ILOpCodeStore.cs | 20 +- ChocolArm64/Translation/ILOpCodeStoreState.cs | 26 ++- .../{LocalAlloc.cs => RegisterUsage.cs} | 199 ++++++++++-------- ChocolArm64/Translation/TranslatedSub.cs | 55 ++++- ChocolArm64/Translation/Translator.cs | 56 +++-- ChocolArm64/Translation/TranslatorQueue.cs | 14 +- .../Translation/TranslatorQueueItem.cs | 15 +- .../Translation/{IoType.cs => VarType.cs} | 2 +- Ryujinx/Config.jsonc | 17 +- Ryujinx/Configuration.cs | 10 + Ryujinx/_schema.json | 12 ++ 28 files changed, 456 insertions(+), 280 deletions(-) create mode 100644 ChocolArm64/Translation/CallType.cs rename ChocolArm64/Translation/{LocalAlloc.cs => RegisterUsage.cs} (56%) rename ChocolArm64/Translation/{IoType.cs => VarType.cs} (85%) diff --git a/ChocolArm64/Instructions/InstEmitFlow.cs b/ChocolArm64/Instructions/InstEmitFlow.cs index a842dca9d1..5eae89cc09 100644 --- a/ChocolArm64/Instructions/InstEmitFlow.cs +++ b/ChocolArm64/Instructions/InstEmitFlow.cs @@ -39,7 +39,6 @@ namespace ChocolArm64.Instructions context.EmitLdc_I(op.Position + 4); context.EmitStint(RegisterAlias.Lr); - context.EmitStoreState(); EmitCall(context, op.Imm); } @@ -60,6 +59,8 @@ namespace ChocolArm64.Instructions { OpCodeBReg64 op = (OpCodeBReg64)context.CurrOp; + context.HasIndirectJump = true; + context.EmitStoreState(); context.EmitLdintzr(op.Rn); diff --git a/ChocolArm64/Instructions/InstEmitFlow32.cs b/ChocolArm64/Instructions/InstEmitFlow32.cs index 61f1d34c53..dea490c775 100644 --- a/ChocolArm64/Instructions/InstEmitFlow32.cs +++ b/ChocolArm64/Instructions/InstEmitFlow32.cs @@ -65,7 +65,6 @@ namespace ChocolArm64.Instructions } context.EmitStint(GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr)); - context.EmitStoreState(); //If x is true, then this is a branch with link and exchange. //In this case we need to swap the mode between Arm <-> Thumb. diff --git a/ChocolArm64/Instructions/InstEmitFlowHelper.cs b/ChocolArm64/Instructions/InstEmitFlowHelper.cs index e93ef42679..a6091a5711 100644 --- a/ChocolArm64/Instructions/InstEmitFlowHelper.cs +++ b/ChocolArm64/Instructions/InstEmitFlowHelper.cs @@ -11,6 +11,8 @@ namespace ChocolArm64.Instructions { if (context.Tier == TranslationTier.Tier0) { + context.EmitStoreState(); + context.TranslateAhead(imm); context.EmitLdc_I8(imm); @@ -22,6 +24,10 @@ namespace ChocolArm64.Instructions if (!context.TryOptEmitSubroutineCall()) { + context.HasSlowCall = true; + + context.EmitStoreState(); + context.TranslateAhead(imm); context.EmitLdarg(TranslatedSub.StateArgIdx); @@ -32,6 +38,7 @@ namespace ChocolArm64.Instructions context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdc_I8(imm); + context.EmitLdc_I4((int)CallType.Call); context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateSubroutine)); @@ -58,20 +65,6 @@ namespace ChocolArm64.Instructions { if (context.Tier == TranslationTier.Tier0) { - context.Emit(OpCodes.Dup); - - context.EmitSttmp(); - context.EmitLdarg(TranslatedSub.StateArgIdx); - - context.EmitFieldLoad(typeof(CpuThreadState).GetField(nameof(CpuThreadState.CurrentTranslator), - BindingFlags.Instance | - BindingFlags.NonPublic)); - - context.EmitLdarg(TranslatedSub.StateArgIdx); - context.EmitLdtmp(); - - context.EmitPrivateCall(typeof(Translator), nameof(Translator.TranslateVirtualSubroutine)); - context.Emit(OpCodes.Ret); } else @@ -85,8 +78,11 @@ namespace ChocolArm64.Instructions context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdtmp(); + context.EmitLdc_I4(isJump + ? (int)CallType.VirtualJump + : (int)CallType.VirtualCall); - context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateVirtualSubroutine)); + context.EmitPrivateCall(typeof(Translator), nameof(Translator.GetOrTranslateSubroutine)); context.EmitLdarg(TranslatedSub.StateArgIdx); context.EmitLdarg(TranslatedSub.MemoryArgIdx); diff --git a/ChocolArm64/Optimizations.cs b/ChocolArm64/Optimizations.cs index 8fa6f4626c..cbb8131f5c 100644 --- a/ChocolArm64/Optimizations.cs +++ b/ChocolArm64/Optimizations.cs @@ -2,21 +2,23 @@ using System.Runtime.Intrinsics.X86; public static class Optimizations { - internal static bool FastFP = true; + public static bool AssumeStrictAbiCompliance { get; set; } - private static bool _useAllSseIfAvailable = true; + public static bool FastFP { get; set; } = true; - private static bool _useSseIfAvailable = true; - private static bool _useSse2IfAvailable = true; - private static bool _useSse3IfAvailable = true; - private static bool _useSsse3IfAvailable = true; - private static bool _useSse41IfAvailable = true; - private static bool _useSse42IfAvailable = true; + private const bool UseAllSseIfAvailable = true; - internal static bool UseSse = (_useAllSseIfAvailable && _useSseIfAvailable) && Sse.IsSupported; - internal static bool UseSse2 = (_useAllSseIfAvailable && _useSse2IfAvailable) && Sse2.IsSupported; - internal static bool UseSse3 = (_useAllSseIfAvailable && _useSse3IfAvailable) && Sse3.IsSupported; - internal static bool UseSsse3 = (_useAllSseIfAvailable && _useSsse3IfAvailable) && Ssse3.IsSupported; - internal static bool UseSse41 = (_useAllSseIfAvailable && _useSse41IfAvailable) && Sse41.IsSupported; - internal static bool UseSse42 = (_useAllSseIfAvailable && _useSse42IfAvailable) && Sse42.IsSupported; -} + public static bool UseSseIfAvailable { get; set; } = UseAllSseIfAvailable; + public static bool UseSse2IfAvailable { get; set; } = UseAllSseIfAvailable; + public static bool UseSse3IfAvailable { get; set; } = UseAllSseIfAvailable; + public static bool UseSsse3IfAvailable { get; set; } = UseAllSseIfAvailable; + public static bool UseSse41IfAvailable { get; set; } = UseAllSseIfAvailable; + public static bool UseSse42IfAvailable { get; set; } = UseAllSseIfAvailable; + + internal static bool UseSse => UseSseIfAvailable && Sse.IsSupported; + internal static bool UseSse2 => UseSse2IfAvailable && Sse2.IsSupported; + internal static bool UseSse3 => UseSse3IfAvailable && Sse3.IsSupported; + internal static bool UseSsse3 => UseSsse3IfAvailable && Ssse3.IsSupported; + internal static bool UseSse41 => UseSse41IfAvailable && Sse41.IsSupported; + internal static bool UseSse42 => UseSse42IfAvailable && Sse42.IsSupported; +} \ No newline at end of file diff --git a/ChocolArm64/Translation/CallType.cs b/ChocolArm64/Translation/CallType.cs new file mode 100644 index 0000000000..937ede768a --- /dev/null +++ b/ChocolArm64/Translation/CallType.cs @@ -0,0 +1,9 @@ +namespace ChocolArm64.Translation +{ + enum CallType + { + Call, + VirtualCall, + VirtualJump + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/ILBlock.cs b/ChocolArm64/Translation/ILBlock.cs index 136579012b..12773705a1 100644 --- a/ChocolArm64/Translation/ILBlock.cs +++ b/ChocolArm64/Translation/ILBlock.cs @@ -4,13 +4,13 @@ namespace ChocolArm64.Translation { class ILBlock : IILEmit { - public long IntInputs { get; private set; } - public long IntOutputs { get; private set; } - public long IntAwOutputs { get; private set; } + public long IntInputs { get; private set; } + public long IntOutputs { get; private set; } + private long _intAwOutputs; - public long VecInputs { get; private set; } - public long VecOutputs { get; private set; } - public long VecAwOutputs { get; private set; } + public long VecInputs { get; private set; } + public long VecOutputs { get; private set; } + private long _vecAwOutputs; public bool HasStateStore { get; private set; } @@ -34,25 +34,25 @@ namespace ChocolArm64.Translation //opcodes emitted by each ARM instruction. //We can only consider the new outputs for doing input elimination //after all the CIL opcodes used by the instruction being emitted. - IntAwOutputs = IntOutputs; - VecAwOutputs = VecOutputs; + _intAwOutputs = IntOutputs; + _vecAwOutputs = VecOutputs; } else if (emitter is ILOpCodeLoad ld && ILMethodBuilder.IsRegIndex(ld.Index)) { - switch (ld.IoType) + switch (ld.VarType) { - case IoType.Flag: IntInputs |= ((1L << ld.Index) << 32) & ~IntAwOutputs; break; - case IoType.Int: IntInputs |= (1L << ld.Index) & ~IntAwOutputs; break; - case IoType.Vector: VecInputs |= (1L << ld.Index) & ~VecAwOutputs; break; + case VarType.Flag: IntInputs |= ((1L << ld.Index) << 32) & ~_intAwOutputs; break; + case VarType.Int: IntInputs |= (1L << ld.Index) & ~_intAwOutputs; break; + case VarType.Vector: VecInputs |= (1L << ld.Index) & ~_vecAwOutputs; break; } } else if (emitter is ILOpCodeStore st && ILMethodBuilder.IsRegIndex(st.Index)) { - switch (st.IoType) + switch (st.VarType) { - case IoType.Flag: IntOutputs |= (1L << st.Index) << 32; break; - case IoType.Int: IntOutputs |= 1L << st.Index; break; - case IoType.Vector: VecOutputs |= 1L << st.Index; break; + case VarType.Flag: IntOutputs |= (1L << st.Index) << 32; break; + case VarType.Int: IntOutputs |= 1L << st.Index; break; + case VarType.Vector: VecOutputs |= 1L << st.Index; break; } } else if (emitter is ILOpCodeStoreState) diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs index f7e61bc999..91b72b13ae 100644 --- a/ChocolArm64/Translation/ILEmitterCtx.cs +++ b/ChocolArm64/Translation/ILEmitterCtx.cs @@ -31,6 +31,10 @@ namespace ChocolArm64.Translation public Aarch32Mode Mode { get; } = Aarch32Mode.User; //TODO + public bool HasIndirectJump { get; set; } + + public bool HasSlowCall { get; set; } + private Dictionary _visitedBlocks; private Queue _branchTargets; @@ -91,7 +95,12 @@ namespace ChocolArm64.Translation ResetBlockState(); - AdvanceOpCode(); + if (AdvanceOpCode()) + { + EmitSynchronization(); + + _ilBlock.Add(new ILOpCodeLoadState(_ilBlock, isSubEntry: true)); + } } public static int GetIntTempIndex() @@ -127,10 +136,18 @@ namespace ChocolArm64.Translation return; } - if (_opcIndex == 0) + int opcIndex = _opcIndex; + + if (opcIndex == 0) { MarkLabel(GetLabel(_currBlock.Position)); + } + bool isLastOp = opcIndex == CurrBlock.OpCodes.Count - 1; + + if (isLastOp && CurrBlock.Branch != null && + (ulong)CurrBlock.Branch.Position <= (ulong)CurrBlock.Position) + { EmitSynchronization(); } @@ -161,7 +178,7 @@ namespace ChocolArm64.Translation //of the next instruction to be executed (in the case that the condition //is false, and the branch was not taken, as all basic blocks should end with //some kind of branch). - if (CurrOp == CurrBlock.GetLastOp() && CurrBlock.Next == null) + if (isLastOp && CurrBlock.Next == null) { EmitStoreState(); EmitLdc_I8(CurrOp.Position + CurrOp.OpCodeSizeInBytes); @@ -285,32 +302,43 @@ namespace ChocolArm64.Translation return; } - _queue.Enqueue(new TranslatorQueueItem(position, mode, TranslationTier.Tier1)); + _queue.Enqueue(position, mode, TranslationTier.Tier1, isComplete: true); } public bool TryOptEmitSubroutineCall() { + //Calls should always have a next block, unless + //we're translating a single basic block. if (_currBlock.Next == null) { return false; } - if (CurrOp.Emitter != InstEmit.Bl) + if (!(CurrOp is IOpCodeBImm op)) { return false; } - if (!_cache.TryGetSubroutine(((OpCodeBImmAl64)CurrOp).Imm, out TranslatedSub subroutine)) + if (!_cache.TryGetSubroutine(op.Imm, out TranslatedSub sub)) { return false; } + //It's not worth to call a Tier0 method, because + //it contains slow code, rather than the entire function. + if (sub.Tier == TranslationTier.Tier0) + { + return false; + } + + EmitStoreState(sub); + for (int index = 0; index < TranslatedSub.FixedArgTypes.Length; index++) { EmitLdarg(index); } - EmitCall(subroutine.Method); + EmitCall(sub.Method); return true; } @@ -321,8 +349,8 @@ namespace ChocolArm64.Translation InstEmitAluHelper.EmitAluLoadOpers(this); - Stloc(CmpOptTmp2Index, IoType.Int); - Stloc(CmpOptTmp1Index, IoType.Int); + Stloc(CmpOptTmp2Index, VarType.Int); + Stloc(CmpOptTmp1Index, VarType.Int); } private Dictionary _branchOps = new Dictionary() @@ -346,8 +374,8 @@ namespace ChocolArm64.Translation { if (_optOpLastCompare.Emitter == InstEmit.Subs) { - Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize); - Ldloc(CmpOptTmp2Index, IoType.Int, _optOpLastCompare.RegisterSize); + Ldloc(CmpOptTmp1Index, VarType.Int, _optOpLastCompare.RegisterSize); + Ldloc(CmpOptTmp2Index, VarType.Int, _optOpLastCompare.RegisterSize); Emit(_branchOps[cond], target); @@ -369,7 +397,7 @@ namespace ChocolArm64.Translation //Such invalid values can't be encoded on the immediate encodings. if (_optOpLastCompare is IOpCodeAluImm64 op) { - Ldloc(CmpOptTmp1Index, IoType.Int, _optOpLastCompare.RegisterSize); + Ldloc(CmpOptTmp1Index, VarType.Int, _optOpLastCompare.RegisterSize); if (_optOpLastCompare.RegisterSize == RegisterSize.Int32) { @@ -491,14 +519,14 @@ namespace ChocolArm64.Translation { if (amount > 0) { - Stloc(RorTmpIndex, IoType.Int); - Ldloc(RorTmpIndex, IoType.Int); + Stloc(RorTmpIndex, VarType.Int); + Ldloc(RorTmpIndex, VarType.Int); EmitLdc_I4(amount); Emit(OpCodes.Shr_Un); - Ldloc(RorTmpIndex, IoType.Int); + Ldloc(RorTmpIndex, VarType.Int); EmitLdc_I4(CurrOp.GetBitsCount() - amount); @@ -546,7 +574,7 @@ namespace ChocolArm64.Translation public void EmitLdarg(int index) { - _ilBlock.Add(new ILOpCodeLoad(index, IoType.Arg)); + _ilBlock.Add(new ILOpCodeLoad(index, VarType.Arg)); } public void EmitLdintzr(int index) @@ -588,6 +616,11 @@ namespace ChocolArm64.Translation _ilBlock.Add(new ILOpCodeStoreState(_ilBlock)); } + private void EmitStoreState(TranslatedSub callSub) + { + _ilBlock.Add(new ILOpCodeStoreState(_ilBlock, callSub)); + } + public void EmitLdtmp() => EmitLdint(IntGpTmp1Index); public void EmitSttmp() => EmitStint(IntGpTmp1Index); @@ -600,13 +633,13 @@ namespace ChocolArm64.Translation public void EmitLdvectmp2() => EmitLdvec(VecGpTmp2Index); public void EmitStvectmp2() => EmitStvec(VecGpTmp2Index); - public void EmitLdint(int index) => Ldloc(index, IoType.Int); - public void EmitStint(int index) => Stloc(index, IoType.Int); + public void EmitLdint(int index) => Ldloc(index, VarType.Int); + public void EmitStint(int index) => Stloc(index, VarType.Int); - public void EmitLdvec(int index) => Ldloc(index, IoType.Vector); - public void EmitStvec(int index) => Stloc(index, IoType.Vector); + public void EmitLdvec(int index) => Ldloc(index, VarType.Vector); + public void EmitStvec(int index) => Stloc(index, VarType.Vector); - public void EmitLdflg(int index) => Ldloc(index, IoType.Flag); + public void EmitLdflg(int index) => Ldloc(index, VarType.Flag); public void EmitStflg(int index) { //Set this only if any of the NZCV flag bits were modified. @@ -619,22 +652,22 @@ namespace ChocolArm64.Translation _optOpLastFlagSet = CurrOp; } - Stloc(index, IoType.Flag); + Stloc(index, VarType.Flag); } - private void Ldloc(int index, IoType ioType) + private void Ldloc(int index, VarType varType) { - _ilBlock.Add(new ILOpCodeLoad(index, ioType, CurrOp.RegisterSize)); + _ilBlock.Add(new ILOpCodeLoad(index, varType, CurrOp.RegisterSize)); } - private void Ldloc(int index, IoType ioType, RegisterSize registerSize) + private void Ldloc(int index, VarType varType, RegisterSize registerSize) { - _ilBlock.Add(new ILOpCodeLoad(index, ioType, registerSize)); + _ilBlock.Add(new ILOpCodeLoad(index, varType, registerSize)); } - private void Stloc(int index, IoType ioType) + private void Stloc(int index, VarType varType) { - _ilBlock.Add(new ILOpCodeStore(index, ioType, CurrOp.RegisterSize)); + _ilBlock.Add(new ILOpCodeStore(index, varType, CurrOp.RegisterSize)); } public void EmitCallPropGet(Type objType, string propName) diff --git a/ChocolArm64/Translation/ILLabel.cs b/ChocolArm64/Translation/ILLabel.cs index f423a4256c..17a31783df 100644 --- a/ChocolArm64/Translation/ILLabel.cs +++ b/ChocolArm64/Translation/ILLabel.cs @@ -6,7 +6,7 @@ namespace ChocolArm64.Translation { private bool _hasLabel; - private Label _lbl; + private Label _label; public void Emit(ILMethodBuilder context) { @@ -17,12 +17,12 @@ namespace ChocolArm64.Translation { if (!_hasLabel) { - _lbl = context.Generator.DefineLabel(); + _label = context.Generator.DefineLabel(); _hasLabel = true; } - return _lbl; + return _label; } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILMethodBuilder.cs b/ChocolArm64/Translation/ILMethodBuilder.cs index 892f831be3..98b5052043 100644 --- a/ChocolArm64/Translation/ILMethodBuilder.cs +++ b/ChocolArm64/Translation/ILMethodBuilder.cs @@ -8,7 +8,10 @@ namespace ChocolArm64.Translation { class ILMethodBuilder { - public LocalAlloc LocalAlloc { get; private set; } + private const int RegsCount = 32; + private const int RegsMask = RegsCount - 1; + + public RegisterUsage RegUsage { get; private set; } public ILGenerator Generator { get; private set; } @@ -18,29 +21,47 @@ namespace ChocolArm64.Translation private string _subName; + public bool IsAarch64 { get; } + + public bool IsSubComplete { get; } + private int _localsCount; - public ILMethodBuilder(ILBlock[] ilBlocks, string subName) + public ILMethodBuilder( + ILBlock[] ilBlocks, + string subName, + bool isAarch64, + bool isSubComplete = false) { - _ilBlocks = ilBlocks; - _subName = subName; + _ilBlocks = ilBlocks; + _subName = subName; + IsAarch64 = isAarch64; + IsSubComplete = isSubComplete; } - public TranslatedSub GetSubroutine(TranslationTier tier) + public TranslatedSub GetSubroutine(TranslationTier tier, bool isWorthOptimizing) { - LocalAlloc = new LocalAlloc(_ilBlocks, _ilBlocks[0]); + RegUsage = new RegisterUsage(); + + RegUsage.BuildUses(_ilBlocks[0]); DynamicMethod method = new DynamicMethod(_subName, typeof(long), TranslatedSub.FixedArgTypes); - Generator = method.GetILGenerator(); + long intNiRegsMask = RegUsage.GetIntNotInputs(_ilBlocks[0]); + long vecNiRegsMask = RegUsage.GetVecNotInputs(_ilBlocks[0]); - TranslatedSub subroutine = new TranslatedSub(method, tier); + TranslatedSub subroutine = new TranslatedSub( + method, + intNiRegsMask, + vecNiRegsMask, + tier, + isWorthOptimizing); _locals = new Dictionary(); _localsCount = 0; - new ILOpCodeLoadState(_ilBlocks[0]).Emit(this); + Generator = method.GetILGenerator(); foreach (ILBlock ilBlock in _ilBlocks) { @@ -80,13 +101,13 @@ namespace ChocolArm64.Translation public static Register GetRegFromBit(int bit, RegisterType baseType) { - if (bit < 32) + if (bit < RegsCount) { return new Register(bit, baseType); } else if (baseType == RegisterType.Int) { - return new Register(bit & 0x1f, RegisterType.Flag); + return new Register(bit & RegsMask, RegisterType.Flag); } else { @@ -96,7 +117,7 @@ namespace ChocolArm64.Translation public static bool IsRegIndex(int index) { - return (uint)index < 32; + return (uint)index < RegsCount; } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILOpCode.cs b/ChocolArm64/Translation/ILOpCode.cs index 4021603c01..486452820d 100644 --- a/ChocolArm64/Translation/ILOpCode.cs +++ b/ChocolArm64/Translation/ILOpCode.cs @@ -4,16 +4,16 @@ namespace ChocolArm64.Translation { struct ILOpCode : IILEmit { - private OpCode _ilOp; + public OpCode ILOp { get; } public ILOpCode(OpCode ilOp) { - _ilOp = ilOp; + ILOp = ilOp; } public void Emit(ILMethodBuilder context) { - context.Generator.Emit(_ilOp); + context.Generator.Emit(ILOp); } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILOpCodeBranch.cs b/ChocolArm64/Translation/ILOpCodeBranch.cs index 22b80b5d52..9d4e40fa9d 100644 --- a/ChocolArm64/Translation/ILOpCodeBranch.cs +++ b/ChocolArm64/Translation/ILOpCodeBranch.cs @@ -4,18 +4,18 @@ namespace ChocolArm64.Translation { struct ILOpCodeBranch : IILEmit { - private OpCode _ilOp; - private ILLabel _label; + public OpCode ILOp { get; } + public ILLabel Label { get; } public ILOpCodeBranch(OpCode ilOp, ILLabel label) { - _ilOp = ilOp; - _label = label; + ILOp = ilOp; + Label = label; } public void Emit(ILMethodBuilder context) { - context.Generator.Emit(_ilOp, _label.GetLabel(context)); + context.Generator.Emit(ILOp, Label.GetLabel(context)); } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILOpCodeCall.cs b/ChocolArm64/Translation/ILOpCodeCall.cs index c046aeeb75..dc20417a9a 100644 --- a/ChocolArm64/Translation/ILOpCodeCall.cs +++ b/ChocolArm64/Translation/ILOpCodeCall.cs @@ -5,9 +5,9 @@ namespace ChocolArm64.Translation { struct ILOpCodeCall : IILEmit { - public MethodInfo Info { get; private set; } + public MethodInfo Info { get; } - public bool IsVirtual { get; private set; } + public bool IsVirtual { get; } public ILOpCodeCall(MethodInfo info, bool isVirtual) { diff --git a/ChocolArm64/Translation/ILOpCodeConst.cs b/ChocolArm64/Translation/ILOpCodeConst.cs index 2aaf8676ee..cd3b58ff04 100644 --- a/ChocolArm64/Translation/ILOpCodeConst.cs +++ b/ChocolArm64/Translation/ILOpCodeConst.cs @@ -16,6 +16,8 @@ namespace ChocolArm64.Translation private ImmVal _value; + public long Value => _value.I8; + private enum ConstType { Int32, diff --git a/ChocolArm64/Translation/ILOpCodeLoad.cs b/ChocolArm64/Translation/ILOpCodeLoad.cs index c31e06bbd9..0d11eeaa4b 100644 --- a/ChocolArm64/Translation/ILOpCodeLoad.cs +++ b/ChocolArm64/Translation/ILOpCodeLoad.cs @@ -5,28 +5,28 @@ namespace ChocolArm64.Translation { struct ILOpCodeLoad : IILEmit { - public int Index { get; private set; } + public int Index { get; } - public IoType IoType { get; private set; } + public VarType VarType { get; } - public RegisterSize RegisterSize { get; private set; } + public RegisterSize RegisterSize { get; } - public ILOpCodeLoad(int index, IoType ioType, RegisterSize registerSize = 0) + public ILOpCodeLoad(int index, VarType varType, RegisterSize registerSize = 0) { Index = index; - IoType = ioType; + VarType = varType; RegisterSize = registerSize; } public void Emit(ILMethodBuilder context) { - switch (IoType) + switch (VarType) { - case IoType.Arg: context.Generator.EmitLdarg(Index); break; + case VarType.Arg: context.Generator.EmitLdarg(Index); break; - case IoType.Flag: EmitLdloc(context, Index, RegisterType.Flag); break; - case IoType.Int: EmitLdloc(context, Index, RegisterType.Int); break; - case IoType.Vector: EmitLdloc(context, Index, RegisterType.Vector); break; + case VarType.Flag: EmitLdloc(context, Index, RegisterType.Flag); break; + case VarType.Int: EmitLdloc(context, Index, RegisterType.Int); break; + case VarType.Vector: EmitLdloc(context, Index, RegisterType.Vector); break; } } diff --git a/ChocolArm64/Translation/ILOpCodeLoadField.cs b/ChocolArm64/Translation/ILOpCodeLoadField.cs index abcd37c348..f0507ac226 100644 --- a/ChocolArm64/Translation/ILOpCodeLoadField.cs +++ b/ChocolArm64/Translation/ILOpCodeLoadField.cs @@ -5,7 +5,7 @@ namespace ChocolArm64.Translation { struct ILOpCodeLoadField : IILEmit { - public FieldInfo Info { get; private set; } + public FieldInfo Info { get; } public ILOpCodeLoadField(FieldInfo info) { diff --git a/ChocolArm64/Translation/ILOpCodeLoadState.cs b/ChocolArm64/Translation/ILOpCodeLoadState.cs index ddab611019..c23dc94329 100644 --- a/ChocolArm64/Translation/ILOpCodeLoadState.cs +++ b/ChocolArm64/Translation/ILOpCodeLoadState.cs @@ -7,15 +7,24 @@ namespace ChocolArm64.Translation { private ILBlock _block; - public ILOpCodeLoadState(ILBlock block) + private bool _isSubEntry; + + public ILOpCodeLoadState(ILBlock block, bool isSubEntry = false) { - _block = block; + _block = block; + _isSubEntry = isSubEntry; } public void Emit(ILMethodBuilder context) { - long intInputs = context.LocalAlloc.GetIntInputs(_block); - long vecInputs = context.LocalAlloc.GetVecInputs(_block); + long intInputs = context.RegUsage.GetIntInputs(_block); + long vecInputs = context.RegUsage.GetVecInputs(_block); + + if (Optimizations.AssumeStrictAbiCompliance && context.IsSubComplete) + { + intInputs = RegisterUsage.ClearCallerSavedIntRegs(intInputs, context.IsAarch64); + vecInputs = RegisterUsage.ClearCallerSavedVecRegs(vecInputs, context.IsAarch64); + } LoadLocals(context, intInputs, RegisterType.Int); LoadLocals(context, vecInputs, RegisterType.Vector); diff --git a/ChocolArm64/Translation/ILOpCodeLog.cs b/ChocolArm64/Translation/ILOpCodeLog.cs index ebb042b596..53846f927e 100644 --- a/ChocolArm64/Translation/ILOpCodeLog.cs +++ b/ChocolArm64/Translation/ILOpCodeLog.cs @@ -2,16 +2,16 @@ namespace ChocolArm64.Translation { struct ILOpCodeLog : IILEmit { - private string _text; + public string Text { get; } public ILOpCodeLog(string text) { - _text = text; + Text = text; } public void Emit(ILMethodBuilder context) { - context.Generator.EmitWriteLine(_text); + context.Generator.EmitWriteLine(Text); } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/ILOpCodeStore.cs b/ChocolArm64/Translation/ILOpCodeStore.cs index 17a6259c6f..7ac78e9ae4 100644 --- a/ChocolArm64/Translation/ILOpCodeStore.cs +++ b/ChocolArm64/Translation/ILOpCodeStore.cs @@ -5,28 +5,28 @@ namespace ChocolArm64.Translation { struct ILOpCodeStore : IILEmit { - public int Index { get; private set; } + public int Index { get; } - public IoType IoType { get; private set; } + public VarType VarType { get; } - public RegisterSize RegisterSize { get; private set; } + public RegisterSize RegisterSize { get; } - public ILOpCodeStore(int index, IoType ioType, RegisterSize registerSize = 0) + public ILOpCodeStore(int index, VarType varType, RegisterSize registerSize = 0) { Index = index; - IoType = ioType; + VarType = varType; RegisterSize = registerSize; } public void Emit(ILMethodBuilder context) { - switch (IoType) + switch (VarType) { - case IoType.Arg: context.Generator.EmitStarg(Index); break; + case VarType.Arg: context.Generator.EmitStarg(Index); break; - case IoType.Flag: EmitStloc(context, Index, RegisterType.Flag); break; - case IoType.Int: EmitStloc(context, Index, RegisterType.Int); break; - case IoType.Vector: EmitStloc(context, Index, RegisterType.Vector); break; + case VarType.Flag: EmitStloc(context, Index, RegisterType.Flag); break; + case VarType.Int: EmitStloc(context, Index, RegisterType.Int); break; + case VarType.Vector: EmitStloc(context, Index, RegisterType.Vector); break; } } diff --git a/ChocolArm64/Translation/ILOpCodeStoreState.cs b/ChocolArm64/Translation/ILOpCodeStoreState.cs index 458e9eda43..a587dbfe84 100644 --- a/ChocolArm64/Translation/ILOpCodeStoreState.cs +++ b/ChocolArm64/Translation/ILOpCodeStoreState.cs @@ -7,15 +7,33 @@ namespace ChocolArm64.Translation { private ILBlock _block; - public ILOpCodeStoreState(ILBlock block) + private TranslatedSub _callSub; + + public ILOpCodeStoreState(ILBlock block, TranslatedSub callSub = null) { - _block = block; + _block = block; + _callSub = callSub; } public void Emit(ILMethodBuilder context) { - long intOutputs = context.LocalAlloc.GetIntOutputs(_block); - long vecOutputs = context.LocalAlloc.GetVecOutputs(_block); + long intOutputs = context.RegUsage.GetIntOutputs(_block); + long vecOutputs = context.RegUsage.GetVecOutputs(_block); + + if (Optimizations.AssumeStrictAbiCompliance && context.IsSubComplete) + { + intOutputs = RegisterUsage.ClearCallerSavedIntRegs(intOutputs, context.IsAarch64); + vecOutputs = RegisterUsage.ClearCallerSavedVecRegs(vecOutputs, context.IsAarch64); + } + + if (_callSub != null) + { + //Those register are assigned on the callee function, without + //reading it's value first. We don't need to write them because + //they are not going to be read on the callee. + intOutputs &= ~_callSub.IntNiRegsMask; + vecOutputs &= ~_callSub.VecNiRegsMask; + } StoreLocals(context, intOutputs, RegisterType.Int); StoreLocals(context, vecOutputs, RegisterType.Vector); diff --git a/ChocolArm64/Translation/LocalAlloc.cs b/ChocolArm64/Translation/RegisterUsage.cs similarity index 56% rename from ChocolArm64/Translation/LocalAlloc.cs rename to ChocolArm64/Translation/RegisterUsage.cs index 763be6190d..2e6829d512 100644 --- a/ChocolArm64/Translation/LocalAlloc.cs +++ b/ChocolArm64/Translation/RegisterUsage.cs @@ -3,8 +3,13 @@ using System.Collections.Generic; namespace ChocolArm64.Translation { - class LocalAlloc + class RegisterUsage { + public const long CallerSavedIntRegistersMask = 0x7fL << 9; + public const long PStateNzcvFlagsMask = 0xfL << 60; + + public const long CallerSavedVecRegistersMask = 0xffffL << 16; + private class PathIo { private Dictionary _allInputs; @@ -18,31 +23,30 @@ namespace ChocolArm64.Translation _cmnOutputs = new Dictionary(); } - public PathIo(ILBlock root, long inputs, long outputs) : this() + public void Set(ILBlock entry, long inputs, long outputs) { - Set(root, inputs, outputs); - } - - public void Set(ILBlock root, long inputs, long outputs) - { - if (!_allInputs.TryAdd(root, inputs)) + if (!_allInputs.TryAdd(entry, inputs)) { - _allInputs[root] |= inputs; + _allInputs[entry] |= inputs; } - if (!_cmnOutputs.TryAdd(root, outputs)) + if (!_cmnOutputs.TryAdd(entry, outputs)) { - _cmnOutputs[root] &= outputs; + _cmnOutputs[entry] &= outputs; } _allOutputs |= outputs; } - public long GetInputs(ILBlock root) + public long GetInputs(ILBlock entry) { - if (_allInputs.TryGetValue(root, out long inputs)) + if (_allInputs.TryGetValue(entry, out long inputs)) { - return inputs | (_allOutputs & ~_cmnOutputs[root]); + //We also need to read the registers that may not be written + //by all paths that can reach a exit point, to ensure that + //the local variable will not remain uninitialized depending + //on the flow path taken. + return inputs | (_allOutputs & ~_cmnOutputs[entry]); } return 0; @@ -57,15 +61,38 @@ namespace ChocolArm64.Translation private Dictionary _intPaths; private Dictionary _vecPaths; - private struct BlockIo + private struct BlockIo : IEquatable { - public ILBlock Block; - public ILBlock Entry; + public ILBlock Block { get; } + public ILBlock Entry { get; } - public long IntInputs; - public long VecInputs; - public long IntOutputs; - public long VecOutputs; + public long IntInputs { get; set; } + public long VecInputs { get; set; } + public long IntOutputs { get; set; } + public long VecOutputs { get; set; } + + public BlockIo(ILBlock block, ILBlock entry) + { + Block = block; + Entry = entry; + + IntInputs = IntOutputs = 0; + VecInputs = VecOutputs = 0; + } + + public BlockIo( + ILBlock block, + ILBlock entry, + long intInputs, + long vecInputs, + long intOutputs, + long vecOutputs) : this(block, entry) + { + IntInputs = intInputs; + VecInputs = vecInputs; + IntOutputs = intOutputs; + VecOutputs = vecOutputs; + } public override bool Equals(object obj) { @@ -74,6 +101,11 @@ namespace ChocolArm64.Translation return false; } + return Equals(other); + } + + public bool Equals(BlockIo other) + { return other.Block == Block && other.Entry == Entry && other.IntInputs == IntInputs && @@ -98,25 +130,13 @@ namespace ChocolArm64.Translation } } - private const int MaxOptGraphLength = 40; - - public LocalAlloc(ILBlock[] graph, ILBlock entry) + public RegisterUsage() { _intPaths = new Dictionary(); _vecPaths = new Dictionary(); - - if (graph.Length > 1 && - graph.Length < MaxOptGraphLength) - { - InitializeOptimal(graph, entry); - } - else - { - InitializeFast(graph); - } } - private void InitializeOptimal(ILBlock[] graph, ILBlock entry) + public void BuildUses(ILBlock entry) { //This will go through all possible paths on the graph, //and store all inputs/outputs for each block. A register @@ -124,7 +144,7 @@ namespace ChocolArm64.Translation //When a block can be reached by more than one path, then the //output from all paths needs to be set for this block, and //only outputs present in all of the parent blocks can be considered - //when doing input elimination. Each block chain have a entry, that's where + //when doing input elimination. Each block chain has a entry, that's where //the code starts executing. They are present on the subroutine start point, //and on call return points too (address written to X30 by BL). HashSet visited = new HashSet(); @@ -133,19 +153,13 @@ namespace ChocolArm64.Translation void Enqueue(BlockIo block) { - if (!visited.Contains(block)) + if (visited.Add(block)) { unvisited.Enqueue(block); - - visited.Add(block); } } - Enqueue(new BlockIo() - { - Block = entry, - Entry = entry - }); + Enqueue(new BlockIo(entry, entry)); while (unvisited.Count > 0) { @@ -177,19 +191,21 @@ namespace ChocolArm64.Translation void EnqueueFromCurrent(ILBlock block, bool retTarget) { - BlockIo blockIo = new BlockIo() { Block = block }; + BlockIo blockIo; if (retTarget) { - blockIo.Entry = block; + blockIo = new BlockIo(block, block); } else { - blockIo.Entry = current.Entry; - blockIo.IntInputs = current.IntInputs; - blockIo.VecInputs = current.VecInputs; - blockIo.IntOutputs = current.IntOutputs; - blockIo.VecOutputs = current.VecOutputs; + blockIo = new BlockIo( + block, + current.Entry, + current.IntInputs, + current.VecInputs, + current.IntOutputs, + current.VecOutputs); } Enqueue(blockIo); @@ -207,54 +223,63 @@ namespace ChocolArm64.Translation } } - private void InitializeFast(ILBlock[] graph) - { - //This is WAY faster than InitializeOptimal, but results in - //unneeded loads and stores, so the resulting code will be slower. - long intInputs = 0, intOutputs = 0; - long vecInputs = 0, vecOutputs = 0; + public long GetIntInputs(ILBlock entry) => GetInputsImpl(entry, _intPaths.Values); + public long GetVecInputs(ILBlock entry) => GetInputsImpl(entry, _vecPaths.Values); - foreach (ILBlock block in graph) - { - intInputs |= block.IntInputs; - intOutputs |= block.IntOutputs; - vecInputs |= block.VecInputs; - vecOutputs |= block.VecOutputs; - } - - //It's possible that not all code paths writes to those output registers, - //in those cases if we attempt to write an output registers that was - //not written, we will be just writing zero and messing up the old register value. - //So we just need to ensure that all outputs are loaded. - if (graph.Length > 1) - { - intInputs |= intOutputs; - vecInputs |= vecOutputs; - } - - foreach (ILBlock block in graph) - { - _intPaths.Add(block, new PathIo(block, intInputs, intOutputs)); - _vecPaths.Add(block, new PathIo(block, vecInputs, vecOutputs)); - } - } - - public long GetIntInputs(ILBlock root) => GetInputsImpl(root, _intPaths.Values); - public long GetVecInputs(ILBlock root) => GetInputsImpl(root, _vecPaths.Values); - - private long GetInputsImpl(ILBlock root, IEnumerable values) + private long GetInputsImpl(ILBlock entry, IEnumerable values) { long inputs = 0; foreach (PathIo path in values) { - inputs |= path.GetInputs(root); + inputs |= path.GetInputs(entry); } return inputs; } + public long GetIntNotInputs(ILBlock entry) => GetNotInputsImpl(entry, _intPaths.Values); + public long GetVecNotInputs(ILBlock entry) => GetNotInputsImpl(entry, _vecPaths.Values); + + private long GetNotInputsImpl(ILBlock entry, IEnumerable values) + { + //Returns a mask with registers that are written to + //before being read. Only those registers that are + //written in all paths, and is not read before being + //written to on those paths, should be set on the mask. + long mask = -1L; + + foreach (PathIo path in values) + { + mask &= path.GetOutputs() & ~path.GetInputs(entry); + } + + return mask; + } + public long GetIntOutputs(ILBlock block) => _intPaths[block].GetOutputs(); public long GetVecOutputs(ILBlock block) => _vecPaths[block].GetOutputs(); + + public static long ClearCallerSavedIntRegs(long mask, bool isAarch64) + { + //TODO: ARM32 support. + if (isAarch64) + { + mask &= ~(CallerSavedIntRegistersMask | PStateNzcvFlagsMask); + } + + return mask; + } + + public static long ClearCallerSavedVecRegs(long mask, bool isAarch64) + { + //TODO: ARM32 support. + if (isAarch64) + { + mask &= ~CallerSavedVecRegistersMask; + } + + return mask; + } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/TranslatedSub.cs b/ChocolArm64/Translation/TranslatedSub.cs index 65d7035107..8b599b7a93 100644 --- a/ChocolArm64/Translation/TranslatedSub.cs +++ b/ChocolArm64/Translation/TranslatedSub.cs @@ -10,21 +10,41 @@ namespace ChocolArm64.Translation class TranslatedSub { + //This is the minimum amount of calls needed for the method + //to be retranslated with higher quality code. It's only worth + //doing that for hot code. + private const int MinCallCountForOpt = 30; + public ArmSubroutine Delegate { get; private set; } - public static int StateArgIdx { get; private set; } - public static int MemoryArgIdx { get; private set; } + public static int StateArgIdx { get; } + public static int MemoryArgIdx { get; } - public static Type[] FixedArgTypes { get; private set; } + public static Type[] FixedArgTypes { get; } - public DynamicMethod Method { get; private set; } + public DynamicMethod Method { get; } - public TranslationTier Tier { get; private set; } + public TranslationTier Tier { get; } - public TranslatedSub(DynamicMethod method, TranslationTier tier) + public long IntNiRegsMask { get; } + public long VecNiRegsMask { get; } + + private bool _isWorthOptimizing; + + private int _callCount; + + public TranslatedSub( + DynamicMethod method, + long intNiRegsMask, + long vecNiRegsMask, + TranslationTier tier, + bool isWorthOptimizing) { - Method = method ?? throw new ArgumentNullException(nameof(method));; - Tier = tier; + Method = method ?? throw new ArgumentNullException(nameof(method));; + IntNiRegsMask = intNiRegsMask; + VecNiRegsMask = vecNiRegsMask; + _isWorthOptimizing = isWorthOptimizing; + Tier = tier; } static TranslatedSub() @@ -61,5 +81,24 @@ namespace ChocolArm64.Translation { return Delegate(threadState, memory); } + + public bool IsWorthOptimizing() + { + if (!_isWorthOptimizing) + { + return false; + } + + if (_callCount++ < MinCallCountForOpt) + { + return false; + } + + //Only return true once, so that it is + //added to the queue only once. + _isWorthOptimizing = false; + + return true; + } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/Translator.cs b/ChocolArm64/Translation/Translator.cs index dd1215f50c..bda0bca09f 100644 --- a/ChocolArm64/Translation/Translator.cs +++ b/ChocolArm64/Translation/Translator.cs @@ -63,48 +63,36 @@ namespace ChocolArm64.Translation CpuTrace?.Invoke(this, new CpuTraceEventArgs(position)); } - TranslatedSub subroutine = GetOrTranslateSubroutine(state, position); + if (!_cache.TryGetSubroutine(position, out TranslatedSub sub)) + { + sub = TranslateLowCq(position, state.GetExecutionMode()); + } - position = subroutine.Execute(state, _memory); + position = sub.Execute(state, _memory); } while (position != 0 && state.Running); state.CurrentTranslator = null; } - internal void TranslateVirtualSubroutine(CpuThreadState state, long position) - { - if (!_cache.TryGetSubroutine(position, out TranslatedSub sub) || sub.Tier == TranslationTier.Tier0) - { - _queue.Enqueue(new TranslatorQueueItem(position, state.GetExecutionMode(), TranslationTier.Tier1)); - } - } - - internal ArmSubroutine GetOrTranslateVirtualSubroutine(CpuThreadState state, long position) + internal ArmSubroutine GetOrTranslateSubroutine(CpuThreadState state, long position, CallType cs) { if (!_cache.TryGetSubroutine(position, out TranslatedSub sub)) { sub = TranslateLowCq(position, state.GetExecutionMode()); } - if (sub.Tier == TranslationTier.Tier0) + if (sub.IsWorthOptimizing()) { - _queue.Enqueue(new TranslatorQueueItem(position, state.GetExecutionMode(), TranslationTier.Tier1)); + bool isComplete = cs == CallType.Call || + cs == CallType.VirtualCall; + + _queue.Enqueue(position, state.GetExecutionMode(), TranslationTier.Tier1, isComplete); } return sub.Delegate; } - internal TranslatedSub GetOrTranslateSubroutine(CpuThreadState state, long position) - { - if (!_cache.TryGetSubroutine(position, out TranslatedSub subroutine)) - { - subroutine = TranslateLowCq(position, state.GetExecutionMode()); - } - - return subroutine; - } - private void TranslateQueuedSubs() { while (_threadCount != 0) @@ -124,7 +112,7 @@ namespace ChocolArm64.Translation } else { - TranslateHighCq(item.Position, item.Mode); + TranslateHighCq(item.Position, item.Mode, item.IsComplete); } } else @@ -142,14 +130,16 @@ namespace ChocolArm64.Translation string subName = GetSubroutineName(position); - ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(context.GetILBlocks(), subName); + bool isAarch64 = mode == ExecutionMode.Aarch64; - TranslatedSub subroutine = ilMthdBuilder.GetSubroutine(TranslationTier.Tier0); + ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(context.GetILBlocks(), subName, isAarch64); + + TranslatedSub subroutine = ilMthdBuilder.GetSubroutine(TranslationTier.Tier0, isWorthOptimizing: true); return _cache.GetOrAdd(position, subroutine, block.OpCodes.Count); } - private void TranslateHighCq(long position, ExecutionMode mode) + private TranslatedSub TranslateHighCq(long position, ExecutionMode mode, bool isComplete) { Block graph = Decoder.DecodeSubroutine(_memory, position, mode); @@ -159,9 +149,13 @@ namespace ChocolArm64.Translation string subName = GetSubroutineName(position); - ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(ilBlocks, subName); + bool isAarch64 = mode == ExecutionMode.Aarch64; - TranslatedSub subroutine = ilMthdBuilder.GetSubroutine(TranslationTier.Tier1); + isComplete &= !context.HasIndirectJump; + + ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(ilBlocks, subName, isAarch64, isComplete); + + TranslatedSub subroutine = ilMthdBuilder.GetSubroutine(TranslationTier.Tier1, context.HasSlowCall); int ilOpCount = 0; @@ -170,9 +164,11 @@ namespace ChocolArm64.Translation ilOpCount += ilBlock.Count; } + ForceAheadOfTimeCompilation(subroutine); + _cache.AddOrUpdate(position, subroutine, ilOpCount); - ForceAheadOfTimeCompilation(subroutine); + return subroutine; } private string GetSubroutineName(long position) diff --git a/ChocolArm64/Translation/TranslatorQueue.cs b/ChocolArm64/Translation/TranslatorQueue.cs index 89d665bfbd..0f1d847470 100644 --- a/ChocolArm64/Translation/TranslatorQueue.cs +++ b/ChocolArm64/Translation/TranslatorQueue.cs @@ -1,3 +1,4 @@ +using ChocolArm64.State; using System.Collections.Concurrent; using System.Threading; @@ -5,10 +6,6 @@ namespace ChocolArm64.Translation { class TranslatorQueue { - //This is the maximum number of functions to be translated that the queue can hold. - //The value may need some tuning to find the sweet spot. - private const int MaxQueueSize = 1024; - private ConcurrentStack[] _translationQueue; private ManualResetEvent _queueDataReceivedEvent; @@ -27,14 +24,11 @@ namespace ChocolArm64.Translation _queueDataReceivedEvent = new ManualResetEvent(false); } - public void Enqueue(TranslatorQueueItem item) + public void Enqueue(long position, ExecutionMode mode, TranslationTier tier, bool isComplete) { - ConcurrentStack queue = _translationQueue[(int)item.Tier]; + TranslatorQueueItem item = new TranslatorQueueItem(position, mode, tier, isComplete); - if (queue.Count >= MaxQueueSize) - { - queue.TryPop(out _); - } + ConcurrentStack queue = _translationQueue[(int)tier]; queue.Push(item); diff --git a/ChocolArm64/Translation/TranslatorQueueItem.cs b/ChocolArm64/Translation/TranslatorQueueItem.cs index 0988414a50..dde2706d98 100644 --- a/ChocolArm64/Translation/TranslatorQueueItem.cs +++ b/ChocolArm64/Translation/TranslatorQueueItem.cs @@ -10,11 +10,18 @@ namespace ChocolArm64.Translation public TranslationTier Tier { get; } - public TranslatorQueueItem(long position, ExecutionMode mode, TranslationTier tier) + public bool IsComplete { get; } + + public TranslatorQueueItem( + long position, + ExecutionMode mode, + TranslationTier tier, + bool isComplete = false) { - Position = position; - Mode = mode; - Tier = tier; + Position = position; + Mode = mode; + Tier = tier; + IsComplete = isComplete; } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/IoType.cs b/ChocolArm64/Translation/VarType.cs similarity index 85% rename from ChocolArm64/Translation/IoType.cs rename to ChocolArm64/Translation/VarType.cs index c7710e0c67..d671575e98 100644 --- a/ChocolArm64/Translation/IoType.cs +++ b/ChocolArm64/Translation/VarType.cs @@ -1,6 +1,6 @@ namespace ChocolArm64.Translation { - enum IoType + enum VarType { Arg, Flag, diff --git a/Ryujinx/Config.jsonc b/Ryujinx/Config.jsonc index 8b5ebe0328..6e808b56fd 100644 --- a/Ryujinx/Config.jsonc +++ b/Ryujinx/Config.jsonc @@ -29,18 +29,21 @@ // System Language list: https://gist.github.com/HorrorTroll/b6e4a88d774c3c9b3bdf54d79a7ca43b "system_language": "AmericanEnglish", - // Enable or Disable Docked Mode + // Enable or disable Docked Mode "docked_mode": false, - - // Enable or Disable Game Vsync + + // Enable or disable Game Vsync "enable_vsync": true, - - // Enable or Disable Multi-core scheduling of threads + + // Enable or disable Multi-core scheduling of threads "enable_multicore_scheduling": true, - + // Enable integrity checks on Switch content files "enable_fs_integrity_checks": true, - + + // Enable or disable aggressive CPU optimizations + "enable_aggressive_cpu_opts": true, + // The primary controller's type // Supported Values: Handheld, ProController, NpadPair, NpadLeft, NpadRight "controller_type": "Handheld", diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs index dbbec1cbc6..c4a1b4369f 100644 --- a/Ryujinx/Configuration.cs +++ b/Ryujinx/Configuration.cs @@ -86,6 +86,11 @@ namespace Ryujinx /// public bool EnableFsIntegrityChecks { get; private set; } + /// + /// Enable or Disable aggressive CPU optimizations + /// + public bool EnableAggressiveCpuOpts { get; private set; } + /// /// The primary controller's type /// @@ -197,6 +202,11 @@ namespace Ryujinx ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; + if (Instance.EnableAggressiveCpuOpts) + { + Optimizations.AssumeStrictAbiCompliance = true; + } + if(Instance.GamepadControls.Enabled) { if (GamePad.GetName(Instance.GamepadControls.Index) == "Unmapped Controller") diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json index 0e586671d6..7e7e466594 100644 --- a/Ryujinx/_schema.json +++ b/Ryujinx/_schema.json @@ -17,6 +17,7 @@ "enable_vsync", "enable_multicore_scheduling", "enable_fs_integrity_checks", + "enable_aggressive_cpu_opts", "controller_type", "keyboard_controls", "gamepad_controls" @@ -399,6 +400,17 @@ false ] }, + "enable_aggressive_cpu_opts": { + "$id": "#/properties/enable_aggressive_cpu_opts", + "type": "boolean", + "title": "Enable Aggressive CPU Optimizations", + "description": "Enable or disable aggressive CPU optimizations", + "default": true, + "examples": [ + true, + false + ] + }, "controller_type": { "$id": "#/properties/controller_type", "type": "string", From dbc105eafba1db23858c015d6bd24c42c5dc255c Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Fri, 1 Mar 2019 10:12:09 +0100 Subject: [PATCH 17/36] Create CpuTestSimdImm.cs (#608) --- Ryujinx.Tests/Cpu/CpuTestSimdImm.cs | 267 ++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 Ryujinx.Tests/Cpu/CpuTestSimdImm.cs diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs new file mode 100644 index 0000000000..bb6e117395 --- /dev/null +++ b/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs @@ -0,0 +1,267 @@ +#define SimdImm + +using NUnit.Framework; + +using System.Collections.Generic; +using System.Runtime.Intrinsics; + +namespace Ryujinx.Tests.Cpu +{ + [Category("SimdImm")] + public sealed class CpuTestSimdImm : CpuTest + { +#if SimdImm + +#region "Helper methods" + // abcdefgh -> aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh + private static ulong ExpandImm8(byte imm8) + { + ulong imm64 = 0ul; + + for (int i = 0, j = 0; i < 8; i++, j += 8) + { + if (((imm8 >> i) & 0b1) != 0) + { + imm64 |= 0b11111111ul << j; + } + } + + return imm64; + } + + // aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh -> abcdefgh + private static byte ShrinkImm64(ulong imm64) + { + byte imm8 = 0; + + for (int i = 0, j = 0; i < 8; i++, j += 8) + { + if (((imm64 >> j) & 0b11111111ul) != 0ul) // Note: no format check. + { + imm8 |= (byte)(0b1 << i); + } + } + + return imm8; + } +#endregion + +#region "ValueSource (Types)" + private static IEnumerable _8BIT_IMM_() + { + yield return 0x00; + yield return 0x7F; + yield return 0x80; + yield return 0xFF; + + for (int cnt = 1; cnt <= RndCntImm8; cnt++) + { + byte imm8 = TestContext.CurrentContext.Random.NextByte(); + + yield return imm8; + } + } + + private static IEnumerable _64BIT_IMM_() + { + yield return ExpandImm8(0x00); + yield return ExpandImm8(0x7F); + yield return ExpandImm8(0x80); + yield return ExpandImm8(0xFF); + + for (int cnt = 1; cnt <= RndCntImm64; cnt++) + { + byte imm8 = TestContext.CurrentContext.Random.NextByte(); + + yield return ExpandImm8(imm8); + } + } +#endregion + +#region "ValueSource (Opcodes)" + private static uint[] _Movi_V_8bit_() + { + return new uint[] + { + 0x0F00E400u // MOVI V0.8B, #0 + }; + } + + private static uint[] _Movi_Mvni_V_16bit_shifted_imm_() + { + return new uint[] + { + 0x0F008400u, // MOVI V0.4H, #0 + 0x2F008400u // MVNI V0.4H, #0 + }; + } + + private static uint[] _Movi_Mvni_V_32bit_shifted_imm_() + { + return new uint[] + { + 0x0F000400u, // MOVI V0.2S, #0 + 0x2F000400u // MVNI V0.2S, #0 + }; + } + + private static uint[] _Movi_Mvni_V_32bit_shifting_ones_() + { + return new uint[] + { + 0x0F00C400u, // MOVI V0.2S, #0, MSL #8 + 0x2F00C400u // MVNI V0.2S, #0, MSL #8 + }; + } + + private static uint[] _Movi_V_64bit_scalar_() + { + return new uint[] + { + 0x2F00E400u // MOVI D0, #0 + }; + } + + private static uint[] _Movi_V_64bit_vector_() + { + return new uint[] + { + 0x6F00E400u // MOVI V0.2D, #0 + }; + } +#endregion + + private const int RndCntImm8 = 2; + private const int RndCntImm64 = 2; + + [Test, Pairwise] + public void Movi_V_8bit([ValueSource("_Movi_V_8bit_")] uint opcodes, + [Values(0u)] uint rd, + [ValueSource("_8BIT_IMM_")] byte imm8, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + uint abc = (imm8 & 0xE0u) >> 5; + uint defgh = (imm8 & 0x1Fu); + + opcodes |= ((rd & 31) << 0); + opcodes |= (abc << 16) | (defgh << 5); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(q == 0u ? z : 0ul); + + SingleOpcode(opcodes, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Movi_Mvni_V_16bit_shifted_imm([ValueSource("_Movi_Mvni_V_16bit_shifted_imm_")] uint opcodes, + [Values(0u)] uint rd, + [ValueSource("_8BIT_IMM_")] byte imm8, + [Values(0b0u, 0b1u)] uint amount, // <0, 8> + [Values(0b0u, 0b1u)] uint q) // <4H, 8H> + { + uint abc = (imm8 & 0xE0u) >> 5; + uint defgh = (imm8 & 0x1Fu); + + opcodes |= ((rd & 31) << 0); + opcodes |= (abc << 16) | (defgh << 5); + opcodes |= ((amount & 1) << 13); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(q == 0u ? z : 0ul); + + SingleOpcode(opcodes, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Movi_Mvni_V_32bit_shifted_imm([ValueSource("_Movi_Mvni_V_32bit_shifted_imm_")] uint opcodes, + [Values(0u)] uint rd, + [ValueSource("_8BIT_IMM_")] byte imm8, + [Values(0b00u, 0b01u, 0b10u, 0b11u)] uint amount, // <0, 8, 16, 24> + [Values(0b0u, 0b1u)] uint q) // <2S, 4S> + { + uint abc = (imm8 & 0xE0u) >> 5; + uint defgh = (imm8 & 0x1Fu); + + opcodes |= ((rd & 31) << 0); + opcodes |= (abc << 16) | (defgh << 5); + opcodes |= ((amount & 3) << 13); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(q == 0u ? z : 0ul); + + SingleOpcode(opcodes, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Movi_Mvni_V_32bit_shifting_ones([ValueSource("_Movi_Mvni_V_32bit_shifting_ones_")] uint opcodes, + [Values(0u)] uint rd, + [ValueSource("_8BIT_IMM_")] byte imm8, + [Values(0b0u, 0b1u)] uint amount, // <8, 16> + [Values(0b0u, 0b1u)] uint q) // <2S, 4S> + { + uint abc = (imm8 & 0xE0u) >> 5; + uint defgh = (imm8 & 0x1Fu); + + opcodes |= ((rd & 31) << 0); + opcodes |= (abc << 16) | (defgh << 5); + opcodes |= ((amount & 1) << 12); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(q == 0u ? z : 0ul); + + SingleOpcode(opcodes, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Movi_V_64bit_scalar([ValueSource("_Movi_V_64bit_scalar_")] uint opcodes, + [Values(0u)] uint rd, + [ValueSource("_64BIT_IMM_")] ulong imm) + { + byte imm8 = ShrinkImm64(imm); + + uint abc = (imm8 & 0xE0u) >> 5; + uint defgh = (imm8 & 0x1Fu); + + opcodes |= ((rd & 31) << 0); + opcodes |= (abc << 16) | (defgh << 5); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(z); + + SingleOpcode(opcodes, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Movi_V_64bit_vector([ValueSource("_Movi_V_64bit_vector_")] uint opcodes, + [Values(0u)] uint rd, + [ValueSource("_64BIT_IMM_")] ulong imm) + { + byte imm8 = ShrinkImm64(imm); + + uint abc = (imm8 & 0xE0u) >> 5; + uint defgh = (imm8 & 0x1Fu); + + opcodes |= ((rd & 31) << 0); + opcodes |= (abc << 16) | (defgh << 5); + + SingleOpcode(opcodes); + + CompareAgainstUnicorn(); + } +#endif + } +} From 0973daefa1a509a8b08c936384251f1fee475587 Mon Sep 17 00:00:00 2001 From: BaronKiko Date: Sat, 2 Mar 2019 10:50:21 +0000 Subject: [PATCH 18/36] Fixed Scissor Test on Intel based GPUs (#595) * Reworked scissor tests to remove fixme and handle issues with intel gpu's * Error handling for scissor tests * Disable strict opengl by default * Reformatting for JD * Updated scheme for new property in config * Fixed typo * Moved magic value to constant. I liked the magic :( * Fixed ordering for undertale * Fixed undertale bug * Removed strict opengl in favour of required. With this an exception is no longer thrown, just a warning for required extensions * Uses clamp instead of if's * Removed evil tabs and no longer used include --- Ryujinx.Graphics/Gal/IGalPipeline.cs | 1 + Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs | 36 +++++- Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs | 85 +++++++------ .../Gal/OpenGL/OGLRenderTarget.cs | 3 - Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs | 117 +++++++++++++----- Ryujinx.Graphics/NvGpu.cs | 2 + 6 files changed, 171 insertions(+), 73 deletions(-) diff --git a/Ryujinx.Graphics/Gal/IGalPipeline.cs b/Ryujinx.Graphics/Gal/IGalPipeline.cs index cba4e7dcc6..cb470fb4b4 100644 --- a/Ryujinx.Graphics/Gal/IGalPipeline.cs +++ b/Ryujinx.Graphics/Gal/IGalPipeline.cs @@ -3,6 +3,7 @@ public interface IGalPipeline { void Bind(GalPipelineState State); + void Unbind(GalPipelineState State); void ResetDepthMask(); void ResetColorMask(int Index); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs index 52b3d0ce31..eb06f83ca9 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs @@ -1,19 +1,23 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Common.Logging; using System; namespace Ryujinx.Graphics.Gal.OpenGL { static class OGLExtension { + // Private lazy backing variables private static Lazy s_EnhancedLayouts = new Lazy(() => HasExtension("GL_ARB_enhanced_layouts")); private static Lazy s_TextureMirrorClamp = new Lazy(() => HasExtension("GL_EXT_texture_mirror_clamp")); private static Lazy s_ViewportArray = new Lazy(() => HasExtension("GL_ARB_viewport_array")); private static Lazy s_NvidiaDriver = new Lazy(() => IsNvidiaDriver()); + // Public accessors public static bool EnhancedLayouts => s_EnhancedLayouts.Value; public static bool TextureMirrorClamp => s_TextureMirrorClamp.Value; public static bool ViewportArray => s_ViewportArray.Value; + public static bool NvidiaDrvier => s_NvidiaDriver.Value; private static bool HasExtension(string Name) @@ -28,11 +32,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } + Logger.PrintInfo(LogClass.Gpu, $"OpenGL extension {Name} unavailable. You may experience some performance degredation"); + return false; } - private static bool IsNvidiaDriver() { + private static bool IsNvidiaDriver() + { return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation"); } + + public static class Required + { + // Public accessors + public static bool EnhancedLayouts => s_EnhancedLayoutsRequired.Value; + public static bool TextureMirrorClamp => s_TextureMirrorClampRequired.Value; + public static bool ViewportArray => s_ViewportArrayRequired.Value; + + // Private lazy backing variables + private static Lazy s_EnhancedLayoutsRequired = new Lazy(() => HasExtensionRequired(OGLExtension.EnhancedLayouts, "GL_ARB_enhanced_layouts")); + private static Lazy s_TextureMirrorClampRequired = new Lazy(() => HasExtensionRequired(OGLExtension.TextureMirrorClamp, "GL_EXT_texture_mirror_clamp")); + private static Lazy s_ViewportArrayRequired = new Lazy(() => HasExtensionRequired(OGLExtension.ViewportArray, "GL_ARB_viewport_array")); + + private static bool HasExtensionRequired(bool Value, string Name) + { + if (Value) + { + return true; + } + + Logger.PrintWarning(LogClass.Gpu, $"Required OpenGL extension {Name} unavailable. You may experience some rendering issues"); + + return false; + } + } } -} \ No newline at end of file +} diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs index 6a928603ae..96d42e0238 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs @@ -270,47 +270,52 @@ namespace Ryujinx.Graphics.Gal.OpenGL // Scissor Test - bool forceUpdate; - - for (int Index = 0; Index < New.ScissorTestCount; Index++) + // All scissor test are disabled before drawing final framebuffer to screen so we don't need to handle disabling + // Skip if there are no scissor tests to enable + if (New.ScissorTestCount != 0) { - forceUpdate = false; + int scissorsApplied = 0; + bool applyToAll = false; - if (New.ScissorTestEnabled[Index]) + for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) { - // If there is only 1 scissor test, geometry shaders are disabled so the scissor test applies to all viewports - if (New.ScissorTestCount == 1) + if (New.ScissorTestEnabled[Index]) { - GL.Enable(EnableCap.ScissorTest); - } - else - { - GL.Enable(IndexedEnableCap.ScissorTest, Index); - } - forceUpdate = true; - } - else - { - GL.Disable(IndexedEnableCap.ScissorTest, Index); - } + // If viewport arrays are unavailable apply first scissor test to all or + // there is only 1 scissor test and it's the first, the scissor test applies to all viewports + if (!OGLExtension.Required.ViewportArray || (Index == 0 && New.ScissorTestCount == 1)) + { + GL.Enable(EnableCap.ScissorTest); + applyToAll = true; + } + else + { + GL.Enable(IndexedEnableCap.ScissorTest, Index); + } - if (New.ScissorTestEnabled[Index] && - (New.ScissorTestX[Index] != Old.ScissorTestX[Index] || - New.ScissorTestY[Index] != Old.ScissorTestY[Index] || - New.ScissorTestWidth[Index] != Old.ScissorTestWidth[Index] || - New.ScissorTestHeight[Index] != Old.ScissorTestHeight[Index] || - forceUpdate)) // Force update intentionally last to reduce if comparisons - { - // If there is only 1 scissor test geometry shaders are disables so the scissor test applies to all viewports - if (New.ScissorTestCount == 1) - { - GL.Scissor(New.ScissorTestX[Index], New.ScissorTestY[Index], - New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]); - } - else - { - GL.ScissorIndexed(Index, New.ScissorTestX[Index], New.ScissorTestY[Index], - New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]); + if (New.ScissorTestEnabled[Index] != Old.ScissorTestEnabled[Index] || + New.ScissorTestX[Index] != Old.ScissorTestX[Index] || + New.ScissorTestY[Index] != Old.ScissorTestY[Index] || + New.ScissorTestWidth[Index] != Old.ScissorTestWidth[Index] || + New.ScissorTestHeight[Index] != Old.ScissorTestHeight[Index]) + { + if (applyToAll) + { + GL.Scissor(New.ScissorTestX[Index], New.ScissorTestY[Index], + New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]); + } + else + { + GL.ScissorIndexed(Index, New.ScissorTestX[Index], New.ScissorTestY[Index], + New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]); + } + } + + // If all scissor tests have been applied, or viewport arrays are unavailable we can skip remaining itterations + if (!OGLExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount) + { + break; + } } } } @@ -378,6 +383,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL Old = New; } + public void Unbind(GalPipelineState State) + { + if (State.ScissorTestCount > 0) + { + GL.Disable(EnableCap.ScissorTest); + } + } + private void SetAllBlendState(BlendState New) { Enable(EnableCap.Blend, New.Enabled); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs index 8dd3b37fc2..53cfd4a604 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs @@ -367,9 +367,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.Disable(EnableCap.FramebufferSrgb); - // Will be re-enabled if needed while binding, called before any game GL calls - GL.Disable(EnableCap.ScissorTest); - GL.BlitFramebuffer( SrcX0, SrcY0, diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs index eb6289fbdb..370fe1fa86 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs @@ -25,7 +25,12 @@ namespace Ryujinx.Graphics.Graphics3d private ConstBuffer[][] ConstBuffers; - // Height kept for flipping y axis + // Viewport dimensions kept for scissor test limits + private int ViewportX0 = 0; + private int ViewportY0 = 0; + private int ViewportX1 = 0; + private int ViewportY1 = 0; + private int ViewportWidth = 0; private int ViewportHeight = 0; private int CurrentInstance = 0; @@ -98,7 +103,14 @@ namespace Ryujinx.Graphics.Graphics3d GalPipelineState State = new GalPipelineState(); + // Framebuffer must be run configured because viewport dimensions may be used in other methods SetFrameBuffer(State); + + for (int FbIndex = 0; FbIndex < 8; FbIndex++) + { + SetFrameBuffer(Vmm, FbIndex); + } + SetFrontFace(State); SetCullFace(State); SetDepth(State); @@ -108,11 +120,6 @@ namespace Ryujinx.Graphics.Graphics3d SetColorMask(State); SetPrimitiveRestart(State); - for (int FbIndex = 0; FbIndex < 8; FbIndex++) - { - SetFrameBuffer(Vmm, FbIndex); - } - SetZeta(Vmm); SetRenderTargets(); @@ -207,11 +214,11 @@ namespace Ryujinx.Graphics.Graphics3d float SX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + FbIndex * 8); float SY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + FbIndex * 8); - int VpX = (int)MathF.Max(0, TX - MathF.Abs(SX)); - int VpY = (int)MathF.Max(0, TY - MathF.Abs(SY)); + ViewportX0 = (int)MathF.Max(0, TX - MathF.Abs(SX)); + ViewportY0 = (int)MathF.Max(0, TY - MathF.Abs(SY)); - int VpW = (int)(TX + MathF.Abs(SX)) - VpX; - int VpH = (int)(TY + MathF.Abs(SY)) - VpY; + ViewportX1 = (int)(TX + MathF.Abs(SX)); + ViewportY1 = (int)(TY + MathF.Abs(SY)); GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat); @@ -219,9 +226,7 @@ namespace Ryujinx.Graphics.Graphics3d Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image); - ViewportHeight = VpH; - - Gpu.Renderer.RenderTarget.SetViewport(FbIndex, VpX, VpY, VpW, VpH); + Gpu.Renderer.RenderTarget.SetViewport(FbIndex, ViewportX0, ViewportY0, ViewportX1 - ViewportX0, ViewportY1 - ViewportY0); } private void SetFrameBuffer(GalPipelineState State) @@ -423,38 +428,83 @@ namespace Ryujinx.Graphics.Graphics3d private void SetScissor(GalPipelineState State) { - // FIXME: Stubbed, only the first scissor test is valid without a geometry shader loaded. At time of writing geometry shaders are also stubbed. - // Once geometry shaders are fixed it should be equal to GalPipelineState.RenderTargetCount when shader loaded, otherwise equal to 1 - State.ScissorTestCount = 1; + int count = 0; - for (int Index = 0; Index < State.ScissorTestCount; Index++) + for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) { State.ScissorTestEnabled[Index] = ReadRegisterBool(NvGpuEngine3dReg.ScissorEnable + Index * 4); if (State.ScissorTestEnabled[Index]) { - uint ScissorHorizontal = (uint)ReadRegister(NvGpuEngine3dReg.ScissorHorizontal + Index * 4); - uint ScissorVertical = (uint)ReadRegister(NvGpuEngine3dReg.ScissorVertical + Index * 4); + uint ScissorHorizontal = (uint)ReadRegister(NvGpuEngine3dReg.ScissorHorizontal + Index * 4); + uint ScissorVertical = (uint)ReadRegister(NvGpuEngine3dReg.ScissorVertical + Index * 4); - State.ScissorTestX[Index] = (int)((ScissorHorizontal & 0xFFFF) * State.FlipX); // X, lower 16 bits - State.ScissorTestWidth[Index] = (int)((ScissorHorizontal >> 16) * State.FlipX) - State.ScissorTestX[Index]; // Width, right side is upper 16 bits + int left = (int)(ScissorHorizontal & 0xFFFF); // Left, lower 16 bits + int right = (int)(ScissorHorizontal >> 16); // Right, upper 16 bits - State.ScissorTestY[Index] = (int)((ScissorVertical & 0xFFFF)); // Y, lower 16 bits - State.ScissorTestHeight[Index] = (int)((ScissorVertical >> 16)) - State.ScissorTestY[Index]; // Height, top side is upper 16 bits + int bottom = (int)(ScissorVertical & 0xFFFF); // Bottom, lower 16 bits + int top = (int)(ScissorVertical >> 16); // Top, upper 16 bits - // Y coordinates may have to be flipped - if ((int)State.FlipY == -1) + int width = Math.Abs(right - left); + int height = Math.Abs(top - bottom); + + // If the scissor test covers the whole possible viewport, i.e. uninititalized, disable scissor test + if ((width > NvGpu.MaxViewportSize && height > NvGpu.MaxViewportSize) || width <= 0 || height <= 0) { - State.ScissorTestY[Index] = ViewportHeight - State.ScissorTestY[Index] - State.ScissorTestHeight[Index]; - - // Handle negative viewpont coordinate - if (State.ScissorTestY[Index] < 0) - { - State.ScissorTestY[Index] = 0; - } + State.ScissorTestEnabled[Index] = false; + continue; } + + // Keep track of how many scissor tests are active. + // If only 1, and it's the first user should apply to all viewports + count++; + + // Flip X + if (State.FlipX == -1) + { + left = ViewportX1 - (left - ViewportX0); + right = ViewportX1 - (right - ViewportX0); + } + + // Ensure X is in the right order + if (left > right) + { + int temp = left; + left = right; + right = temp; + } + + // Flip Y + if (State.FlipY == -1) + { + bottom = ViewportY1 - (bottom - ViewportY0); + top = ViewportY1 - (top - ViewportY0); + } + + // Ensure Y is in the right order + if (bottom > top) + { + int temp = top; + top = bottom; + bottom = temp; + } + + // Handle out of active viewport dimensions + left = Math.Clamp(left, ViewportX0, ViewportX1); + right = Math.Clamp(right, ViewportX0, ViewportX1); + top = Math.Clamp(top, ViewportY0, ViewportY1); + bottom = Math.Clamp(bottom, ViewportY0, ViewportY1); + + // Save values to state + State.ScissorTestX[Index] = left; + State.ScissorTestY[Index] = bottom; + + State.ScissorTestWidth[Index] = right - left; + State.ScissorTestHeight[Index] = top - bottom; } } + + State.ScissorTestCount = count; } private void SetBlending(GalPipelineState State) @@ -997,6 +1047,9 @@ namespace Ryujinx.Graphics.Graphics3d Gpu.Renderer.Rasterizer.DrawArrays(VertexFirst, VertexCount, PrimType); } + // Reset pipeline for host OpenGL calls + Gpu.Renderer.Pipeline.Unbind(State); + //Is the GPU really clearing those registers after draw? WriteRegister(NvGpuEngine3dReg.IndexBatchFirst, 0); WriteRegister(NvGpuEngine3dReg.IndexBatchCount, 0); diff --git a/Ryujinx.Graphics/NvGpu.cs b/Ryujinx.Graphics/NvGpu.cs index 3fd91f74a5..4669c8998c 100644 --- a/Ryujinx.Graphics/NvGpu.cs +++ b/Ryujinx.Graphics/NvGpu.cs @@ -8,6 +8,8 @@ namespace Ryujinx.Graphics { public class NvGpu { + public const int MaxViewportSize = 0x3FFF; + public IGalRenderer Renderer { get; private set; } public GpuResourceManager ResourceManager { get; private set; } From 8e71ea0812f6b56ff819dbda951b463bcb5eb8dc Mon Sep 17 00:00:00 2001 From: Ryan Teal Date: Sat, 2 Mar 2019 10:51:55 +0000 Subject: [PATCH 19/36] Reuse basePath variable in LocationHelper (#609) --- Ryujinx.HLE/FileSystem/Content/LocationHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Ryujinx.HLE/FileSystem/Content/LocationHelper.cs b/Ryujinx.HLE/FileSystem/Content/LocationHelper.cs index df3f5ad655..c522b053ba 100644 --- a/Ryujinx.HLE/FileSystem/Content/LocationHelper.cs +++ b/Ryujinx.HLE/FileSystem/Content/LocationHelper.cs @@ -14,9 +14,9 @@ namespace Ryujinx.HLE.FileSystem.Content switch (switchContentPath) { case ContentPath.SystemContent: - return Path.Combine(fileSystem.GetBasePath(), SystemNandPath, "Contents"); + return Path.Combine(basePath, SystemNandPath, "Contents"); case ContentPath.UserContent: - return Path.Combine(fileSystem.GetBasePath(), UserNandPath, "Contents"); + return Path.Combine(basePath, UserNandPath, "Contents"); case ContentPath.SdCardContent: return Path.Combine(fileSystem.GetSdCardPath(), "Nintendo", "Contents"); case ContentPath.System: From 1f554c1093dde6a4d3ed80fae2675abfb6c12fac Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Sun, 3 Mar 2019 19:45:25 -0600 Subject: [PATCH 20/36] Do naming refactoring on Ryujinx.Graphics (#611) * Renaming part 1 * Renaming part 2 * Renaming part 3 * Renaming part 4 * Renaming part 5 * Renaming part 6 * Renaming part 7 * Renaming part 8 * Renaming part 9 * Renaming part 10 * General cleanup * Thought I got all of these * Apply #595 * Additional renaming * Tweaks from feedback * Rename files --- Ryujinx.Graphics/CdmaProcessor.cs | 64 +- Ryujinx.Graphics/ChClassId.cs | 4 +- Ryujinx.Graphics/ChCommandEntry.cs | 8 +- Ryujinx.Graphics/DmaPusher.cs | 142 +- Ryujinx.Graphics/Gal/EmbeddedResource.cs | 10 +- Ryujinx.Graphics/Gal/GalColorF.cs | 16 +- Ryujinx.Graphics/Gal/GalFrontFace.cs | 4 +- Ryujinx.Graphics/Gal/GalImage.cs | 76 +- Ryujinx.Graphics/Gal/GalImageFormat.cs | 28 +- Ryujinx.Graphics/Gal/GalPipelineState.cs | 12 +- Ryujinx.Graphics/Gal/GalSurfaceFormat.cs | 88 +- Ryujinx.Graphics/Gal/GalTextureFormat.cs | 22 +- Ryujinx.Graphics/Gal/GalTextureSampler.cs | 36 +- Ryujinx.Graphics/Gal/GalTextureType.cs | 4 +- Ryujinx.Graphics/Gal/GalVertexAttrib.cs | 28 +- Ryujinx.Graphics/Gal/IGalConstBuffer.cs | 8 +- Ryujinx.Graphics/Gal/IGalMemory.cs | 4 +- Ryujinx.Graphics/Gal/IGalPipeline.cs | 6 +- Ryujinx.Graphics/Gal/IGalRasterizer.cs | 34 +- Ryujinx.Graphics/Gal/IGalRenderTarget.cs | 46 +- Ryujinx.Graphics/Gal/IGalRenderer.cs | 2 +- Ryujinx.Graphics/Gal/IGalShader.cs | 12 +- Ryujinx.Graphics/Gal/IGalTexture.cs | 10 +- .../Gal/OpenGL/DeleteValueCallback.cs | 2 +- Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs | 6 +- .../Gal/OpenGL/OGLCachedResource.cs | 191 --- Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs | 74 - Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs | 70 - Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs | 12 - Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs | 207 --- .../Gal/OpenGL/OGLRenderTarget.cs | 549 ------- Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs | 58 - Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs | 298 ---- .../Gal/OpenGL/OGLShaderProgram.cs | 86 - Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs | 381 ----- .../Gal/OpenGL/OglCachedResource.cs | 191 +++ Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs | 74 + ...GLEnumConverter.cs => OglEnumConverter.cs} | 192 +-- Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs | 70 + Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs | 12 + .../OpenGL/{OGLPipeline.cs => OglPipeline.cs} | 490 +++--- Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs | 207 +++ .../Gal/OpenGL/OglRenderTarget.cs | 549 +++++++ Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs | 58 + Ryujinx.Graphics/Gal/OpenGL/OglShader.cs | 298 ++++ .../Gal/OpenGL/OglShaderProgram.cs | 86 + ...{OGLStreamBuffer.cs => OglStreamBuffer.cs} | 24 +- Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs | 381 +++++ Ryujinx.Graphics/Gal/Shader/GlslDecl.cs | 263 ++-- Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 1234 +++++++-------- Ryujinx.Graphics/Gal/Shader/GlslProgram.cs | 12 +- .../Gal/Shader/ShaderDecodeAlu.cs | 1206 +++++++------- .../Gal/Shader/ShaderDecodeFlow.cs | 32 +- .../Gal/Shader/ShaderDecodeFunc.cs | 2 +- .../Gal/Shader/ShaderDecodeHelper.cs | 58 +- .../Gal/Shader/ShaderDecodeMem.cs | 696 ++++----- .../Gal/Shader/ShaderDecodeMove.cs | 352 ++--- .../Gal/Shader/ShaderDecodeOpCode.cs | 224 +-- .../Gal/Shader/ShaderDecodeSpecial.cs | 18 +- Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs | 170 +- Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs | 92 +- Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs | 6 +- Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs | 8 +- Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs | 4 +- Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs | 8 +- .../Gal/Shader/ShaderIrMetaIpa.cs | 4 +- .../Gal/Shader/ShaderIrMetaTex.cs | 10 +- .../Gal/Shader/ShaderIrMetaTexq.cs | 6 +- Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs | 20 +- .../Gal/Shader/ShaderIrOperAbuf.cs | 6 +- .../Gal/Shader/ShaderIrOperCbuf.cs | 8 +- .../Gal/Shader/ShaderIrOperGpr.cs | 20 +- .../Gal/Shader/ShaderIrOperImm.cs | 4 +- .../Gal/Shader/ShaderIrOperImmf.cs | 4 +- .../Gal/Shader/ShaderIrOperPred.cs | 4 +- .../Gal/Shader/ShaderOpCodeTable.cs | 62 +- Ryujinx.Graphics/Gal/Shader/ShaderOper.cs | 6 +- Ryujinx.Graphics/Gal/ShaderDeclInfo.cs | 34 +- Ryujinx.Graphics/Gal/ShaderDumper.cs | 76 +- Ryujinx.Graphics/Gal/ShaderException.cs | 2 +- Ryujinx.Graphics/GpuMethodCall.cs | 16 +- Ryujinx.Graphics/GpuResourceManager.cs | 116 +- Ryujinx.Graphics/Graphics3d/INvGpuEngine.cs | 2 +- .../Graphics3d/MacroInterpreter.cs | 230 +-- Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs | 277 ++-- Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs | 973 ++++++------ .../Graphics3d/NvGpuEngine3dReg.cs | 4 +- .../Graphics3d/NvGpuEngineM2mf.cs | 185 ++- .../Graphics3d/NvGpuEngineP2mf.cs | 141 +- Ryujinx.Graphics/Graphics3d/NvGpuFifo.cs | 120 +- Ryujinx.Graphics/Graphics3d/NvGpuMethod.cs | 2 +- .../Graphics3d/Texture/ASTCDecoder.cs | 1385 ----------------- .../Graphics3d/Texture/ASTCPixel.cs | 138 -- .../Graphics3d/Texture/AstcDecoder.cs | 1385 +++++++++++++++++ .../Graphics3d/Texture/AstcPixel.cs | 138 ++ .../Graphics3d/Texture/BitArrayStream.cs | 90 +- .../Graphics3d/Texture/BlockLinearSwizzle.cs | 180 +-- .../Graphics3d/Texture/ISwizzle.cs | 8 +- .../Graphics3d/Texture/ImageUtils.cs | 409 +++-- .../Graphics3d/Texture/IntegerEncoded.cs | 204 +-- .../Graphics3d/Texture/LinearSwizzle.cs | 34 +- .../Graphics3d/Texture/TextureFactory.cs | 188 +-- .../Graphics3d/Texture/TextureHelper.cs | 46 +- .../Graphics3d/Texture/TextureSwizzle.cs | 2 +- Ryujinx.Graphics/Memory/NvGpuVmm.cs | 308 ++-- Ryujinx.Graphics/Memory/NvGpuVmmCache.cs | 10 +- Ryujinx.Graphics/NvGpu.cs | 16 +- Ryujinx.Graphics/QuadHelper.cs | 52 +- .../Texture/TextureInstructionSuffix.cs | 16 +- Ryujinx.Graphics/VDec/BitStreamWriter.cs | 56 +- Ryujinx.Graphics/VDec/DecoderHelper.cs | 10 +- Ryujinx.Graphics/VDec/FFmpeg.cs | 106 +- Ryujinx.Graphics/VDec/H264BitStreamWriter.cs | 54 +- Ryujinx.Graphics/VDec/H264Decoder.cs | 278 ++-- Ryujinx.Graphics/VDec/VideoDecoder.cs | 284 ++-- Ryujinx.Graphics/VDec/Vp9Decoder.cs | 580 +++---- Ryujinx.Graphics/VDec/VpxBitStreamWriter.cs | 26 +- Ryujinx.Graphics/VDec/VpxRangeEncoder.cs | 92 +- Ryujinx.Graphics/Vic/StructUnpacker.cs | 52 +- Ryujinx.Graphics/Vic/SurfaceOutputConfig.cs | 28 +- Ryujinx.Graphics/Vic/SurfacePixelFormat.cs | 4 +- Ryujinx.Graphics/Vic/VideoImageComposer.cs | 96 +- Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs | 10 +- Ryujinx.sln.DotSettings | 7 + Ryujinx/Program.cs | 2 +- 125 files changed, 9121 insertions(+), 9120 deletions(-) delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs delete mode 100644 Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs rename Ryujinx.Graphics/Gal/OpenGL/{OGLEnumConverter.cs => OglEnumConverter.cs} (79%) create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs rename Ryujinx.Graphics/Gal/OpenGL/{OGLPipeline.cs => OglPipeline.cs} (56%) create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglShader.cs create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs rename Ryujinx.Graphics/Gal/OpenGL/{OGLStreamBuffer.cs => OglStreamBuffer.cs} (51%) create mode 100644 Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs delete mode 100644 Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs delete mode 100644 Ryujinx.Graphics/Graphics3d/Texture/ASTCPixel.cs create mode 100644 Ryujinx.Graphics/Graphics3d/Texture/AstcDecoder.cs create mode 100644 Ryujinx.Graphics/Graphics3d/Texture/AstcPixel.cs diff --git a/Ryujinx.Graphics/CdmaProcessor.cs b/Ryujinx.Graphics/CdmaProcessor.cs index 4ebf200751..4ff12fbf50 100644 --- a/Ryujinx.Graphics/CdmaProcessor.cs +++ b/Ryujinx.Graphics/CdmaProcessor.cs @@ -8,41 +8,41 @@ namespace Ryujinx.Graphics private const int MethSetMethod = 0x10; private const int MethSetData = 0x11; - private NvGpu Gpu; + private NvGpu _gpu; - public CdmaProcessor(NvGpu Gpu) + public CdmaProcessor(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; } - public void PushCommands(NvGpuVmm Vmm, int[] CmdBuffer) + public void PushCommands(NvGpuVmm vmm, int[] cmdBuffer) { - List Commands = new List(); + List commands = new List(); - ChClassId CurrentClass = 0; + ChClassId currentClass = 0; - for (int Index = 0; Index < CmdBuffer.Length; Index++) + for (int index = 0; index < cmdBuffer.Length; index++) { - int Cmd = CmdBuffer[Index]; + int cmd = cmdBuffer[index]; - int Value = (Cmd >> 0) & 0xffff; - int MethodOffset = (Cmd >> 16) & 0xfff; + int value = (cmd >> 0) & 0xffff; + int methodOffset = (cmd >> 16) & 0xfff; - ChSubmissionMode SubmissionMode = (ChSubmissionMode)((Cmd >> 28) & 0xf); + ChSubmissionMode submissionMode = (ChSubmissionMode)((cmd >> 28) & 0xf); - switch (SubmissionMode) + switch (submissionMode) { - case ChSubmissionMode.SetClass: CurrentClass = (ChClassId)(Value >> 6); break; + case ChSubmissionMode.SetClass: currentClass = (ChClassId)(value >> 6); break; case ChSubmissionMode.Incrementing: { - int Count = Value; + int count = value; - for (int ArgIdx = 0; ArgIdx < Count; ArgIdx++) + for (int argIdx = 0; argIdx < count; argIdx++) { - int Argument = CmdBuffer[++Index]; + int argument = cmdBuffer[++index]; - Commands.Add(new ChCommand(CurrentClass, MethodOffset + ArgIdx, Argument)); + commands.Add(new ChCommand(currentClass, methodOffset + argIdx, argument)); } break; @@ -50,44 +50,44 @@ namespace Ryujinx.Graphics case ChSubmissionMode.NonIncrementing: { - int Count = Value; + int count = value; - int[] Arguments = new int[Count]; + int[] arguments = new int[count]; - for (int ArgIdx = 0; ArgIdx < Count; ArgIdx++) + for (int argIdx = 0; argIdx < count; argIdx++) { - Arguments[ArgIdx] = CmdBuffer[++Index]; + arguments[argIdx] = cmdBuffer[++index]; } - Commands.Add(new ChCommand(CurrentClass, MethodOffset, Arguments)); + commands.Add(new ChCommand(currentClass, methodOffset, arguments)); break; } } } - ProcessCommands(Vmm, Commands.ToArray()); + ProcessCommands(vmm, commands.ToArray()); } - private void ProcessCommands(NvGpuVmm Vmm, ChCommand[] Commands) + private void ProcessCommands(NvGpuVmm vmm, ChCommand[] commands) { - int MethodOffset = 0; + int methodOffset = 0; - foreach (ChCommand Command in Commands) + foreach (ChCommand command in commands) { - switch (Command.MethodOffset) + switch (command.MethodOffset) { - case MethSetMethod: MethodOffset = Command.Arguments[0]; break; + case MethSetMethod: methodOffset = command.Arguments[0]; break; case MethSetData: { - if (Command.ClassId == ChClassId.NvDec) + if (command.ClassId == ChClassId.NvDec) { - Gpu.VideoDecoder.Process(Vmm, MethodOffset, Command.Arguments); + _gpu.VideoDecoder.Process(vmm, methodOffset, command.Arguments); } - else if (Command.ClassId == ChClassId.GraphicsVic) + else if (command.ClassId == ChClassId.GraphicsVic) { - Gpu.VideoImageComposer.Process(Vmm, MethodOffset, Command.Arguments); + _gpu.VideoImageComposer.Process(vmm, methodOffset, command.Arguments); } break; diff --git a/Ryujinx.Graphics/ChClassId.cs b/Ryujinx.Graphics/ChClassId.cs index 7b74c6fb73..115f0b89c3 100644 --- a/Ryujinx.Graphics/ChClassId.cs +++ b/Ryujinx.Graphics/ChClassId.cs @@ -2,7 +2,7 @@ namespace Ryujinx.Graphics { enum ChClassId { - Host1x = 0x1, + Host1X = 0x1, VideoEncodeMpeg = 0x20, VideoEncodeNvEnc = 0x21, VideoStreamingVi = 0x30, @@ -10,7 +10,7 @@ namespace Ryujinx.Graphics VideoStreamingIspB = 0x34, VideoStreamingViI2c = 0x36, GraphicsVic = 0x5d, - Graphics3d = 0x60, + Graphics3D = 0x60, GraphicsGpu = 0x61, Tsec = 0xe0, TsecB = 0xe1, diff --git a/Ryujinx.Graphics/ChCommandEntry.cs b/Ryujinx.Graphics/ChCommandEntry.cs index 9001fab137..b01b77eda5 100644 --- a/Ryujinx.Graphics/ChCommandEntry.cs +++ b/Ryujinx.Graphics/ChCommandEntry.cs @@ -8,11 +8,11 @@ namespace Ryujinx.Graphics public int[] Arguments { get; private set; } - public ChCommand(ChClassId ClassId, int MethodOffset, params int[] Arguments) + public ChCommand(ChClassId classId, int methodOffset, params int[] arguments) { - this.ClassId = ClassId; - this.MethodOffset = MethodOffset; - this.Arguments = Arguments; + ClassId = classId; + MethodOffset = methodOffset; + Arguments = arguments; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/DmaPusher.cs b/Ryujinx.Graphics/DmaPusher.cs index 608d8a1d1a..c6825abaf6 100644 --- a/Ryujinx.Graphics/DmaPusher.cs +++ b/Ryujinx.Graphics/DmaPusher.cs @@ -6,10 +6,10 @@ namespace Ryujinx.Graphics { public class DmaPusher { - private ConcurrentQueue<(NvGpuVmm, long)> IbBuffer; + private ConcurrentQueue<(NvGpuVmm, long)> _ibBuffer; - private long DmaPut; - private long DmaGet; + private long _dmaPut; + private long _dmaGet; private struct DmaState { @@ -21,43 +21,43 @@ namespace Ryujinx.Graphics public int LengthPending; } - private DmaState State; + private DmaState _state; - private bool SliEnable; - private bool SliActive; + private bool _sliEnable; + private bool _sliActive; - private bool IbEnable; - private bool NonMain; + private bool _ibEnable; + private bool _nonMain; - private long DmaMGet; + private long _dmaMGet; - private NvGpuVmm Vmm; + private NvGpuVmm _vmm; - private NvGpu Gpu; + private NvGpu _gpu; - private AutoResetEvent Event; + private AutoResetEvent _event; - public DmaPusher(NvGpu Gpu) + public DmaPusher(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; - IbBuffer = new ConcurrentQueue<(NvGpuVmm, long)>(); + _ibBuffer = new ConcurrentQueue<(NvGpuVmm, long)>(); - IbEnable = true; + _ibEnable = true; - Event = new AutoResetEvent(false); + _event = new AutoResetEvent(false); } - public void Push(NvGpuVmm Vmm, long Entry) + public void Push(NvGpuVmm vmm, long entry) { - IbBuffer.Enqueue((Vmm, Entry)); + _ibBuffer.Enqueue((vmm, entry)); - Event.Set(); + _event.Set(); } public bool WaitForCommands() { - return Event.WaitOne(8); + return _event.WaitOne(8); } public void DispatchCalls() @@ -67,101 +67,101 @@ namespace Ryujinx.Graphics private bool Step() { - if (DmaGet != DmaPut) + if (_dmaGet != _dmaPut) { - int Word = Vmm.ReadInt32(DmaGet); + int word = _vmm.ReadInt32(_dmaGet); - DmaGet += 4; + _dmaGet += 4; - if (!NonMain) + if (!_nonMain) { - DmaMGet = DmaGet; + _dmaMGet = _dmaGet; } - if (State.LengthPending != 0) + if (_state.LengthPending != 0) { - State.LengthPending = 0; - State.MethodCount = Word & 0xffffff; + _state.LengthPending = 0; + _state.MethodCount = word & 0xffffff; } - else if (State.MethodCount != 0) + else if (_state.MethodCount != 0) { - if (!SliEnable || SliActive) + if (!_sliEnable || _sliActive) { - CallMethod(Word); + CallMethod(word); } - if (!State.NonIncrementing) + if (!_state.NonIncrementing) { - State.Method++; + _state.Method++; } - if (State.IncrementOnce) + if (_state.IncrementOnce) { - State.NonIncrementing = true; + _state.NonIncrementing = true; } - State.MethodCount--; + _state.MethodCount--; } else { - int SumissionMode = (Word >> 29) & 7; + int sumissionMode = (word >> 29) & 7; - switch (SumissionMode) + switch (sumissionMode) { case 1: //Incrementing. - SetNonImmediateState(Word); + SetNonImmediateState(word); - State.NonIncrementing = false; - State.IncrementOnce = false; + _state.NonIncrementing = false; + _state.IncrementOnce = false; break; case 3: //Non-incrementing. - SetNonImmediateState(Word); + SetNonImmediateState(word); - State.NonIncrementing = true; - State.IncrementOnce = false; + _state.NonIncrementing = true; + _state.IncrementOnce = false; break; case 4: //Immediate. - State.Method = (Word >> 0) & 0x1fff; - State.SubChannel = (Word >> 13) & 7; - State.NonIncrementing = true; - State.IncrementOnce = false; + _state.Method = (word >> 0) & 0x1fff; + _state.SubChannel = (word >> 13) & 7; + _state.NonIncrementing = true; + _state.IncrementOnce = false; - CallMethod((Word >> 16) & 0x1fff); + CallMethod((word >> 16) & 0x1fff); break; case 5: //Increment-once. - SetNonImmediateState(Word); + SetNonImmediateState(word); - State.NonIncrementing = false; - State.IncrementOnce = true; + _state.NonIncrementing = false; + _state.IncrementOnce = true; break; } } } - else if (IbEnable && IbBuffer.TryDequeue(out (NvGpuVmm Vmm, long Entry) Tuple)) + else if (_ibEnable && _ibBuffer.TryDequeue(out (NvGpuVmm Vmm, long Entry) tuple)) { - this.Vmm = Tuple.Vmm; + _vmm = tuple.Vmm; - long Entry = Tuple.Entry; + long entry = tuple.Entry; - int Length = (int)(Entry >> 42) & 0x1fffff; + int length = (int)(entry >> 42) & 0x1fffff; - DmaGet = Entry & 0xfffffffffc; - DmaPut = DmaGet + Length * 4; + _dmaGet = entry & 0xfffffffffc; + _dmaPut = _dmaGet + length * 4; - NonMain = (Entry & (1L << 41)) != 0; + _nonMain = (entry & (1L << 41)) != 0; - Gpu.ResourceManager.ClearPbCache(); + _gpu.ResourceManager.ClearPbCache(); } else { @@ -171,20 +171,20 @@ namespace Ryujinx.Graphics return true; } - private void SetNonImmediateState(int Word) + private void SetNonImmediateState(int word) { - State.Method = (Word >> 0) & 0x1fff; - State.SubChannel = (Word >> 13) & 7; - State.MethodCount = (Word >> 16) & 0x1fff; + _state.Method = (word >> 0) & 0x1fff; + _state.SubChannel = (word >> 13) & 7; + _state.MethodCount = (word >> 16) & 0x1fff; } - private void CallMethod(int Argument) + private void CallMethod(int argument) { - Gpu.Fifo.CallMethod(Vmm, new GpuMethodCall( - State.Method, - Argument, - State.SubChannel, - State.MethodCount)); + _gpu.Fifo.CallMethod(_vmm, new GpuMethodCall( + _state.Method, + argument, + _state.SubChannel, + _state.MethodCount)); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/EmbeddedResource.cs b/Ryujinx.Graphics/Gal/EmbeddedResource.cs index 45b77da71c..ba6624991e 100644 --- a/Ryujinx.Graphics/Gal/EmbeddedResource.cs +++ b/Ryujinx.Graphics/Gal/EmbeddedResource.cs @@ -5,15 +5,15 @@ namespace Ryujinx.Graphics.Gal { static class EmbeddedResource { - public static string GetString(string Name) + public static string GetString(string name) { - Assembly Asm = typeof(EmbeddedResource).Assembly; + Assembly asm = typeof(EmbeddedResource).Assembly; - using (Stream ResStream = Asm.GetManifestResourceStream(Name)) + using (Stream resStream = asm.GetManifestResourceStream(name)) { - StreamReader Reader = new StreamReader(ResStream); + StreamReader reader = new StreamReader(resStream); - return Reader.ReadToEnd(); + return reader.ReadToEnd(); } } } diff --git a/Ryujinx.Graphics/Gal/GalColorF.cs b/Ryujinx.Graphics/Gal/GalColorF.cs index 7cfb171dcd..e915870c2c 100644 --- a/Ryujinx.Graphics/Gal/GalColorF.cs +++ b/Ryujinx.Graphics/Gal/GalColorF.cs @@ -8,15 +8,15 @@ namespace Ryujinx.Graphics.Gal public float Alpha { get; private set; } public GalColorF( - float Red, - float Green, - float Blue, - float Alpha) + float red, + float green, + float blue, + float alpha) { - this.Red = Red; - this.Green = Green; - this.Blue = Blue; - this.Alpha = Alpha; + Red = red; + Green = green; + Blue = blue; + Alpha = alpha; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalFrontFace.cs b/Ryujinx.Graphics/Gal/GalFrontFace.cs index 17ad11267b..6cc4a80242 100644 --- a/Ryujinx.Graphics/Gal/GalFrontFace.cs +++ b/Ryujinx.Graphics/Gal/GalFrontFace.cs @@ -2,7 +2,7 @@ { public enum GalFrontFace { - CW = 0x900, - CCW = 0x901 + Cw = 0x900, + Ccw = 0x901 } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalImage.cs b/Ryujinx.Graphics/Gal/GalImage.cs index fb904b0925..1345704d29 100644 --- a/Ryujinx.Graphics/Gal/GalImage.cs +++ b/Ryujinx.Graphics/Gal/GalImage.cs @@ -25,63 +25,63 @@ namespace Ryujinx.Graphics.Gal public GalTextureTarget TextureTarget; public GalImage( - int Width, - int Height, - int Depth, - int LayerCount, - int TileWidth, - int GobBlockHeight, - int GobBlockDepth, - GalMemoryLayout Layout, - GalImageFormat Format, - GalTextureTarget TextureTarget, - int MaxMipmapLevel = 1, - GalTextureSource XSource = GalTextureSource.Red, - GalTextureSource YSource = GalTextureSource.Green, - GalTextureSource ZSource = GalTextureSource.Blue, - GalTextureSource WSource = GalTextureSource.Alpha) + int width, + int height, + int depth, + int layerCount, + int tileWidth, + int gobBlockHeight, + int gobBlockDepth, + GalMemoryLayout layout, + GalImageFormat format, + GalTextureTarget textureTarget, + int maxMipmapLevel = 1, + GalTextureSource xSource = GalTextureSource.Red, + GalTextureSource ySource = GalTextureSource.Green, + GalTextureSource zSource = GalTextureSource.Blue, + GalTextureSource wSource = GalTextureSource.Alpha) { - this.Width = Width; - this.Height = Height; - this.LayerCount = LayerCount; - this.Depth = Depth; - this.TileWidth = TileWidth; - this.GobBlockHeight = GobBlockHeight; - this.GobBlockDepth = GobBlockDepth; - this.Layout = Layout; - this.Format = Format; - this.MaxMipmapLevel = MaxMipmapLevel; - this.XSource = XSource; - this.YSource = YSource; - this.ZSource = ZSource; - this.WSource = WSource; - this.TextureTarget = TextureTarget; + Width = width; + Height = height; + LayerCount = layerCount; + Depth = depth; + TileWidth = tileWidth; + GobBlockHeight = gobBlockHeight; + GobBlockDepth = gobBlockDepth; + Layout = layout; + Format = format; + MaxMipmapLevel = maxMipmapLevel; + XSource = xSource; + YSource = ySource; + ZSource = zSource; + WSource = wSource; + TextureTarget = textureTarget; - Pitch = ImageUtils.GetPitch(Format, Width); + Pitch = ImageUtils.GetPitch(format, width); } - public bool SizeMatches(GalImage Image, bool IgnoreLayer = false) + public bool SizeMatches(GalImage image, bool ignoreLayer = false) { if (ImageUtils.GetBytesPerPixel(Format) != - ImageUtils.GetBytesPerPixel(Image.Format)) + ImageUtils.GetBytesPerPixel(image.Format)) { return false; } if (ImageUtils.GetAlignedWidth(this) != - ImageUtils.GetAlignedWidth(Image)) + ImageUtils.GetAlignedWidth(image)) { return false; } - bool Result = Height == Image.Height && Depth == Image.Depth; + bool result = Height == image.Height && Depth == image.Depth; - if (!IgnoreLayer) + if (!ignoreLayer) { - Result = Result && LayerCount == Image.LayerCount; + result = result && LayerCount == image.LayerCount; } - return Result; + return result; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalImageFormat.cs b/Ryujinx.Graphics/Gal/GalImageFormat.cs index 70998d1113..8dcde18201 100644 --- a/Ryujinx.Graphics/Gal/GalImageFormat.cs +++ b/Ryujinx.Graphics/Gal/GalImageFormat.cs @@ -22,23 +22,23 @@ namespace Ryujinx.Graphics.Gal Astc2D12x12, Astc2DEnd, - RGBA4, - RGB565, - BGR565, - BGR5A1, - RGB5A1, + Rgba4, + Rgb565, + Bgr565, + Bgr5A1, + Rgb5A1, R8, - RG8, - RGBX8, - RGBA8, - BGRA8, - RGB10A2, + Rg8, + Rgbx8, + Rgba8, + Bgra8, + Rgb10A2, R16, - RG16, - RGBA16, + Rg16, + Rgba16, R32, - RG32, - RGBA32, + Rg32, + Rgba32, R11G11B10, D16, D24, diff --git a/Ryujinx.Graphics/Gal/GalPipelineState.cs b/Ryujinx.Graphics/Gal/GalPipelineState.cs index 8deb68b48f..c044a55fc3 100644 --- a/Ryujinx.Graphics/Gal/GalPipelineState.cs +++ b/Ryujinx.Graphics/Gal/GalPipelineState.cs @@ -2,7 +2,7 @@ { public struct ColorMaskState { - private static readonly ColorMaskState _Default = new ColorMaskState() + private static readonly ColorMaskState DefaultBackingField = new ColorMaskState() { Red = true, Green = true, @@ -10,7 +10,7 @@ Alpha = true }; - public static ColorMaskState Default => _Default; + public static ColorMaskState Default => DefaultBackingField; public bool Red; public bool Green; @@ -20,7 +20,7 @@ public struct BlendState { - private static readonly BlendState _Default = new BlendState() + private static readonly BlendState DefaultBackingField = new BlendState() { Enabled = false, SeparateAlpha = false, @@ -32,7 +32,7 @@ FuncDstAlpha = GalBlendFactor.Zero }; - public static BlendState Default => _Default; + public static BlendState Default => DefaultBackingField; public bool Enabled; public bool SeparateAlpha; @@ -111,9 +111,9 @@ { ConstBufferKeys = new long[Stages][]; - for (int Stage = 0; Stage < Stages; Stage++) + for (int stage = 0; stage < Stages; stage++) { - ConstBufferKeys[Stage] = new long[ConstBuffersPerStage]; + ConstBufferKeys[stage] = new long[ConstBuffersPerStage]; } Blends = new BlendState[RenderTargetsCount]; diff --git a/Ryujinx.Graphics/Gal/GalSurfaceFormat.cs b/Ryujinx.Graphics/Gal/GalSurfaceFormat.cs index 08bd622b3b..9cebcc272b 100644 --- a/Ryujinx.Graphics/Gal/GalSurfaceFormat.cs +++ b/Ryujinx.Graphics/Gal/GalSurfaceFormat.cs @@ -4,48 +4,48 @@ { Bitmap = 0x1c, Unknown1D = 0x1d, - RGBA32Float = 0xc0, - RGBA32Sint = 0xc1, - RGBA32Uint = 0xc2, - RGBX32Float = 0xc3, - RGBX32Sint = 0xc4, - RGBX32Uint = 0xc5, - RGBA16Unorm = 0xc6, - RGBA16Snorm = 0xc7, - RGBA16Sint = 0xc8, - RGBA16Uint = 0xc9, - RGBA16Float = 0xca, - RG32Float = 0xcb, - RG32Sint = 0xcc, - RG32Uint = 0xcd, - RGBX16Float = 0xce, - BGRA8Unorm = 0xcf, - BGRA8Srgb = 0xd0, - RGB10A2Unorm = 0xd1, - RGB10A2Uint = 0xd2, - RGBA8Unorm = 0xd5, - RGBA8Srgb = 0xd6, - RGBA8Snorm = 0xd7, - RGBA8Sint = 0xd8, - RGBA8Uint = 0xd9, - RG16Unorm = 0xda, - RG16Snorm = 0xdb, - RG16Sint = 0xdc, - RG16Uint = 0xdd, - RG16Float = 0xde, - BGR10A2Unorm = 0xdf, + Rgba32Float = 0xc0, + Rgba32Sint = 0xc1, + Rgba32Uint = 0xc2, + Rgbx32Float = 0xc3, + Rgbx32Sint = 0xc4, + Rgbx32Uint = 0xc5, + Rgba16Unorm = 0xc6, + Rgba16Snorm = 0xc7, + Rgba16Sint = 0xc8, + Rgba16Uint = 0xc9, + Rgba16Float = 0xca, + Rg32Float = 0xcb, + Rg32Sint = 0xcc, + Rg32Uint = 0xcd, + Rgbx16Float = 0xce, + Bgra8Unorm = 0xcf, + Bgra8Srgb = 0xd0, + Rgb10A2Unorm = 0xd1, + Rgb10A2Uint = 0xd2, + Rgba8Unorm = 0xd5, + Rgba8Srgb = 0xd6, + Rgba8Snorm = 0xd7, + Rgba8Sint = 0xd8, + Rgba8Uint = 0xd9, + Rg16Unorm = 0xda, + Rg16Snorm = 0xdb, + Rg16Sint = 0xdc, + Rg16Uint = 0xdd, + Rg16Float = 0xde, + Bgr10A2Unorm = 0xdf, R11G11B10Float = 0xe0, R32Sint = 0xe3, R32Uint = 0xe4, R32Float = 0xe5, - BGRX8Unorm = 0xe6, - BGRX8Srgb = 0xe7, + Bgrx8Unorm = 0xe6, + Bgrx8Srgb = 0xe7, B5G6R5Unorm = 0xe8, - BGR5A1Unorm = 0xe9, - RG8Unorm = 0xea, - RG8Snorm = 0xeb, - RG8Sint = 0xec, - RG8Uint = 0xed, + Bgr5A1Unorm = 0xe9, + Rg8Unorm = 0xea, + Rg8Snorm = 0xeb, + Rg8Sint = 0xec, + Rg8Uint = 0xed, R16Unorm = 0xee, R16Snorm = 0xef, R16Sint = 0xf0, @@ -56,13 +56,13 @@ R8Sint = 0xf5, R8Uint = 0xf6, A8Unorm = 0xf7, - BGR5X1Unorm = 0xf8, - RGBX8Unorm = 0xf9, - RGBX8Srgb = 0xfa, - BGR5X1UnormUnknownFB = 0xfb, - BGR5X1UnormUnknownFC = 0xfc, - BGRX8UnormUnknownFD = 0xfd, - BGRX8UnormUnknownFE = 0xfe, + Bgr5x1Unorm = 0xf8, + Rgbx8Unorm = 0xf9, + Rgbx8Srgb = 0xfa, + Bgr5x1UnormUnknownFB = 0xfb, + Bgr5x1UnormUnknownFC = 0xfc, + Bgrx8UnormUnknownFD = 0xfd, + Bgrx8UnormUnknownFE = 0xfe, Y32UintUnknownFF = 0xff } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs index 51ce577970..ed27180a27 100644 --- a/Ryujinx.Graphics/Gal/GalTextureFormat.cs +++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs @@ -2,20 +2,20 @@ namespace Ryujinx.Graphics.Gal { public enum GalTextureFormat { - RGBA32 = 0x1, - RGBA16 = 0x3, - RG32 = 0x4, - RGBA8 = 0x8, - RGB10A2 = 0x9, - RG16 = 0xc, + Rgba32 = 0x1, + Rgba16 = 0x3, + Rg32 = 0x4, + Rgba8 = 0x8, + Rgb10A2 = 0x9, + Rg16 = 0xc, R32 = 0xf, BptcSfloat = 0x10, BptcUfloat = 0x11, - RGBA4 = 0x12, - RGB5A1 = 0x14, - RGB565 = 0x15, + Rgba4 = 0x12, + Rgb5A1 = 0x14, + Rgb565 = 0x15, BptcUnorm = 0x17, - RG8 = 0x18, + Rg8 = 0x18, R16 = 0x1b, R8 = 0x1d, R11G11B10F = 0x21, @@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gal BC5 = 0x28, D24S8 = 0x29, D32F = 0x2f, - D32FX24S8 = 0x30, + D32Fx24S8 = 0x30, D16 = 0x3a, Astc2D4x4 = 0x40, Astc2D5x5 = 0x41, diff --git a/Ryujinx.Graphics/Gal/GalTextureSampler.cs b/Ryujinx.Graphics/Gal/GalTextureSampler.cs index 1d658cea85..2e57a130c6 100644 --- a/Ryujinx.Graphics/Gal/GalTextureSampler.cs +++ b/Ryujinx.Graphics/Gal/GalTextureSampler.cs @@ -16,26 +16,26 @@ namespace Ryujinx.Graphics.Gal public DepthCompareFunc DepthCompareFunc { get; private set; } public GalTextureSampler( - GalTextureWrap AddressU, - GalTextureWrap AddressV, - GalTextureWrap AddressP, - GalTextureFilter MinFilter, - GalTextureFilter MagFilter, - GalTextureMipFilter MipFilter, - GalColorF BorderColor, - bool DepthCompare, - DepthCompareFunc DepthCompareFunc) + GalTextureWrap addressU, + GalTextureWrap addressV, + GalTextureWrap addressP, + GalTextureFilter minFilter, + GalTextureFilter magFilter, + GalTextureMipFilter mipFilter, + GalColorF borderColor, + bool depthCompare, + DepthCompareFunc depthCompareFunc) { - this.AddressU = AddressU; - this.AddressV = AddressV; - this.AddressP = AddressP; - this.MinFilter = MinFilter; - this.MagFilter = MagFilter; - this.MipFilter = MipFilter; - this.BorderColor = BorderColor; + AddressU = addressU; + AddressV = addressV; + AddressP = addressP; + MinFilter = minFilter; + MagFilter = magFilter; + MipFilter = mipFilter; + BorderColor = borderColor; - this.DepthCompare = DepthCompare; - this.DepthCompareFunc = DepthCompareFunc; + DepthCompare = depthCompare; + DepthCompareFunc = depthCompareFunc; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalTextureType.cs b/Ryujinx.Graphics/Gal/GalTextureType.cs index f7dd16d15a..b02b8b37b4 100644 --- a/Ryujinx.Graphics/Gal/GalTextureType.cs +++ b/Ryujinx.Graphics/Gal/GalTextureType.cs @@ -6,8 +6,8 @@ Unorm = 2, Sint = 3, Uint = 4, - Snorm_Force_Fp16 = 5, - Unorm_Force_Fp16 = 6, + SnormForceFp16 = 5, + UnormForceFp16 = 6, Float = 7 } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/GalVertexAttrib.cs b/Ryujinx.Graphics/Gal/GalVertexAttrib.cs index 31b648df38..feca5aea33 100644 --- a/Ryujinx.Graphics/Gal/GalVertexAttrib.cs +++ b/Ryujinx.Graphics/Gal/GalVertexAttrib.cs @@ -13,21 +13,21 @@ namespace Ryujinx.Graphics.Gal public bool IsBgra { get; private set; } public GalVertexAttrib( - int Index, - bool IsConst, - int Offset, - byte[] Data, - GalVertexAttribSize Size, - GalVertexAttribType Type, - bool IsBgra) + int index, + bool isConst, + int offset, + byte[] data, + GalVertexAttribSize size, + GalVertexAttribType type, + bool isBgra) { - this.Index = Index; - this.IsConst = IsConst; - this.Data = Data; - this.Offset = Offset; - this.Size = Size; - this.Type = Type; - this.IsBgra = IsBgra; + Index = index; + IsConst = isConst; + Data = data; + Offset = offset; + Size = size; + Type = type; + IsBgra = isBgra; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalConstBuffer.cs b/Ryujinx.Graphics/Gal/IGalConstBuffer.cs index 0cdcc2371f..8c4e6d0328 100644 --- a/Ryujinx.Graphics/Gal/IGalConstBuffer.cs +++ b/Ryujinx.Graphics/Gal/IGalConstBuffer.cs @@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal void LockCache(); void UnlockCache(); - void Create(long Key, long Size); + void Create(long key, long size); - bool IsCached(long Key, long Size); + bool IsCached(long key, long size); - void SetData(long Key, long Size, IntPtr HostAddress); - void SetData(long Key, byte[] Data); + void SetData(long key, long size, IntPtr hostAddress); + void SetData(long key, byte[] data); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalMemory.cs b/Ryujinx.Graphics/Gal/IGalMemory.cs index e6762b50cc..78eb7154b0 100644 --- a/Ryujinx.Graphics/Gal/IGalMemory.cs +++ b/Ryujinx.Graphics/Gal/IGalMemory.cs @@ -1,7 +1,7 @@ namespace Ryujinx.Graphics.Gal { - public unsafe interface IGalMemory + public interface IGalMemory { - int ReadInt32(long Position); + int ReadInt32(long position); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalPipeline.cs b/Ryujinx.Graphics/Gal/IGalPipeline.cs index cb470fb4b4..1ecb260288 100644 --- a/Ryujinx.Graphics/Gal/IGalPipeline.cs +++ b/Ryujinx.Graphics/Gal/IGalPipeline.cs @@ -2,10 +2,10 @@ { public interface IGalPipeline { - void Bind(GalPipelineState State); - void Unbind(GalPipelineState State); + void Bind(GalPipelineState state); + void Unbind(GalPipelineState state); void ResetDepthMask(); - void ResetColorMask(int Index); + void ResetColorMask(int index); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRasterizer.cs b/Ryujinx.Graphics/Gal/IGalRasterizer.cs index 04f7aae50a..33bdeaad8c 100644 --- a/Ryujinx.Graphics/Gal/IGalRasterizer.cs +++ b/Ryujinx.Graphics/Gal/IGalRasterizer.cs @@ -8,29 +8,29 @@ namespace Ryujinx.Graphics.Gal void UnlockCaches(); void ClearBuffers( - GalClearBufferFlags Flags, - int Attachment, - float Red, - float Green, - float Blue, - float Alpha, - float Depth, - int Stencil); + GalClearBufferFlags flags, + int attachment, + float red, + float green, + float blue, + float alpha, + float depth, + int stencil); - bool IsVboCached(long Key, long DataSize); + bool IsVboCached(long key, long dataSize); - bool IsIboCached(long Key, long DataSize); + bool IsIboCached(long key, long dataSize); - void CreateVbo(long Key, int DataSize, IntPtr HostAddress); - void CreateVbo(long Key, byte[] Data); + void CreateVbo(long key, int dataSize, IntPtr hostAddress); + void CreateVbo(long key, byte[] data); - void CreateIbo(long Key, int DataSize, IntPtr HostAddress); - void CreateIbo(long Key, int DataSize, byte[] Buffer); + void CreateIbo(long key, int dataSize, IntPtr hostAddress); + void CreateIbo(long key, int dataSize, byte[] buffer); - void SetIndexArray(int Size, GalIndexFormat Format); + void SetIndexArray(int size, GalIndexFormat format); - void DrawArrays(int First, int Count, GalPrimitiveType PrimType); + void DrawArrays(int first, int count, GalPrimitiveType primType); - void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType); + void DrawElements(long iboKey, int first, int vertexBase, GalPrimitiveType primType); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs index 90cad856d9..c281fe06c3 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderTarget.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderTarget.cs @@ -4,42 +4,42 @@ namespace Ryujinx.Graphics.Gal { void Bind(); - void BindColor(long Key, int Attachment); + void BindColor(long key, int attachment); - void UnbindColor(int Attachment); + void UnbindColor(int attachment); - void BindZeta(long Key); + void BindZeta(long key); void UnbindZeta(); - void Present(long Key); + void Present(long key); - void SetMap(int[] Map); + void SetMap(int[] map); - void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom); + void SetTransform(bool flipX, bool flipY, int top, int left, int right, int bottom); - void SetWindowSize(int Width, int Height); + void SetWindowSize(int width, int height); - void SetViewport(int Attachment, int X, int Y, int Width, int Height); + void SetViewport(int attachment, int x, int y, int width, int height); void Render(); void Copy( - GalImage SrcImage, - GalImage DstImage, - long SrcKey, - long DstKey, - int SrcLayer, - int DstLayer, - int SrcX0, - int SrcY0, - int SrcX1, - int SrcY1, - int DstX0, - int DstY0, - int DstX1, - int DstY1); + GalImage srcImage, + GalImage dstImage, + long srcKey, + long dstKey, + int srcLayer, + int dstLayer, + int srcX0, + int srcY0, + int srcX1, + int srcY1, + int dstX0, + int dstY0, + int dstX1, + int dstY1); - void Reinterpret(long Key, GalImage NewImage); + void Reinterpret(long key, GalImage newImage); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index 41e95a8789..1acc4d03b1 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Gal { public interface IGalRenderer { - void QueueAction(Action ActionMthd); + void QueueAction(Action actionMthd); void RunActions(); diff --git a/Ryujinx.Graphics/Gal/IGalShader.cs b/Ryujinx.Graphics/Gal/IGalShader.cs index 4b951fa611..99cd4d7624 100644 --- a/Ryujinx.Graphics/Gal/IGalShader.cs +++ b/Ryujinx.Graphics/Gal/IGalShader.cs @@ -4,16 +4,16 @@ namespace Ryujinx.Graphics.Gal { public interface IGalShader { - void Create(IGalMemory Memory, long Key, GalShaderType Type); + void Create(IGalMemory memory, long key, GalShaderType type); - void Create(IGalMemory Memory, long VpAPos, long Key, GalShaderType Type); + void Create(IGalMemory memory, long vpAPos, long key, GalShaderType type); - IEnumerable GetConstBufferUsage(long Key); - IEnumerable GetTextureUsage(long Key); + IEnumerable GetConstBufferUsage(long key); + IEnumerable GetTextureUsage(long key); - void Bind(long Key); + void Bind(long key); - void Unbind(GalShaderType Type); + void Unbind(GalShaderType type); void BindProgram(); } diff --git a/Ryujinx.Graphics/Gal/IGalTexture.cs b/Ryujinx.Graphics/Gal/IGalTexture.cs index de4ba9cba7..23ce054ae9 100644 --- a/Ryujinx.Graphics/Gal/IGalTexture.cs +++ b/Ryujinx.Graphics/Gal/IGalTexture.cs @@ -5,14 +5,14 @@ namespace Ryujinx.Graphics.Gal void LockCache(); void UnlockCache(); - void Create(long Key, int Size, GalImage Image); + void Create(long key, int size, GalImage image); - void Create(long Key, byte[] Data, GalImage Image); + void Create(long key, byte[] data, GalImage image); - bool TryGetImage(long Key, out GalImage Image); + bool TryGetImage(long key, out GalImage image); - void Bind(long Key, int Index, GalImage Image); + void Bind(long key, int index, GalImage image); - void SetSampler(GalImage Image, GalTextureSampler Sampler); + void SetSampler(GalImage image, GalTextureSampler sampler); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs b/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs index acd8d72f66..63b626f18a 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/DeleteValueCallback.cs @@ -1,4 +1,4 @@ namespace Ryujinx.Graphics.Gal.OpenGL { - delegate void DeleteValue(T Value); + delegate void DeleteValue(T value); } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs index 5714f3d891..d7f6f00443 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs @@ -18,10 +18,10 @@ namespace Ryujinx.Graphics.Gal.OpenGL public bool HasDepth => ImageUtils.HasDepth(Image.Format); public bool HasStencil => ImageUtils.HasStencil(Image.Format); - public ImageHandler(int Handle, GalImage Image) + public ImageHandler(int handle, GalImage image) { - this.Handle = Handle; - this.Image = Image; + Handle = handle; + Image = image; } } } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs deleted file mode 100644 index 6e17872ba0..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLCachedResource.cs +++ /dev/null @@ -1,191 +0,0 @@ -using Ryujinx.Common; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - class OGLCachedResource - { - public delegate void DeleteValue(T Value); - - private const int MinTimeDelta = 5 * 60000; - private const int MaxRemovalsPerRun = 10; - - private struct CacheBucket - { - public T Value { get; private set; } - - public LinkedListNode Node { get; private set; } - - public long DataSize { get; private set; } - - public long Timestamp { get; private set; } - - public CacheBucket(T Value, long DataSize, LinkedListNode Node) - { - this.Value = Value; - this.DataSize = DataSize; - this.Node = Node; - - Timestamp = PerformanceCounter.ElapsedMilliseconds; - } - } - - private Dictionary Cache; - - private LinkedList SortedCache; - - private DeleteValue DeleteValueCallback; - - private Queue DeletePending; - - private bool Locked; - - private long MaxSize; - private long TotalSize; - - public OGLCachedResource(DeleteValue DeleteValueCallback, long MaxSize) - { - this.MaxSize = MaxSize; - - if (DeleteValueCallback == null) - { - throw new ArgumentNullException(nameof(DeleteValueCallback)); - } - - this.DeleteValueCallback = DeleteValueCallback; - - Cache = new Dictionary(); - - SortedCache = new LinkedList(); - - DeletePending = new Queue(); - } - - public void Lock() - { - Locked = true; - } - - public void Unlock() - { - Locked = false; - - while (DeletePending.TryDequeue(out T Value)) - { - DeleteValueCallback(Value); - } - - ClearCacheIfNeeded(); - } - - public void AddOrUpdate(long Key, T Value, long Size) - { - if (!Locked) - { - ClearCacheIfNeeded(); - } - - LinkedListNode Node = SortedCache.AddLast(Key); - - CacheBucket NewBucket = new CacheBucket(Value, Size, Node); - - if (Cache.TryGetValue(Key, out CacheBucket Bucket)) - { - if (Locked) - { - DeletePending.Enqueue(Bucket.Value); - } - else - { - DeleteValueCallback(Bucket.Value); - } - - SortedCache.Remove(Bucket.Node); - - TotalSize -= Bucket.DataSize; - - Cache[Key] = NewBucket; - } - else - { - Cache.Add(Key, NewBucket); - } - - TotalSize += Size; - } - - public bool TryGetValue(long Key, out T Value) - { - if (Cache.TryGetValue(Key, out CacheBucket Bucket)) - { - Value = Bucket.Value; - - SortedCache.Remove(Bucket.Node); - - LinkedListNode Node = SortedCache.AddLast(Key); - - Cache[Key] = new CacheBucket(Value, Bucket.DataSize, Node); - - return true; - } - - Value = default(T); - - return false; - } - - public bool TryGetSize(long Key, out long Size) - { - if (Cache.TryGetValue(Key, out CacheBucket Bucket)) - { - Size = Bucket.DataSize; - - return true; - } - - Size = 0; - - return false; - } - - private void ClearCacheIfNeeded() - { - long Timestamp = PerformanceCounter.ElapsedMilliseconds; - - int Count = 0; - - while (Count++ < MaxRemovalsPerRun) - { - LinkedListNode Node = SortedCache.First; - - if (Node == null) - { - break; - } - - CacheBucket Bucket = Cache[Node.Value]; - - long TimeDelta = Timestamp - Bucket.Timestamp; - - if (TimeDelta <= MinTimeDelta && !UnderMemoryPressure()) - { - break; - } - - SortedCache.Remove(Node); - - Cache.Remove(Node.Value); - - DeleteValueCallback(Bucket.Value); - - TotalSize -= Bucket.DataSize; - } - } - - private bool UnderMemoryPressure() - { - return TotalSize >= MaxSize; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs deleted file mode 100644 index a12681c7ce..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLConstBuffer.cs +++ /dev/null @@ -1,74 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using System; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - class OGLConstBuffer : IGalConstBuffer - { - private const long MaxConstBufferCacheSize = 64 * 1024 * 1024; - - private OGLCachedResource Cache; - - public OGLConstBuffer() - { - Cache = new OGLCachedResource(DeleteBuffer, MaxConstBufferCacheSize); - } - - public void LockCache() - { - Cache.Lock(); - } - - public void UnlockCache() - { - Cache.Unlock(); - } - - public void Create(long Key, long Size) - { - OGLStreamBuffer Buffer = new OGLStreamBuffer(BufferTarget.UniformBuffer, Size); - - Cache.AddOrUpdate(Key, Buffer, Size); - } - - public bool IsCached(long Key, long Size) - { - return Cache.TryGetSize(Key, out long CachedSize) && CachedSize == Size; - } - - public void SetData(long Key, long Size, IntPtr HostAddress) - { - if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer)) - { - Buffer.SetData(Size, HostAddress); - } - } - - public void SetData(long Key, byte[] Data) - { - if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer)) - { - Buffer.SetData(Data); - } - } - - public bool TryGetUbo(long Key, out int UboHandle) - { - if (Cache.TryGetValue(Key, out OGLStreamBuffer Buffer)) - { - UboHandle = Buffer.Handle; - - return true; - } - - UboHandle = 0; - - return false; - } - - private static void DeleteBuffer(OGLStreamBuffer Buffer) - { - Buffer.Dispose(); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs deleted file mode 100644 index eb06f83ca9..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs +++ /dev/null @@ -1,70 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using Ryujinx.Common.Logging; -using System; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - static class OGLExtension - { - // Private lazy backing variables - private static Lazy s_EnhancedLayouts = new Lazy(() => HasExtension("GL_ARB_enhanced_layouts")); - private static Lazy s_TextureMirrorClamp = new Lazy(() => HasExtension("GL_EXT_texture_mirror_clamp")); - private static Lazy s_ViewportArray = new Lazy(() => HasExtension("GL_ARB_viewport_array")); - - private static Lazy s_NvidiaDriver = new Lazy(() => IsNvidiaDriver()); - - // Public accessors - public static bool EnhancedLayouts => s_EnhancedLayouts.Value; - public static bool TextureMirrorClamp => s_TextureMirrorClamp.Value; - public static bool ViewportArray => s_ViewportArray.Value; - - public static bool NvidiaDrvier => s_NvidiaDriver.Value; - - private static bool HasExtension(string Name) - { - int NumExtensions = GL.GetInteger(GetPName.NumExtensions); - - for (int Extension = 0; Extension < NumExtensions; Extension++) - { - if (GL.GetString(StringNameIndexed.Extensions, Extension) == Name) - { - return true; - } - } - - Logger.PrintInfo(LogClass.Gpu, $"OpenGL extension {Name} unavailable. You may experience some performance degredation"); - - return false; - } - - private static bool IsNvidiaDriver() - { - return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation"); - } - - public static class Required - { - // Public accessors - public static bool EnhancedLayouts => s_EnhancedLayoutsRequired.Value; - public static bool TextureMirrorClamp => s_TextureMirrorClampRequired.Value; - public static bool ViewportArray => s_ViewportArrayRequired.Value; - - // Private lazy backing variables - private static Lazy s_EnhancedLayoutsRequired = new Lazy(() => HasExtensionRequired(OGLExtension.EnhancedLayouts, "GL_ARB_enhanced_layouts")); - private static Lazy s_TextureMirrorClampRequired = new Lazy(() => HasExtensionRequired(OGLExtension.TextureMirrorClamp, "GL_EXT_texture_mirror_clamp")); - private static Lazy s_ViewportArrayRequired = new Lazy(() => HasExtensionRequired(OGLExtension.ViewportArray, "GL_ARB_viewport_array")); - - private static bool HasExtensionRequired(bool Value, string Name) - { - if (Value) - { - return true; - } - - Logger.PrintWarning(LogClass.Gpu, $"Required OpenGL extension {Name} unavailable. You may experience some rendering issues"); - - return false; - } - } - } -} diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs deleted file mode 100644 index 6c385bc4a2..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLLimit.cs +++ /dev/null @@ -1,12 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using System; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - static class OGLLimit - { - private static Lazy s_MaxUboSize = new Lazy(() => GL.GetInteger(GetPName.MaxUniformBlockSize)); - - public static int MaxUboSize => s_MaxUboSize.Value; - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs deleted file mode 100644 index c4015d020c..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ /dev/null @@ -1,207 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using System; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - class OGLRasterizer : IGalRasterizer - { - private const long MaxVertexBufferCacheSize = 128 * 1024 * 1024; - private const long MaxIndexBufferCacheSize = 64 * 1024 * 1024; - - private int[] VertexBuffers; - - private OGLCachedResource VboCache; - private OGLCachedResource IboCache; - - private struct IbInfo - { - public int Count; - public int ElemSizeLog2; - - public DrawElementsType Type; - } - - private IbInfo IndexBuffer; - - public OGLRasterizer() - { - VertexBuffers = new int[32]; - - VboCache = new OGLCachedResource(GL.DeleteBuffer, MaxVertexBufferCacheSize); - IboCache = new OGLCachedResource(GL.DeleteBuffer, MaxIndexBufferCacheSize); - - IndexBuffer = new IbInfo(); - } - - public void LockCaches() - { - VboCache.Lock(); - IboCache.Lock(); - } - - public void UnlockCaches() - { - VboCache.Unlock(); - IboCache.Unlock(); - } - - public void ClearBuffers( - GalClearBufferFlags Flags, - int Attachment, - float Red, - float Green, - float Blue, - float Alpha, - float Depth, - int Stencil) - { - GL.ColorMask( - Attachment, - Flags.HasFlag(GalClearBufferFlags.ColorRed), - Flags.HasFlag(GalClearBufferFlags.ColorGreen), - Flags.HasFlag(GalClearBufferFlags.ColorBlue), - Flags.HasFlag(GalClearBufferFlags.ColorAlpha)); - - GL.ClearBuffer(ClearBuffer.Color, Attachment, new float[] { Red, Green, Blue, Alpha }); - - GL.ColorMask(Attachment, true, true, true, true); - GL.DepthMask(true); - - if (Flags.HasFlag(GalClearBufferFlags.Depth)) - { - GL.ClearBuffer(ClearBuffer.Depth, 0, ref Depth); - } - - if (Flags.HasFlag(GalClearBufferFlags.Stencil)) - { - GL.ClearBuffer(ClearBuffer.Stencil, 0, ref Stencil); - } - } - - public bool IsVboCached(long Key, long DataSize) - { - return VboCache.TryGetSize(Key, out long Size) && Size == DataSize; - } - - public bool IsIboCached(long Key, long DataSize) - { - return IboCache.TryGetSize(Key, out long Size) && Size == DataSize; - } - - public void CreateVbo(long Key, int DataSize, IntPtr HostAddress) - { - int Handle = GL.GenBuffer(); - - VboCache.AddOrUpdate(Key, Handle, DataSize); - - IntPtr Length = new IntPtr(DataSize); - - GL.BindBuffer(BufferTarget.ArrayBuffer, Handle); - GL.BufferData(BufferTarget.ArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw); - } - - public void CreateVbo(long Key, byte[] Data) - { - int Handle = GL.GenBuffer(); - - VboCache.AddOrUpdate(Key, Handle, Data.Length); - - IntPtr Length = new IntPtr(Data.Length); - - GL.BindBuffer(BufferTarget.ArrayBuffer, Handle); - GL.BufferData(BufferTarget.ArrayBuffer, Length, Data, BufferUsageHint.StreamDraw); - } - - public void CreateIbo(long Key, int DataSize, IntPtr HostAddress) - { - int Handle = GL.GenBuffer(); - - IboCache.AddOrUpdate(Key, Handle, (uint)DataSize); - - IntPtr Length = new IntPtr(DataSize); - - GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle); - GL.BufferData(BufferTarget.ElementArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw); - } - - public void CreateIbo(long Key, int DataSize, byte[] Buffer) - { - int Handle = GL.GenBuffer(); - - IboCache.AddOrUpdate(Key, Handle, DataSize); - - IntPtr Length = new IntPtr(Buffer.Length); - - GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle); - GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw); - } - - public void SetIndexArray(int Size, GalIndexFormat Format) - { - IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format); - - IndexBuffer.Count = Size >> (int)Format; - - IndexBuffer.ElemSizeLog2 = (int)Format; - } - - public void DrawArrays(int First, int Count, GalPrimitiveType PrimType) - { - if (Count == 0) - { - return; - } - - if (PrimType == GalPrimitiveType.Quads) - { - for (int Offset = 0; Offset < Count; Offset += 4) - { - GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4); - } - } - else if (PrimType == GalPrimitiveType.QuadStrip) - { - GL.DrawArrays(PrimitiveType.TriangleFan, First, 4); - - for (int Offset = 2; Offset < Count; Offset += 2) - { - GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4); - } - } - else - { - GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count); - } - } - - public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType) - { - if (!IboCache.TryGetValue(IboKey, out int IboHandle)) - { - return; - } - - PrimitiveType Mode = OGLEnumConverter.GetPrimitiveType(PrimType); - - GL.BindBuffer(BufferTarget.ElementArrayBuffer, IboHandle); - - First <<= IndexBuffer.ElemSizeLog2; - - if (VertexBase != 0) - { - IntPtr Indices = new IntPtr(First); - - GL.DrawElementsBaseVertex(Mode, IndexBuffer.Count, IndexBuffer.Type, Indices, VertexBase); - } - else - { - GL.DrawElements(Mode, IndexBuffer.Count, IndexBuffer.Type, First); - } - } - - public bool TryGetVbo(long VboKey, out int VboHandle) - { - return VboCache.TryGetValue(VboKey, out VboHandle); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs deleted file mode 100644 index 53cfd4a604..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderTarget.cs +++ /dev/null @@ -1,549 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using Ryujinx.Graphics.Texture; -using System; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - class OGLRenderTarget : IGalRenderTarget - { - private const int NativeWidth = 1280; - private const int NativeHeight = 720; - - private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount; - - private struct Rect - { - public int X { get; private set; } - public int Y { get; private set; } - public int Width { get; private set; } - public int Height { get; private set; } - - public Rect(int X, int Y, int Width, int Height) - { - this.X = X; - this.Y = Y; - this.Width = Width; - this.Height = Height; - } - } - - private class FrameBufferAttachments - { - public int MapCount { get; set; } - - public DrawBuffersEnum[] Map { get; private set; } - - public long[] Colors { get; private set; } - - public long Zeta { get; set; } - - public FrameBufferAttachments() - { - Colors = new long[RenderTargetsCount]; - - Map = new DrawBuffersEnum[RenderTargetsCount]; - } - - public void Update(FrameBufferAttachments Source) - { - for (int Index = 0; Index < RenderTargetsCount; Index++) - { - Map[Index] = Source.Map[Index]; - - Colors[Index] = Source.Colors[Index]; - } - - MapCount = Source.MapCount; - Zeta = Source.Zeta; - } - } - - private int[] ColorHandles; - private int ZetaHandle; - - private OGLTexture Texture; - - private ImageHandler ReadTex; - - private Rect Window; - - private float[] Viewports; - - private bool FlipX; - private bool FlipY; - - private int CropTop; - private int CropLeft; - private int CropRight; - private int CropBottom; - - //This framebuffer is used to attach guest rendertargets, - //think of it as a dummy OpenGL VAO - private int DummyFrameBuffer; - - //These framebuffers are used to blit images - private int SrcFb; - private int DstFb; - - private FrameBufferAttachments Attachments; - private FrameBufferAttachments OldAttachments; - - private int CopyPBO; - - public bool FramebufferSrgb { get; set; } - - public OGLRenderTarget(OGLTexture Texture) - { - Attachments = new FrameBufferAttachments(); - - OldAttachments = new FrameBufferAttachments(); - - ColorHandles = new int[RenderTargetsCount]; - - Viewports = new float[RenderTargetsCount * 4]; - - this.Texture = Texture; - - Texture.TextureDeleted += TextureDeletionHandler; - } - - private void TextureDeletionHandler(object Sender, int Handle) - { - //Texture was deleted, the handle is no longer valid, so - //reset all uses of this handle on a render target. - for (int Attachment = 0; Attachment < RenderTargetsCount; Attachment++) - { - if (ColorHandles[Attachment] == Handle) - { - ColorHandles[Attachment] = 0; - } - } - - if (ZetaHandle == Handle) - { - ZetaHandle = 0; - } - } - - public void Bind() - { - if (DummyFrameBuffer == 0) - { - DummyFrameBuffer = GL.GenFramebuffer(); - } - - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer); - - ImageHandler CachedImage; - - for (int Attachment = 0; Attachment < RenderTargetsCount; Attachment++) - { - long Key = Attachments.Colors[Attachment]; - - int Handle = 0; - - if (Key != 0 && Texture.TryGetImageHandler(Key, out CachedImage)) - { - Handle = CachedImage.Handle; - } - - if (Handle == ColorHandles[Attachment]) - { - continue; - } - - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - FramebufferAttachment.ColorAttachment0 + Attachment, - Handle, - 0); - - ColorHandles[Attachment] = Handle; - } - - if (Attachments.Zeta != 0 && Texture.TryGetImageHandler(Attachments.Zeta, out CachedImage)) - { - if (CachedImage.Handle != ZetaHandle) - { - if (CachedImage.HasDepth && CachedImage.HasStencil) - { - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - FramebufferAttachment.DepthStencilAttachment, - CachedImage.Handle, - 0); - } - else if (CachedImage.HasDepth) - { - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - FramebufferAttachment.DepthAttachment, - CachedImage.Handle, - 0); - - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - FramebufferAttachment.StencilAttachment, - 0, - 0); - } - else - { - throw new InvalidOperationException("Invalid image format \"" + CachedImage.Format + "\" used as Zeta!"); - } - - ZetaHandle = CachedImage.Handle; - } - } - else if (ZetaHandle != 0) - { - GL.FramebufferTexture( - FramebufferTarget.DrawFramebuffer, - FramebufferAttachment.DepthStencilAttachment, - 0, - 0); - - ZetaHandle = 0; - } - - if (OGLExtension.ViewportArray) - { - GL.ViewportArray(0, RenderTargetsCount, Viewports); - } - else - { - GL.Viewport( - (int)Viewports[0], - (int)Viewports[1], - (int)Viewports[2], - (int)Viewports[3]); - } - - if (Attachments.MapCount > 1) - { - GL.DrawBuffers(Attachments.MapCount, Attachments.Map); - } - else if (Attachments.MapCount == 1) - { - GL.DrawBuffer((DrawBufferMode)Attachments.Map[0]); - } - else - { - GL.DrawBuffer(DrawBufferMode.None); - } - - OldAttachments.Update(Attachments); - } - - public void BindColor(long Key, int Attachment) - { - Attachments.Colors[Attachment] = Key; - } - - public void UnbindColor(int Attachment) - { - Attachments.Colors[Attachment] = 0; - } - - public void BindZeta(long Key) - { - Attachments.Zeta = Key; - } - - public void UnbindZeta() - { - Attachments.Zeta = 0; - } - - public void Present(long Key) - { - Texture.TryGetImageHandler(Key, out ReadTex); - } - - public void SetMap(int[] Map) - { - if (Map != null) - { - Attachments.MapCount = Map.Length; - - for (int Attachment = 0; Attachment < Attachments.MapCount; Attachment++) - { - Attachments.Map[Attachment] = DrawBuffersEnum.ColorAttachment0 + Map[Attachment]; - } - } - else - { - Attachments.MapCount = 0; - } - } - - public void SetTransform(bool FlipX, bool FlipY, int Top, int Left, int Right, int Bottom) - { - this.FlipX = FlipX; - this.FlipY = FlipY; - - CropTop = Top; - CropLeft = Left; - CropRight = Right; - CropBottom = Bottom; - } - - public void SetWindowSize(int Width, int Height) - { - Window = new Rect(0, 0, Width, Height); - } - - public void SetViewport(int Attachment, int X, int Y, int Width, int Height) - { - int Offset = Attachment * 4; - - Viewports[Offset + 0] = X; - Viewports[Offset + 1] = Y; - Viewports[Offset + 2] = Width; - Viewports[Offset + 3] = Height; - } - - public void Render() - { - if (ReadTex == null) - { - return; - } - - int SrcX0, SrcX1, SrcY0, SrcY1; - - if (CropLeft == 0 && CropRight == 0) - { - SrcX0 = 0; - SrcX1 = ReadTex.Width; - } - else - { - SrcX0 = CropLeft; - SrcX1 = CropRight; - } - - if (CropTop == 0 && CropBottom == 0) - { - SrcY0 = 0; - SrcY1 = ReadTex.Height; - } - else - { - SrcY0 = CropTop; - SrcY1 = CropBottom; - } - - float RatioX = MathF.Min(1f, (Window.Height * (float)NativeWidth) / ((float)NativeHeight * Window.Width)); - float RatioY = MathF.Min(1f, (Window.Width * (float)NativeHeight) / ((float)NativeWidth * Window.Height)); - - int DstWidth = (int)(Window.Width * RatioX); - int DstHeight = (int)(Window.Height * RatioY); - - int DstPaddingX = (Window.Width - DstWidth) / 2; - int DstPaddingY = (Window.Height - DstHeight) / 2; - - int DstX0 = FlipX ? Window.Width - DstPaddingX : DstPaddingX; - int DstX1 = FlipX ? DstPaddingX : Window.Width - DstPaddingX; - - int DstY0 = FlipY ? DstPaddingY : Window.Height - DstPaddingY; - int DstY1 = FlipY ? Window.Height - DstPaddingY : DstPaddingY; - - GL.Viewport(0, 0, Window.Width, Window.Height); - - if (SrcFb == 0) - { - SrcFb = GL.GenFramebuffer(); - } - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); - - GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0); - - GL.ReadBuffer(ReadBufferMode.ColorAttachment0); - - GL.Clear(ClearBufferMask.ColorBufferBit); - - GL.Disable(EnableCap.FramebufferSrgb); - - GL.BlitFramebuffer( - SrcX0, - SrcY0, - SrcX1, - SrcY1, - DstX0, - DstY0, - DstX1, - DstY1, - ClearBufferMask.ColorBufferBit, - BlitFramebufferFilter.Linear); - - if (FramebufferSrgb) - { - GL.Enable(EnableCap.FramebufferSrgb); - } - } - - public void Copy( - GalImage SrcImage, - GalImage DstImage, - long SrcKey, - long DstKey, - int SrcLayer, - int DstLayer, - int SrcX0, - int SrcY0, - int SrcX1, - int SrcY1, - int DstX0, - int DstY0, - int DstX1, - int DstY1) - { - if (Texture.TryGetImageHandler(SrcKey, out ImageHandler SrcTex) && - Texture.TryGetImageHandler(DstKey, out ImageHandler DstTex)) - { - if (SrcTex.HasColor != DstTex.HasColor || - SrcTex.HasDepth != DstTex.HasDepth || - SrcTex.HasStencil != DstTex.HasStencil) - { - throw new NotImplementedException(); - } - - if (SrcFb == 0) - { - SrcFb = GL.GenFramebuffer(); - } - - if (DstFb == 0) - { - DstFb = GL.GenFramebuffer(); - } - - GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, SrcFb); - GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DstFb); - - FramebufferAttachment Attachment = GetAttachment(SrcTex); - - if (ImageUtils.IsArray(SrcImage.TextureTarget) && SrcLayer > 0) - { - GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0, SrcLayer); - } - else - { - GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, Attachment, SrcTex.Handle, 0); - } - - if (ImageUtils.IsArray(DstImage.TextureTarget) && DstLayer > 0) - { - GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0, DstLayer); - } - else - { - GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, Attachment, DstTex.Handle, 0); - } - - - BlitFramebufferFilter Filter = BlitFramebufferFilter.Nearest; - - if (SrcTex.HasColor) - { - GL.DrawBuffer(DrawBufferMode.ColorAttachment0); - - Filter = BlitFramebufferFilter.Linear; - } - - ClearBufferMask Mask = GetClearMask(SrcTex); - - GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter); - } - } - - public void Reinterpret(long Key, GalImage NewImage) - { - if (!Texture.TryGetImage(Key, out GalImage OldImage)) - { - return; - } - - if (NewImage.Format == OldImage.Format && - NewImage.Width == OldImage.Width && - NewImage.Height == OldImage.Height && - NewImage.Depth == OldImage.Depth && - NewImage.LayerCount == OldImage.LayerCount && - NewImage.TextureTarget == OldImage.TextureTarget) - { - return; - } - - if (CopyPBO == 0) - { - CopyPBO = GL.GenBuffer(); - } - - GL.BindBuffer(BufferTarget.PixelPackBuffer, CopyPBO); - - //The buffer should be large enough to hold the largest texture. - int BufferSize = Math.Max(ImageUtils.GetSize(OldImage), - ImageUtils.GetSize(NewImage)); - - GL.BufferData(BufferTarget.PixelPackBuffer, BufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy); - - if (!Texture.TryGetImageHandler(Key, out ImageHandler CachedImage)) - { - throw new InvalidOperationException(); - } - - (_, PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(CachedImage.Format); - - TextureTarget Target = ImageUtils.GetTextureTarget(NewImage.TextureTarget); - - GL.BindTexture(Target, CachedImage.Handle); - - GL.GetTexImage(Target, 0, Format, Type, IntPtr.Zero); - - GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); - GL.BindBuffer(BufferTarget.PixelUnpackBuffer, CopyPBO); - - GL.PixelStore(PixelStoreParameter.UnpackRowLength, OldImage.Width); - - Texture.Create(Key, ImageUtils.GetSize(NewImage), NewImage); - - GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0); - - GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); - } - - private static FramebufferAttachment GetAttachment(ImageHandler CachedImage) - { - if (CachedImage.HasColor) - { - return FramebufferAttachment.ColorAttachment0; - } - else if (CachedImage.HasDepth && CachedImage.HasStencil) - { - return FramebufferAttachment.DepthStencilAttachment; - } - else if (CachedImage.HasDepth) - { - return FramebufferAttachment.DepthAttachment; - } - else if (CachedImage.HasStencil) - { - return FramebufferAttachment.StencilAttachment; - } - else - { - throw new InvalidOperationException(); - } - } - - private static ClearBufferMask GetClearMask(ImageHandler CachedImage) - { - return (CachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) | - (CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) | - (CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs deleted file mode 100644 index 14fb901809..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRenderer.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Collections.Concurrent; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - public class OGLRenderer : IGalRenderer - { - public IGalConstBuffer Buffer { get; private set; } - - public IGalRenderTarget RenderTarget { get; private set; } - - public IGalRasterizer Rasterizer { get; private set; } - - public IGalShader Shader { get; private set; } - - public IGalPipeline Pipeline { get; private set; } - - public IGalTexture Texture { get; private set; } - - private ConcurrentQueue ActionsQueue; - - public OGLRenderer() - { - Buffer = new OGLConstBuffer(); - - Texture = new OGLTexture(); - - RenderTarget = new OGLRenderTarget(Texture as OGLTexture); - - Rasterizer = new OGLRasterizer(); - - Shader = new OGLShader(Buffer as OGLConstBuffer); - - Pipeline = new OGLPipeline( - Buffer as OGLConstBuffer, - RenderTarget as OGLRenderTarget, - Rasterizer as OGLRasterizer, - Shader as OGLShader); - - ActionsQueue = new ConcurrentQueue(); - } - - public void QueueAction(Action ActionMthd) - { - ActionsQueue.Enqueue(ActionMthd); - } - - public void RunActions() - { - int Count = ActionsQueue.Count; - - while (Count-- > 0 && ActionsQueue.TryDequeue(out Action RenderAction)) - { - RenderAction(); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs deleted file mode 100644 index dc168ff919..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs +++ /dev/null @@ -1,298 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using Ryujinx.Graphics.Gal.Shader; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - class OGLShader : IGalShader - { - public const int ReservedCbufCount = 1; - - private const int ExtraDataSize = 4; - - public OGLShaderProgram Current; - - private ConcurrentDictionary Stages; - - private Dictionary Programs; - - public int CurrentProgramHandle { get; private set; } - - private OGLConstBuffer Buffer; - - private int ExtraUboHandle; - - public OGLShader(OGLConstBuffer Buffer) - { - this.Buffer = Buffer; - - Stages = new ConcurrentDictionary(); - - Programs = new Dictionary(); - } - - public void Create(IGalMemory Memory, long Key, GalShaderType Type) - { - Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, Key, 0, false, Type)); - } - - public void Create(IGalMemory Memory, long VpAPos, long Key, GalShaderType Type) - { - Stages.GetOrAdd(Key, (Stage) => ShaderStageFactory(Memory, VpAPos, Key, true, Type)); - } - - private OGLShaderStage ShaderStageFactory( - IGalMemory Memory, - long Position, - long PositionB, - bool IsDualVp, - GalShaderType Type) - { - GlslProgram Program; - - GlslDecompiler Decompiler = new GlslDecompiler(OGLLimit.MaxUboSize, OGLExtension.NvidiaDrvier); - - int ShaderDumpIndex = ShaderDumper.DumpIndex; - - if (IsDualVp) - { - ShaderDumper.Dump(Memory, Position, Type, "a"); - ShaderDumper.Dump(Memory, PositionB, Type, "b"); - - Program = Decompiler.Decompile(Memory, Position, PositionB, Type); - } - else - { - ShaderDumper.Dump(Memory, Position, Type); - - Program = Decompiler.Decompile(Memory, Position, Type); - } - - string Code = Program.Code; - - if (ShaderDumper.IsDumpEnabled()) - { - Code = "//Shader " + ShaderDumpIndex + Environment.NewLine + Code; - } - - return new OGLShaderStage(Type, Code, Program.Uniforms, Program.Textures); - } - - public IEnumerable GetConstBufferUsage(long Key) - { - if (Stages.TryGetValue(Key, out OGLShaderStage Stage)) - { - return Stage.ConstBufferUsage; - } - - return Enumerable.Empty(); - } - - public IEnumerable GetTextureUsage(long Key) - { - if (Stages.TryGetValue(Key, out OGLShaderStage Stage)) - { - return Stage.TextureUsage; - } - - return Enumerable.Empty(); - } - - public unsafe void SetExtraData(float FlipX, float FlipY, int Instance) - { - BindProgram(); - - EnsureExtraBlock(); - - GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle); - - float* Data = stackalloc float[ExtraDataSize]; - Data[0] = FlipX; - Data[1] = FlipY; - Data[2] = BitConverter.Int32BitsToSingle(Instance); - - //Invalidate buffer - GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw); - - GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, ExtraDataSize * sizeof(float), (IntPtr)Data); - } - - public void Bind(long Key) - { - if (Stages.TryGetValue(Key, out OGLShaderStage Stage)) - { - Bind(Stage); - } - } - - private void Bind(OGLShaderStage Stage) - { - if (Stage.Type == GalShaderType.Geometry) - { - //Enhanced layouts are required for Geometry shaders - //skip this stage if current driver has no ARB_enhanced_layouts - if (!OGLExtension.EnhancedLayouts) - { - return; - } - } - - switch (Stage.Type) - { - case GalShaderType.Vertex: Current.Vertex = Stage; break; - case GalShaderType.TessControl: Current.TessControl = Stage; break; - case GalShaderType.TessEvaluation: Current.TessEvaluation = Stage; break; - case GalShaderType.Geometry: Current.Geometry = Stage; break; - case GalShaderType.Fragment: Current.Fragment = Stage; break; - } - } - - public void Unbind(GalShaderType Type) - { - switch (Type) - { - case GalShaderType.Vertex: Current.Vertex = null; break; - case GalShaderType.TessControl: Current.TessControl = null; break; - case GalShaderType.TessEvaluation: Current.TessEvaluation = null; break; - case GalShaderType.Geometry: Current.Geometry = null; break; - case GalShaderType.Fragment: Current.Fragment = null; break; - } - } - - public void BindProgram() - { - if (Current.Vertex == null || - Current.Fragment == null) - { - return; - } - - if (!Programs.TryGetValue(Current, out int Handle)) - { - Handle = GL.CreateProgram(); - - AttachIfNotNull(Handle, Current.Vertex); - AttachIfNotNull(Handle, Current.TessControl); - AttachIfNotNull(Handle, Current.TessEvaluation); - AttachIfNotNull(Handle, Current.Geometry); - AttachIfNotNull(Handle, Current.Fragment); - - GL.LinkProgram(Handle); - - CheckProgramLink(Handle); - - BindUniformBlocks(Handle); - BindTextureLocations(Handle); - - Programs.Add(Current, Handle); - } - - GL.UseProgram(Handle); - - CurrentProgramHandle = Handle; - } - - private void EnsureExtraBlock() - { - if (ExtraUboHandle == 0) - { - ExtraUboHandle = GL.GenBuffer(); - - GL.BindBuffer(BufferTarget.UniformBuffer, ExtraUboHandle); - - GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw); - - GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, ExtraUboHandle); - } - } - - private void AttachIfNotNull(int ProgramHandle, OGLShaderStage Stage) - { - if (Stage != null) - { - Stage.Compile(); - - GL.AttachShader(ProgramHandle, Stage.Handle); - } - } - - private void BindUniformBlocks(int ProgramHandle) - { - int ExtraBlockindex = GL.GetUniformBlockIndex(ProgramHandle, GlslDecl.ExtraUniformBlockName); - - GL.UniformBlockBinding(ProgramHandle, ExtraBlockindex, 0); - - int FreeBinding = ReservedCbufCount; - - void BindUniformBlocksIfNotNull(OGLShaderStage Stage) - { - if (Stage != null) - { - foreach (ShaderDeclInfo DeclInfo in Stage.ConstBufferUsage) - { - int BlockIndex = GL.GetUniformBlockIndex(ProgramHandle, DeclInfo.Name); - - if (BlockIndex < 0) - { - //It is expected that its found, if it's not then driver might be in a malfunction - throw new InvalidOperationException(); - } - - GL.UniformBlockBinding(ProgramHandle, BlockIndex, FreeBinding); - - FreeBinding++; - } - } - } - - BindUniformBlocksIfNotNull(Current.Vertex); - BindUniformBlocksIfNotNull(Current.TessControl); - BindUniformBlocksIfNotNull(Current.TessEvaluation); - BindUniformBlocksIfNotNull(Current.Geometry); - BindUniformBlocksIfNotNull(Current.Fragment); - } - - private void BindTextureLocations(int ProgramHandle) - { - int Index = 0; - - void BindTexturesIfNotNull(OGLShaderStage Stage) - { - if (Stage != null) - { - foreach (ShaderDeclInfo Decl in Stage.TextureUsage) - { - int Location = GL.GetUniformLocation(ProgramHandle, Decl.Name); - - GL.Uniform1(Location, Index); - - Index++; - } - } - } - - GL.UseProgram(ProgramHandle); - - BindTexturesIfNotNull(Current.Vertex); - BindTexturesIfNotNull(Current.TessControl); - BindTexturesIfNotNull(Current.TessEvaluation); - BindTexturesIfNotNull(Current.Geometry); - BindTexturesIfNotNull(Current.Fragment); - } - - private static void CheckProgramLink(int Handle) - { - int Status = 0; - - GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out Status); - - if (Status == 0) - { - throw new ShaderException(GL.GetProgramInfoLog(Handle)); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs deleted file mode 100644 index c87b0d4053..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLShaderProgram.cs +++ /dev/null @@ -1,86 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - struct OGLShaderProgram - { - public OGLShaderStage Vertex; - public OGLShaderStage TessControl; - public OGLShaderStage TessEvaluation; - public OGLShaderStage Geometry; - public OGLShaderStage Fragment; - } - - class OGLShaderStage : IDisposable - { - public int Handle { get; private set; } - - public bool IsCompiled { get; private set; } - - public GalShaderType Type { get; private set; } - - public string Code { get; private set; } - - public IEnumerable ConstBufferUsage { get; private set; } - public IEnumerable TextureUsage { get; private set; } - - public OGLShaderStage( - GalShaderType Type, - string Code, - IEnumerable ConstBufferUsage, - IEnumerable TextureUsage) - { - this.Type = Type; - this.Code = Code; - this.ConstBufferUsage = ConstBufferUsage; - this.TextureUsage = TextureUsage; - } - - public void Compile() - { - if (Handle == 0) - { - Handle = GL.CreateShader(OGLEnumConverter.GetShaderType(Type)); - - CompileAndCheck(Handle, Code); - } - } - - public void Dispose() - { - Dispose(true); - } - - protected virtual void Dispose(bool Disposing) - { - if (Disposing && Handle != 0) - { - GL.DeleteShader(Handle); - - Handle = 0; - } - } - - public static void CompileAndCheck(int Handle, string Code) - { - GL.ShaderSource(Handle, Code); - GL.CompileShader(Handle); - - CheckCompilation(Handle); - } - - private static void CheckCompilation(int Handle) - { - int Status = 0; - - GL.GetShader(Handle, ShaderParameter.CompileStatus, out Status); - - if (Status == 0) - { - throw new ShaderException(GL.GetShaderInfoLog(Handle)); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs deleted file mode 100644 index 4fef11d296..0000000000 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ /dev/null @@ -1,381 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using Ryujinx.Graphics.Texture; -using System; - -namespace Ryujinx.Graphics.Gal.OpenGL -{ - class OGLTexture : IGalTexture - { - private const long MaxTextureCacheSize = 768 * 1024 * 1024; - - private OGLCachedResource TextureCache; - - public EventHandler TextureDeleted { get; set; } - - public OGLTexture() - { - TextureCache = new OGLCachedResource(DeleteTexture, MaxTextureCacheSize); - } - - public void LockCache() - { - TextureCache.Lock(); - } - - public void UnlockCache() - { - TextureCache.Unlock(); - } - - private void DeleteTexture(ImageHandler CachedImage) - { - TextureDeleted?.Invoke(this, CachedImage.Handle); - - GL.DeleteTexture(CachedImage.Handle); - } - - public void Create(long Key, int Size, GalImage Image) - { - int Handle = GL.GenTexture(); - - TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget); - - GL.BindTexture(Target, Handle); - - const int Level = 0; //TODO: Support mipmap textures. - const int Border = 0; - - TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size); - - if (ImageUtils.IsCompressed(Image.Format)) - { - throw new InvalidOperationException("Surfaces with compressed formats are not supported!"); - } - - (PixelInternalFormat InternalFmt, - PixelFormat Format, - PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); - - switch (Target) - { - case TextureTarget.Texture1D: - GL.TexImage1D( - Target, - Level, - InternalFmt, - Image.Width, - Border, - Format, - Type, - IntPtr.Zero); - break; - - case TextureTarget.Texture2D: - GL.TexImage2D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Border, - Format, - Type, - IntPtr.Zero); - break; - case TextureTarget.Texture3D: - GL.TexImage3D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Image.Depth, - Border, - Format, - Type, - IntPtr.Zero); - break; - case TextureTarget.Texture2DArray: - GL.TexImage3D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Image.LayerCount, - Border, - Format, - Type, - IntPtr.Zero); - break; - default: - throw new NotImplementedException($"Unsupported texture target type: {Target}"); - } - } - - public void Create(long Key, byte[] Data, GalImage Image) - { - int Handle = GL.GenTexture(); - - TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget); - - GL.BindTexture(Target, Handle); - - const int Level = 0; //TODO: Support mipmap textures. - const int Border = 0; - - TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length); - - if (ImageUtils.IsCompressed(Image.Format) && !IsAstc(Image.Format)) - { - InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format); - - switch (Target) - { - case TextureTarget.Texture1D: - GL.CompressedTexImage1D( - Target, - Level, - InternalFmt, - Image.Width, - Border, - Data.Length, - Data); - break; - case TextureTarget.Texture2D: - GL.CompressedTexImage2D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Border, - Data.Length, - Data); - break; - case TextureTarget.Texture3D: - GL.CompressedTexImage3D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Image.Depth, - Border, - Data.Length, - Data); - break; - case TextureTarget.Texture2DArray: - GL.CompressedTexImage3D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Image.LayerCount, - Border, - Data.Length, - Data); - break; - default: - throw new NotImplementedException($"Unsupported texture target type: {Target}"); - } - } - else - { - //TODO: Use KHR_texture_compression_astc_hdr when available - if (IsAstc(Image.Format)) - { - int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format); - int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format); - int TextureBlockDepth = ImageUtils.GetBlockDepth(Image.Format); - - Data = ASTCDecoder.DecodeToRGBA8888( - Data, - TextureBlockWidth, - TextureBlockHeight, - TextureBlockDepth, - Image.Width, - Image.Height, - Image.Depth); - - Image.Format = GalImageFormat.RGBA8 | (Image.Format & GalImageFormat.TypeMask); - } - - (PixelInternalFormat InternalFmt, - PixelFormat Format, - PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); - - - switch (Target) - { - case TextureTarget.Texture1D: - GL.TexImage1D( - Target, - Level, - InternalFmt, - Image.Width, - Border, - Format, - Type, - Data); - break; - case TextureTarget.Texture2D: - GL.TexImage2D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Border, - Format, - Type, - Data); - break; - case TextureTarget.Texture3D: - GL.TexImage3D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Image.Depth, - Border, - Format, - Type, - Data); - break; - case TextureTarget.Texture2DArray: - GL.TexImage3D( - Target, - Level, - InternalFmt, - Image.Width, - Image.Height, - Image.LayerCount, - Border, - Format, - Type, - Data); - break; - case TextureTarget.TextureCubeMap: - Span Array = new Span(Data); - - int FaceSize = ImageUtils.GetSize(Image) / 6; - - for (int Face = 0; Face < 6; Face++) - { - GL.TexImage2D( - TextureTarget.TextureCubeMapPositiveX + Face, - Level, - InternalFmt, - Image.Width, - Image.Height, - Border, - Format, - Type, - Array.Slice(Face * FaceSize, FaceSize).ToArray()); - } - break; - default: - throw new NotImplementedException($"Unsupported texture target type: {Target}"); - } - } - } - - private static bool IsAstc(GalImageFormat Format) - { - Format &= GalImageFormat.FormatMask; - - return Format > GalImageFormat.Astc2DStart && Format < GalImageFormat.Astc2DEnd; - } - - public bool TryGetImage(long Key, out GalImage Image) - { - if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) - { - Image = CachedImage.Image; - - return true; - } - - Image = default(GalImage); - - return false; - } - - public bool TryGetImageHandler(long Key, out ImageHandler CachedImage) - { - if (TextureCache.TryGetValue(Key, out CachedImage)) - { - return true; - } - - CachedImage = null; - - return false; - } - - public void Bind(long Key, int Index, GalImage Image) - { - if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage)) - { - GL.ActiveTexture(TextureUnit.Texture0 + Index); - - TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget); - - GL.BindTexture(Target, CachedImage.Handle); - - int[] SwizzleRgba = new int[] - { - (int)OGLEnumConverter.GetTextureSwizzle(Image.XSource), - (int)OGLEnumConverter.GetTextureSwizzle(Image.YSource), - (int)OGLEnumConverter.GetTextureSwizzle(Image.ZSource), - (int)OGLEnumConverter.GetTextureSwizzle(Image.WSource) - }; - - GL.TexParameter(Target, TextureParameterName.TextureSwizzleRgba, SwizzleRgba); - } - } - - public void SetSampler(GalImage Image, GalTextureSampler Sampler) - { - int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU); - int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV); - int WrapR = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressP); - - int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter); - int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter); - - TextureTarget Target = ImageUtils.GetTextureTarget(Image.TextureTarget); - - GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS); - GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT); - GL.TexParameter(Target, TextureParameterName.TextureWrapR, WrapR); - - GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter); - GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter); - - float[] Color = new float[] - { - Sampler.BorderColor.Red, - Sampler.BorderColor.Green, - Sampler.BorderColor.Blue, - Sampler.BorderColor.Alpha - }; - - GL.TexParameter(Target, TextureParameterName.TextureBorderColor, Color); - - if (Sampler.DepthCompare) - { - GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture); - GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)OGLEnumConverter.GetDepthCompareFunc(Sampler.DepthCompareFunc)); - } - else - { - GL.TexParameter(Target, TextureParameterName.TextureCompareMode, (int)All.None); - GL.TexParameter(Target, TextureParameterName.TextureCompareFunc, (int)All.Never); - } - } - } -} diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs b/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs new file mode 100644 index 0000000000..91f0a7e169 --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglCachedResource.cs @@ -0,0 +1,191 @@ +using Ryujinx.Common; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OglCachedResource + { + public delegate void DeleteValue(T value); + + private const int MinTimeDelta = 5 * 60000; + private const int MaxRemovalsPerRun = 10; + + private struct CacheBucket + { + public T Value { get; private set; } + + public LinkedListNode Node { get; private set; } + + public long DataSize { get; private set; } + + public long Timestamp { get; private set; } + + public CacheBucket(T value, long dataSize, LinkedListNode node) + { + Value = value; + DataSize = dataSize; + Node = node; + + Timestamp = PerformanceCounter.ElapsedMilliseconds; + } + } + + private Dictionary _cache; + + private LinkedList _sortedCache; + + private DeleteValue _deleteValueCallback; + + private Queue _deletePending; + + private bool _locked; + + private long _maxSize; + private long _totalSize; + + public OglCachedResource(DeleteValue deleteValueCallback, long maxSize) + { + _maxSize = maxSize; + + if (deleteValueCallback == null) + { + throw new ArgumentNullException(nameof(deleteValueCallback)); + } + + _deleteValueCallback = deleteValueCallback; + + _cache = new Dictionary(); + + _sortedCache = new LinkedList(); + + _deletePending = new Queue(); + } + + public void Lock() + { + _locked = true; + } + + public void Unlock() + { + _locked = false; + + while (_deletePending.TryDequeue(out T value)) + { + _deleteValueCallback(value); + } + + ClearCacheIfNeeded(); + } + + public void AddOrUpdate(long key, T value, long size) + { + if (!_locked) + { + ClearCacheIfNeeded(); + } + + LinkedListNode node = _sortedCache.AddLast(key); + + CacheBucket newBucket = new CacheBucket(value, size, node); + + if (_cache.TryGetValue(key, out CacheBucket bucket)) + { + if (_locked) + { + _deletePending.Enqueue(bucket.Value); + } + else + { + _deleteValueCallback(bucket.Value); + } + + _sortedCache.Remove(bucket.Node); + + _totalSize -= bucket.DataSize; + + _cache[key] = newBucket; + } + else + { + _cache.Add(key, newBucket); + } + + _totalSize += size; + } + + public bool TryGetValue(long key, out T value) + { + if (_cache.TryGetValue(key, out CacheBucket bucket)) + { + value = bucket.Value; + + _sortedCache.Remove(bucket.Node); + + LinkedListNode node = _sortedCache.AddLast(key); + + _cache[key] = new CacheBucket(value, bucket.DataSize, node); + + return true; + } + + value = default(T); + + return false; + } + + public bool TryGetSize(long key, out long size) + { + if (_cache.TryGetValue(key, out CacheBucket bucket)) + { + size = bucket.DataSize; + + return true; + } + + size = 0; + + return false; + } + + private void ClearCacheIfNeeded() + { + long timestamp = PerformanceCounter.ElapsedMilliseconds; + + int count = 0; + + while (count++ < MaxRemovalsPerRun) + { + LinkedListNode node = _sortedCache.First; + + if (node == null) + { + break; + } + + CacheBucket bucket = _cache[node.Value]; + + long timeDelta = timestamp - bucket.Timestamp; + + if (timeDelta <= MinTimeDelta && !UnderMemoryPressure()) + { + break; + } + + _sortedCache.Remove(node); + + _cache.Remove(node.Value); + + _deleteValueCallback(bucket.Value); + + _totalSize -= bucket.DataSize; + } + } + + private bool UnderMemoryPressure() + { + return _totalSize >= _maxSize; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs new file mode 100644 index 0000000000..e076be336d --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglConstBuffer.cs @@ -0,0 +1,74 @@ +using OpenTK.Graphics.OpenGL; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OglConstBuffer : IGalConstBuffer + { + private const long MaxConstBufferCacheSize = 64 * 1024 * 1024; + + private OglCachedResource _cache; + + public OglConstBuffer() + { + _cache = new OglCachedResource(DeleteBuffer, MaxConstBufferCacheSize); + } + + public void LockCache() + { + _cache.Lock(); + } + + public void UnlockCache() + { + _cache.Unlock(); + } + + public void Create(long key, long size) + { + OglStreamBuffer buffer = new OglStreamBuffer(BufferTarget.UniformBuffer, size); + + _cache.AddOrUpdate(key, buffer, size); + } + + public bool IsCached(long key, long size) + { + return _cache.TryGetSize(key, out long cachedSize) && cachedSize == size; + } + + public void SetData(long key, long size, IntPtr hostAddress) + { + if (_cache.TryGetValue(key, out OglStreamBuffer buffer)) + { + buffer.SetData(size, hostAddress); + } + } + + public void SetData(long key, byte[] data) + { + if (_cache.TryGetValue(key, out OglStreamBuffer buffer)) + { + buffer.SetData(data); + } + } + + public bool TryGetUbo(long key, out int uboHandle) + { + if (_cache.TryGetValue(key, out OglStreamBuffer buffer)) + { + uboHandle = buffer.Handle; + + return true; + } + + uboHandle = 0; + + return false; + } + + private static void DeleteBuffer(OglStreamBuffer buffer) + { + buffer.Dispose(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OglEnumConverter.cs similarity index 79% rename from Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs rename to Ryujinx.Graphics/Gal/OpenGL/OglEnumConverter.cs index 3a25fff7a5..a3f9957f3e 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglEnumConverter.cs @@ -3,34 +3,34 @@ using System; namespace Ryujinx.Graphics.Gal.OpenGL { - static class OGLEnumConverter + static class OglEnumConverter { - public static FrontFaceDirection GetFrontFace(GalFrontFace FrontFace) + public static FrontFaceDirection GetFrontFace(GalFrontFace frontFace) { - switch (FrontFace) + switch (frontFace) { - case GalFrontFace.CW: return FrontFaceDirection.Cw; - case GalFrontFace.CCW: return FrontFaceDirection.Ccw; + case GalFrontFace.Cw: return FrontFaceDirection.Cw; + case GalFrontFace.Ccw: return FrontFaceDirection.Ccw; } - throw new ArgumentException(nameof(FrontFace) + " \"" + FrontFace + "\" is not valid!"); + throw new ArgumentException(nameof(frontFace) + " \"" + frontFace + "\" is not valid!"); } - public static CullFaceMode GetCullFace(GalCullFace CullFace) + public static CullFaceMode GetCullFace(GalCullFace cullFace) { - switch (CullFace) + switch (cullFace) { case GalCullFace.Front: return CullFaceMode.Front; case GalCullFace.Back: return CullFaceMode.Back; case GalCullFace.FrontAndBack: return CullFaceMode.FrontAndBack; } - throw new ArgumentException(nameof(CullFace) + " \"" + CullFace + "\" is not valid!"); + throw new ArgumentException(nameof(cullFace) + " \"" + cullFace + "\" is not valid!"); } - public static StencilOp GetStencilOp(GalStencilOp Op) + public static StencilOp GetStencilOp(GalStencilOp op) { - switch (Op) + switch (op) { case GalStencilOp.Keep: return StencilOp.Keep; case GalStencilOp.Zero: return StencilOp.Zero; @@ -42,28 +42,28 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalStencilOp.DecrWrap: return StencilOp.DecrWrap; } - throw new ArgumentException(nameof(Op) + " \"" + Op + "\" is not valid!"); + throw new ArgumentException(nameof(op) + " \"" + op + "\" is not valid!"); } - public static DepthFunction GetDepthFunc(GalComparisonOp Func) + public static DepthFunction GetDepthFunc(GalComparisonOp func) { - return (DepthFunction)GetFunc(Func); + return (DepthFunction)GetFunc(func); } - public static StencilFunction GetStencilFunc(GalComparisonOp Func) + public static StencilFunction GetStencilFunc(GalComparisonOp func) { - return (StencilFunction)GetFunc(Func); + return (StencilFunction)GetFunc(func); } - private static All GetFunc(GalComparisonOp Func) + private static All GetFunc(GalComparisonOp func) { - if ((int)Func >= (int)All.Never && - (int)Func <= (int)All.Always) + if ((int)func >= (int)All.Never && + (int)func <= (int)All.Always) { - return (All)Func; + return (All)func; } - switch (Func) + switch (func) { case GalComparisonOp.Never: return All.Never; case GalComparisonOp.Less: return All.Less; @@ -75,24 +75,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalComparisonOp.Always: return All.Always; } - throw new ArgumentException(nameof(Func) + " \"" + Func + "\" is not valid!"); + throw new ArgumentException(nameof(func) + " \"" + func + "\" is not valid!"); } - public static DrawElementsType GetDrawElementsType(GalIndexFormat Format) + public static DrawElementsType GetDrawElementsType(GalIndexFormat format) { - switch (Format) + switch (format) { case GalIndexFormat.Byte: return DrawElementsType.UnsignedByte; case GalIndexFormat.Int16: return DrawElementsType.UnsignedShort; case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt; } - throw new ArgumentException(nameof(Format) + " \"" + Format + "\" is not valid!"); + throw new ArgumentException(nameof(format) + " \"" + format + "\" is not valid!"); } - public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type) + public static PrimitiveType GetPrimitiveType(GalPrimitiveType type) { - switch (Type) + switch (type) { case GalPrimitiveType.Points: return PrimitiveType.Points; case GalPrimitiveType.Lines: return PrimitiveType.Lines; @@ -109,12 +109,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalPrimitiveType.Patches: return PrimitiveType.Patches; } - throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!"); + throw new ArgumentException(nameof(type) + " \"" + type + "\" is not valid!"); } - public static ShaderType GetShaderType(GalShaderType Type) + public static ShaderType GetShaderType(GalShaderType type) { - switch (Type) + switch (type) { case GalShaderType.Vertex: return ShaderType.VertexShader; case GalShaderType.TessControl: return ShaderType.TessControlShader; @@ -123,50 +123,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalShaderType.Fragment: return ShaderType.FragmentShader; } - throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!"); + throw new ArgumentException(nameof(type) + " \"" + type + "\" is not valid!"); } - public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat Format) + public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat format) { - switch (Format) + switch (format) { - case GalImageFormat.RGBA32 | GalImageFormat.Float: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float); - case GalImageFormat.RGBA32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int); - case GalImageFormat.RGBA32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt); - case GalImageFormat.RGBA16 | GalImageFormat.Float: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat); - case GalImageFormat.RGBA16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short); - case GalImageFormat.RGBA16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort); - case GalImageFormat.RGBA16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba16, PixelFormat.Rgba, PixelType.UnsignedShort); - case GalImageFormat.RG32 | GalImageFormat.Float: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float); - case GalImageFormat.RG32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int); - case GalImageFormat.RG32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt); - case GalImageFormat.RGBX8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb8, PixelFormat.Rgba, PixelType.UnsignedByte); - case GalImageFormat.RGBA8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte); - case GalImageFormat.RGBA8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte); - case GalImageFormat.RGBA8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte); - case GalImageFormat.RGBA8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte); - case GalImageFormat.RGBA8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte); - case GalImageFormat.BGRA8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte); - case GalImageFormat.BGRA8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Bgra, PixelType.UnsignedByte); - case GalImageFormat.RGBA4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed); - case GalImageFormat.RGB10A2 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed); - case GalImageFormat.RGB10A2 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed); + case GalImageFormat.Rgba32 | GalImageFormat.Float: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float); + case GalImageFormat.Rgba32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int); + case GalImageFormat.Rgba32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt); + case GalImageFormat.Rgba16 | GalImageFormat.Float: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat); + case GalImageFormat.Rgba16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short); + case GalImageFormat.Rgba16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort); + case GalImageFormat.Rgba16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba16, PixelFormat.Rgba, PixelType.UnsignedShort); + case GalImageFormat.Rg32 | GalImageFormat.Float: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float); + case GalImageFormat.Rg32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int); + case GalImageFormat.Rg32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt); + case GalImageFormat.Rgbx8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb8, PixelFormat.Rgba, PixelType.UnsignedByte); + case GalImageFormat.Rgba8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte); + case GalImageFormat.Rgba8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte); + case GalImageFormat.Rgba8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte); + case GalImageFormat.Rgba8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte); + case GalImageFormat.Rgba8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte); + case GalImageFormat.Bgra8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte); + case GalImageFormat.Bgra8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Bgra, PixelType.UnsignedByte); + case GalImageFormat.Rgba4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed); + case GalImageFormat.Rgb10A2 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed); + case GalImageFormat.Rgb10A2 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed); case GalImageFormat.R32 | GalImageFormat.Float: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float); case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int); case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt); - case GalImageFormat.BGR5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551); - case GalImageFormat.RGB5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed); - case GalImageFormat.RGB565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed); - case GalImageFormat.BGR565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565); - case GalImageFormat.RG16 | GalImageFormat.Float: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat); - case GalImageFormat.RG16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short); - case GalImageFormat.RG16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Short); - case GalImageFormat.RG16 | GalImageFormat.Uint: return (PixelInternalFormat.Rg16ui, PixelFormat.RgInteger, PixelType.UnsignedShort); - case GalImageFormat.RG16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort); - case GalImageFormat.RG8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte); - case GalImageFormat.RG8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte); - case GalImageFormat.RG8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte); - case GalImageFormat.RG8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte); + case GalImageFormat.Bgr5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551); + case GalImageFormat.Rgb5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed); + case GalImageFormat.Rgb565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed); + case GalImageFormat.Bgr565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565); + case GalImageFormat.Rg16 | GalImageFormat.Float: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat); + case GalImageFormat.Rg16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short); + case GalImageFormat.Rg16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Short); + case GalImageFormat.Rg16 | GalImageFormat.Uint: return (PixelInternalFormat.Rg16ui, PixelFormat.RgInteger, PixelType.UnsignedShort); + case GalImageFormat.Rg16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort); + case GalImageFormat.Rg8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte); + case GalImageFormat.Rg8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte); + case GalImageFormat.Rg8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte); + case GalImageFormat.Rg8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte); case GalImageFormat.R16 | GalImageFormat.Float: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat); case GalImageFormat.R16 | GalImageFormat.Sint: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short); case GalImageFormat.R16 | GalImageFormat.Snorm: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Short); @@ -186,12 +186,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalImageFormat.D32S8 | GalImageFormat.Float: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev); } - throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}"); + throw new NotImplementedException($"{format & GalImageFormat.FormatMask} {format & GalImageFormat.TypeMask}"); } - public static All GetDepthCompareFunc(DepthCompareFunc DepthCompareFunc) + public static All GetDepthCompareFunc(DepthCompareFunc depthCompareFunc) { - switch (DepthCompareFunc) + switch (depthCompareFunc) { case DepthCompareFunc.LEqual: return All.Lequal; @@ -210,13 +210,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL case DepthCompareFunc.Never: return All.Never; default: - throw new ArgumentException(nameof(DepthCompareFunc) + " \"" + DepthCompareFunc + "\" is not valid!"); + throw new ArgumentException(nameof(depthCompareFunc) + " \"" + depthCompareFunc + "\" is not valid!"); } } - public static InternalFormat GetCompressedImageFormat(GalImageFormat Format) + public static InternalFormat GetCompressedImageFormat(GalImageFormat format) { - switch (Format) + switch (format) { case GalImageFormat.BptcSfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcSignedFloat; case GalImageFormat.BptcUfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcUnsignedFloat; @@ -234,12 +234,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2; } - throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}"); + throw new NotImplementedException($"{format & GalImageFormat.FormatMask} {format & GalImageFormat.TypeMask}"); } - public static All GetTextureSwizzle(GalTextureSource Source) + public static All GetTextureSwizzle(GalTextureSource source) { - switch (Source) + switch (source) { case GalTextureSource.Zero: return All.Zero; case GalTextureSource.Red: return All.Red; @@ -250,12 +250,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalTextureSource.OneFloat: return All.One; } - throw new ArgumentException(nameof(Source) + " \"" + Source + "\" is not valid!"); + throw new ArgumentException(nameof(source) + " \"" + source + "\" is not valid!"); } - public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap) + public static TextureWrapMode GetTextureWrapMode(GalTextureWrap wrap) { - switch (Wrap) + switch (wrap) { case GalTextureWrap.Repeat: return TextureWrapMode.Repeat; case GalTextureWrap.MirroredRepeat: return TextureWrapMode.MirroredRepeat; @@ -264,9 +264,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL case GalTextureWrap.Clamp: return TextureWrapMode.Clamp; } - if (OGLExtension.TextureMirrorClamp) + if (OglExtension.TextureMirrorClamp) { - switch (Wrap) + switch (wrap) { case GalTextureWrap.MirrorClampToEdge: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToEdgeExt; case GalTextureWrap.MirrorClampToBorder: return (TextureWrapMode)ExtTextureMirrorClamp.MirrorClampToBorderExt; @@ -276,7 +276,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL else { //Fallback to non-mirrored clamps - switch (Wrap) + switch (wrap) { case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge; case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder; @@ -284,37 +284,37 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } - throw new ArgumentException(nameof(Wrap) + " \"" + Wrap + "\" is not valid!"); + throw new ArgumentException(nameof(wrap) + " \"" + wrap + "\" is not valid!"); } public static TextureMinFilter GetTextureMinFilter( - GalTextureFilter MinFilter, - GalTextureMipFilter MipFilter) + GalTextureFilter minFilter, + GalTextureMipFilter mipFilter) { //TODO: Mip (needs mipmap support first). - switch (MinFilter) + switch (minFilter) { case GalTextureFilter.Nearest: return TextureMinFilter.Nearest; case GalTextureFilter.Linear: return TextureMinFilter.Linear; } - throw new ArgumentException(nameof(MinFilter) + " \"" + MinFilter + "\" is not valid!"); + throw new ArgumentException(nameof(minFilter) + " \"" + minFilter + "\" is not valid!"); } - public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter) + public static TextureMagFilter GetTextureMagFilter(GalTextureFilter filter) { - switch (Filter) + switch (filter) { case GalTextureFilter.Nearest: return TextureMagFilter.Nearest; case GalTextureFilter.Linear: return TextureMagFilter.Linear; } - throw new ArgumentException(nameof(Filter) + " \"" + Filter + "\" is not valid!"); + throw new ArgumentException(nameof(filter) + " \"" + filter + "\" is not valid!"); } - public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation) + public static BlendEquationMode GetBlendEquation(GalBlendEquation blendEquation) { - switch (BlendEquation) + switch (blendEquation) { case GalBlendEquation.FuncAdd: case GalBlendEquation.FuncAddGl: @@ -337,12 +337,12 @@ namespace Ryujinx.Graphics.Gal.OpenGL return BlendEquationMode.Max; } - throw new ArgumentException(nameof(BlendEquation) + " \"" + BlendEquation + "\" is not valid!"); + throw new ArgumentException(nameof(blendEquation) + " \"" + blendEquation + "\" is not valid!"); } - public static BlendingFactor GetBlendFactor(GalBlendFactor BlendFactor) + public static BlendingFactor GetBlendFactor(GalBlendFactor blendFactor) { - switch (BlendFactor) + switch (blendFactor) { case GalBlendFactor.Zero: case GalBlendFactor.ZeroGl: @@ -421,7 +421,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL return BlendingFactor.ConstantColor; } - throw new ArgumentException(nameof(BlendFactor) + " \"" + BlendFactor + "\" is not valid!"); + throw new ArgumentException(nameof(blendFactor) + " \"" + blendFactor + "\" is not valid!"); } } } diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs new file mode 100644 index 0000000000..8a1a0510f7 --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglExtension.cs @@ -0,0 +1,70 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Common.Logging; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + static class OglExtension + { + // Private lazy backing variables + private static Lazy _enhancedLayouts = new Lazy(() => HasExtension("GL_ARB_enhanced_layouts")); + private static Lazy _textureMirrorClamp = new Lazy(() => HasExtension("GL_EXT_texture_mirror_clamp")); + private static Lazy _viewportArray = new Lazy(() => HasExtension("GL_ARB_viewport_array")); + + private static Lazy _nvidiaDriver = new Lazy(() => IsNvidiaDriver()); + + // Public accessors + public static bool EnhancedLayouts => _enhancedLayouts.Value; + public static bool TextureMirrorClamp => _textureMirrorClamp.Value; + public static bool ViewportArray => _viewportArray.Value; + + public static bool NvidiaDriver => _nvidiaDriver.Value; + + private static bool HasExtension(string name) + { + int numExtensions = GL.GetInteger(GetPName.NumExtensions); + + for (int extension = 0; extension < numExtensions; extension++) + { + if (GL.GetString(StringNameIndexed.Extensions, extension) == name) + { + return true; + } + } + + Logger.PrintInfo(LogClass.Gpu, $"OpenGL extension {name} unavailable. You may experience some performance degradation"); + + return false; + } + + private static bool IsNvidiaDriver() + { + return GL.GetString(StringName.Vendor).Equals("NVIDIA Corporation"); + } + + public static class Required + { + // Public accessors + public static bool EnhancedLayouts => _enhancedLayoutsRequired.Value; + public static bool TextureMirrorClamp => _textureMirrorClampRequired.Value; + public static bool ViewportArray => _viewportArrayRequired.Value; + + // Private lazy backing variables + private static Lazy _enhancedLayoutsRequired = new Lazy(() => HasExtensionRequired(OglExtension.EnhancedLayouts, "GL_ARB_enhanced_layouts")); + private static Lazy _textureMirrorClampRequired = new Lazy(() => HasExtensionRequired(OglExtension.TextureMirrorClamp, "GL_EXT_texture_mirror_clamp")); + private static Lazy _viewportArrayRequired = new Lazy(() => HasExtensionRequired(OglExtension.ViewportArray, "GL_ARB_viewport_array")); + + private static bool HasExtensionRequired(bool value, string name) + { + if (value) + { + return true; + } + + Logger.PrintWarning(LogClass.Gpu, $"Required OpenGL extension {name} unavailable. You may experience some rendering issues"); + + return false; + } + } + } +} diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs b/Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs new file mode 100644 index 0000000000..2a227a374a --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglLimit.cs @@ -0,0 +1,12 @@ +using OpenTK.Graphics.OpenGL; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + static class OglLimit + { + private static Lazy _sMaxUboSize = new Lazy(() => GL.GetInteger(GetPName.MaxUniformBlockSize)); + + public static int MaxUboSize => _sMaxUboSize.Value; + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs similarity index 56% rename from Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs rename to Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs index 96d42e0238..3c8ada3ea6 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs @@ -4,9 +4,9 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Gal.OpenGL { - class OGLPipeline : IGalPipeline + class OglPipeline : IGalPipeline { - private static Dictionary AttribElements = + private static Dictionary _attribElements = new Dictionary() { { GalVertexAttribSize._32_32_32_32, 4 }, @@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GalVertexAttribSize._11_11_10, 3 } }; - private static Dictionary FloatAttribTypes = + private static Dictionary _floatAttribTypes = new Dictionary() { { GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Float }, @@ -38,7 +38,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GalVertexAttribSize._16, VertexAttribPointerType.HalfFloat } }; - private static Dictionary SignedAttribTypes = + private static Dictionary _signedAttribTypes = new Dictionary() { { GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Int }, @@ -56,7 +56,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GalVertexAttribSize._10_10_10_2, VertexAttribPointerType.Int2101010Rev } }; - private static Dictionary UnsignedAttribTypes = + private static Dictionary _unsignedAttribTypes = new Dictionary() { { GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.UnsignedInt }, @@ -75,30 +75,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL { GalVertexAttribSize._11_11_10, VertexAttribPointerType.UnsignedInt10F11F11FRev } }; - private GalPipelineState Old; + private GalPipelineState _old; - private OGLConstBuffer Buffer; - private OGLRenderTarget RenderTarget; - private OGLRasterizer Rasterizer; - private OGLShader Shader; + private OglConstBuffer _buffer; + private OglRenderTarget _renderTarget; + private OglRasterizer _rasterizer; + private OglShader _shader; - private int VaoHandle; + private int _vaoHandle; - public OGLPipeline( - OGLConstBuffer Buffer, - OGLRenderTarget RenderTarget, - OGLRasterizer Rasterizer, - OGLShader Shader) + public OglPipeline( + OglConstBuffer buffer, + OglRenderTarget renderTarget, + OglRasterizer rasterizer, + OglShader shader) { - this.Buffer = Buffer; - this.RenderTarget = RenderTarget; - this.Rasterizer = Rasterizer; - this.Shader = Shader; + _buffer = buffer; + _renderTarget = renderTarget; + _rasterizer = rasterizer; + _shader = shader; //These values match OpenGL's defaults - Old = new GalPipelineState + _old = new GalPipelineState { - FrontFace = GalFrontFace.CCW, + FrontFace = GalFrontFace.Ccw, CullFaceEnabled = false, CullFace = GalCullFace.Back, @@ -133,11 +133,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL PrimitiveRestartIndex = 0 }; - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) { - Old.Blends[Index] = BlendState.Default; + _old.Blends[index] = BlendState.Default; - Old.ColorMasks[Index] = ColorMaskState.Default; + _old.ColorMasks[index] = ColorMaskState.Default; } } @@ -147,122 +147,122 @@ namespace Ryujinx.Graphics.Gal.OpenGL BindVertexLayout(New); - if (New.FramebufferSrgb != Old.FramebufferSrgb) + if (New.FramebufferSrgb != _old.FramebufferSrgb) { Enable(EnableCap.FramebufferSrgb, New.FramebufferSrgb); - RenderTarget.FramebufferSrgb = New.FramebufferSrgb; + _renderTarget.FramebufferSrgb = New.FramebufferSrgb; } - if (New.FlipX != Old.FlipX || New.FlipY != Old.FlipY || New.Instance != Old.Instance) + if (New.FlipX != _old.FlipX || New.FlipY != _old.FlipY || New.Instance != _old.Instance) { - Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance); + _shader.SetExtraData(New.FlipX, New.FlipY, New.Instance); } - if (New.FrontFace != Old.FrontFace) + if (New.FrontFace != _old.FrontFace) { - GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace)); + GL.FrontFace(OglEnumConverter.GetFrontFace(New.FrontFace)); } - if (New.CullFaceEnabled != Old.CullFaceEnabled) + if (New.CullFaceEnabled != _old.CullFaceEnabled) { Enable(EnableCap.CullFace, New.CullFaceEnabled); } if (New.CullFaceEnabled) { - if (New.CullFace != Old.CullFace) + if (New.CullFace != _old.CullFace) { - GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace)); + GL.CullFace(OglEnumConverter.GetCullFace(New.CullFace)); } } - if (New.DepthTestEnabled != Old.DepthTestEnabled) + if (New.DepthTestEnabled != _old.DepthTestEnabled) { Enable(EnableCap.DepthTest, New.DepthTestEnabled); } - if (New.DepthWriteEnabled != Old.DepthWriteEnabled) + if (New.DepthWriteEnabled != _old.DepthWriteEnabled) { GL.DepthMask(New.DepthWriteEnabled); } if (New.DepthTestEnabled) { - if (New.DepthFunc != Old.DepthFunc) + if (New.DepthFunc != _old.DepthFunc) { - GL.DepthFunc(OGLEnumConverter.GetDepthFunc(New.DepthFunc)); + GL.DepthFunc(OglEnumConverter.GetDepthFunc(New.DepthFunc)); } } - if (New.DepthRangeNear != Old.DepthRangeNear || - New.DepthRangeFar != Old.DepthRangeFar) + if (New.DepthRangeNear != _old.DepthRangeNear || + New.DepthRangeFar != _old.DepthRangeFar) { GL.DepthRange(New.DepthRangeNear, New.DepthRangeFar); } - if (New.StencilTestEnabled != Old.StencilTestEnabled) + if (New.StencilTestEnabled != _old.StencilTestEnabled) { Enable(EnableCap.StencilTest, New.StencilTestEnabled); } - if (New.StencilTwoSideEnabled != Old.StencilTwoSideEnabled) + if (New.StencilTwoSideEnabled != _old.StencilTwoSideEnabled) { Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled); } if (New.StencilTestEnabled) { - if (New.StencilBackFuncFunc != Old.StencilBackFuncFunc || - New.StencilBackFuncRef != Old.StencilBackFuncRef || - New.StencilBackFuncMask != Old.StencilBackFuncMask) + if (New.StencilBackFuncFunc != _old.StencilBackFuncFunc || + New.StencilBackFuncRef != _old.StencilBackFuncRef || + New.StencilBackFuncMask != _old.StencilBackFuncMask) { GL.StencilFuncSeparate( StencilFace.Back, - OGLEnumConverter.GetStencilFunc(New.StencilBackFuncFunc), + OglEnumConverter.GetStencilFunc(New.StencilBackFuncFunc), New.StencilBackFuncRef, New.StencilBackFuncMask); } - if (New.StencilBackOpFail != Old.StencilBackOpFail || - New.StencilBackOpZFail != Old.StencilBackOpZFail || - New.StencilBackOpZPass != Old.StencilBackOpZPass) + if (New.StencilBackOpFail != _old.StencilBackOpFail || + New.StencilBackOpZFail != _old.StencilBackOpZFail || + New.StencilBackOpZPass != _old.StencilBackOpZPass) { GL.StencilOpSeparate( StencilFace.Back, - OGLEnumConverter.GetStencilOp(New.StencilBackOpFail), - OGLEnumConverter.GetStencilOp(New.StencilBackOpZFail), - OGLEnumConverter.GetStencilOp(New.StencilBackOpZPass)); + OglEnumConverter.GetStencilOp(New.StencilBackOpFail), + OglEnumConverter.GetStencilOp(New.StencilBackOpZFail), + OglEnumConverter.GetStencilOp(New.StencilBackOpZPass)); } - if (New.StencilBackMask != Old.StencilBackMask) + if (New.StencilBackMask != _old.StencilBackMask) { GL.StencilMaskSeparate(StencilFace.Back, New.StencilBackMask); } - if (New.StencilFrontFuncFunc != Old.StencilFrontFuncFunc || - New.StencilFrontFuncRef != Old.StencilFrontFuncRef || - New.StencilFrontFuncMask != Old.StencilFrontFuncMask) + if (New.StencilFrontFuncFunc != _old.StencilFrontFuncFunc || + New.StencilFrontFuncRef != _old.StencilFrontFuncRef || + New.StencilFrontFuncMask != _old.StencilFrontFuncMask) { GL.StencilFuncSeparate( StencilFace.Front, - OGLEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc), + OglEnumConverter.GetStencilFunc(New.StencilFrontFuncFunc), New.StencilFrontFuncRef, New.StencilFrontFuncMask); } - if (New.StencilFrontOpFail != Old.StencilFrontOpFail || - New.StencilFrontOpZFail != Old.StencilFrontOpZFail || - New.StencilFrontOpZPass != Old.StencilFrontOpZPass) + if (New.StencilFrontOpFail != _old.StencilFrontOpFail || + New.StencilFrontOpZFail != _old.StencilFrontOpZFail || + New.StencilFrontOpZPass != _old.StencilFrontOpZPass) { GL.StencilOpSeparate( StencilFace.Front, - OGLEnumConverter.GetStencilOp(New.StencilFrontOpFail), - OGLEnumConverter.GetStencilOp(New.StencilFrontOpZFail), - OGLEnumConverter.GetStencilOp(New.StencilFrontOpZPass)); + OglEnumConverter.GetStencilOp(New.StencilFrontOpFail), + OglEnumConverter.GetStencilOp(New.StencilFrontOpZFail), + OglEnumConverter.GetStencilOp(New.StencilFrontOpZPass)); } - if (New.StencilFrontMask != Old.StencilFrontMask) + if (New.StencilFrontMask != _old.StencilFrontMask) { GL.StencilMaskSeparate(StencilFace.Front, New.StencilFrontMask); } @@ -277,42 +277,42 @@ namespace Ryujinx.Graphics.Gal.OpenGL int scissorsApplied = 0; bool applyToAll = false; - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) { - if (New.ScissorTestEnabled[Index]) + if (New.ScissorTestEnabled[index]) { // If viewport arrays are unavailable apply first scissor test to all or // there is only 1 scissor test and it's the first, the scissor test applies to all viewports - if (!OGLExtension.Required.ViewportArray || (Index == 0 && New.ScissorTestCount == 1)) + if (!OglExtension.Required.ViewportArray || (index == 0 && New.ScissorTestCount == 1)) { GL.Enable(EnableCap.ScissorTest); applyToAll = true; } else { - GL.Enable(IndexedEnableCap.ScissorTest, Index); + GL.Enable(IndexedEnableCap.ScissorTest, index); } - if (New.ScissorTestEnabled[Index] != Old.ScissorTestEnabled[Index] || - New.ScissorTestX[Index] != Old.ScissorTestX[Index] || - New.ScissorTestY[Index] != Old.ScissorTestY[Index] || - New.ScissorTestWidth[Index] != Old.ScissorTestWidth[Index] || - New.ScissorTestHeight[Index] != Old.ScissorTestHeight[Index]) + if (New.ScissorTestEnabled[index] != _old.ScissorTestEnabled[index] || + New.ScissorTestX[index] != _old.ScissorTestX[index] || + New.ScissorTestY[index] != _old.ScissorTestY[index] || + New.ScissorTestWidth[index] != _old.ScissorTestWidth[index] || + New.ScissorTestHeight[index] != _old.ScissorTestHeight[index]) { if (applyToAll) { - GL.Scissor(New.ScissorTestX[Index], New.ScissorTestY[Index], - New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]); + GL.Scissor(New.ScissorTestX[index], New.ScissorTestY[index], + New.ScissorTestWidth[index], New.ScissorTestHeight[index]); } else { - GL.ScissorIndexed(Index, New.ScissorTestX[Index], New.ScissorTestY[Index], - New.ScissorTestWidth[Index], New.ScissorTestHeight[Index]); + GL.ScissorIndexed(index, New.ScissorTestX[index], New.ScissorTestY[index], + New.ScissorTestWidth[index], New.ScissorTestHeight[index]); } } - // If all scissor tests have been applied, or viewport arrays are unavailable we can skip remaining itterations - if (!OGLExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount) + // If all scissor tests have been applied, or viewport arrays are unavailable we can skip remaining iterations + if (!OglExtension.Required.ViewportArray || ++scissorsApplied == New.ScissorTestCount) { break; } @@ -323,26 +323,26 @@ namespace Ryujinx.Graphics.Gal.OpenGL if (New.BlendIndependent) { - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) { - SetBlendState(Index, New.Blends[Index], Old.Blends[Index]); + SetBlendState(index, New.Blends[index], _old.Blends[index]); } } else { - if (New.BlendIndependent != Old.BlendIndependent) + if (New.BlendIndependent != _old.BlendIndependent) { SetAllBlendState(New.Blends[0]); } else { - SetBlendState(New.Blends[0], Old.Blends[0]); + SetBlendState(New.Blends[0], _old.Blends[0]); } } if (New.ColorMaskCommon) { - if (New.ColorMaskCommon != Old.ColorMaskCommon || !New.ColorMasks[0].Equals(Old.ColorMasks[0])) + if (New.ColorMaskCommon != _old.ColorMaskCommon || !New.ColorMasks[0].Equals(_old.ColorMasks[0])) { GL.ColorMask( New.ColorMasks[0].Red, @@ -353,39 +353,39 @@ namespace Ryujinx.Graphics.Gal.OpenGL } else { - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) { - if (!New.ColorMasks[Index].Equals(Old.ColorMasks[Index])) + if (!New.ColorMasks[index].Equals(_old.ColorMasks[index])) { GL.ColorMask( - Index, - New.ColorMasks[Index].Red, - New.ColorMasks[Index].Green, - New.ColorMasks[Index].Blue, - New.ColorMasks[Index].Alpha); + index, + New.ColorMasks[index].Red, + New.ColorMasks[index].Green, + New.ColorMasks[index].Blue, + New.ColorMasks[index].Alpha); } } } - if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled) + if (New.PrimitiveRestartEnabled != _old.PrimitiveRestartEnabled) { Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled); } if (New.PrimitiveRestartEnabled) { - if (New.PrimitiveRestartIndex != Old.PrimitiveRestartIndex) + if (New.PrimitiveRestartIndex != _old.PrimitiveRestartIndex) { GL.PrimitiveRestartIndex(New.PrimitiveRestartIndex); } } - Old = New; + _old = New; } - public void Unbind(GalPipelineState State) + public void Unbind(GalPipelineState state) { - if (State.ScissorTestCount > 0) + if (state.ScissorTestCount > 0) { GL.Disable(EnableCap.ScissorTest); } @@ -400,29 +400,29 @@ namespace Ryujinx.Graphics.Gal.OpenGL if (New.SeparateAlpha) { GL.BlendEquationSeparate( - OGLEnumConverter.GetBlendEquation(New.EquationRgb), - OGLEnumConverter.GetBlendEquation(New.EquationAlpha)); + OglEnumConverter.GetBlendEquation(New.EquationRgb), + OglEnumConverter.GetBlendEquation(New.EquationAlpha)); GL.BlendFuncSeparate( - (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb), - (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha), - (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha)); + (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb), + (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb), + (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha), + (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha)); } else { - GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb)); + GL.BlendEquation(OglEnumConverter.GetBlendEquation(New.EquationRgb)); GL.BlendFunc( - OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - OGLEnumConverter.GetBlendFactor(New.FuncDstRgb)); + OglEnumConverter.GetBlendFactor(New.FuncSrcRgb), + OglEnumConverter.GetBlendFactor(New.FuncDstRgb)); } } } - private void SetBlendState(BlendState New, BlendState Old) + private void SetBlendState(BlendState New, BlendState old) { - if (New.Enabled != Old.Enabled) + if (New.Enabled != old.Enabled) { Enable(EnableCap.Blend, New.Enabled); } @@ -431,91 +431,91 @@ namespace Ryujinx.Graphics.Gal.OpenGL { if (New.SeparateAlpha) { - if (New.EquationRgb != Old.EquationRgb || - New.EquationAlpha != Old.EquationAlpha) + if (New.EquationRgb != old.EquationRgb || + New.EquationAlpha != old.EquationAlpha) { GL.BlendEquationSeparate( - OGLEnumConverter.GetBlendEquation(New.EquationRgb), - OGLEnumConverter.GetBlendEquation(New.EquationAlpha)); + OglEnumConverter.GetBlendEquation(New.EquationRgb), + OglEnumConverter.GetBlendEquation(New.EquationAlpha)); } - if (New.FuncSrcRgb != Old.FuncSrcRgb || - New.FuncDstRgb != Old.FuncDstRgb || - New.FuncSrcAlpha != Old.FuncSrcAlpha || - New.FuncDstAlpha != Old.FuncDstAlpha) + if (New.FuncSrcRgb != old.FuncSrcRgb || + New.FuncDstRgb != old.FuncDstRgb || + New.FuncSrcAlpha != old.FuncSrcAlpha || + New.FuncDstAlpha != old.FuncDstAlpha) { GL.BlendFuncSeparate( - (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb), - (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha), - (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha)); + (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb), + (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb), + (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha), + (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha)); } } else { - if (New.EquationRgb != Old.EquationRgb) + if (New.EquationRgb != old.EquationRgb) { - GL.BlendEquation(OGLEnumConverter.GetBlendEquation(New.EquationRgb)); + GL.BlendEquation(OglEnumConverter.GetBlendEquation(New.EquationRgb)); } - if (New.FuncSrcRgb != Old.FuncSrcRgb || - New.FuncDstRgb != Old.FuncDstRgb) + if (New.FuncSrcRgb != old.FuncSrcRgb || + New.FuncDstRgb != old.FuncDstRgb) { GL.BlendFunc( - OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - OGLEnumConverter.GetBlendFactor(New.FuncDstRgb)); + OglEnumConverter.GetBlendFactor(New.FuncSrcRgb), + OglEnumConverter.GetBlendFactor(New.FuncDstRgb)); } } } } - private void SetBlendState(int Index, BlendState New, BlendState Old) + private void SetBlendState(int index, BlendState New, BlendState old) { - if (New.Enabled != Old.Enabled) + if (New.Enabled != old.Enabled) { - Enable(IndexedEnableCap.Blend, Index, New.Enabled); + Enable(IndexedEnableCap.Blend, index, New.Enabled); } if (New.Enabled) { if (New.SeparateAlpha) { - if (New.EquationRgb != Old.EquationRgb || - New.EquationAlpha != Old.EquationAlpha) + if (New.EquationRgb != old.EquationRgb || + New.EquationAlpha != old.EquationAlpha) { GL.BlendEquationSeparate( - Index, - OGLEnumConverter.GetBlendEquation(New.EquationRgb), - OGLEnumConverter.GetBlendEquation(New.EquationAlpha)); + index, + OglEnumConverter.GetBlendEquation(New.EquationRgb), + OglEnumConverter.GetBlendEquation(New.EquationAlpha)); } - if (New.FuncSrcRgb != Old.FuncSrcRgb || - New.FuncDstRgb != Old.FuncDstRgb || - New.FuncSrcAlpha != Old.FuncSrcAlpha || - New.FuncDstAlpha != Old.FuncDstAlpha) + if (New.FuncSrcRgb != old.FuncSrcRgb || + New.FuncDstRgb != old.FuncDstRgb || + New.FuncSrcAlpha != old.FuncSrcAlpha || + New.FuncDstAlpha != old.FuncDstAlpha) { GL.BlendFuncSeparate( - Index, - (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb), - (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcAlpha), - (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstAlpha)); + index, + (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb), + (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb), + (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcAlpha), + (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstAlpha)); } } else { - if (New.EquationRgb != Old.EquationRgb) + if (New.EquationRgb != old.EquationRgb) { - GL.BlendEquation(Index, OGLEnumConverter.GetBlendEquation(New.EquationRgb)); + GL.BlendEquation(index, OglEnumConverter.GetBlendEquation(New.EquationRgb)); } - if (New.FuncSrcRgb != Old.FuncSrcRgb || - New.FuncDstRgb != Old.FuncDstRgb) + if (New.FuncSrcRgb != old.FuncSrcRgb || + New.FuncDstRgb != old.FuncDstRgb) { GL.BlendFunc( - Index, - (BlendingFactorSrc) OGLEnumConverter.GetBlendFactor(New.FuncSrcRgb), - (BlendingFactorDest)OGLEnumConverter.GetBlendFactor(New.FuncDstRgb)); + index, + (BlendingFactorSrc) OglEnumConverter.GetBlendFactor(New.FuncSrcRgb), + (BlendingFactorDest)OglEnumConverter.GetBlendFactor(New.FuncDstRgb)); } } } @@ -523,310 +523,310 @@ namespace Ryujinx.Graphics.Gal.OpenGL private void BindConstBuffers(GalPipelineState New) { - int FreeBinding = OGLShader.ReservedCbufCount; + int freeBinding = OglShader.ReservedCbufCount; - void BindIfNotNull(OGLShaderStage Stage) + void BindIfNotNull(OglShaderStage stage) { - if (Stage != null) + if (stage != null) { - foreach (ShaderDeclInfo DeclInfo in Stage.ConstBufferUsage) + foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage) { - long Key = New.ConstBufferKeys[(int)Stage.Type][DeclInfo.Cbuf]; + long key = New.ConstBufferKeys[(int)stage.Type][declInfo.Cbuf]; - if (Key != 0 && Buffer.TryGetUbo(Key, out int UboHandle)) + if (key != 0 && _buffer.TryGetUbo(key, out int uboHandle)) { - GL.BindBufferBase(BufferRangeTarget.UniformBuffer, FreeBinding, UboHandle); + GL.BindBufferBase(BufferRangeTarget.UniformBuffer, freeBinding, uboHandle); } - FreeBinding++; + freeBinding++; } } } - BindIfNotNull(Shader.Current.Vertex); - BindIfNotNull(Shader.Current.TessControl); - BindIfNotNull(Shader.Current.TessEvaluation); - BindIfNotNull(Shader.Current.Geometry); - BindIfNotNull(Shader.Current.Fragment); + BindIfNotNull(_shader.Current.Vertex); + BindIfNotNull(_shader.Current.TessControl); + BindIfNotNull(_shader.Current.TessEvaluation); + BindIfNotNull(_shader.Current.Geometry); + BindIfNotNull(_shader.Current.Fragment); } private void BindVertexLayout(GalPipelineState New) { - foreach (GalVertexBinding Binding in New.VertexBindings) + foreach (GalVertexBinding binding in New.VertexBindings) { - if (!Binding.Enabled || !Rasterizer.TryGetVbo(Binding.VboKey, out int VboHandle)) + if (!binding.Enabled || !_rasterizer.TryGetVbo(binding.VboKey, out int vboHandle)) { continue; } - if (VaoHandle == 0) + if (_vaoHandle == 0) { - VaoHandle = GL.GenVertexArray(); + _vaoHandle = GL.GenVertexArray(); //Vertex arrays shouldn't be used anywhere else in OpenGL's backend //if you want to use it, move this line out of the if - GL.BindVertexArray(VaoHandle); + GL.BindVertexArray(_vaoHandle); } - foreach (GalVertexAttrib Attrib in Binding.Attribs) + foreach (GalVertexAttrib attrib in binding.Attribs) { //Skip uninitialized attributes. - if (Attrib.Size == 0) + if (attrib.Size == 0) { continue; } - GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle); + GL.BindBuffer(BufferTarget.ArrayBuffer, vboHandle); - bool Unsigned = - Attrib.Type == GalVertexAttribType.Unorm || - Attrib.Type == GalVertexAttribType.Uint || - Attrib.Type == GalVertexAttribType.Uscaled; + bool unsigned = + attrib.Type == GalVertexAttribType.Unorm || + attrib.Type == GalVertexAttribType.Uint || + attrib.Type == GalVertexAttribType.Uscaled; - bool Normalize = - Attrib.Type == GalVertexAttribType.Snorm || - Attrib.Type == GalVertexAttribType.Unorm; + bool normalize = + attrib.Type == GalVertexAttribType.Snorm || + attrib.Type == GalVertexAttribType.Unorm; - VertexAttribPointerType Type = 0; + VertexAttribPointerType type = 0; - if (Attrib.Type == GalVertexAttribType.Float) + if (attrib.Type == GalVertexAttribType.Float) { - Type = GetType(FloatAttribTypes, Attrib); + type = GetType(_floatAttribTypes, attrib); } else { - if (Unsigned) + if (unsigned) { - Type = GetType(UnsignedAttribTypes, Attrib); + type = GetType(_unsignedAttribTypes, attrib); } else { - Type = GetType(SignedAttribTypes, Attrib); + type = GetType(_signedAttribTypes, attrib); } } - if (!AttribElements.TryGetValue(Attrib.Size, out int Size)) + if (!_attribElements.TryGetValue(attrib.Size, out int size)) { - throw new InvalidOperationException("Invalid attribute size \"" + Attrib.Size + "\"!"); + throw new InvalidOperationException("Invalid attribute size \"" + attrib.Size + "\"!"); } - int Offset = Attrib.Offset; + int offset = attrib.Offset; - if (Binding.Stride != 0) + if (binding.Stride != 0) { - GL.EnableVertexAttribArray(Attrib.Index); + GL.EnableVertexAttribArray(attrib.Index); - if (Attrib.Type == GalVertexAttribType.Sint || - Attrib.Type == GalVertexAttribType.Uint) + if (attrib.Type == GalVertexAttribType.Sint || + attrib.Type == GalVertexAttribType.Uint) { - IntPtr Pointer = new IntPtr(Offset); + IntPtr pointer = new IntPtr(offset); - VertexAttribIntegerType IType = (VertexAttribIntegerType)Type; + VertexAttribIntegerType iType = (VertexAttribIntegerType)type; - GL.VertexAttribIPointer(Attrib.Index, Size, IType, Binding.Stride, Pointer); + GL.VertexAttribIPointer(attrib.Index, size, iType, binding.Stride, pointer); } else { - GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset); + GL.VertexAttribPointer(attrib.Index, size, type, normalize, binding.Stride, offset); } } else { - GL.DisableVertexAttribArray(Attrib.Index); + GL.DisableVertexAttribArray(attrib.Index); - SetConstAttrib(Attrib); + SetConstAttrib(attrib); } - if (Binding.Instanced && Binding.Divisor != 0) + if (binding.Instanced && binding.Divisor != 0) { - GL.VertexAttribDivisor(Attrib.Index, 1); + GL.VertexAttribDivisor(attrib.Index, 1); } else { - GL.VertexAttribDivisor(Attrib.Index, 0); + GL.VertexAttribDivisor(attrib.Index, 0); } } } } - private static VertexAttribPointerType GetType(Dictionary Dict, GalVertexAttrib Attrib) + private static VertexAttribPointerType GetType(Dictionary dict, GalVertexAttrib attrib) { - if (!Dict.TryGetValue(Attrib.Size, out VertexAttribPointerType Type)) + if (!dict.TryGetValue(attrib.Size, out VertexAttribPointerType type)) { - ThrowUnsupportedAttrib(Attrib); + ThrowUnsupportedAttrib(attrib); } - return Type; + return type; } - private unsafe static void SetConstAttrib(GalVertexAttrib Attrib) + private static unsafe void SetConstAttrib(GalVertexAttrib attrib) { - if (Attrib.Size == GalVertexAttribSize._10_10_10_2 || - Attrib.Size == GalVertexAttribSize._11_11_10) + if (attrib.Size == GalVertexAttribSize._10_10_10_2 || + attrib.Size == GalVertexAttribSize._11_11_10) { - ThrowUnsupportedAttrib(Attrib); + ThrowUnsupportedAttrib(attrib); } - fixed (byte* Ptr = Attrib.Data) + fixed (byte* ptr = attrib.Data) { - if (Attrib.Type == GalVertexAttribType.Unorm) + if (attrib.Type == GalVertexAttribType.Unorm) { - switch (Attrib.Size) + switch (attrib.Size) { case GalVertexAttribSize._8: case GalVertexAttribSize._8_8: case GalVertexAttribSize._8_8_8: case GalVertexAttribSize._8_8_8_8: - GL.VertexAttrib4N((uint)Attrib.Index, Ptr); + GL.VertexAttrib4N((uint)attrib.Index, ptr); break; case GalVertexAttribSize._16: case GalVertexAttribSize._16_16: case GalVertexAttribSize._16_16_16: case GalVertexAttribSize._16_16_16_16: - GL.VertexAttrib4N((uint)Attrib.Index, (ushort*)Ptr); + GL.VertexAttrib4N((uint)attrib.Index, (ushort*)ptr); break; case GalVertexAttribSize._32: case GalVertexAttribSize._32_32: case GalVertexAttribSize._32_32_32: case GalVertexAttribSize._32_32_32_32: - GL.VertexAttrib4N((uint)Attrib.Index, (uint*)Ptr); + GL.VertexAttrib4N((uint)attrib.Index, (uint*)ptr); break; } } - else if (Attrib.Type == GalVertexAttribType.Snorm) + else if (attrib.Type == GalVertexAttribType.Snorm) { - switch (Attrib.Size) + switch (attrib.Size) { case GalVertexAttribSize._8: case GalVertexAttribSize._8_8: case GalVertexAttribSize._8_8_8: case GalVertexAttribSize._8_8_8_8: - GL.VertexAttrib4N((uint)Attrib.Index, (sbyte*)Ptr); + GL.VertexAttrib4N((uint)attrib.Index, (sbyte*)ptr); break; case GalVertexAttribSize._16: case GalVertexAttribSize._16_16: case GalVertexAttribSize._16_16_16: case GalVertexAttribSize._16_16_16_16: - GL.VertexAttrib4N((uint)Attrib.Index, (short*)Ptr); + GL.VertexAttrib4N((uint)attrib.Index, (short*)ptr); break; case GalVertexAttribSize._32: case GalVertexAttribSize._32_32: case GalVertexAttribSize._32_32_32: case GalVertexAttribSize._32_32_32_32: - GL.VertexAttrib4N((uint)Attrib.Index, (int*)Ptr); + GL.VertexAttrib4N((uint)attrib.Index, (int*)ptr); break; } } - else if (Attrib.Type == GalVertexAttribType.Uint) + else if (attrib.Type == GalVertexAttribType.Uint) { - switch (Attrib.Size) + switch (attrib.Size) { case GalVertexAttribSize._8: case GalVertexAttribSize._8_8: case GalVertexAttribSize._8_8_8: case GalVertexAttribSize._8_8_8_8: - GL.VertexAttribI4((uint)Attrib.Index, Ptr); + GL.VertexAttribI4((uint)attrib.Index, ptr); break; case GalVertexAttribSize._16: case GalVertexAttribSize._16_16: case GalVertexAttribSize._16_16_16: case GalVertexAttribSize._16_16_16_16: - GL.VertexAttribI4((uint)Attrib.Index, (ushort*)Ptr); + GL.VertexAttribI4((uint)attrib.Index, (ushort*)ptr); break; case GalVertexAttribSize._32: case GalVertexAttribSize._32_32: case GalVertexAttribSize._32_32_32: case GalVertexAttribSize._32_32_32_32: - GL.VertexAttribI4((uint)Attrib.Index, (uint*)Ptr); + GL.VertexAttribI4((uint)attrib.Index, (uint*)ptr); break; } } - else if (Attrib.Type == GalVertexAttribType.Sint) + else if (attrib.Type == GalVertexAttribType.Sint) { - switch (Attrib.Size) + switch (attrib.Size) { case GalVertexAttribSize._8: case GalVertexAttribSize._8_8: case GalVertexAttribSize._8_8_8: case GalVertexAttribSize._8_8_8_8: - GL.VertexAttribI4((uint)Attrib.Index, (sbyte*)Ptr); + GL.VertexAttribI4((uint)attrib.Index, (sbyte*)ptr); break; case GalVertexAttribSize._16: case GalVertexAttribSize._16_16: case GalVertexAttribSize._16_16_16: case GalVertexAttribSize._16_16_16_16: - GL.VertexAttribI4((uint)Attrib.Index, (short*)Ptr); + GL.VertexAttribI4((uint)attrib.Index, (short*)ptr); break; case GalVertexAttribSize._32: case GalVertexAttribSize._32_32: case GalVertexAttribSize._32_32_32: case GalVertexAttribSize._32_32_32_32: - GL.VertexAttribI4((uint)Attrib.Index, (int*)Ptr); + GL.VertexAttribI4((uint)attrib.Index, (int*)ptr); break; } } - else if (Attrib.Type == GalVertexAttribType.Float) + else if (attrib.Type == GalVertexAttribType.Float) { - switch (Attrib.Size) + switch (attrib.Size) { case GalVertexAttribSize._32: case GalVertexAttribSize._32_32: case GalVertexAttribSize._32_32_32: case GalVertexAttribSize._32_32_32_32: - GL.VertexAttrib4(Attrib.Index, (float*)Ptr); + GL.VertexAttrib4(attrib.Index, (float*)ptr); break; - default: ThrowUnsupportedAttrib(Attrib); break; + default: ThrowUnsupportedAttrib(attrib); break; } } } } - private static void ThrowUnsupportedAttrib(GalVertexAttrib Attrib) + private static void ThrowUnsupportedAttrib(GalVertexAttrib attrib) { - throw new NotImplementedException("Unsupported size \"" + Attrib.Size + "\" on type \"" + Attrib.Type + "\"!"); + throw new NotImplementedException("Unsupported size \"" + attrib.Size + "\" on type \"" + attrib.Type + "\"!"); } - private void Enable(EnableCap Cap, bool Enabled) + private void Enable(EnableCap cap, bool enabled) { - if (Enabled) + if (enabled) { - GL.Enable(Cap); + GL.Enable(cap); } else { - GL.Disable(Cap); + GL.Disable(cap); } } - private void Enable(IndexedEnableCap Cap, int Index, bool Enabled) + private void Enable(IndexedEnableCap cap, int index, bool enabled) { - if (Enabled) + if (enabled) { - GL.Enable(Cap, Index); + GL.Enable(cap, index); } else { - GL.Disable(Cap, Index); + GL.Disable(cap, index); } } public void ResetDepthMask() { - Old.DepthWriteEnabled = true; + _old.DepthWriteEnabled = true; } - public void ResetColorMask(int Index) + public void ResetColorMask(int index) { - Old.ColorMasks[Index] = ColorMaskState.Default; + _old.ColorMasks[index] = ColorMaskState.Default; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs new file mode 100644 index 0000000000..c19911c57a --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglRasterizer.cs @@ -0,0 +1,207 @@ +using OpenTK.Graphics.OpenGL; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OglRasterizer : IGalRasterizer + { + private const long MaxVertexBufferCacheSize = 128 * 1024 * 1024; + private const long MaxIndexBufferCacheSize = 64 * 1024 * 1024; + + private int[] _vertexBuffers; + + private OglCachedResource _vboCache; + private OglCachedResource _iboCache; + + private struct IbInfo + { + public int Count; + public int ElemSizeLog2; + + public DrawElementsType Type; + } + + private IbInfo _indexBuffer; + + public OglRasterizer() + { + _vertexBuffers = new int[32]; + + _vboCache = new OglCachedResource(GL.DeleteBuffer, MaxVertexBufferCacheSize); + _iboCache = new OglCachedResource(GL.DeleteBuffer, MaxIndexBufferCacheSize); + + _indexBuffer = new IbInfo(); + } + + public void LockCaches() + { + _vboCache.Lock(); + _iboCache.Lock(); + } + + public void UnlockCaches() + { + _vboCache.Unlock(); + _iboCache.Unlock(); + } + + public void ClearBuffers( + GalClearBufferFlags flags, + int attachment, + float red, + float green, + float blue, + float alpha, + float depth, + int stencil) + { + GL.ColorMask( + attachment, + flags.HasFlag(GalClearBufferFlags.ColorRed), + flags.HasFlag(GalClearBufferFlags.ColorGreen), + flags.HasFlag(GalClearBufferFlags.ColorBlue), + flags.HasFlag(GalClearBufferFlags.ColorAlpha)); + + GL.ClearBuffer(ClearBuffer.Color, attachment, new float[] { red, green, blue, alpha }); + + GL.ColorMask(attachment, true, true, true, true); + GL.DepthMask(true); + + if (flags.HasFlag(GalClearBufferFlags.Depth)) + { + GL.ClearBuffer(ClearBuffer.Depth, 0, ref depth); + } + + if (flags.HasFlag(GalClearBufferFlags.Stencil)) + { + GL.ClearBuffer(ClearBuffer.Stencil, 0, ref stencil); + } + } + + public bool IsVboCached(long key, long dataSize) + { + return _vboCache.TryGetSize(key, out long size) && size == dataSize; + } + + public bool IsIboCached(long key, long dataSize) + { + return _iboCache.TryGetSize(key, out long size) && size == dataSize; + } + + public void CreateVbo(long key, int dataSize, IntPtr hostAddress) + { + int handle = GL.GenBuffer(); + + _vboCache.AddOrUpdate(key, handle, dataSize); + + IntPtr length = new IntPtr(dataSize); + + GL.BindBuffer(BufferTarget.ArrayBuffer, handle); + GL.BufferData(BufferTarget.ArrayBuffer, length, hostAddress, BufferUsageHint.StreamDraw); + } + + public void CreateVbo(long key, byte[] data) + { + int handle = GL.GenBuffer(); + + _vboCache.AddOrUpdate(key, handle, data.Length); + + IntPtr length = new IntPtr(data.Length); + + GL.BindBuffer(BufferTarget.ArrayBuffer, handle); + GL.BufferData(BufferTarget.ArrayBuffer, length, data, BufferUsageHint.StreamDraw); + } + + public void CreateIbo(long key, int dataSize, IntPtr hostAddress) + { + int handle = GL.GenBuffer(); + + _iboCache.AddOrUpdate(key, handle, (uint)dataSize); + + IntPtr length = new IntPtr(dataSize); + + GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle); + GL.BufferData(BufferTarget.ElementArrayBuffer, length, hostAddress, BufferUsageHint.StreamDraw); + } + + public void CreateIbo(long key, int dataSize, byte[] buffer) + { + int handle = GL.GenBuffer(); + + _iboCache.AddOrUpdate(key, handle, dataSize); + + IntPtr length = new IntPtr(buffer.Length); + + GL.BindBuffer(BufferTarget.ElementArrayBuffer, handle); + GL.BufferData(BufferTarget.ElementArrayBuffer, length, buffer, BufferUsageHint.StreamDraw); + } + + public void SetIndexArray(int size, GalIndexFormat format) + { + _indexBuffer.Type = OglEnumConverter.GetDrawElementsType(format); + + _indexBuffer.Count = size >> (int)format; + + _indexBuffer.ElemSizeLog2 = (int)format; + } + + public void DrawArrays(int first, int count, GalPrimitiveType primType) + { + if (count == 0) + { + return; + } + + if (primType == GalPrimitiveType.Quads) + { + for (int offset = 0; offset < count; offset += 4) + { + GL.DrawArrays(PrimitiveType.TriangleFan, first + offset, 4); + } + } + else if (primType == GalPrimitiveType.QuadStrip) + { + GL.DrawArrays(PrimitiveType.TriangleFan, first, 4); + + for (int offset = 2; offset < count; offset += 2) + { + GL.DrawArrays(PrimitiveType.TriangleFan, first + offset, 4); + } + } + else + { + GL.DrawArrays(OglEnumConverter.GetPrimitiveType(primType), first, count); + } + } + + public void DrawElements(long iboKey, int first, int vertexBase, GalPrimitiveType primType) + { + if (!_iboCache.TryGetValue(iboKey, out int iboHandle)) + { + return; + } + + PrimitiveType mode = OglEnumConverter.GetPrimitiveType(primType); + + GL.BindBuffer(BufferTarget.ElementArrayBuffer, iboHandle); + + first <<= _indexBuffer.ElemSizeLog2; + + if (vertexBase != 0) + { + IntPtr indices = new IntPtr(first); + + GL.DrawElementsBaseVertex(mode, _indexBuffer.Count, _indexBuffer.Type, indices, vertexBase); + } + else + { + GL.DrawElements(mode, _indexBuffer.Count, _indexBuffer.Type, first); + } + } + + public bool TryGetVbo(long vboKey, out int vboHandle) + { + return _vboCache.TryGetValue(vboKey, out vboHandle); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs b/Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs new file mode 100644 index 0000000000..d36bac1bcf --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglRenderTarget.cs @@ -0,0 +1,549 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Texture; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OglRenderTarget : IGalRenderTarget + { + private const int NativeWidth = 1280; + private const int NativeHeight = 720; + + private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount; + + private struct Rect + { + public int X { get; private set; } + public int Y { get; private set; } + public int Width { get; private set; } + public int Height { get; private set; } + + public Rect(int x, int y, int width, int height) + { + X = x; + Y = y; + Width = width; + Height = height; + } + } + + private class FrameBufferAttachments + { + public int MapCount { get; set; } + + public DrawBuffersEnum[] Map { get; private set; } + + public long[] Colors { get; private set; } + + public long Zeta { get; set; } + + public FrameBufferAttachments() + { + Colors = new long[RenderTargetsCount]; + + Map = new DrawBuffersEnum[RenderTargetsCount]; + } + + public void Update(FrameBufferAttachments source) + { + for (int index = 0; index < RenderTargetsCount; index++) + { + Map[index] = source.Map[index]; + + Colors[index] = source.Colors[index]; + } + + MapCount = source.MapCount; + Zeta = source.Zeta; + } + } + + private int[] _colorHandles; + private int _zetaHandle; + + private OglTexture _texture; + + private ImageHandler _readTex; + + private Rect _window; + + private float[] _viewports; + + private bool _flipX; + private bool _flipY; + + private int _cropTop; + private int _cropLeft; + private int _cropRight; + private int _cropBottom; + + //This framebuffer is used to attach guest rendertargets, + //think of it as a dummy OpenGL VAO + private int _dummyFrameBuffer; + + //These framebuffers are used to blit images + private int _srcFb; + private int _dstFb; + + private FrameBufferAttachments _attachments; + private FrameBufferAttachments _oldAttachments; + + private int _copyPbo; + + public bool FramebufferSrgb { get; set; } + + public OglRenderTarget(OglTexture texture) + { + _attachments = new FrameBufferAttachments(); + + _oldAttachments = new FrameBufferAttachments(); + + _colorHandles = new int[RenderTargetsCount]; + + _viewports = new float[RenderTargetsCount * 4]; + + _texture = texture; + + texture.TextureDeleted += TextureDeletionHandler; + } + + private void TextureDeletionHandler(object sender, int handle) + { + //Texture was deleted, the handle is no longer valid, so + //reset all uses of this handle on a render target. + for (int attachment = 0; attachment < RenderTargetsCount; attachment++) + { + if (_colorHandles[attachment] == handle) + { + _colorHandles[attachment] = 0; + } + } + + if (_zetaHandle == handle) + { + _zetaHandle = 0; + } + } + + public void Bind() + { + if (_dummyFrameBuffer == 0) + { + _dummyFrameBuffer = GL.GenFramebuffer(); + } + + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _dummyFrameBuffer); + + ImageHandler cachedImage; + + for (int attachment = 0; attachment < RenderTargetsCount; attachment++) + { + long key = _attachments.Colors[attachment]; + + int handle = 0; + + if (key != 0 && _texture.TryGetImageHandler(key, out cachedImage)) + { + handle = cachedImage.Handle; + } + + if (handle == _colorHandles[attachment]) + { + continue; + } + + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.ColorAttachment0 + attachment, + handle, + 0); + + _colorHandles[attachment] = handle; + } + + if (_attachments.Zeta != 0 && _texture.TryGetImageHandler(_attachments.Zeta, out cachedImage)) + { + if (cachedImage.Handle != _zetaHandle) + { + if (cachedImage.HasDepth && cachedImage.HasStencil) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthStencilAttachment, + cachedImage.Handle, + 0); + } + else if (cachedImage.HasDepth) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthAttachment, + cachedImage.Handle, + 0); + + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.StencilAttachment, + 0, + 0); + } + else + { + throw new InvalidOperationException("Invalid image format \"" + cachedImage.Format + "\" used as Zeta!"); + } + + _zetaHandle = cachedImage.Handle; + } + } + else if (_zetaHandle != 0) + { + GL.FramebufferTexture( + FramebufferTarget.DrawFramebuffer, + FramebufferAttachment.DepthStencilAttachment, + 0, + 0); + + _zetaHandle = 0; + } + + if (OglExtension.ViewportArray) + { + GL.ViewportArray(0, RenderTargetsCount, _viewports); + } + else + { + GL.Viewport( + (int)_viewports[0], + (int)_viewports[1], + (int)_viewports[2], + (int)_viewports[3]); + } + + if (_attachments.MapCount > 1) + { + GL.DrawBuffers(_attachments.MapCount, _attachments.Map); + } + else if (_attachments.MapCount == 1) + { + GL.DrawBuffer((DrawBufferMode)_attachments.Map[0]); + } + else + { + GL.DrawBuffer(DrawBufferMode.None); + } + + _oldAttachments.Update(_attachments); + } + + public void BindColor(long key, int attachment) + { + _attachments.Colors[attachment] = key; + } + + public void UnbindColor(int attachment) + { + _attachments.Colors[attachment] = 0; + } + + public void BindZeta(long key) + { + _attachments.Zeta = key; + } + + public void UnbindZeta() + { + _attachments.Zeta = 0; + } + + public void Present(long key) + { + _texture.TryGetImageHandler(key, out _readTex); + } + + public void SetMap(int[] map) + { + if (map != null) + { + _attachments.MapCount = map.Length; + + for (int attachment = 0; attachment < _attachments.MapCount; attachment++) + { + _attachments.Map[attachment] = DrawBuffersEnum.ColorAttachment0 + map[attachment]; + } + } + else + { + _attachments.MapCount = 0; + } + } + + public void SetTransform(bool flipX, bool flipY, int top, int left, int right, int bottom) + { + _flipX = flipX; + _flipY = flipY; + + _cropTop = top; + _cropLeft = left; + _cropRight = right; + _cropBottom = bottom; + } + + public void SetWindowSize(int width, int height) + { + _window = new Rect(0, 0, width, height); + } + + public void SetViewport(int attachment, int x, int y, int width, int height) + { + int offset = attachment * 4; + + _viewports[offset + 0] = x; + _viewports[offset + 1] = y; + _viewports[offset + 2] = width; + _viewports[offset + 3] = height; + } + + public void Render() + { + if (_readTex == null) + { + return; + } + + int srcX0, srcX1, srcY0, srcY1; + + if (_cropLeft == 0 && _cropRight == 0) + { + srcX0 = 0; + srcX1 = _readTex.Width; + } + else + { + srcX0 = _cropLeft; + srcX1 = _cropRight; + } + + if (_cropTop == 0 && _cropBottom == 0) + { + srcY0 = 0; + srcY1 = _readTex.Height; + } + else + { + srcY0 = _cropTop; + srcY1 = _cropBottom; + } + + float ratioX = MathF.Min(1f, (_window.Height * (float)NativeWidth) / ((float)NativeHeight * _window.Width)); + float ratioY = MathF.Min(1f, (_window.Width * (float)NativeHeight) / ((float)NativeWidth * _window.Height)); + + int dstWidth = (int)(_window.Width * ratioX); + int dstHeight = (int)(_window.Height * ratioY); + + int dstPaddingX = (_window.Width - dstWidth) / 2; + int dstPaddingY = (_window.Height - dstHeight) / 2; + + int dstX0 = _flipX ? _window.Width - dstPaddingX : dstPaddingX; + int dstX1 = _flipX ? dstPaddingX : _window.Width - dstPaddingX; + + int dstY0 = _flipY ? dstPaddingY : _window.Height - dstPaddingY; + int dstY1 = _flipY ? _window.Height - dstPaddingY : dstPaddingY; + + GL.Viewport(0, 0, _window.Width, _window.Height); + + if (_srcFb == 0) + { + _srcFb = GL.GenFramebuffer(); + } + + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _srcFb); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, 0); + + GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, _readTex.Handle, 0); + + GL.ReadBuffer(ReadBufferMode.ColorAttachment0); + + GL.Clear(ClearBufferMask.ColorBufferBit); + + GL.Disable(EnableCap.FramebufferSrgb); + + GL.BlitFramebuffer( + srcX0, + srcY0, + srcX1, + srcY1, + dstX0, + dstY0, + dstX1, + dstY1, + ClearBufferMask.ColorBufferBit, + BlitFramebufferFilter.Linear); + + if (FramebufferSrgb) + { + GL.Enable(EnableCap.FramebufferSrgb); + } + } + + public void Copy( + GalImage srcImage, + GalImage dstImage, + long srcKey, + long dstKey, + int srcLayer, + int dstLayer, + int srcX0, + int srcY0, + int srcX1, + int srcY1, + int dstX0, + int dstY0, + int dstX1, + int dstY1) + { + if (_texture.TryGetImageHandler(srcKey, out ImageHandler srcTex) && + _texture.TryGetImageHandler(dstKey, out ImageHandler dstTex)) + { + if (srcTex.HasColor != dstTex.HasColor || + srcTex.HasDepth != dstTex.HasDepth || + srcTex.HasStencil != dstTex.HasStencil) + { + throw new NotImplementedException(); + } + + if (_srcFb == 0) + { + _srcFb = GL.GenFramebuffer(); + } + + if (_dstFb == 0) + { + _dstFb = GL.GenFramebuffer(); + } + + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _srcFb); + GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _dstFb); + + FramebufferAttachment attachment = GetAttachment(srcTex); + + if (ImageUtils.IsArray(srcImage.TextureTarget) && srcLayer > 0) + { + GL.FramebufferTextureLayer(FramebufferTarget.ReadFramebuffer, attachment, srcTex.Handle, 0, srcLayer); + } + else + { + GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, attachment, srcTex.Handle, 0); + } + + if (ImageUtils.IsArray(dstImage.TextureTarget) && dstLayer > 0) + { + GL.FramebufferTextureLayer(FramebufferTarget.DrawFramebuffer, attachment, dstTex.Handle, 0, dstLayer); + } + else + { + GL.FramebufferTexture(FramebufferTarget.DrawFramebuffer, attachment, dstTex.Handle, 0); + } + + + BlitFramebufferFilter filter = BlitFramebufferFilter.Nearest; + + if (srcTex.HasColor) + { + GL.DrawBuffer(DrawBufferMode.ColorAttachment0); + + filter = BlitFramebufferFilter.Linear; + } + + ClearBufferMask mask = GetClearMask(srcTex); + + GL.BlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); + } + } + + public void Reinterpret(long key, GalImage newImage) + { + if (!_texture.TryGetImage(key, out GalImage oldImage)) + { + return; + } + + if (newImage.Format == oldImage.Format && + newImage.Width == oldImage.Width && + newImage.Height == oldImage.Height && + newImage.Depth == oldImage.Depth && + newImage.LayerCount == oldImage.LayerCount && + newImage.TextureTarget == oldImage.TextureTarget) + { + return; + } + + if (_copyPbo == 0) + { + _copyPbo = GL.GenBuffer(); + } + + GL.BindBuffer(BufferTarget.PixelPackBuffer, _copyPbo); + + //The buffer should be large enough to hold the largest texture. + int bufferSize = Math.Max(ImageUtils.GetSize(oldImage), + ImageUtils.GetSize(newImage)); + + GL.BufferData(BufferTarget.PixelPackBuffer, bufferSize, IntPtr.Zero, BufferUsageHint.StreamCopy); + + if (!_texture.TryGetImageHandler(key, out ImageHandler cachedImage)) + { + throw new InvalidOperationException(); + } + + (_, PixelFormat format, PixelType type) = OglEnumConverter.GetImageFormat(cachedImage.Format); + + TextureTarget target = ImageUtils.GetTextureTarget(newImage.TextureTarget); + + GL.BindTexture(target, cachedImage.Handle); + + GL.GetTexImage(target, 0, format, type, IntPtr.Zero); + + GL.BindBuffer(BufferTarget.PixelPackBuffer, 0); + GL.BindBuffer(BufferTarget.PixelUnpackBuffer, _copyPbo); + + GL.PixelStore(PixelStoreParameter.UnpackRowLength, oldImage.Width); + + _texture.Create(key, ImageUtils.GetSize(newImage), newImage); + + GL.PixelStore(PixelStoreParameter.UnpackRowLength, 0); + + GL.BindBuffer(BufferTarget.PixelUnpackBuffer, 0); + } + + private static FramebufferAttachment GetAttachment(ImageHandler cachedImage) + { + if (cachedImage.HasColor) + { + return FramebufferAttachment.ColorAttachment0; + } + else if (cachedImage.HasDepth && cachedImage.HasStencil) + { + return FramebufferAttachment.DepthStencilAttachment; + } + else if (cachedImage.HasDepth) + { + return FramebufferAttachment.DepthAttachment; + } + else if (cachedImage.HasStencil) + { + return FramebufferAttachment.StencilAttachment; + } + else + { + throw new InvalidOperationException(); + } + } + + private static ClearBufferMask GetClearMask(ImageHandler cachedImage) + { + return (cachedImage.HasColor ? ClearBufferMask.ColorBufferBit : 0) | + (cachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) | + (cachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs new file mode 100644 index 0000000000..1ff8c7ad5d --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglRenderer.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Concurrent; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + public class OglRenderer : IGalRenderer + { + public IGalConstBuffer Buffer { get; private set; } + + public IGalRenderTarget RenderTarget { get; private set; } + + public IGalRasterizer Rasterizer { get; private set; } + + public IGalShader Shader { get; private set; } + + public IGalPipeline Pipeline { get; private set; } + + public IGalTexture Texture { get; private set; } + + private ConcurrentQueue _actionsQueue; + + public OglRenderer() + { + Buffer = new OglConstBuffer(); + + Texture = new OglTexture(); + + RenderTarget = new OglRenderTarget(Texture as OglTexture); + + Rasterizer = new OglRasterizer(); + + Shader = new OglShader(Buffer as OglConstBuffer); + + Pipeline = new OglPipeline( + Buffer as OglConstBuffer, + RenderTarget as OglRenderTarget, + Rasterizer as OglRasterizer, + Shader as OglShader); + + _actionsQueue = new ConcurrentQueue(); + } + + public void QueueAction(Action actionMthd) + { + _actionsQueue.Enqueue(actionMthd); + } + + public void RunActions() + { + int count = _actionsQueue.Count; + + while (count-- > 0 && _actionsQueue.TryDequeue(out Action renderAction)) + { + renderAction(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs new file mode 100644 index 0000000000..8faa90537e --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs @@ -0,0 +1,298 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Gal.Shader; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OglShader : IGalShader + { + public const int ReservedCbufCount = 1; + + private const int ExtraDataSize = 4; + + public OglShaderProgram Current; + + private ConcurrentDictionary _stages; + + private Dictionary _programs; + + public int CurrentProgramHandle { get; private set; } + + private OglConstBuffer _buffer; + + private int _extraUboHandle; + + public OglShader(OglConstBuffer buffer) + { + _buffer = buffer; + + _stages = new ConcurrentDictionary(); + + _programs = new Dictionary(); + } + + public void Create(IGalMemory memory, long key, GalShaderType type) + { + _stages.GetOrAdd(key, (stage) => ShaderStageFactory(memory, key, 0, false, type)); + } + + public void Create(IGalMemory memory, long vpAPos, long key, GalShaderType type) + { + _stages.GetOrAdd(key, (stage) => ShaderStageFactory(memory, vpAPos, key, true, type)); + } + + private OglShaderStage ShaderStageFactory( + IGalMemory memory, + long position, + long positionB, + bool isDualVp, + GalShaderType type) + { + GlslProgram program; + + GlslDecompiler decompiler = new GlslDecompiler(OglLimit.MaxUboSize, OglExtension.NvidiaDriver); + + int shaderDumpIndex = ShaderDumper.DumpIndex; + + if (isDualVp) + { + ShaderDumper.Dump(memory, position, type, "a"); + ShaderDumper.Dump(memory, positionB, type, "b"); + + program = decompiler.Decompile(memory, position, positionB, type); + } + else + { + ShaderDumper.Dump(memory, position, type); + + program = decompiler.Decompile(memory, position, type); + } + + string code = program.Code; + + if (ShaderDumper.IsDumpEnabled()) + { + code = "//Shader " + shaderDumpIndex + Environment.NewLine + code; + } + + return new OglShaderStage(type, code, program.Uniforms, program.Textures); + } + + public IEnumerable GetConstBufferUsage(long key) + { + if (_stages.TryGetValue(key, out OglShaderStage stage)) + { + return stage.ConstBufferUsage; + } + + return Enumerable.Empty(); + } + + public IEnumerable GetTextureUsage(long key) + { + if (_stages.TryGetValue(key, out OglShaderStage stage)) + { + return stage.TextureUsage; + } + + return Enumerable.Empty(); + } + + public unsafe void SetExtraData(float flipX, float flipY, int instance) + { + BindProgram(); + + EnsureExtraBlock(); + + GL.BindBuffer(BufferTarget.UniformBuffer, _extraUboHandle); + + float* data = stackalloc float[ExtraDataSize]; + data[0] = flipX; + data[1] = flipY; + data[2] = BitConverter.Int32BitsToSingle(instance); + + //Invalidate buffer + GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw); + + GL.BufferSubData(BufferTarget.UniformBuffer, IntPtr.Zero, ExtraDataSize * sizeof(float), (IntPtr)data); + } + + public void Bind(long key) + { + if (_stages.TryGetValue(key, out OglShaderStage stage)) + { + Bind(stage); + } + } + + private void Bind(OglShaderStage stage) + { + if (stage.Type == GalShaderType.Geometry) + { + //Enhanced layouts are required for Geometry shaders + //skip this stage if current driver has no ARB_enhanced_layouts + if (!OglExtension.EnhancedLayouts) + { + return; + } + } + + switch (stage.Type) + { + case GalShaderType.Vertex: Current.Vertex = stage; break; + case GalShaderType.TessControl: Current.TessControl = stage; break; + case GalShaderType.TessEvaluation: Current.TessEvaluation = stage; break; + case GalShaderType.Geometry: Current.Geometry = stage; break; + case GalShaderType.Fragment: Current.Fragment = stage; break; + } + } + + public void Unbind(GalShaderType type) + { + switch (type) + { + case GalShaderType.Vertex: Current.Vertex = null; break; + case GalShaderType.TessControl: Current.TessControl = null; break; + case GalShaderType.TessEvaluation: Current.TessEvaluation = null; break; + case GalShaderType.Geometry: Current.Geometry = null; break; + case GalShaderType.Fragment: Current.Fragment = null; break; + } + } + + public void BindProgram() + { + if (Current.Vertex == null || + Current.Fragment == null) + { + return; + } + + if (!_programs.TryGetValue(Current, out int handle)) + { + handle = GL.CreateProgram(); + + AttachIfNotNull(handle, Current.Vertex); + AttachIfNotNull(handle, Current.TessControl); + AttachIfNotNull(handle, Current.TessEvaluation); + AttachIfNotNull(handle, Current.Geometry); + AttachIfNotNull(handle, Current.Fragment); + + GL.LinkProgram(handle); + + CheckProgramLink(handle); + + BindUniformBlocks(handle); + BindTextureLocations(handle); + + _programs.Add(Current, handle); + } + + GL.UseProgram(handle); + + CurrentProgramHandle = handle; + } + + private void EnsureExtraBlock() + { + if (_extraUboHandle == 0) + { + _extraUboHandle = GL.GenBuffer(); + + GL.BindBuffer(BufferTarget.UniformBuffer, _extraUboHandle); + + GL.BufferData(BufferTarget.UniformBuffer, ExtraDataSize * sizeof(float), IntPtr.Zero, BufferUsageHint.StreamDraw); + + GL.BindBufferBase(BufferRangeTarget.UniformBuffer, 0, _extraUboHandle); + } + } + + private void AttachIfNotNull(int programHandle, OglShaderStage stage) + { + if (stage != null) + { + stage.Compile(); + + GL.AttachShader(programHandle, stage.Handle); + } + } + + private void BindUniformBlocks(int programHandle) + { + int extraBlockindex = GL.GetUniformBlockIndex(programHandle, GlslDecl.ExtraUniformBlockName); + + GL.UniformBlockBinding(programHandle, extraBlockindex, 0); + + int freeBinding = ReservedCbufCount; + + void BindUniformBlocksIfNotNull(OglShaderStage stage) + { + if (stage != null) + { + foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage) + { + int blockIndex = GL.GetUniformBlockIndex(programHandle, declInfo.Name); + + if (blockIndex < 0) + { + //It is expected that its found, if it's not then driver might be in a malfunction + throw new InvalidOperationException(); + } + + GL.UniformBlockBinding(programHandle, blockIndex, freeBinding); + + freeBinding++; + } + } + } + + BindUniformBlocksIfNotNull(Current.Vertex); + BindUniformBlocksIfNotNull(Current.TessControl); + BindUniformBlocksIfNotNull(Current.TessEvaluation); + BindUniformBlocksIfNotNull(Current.Geometry); + BindUniformBlocksIfNotNull(Current.Fragment); + } + + private void BindTextureLocations(int programHandle) + { + int index = 0; + + void BindTexturesIfNotNull(OglShaderStage stage) + { + if (stage != null) + { + foreach (ShaderDeclInfo decl in stage.TextureUsage) + { + int location = GL.GetUniformLocation(programHandle, decl.Name); + + GL.Uniform1(location, index); + + index++; + } + } + } + + GL.UseProgram(programHandle); + + BindTexturesIfNotNull(Current.Vertex); + BindTexturesIfNotNull(Current.TessControl); + BindTexturesIfNotNull(Current.TessEvaluation); + BindTexturesIfNotNull(Current.Geometry); + BindTexturesIfNotNull(Current.Fragment); + } + + private static void CheckProgramLink(int handle) + { + int status = 0; + + GL.GetProgram(handle, GetProgramParameterName.LinkStatus, out status); + + if (status == 0) + { + throw new ShaderException(GL.GetProgramInfoLog(handle)); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs b/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs new file mode 100644 index 0000000000..9e68a8e6dc --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs @@ -0,0 +1,86 @@ +using OpenTK.Graphics.OpenGL; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + struct OglShaderProgram + { + public OglShaderStage Vertex; + public OglShaderStage TessControl; + public OglShaderStage TessEvaluation; + public OglShaderStage Geometry; + public OglShaderStage Fragment; + } + + class OglShaderStage : IDisposable + { + public int Handle { get; private set; } + + public bool IsCompiled { get; private set; } + + public GalShaderType Type { get; private set; } + + public string Code { get; private set; } + + public IEnumerable ConstBufferUsage { get; private set; } + public IEnumerable TextureUsage { get; private set; } + + public OglShaderStage( + GalShaderType type, + string code, + IEnumerable constBufferUsage, + IEnumerable textureUsage) + { + Type = type; + Code = code; + ConstBufferUsage = constBufferUsage; + TextureUsage = textureUsage; + } + + public void Compile() + { + if (Handle == 0) + { + Handle = GL.CreateShader(OglEnumConverter.GetShaderType(Type)); + + CompileAndCheck(Handle, Code); + } + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing && Handle != 0) + { + GL.DeleteShader(Handle); + + Handle = 0; + } + } + + public static void CompileAndCheck(int handle, string code) + { + GL.ShaderSource(handle, code); + GL.CompileShader(handle); + + CheckCompilation(handle); + } + + private static void CheckCompilation(int handle) + { + int status = 0; + + GL.GetShader(handle, ShaderParameter.CompileStatus, out status); + + if (status == 0) + { + throw new ShaderException(GL.GetShaderInfoLog(handle)); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLStreamBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OglStreamBuffer.cs similarity index 51% rename from Ryujinx.Graphics/Gal/OpenGL/OGLStreamBuffer.cs rename to Ryujinx.Graphics/Gal/OpenGL/OglStreamBuffer.cs index 411d33aab7..58b3ace5bb 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLStreamBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglStreamBuffer.cs @@ -3,7 +3,7 @@ using System; namespace Ryujinx.Graphics.Gal.OpenGL { - class OGLStreamBuffer : IDisposable + class OglStreamBuffer : IDisposable { public int Handle { get; protected set; } @@ -11,30 +11,30 @@ namespace Ryujinx.Graphics.Gal.OpenGL protected BufferTarget Target { get; private set; } - public OGLStreamBuffer(BufferTarget Target, long Size) + public OglStreamBuffer(BufferTarget target, long size) { - this.Target = Target; - this.Size = Size; + Target = target; + Size = size; Handle = GL.GenBuffer(); - GL.BindBuffer(Target, Handle); + GL.BindBuffer(target, Handle); - GL.BufferData(Target, (IntPtr)Size, IntPtr.Zero, BufferUsageHint.StreamDraw); + GL.BufferData(target, (IntPtr)size, IntPtr.Zero, BufferUsageHint.StreamDraw); } - public void SetData(long Size, IntPtr HostAddress) + public void SetData(long size, IntPtr hostAddress) { GL.BindBuffer(Target, Handle); - GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Size, HostAddress); + GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)size, hostAddress); } - public void SetData(byte[] Data) + public void SetData(byte[] data) { GL.BindBuffer(Target, Handle); - GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)Data.Length, Data); + GL.BufferSubData(Target, IntPtr.Zero, (IntPtr)data.Length, data); } public void Dispose() @@ -42,9 +42,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL Dispose(true); } - protected virtual void Dispose(bool Disposing) + protected virtual void Dispose(bool disposing) { - if (Disposing && Handle != 0) + if (disposing && Handle != 0) { GL.DeleteBuffer(Handle); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs new file mode 100644 index 0000000000..f836702f5e --- /dev/null +++ b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs @@ -0,0 +1,381 @@ +using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Texture; +using System; + +namespace Ryujinx.Graphics.Gal.OpenGL +{ + class OglTexture : IGalTexture + { + private const long MaxTextureCacheSize = 768 * 1024 * 1024; + + private OglCachedResource _textureCache; + + public EventHandler TextureDeleted { get; set; } + + public OglTexture() + { + _textureCache = new OglCachedResource(DeleteTexture, MaxTextureCacheSize); + } + + public void LockCache() + { + _textureCache.Lock(); + } + + public void UnlockCache() + { + _textureCache.Unlock(); + } + + private void DeleteTexture(ImageHandler cachedImage) + { + TextureDeleted?.Invoke(this, cachedImage.Handle); + + GL.DeleteTexture(cachedImage.Handle); + } + + public void Create(long key, int size, GalImage image) + { + int handle = GL.GenTexture(); + + TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget); + + GL.BindTexture(target, handle); + + const int level = 0; //TODO: Support mipmap textures. + const int border = 0; + + _textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)size); + + if (ImageUtils.IsCompressed(image.Format)) + { + throw new InvalidOperationException("Surfaces with compressed formats are not supported!"); + } + + (PixelInternalFormat internalFmt, + PixelFormat format, + PixelType type) = OglEnumConverter.GetImageFormat(image.Format); + + switch (target) + { + case TextureTarget.Texture1D: + GL.TexImage1D( + target, + level, + internalFmt, + image.Width, + border, + format, + type, + IntPtr.Zero); + break; + + case TextureTarget.Texture2D: + GL.TexImage2D( + target, + level, + internalFmt, + image.Width, + image.Height, + border, + format, + type, + IntPtr.Zero); + break; + case TextureTarget.Texture3D: + GL.TexImage3D( + target, + level, + internalFmt, + image.Width, + image.Height, + image.Depth, + border, + format, + type, + IntPtr.Zero); + break; + case TextureTarget.Texture2DArray: + GL.TexImage3D( + target, + level, + internalFmt, + image.Width, + image.Height, + image.LayerCount, + border, + format, + type, + IntPtr.Zero); + break; + default: + throw new NotImplementedException($"Unsupported texture target type: {target}"); + } + } + + public void Create(long key, byte[] data, GalImage image) + { + int handle = GL.GenTexture(); + + TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget); + + GL.BindTexture(target, handle); + + const int level = 0; //TODO: Support mipmap textures. + const int border = 0; + + _textureCache.AddOrUpdate(key, new ImageHandler(handle, image), (uint)data.Length); + + if (ImageUtils.IsCompressed(image.Format) && !IsAstc(image.Format)) + { + InternalFormat internalFmt = OglEnumConverter.GetCompressedImageFormat(image.Format); + + switch (target) + { + case TextureTarget.Texture1D: + GL.CompressedTexImage1D( + target, + level, + internalFmt, + image.Width, + border, + data.Length, + data); + break; + case TextureTarget.Texture2D: + GL.CompressedTexImage2D( + target, + level, + internalFmt, + image.Width, + image.Height, + border, + data.Length, + data); + break; + case TextureTarget.Texture3D: + GL.CompressedTexImage3D( + target, + level, + internalFmt, + image.Width, + image.Height, + image.Depth, + border, + data.Length, + data); + break; + case TextureTarget.Texture2DArray: + GL.CompressedTexImage3D( + target, + level, + internalFmt, + image.Width, + image.Height, + image.LayerCount, + border, + data.Length, + data); + break; + default: + throw new NotImplementedException($"Unsupported texture target type: {target}"); + } + } + else + { + //TODO: Use KHR_texture_compression_astc_hdr when available + if (IsAstc(image.Format)) + { + int textureBlockWidth = ImageUtils.GetBlockWidth(image.Format); + int textureBlockHeight = ImageUtils.GetBlockHeight(image.Format); + int textureBlockDepth = ImageUtils.GetBlockDepth(image.Format); + + data = AstcDecoder.DecodeToRgba8888( + data, + textureBlockWidth, + textureBlockHeight, + textureBlockDepth, + image.Width, + image.Height, + image.Depth); + + image.Format = GalImageFormat.Rgba8 | (image.Format & GalImageFormat.TypeMask); + } + + (PixelInternalFormat internalFmt, + PixelFormat format, + PixelType type) = OglEnumConverter.GetImageFormat(image.Format); + + + switch (target) + { + case TextureTarget.Texture1D: + GL.TexImage1D( + target, + level, + internalFmt, + image.Width, + border, + format, + type, + data); + break; + case TextureTarget.Texture2D: + GL.TexImage2D( + target, + level, + internalFmt, + image.Width, + image.Height, + border, + format, + type, + data); + break; + case TextureTarget.Texture3D: + GL.TexImage3D( + target, + level, + internalFmt, + image.Width, + image.Height, + image.Depth, + border, + format, + type, + data); + break; + case TextureTarget.Texture2DArray: + GL.TexImage3D( + target, + level, + internalFmt, + image.Width, + image.Height, + image.LayerCount, + border, + format, + type, + data); + break; + case TextureTarget.TextureCubeMap: + Span array = new Span(data); + + int faceSize = ImageUtils.GetSize(image) / 6; + + for (int face = 0; face < 6; face++) + { + GL.TexImage2D( + TextureTarget.TextureCubeMapPositiveX + face, + level, + internalFmt, + image.Width, + image.Height, + border, + format, + type, + array.Slice(face * faceSize, faceSize).ToArray()); + } + break; + default: + throw new NotImplementedException($"Unsupported texture target type: {target}"); + } + } + } + + private static bool IsAstc(GalImageFormat format) + { + format &= GalImageFormat.FormatMask; + + return format > GalImageFormat.Astc2DStart && format < GalImageFormat.Astc2DEnd; + } + + public bool TryGetImage(long key, out GalImage image) + { + if (_textureCache.TryGetValue(key, out ImageHandler cachedImage)) + { + image = cachedImage.Image; + + return true; + } + + image = default(GalImage); + + return false; + } + + public bool TryGetImageHandler(long key, out ImageHandler cachedImage) + { + if (_textureCache.TryGetValue(key, out cachedImage)) + { + return true; + } + + cachedImage = null; + + return false; + } + + public void Bind(long key, int index, GalImage image) + { + if (_textureCache.TryGetValue(key, out ImageHandler cachedImage)) + { + GL.ActiveTexture(TextureUnit.Texture0 + index); + + TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget); + + GL.BindTexture(target, cachedImage.Handle); + + int[] swizzleRgba = new int[] + { + (int)OglEnumConverter.GetTextureSwizzle(image.XSource), + (int)OglEnumConverter.GetTextureSwizzle(image.YSource), + (int)OglEnumConverter.GetTextureSwizzle(image.ZSource), + (int)OglEnumConverter.GetTextureSwizzle(image.WSource) + }; + + GL.TexParameter(target, TextureParameterName.TextureSwizzleRgba, swizzleRgba); + } + } + + public void SetSampler(GalImage image, GalTextureSampler sampler) + { + int wrapS = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressU); + int wrapT = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressV); + int wrapR = (int)OglEnumConverter.GetTextureWrapMode(sampler.AddressP); + + int minFilter = (int)OglEnumConverter.GetTextureMinFilter(sampler.MinFilter, sampler.MipFilter); + int magFilter = (int)OglEnumConverter.GetTextureMagFilter(sampler.MagFilter); + + TextureTarget target = ImageUtils.GetTextureTarget(image.TextureTarget); + + GL.TexParameter(target, TextureParameterName.TextureWrapS, wrapS); + GL.TexParameter(target, TextureParameterName.TextureWrapT, wrapT); + GL.TexParameter(target, TextureParameterName.TextureWrapR, wrapR); + + GL.TexParameter(target, TextureParameterName.TextureMinFilter, minFilter); + GL.TexParameter(target, TextureParameterName.TextureMagFilter, magFilter); + + float[] color = new float[] + { + sampler.BorderColor.Red, + sampler.BorderColor.Green, + sampler.BorderColor.Blue, + sampler.BorderColor.Alpha + }; + + GL.TexParameter(target, TextureParameterName.TextureBorderColor, color); + + if (sampler.DepthCompare) + { + GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.CompareRToTexture); + GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)OglEnumConverter.GetDepthCompareFunc(sampler.DepthCompareFunc)); + } + else + { + GL.TexParameter(target, TextureParameterName.TextureCompareMode, (int)All.None); + GL.TexParameter(target, TextureParameterName.TextureCompareFunc, (int)All.Never); + } + } + } +} diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs index f7ae34faa5..734267625c 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs @@ -1,4 +1,3 @@ -using Ryujinx.Graphics.Gal.OpenGL; using Ryujinx.Graphics.Texture; using System; using System.Collections.Generic; @@ -51,9 +50,9 @@ namespace Ryujinx.Graphics.Gal.Shader public const string SsyStackName = "ssy_stack"; public const string SsyCursorName = "ssy_cursor"; - private string[] StagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" }; + private string[] _stagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" }; - private string StagePrefix; + private string _stagePrefix; private Dictionary m_CbTextures; @@ -83,9 +82,9 @@ namespace Ryujinx.Graphics.Gal.Shader public GalShaderType ShaderType { get; private set; } - private GlslDecl(GalShaderType ShaderType) + private GlslDecl(GalShaderType shaderType) { - this.ShaderType = ShaderType; + ShaderType = shaderType; m_CbTextures = new Dictionary(); @@ -101,187 +100,187 @@ namespace Ryujinx.Graphics.Gal.Shader m_Preds = new Dictionary(); } - public GlslDecl(ShaderIrBlock[] Blocks, GalShaderType ShaderType, ShaderHeader Header) : this(ShaderType) + public GlslDecl(ShaderIrBlock[] blocks, GalShaderType shaderType, ShaderHeader header) : this(shaderType) { - StagePrefix = StagePrefixes[(int)ShaderType] + "_"; + _stagePrefix = _stagePrefixes[(int)shaderType] + "_"; - if (ShaderType == GalShaderType.Fragment) + if (shaderType == GalShaderType.Fragment) { - int Index = 0; + int index = 0; - for (int Attachment = 0; Attachment < 8; Attachment++) + for (int attachment = 0; attachment < 8; attachment++) { - for (int Component = 0; Component < 4; Component++) + for (int component = 0; component < 4; component++) { - if (Header.OmapTargets[Attachment].ComponentEnabled(Component)) + if (header.OmapTargets[attachment].ComponentEnabled(component)) { - m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index)); + m_Gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index)); - Index++; + index++; } } } - if (Header.OmapDepth) + if (header.OmapDepth) { - Index = Header.DepthRegister; + index = header.DepthRegister; - m_Gprs.TryAdd(Index, new ShaderDeclInfo(GetGprName(Index), Index)); + m_Gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index)); } } - foreach (ShaderIrBlock Block in Blocks) + foreach (ShaderIrBlock block in blocks) { - ShaderIrNode[] Nodes = Block.GetNodes(); + ShaderIrNode[] nodes = block.GetNodes(); - foreach (ShaderIrNode Node in Nodes) + foreach (ShaderIrNode node in nodes) { - Traverse(Nodes, null, Node); + Traverse(nodes, null, node); } } } - public static GlslDecl Merge(GlslDecl VpA, GlslDecl VpB) + public static GlslDecl Merge(GlslDecl vpA, GlslDecl vpB) { - GlslDecl Combined = new GlslDecl(GalShaderType.Vertex); + GlslDecl combined = new GlslDecl(GalShaderType.Vertex); - Merge(Combined.m_Textures, VpA.m_Textures, VpB.m_Textures); - Merge(Combined.m_Uniforms, VpA.m_Uniforms, VpB.m_Uniforms); + Merge(combined.m_Textures, vpA.m_Textures, vpB.m_Textures); + Merge(combined.m_Uniforms, vpA.m_Uniforms, vpB.m_Uniforms); - Merge(Combined.m_Attributes, VpA.m_Attributes, VpB.m_Attributes); - Merge(Combined.m_OutAttributes, VpA.m_OutAttributes, VpB.m_OutAttributes); + Merge(combined.m_Attributes, vpA.m_Attributes, vpB.m_Attributes); + Merge(combined.m_OutAttributes, vpA.m_OutAttributes, vpB.m_OutAttributes); - Merge(Combined.m_Gprs, VpA.m_Gprs, VpB.m_Gprs); - Merge(Combined.m_GprsHalf, VpA.m_GprsHalf, VpB.m_GprsHalf); - Merge(Combined.m_Preds, VpA.m_Preds, VpB.m_Preds); + Merge(combined.m_Gprs, vpA.m_Gprs, vpB.m_Gprs); + Merge(combined.m_GprsHalf, vpA.m_GprsHalf, vpB.m_GprsHalf); + Merge(combined.m_Preds, vpA.m_Preds, vpB.m_Preds); //Merge input attributes. - foreach (KeyValuePair KV in VpA.m_InAttributes) + foreach (KeyValuePair kv in vpA.m_InAttributes) { - Combined.m_InAttributes.TryAdd(KV.Key, KV.Value); + combined.m_InAttributes.TryAdd(kv.Key, kv.Value); } - foreach (KeyValuePair KV in VpB.m_InAttributes) + foreach (KeyValuePair kv in vpB.m_InAttributes) { //If Vertex Program A already writes to this attribute, //then we don't need to add it as an input attribute since //Vertex Program A will already have written to it anyway, //and there's no guarantee that there is an input attribute //for this slot. - if (!VpA.m_OutAttributes.ContainsKey(KV.Key)) + if (!vpA.m_OutAttributes.ContainsKey(kv.Key)) { - Combined.m_InAttributes.TryAdd(KV.Key, KV.Value); + combined.m_InAttributes.TryAdd(kv.Key, kv.Value); } } - return Combined; + return combined; } - public static string GetGprName(int Index) + public static string GetGprName(int index) { - return GprName + Index; + return GprName + index; } private static void Merge( - Dictionary C, - Dictionary A, - Dictionary B) + Dictionary c, + Dictionary a, + Dictionary b) { - foreach (KeyValuePair KV in A) + foreach (KeyValuePair kv in a) { - C.TryAdd(KV.Key, KV.Value); + c.TryAdd(kv.Key, kv.Value); } - foreach (KeyValuePair KV in B) + foreach (KeyValuePair kv in b) { - C.TryAdd(KV.Key, KV.Value); + c.TryAdd(kv.Key, kv.Value); } } - private void Traverse(ShaderIrNode[] Nodes, ShaderIrNode Parent, ShaderIrNode Node) + private void Traverse(ShaderIrNode[] nodes, ShaderIrNode parent, ShaderIrNode node) { - switch (Node) + switch (node) { - case ShaderIrAsg Asg: + case ShaderIrAsg asg: { - Traverse(Nodes, Asg, Asg.Dst); - Traverse(Nodes, Asg, Asg.Src); + Traverse(nodes, asg, asg.Dst); + Traverse(nodes, asg, asg.Src); break; } - case ShaderIrCond Cond: + case ShaderIrCond cond: { - Traverse(Nodes, Cond, Cond.Pred); - Traverse(Nodes, Cond, Cond.Child); + Traverse(nodes, cond, cond.Pred); + Traverse(nodes, cond, cond.Child); break; } - case ShaderIrOp Op: + case ShaderIrOp op: { - Traverse(Nodes, Op, Op.OperandA); - Traverse(Nodes, Op, Op.OperandB); - Traverse(Nodes, Op, Op.OperandC); + Traverse(nodes, op, op.OperandA); + Traverse(nodes, op, op.OperandB); + Traverse(nodes, op, op.OperandC); - if (Op.Inst == ShaderIrInst.Texq || - Op.Inst == ShaderIrInst.Texs || - Op.Inst == ShaderIrInst.Tld4 || - Op.Inst == ShaderIrInst.Txlf) + if (op.Inst == ShaderIrInst.Texq || + op.Inst == ShaderIrInst.Texs || + op.Inst == ShaderIrInst.Tld4 || + op.Inst == ShaderIrInst.Txlf) { - int Handle = ((ShaderIrOperImm)Op.OperandC).Value; + int handle = ((ShaderIrOperImm)op.OperandC).Value; - int Index = Handle - TexStartIndex; + int index = handle - TexStartIndex; - string Name = StagePrefix + TextureName + Index; + string name = _stagePrefix + TextureName + index; - GalTextureTarget TextureTarget; + GalTextureTarget textureTarget; - TextureInstructionSuffix TextureInstructionSuffix; + TextureInstructionSuffix textureInstructionSuffix; // TODO: Non 2D texture type for TEXQ? - if (Op.Inst == ShaderIrInst.Texq) + if (op.Inst == ShaderIrInst.Texq) { - TextureTarget = GalTextureTarget.TwoD; - TextureInstructionSuffix = TextureInstructionSuffix.None; + textureTarget = GalTextureTarget.TwoD; + textureInstructionSuffix = TextureInstructionSuffix.None; } else { - ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData); + ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData); - TextureTarget = Meta.TextureTarget; - TextureInstructionSuffix = Meta.TextureInstructionSuffix; + textureTarget = meta.TextureTarget; + textureInstructionSuffix = meta.TextureInstructionSuffix; } - m_Textures.TryAdd(Handle, new ShaderDeclInfo(Name, Handle, false, 0, 1, TextureTarget, TextureInstructionSuffix)); + m_Textures.TryAdd(handle, new ShaderDeclInfo(name, handle, false, 0, 1, textureTarget, textureInstructionSuffix)); } - else if (Op.Inst == ShaderIrInst.Texb) + else if (op.Inst == ShaderIrInst.Texb) { - ShaderIrNode HandleSrc = null; + ShaderIrNode handleSrc = null; - int Index = Array.IndexOf(Nodes, Parent) - 1; + int index = Array.IndexOf(nodes, parent) - 1; - for (; Index >= 0; Index--) + for (; index >= 0; index--) { - ShaderIrNode Curr = Nodes[Index]; + ShaderIrNode curr = nodes[index]; - if (Curr is ShaderIrAsg Asg && Asg.Dst is ShaderIrOperGpr Gpr) + if (curr is ShaderIrAsg asg && asg.Dst is ShaderIrOperGpr gpr) { - if (Gpr.Index == ((ShaderIrOperGpr)Op.OperandC).Index) + if (gpr.Index == ((ShaderIrOperGpr)op.OperandC).Index) { - HandleSrc = Asg.Src; + handleSrc = asg.Src; break; } } } - if (HandleSrc != null && HandleSrc is ShaderIrOperCbuf Cbuf) + if (handleSrc != null && handleSrc is ShaderIrOperCbuf cbuf) { - ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData); - string Name = StagePrefix + TextureName + "_cb" + Cbuf.Index + "_" + Cbuf.Pos; + ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData); + string name = _stagePrefix + TextureName + "_cb" + cbuf.Index + "_" + cbuf.Pos; - m_CbTextures.Add(Op, new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index, 1, Meta.TextureTarget, Meta.TextureInstructionSuffix)); + m_CbTextures.Add(op, new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index, 1, meta.TextureTarget, meta.TextureInstructionSuffix)); } else { @@ -291,93 +290,93 @@ namespace Ryujinx.Graphics.Gal.Shader break; } - case ShaderIrOperCbuf Cbuf: + case ShaderIrOperCbuf cbuf: { - if (!m_Uniforms.ContainsKey(Cbuf.Index)) + if (!m_Uniforms.ContainsKey(cbuf.Index)) { - string Name = StagePrefix + UniformName + Cbuf.Index; + string name = _stagePrefix + UniformName + cbuf.Index; - ShaderDeclInfo DeclInfo = new ShaderDeclInfo(Name, Cbuf.Pos, true, Cbuf.Index); + ShaderDeclInfo declInfo = new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index); - m_Uniforms.Add(Cbuf.Index, DeclInfo); + m_Uniforms.Add(cbuf.Index, declInfo); } break; } - case ShaderIrOperAbuf Abuf: + case ShaderIrOperAbuf abuf: { //This is a built-in variable. - if (Abuf.Offs == LayerAttr || - Abuf.Offs == PointSizeAttr || - Abuf.Offs == PointCoordAttrX || - Abuf.Offs == PointCoordAttrY || - Abuf.Offs == VertexIdAttr || - Abuf.Offs == InstanceIdAttr || - Abuf.Offs == FaceAttr) + if (abuf.Offs == LayerAttr || + abuf.Offs == PointSizeAttr || + abuf.Offs == PointCoordAttrX || + abuf.Offs == PointCoordAttrY || + abuf.Offs == VertexIdAttr || + abuf.Offs == InstanceIdAttr || + abuf.Offs == FaceAttr) { break; } - int Index = Abuf.Offs >> 4; - int Elem = (Abuf.Offs >> 2) & 3; + int index = abuf.Offs >> 4; + int elem = (abuf.Offs >> 2) & 3; - int GlslIndex = Index - AttrStartIndex; + int glslIndex = index - AttrStartIndex; - if (GlslIndex < 0) + if (glslIndex < 0) { return; } - ShaderDeclInfo DeclInfo; + ShaderDeclInfo declInfo; - if (Parent is ShaderIrAsg Asg && Asg.Dst == Node) + if (parent is ShaderIrAsg asg && asg.Dst == node) { - if (!m_OutAttributes.TryGetValue(Index, out DeclInfo)) + if (!m_OutAttributes.TryGetValue(index, out declInfo)) { - DeclInfo = new ShaderDeclInfo(OutAttrName + GlslIndex, GlslIndex); + declInfo = new ShaderDeclInfo(OutAttrName + glslIndex, glslIndex); - m_OutAttributes.Add(Index, DeclInfo); + m_OutAttributes.Add(index, declInfo); } } else { - if (!m_InAttributes.TryGetValue(Index, out DeclInfo)) + if (!m_InAttributes.TryGetValue(index, out declInfo)) { - DeclInfo = new ShaderDeclInfo(InAttrName + GlslIndex, GlslIndex); + declInfo = new ShaderDeclInfo(InAttrName + glslIndex, glslIndex); - m_InAttributes.Add(Index, DeclInfo); + m_InAttributes.Add(index, declInfo); } } - DeclInfo.Enlarge(Elem + 1); + declInfo.Enlarge(elem + 1); - if (!m_Attributes.ContainsKey(Index)) + if (!m_Attributes.ContainsKey(index)) { - DeclInfo = new ShaderDeclInfo(AttrName + GlslIndex, GlslIndex, false, 0, 4); + declInfo = new ShaderDeclInfo(AttrName + glslIndex, glslIndex, false, 0, 4); - m_Attributes.Add(Index, DeclInfo); + m_Attributes.Add(index, declInfo); } - Traverse(Nodes, Abuf, Abuf.Vertex); + Traverse(nodes, abuf, abuf.Vertex); break; } - case ShaderIrOperGpr Gpr: + case ShaderIrOperGpr gpr: { - if (!Gpr.IsConst) + if (!gpr.IsConst) { - string Name = GetGprName(Gpr.Index); + string name = GetGprName(gpr.Index); - if (Gpr.RegisterSize == ShaderRegisterSize.Single) + if (gpr.RegisterSize == ShaderRegisterSize.Single) { - m_Gprs.TryAdd(Gpr.Index, new ShaderDeclInfo(Name, Gpr.Index)); + m_Gprs.TryAdd(gpr.Index, new ShaderDeclInfo(name, gpr.Index)); } - else if (Gpr.RegisterSize == ShaderRegisterSize.Half) + else if (gpr.RegisterSize == ShaderRegisterSize.Half) { - Name += "_h" + Gpr.HalfPart; + name += "_h" + gpr.HalfPart; - m_GprsHalf.TryAdd((Gpr.Index << 1) | Gpr.HalfPart, new ShaderDeclInfo(Name, Gpr.Index)); + m_GprsHalf.TryAdd((gpr.Index << 1) | gpr.HalfPart, new ShaderDeclInfo(name, gpr.Index)); } else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */ { @@ -387,35 +386,35 @@ namespace Ryujinx.Graphics.Gal.Shader break; } - case ShaderIrOperPred Pred: + case ShaderIrOperPred pred: { - if (!Pred.IsConst && !HasName(m_Preds, Pred.Index)) + if (!pred.IsConst && !HasName(m_Preds, pred.Index)) { - string Name = PredName + Pred.Index; + string name = PredName + pred.Index; - m_Preds.TryAdd(Pred.Index, new ShaderDeclInfo(Name, Pred.Index)); + m_Preds.TryAdd(pred.Index, new ShaderDeclInfo(name, pred.Index)); } break; } } } - private bool HasName(Dictionary Decls, int Index) + private bool HasName(Dictionary decls, int index) { //This is used to check if the dictionary already contains //a entry for a vector at a given index position. //Used to enable turning gprs into vectors. - int VecIndex = Index & ~3; + int vecIndex = index & ~3; - if (Decls.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo)) + if (decls.TryGetValue(vecIndex, out ShaderDeclInfo declInfo)) { - if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size) + if (declInfo.Size > 1 && index < vecIndex + declInfo.Size) { return true; } } - return Decls.ContainsKey(Index); + return decls.ContainsKey(index); } } } diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 5f809525f9..228a901851 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -10,9 +10,9 @@ namespace Ryujinx.Graphics.Gal.Shader { public class GlslDecompiler { - private delegate string GetInstExpr(ShaderIrOp Op); + private delegate string GetInstExpr(ShaderIrOp op); - private Dictionary InstsExpr; + private Dictionary _instsExpr; private enum OperType { @@ -25,21 +25,21 @@ namespace Ryujinx.Graphics.Gal.Shader private const int MaxVertexInput = 3; - private GlslDecl Decl; + private GlslDecl _decl; - private ShaderHeader Header, HeaderB; + private ShaderHeader _header, _headerB; - private ShaderIrBlock[] Blocks, BlocksB; + private ShaderIrBlock[] _blocks, _blocksB; - private StringBuilder SB; + private StringBuilder _sb; public int MaxUboSize { get; } - private bool IsNvidiaDriver; + private bool _isNvidiaDriver; - public GlslDecompiler(int MaxUboSize, bool IsNvidiaDriver) + public GlslDecompiler(int maxUboSize, bool isNvidiaDriver) { - InstsExpr = new Dictionary() + _instsExpr = new Dictionary() { { ShaderIrInst.Abs, GetAbsExpr }, { ShaderIrInst.Add, GetAddExpr }, @@ -114,48 +114,48 @@ namespace Ryujinx.Graphics.Gal.Shader { ShaderIrInst.Xor, GetXorExpr } }; - this.MaxUboSize = MaxUboSize / 16; - this.IsNvidiaDriver = IsNvidiaDriver; + MaxUboSize = maxUboSize / 16; + _isNvidiaDriver = isNvidiaDriver; } public GlslProgram Decompile( - IGalMemory Memory, - long VpAPosition, - long VpBPosition, - GalShaderType ShaderType) + IGalMemory memory, + long vpAPosition, + long vpBPosition, + GalShaderType shaderType) { - Header = new ShaderHeader(Memory, VpAPosition); - HeaderB = new ShaderHeader(Memory, VpBPosition); + _header = new ShaderHeader(memory, vpAPosition); + _headerB = new ShaderHeader(memory, vpBPosition); - Blocks = ShaderDecoder.Decode(Memory, VpAPosition); - BlocksB = ShaderDecoder.Decode(Memory, VpBPosition); + _blocks = ShaderDecoder.Decode(memory, vpAPosition); + _blocksB = ShaderDecoder.Decode(memory, vpBPosition); - GlslDecl DeclVpA = new GlslDecl(Blocks, ShaderType, Header); - GlslDecl DeclVpB = new GlslDecl(BlocksB, ShaderType, HeaderB); + GlslDecl declVpA = new GlslDecl(_blocks, shaderType, _header); + GlslDecl declVpB = new GlslDecl(_blocksB, shaderType, _headerB); - Decl = GlslDecl.Merge(DeclVpA, DeclVpB); + _decl = GlslDecl.Merge(declVpA, declVpB); return Decompile(); } - public GlslProgram Decompile(IGalMemory Memory, long Position, GalShaderType ShaderType) + public GlslProgram Decompile(IGalMemory memory, long position, GalShaderType shaderType) { - Header = new ShaderHeader(Memory, Position); - HeaderB = null; + _header = new ShaderHeader(memory, position); + _headerB = null; - Blocks = ShaderDecoder.Decode(Memory, Position); - BlocksB = null; + _blocks = ShaderDecoder.Decode(memory, position); + _blocksB = null; - Decl = new GlslDecl(Blocks, ShaderType, Header); + _decl = new GlslDecl(_blocks, shaderType, _header); return Decompile(); } private GlslProgram Decompile() { - SB = new StringBuilder(); + _sb = new StringBuilder(); - SB.AppendLine("#version 410 core"); + _sb.AppendLine("#version 410 core"); PrintDeclHeader(); PrintDeclTextures(); @@ -167,599 +167,599 @@ namespace Ryujinx.Graphics.Gal.Shader PrintDeclPreds(); PrintDeclSsy(); - if (BlocksB != null) + if (_blocksB != null) { - PrintBlockScope(Blocks, GlslDecl.BasicBlockAName); + PrintBlockScope(_blocks, GlslDecl.BasicBlockAName); - SB.AppendLine(); + _sb.AppendLine(); - PrintBlockScope(BlocksB, GlslDecl.BasicBlockBName); + PrintBlockScope(_blocksB, GlslDecl.BasicBlockBName); } else { - PrintBlockScope(Blocks, GlslDecl.BasicBlockName); + PrintBlockScope(_blocks, GlslDecl.BasicBlockName); } - SB.AppendLine(); + _sb.AppendLine(); PrintMain(); - string GlslCode = SB.ToString(); + string glslCode = _sb.ToString(); - List TextureInfo = new List(); + List textureInfo = new List(); - TextureInfo.AddRange(Decl.Textures.Values); - TextureInfo.AddRange(IterateCbTextures()); + textureInfo.AddRange(_decl.Textures.Values); + textureInfo.AddRange(IterateCbTextures()); - return new GlslProgram(GlslCode, TextureInfo, Decl.Uniforms.Values); + return new GlslProgram(glslCode, textureInfo, _decl.Uniforms.Values); } private void PrintDeclHeader() { - if (Decl.ShaderType == GalShaderType.Geometry) + if (_decl.ShaderType == GalShaderType.Geometry) { - int MaxVertices = Header.MaxOutputVertexCount; + int maxVertices = _header.MaxOutputVertexCount; - string OutputTopology; + string outputTopology; - switch (Header.OutputTopology) + switch (_header.OutputTopology) { - case ShaderHeader.PointList: OutputTopology = "points"; break; - case ShaderHeader.LineStrip: OutputTopology = "line_strip"; break; - case ShaderHeader.TriangleStrip: OutputTopology = "triangle_strip"; break; + case ShaderHeader.PointList: outputTopology = "points"; break; + case ShaderHeader.LineStrip: outputTopology = "line_strip"; break; + case ShaderHeader.TriangleStrip: outputTopology = "triangle_strip"; break; default: throw new InvalidOperationException(); } - SB.AppendLine("#extension GL_ARB_enhanced_layouts : require"); + _sb.AppendLine("#extension GL_ARB_enhanced_layouts : require"); - SB.AppendLine(); + _sb.AppendLine(); - SB.AppendLine("// Stubbed. Maxwell geometry shaders don't inform input geometry type"); + _sb.AppendLine("// Stubbed. Maxwell geometry shaders don't inform input geometry type"); - SB.AppendLine("layout(triangles) in;" + Environment.NewLine); + _sb.AppendLine("layout(triangles) in;" + Environment.NewLine); - SB.AppendLine($"layout({OutputTopology}, max_vertices = {MaxVertices}) out;"); + _sb.AppendLine($"layout({outputTopology}, max_vertices = {maxVertices}) out;"); - SB.AppendLine(); + _sb.AppendLine(); } } - private string GetSamplerType(TextureTarget TextureTarget, bool HasShadow) + private string GetSamplerType(TextureTarget textureTarget, bool hasShadow) { - string Result; + string result; - switch (TextureTarget) + switch (textureTarget) { case TextureTarget.Texture1D: - Result = "sampler1D"; + result = "sampler1D"; break; case TextureTarget.Texture2D: - Result = "sampler2D"; + result = "sampler2D"; break; case TextureTarget.Texture3D: - Result = "sampler3D"; + result = "sampler3D"; break; case TextureTarget.TextureCubeMap: - Result = "samplerCube"; + result = "samplerCube"; break; case TextureTarget.TextureRectangle: - Result = "sampler2DRect"; + result = "sampler2DRect"; break; case TextureTarget.Texture1DArray: - Result = "sampler1DArray"; + result = "sampler1DArray"; break; case TextureTarget.Texture2DArray: - Result = "sampler2DArray"; + result = "sampler2DArray"; break; case TextureTarget.TextureCubeMapArray: - Result = "samplerCubeArray"; + result = "samplerCubeArray"; break; case TextureTarget.TextureBuffer: - Result = "samplerBuffer"; + result = "samplerBuffer"; break; case TextureTarget.Texture2DMultisample: - Result = "sampler2DMS"; + result = "sampler2DMS"; break; case TextureTarget.Texture2DMultisampleArray: - Result = "sampler2DMSArray"; + result = "sampler2DMSArray"; break; default: throw new NotSupportedException(); } - if (HasShadow) - Result += "Shadow"; + if (hasShadow) + result += "Shadow"; - return Result; + return result; } private void PrintDeclTextures() { - foreach (ShaderDeclInfo DeclInfo in IterateCbTextures()) + foreach (ShaderDeclInfo declInfo in IterateCbTextures()) { - TextureTarget Target = ImageUtils.GetTextureTarget(DeclInfo.TextureTarget); - SB.AppendLine($"// {DeclInfo.TextureSuffix}"); - SB.AppendLine("uniform " + GetSamplerType(Target, (DeclInfo.TextureSuffix & TextureInstructionSuffix.DC) != 0) + " " + DeclInfo.Name + ";"); + TextureTarget target = ImageUtils.GetTextureTarget(declInfo.TextureTarget); + _sb.AppendLine($"// {declInfo.TextureSuffix}"); + _sb.AppendLine("uniform " + GetSamplerType(target, (declInfo.TextureSuffix & TextureInstructionSuffix.Dc) != 0) + " " + declInfo.Name + ";"); } - foreach (ShaderDeclInfo DeclInfo in Decl.Textures.Values.OrderBy(DeclKeySelector)) + foreach (ShaderDeclInfo declInfo in _decl.Textures.Values.OrderBy(DeclKeySelector)) { - TextureTarget Target = ImageUtils.GetTextureTarget(DeclInfo.TextureTarget); - SB.AppendLine($"// {DeclInfo.TextureSuffix}"); - SB.AppendLine("uniform " + GetSamplerType(Target, (DeclInfo.TextureSuffix & TextureInstructionSuffix.DC) != 0) + " " + DeclInfo.Name + ";"); + TextureTarget target = ImageUtils.GetTextureTarget(declInfo.TextureTarget); + _sb.AppendLine($"// {declInfo.TextureSuffix}"); + _sb.AppendLine("uniform " + GetSamplerType(target, (declInfo.TextureSuffix & TextureInstructionSuffix.Dc) != 0) + " " + declInfo.Name + ";"); } } private IEnumerable IterateCbTextures() { - HashSet Names = new HashSet(); + HashSet names = new HashSet(); - foreach (ShaderDeclInfo DeclInfo in Decl.CbTextures.Values.OrderBy(DeclKeySelector)) + foreach (ShaderDeclInfo declInfo in _decl.CbTextures.Values.OrderBy(DeclKeySelector)) { - if (Names.Add(DeclInfo.Name)) + if (names.Add(declInfo.Name)) { - yield return DeclInfo; + yield return declInfo; } } } private void PrintDeclUniforms() { - if (Decl.ShaderType == GalShaderType.Vertex) + if (_decl.ShaderType == GalShaderType.Vertex) { //Memory layout here is [flip_x, flip_y, instance, unused] //It's using 4 bytes, not 8 - SB.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + " {"); + _sb.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + " {"); - SB.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";"); + _sb.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";"); - SB.AppendLine(IdentationStr + "int " + GlslDecl.InstanceUniformName + ";"); + _sb.AppendLine(IdentationStr + "int " + GlslDecl.InstanceUniformName + ";"); - SB.AppendLine("};"); - SB.AppendLine(); + _sb.AppendLine("};"); + _sb.AppendLine(); } - foreach (ShaderDeclInfo DeclInfo in Decl.Uniforms.Values.OrderBy(DeclKeySelector)) + foreach (ShaderDeclInfo declInfo in _decl.Uniforms.Values.OrderBy(DeclKeySelector)) { - SB.AppendLine($"layout (std140) uniform {DeclInfo.Name} {{"); + _sb.AppendLine($"layout (std140) uniform {declInfo.Name} {{"); - SB.AppendLine($"{IdentationStr}vec4 {DeclInfo.Name}_data[{MaxUboSize}];"); + _sb.AppendLine($"{IdentationStr}vec4 {declInfo.Name}_data[{MaxUboSize}];"); - SB.AppendLine("};"); + _sb.AppendLine("};"); } - if (Decl.Uniforms.Count > 0) + if (_decl.Uniforms.Count > 0) { - SB.AppendLine(); + _sb.AppendLine(); } } private void PrintDeclAttributes() { - string GeometryArray = (Decl.ShaderType == GalShaderType.Geometry) ? "[" + MaxVertexInput + "]" : ""; + string geometryArray = (_decl.ShaderType == GalShaderType.Geometry) ? "[" + MaxVertexInput + "]" : ""; - PrintDecls(Decl.Attributes, Suffix: GeometryArray); + PrintDecls(_decl.Attributes, suffix: geometryArray); } private void PrintDeclInAttributes() { - if (Decl.ShaderType == GalShaderType.Fragment) + if (_decl.ShaderType == GalShaderType.Fragment) { - SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") in vec4 " + GlslDecl.PositionOutAttrName + ";"); + _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") in vec4 " + GlslDecl.PositionOutAttrName + ";"); } - if (Decl.ShaderType == GalShaderType.Geometry) + if (_decl.ShaderType == GalShaderType.Geometry) { - if (Decl.InAttributes.Count > 0) + if (_decl.InAttributes.Count > 0) { - SB.AppendLine("in Vertex {"); + _sb.AppendLine("in Vertex {"); - foreach (ShaderDeclInfo DeclInfo in Decl.InAttributes.Values.OrderBy(DeclKeySelector)) + foreach (ShaderDeclInfo declInfo in _decl.InAttributes.Values.OrderBy(DeclKeySelector)) { - if (DeclInfo.Index >= 0) + if (declInfo.Index >= 0) { - SB.AppendLine(IdentationStr + "layout (location = " + DeclInfo.Index + ") vec4 " + DeclInfo.Name + "; "); + _sb.AppendLine(IdentationStr + "layout (location = " + declInfo.Index + ") vec4 " + declInfo.Name + "; "); } } - SB.AppendLine("} block_in[];" + Environment.NewLine); + _sb.AppendLine("} block_in[];" + Environment.NewLine); } } else { - PrintDeclAttributes(Decl.InAttributes.Values, "in"); + PrintDeclAttributes(_decl.InAttributes.Values, "in"); } } private void PrintDeclOutAttributes() { - if (Decl.ShaderType == GalShaderType.Fragment) + if (_decl.ShaderType == GalShaderType.Fragment) { - int Count = 0; + int count = 0; - for (int Attachment = 0; Attachment < 8; Attachment++) + for (int attachment = 0; attachment < 8; attachment++) { - if (Header.OmapTargets[Attachment].Enabled) + if (_header.OmapTargets[attachment].Enabled) { - SB.AppendLine("layout (location = " + Attachment + ") out vec4 " + GlslDecl.FragmentOutputName + Attachment + ";"); + _sb.AppendLine("layout (location = " + attachment + ") out vec4 " + GlslDecl.FragmentOutputName + attachment + ";"); - Count++; + count++; } } - if (Count > 0) + if (count > 0) { - SB.AppendLine(); + _sb.AppendLine(); } } else { - SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";"); - SB.AppendLine(); + _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";"); + _sb.AppendLine(); } - PrintDeclAttributes(Decl.OutAttributes.Values, "out"); + PrintDeclAttributes(_decl.OutAttributes.Values, "out"); } - private void PrintDeclAttributes(IEnumerable Decls, string InOut) + private void PrintDeclAttributes(IEnumerable decls, string inOut) { - int Count = 0; + int count = 0; - foreach (ShaderDeclInfo DeclInfo in Decls.OrderBy(DeclKeySelector)) + foreach (ShaderDeclInfo declInfo in decls.OrderBy(DeclKeySelector)) { - if (DeclInfo.Index >= 0) + if (declInfo.Index >= 0) { - SB.AppendLine("layout (location = " + DeclInfo.Index + ") " + InOut + " vec4 " + DeclInfo.Name + ";"); + _sb.AppendLine("layout (location = " + declInfo.Index + ") " + inOut + " vec4 " + declInfo.Name + ";"); - Count++; + count++; } } - if (Count > 0) + if (count > 0) { - SB.AppendLine(); + _sb.AppendLine(); } } private void PrintDeclGprs() { - PrintDecls(Decl.Gprs); - PrintDecls(Decl.GprsHalf); + PrintDecls(_decl.Gprs); + PrintDecls(_decl.GprsHalf); } private void PrintDeclPreds() { - PrintDecls(Decl.Preds, "bool"); + PrintDecls(_decl.Preds, "bool"); } private void PrintDeclSsy() { - SB.AppendLine("uint " + GlslDecl.SsyCursorName + " = 0;"); + _sb.AppendLine("uint " + GlslDecl.SsyCursorName + " = 0;"); - SB.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine); + _sb.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine); } - private void PrintDecls(IReadOnlyDictionary Dict, string CustomType = null, string Suffix = "") + private void PrintDecls(IReadOnlyDictionary dict, string customType = null, string suffix = "") { - foreach (ShaderDeclInfo DeclInfo in Dict.Values.OrderBy(DeclKeySelector)) + foreach (ShaderDeclInfo declInfo in dict.Values.OrderBy(DeclKeySelector)) { - string Name; + string name; - if (CustomType != null) + if (customType != null) { - Name = CustomType + " " + DeclInfo.Name + Suffix + ";"; + name = customType + " " + declInfo.Name + suffix + ";"; } - else if (DeclInfo.Name.Contains(GlslDecl.FragmentOutputName)) + else if (declInfo.Name.Contains(GlslDecl.FragmentOutputName)) { - Name = "layout (location = " + DeclInfo.Index / 4 + ") out vec4 " + DeclInfo.Name + Suffix + ";"; + name = "layout (location = " + declInfo.Index / 4 + ") out vec4 " + declInfo.Name + suffix + ";"; } else { - Name = GetDecl(DeclInfo) + Suffix + ";"; + name = GetDecl(declInfo) + suffix + ";"; } - SB.AppendLine(Name); + _sb.AppendLine(name); } - if (Dict.Count > 0) + if (dict.Count > 0) { - SB.AppendLine(); + _sb.AppendLine(); } } - private int DeclKeySelector(ShaderDeclInfo DeclInfo) + private int DeclKeySelector(ShaderDeclInfo declInfo) { - return DeclInfo.Cbuf << 24 | DeclInfo.Index; + return declInfo.Cbuf << 24 | declInfo.Index; } - private string GetDecl(ShaderDeclInfo DeclInfo) + private string GetDecl(ShaderDeclInfo declInfo) { - if (DeclInfo.Size == 4) + if (declInfo.Size == 4) { - return "vec4 " + DeclInfo.Name; + return "vec4 " + declInfo.Name; } else { - return "float " + DeclInfo.Name; + return "float " + declInfo.Name; } } private void PrintMain() { - SB.AppendLine("void main() {"); + _sb.AppendLine("void main() {"); - foreach (KeyValuePair KV in Decl.InAttributes) + foreach (KeyValuePair kv in _decl.InAttributes) { - if (!Decl.Attributes.TryGetValue(KV.Key, out ShaderDeclInfo Attr)) + if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr)) { continue; } - ShaderDeclInfo DeclInfo = KV.Value; + ShaderDeclInfo declInfo = kv.Value; - if (Decl.ShaderType == GalShaderType.Geometry) + if (_decl.ShaderType == GalShaderType.Geometry) { - for (int Vertex = 0; Vertex < MaxVertexInput; Vertex++) + for (int vertex = 0; vertex < MaxVertexInput; vertex++) { - string Dst = Attr.Name + "[" + Vertex + "]"; + string dst = attr.Name + "[" + vertex + "]"; - string Src = "block_in[" + Vertex + "]." + DeclInfo.Name; + string src = "block_in[" + vertex + "]." + declInfo.Name; - SB.AppendLine(IdentationStr + Dst + " = " + Src + ";"); + _sb.AppendLine(IdentationStr + dst + " = " + src + ";"); } } else { - SB.AppendLine(IdentationStr + Attr.Name + " = " + DeclInfo.Name + ";"); + _sb.AppendLine(IdentationStr + attr.Name + " = " + declInfo.Name + ";"); } } - SB.AppendLine(IdentationStr + "uint pc;"); + _sb.AppendLine(IdentationStr + "uint pc;"); - if (BlocksB != null) + if (_blocksB != null) { - PrintProgram(Blocks, GlslDecl.BasicBlockAName); - PrintProgram(BlocksB, GlslDecl.BasicBlockBName); + PrintProgram(_blocks, GlslDecl.BasicBlockAName); + PrintProgram(_blocksB, GlslDecl.BasicBlockBName); } else { - PrintProgram(Blocks, GlslDecl.BasicBlockName); + PrintProgram(_blocks, GlslDecl.BasicBlockName); } - if (Decl.ShaderType != GalShaderType.Geometry) + if (_decl.ShaderType != GalShaderType.Geometry) { PrintAttrToOutput(); } - if (Decl.ShaderType == GalShaderType.Fragment) + if (_decl.ShaderType == GalShaderType.Fragment) { - if (Header.OmapDepth) + if (_header.OmapDepth) { - SB.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(Header.DepthRegister) + ";"); + _sb.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(_header.DepthRegister) + ";"); } - int GprIndex = 0; + int gprIndex = 0; - for (int Attachment = 0; Attachment < 8; Attachment++) + for (int attachment = 0; attachment < 8; attachment++) { - string Output = GlslDecl.FragmentOutputName + Attachment; + string output = GlslDecl.FragmentOutputName + attachment; - OmapTarget Target = Header.OmapTargets[Attachment]; + OmapTarget target = _header.OmapTargets[attachment]; - for (int Component = 0; Component < 4; Component++) + for (int component = 0; component < 4; component++) { - if (Target.ComponentEnabled(Component)) + if (target.ComponentEnabled(component)) { - SB.AppendLine(IdentationStr + Output + "[" + Component + "] = " + GlslDecl.GetGprName(GprIndex) + ";"); + _sb.AppendLine(IdentationStr + output + "[" + component + "] = " + GlslDecl.GetGprName(gprIndex) + ";"); - GprIndex++; + gprIndex++; } } } } - SB.AppendLine("}"); + _sb.AppendLine("}"); } - private void PrintProgram(ShaderIrBlock[] Blocks, string Name) + private void PrintProgram(ShaderIrBlock[] blocks, string name) { - const string Ident1 = IdentationStr; - const string Ident2 = Ident1 + IdentationStr; - const string Ident3 = Ident2 + IdentationStr; - const string Ident4 = Ident3 + IdentationStr; + const string ident1 = IdentationStr; + const string ident2 = ident1 + IdentationStr; + const string ident3 = ident2 + IdentationStr; + const string ident4 = ident3 + IdentationStr; - SB.AppendLine(Ident1 + "pc = " + GetBlockPosition(Blocks[0]) + ";"); - SB.AppendLine(Ident1 + "do {"); - SB.AppendLine(Ident2 + "switch (pc) {"); + _sb.AppendLine(ident1 + "pc = " + GetBlockPosition(blocks[0]) + ";"); + _sb.AppendLine(ident1 + "do {"); + _sb.AppendLine(ident2 + "switch (pc) {"); - foreach (ShaderIrBlock Block in Blocks) + foreach (ShaderIrBlock block in blocks) { - string FunctionName = Block.Position.ToString("x8"); + string functionName = block.Position.ToString("x8"); - SB.AppendLine(Ident3 + "case 0x" + FunctionName + ": pc = " + Name + "_" + FunctionName + "(); break;"); + _sb.AppendLine(ident3 + "case 0x" + functionName + ": pc = " + name + "_" + functionName + "(); break;"); } - SB.AppendLine(Ident3 + "default:"); - SB.AppendLine(Ident4 + "pc = 0;"); - SB.AppendLine(Ident4 + "break;"); + _sb.AppendLine(ident3 + "default:"); + _sb.AppendLine(ident4 + "pc = 0;"); + _sb.AppendLine(ident4 + "break;"); - SB.AppendLine(Ident2 + "}"); - SB.AppendLine(Ident1 + "} while (pc != 0);"); + _sb.AppendLine(ident2 + "}"); + _sb.AppendLine(ident1 + "} while (pc != 0);"); } - private void PrintAttrToOutput(string Identation = IdentationStr) + private void PrintAttrToOutput(string identation = IdentationStr) { - foreach (KeyValuePair KV in Decl.OutAttributes) + foreach (KeyValuePair kv in _decl.OutAttributes) { - if (!Decl.Attributes.TryGetValue(KV.Key, out ShaderDeclInfo Attr)) + if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr)) { continue; } - ShaderDeclInfo DeclInfo = KV.Value; + ShaderDeclInfo declInfo = kv.Value; - string Name = Attr.Name; + string name = attr.Name; - if (Decl.ShaderType == GalShaderType.Geometry) + if (_decl.ShaderType == GalShaderType.Geometry) { - Name += "[0]"; + name += "[0]"; } - SB.AppendLine(Identation + DeclInfo.Name + " = " + Name + ";"); + _sb.AppendLine(identation + declInfo.Name + " = " + name + ";"); } - if (Decl.ShaderType == GalShaderType.Vertex) + if (_decl.ShaderType == GalShaderType.Vertex) { - SB.AppendLine(Identation + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";"); + _sb.AppendLine(identation + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";"); } - if (Decl.ShaderType != GalShaderType.Fragment) + if (_decl.ShaderType != GalShaderType.Fragment) { - SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;"); - SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + ".w = 1;"); + _sb.AppendLine(identation + GlslDecl.PositionOutAttrName + " = gl_Position;"); + _sb.AppendLine(identation + GlslDecl.PositionOutAttrName + ".w = 1;"); } } - private void PrintBlockScope(ShaderIrBlock[] Blocks, string Name) + private void PrintBlockScope(ShaderIrBlock[] blocks, string name) { - foreach (ShaderIrBlock Block in Blocks) + foreach (ShaderIrBlock block in blocks) { - SB.AppendLine("uint " + Name + "_" + Block.Position.ToString("x8") + "() {"); + _sb.AppendLine("uint " + name + "_" + block.Position.ToString("x8") + "() {"); - PrintNodes(Block, Block.GetNodes()); + PrintNodes(block, block.GetNodes()); - SB.AppendLine("}" + Environment.NewLine); + _sb.AppendLine("}" + Environment.NewLine); } } - private void PrintNodes(ShaderIrBlock Block, ShaderIrNode[] Nodes) + private void PrintNodes(ShaderIrBlock block, ShaderIrNode[] nodes) { - foreach (ShaderIrNode Node in Nodes) + foreach (ShaderIrNode node in nodes) { - PrintNode(Block, Node, IdentationStr); + PrintNode(block, node, IdentationStr); } - if (Nodes.Length == 0) + if (nodes.Length == 0) { - SB.AppendLine(IdentationStr + "return 0u;"); + _sb.AppendLine(IdentationStr + "return 0u;"); return; } - ShaderIrNode Last = Nodes[Nodes.Length - 1]; + ShaderIrNode last = nodes[nodes.Length - 1]; - bool UnconditionalFlowChange = false; + bool unconditionalFlowChange = false; - if (Last is ShaderIrOp Op) + if (last is ShaderIrOp op) { - switch (Op.Inst) + switch (op.Inst) { case ShaderIrInst.Bra: case ShaderIrInst.Exit: case ShaderIrInst.Sync: - UnconditionalFlowChange = true; + unconditionalFlowChange = true; break; } } - if (!UnconditionalFlowChange) + if (!unconditionalFlowChange) { - if (Block.Next != null) + if (block.Next != null) { - SB.AppendLine(IdentationStr + "return " + GetBlockPosition(Block.Next) + ";"); + _sb.AppendLine(IdentationStr + "return " + GetBlockPosition(block.Next) + ";"); } else { - SB.AppendLine(IdentationStr + "return 0u;"); + _sb.AppendLine(IdentationStr + "return 0u;"); } } } - private void PrintNode(ShaderIrBlock Block, ShaderIrNode Node, string Identation) + private void PrintNode(ShaderIrBlock block, ShaderIrNode node, string identation) { - if (Node is ShaderIrCond Cond) + if (node is ShaderIrCond cond) { - string IfExpr = GetSrcExpr(Cond.Pred, true); + string ifExpr = GetSrcExpr(cond.Pred, true); - if (Cond.Not) + if (cond.Not) { - IfExpr = "!(" + IfExpr + ")"; + ifExpr = "!(" + ifExpr + ")"; } - SB.AppendLine(Identation + "if (" + IfExpr + ") {"); + _sb.AppendLine(identation + "if (" + ifExpr + ") {"); - PrintNode(Block, Cond.Child, Identation + IdentationStr); + PrintNode(block, cond.Child, identation + IdentationStr); - SB.AppendLine(Identation + "}"); + _sb.AppendLine(identation + "}"); } - else if (Node is ShaderIrAsg Asg) + else if (node is ShaderIrAsg asg) { - if (IsValidOutOper(Asg.Dst)) + if (IsValidOutOper(asg.Dst)) { - string Expr = GetSrcExpr(Asg.Src, true); + string expr = GetSrcExpr(asg.Src, true); - Expr = GetExprWithCast(Asg.Dst, Asg.Src, Expr); + expr = GetExprWithCast(asg.Dst, asg.Src, expr); - SB.AppendLine(Identation + GetDstOperName(Asg.Dst) + " = " + Expr + ";"); + _sb.AppendLine(identation + GetDstOperName(asg.Dst) + " = " + expr + ";"); } } - else if (Node is ShaderIrOp Op) + else if (node is ShaderIrOp op) { - switch (Op.Inst) + switch (op.Inst) { case ShaderIrInst.Bra: { - SB.AppendLine(Identation + "return " + GetBlockPosition(Block.Branch) + ";"); + _sb.AppendLine(identation + "return " + GetBlockPosition(block.Branch) + ";"); break; } case ShaderIrInst.Emit: { - PrintAttrToOutput(Identation); + PrintAttrToOutput(identation); - SB.AppendLine(Identation + "EmitVertex();"); + _sb.AppendLine(identation + "EmitVertex();"); break; } case ShaderIrInst.Ssy: { - string StackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; + string stackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; - int TargetPosition = (Op.OperandA as ShaderIrOperImm).Value; + int targetPosition = (op.OperandA as ShaderIrOperImm).Value; - string Target = "0x" + TargetPosition.ToString("x8") + "u"; + string target = "0x" + targetPosition.ToString("x8") + "u"; - SB.AppendLine(Identation + StackIndex + " = " + Target + ";"); + _sb.AppendLine(identation + stackIndex + " = " + target + ";"); - SB.AppendLine(Identation + GlslDecl.SsyCursorName + "++;"); + _sb.AppendLine(identation + GlslDecl.SsyCursorName + "++;"); break; } case ShaderIrInst.Sync: { - SB.AppendLine(Identation + GlslDecl.SsyCursorName + "--;"); + _sb.AppendLine(identation + GlslDecl.SsyCursorName + "--;"); - string Target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; + string target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; - SB.AppendLine(Identation + "return " + Target + ";"); + _sb.AppendLine(identation + "return " + target + ";"); break; } default: - SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";"); + _sb.AppendLine(identation + GetSrcExpr(op, true) + ";"); break; } } - else if (Node is ShaderIrCmnt Cmnt) + else if (node is ShaderIrCmnt cmnt) { - SB.AppendLine(Identation + "// " + Cmnt.Comment); + _sb.AppendLine(identation + "// " + cmnt.Comment); } else { @@ -767,13 +767,13 @@ namespace Ryujinx.Graphics.Gal.Shader } } - private bool IsValidOutOper(ShaderIrNode Node) + private bool IsValidOutOper(ShaderIrNode node) { - if (Node is ShaderIrOperGpr Gpr && Gpr.IsConst) + if (node is ShaderIrOperGpr gpr && gpr.IsConst) { return false; } - else if (Node is ShaderIrOperPred Pred && Pred.IsConst) + else if (node is ShaderIrOperPred pred && pred.IsConst) { return false; } @@ -781,61 +781,61 @@ namespace Ryujinx.Graphics.Gal.Shader return true; } - private string GetDstOperName(ShaderIrNode Node) + private string GetDstOperName(ShaderIrNode node) { - if (Node is ShaderIrOperAbuf Abuf) + if (node is ShaderIrOperAbuf abuf) { - return GetOutAbufName(Abuf); + return GetOutAbufName(abuf); } - else if (Node is ShaderIrOperGpr Gpr) + else if (node is ShaderIrOperGpr gpr) { - return GetName(Gpr); + return GetName(gpr); } - else if (Node is ShaderIrOperPred Pred) + else if (node is ShaderIrOperPred pred) { - return GetName(Pred); + return GetName(pred); } - throw new ArgumentException(nameof(Node)); + throw new ArgumentException(nameof(node)); } - private string GetSrcExpr(ShaderIrNode Node, bool Entry = false) + private string GetSrcExpr(ShaderIrNode node, bool entry = false) { - switch (Node) + switch (node) { - case ShaderIrOperAbuf Abuf: return GetName (Abuf); - case ShaderIrOperCbuf Cbuf: return GetName (Cbuf); - case ShaderIrOperGpr Gpr: return GetName (Gpr); - case ShaderIrOperImm Imm: return GetValue(Imm); - case ShaderIrOperImmf Immf: return GetValue(Immf); - case ShaderIrOperPred Pred: return GetName (Pred); + case ShaderIrOperAbuf abuf: return GetName (abuf); + case ShaderIrOperCbuf cbuf: return GetName (cbuf); + case ShaderIrOperGpr gpr: return GetName (gpr); + case ShaderIrOperImm imm: return GetValue(imm); + case ShaderIrOperImmf immf: return GetValue(immf); + case ShaderIrOperPred pred: return GetName (pred); - case ShaderIrOp Op: - string Expr; + case ShaderIrOp op: + string expr; - if (InstsExpr.TryGetValue(Op.Inst, out GetInstExpr GetExpr)) + if (_instsExpr.TryGetValue(op.Inst, out GetInstExpr getExpr)) { - Expr = GetExpr(Op); + expr = getExpr(op); } else { - throw new NotImplementedException(Op.Inst.ToString()); + throw new NotImplementedException(op.Inst.ToString()); } - if (!Entry && NeedsParentheses(Op)) + if (!entry && NeedsParentheses(op)) { - Expr = "(" + Expr + ")"; + expr = "(" + expr + ")"; } - return Expr; + return expr; - default: throw new ArgumentException(nameof(Node)); + default: throw new ArgumentException(nameof(node)); } } - private static bool NeedsParentheses(ShaderIrOp Op) + private static bool NeedsParentheses(ShaderIrOp op) { - switch (Op.Inst) + switch (op.Inst) { case ShaderIrInst.Ipa: case ShaderIrInst.Texq: @@ -848,63 +848,63 @@ namespace Ryujinx.Graphics.Gal.Shader return true; } - private string GetName(ShaderIrOperCbuf Cbuf) + private string GetName(ShaderIrOperCbuf cbuf) { - if (!Decl.Uniforms.TryGetValue(Cbuf.Index, out ShaderDeclInfo DeclInfo)) + if (!_decl.Uniforms.TryGetValue(cbuf.Index, out ShaderDeclInfo declInfo)) { throw new InvalidOperationException(); } - if (Cbuf.Offs != null) + if (cbuf.Offs != null) { - string Offset = "floatBitsToInt(" + GetSrcExpr(Cbuf.Offs) + ")"; + string offset = "floatBitsToInt(" + GetSrcExpr(cbuf.Offs) + ")"; - string Index = "(" + Cbuf.Pos * 4 + " + " + Offset + ")"; + string index = "(" + cbuf.Pos * 4 + " + " + offset + ")"; - return $"{DeclInfo.Name}_data[{Index} / 16][({Index} / 4) % 4]"; + return $"{declInfo.Name}_data[{index} / 16][({index} / 4) % 4]"; } else { - return $"{DeclInfo.Name}_data[{Cbuf.Pos / 4}][{Cbuf.Pos % 4}]"; + return $"{declInfo.Name}_data[{cbuf.Pos / 4}][{cbuf.Pos % 4}]"; } } - private string GetOutAbufName(ShaderIrOperAbuf Abuf) + private string GetOutAbufName(ShaderIrOperAbuf abuf) { - if (Decl.ShaderType == GalShaderType.Geometry) + if (_decl.ShaderType == GalShaderType.Geometry) { - switch (Abuf.Offs) + switch (abuf.Offs) { case GlslDecl.LayerAttr: return "gl_Layer"; } } - return GetAttrTempName(Abuf); + return GetAttrTempName(abuf); } - private string GetName(ShaderIrOperAbuf Abuf) + private string GetName(ShaderIrOperAbuf abuf) { //Handle special scalar read-only attributes here. - if (Decl.ShaderType == GalShaderType.Vertex) + if (_decl.ShaderType == GalShaderType.Vertex) { - switch (Abuf.Offs) + switch (abuf.Offs) { case GlslDecl.VertexIdAttr: return "gl_VertexID"; case GlslDecl.InstanceIdAttr: return GlslDecl.InstanceUniformName; } } - else if (Decl.ShaderType == GalShaderType.TessEvaluation) + else if (_decl.ShaderType == GalShaderType.TessEvaluation) { - switch (Abuf.Offs) + switch (abuf.Offs) { case GlslDecl.TessCoordAttrX: return "gl_TessCoord.x"; case GlslDecl.TessCoordAttrY: return "gl_TessCoord.y"; case GlslDecl.TessCoordAttrZ: return "gl_TessCoord.z"; } } - else if (Decl.ShaderType == GalShaderType.Fragment) + else if (_decl.ShaderType == GalShaderType.Fragment) { - switch (Abuf.Offs) + switch (abuf.Offs) { case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x"; case GlslDecl.PointCoordAttrY: return "gl_PointCoord.y"; @@ -912,65 +912,65 @@ namespace Ryujinx.Graphics.Gal.Shader } } - return GetAttrTempName(Abuf); + return GetAttrTempName(abuf); } - private string GetAttrTempName(ShaderIrOperAbuf Abuf) + private string GetAttrTempName(ShaderIrOperAbuf abuf) { - int Index = Abuf.Offs >> 4; - int Elem = (Abuf.Offs >> 2) & 3; + int index = abuf.Offs >> 4; + int elem = (abuf.Offs >> 2) & 3; - string Swizzle = "." + GetAttrSwizzle(Elem); + string swizzle = "." + GetAttrSwizzle(elem); - if (!Decl.Attributes.TryGetValue(Index, out ShaderDeclInfo DeclInfo)) + if (!_decl.Attributes.TryGetValue(index, out ShaderDeclInfo declInfo)) { //Handle special vec4 attributes here //(for example, index 7 is always gl_Position). - if (Index == GlslDecl.GlPositionVec4Index) + if (index == GlslDecl.GlPositionVec4Index) { - string Name = - Decl.ShaderType != GalShaderType.Vertex && - Decl.ShaderType != GalShaderType.Geometry ? GlslDecl.PositionOutAttrName : "gl_Position"; + string name = + _decl.ShaderType != GalShaderType.Vertex && + _decl.ShaderType != GalShaderType.Geometry ? GlslDecl.PositionOutAttrName : "gl_Position"; - return Name + Swizzle; + return name + swizzle; } - else if (Abuf.Offs == GlslDecl.PointSizeAttr) + else if (abuf.Offs == GlslDecl.PointSizeAttr) { return "gl_PointSize"; } } - if (DeclInfo.Index >= 32) + if (declInfo.Index >= 32) { - throw new InvalidOperationException($"Shader attribute offset {Abuf.Offs} is invalid."); + throw new InvalidOperationException($"Shader attribute offset {abuf.Offs} is invalid."); } - if (Decl.ShaderType == GalShaderType.Geometry) + if (_decl.ShaderType == GalShaderType.Geometry) { - string Vertex = "floatBitsToInt(" + GetSrcExpr(Abuf.Vertex) + ")"; + string vertex = "floatBitsToInt(" + GetSrcExpr(abuf.Vertex) + ")"; - return DeclInfo.Name + "[" + Vertex + "]" + Swizzle; + return declInfo.Name + "[" + vertex + "]" + swizzle; } else { - return DeclInfo.Name + Swizzle; + return declInfo.Name + swizzle; } } - private string GetName(ShaderIrOperGpr Gpr) + private string GetName(ShaderIrOperGpr gpr) { - if (Gpr.IsConst) + if (gpr.IsConst) { return "0"; } - if (Gpr.RegisterSize == ShaderRegisterSize.Single) + if (gpr.RegisterSize == ShaderRegisterSize.Single) { - return GetNameWithSwizzle(Decl.Gprs, Gpr.Index); + return GetNameWithSwizzle(_decl.Gprs, gpr.Index); } - else if (Gpr.RegisterSize == ShaderRegisterSize.Half) + else if (gpr.RegisterSize == ShaderRegisterSize.Half) { - return GetNameWithSwizzle(Decl.GprsHalf, (Gpr.Index << 1) | Gpr.HalfPart); + return GetNameWithSwizzle(_decl.GprsHalf, (gpr.Index << 1) | gpr.HalfPart); } else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */ { @@ -978,163 +978,163 @@ namespace Ryujinx.Graphics.Gal.Shader } } - private string GetValue(ShaderIrOperImm Imm) + private string GetValue(ShaderIrOperImm imm) { //Only use hex is the value is too big and would likely be hard to read as int. - if (Imm.Value > 0xfff || - Imm.Value < -0xfff) + if (imm.Value > 0xfff || + imm.Value < -0xfff) { - return "0x" + Imm.Value.ToString("x8", CultureInfo.InvariantCulture); + return "0x" + imm.Value.ToString("x8", CultureInfo.InvariantCulture); } else { - return GetIntConst(Imm.Value); + return GetIntConst(imm.Value); } } - private string GetValue(ShaderIrOperImmf Immf) + private string GetValue(ShaderIrOperImmf immf) { - return GetFloatConst(Immf.Value); + return GetFloatConst(immf.Value); } - private string GetName(ShaderIrOperPred Pred) + private string GetName(ShaderIrOperPred pred) { - return Pred.IsConst ? "true" : GetNameWithSwizzle(Decl.Preds, Pred.Index); + return pred.IsConst ? "true" : GetNameWithSwizzle(_decl.Preds, pred.Index); } - private string GetNameWithSwizzle(IReadOnlyDictionary Dict, int Index) + private string GetNameWithSwizzle(IReadOnlyDictionary dict, int index) { - int VecIndex = Index & ~3; + int vecIndex = index & ~3; - if (Dict.TryGetValue(VecIndex, out ShaderDeclInfo DeclInfo)) + if (dict.TryGetValue(vecIndex, out ShaderDeclInfo declInfo)) { - if (DeclInfo.Size > 1 && Index < VecIndex + DeclInfo.Size) + if (declInfo.Size > 1 && index < vecIndex + declInfo.Size) { - return DeclInfo.Name + "." + GetAttrSwizzle(Index & 3); + return declInfo.Name + "." + GetAttrSwizzle(index & 3); } } - if (!Dict.TryGetValue(Index, out DeclInfo)) + if (!dict.TryGetValue(index, out declInfo)) { throw new InvalidOperationException(); } - return DeclInfo.Name; + return declInfo.Name; } - private string GetAttrSwizzle(int Elem) + private string GetAttrSwizzle(int elem) { - return "xyzw".Substring(Elem, 1); + return "xyzw".Substring(elem, 1); } - private string GetAbsExpr(ShaderIrOp Op) => GetUnaryCall(Op, "abs"); + private string GetAbsExpr(ShaderIrOp op) => GetUnaryCall(op, "abs"); - private string GetAddExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "+"); + private string GetAddExpr(ShaderIrOp op) => GetBinaryExpr(op, "+"); - private string GetAndExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&"); + private string GetAndExpr(ShaderIrOp op) => GetBinaryExpr(op, "&"); - private string GetAsrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">>"); + private string GetAsrExpr(ShaderIrOp op) => GetBinaryExpr(op, ">>"); - private string GetBandExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "&&"); + private string GetBandExpr(ShaderIrOp op) => GetBinaryExpr(op, "&&"); - private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!"); + private string GetBnotExpr(ShaderIrOp op) => GetUnaryExpr(op, "!"); - private string GetBorExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "||"); + private string GetBorExpr(ShaderIrOp op) => GetBinaryExpr(op, "||"); - private string GetBxorExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "^^"); + private string GetBxorExpr(ShaderIrOp op) => GetBinaryExpr(op, "^^"); - private string GetCeilExpr(ShaderIrOp Op) => GetUnaryCall(Op, "ceil"); + private string GetCeilExpr(ShaderIrOp op) => GetUnaryCall(op, "ceil"); - private string GetClampsExpr(ShaderIrOp Op) + private string GetClampsExpr(ShaderIrOp op) { - return "clamp(" + GetOperExpr(Op, Op.OperandA) + ", " + - GetOperExpr(Op, Op.OperandB) + ", " + - GetOperExpr(Op, Op.OperandC) + ")"; + return "clamp(" + GetOperExpr(op, op.OperandA) + ", " + + GetOperExpr(op, op.OperandB) + ", " + + GetOperExpr(op, op.OperandC) + ")"; } - private string GetClampuExpr(ShaderIrOp Op) + private string GetClampuExpr(ShaderIrOp op) { - return "int(clamp(uint(" + GetOperExpr(Op, Op.OperandA) + "), " + - "uint(" + GetOperExpr(Op, Op.OperandB) + "), " + - "uint(" + GetOperExpr(Op, Op.OperandC) + ")))"; + return "int(clamp(uint(" + GetOperExpr(op, op.OperandA) + "), " + + "uint(" + GetOperExpr(op, op.OperandB) + "), " + + "uint(" + GetOperExpr(op, op.OperandC) + ")))"; } - private string GetCeqExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "=="); + private string GetCeqExpr(ShaderIrOp op) => GetBinaryExpr(op, "=="); - private string GetCequExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "=="); + private string GetCequExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "=="); - private string GetCgeExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">="); + private string GetCgeExpr(ShaderIrOp op) => GetBinaryExpr(op, ">="); - private string GetCgeuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, ">="); + private string GetCgeuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, ">="); - private string GetCgtExpr(ShaderIrOp Op) => GetBinaryExpr(Op, ">"); + private string GetCgtExpr(ShaderIrOp op) => GetBinaryExpr(op, ">"); - private string GetCgtuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, ">"); + private string GetCgtuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, ">"); - private string GetCleExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<="); + private string GetCleExpr(ShaderIrOp op) => GetBinaryExpr(op, "<="); - private string GetCleuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "<="); + private string GetCleuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "<="); - private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<"); + private string GetCltExpr(ShaderIrOp op) => GetBinaryExpr(op, "<"); - private string GetCltuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "<"); + private string GetCltuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "<"); - private string GetCnanExpr(ShaderIrOp Op) => GetUnaryCall(Op, "isnan"); + private string GetCnanExpr(ShaderIrOp op) => GetUnaryCall(op, "isnan"); - private string GetCneExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "!="); + private string GetCneExpr(ShaderIrOp op) => GetBinaryExpr(op, "!="); - private string GetCutExpr(ShaderIrOp Op) => "EndPrimitive()"; + private string GetCutExpr(ShaderIrOp op) => "EndPrimitive()"; - private string GetCneuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "!="); + private string GetCneuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "!="); - private string GetCnumExpr(ShaderIrOp Op) => GetUnaryCall(Op, "!isnan"); + private string GetCnumExpr(ShaderIrOp op) => GetUnaryCall(op, "!isnan"); - private string GetExitExpr(ShaderIrOp Op) => "return 0u"; + private string GetExitExpr(ShaderIrOp op) => "return 0u"; - private string GetFcosExpr(ShaderIrOp Op) => GetUnaryCall(Op, "cos"); + private string GetFcosExpr(ShaderIrOp op) => GetUnaryCall(op, "cos"); - private string GetFex2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "exp2"); + private string GetFex2Expr(ShaderIrOp op) => GetUnaryCall(op, "exp2"); - private string GetFfmaExpr(ShaderIrOp Op) => GetTernaryExpr(Op, "*", "+"); + private string GetFfmaExpr(ShaderIrOp op) => GetTernaryExpr(op, "*", "+"); - private string GetFclampExpr(ShaderIrOp Op) => GetTernaryCall(Op, "clamp"); + private string GetFclampExpr(ShaderIrOp op) => GetTernaryCall(op, "clamp"); - private string GetFlg2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "log2"); + private string GetFlg2Expr(ShaderIrOp op) => GetUnaryCall(op, "log2"); - private string GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor"); + private string GetFloorExpr(ShaderIrOp op) => GetUnaryCall(op, "floor"); - private string GetFrcpExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "1 / "); + private string GetFrcpExpr(ShaderIrOp op) => GetUnaryExpr(op, "1 / "); - private string GetFrsqExpr(ShaderIrOp Op) => GetUnaryCall(Op, "inversesqrt"); + private string GetFrsqExpr(ShaderIrOp op) => GetUnaryCall(op, "inversesqrt"); - private string GetFsinExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sin"); + private string GetFsinExpr(ShaderIrOp op) => GetUnaryCall(op, "sin"); - private string GetFsqrtExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sqrt"); + private string GetFsqrtExpr(ShaderIrOp op) => GetUnaryCall(op, "sqrt"); - private string GetFtosExpr(ShaderIrOp Op) + private string GetFtosExpr(ShaderIrOp op) { - return "int(" + GetOperExpr(Op, Op.OperandA) + ")"; + return "int(" + GetOperExpr(op, op.OperandA) + ")"; } - private string GetFtouExpr(ShaderIrOp Op) + private string GetFtouExpr(ShaderIrOp op) { - return "int(uint(" + GetOperExpr(Op, Op.OperandA) + "))"; + return "int(uint(" + GetOperExpr(op, op.OperandA) + "))"; } - private string GetIpaExpr(ShaderIrOp Op) + private string GetIpaExpr(ShaderIrOp op) { - ShaderIrMetaIpa Meta = (ShaderIrMetaIpa)Op.MetaData; + ShaderIrMetaIpa meta = (ShaderIrMetaIpa)op.MetaData; - ShaderIrOperAbuf Abuf = (ShaderIrOperAbuf)Op.OperandA; + ShaderIrOperAbuf abuf = (ShaderIrOperAbuf)op.OperandA; - if (Meta.Mode == ShaderIpaMode.Pass) + if (meta.Mode == ShaderIpaMode.Pass) { - int Index = Abuf.Offs >> 4; - int Elem = (Abuf.Offs >> 2) & 3; + int index = abuf.Offs >> 4; + int elem = (abuf.Offs >> 2) & 3; - if (Decl.ShaderType == GalShaderType.Fragment && Index == GlslDecl.GlPositionVec4Index) + if (_decl.ShaderType == GalShaderType.Fragment && index == GlslDecl.GlPositionVec4Index) { - switch (Elem) + switch (elem) { case 0: return "gl_FragCoord.x"; case 1: return "gl_FragCoord.y"; @@ -1144,433 +1144,433 @@ namespace Ryujinx.Graphics.Gal.Shader } } - return GetSrcExpr(Op.OperandA); + return GetSrcExpr(op.OperandA); } - private string GetKilExpr(ShaderIrOp Op) => "discard"; + private string GetKilExpr(ShaderIrOp op) => "discard"; - private string GetLslExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<<"); - private string GetLsrExpr(ShaderIrOp Op) + private string GetLslExpr(ShaderIrOp op) => GetBinaryExpr(op, "<<"); + private string GetLsrExpr(ShaderIrOp op) { - return "int(uint(" + GetOperExpr(Op, Op.OperandA) + ") >> " + - GetOperExpr(Op, Op.OperandB) + ")"; + return "int(uint(" + GetOperExpr(op, op.OperandA) + ") >> " + + GetOperExpr(op, op.OperandB) + ")"; } - private string GetMaxExpr(ShaderIrOp Op) => GetBinaryCall(Op, "max"); - private string GetMinExpr(ShaderIrOp Op) => GetBinaryCall(Op, "min"); + private string GetMaxExpr(ShaderIrOp op) => GetBinaryCall(op, "max"); + private string GetMinExpr(ShaderIrOp op) => GetBinaryCall(op, "min"); - private string GetMulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*"); + private string GetMulExpr(ShaderIrOp op) => GetBinaryExpr(op, "*"); - private string GetNegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-"); + private string GetNegExpr(ShaderIrOp op) => GetUnaryExpr(op, "-"); - private string GetNotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "~"); + private string GetNotExpr(ShaderIrOp op) => GetUnaryExpr(op, "~"); - private string GetOrExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "|"); + private string GetOrExpr(ShaderIrOp op) => GetBinaryExpr(op, "|"); - private string GetStofExpr(ShaderIrOp Op) + private string GetStofExpr(ShaderIrOp op) { - return "float(" + GetOperExpr(Op, Op.OperandA) + ")"; + return "float(" + GetOperExpr(op, op.OperandA) + ")"; } - private string GetSubExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "-"); + private string GetSubExpr(ShaderIrOp op) => GetBinaryExpr(op, "-"); - private string GetTexbExpr(ShaderIrOp Op) + private string GetTexbExpr(ShaderIrOp op) { - ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - if (!Decl.CbTextures.TryGetValue(Op, out ShaderDeclInfo DeclInfo)) + if (!_decl.CbTextures.TryGetValue(op, out ShaderDeclInfo declInfo)) { throw new InvalidOperationException(); } - string Coords = GetTexSamplerCoords(Op); + string coords = GetTexSamplerCoords(op); - string Ch = "rgba".Substring(Meta.Elem, 1); + string ch = "rgba".Substring(meta.Elem, 1); - return GetTextureOperation(Op, DeclInfo.Name, Coords, Ch); + return GetTextureOperation(op, declInfo.Name, coords, ch); } - private string GetTexqExpr(ShaderIrOp Op) + private string GetTexqExpr(ShaderIrOp op) { - ShaderIrMetaTexq Meta = (ShaderIrMetaTexq)Op.MetaData; + ShaderIrMetaTexq meta = (ShaderIrMetaTexq)op.MetaData; - string Ch = "xyzw".Substring(Meta.Elem, 1); + string ch = "xyzw".Substring(meta.Elem, 1); - if (Meta.Info == ShaderTexqInfo.Dimension) + if (meta.Info == ShaderTexqInfo.Dimension) { - string Sampler = GetTexSamplerName(Op); + string sampler = GetTexSamplerName(op); - string Lod = GetOperExpr(Op, Op.OperandA); //??? + string lod = GetOperExpr(op, op.OperandA); //??? - return "textureSize(" + Sampler + ", " + Lod + ")." + Ch; + return "textureSize(" + sampler + ", " + lod + ")." + ch; } else { - throw new NotImplementedException(Meta.Info.ToString()); + throw new NotImplementedException(meta.Info.ToString()); } } - private string GetTexsExpr(ShaderIrOp Op) + private string GetTexsExpr(ShaderIrOp op) { - ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - string Sampler = GetTexSamplerName(Op); + string sampler = GetTexSamplerName(op); - string Coords = GetTexSamplerCoords(Op); + string coords = GetTexSamplerCoords(op); - string Ch = "rgba".Substring(Meta.Elem, 1); + string ch = "rgba".Substring(meta.Elem, 1); - return GetTextureOperation(Op, Sampler, Coords, Ch); + return GetTextureOperation(op, sampler, coords, ch); } - private string GetTld4Expr(ShaderIrOp Op) + private string GetTld4Expr(ShaderIrOp op) { - ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - string Sampler = GetTexSamplerName(Op); + string sampler = GetTexSamplerName(op); - string Coords = GetTexSamplerCoords(Op); + string coords = GetTexSamplerCoords(op); - string Ch = "rgba".Substring(Meta.Elem, 1); + string ch = "rgba".Substring(meta.Elem, 1); - return GetTextureGatherOperation(Op, Sampler, Coords, Ch); + return GetTextureGatherOperation(op, sampler, coords, ch); } // TODO: support AOFFI on non nvidia drivers - private string GetTxlfExpr(ShaderIrOp Op) + private string GetTxlfExpr(ShaderIrOp op) { // TODO: Support all suffixes - ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + TextureInstructionSuffix suffix = meta.TextureInstructionSuffix; - string Sampler = GetTexSamplerName(Op); + string sampler = GetTexSamplerName(op); - string Coords = GetITexSamplerCoords(Op); + string coords = GetITexSamplerCoords(op); - string Ch = "rgba".Substring(Meta.Elem, 1); + string ch = "rgba".Substring(meta.Elem, 1); - string Lod = "0"; + string lod = "0"; - if (Meta.LevelOfDetail != null) + if (meta.LevelOfDetail != null) { - Lod = GetOperExpr(Op, Meta.LevelOfDetail); + lod = GetOperExpr(op, meta.LevelOfDetail); } - if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) { - string Offset = GetTextureOffset(Meta, GetOperExpr(Op, Meta.Offset)); - return "texelFetchOffset(" + Sampler + ", " + Coords + ", " + Lod + ", " + Offset + ")." + Ch; + string offset = GetTextureOffset(meta, GetOperExpr(op, meta.Offset)); + return "texelFetchOffset(" + sampler + ", " + coords + ", " + lod + ", " + offset + ")." + ch; } - return "texelFetch(" + Sampler + ", " + Coords + ", " + Lod + ")." + Ch; + return "texelFetch(" + sampler + ", " + coords + ", " + lod + ")." + ch; } - private string GetTruncExpr(ShaderIrOp Op) => GetUnaryCall(Op, "trunc"); + private string GetTruncExpr(ShaderIrOp op) => GetUnaryCall(op, "trunc"); - private string GetUtofExpr(ShaderIrOp Op) + private string GetUtofExpr(ShaderIrOp op) { - return "float(uint(" + GetOperExpr(Op, Op.OperandA) + "))"; + return "float(uint(" + GetOperExpr(op, op.OperandA) + "))"; } - private string GetXorExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "^"); + private string GetXorExpr(ShaderIrOp op) => GetBinaryExpr(op, "^"); - private string GetUnaryCall(ShaderIrOp Op, string FuncName) + private string GetUnaryCall(ShaderIrOp op, string funcName) { - return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")"; + return funcName + "(" + GetOperExpr(op, op.OperandA) + ")"; } - private string GetBinaryCall(ShaderIrOp Op, string FuncName) + private string GetBinaryCall(ShaderIrOp op, string funcName) { - return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ", " + - GetOperExpr(Op, Op.OperandB) + ")"; + return funcName + "(" + GetOperExpr(op, op.OperandA) + ", " + + GetOperExpr(op, op.OperandB) + ")"; } - private string GetTernaryCall(ShaderIrOp Op, string FuncName) + private string GetTernaryCall(ShaderIrOp op, string funcName) { - return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ", " + - GetOperExpr(Op, Op.OperandB) + ", " + - GetOperExpr(Op, Op.OperandC) + ")"; + return funcName + "(" + GetOperExpr(op, op.OperandA) + ", " + + GetOperExpr(op, op.OperandB) + ", " + + GetOperExpr(op, op.OperandC) + ")"; } - private string GetUnaryExpr(ShaderIrOp Op, string Opr) + private string GetUnaryExpr(ShaderIrOp op, string opr) { - return Opr + GetOperExpr(Op, Op.OperandA); + return opr + GetOperExpr(op, op.OperandA); } - private string GetBinaryExpr(ShaderIrOp Op, string Opr) + private string GetBinaryExpr(ShaderIrOp op, string opr) { - return GetOperExpr(Op, Op.OperandA) + " " + Opr + " " + - GetOperExpr(Op, Op.OperandB); + return GetOperExpr(op, op.OperandA) + " " + opr + " " + + GetOperExpr(op, op.OperandB); } - private string GetBinaryExprWithNaN(ShaderIrOp Op, string Opr) + private string GetBinaryExprWithNaN(ShaderIrOp op, string opr) { - string A = GetOperExpr(Op, Op.OperandA); - string B = GetOperExpr(Op, Op.OperandB); + string a = GetOperExpr(op, op.OperandA); + string b = GetOperExpr(op, op.OperandB); - string NaNCheck = - " || isnan(" + A + ")" + - " || isnan(" + B + ")"; + string nanCheck = + " || isnan(" + a + ")" + + " || isnan(" + b + ")"; - return A + " " + Opr + " " + B + NaNCheck; + return a + " " + opr + " " + b + nanCheck; } - private string GetTernaryExpr(ShaderIrOp Op, string Opr1, string Opr2) + private string GetTernaryExpr(ShaderIrOp op, string opr1, string opr2) { - return GetOperExpr(Op, Op.OperandA) + " " + Opr1 + " " + - GetOperExpr(Op, Op.OperandB) + " " + Opr2 + " " + - GetOperExpr(Op, Op.OperandC); + return GetOperExpr(op, op.OperandA) + " " + opr1 + " " + + GetOperExpr(op, op.OperandB) + " " + opr2 + " " + + GetOperExpr(op, op.OperandC); } - private string GetTexSamplerName(ShaderIrOp Op) + private string GetTexSamplerName(ShaderIrOp op) { - ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC; + ShaderIrOperImm node = (ShaderIrOperImm)op.OperandC; - int Handle = ((ShaderIrOperImm)Op.OperandC).Value; + int handle = ((ShaderIrOperImm)op.OperandC).Value; - if (!Decl.Textures.TryGetValue(Handle, out ShaderDeclInfo DeclInfo)) + if (!_decl.Textures.TryGetValue(handle, out ShaderDeclInfo declInfo)) { throw new InvalidOperationException(); } - return DeclInfo.Name; + return declInfo.Name; } - private string GetTexSamplerCoords(ShaderIrOp Op) + private string GetTexSamplerCoords(ShaderIrOp op) { - ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - bool HasDepth = (Meta.TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0; + bool hasDepth = (meta.TextureInstructionSuffix & TextureInstructionSuffix.Dc) != 0; - int Coords = ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget); + int coords = ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget); - bool IsArray = ImageUtils.IsArray(Meta.TextureTarget); + bool isArray = ImageUtils.IsArray(meta.TextureTarget); - string GetLastArgument(ShaderIrNode Node) + string GetLastArgument(ShaderIrNode node) { - string Result = GetOperExpr(Op, Node); + string result = GetOperExpr(op, node); // array index is actually an integer so we need to pass it correctly - if (IsArray) + if (isArray) { - Result = "float(floatBitsToInt(" + Result + "))"; + result = "float(floatBitsToInt(" + result + "))"; } - return Result; + return result; } - string LastArgument; - string DepthArgument = ""; + string lastArgument; + string depthArgument = ""; - int VecSize = Coords; - if (HasDepth && Op.Inst != ShaderIrInst.Tld4) + int vecSize = coords; + if (hasDepth && op.Inst != ShaderIrInst.Tld4) { - VecSize++; - DepthArgument = $", {GetOperExpr(Op, Meta.DepthCompare)}"; + vecSize++; + depthArgument = $", {GetOperExpr(op, meta.DepthCompare)}"; } - switch (Coords) + switch (coords) { case 1: - if (HasDepth) + if (hasDepth) { - return $"vec3({GetOperExpr(Op, Meta.Coordinates[0])}, 0.0{DepthArgument})"; + return $"vec3({GetOperExpr(op, meta.Coordinates[0])}, 0.0{depthArgument})"; } - return GetOperExpr(Op, Meta.Coordinates[0]); + return GetOperExpr(op, meta.Coordinates[0]); case 2: - LastArgument = GetLastArgument(Meta.Coordinates[1]); + lastArgument = GetLastArgument(meta.Coordinates[1]); - return $"vec{VecSize}({GetOperExpr(Op, Meta.Coordinates[0])}, {LastArgument}{DepthArgument})"; + return $"vec{vecSize}({GetOperExpr(op, meta.Coordinates[0])}, {lastArgument}{depthArgument})"; case 3: - LastArgument = GetLastArgument(Meta.Coordinates[2]); + lastArgument = GetLastArgument(meta.Coordinates[2]); - return $"vec{VecSize}({GetOperExpr(Op, Meta.Coordinates[0])}, {GetOperExpr(Op, Meta.Coordinates[1])}, {LastArgument}{DepthArgument})"; + return $"vec{vecSize}({GetOperExpr(op, meta.Coordinates[0])}, {GetOperExpr(op, meta.Coordinates[1])}, {lastArgument}{depthArgument})"; case 4: - LastArgument = GetLastArgument(Meta.Coordinates[3]); + lastArgument = GetLastArgument(meta.Coordinates[3]); - return $"vec4({GetOperExpr(Op, Meta.Coordinates[0])}, {GetOperExpr(Op, Meta.Coordinates[1])}, {GetOperExpr(Op, Meta.Coordinates[2])}, {LastArgument}){DepthArgument}"; + return $"vec4({GetOperExpr(op, meta.Coordinates[0])}, {GetOperExpr(op, meta.Coordinates[1])}, {GetOperExpr(op, meta.Coordinates[2])}, {lastArgument}){depthArgument}"; default: throw new InvalidOperationException(); } } - private string GetTextureOffset(ShaderIrMetaTex Meta, string Oper, int Shift = 4, int Mask = 0xF) + private string GetTextureOffset(ShaderIrMetaTex meta, string oper, int shift = 4, int mask = 0xF) { - string GetOffset(string Operation, int Index) + string GetOffset(string operation, int index) { - return $"({Operation} >> {Index * Shift}) & 0x{Mask:x}"; + return $"({operation} >> {index * shift}) & 0x{mask:x}"; } - int Coords = ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget); + int coords = ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget); - if (ImageUtils.IsArray(Meta.TextureTarget)) - Coords -= 1; + if (ImageUtils.IsArray(meta.TextureTarget)) + coords -= 1; - switch (Coords) + switch (coords) { case 1: - return GetOffset(Oper, 0); + return GetOffset(oper, 0); case 2: - return "ivec2(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ")"; + return "ivec2(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ")"; case 3: - return "ivec3(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ")"; + return "ivec3(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ", " + GetOffset(oper, 2) + ")"; case 4: - return "ivec4(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ", " + GetOffset(Oper, 3) + ")"; + return "ivec4(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ", " + GetOffset(oper, 2) + ", " + GetOffset(oper, 3) + ")"; default: throw new InvalidOperationException(); } } // TODO: support AOFFI on non nvidia drivers - private string GetTextureGatherOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch) + private string GetTextureGatherOperation(ShaderIrOp op, string sampler, string coords, string ch) { - ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + TextureInstructionSuffix suffix = meta.TextureInstructionSuffix; - string ChString = "." + Ch; + string chString = "." + ch; - string Comp = Meta.Component.ToString(); + string comp = meta.Component.ToString(); - if ((Suffix & TextureInstructionSuffix.DC) != 0) + if ((suffix & TextureInstructionSuffix.Dc) != 0) { - Comp = GetOperExpr(Op, Meta.DepthCompare); + comp = GetOperExpr(op, meta.DepthCompare); } - if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) { - string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))", 8, 0x3F); + string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))", 8, 0x3F); - if ((Suffix & TextureInstructionSuffix.DC) != 0) + if ((suffix & TextureInstructionSuffix.Dc) != 0) { - return "textureGatherOffset(" + Sampler + ", " + Coords + ", " + Comp + ", " + Offset + ")" + ChString; + return "textureGatherOffset(" + sampler + ", " + coords + ", " + comp + ", " + offset + ")" + chString; } - return "textureGatherOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + Comp + ")" + ChString; + return "textureGatherOffset(" + sampler + ", " + coords + ", " + offset + ", " + comp + ")" + chString; } // TODO: Support PTP - else if ((Suffix & TextureInstructionSuffix.PTP) != 0) + else if ((suffix & TextureInstructionSuffix.Ptp) != 0) { throw new NotImplementedException(); } - return "textureGather(" + Sampler + ", " + Coords + ", " + Comp + ")" + ChString; + return "textureGather(" + sampler + ", " + coords + ", " + comp + ")" + chString; } // TODO: support AOFFI on non nvidia drivers - private string GetTextureOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch) + private string GetTextureOperation(ShaderIrOp op, string sampler, string coords, string ch) { - ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix; + TextureInstructionSuffix suffix = meta.TextureInstructionSuffix; - string ChString = "." + Ch; + string chString = "." + ch; - if ((Suffix & TextureInstructionSuffix.DC) != 0) + if ((suffix & TextureInstructionSuffix.Dc) != 0) { - ChString = ""; + chString = ""; } // TODO: Support LBA and LLA - if ((Suffix & TextureInstructionSuffix.LZ) != 0) + if ((suffix & TextureInstructionSuffix.Lz) != 0) { - if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) { - string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))"); - return "textureLodOffset(" + Sampler + ", " + Coords + ", 0.0, " + Offset + ")" + ChString; + return "textureLodOffset(" + sampler + ", " + coords + ", 0.0, " + offset + ")" + chString; } - return "textureLod(" + Sampler + ", " + Coords + ", 0.0)" + ChString; + return "textureLod(" + sampler + ", " + coords + ", 0.0)" + chString; } - else if ((Suffix & TextureInstructionSuffix.LB) != 0) + else if ((suffix & TextureInstructionSuffix.Lb) != 0) { - if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) { - string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))"); - return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; + return "textureOffset(" + sampler + ", " + coords + ", " + offset + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString; } - return "texture(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; + return "texture(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString; } - else if ((Suffix & TextureInstructionSuffix.LL) != 0) + else if ((suffix & TextureInstructionSuffix.Ll) != 0) { - if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) { - string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))"); - return "textureLodOffset(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ", " + Offset + ")" + ChString; + return "textureLodOffset(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ", " + offset + ")" + chString; } - return "textureLod(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")" + ChString; + return "textureLod(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString; } - else if ((Suffix & TextureInstructionSuffix.AOffI) != 0 && IsNvidiaDriver) + else if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) { - string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))"); + string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))"); - return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ")" + ChString; + return "textureOffset(" + sampler + ", " + coords + ", " + offset + ")" + chString; } else { - return "texture(" + Sampler + ", " + Coords + ")" + ChString; + return "texture(" + sampler + ", " + coords + ")" + chString; } - throw new NotImplementedException($"Texture Suffix {Meta.TextureInstructionSuffix} is not implemented"); + throw new NotImplementedException($"Texture Suffix {meta.TextureInstructionSuffix} is not implemented"); } - private string GetITexSamplerCoords(ShaderIrOp Op) + private string GetITexSamplerCoords(ShaderIrOp op) { - ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData; + ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - switch (ImageUtils.GetCoordsCountTextureTarget(Meta.TextureTarget)) + switch (ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget)) { case 1: - return GetOperExpr(Op, Meta.Coordinates[0]); + return GetOperExpr(op, meta.Coordinates[0]); case 2: - return "ivec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ")"; + return "ivec2(" + GetOperExpr(op, meta.Coordinates[0]) + ", " + GetOperExpr(op, meta.Coordinates[1]) + ")"; case 3: - return "ivec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ")"; + return "ivec3(" + GetOperExpr(op, meta.Coordinates[0]) + ", " + GetOperExpr(op, meta.Coordinates[1]) + ", " + GetOperExpr(op, meta.Coordinates[2]) + ")"; default: throw new InvalidOperationException(); } } - private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper) + private string GetOperExpr(ShaderIrOp op, ShaderIrNode oper) { - return GetExprWithCast(Op, Oper, GetSrcExpr(Oper)); + return GetExprWithCast(op, oper, GetSrcExpr(oper)); } - private static string GetExprWithCast(ShaderIrNode Dst, ShaderIrNode Src, string Expr) + private static string GetExprWithCast(ShaderIrNode dst, ShaderIrNode src, string expr) { //Note: The "DstType" (of the cast) is the type that the operation //uses on the source operands, while the "SrcType" is the destination //type of the operand result (if it is a operation) or just the type //of the variable for registers/uniforms/attributes. - OperType DstType = GetSrcNodeType(Dst); - OperType SrcType = GetDstNodeType(Src); + OperType dstType = GetSrcNodeType(dst); + OperType srcType = GetDstNodeType(src); - if (DstType != SrcType) + if (dstType != srcType) { //Check for invalid casts //(like bool to int/float and others). - if (SrcType != OperType.F32 && - SrcType != OperType.I32) + if (srcType != OperType.F32 && + srcType != OperType.I32) { throw new InvalidOperationException(); } - switch (Src) + switch (src) { - case ShaderIrOperGpr Gpr: + case ShaderIrOperGpr gpr: { //When the Gpr is ZR, just return the 0 value directly, //since the float encoding for 0 is 0. - if (Gpr.IsConst) + if (gpr.IsConst) { return "0"; } @@ -1578,37 +1578,37 @@ namespace Ryujinx.Graphics.Gal.Shader } } - switch (DstType) + switch (dstType) { - case OperType.F32: Expr = "intBitsToFloat(" + Expr + ")"; break; - case OperType.I32: Expr = "floatBitsToInt(" + Expr + ")"; break; + case OperType.F32: expr = "intBitsToFloat(" + expr + ")"; break; + case OperType.I32: expr = "floatBitsToInt(" + expr + ")"; break; } } - return Expr; + return expr; } - private static string GetIntConst(int Value) + private static string GetIntConst(int value) { - string Expr = Value.ToString(CultureInfo.InvariantCulture); + string expr = value.ToString(CultureInfo.InvariantCulture); - return Value < 0 ? "(" + Expr + ")" : Expr; + return value < 0 ? "(" + expr + ")" : expr; } - private static string GetFloatConst(float Value) + private static string GetFloatConst(float value) { - string Expr = Value.ToString(CultureInfo.InvariantCulture); + string expr = value.ToString(CultureInfo.InvariantCulture); - return Value < 0 ? "(" + Expr + ")" : Expr; + return value < 0 ? "(" + expr + ")" : expr; } - private static OperType GetDstNodeType(ShaderIrNode Node) + private static OperType GetDstNodeType(ShaderIrNode node) { //Special case instructions with the result type different //from the input types (like integer <-> float conversion) here. - if (Node is ShaderIrOp Op) + if (node is ShaderIrOp op) { - switch (Op.Inst) + switch (op.Inst) { case ShaderIrInst.Stof: case ShaderIrInst.Txlf: @@ -1621,54 +1621,54 @@ namespace Ryujinx.Graphics.Gal.Shader } } - return GetSrcNodeType(Node); + return GetSrcNodeType(node); } - private static OperType GetSrcNodeType(ShaderIrNode Node) + private static OperType GetSrcNodeType(ShaderIrNode node) { - switch (Node) + switch (node) { - case ShaderIrOperAbuf Abuf: - return Abuf.Offs == GlslDecl.LayerAttr || - Abuf.Offs == GlslDecl.InstanceIdAttr || - Abuf.Offs == GlslDecl.VertexIdAttr || - Abuf.Offs == GlslDecl.FaceAttr + case ShaderIrOperAbuf abuf: + return abuf.Offs == GlslDecl.LayerAttr || + abuf.Offs == GlslDecl.InstanceIdAttr || + abuf.Offs == GlslDecl.VertexIdAttr || + abuf.Offs == GlslDecl.FaceAttr ? OperType.I32 : OperType.F32; - case ShaderIrOperCbuf Cbuf: return OperType.F32; - case ShaderIrOperGpr Gpr: return OperType.F32; - case ShaderIrOperImm Imm: return OperType.I32; - case ShaderIrOperImmf Immf: return OperType.F32; - case ShaderIrOperPred Pred: return OperType.Bool; + case ShaderIrOperCbuf cbuf: return OperType.F32; + case ShaderIrOperGpr gpr: return OperType.F32; + case ShaderIrOperImm imm: return OperType.I32; + case ShaderIrOperImmf immf: return OperType.F32; + case ShaderIrOperPred pred: return OperType.Bool; - case ShaderIrOp Op: - if (Op.Inst > ShaderIrInst.B_Start && - Op.Inst < ShaderIrInst.B_End) + case ShaderIrOp op: + if (op.Inst > ShaderIrInst.B_Start && + op.Inst < ShaderIrInst.B_End) { return OperType.Bool; } - else if (Op.Inst > ShaderIrInst.F_Start && - Op.Inst < ShaderIrInst.F_End) + else if (op.Inst > ShaderIrInst.F_Start && + op.Inst < ShaderIrInst.F_End) { return OperType.F32; } - else if (Op.Inst > ShaderIrInst.I_Start && - Op.Inst < ShaderIrInst.I_End) + else if (op.Inst > ShaderIrInst.I_Start && + op.Inst < ShaderIrInst.I_End) { return OperType.I32; } break; } - throw new ArgumentException(nameof(Node)); + throw new ArgumentException(nameof(node)); } - private static string GetBlockPosition(ShaderIrBlock Block) + private static string GetBlockPosition(ShaderIrBlock block) { - if (Block != null) + if (block != null) { - return "0x" + Block.Position.ToString("x8") + "u"; + return "0x" + block.Position.ToString("x8") + "u"; } else { diff --git a/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs b/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs index a7af05aef9..be8555d572 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs @@ -10,13 +10,13 @@ namespace Ryujinx.Graphics.Gal.Shader public IEnumerable Uniforms { get; private set; } public GlslProgram( - string Code, - IEnumerable Textures, - IEnumerable Uniforms) + string code, + IEnumerable textures, + IEnumerable uniforms) { - this.Code = Code; - this.Textures = Textures; - this.Uniforms = Uniforms; + Code = code; + Textures = textures; + Uniforms = uniforms; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index 469092a23c..f935be74ff 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -14,1138 +14,1138 @@ namespace Ryujinx.Graphics.Gal.Shader MergeH1 } - public static void Bfe_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Bfe_C(ShaderIrBlock block, long opCode, int position) { - EmitBfe(Block, OpCode, ShaderOper.CR); + EmitBfe(block, opCode, ShaderOper.Cr); } - public static void Bfe_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Bfe_I(ShaderIrBlock block, long opCode, int position) { - EmitBfe(Block, OpCode, ShaderOper.Imm); + EmitBfe(block, opCode, ShaderOper.Imm); } - public static void Bfe_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Bfe_R(ShaderIrBlock block, long opCode, int position) { - EmitBfe(Block, OpCode, ShaderOper.RR); + EmitBfe(block, opCode, ShaderOper.Rr); } - public static void Fadd_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Fadd_C(ShaderIrBlock block, long opCode, int position) { - EmitFadd(Block, OpCode, ShaderOper.CR); + EmitFadd(block, opCode, ShaderOper.Cr); } - public static void Fadd_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Fadd_I(ShaderIrBlock block, long opCode, int position) { - EmitFadd(Block, OpCode, ShaderOper.Immf); + EmitFadd(block, opCode, ShaderOper.Immf); } - public static void Fadd_I32(ShaderIrBlock Block, long OpCode, int Position) + public static void Fadd_I32(ShaderIrBlock block, long opCode, int position) { - ShaderIrNode OperA = OpCode.Gpr8(); - ShaderIrNode OperB = OpCode.Immf32_20(); + ShaderIrNode operA = opCode.Gpr8(); + ShaderIrNode operB = opCode.Immf32_20(); - bool NegB = OpCode.Read(53); - bool AbsA = OpCode.Read(54); - bool NegA = OpCode.Read(56); - bool AbsB = OpCode.Read(57); + bool negB = opCode.Read(53); + bool absA = opCode.Read(54); + bool negA = opCode.Read(56); + bool absB = opCode.Read(57); - OperA = GetAluFabsFneg(OperA, AbsA, NegA); - OperB = GetAluFabsFneg(OperB, AbsB, NegB); + operA = GetAluFabsFneg(operA, absA, negA); + operB = GetAluFabsFneg(operB, absB, negB); - ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB); + ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Fadd, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - public static void Fadd_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Fadd_R(ShaderIrBlock block, long opCode, int position) { - EmitFadd(Block, OpCode, ShaderOper.RR); + EmitFadd(block, opCode, ShaderOper.Rr); } - public static void Ffma_CR(ShaderIrBlock Block, long OpCode, int Position) + public static void Ffma_CR(ShaderIrBlock block, long opCode, int position) { - EmitFfma(Block, OpCode, ShaderOper.CR); + EmitFfma(block, opCode, ShaderOper.Cr); } - public static void Ffma_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Ffma_I(ShaderIrBlock block, long opCode, int position) { - EmitFfma(Block, OpCode, ShaderOper.Immf); + EmitFfma(block, opCode, ShaderOper.Immf); } - public static void Ffma_RC(ShaderIrBlock Block, long OpCode, int Position) + public static void Ffma_RC(ShaderIrBlock block, long opCode, int position) { - EmitFfma(Block, OpCode, ShaderOper.RC); + EmitFfma(block, opCode, ShaderOper.Rc); } - public static void Ffma_RR(ShaderIrBlock Block, long OpCode, int Position) + public static void Ffma_RR(ShaderIrBlock block, long opCode, int position) { - EmitFfma(Block, OpCode, ShaderOper.RR); + EmitFfma(block, opCode, ShaderOper.Rr); } - public static void Fmnmx_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Fmnmx_C(ShaderIrBlock block, long opCode, int position) { - EmitFmnmx(Block, OpCode, ShaderOper.CR); + EmitFmnmx(block, opCode, ShaderOper.Cr); } - public static void Fmnmx_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Fmnmx_I(ShaderIrBlock block, long opCode, int position) { - EmitFmnmx(Block, OpCode, ShaderOper.Immf); + EmitFmnmx(block, opCode, ShaderOper.Immf); } - public static void Fmnmx_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Fmnmx_R(ShaderIrBlock block, long opCode, int position) { - EmitFmnmx(Block, OpCode, ShaderOper.RR); + EmitFmnmx(block, opCode, ShaderOper.Rr); } - public static void Fmul_I32(ShaderIrBlock Block, long OpCode, int Position) + public static void Fmul_I32(ShaderIrBlock block, long opCode, int position) { - ShaderIrNode OperA = OpCode.Gpr8(); - ShaderIrNode OperB = OpCode.Immf32_20(); + ShaderIrNode operA = opCode.Gpr8(); + ShaderIrNode operB = opCode.Immf32_20(); - ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB); + ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Fmul, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - public static void Fmul_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Fmul_C(ShaderIrBlock block, long opCode, int position) { - EmitFmul(Block, OpCode, ShaderOper.CR); + EmitFmul(block, opCode, ShaderOper.Cr); } - public static void Fmul_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Fmul_I(ShaderIrBlock block, long opCode, int position) { - EmitFmul(Block, OpCode, ShaderOper.Immf); + EmitFmul(block, opCode, ShaderOper.Immf); } - public static void Fmul_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Fmul_R(ShaderIrBlock block, long opCode, int position) { - EmitFmul(Block, OpCode, ShaderOper.RR); + EmitFmul(block, opCode, ShaderOper.Rr); } - public static void Fset_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Fset_C(ShaderIrBlock block, long opCode, int position) { - EmitFset(Block, OpCode, ShaderOper.CR); + EmitFset(block, opCode, ShaderOper.Cr); } - public static void Fset_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Fset_I(ShaderIrBlock block, long opCode, int position) { - EmitFset(Block, OpCode, ShaderOper.Immf); + EmitFset(block, opCode, ShaderOper.Immf); } - public static void Fset_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Fset_R(ShaderIrBlock block, long opCode, int position) { - EmitFset(Block, OpCode, ShaderOper.RR); + EmitFset(block, opCode, ShaderOper.Rr); } - public static void Fsetp_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Fsetp_C(ShaderIrBlock block, long opCode, int position) { - EmitFsetp(Block, OpCode, ShaderOper.CR); + EmitFsetp(block, opCode, ShaderOper.Cr); } - public static void Fsetp_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Fsetp_I(ShaderIrBlock block, long opCode, int position) { - EmitFsetp(Block, OpCode, ShaderOper.Immf); + EmitFsetp(block, opCode, ShaderOper.Immf); } - public static void Fsetp_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Fsetp_R(ShaderIrBlock block, long opCode, int position) { - EmitFsetp(Block, OpCode, ShaderOper.RR); + EmitFsetp(block, opCode, ShaderOper.Rr); } - public static void Hadd2_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Hadd2_R(ShaderIrBlock block, long opCode, int position) { - EmitBinaryHalfOp(Block, OpCode, ShaderIrInst.Fadd); + EmitBinaryHalfOp(block, opCode, ShaderIrInst.Fadd); } - public static void Hmul2_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Hmul2_R(ShaderIrBlock block, long opCode, int position) { - EmitBinaryHalfOp(Block, OpCode, ShaderIrInst.Fmul); + EmitBinaryHalfOp(block, opCode, ShaderIrInst.Fmul); } - public static void Iadd_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Iadd_C(ShaderIrBlock block, long opCode, int position) { - EmitIadd(Block, OpCode, ShaderOper.CR); + EmitIadd(block, opCode, ShaderOper.Cr); } - public static void Iadd_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Iadd_I(ShaderIrBlock block, long opCode, int position) { - EmitIadd(Block, OpCode, ShaderOper.Imm); + EmitIadd(block, opCode, ShaderOper.Imm); } - public static void Iadd_I32(ShaderIrBlock Block, long OpCode, int Position) + public static void Iadd_I32(ShaderIrBlock block, long opCode, int position) { - ShaderIrNode OperA = OpCode.Gpr8(); - ShaderIrNode OperB = OpCode.Imm32_20(); + ShaderIrNode operA = opCode.Gpr8(); + ShaderIrNode operB = opCode.Imm32_20(); - bool NegA = OpCode.Read(56); + bool negA = opCode.Read(56); - OperA = GetAluIneg(OperA, NegA); + operA = GetAluIneg(operA, negA); - ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB); + ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Add, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - public static void Iadd_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Iadd_R(ShaderIrBlock block, long opCode, int position) { - EmitIadd(Block, OpCode, ShaderOper.RR); + EmitIadd(block, opCode, ShaderOper.Rr); } - public static void Iadd3_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Iadd3_C(ShaderIrBlock block, long opCode, int position) { - EmitIadd3(Block, OpCode, ShaderOper.CR); + EmitIadd3(block, opCode, ShaderOper.Cr); } - public static void Iadd3_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Iadd3_I(ShaderIrBlock block, long opCode, int position) { - EmitIadd3(Block, OpCode, ShaderOper.Imm); + EmitIadd3(block, opCode, ShaderOper.Imm); } - public static void Iadd3_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Iadd3_R(ShaderIrBlock block, long opCode, int position) { - EmitIadd3(Block, OpCode, ShaderOper.RR); + EmitIadd3(block, opCode, ShaderOper.Rr); } - public static void Imnmx_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Imnmx_C(ShaderIrBlock block, long opCode, int position) { - EmitImnmx(Block, OpCode, ShaderOper.CR); + EmitImnmx(block, opCode, ShaderOper.Cr); } - public static void Imnmx_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Imnmx_I(ShaderIrBlock block, long opCode, int position) { - EmitImnmx(Block, OpCode, ShaderOper.Imm); + EmitImnmx(block, opCode, ShaderOper.Imm); } - public static void Imnmx_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Imnmx_R(ShaderIrBlock block, long opCode, int position) { - EmitImnmx(Block, OpCode, ShaderOper.RR); + EmitImnmx(block, opCode, ShaderOper.Rr); } - public static void Ipa(ShaderIrBlock Block, long OpCode, int Position) + public static void Ipa(ShaderIrBlock block, long opCode, int position) { - ShaderIrNode OperA = OpCode.Abuf28(); - ShaderIrNode OperB = OpCode.Gpr20(); + ShaderIrNode operA = opCode.Abuf28(); + ShaderIrNode operB = opCode.Gpr20(); - ShaderIpaMode Mode = (ShaderIpaMode)(OpCode.Read(54, 3)); + ShaderIpaMode mode = (ShaderIpaMode)(opCode.Read(54, 3)); - ShaderIrMetaIpa Meta = new ShaderIrMetaIpa(Mode); + ShaderIrMetaIpa meta = new ShaderIrMetaIpa(mode); - ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ipa, OperA, OperB, null, Meta); + ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Ipa, operA, operB, null, meta); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - public static void Iscadd_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Iscadd_C(ShaderIrBlock block, long opCode, int position) { - EmitIscadd(Block, OpCode, ShaderOper.CR); + EmitIscadd(block, opCode, ShaderOper.Cr); } - public static void Iscadd_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Iscadd_I(ShaderIrBlock block, long opCode, int position) { - EmitIscadd(Block, OpCode, ShaderOper.Imm); + EmitIscadd(block, opCode, ShaderOper.Imm); } - public static void Iscadd_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Iscadd_R(ShaderIrBlock block, long opCode, int position) { - EmitIscadd(Block, OpCode, ShaderOper.RR); + EmitIscadd(block, opCode, ShaderOper.Rr); } - public static void Iset_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Iset_C(ShaderIrBlock block, long opCode, int position) { - EmitIset(Block, OpCode, ShaderOper.CR); + EmitIset(block, opCode, ShaderOper.Cr); } - public static void Iset_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Iset_I(ShaderIrBlock block, long opCode, int position) { - EmitIset(Block, OpCode, ShaderOper.Imm); + EmitIset(block, opCode, ShaderOper.Imm); } - public static void Iset_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Iset_R(ShaderIrBlock block, long opCode, int position) { - EmitIset(Block, OpCode, ShaderOper.RR); + EmitIset(block, opCode, ShaderOper.Rr); } - public static void Isetp_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Isetp_C(ShaderIrBlock block, long opCode, int position) { - EmitIsetp(Block, OpCode, ShaderOper.CR); + EmitIsetp(block, opCode, ShaderOper.Cr); } - public static void Isetp_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Isetp_I(ShaderIrBlock block, long opCode, int position) { - EmitIsetp(Block, OpCode, ShaderOper.Imm); + EmitIsetp(block, opCode, ShaderOper.Imm); } - public static void Isetp_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Isetp_R(ShaderIrBlock block, long opCode, int position) { - EmitIsetp(Block, OpCode, ShaderOper.RR); + EmitIsetp(block, opCode, ShaderOper.Rr); } - public static void Lop_I32(ShaderIrBlock Block, long OpCode, int Position) + public static void Lop_I32(ShaderIrBlock block, long opCode, int position) { - int SubOp = OpCode.Read(53, 3); + int subOp = opCode.Read(53, 3); - bool InvA = OpCode.Read(55); - bool InvB = OpCode.Read(56); + bool invA = opCode.Read(55); + bool invB = opCode.Read(56); - ShaderIrInst Inst = 0; + ShaderIrInst inst = 0; - switch (SubOp) + switch (subOp) { - case 0: Inst = ShaderIrInst.And; break; - case 1: Inst = ShaderIrInst.Or; break; - case 2: Inst = ShaderIrInst.Xor; break; + case 0: inst = ShaderIrInst.And; break; + case 1: inst = ShaderIrInst.Or; break; + case 2: inst = ShaderIrInst.Xor; break; } - ShaderIrNode OperB = GetAluNot(OpCode.Imm32_20(), InvB); + ShaderIrNode operB = GetAluNot(opCode.Imm32_20(), invB); //SubOp == 3 is pass, used by the not instruction //which just moves the inverted register value. - if (SubOp < 3) + if (subOp < 3) { - ShaderIrNode OperA = GetAluNot(OpCode.Gpr8(), InvA); + ShaderIrNode operA = GetAluNot(opCode.Gpr8(), invA); - ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB); + ShaderIrOp op = new ShaderIrOp(inst, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } else { - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperB))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operB))); } } - public static void Lop_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Lop_C(ShaderIrBlock block, long opCode, int position) { - EmitLop(Block, OpCode, ShaderOper.CR); + EmitLop(block, opCode, ShaderOper.Cr); } - public static void Lop_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Lop_I(ShaderIrBlock block, long opCode, int position) { - EmitLop(Block, OpCode, ShaderOper.Imm); + EmitLop(block, opCode, ShaderOper.Imm); } - public static void Lop_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Lop_R(ShaderIrBlock block, long opCode, int position) { - EmitLop(Block, OpCode, ShaderOper.RR); + EmitLop(block, opCode, ShaderOper.Rr); } - public static void Mufu(ShaderIrBlock Block, long OpCode, int Position) + public static void Mufu(ShaderIrBlock block, long opCode, int position) { - int SubOp = OpCode.Read(20, 0xf); + int subOp = opCode.Read(20, 0xf); - bool AbsA = OpCode.Read(46); - bool NegA = OpCode.Read(48); + bool absA = opCode.Read(46); + bool negA = opCode.Read(48); - ShaderIrInst Inst = 0; + ShaderIrInst inst = 0; - switch (SubOp) + switch (subOp) { - case 0: Inst = ShaderIrInst.Fcos; break; - case 1: Inst = ShaderIrInst.Fsin; break; - case 2: Inst = ShaderIrInst.Fex2; break; - case 3: Inst = ShaderIrInst.Flg2; break; - case 4: Inst = ShaderIrInst.Frcp; break; - case 5: Inst = ShaderIrInst.Frsq; break; - case 8: Inst = ShaderIrInst.Fsqrt; break; + case 0: inst = ShaderIrInst.Fcos; break; + case 1: inst = ShaderIrInst.Fsin; break; + case 2: inst = ShaderIrInst.Fex2; break; + case 3: inst = ShaderIrInst.Flg2; break; + case 4: inst = ShaderIrInst.Frcp; break; + case 5: inst = ShaderIrInst.Frsq; break; + case 8: inst = ShaderIrInst.Fsqrt; break; - default: throw new NotImplementedException(SubOp.ToString()); + default: throw new NotImplementedException(subOp.ToString()); } - ShaderIrNode OperA = OpCode.Gpr8(); + ShaderIrNode operA = opCode.Gpr8(); - ShaderIrOp Op = new ShaderIrOp(Inst, GetAluFabsFneg(OperA, AbsA, NegA)); + ShaderIrOp op = new ShaderIrOp(inst, GetAluFabsFneg(operA, absA, negA)); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - public static void Psetp(ShaderIrBlock Block, long OpCode, int Position) + public static void Psetp(ShaderIrBlock block, long opCode, int position) { - bool NegA = OpCode.Read(15); - bool NegB = OpCode.Read(32); - bool NegP = OpCode.Read(42); + bool negA = opCode.Read(15); + bool negB = opCode.Read(32); + bool negP = opCode.Read(42); - ShaderIrInst LopInst = OpCode.BLop24(); + ShaderIrInst lopInst = opCode.BLop24(); - ShaderIrNode OperA = OpCode.Pred12(); - ShaderIrNode OperB = OpCode.Pred29(); + ShaderIrNode operA = opCode.Pred12(); + ShaderIrNode operB = opCode.Pred29(); - if (NegA) + if (negA) { - OperA = new ShaderIrOp(ShaderIrInst.Bnot, OperA); + operA = new ShaderIrOp(ShaderIrInst.Bnot, operA); } - if (NegB) + if (negB) { - OperB = new ShaderIrOp(ShaderIrInst.Bnot, OperB); + operB = new ShaderIrOp(ShaderIrInst.Bnot, operB); } - ShaderIrOp Op = new ShaderIrOp(LopInst, OperA, OperB); + ShaderIrOp op = new ShaderIrOp(lopInst, operA, operB); - ShaderIrOperPred P0Node = OpCode.Pred3(); - ShaderIrOperPred P1Node = OpCode.Pred0(); - ShaderIrOperPred P2Node = OpCode.Pred39(); + ShaderIrOperPred p0Node = opCode.Pred3(); + ShaderIrOperPred p1Node = opCode.Pred0(); + ShaderIrOperPred p2Node = opCode.Pred39(); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op))); - LopInst = OpCode.BLop45(); + lopInst = opCode.BLop45(); - if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst) + if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst) { return; } - ShaderIrNode P2NNode = P2Node; + ShaderIrNode p2NNode = p2Node; - if (NegP) + if (negP) { - P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode); + p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode); } - Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node); + op = new ShaderIrOp(ShaderIrInst.Bnot, p0Node); - Op = new ShaderIrOp(LopInst, Op, P2NNode); + op = new ShaderIrOp(lopInst, op, p2NNode); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(p1Node, op))); - Op = new ShaderIrOp(LopInst, P0Node, P2NNode); + op = new ShaderIrOp(lopInst, p0Node, p2NNode); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op))); } - public static void Rro_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Rro_C(ShaderIrBlock block, long opCode, int position) { - EmitRro(Block, OpCode, ShaderOper.CR); + EmitRro(block, opCode, ShaderOper.Cr); } - public static void Rro_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Rro_I(ShaderIrBlock block, long opCode, int position) { - EmitRro(Block, OpCode, ShaderOper.Immf); + EmitRro(block, opCode, ShaderOper.Immf); } - public static void Rro_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Rro_R(ShaderIrBlock block, long opCode, int position) { - EmitRro(Block, OpCode, ShaderOper.RR); + EmitRro(block, opCode, ShaderOper.Rr); } - public static void Shl_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Shl_C(ShaderIrBlock block, long opCode, int position) { - EmitAluBinary(Block, OpCode, ShaderOper.CR, ShaderIrInst.Lsl); + EmitAluBinary(block, opCode, ShaderOper.Cr, ShaderIrInst.Lsl); } - public static void Shl_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Shl_I(ShaderIrBlock block, long opCode, int position) { - EmitAluBinary(Block, OpCode, ShaderOper.Imm, ShaderIrInst.Lsl); + EmitAluBinary(block, opCode, ShaderOper.Imm, ShaderIrInst.Lsl); } - public static void Shl_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Shl_R(ShaderIrBlock block, long opCode, int position) { - EmitAluBinary(Block, OpCode, ShaderOper.RR, ShaderIrInst.Lsl); + EmitAluBinary(block, opCode, ShaderOper.Rr, ShaderIrInst.Lsl); } - public static void Shr_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Shr_C(ShaderIrBlock block, long opCode, int position) { - EmitAluBinary(Block, OpCode, ShaderOper.CR, GetShrInst(OpCode)); + EmitAluBinary(block, opCode, ShaderOper.Cr, GetShrInst(opCode)); } - public static void Shr_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Shr_I(ShaderIrBlock block, long opCode, int position) { - EmitAluBinary(Block, OpCode, ShaderOper.Imm, GetShrInst(OpCode)); + EmitAluBinary(block, opCode, ShaderOper.Imm, GetShrInst(opCode)); } - public static void Shr_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Shr_R(ShaderIrBlock block, long opCode, int position) { - EmitAluBinary(Block, OpCode, ShaderOper.RR, GetShrInst(OpCode)); + EmitAluBinary(block, opCode, ShaderOper.Rr, GetShrInst(opCode)); } - private static ShaderIrInst GetShrInst(long OpCode) + private static ShaderIrInst GetShrInst(long opCode) { - bool Signed = OpCode.Read(48); + bool signed = opCode.Read(48); - return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; + return signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; } - public static void Vmad(ShaderIrBlock Block, long OpCode, int Position) + public static void Vmad(ShaderIrBlock block, long opCode, int position) { - ShaderIrNode OperA = OpCode.Gpr8(); + ShaderIrNode operA = opCode.Gpr8(); - ShaderIrNode OperB; + ShaderIrNode operB; - if (OpCode.Read(50)) + if (opCode.Read(50)) { - OperB = OpCode.Gpr20(); + operB = opCode.Gpr20(); } else { - OperB = OpCode.Imm19_20(); + operB = opCode.Imm19_20(); } - ShaderIrOperGpr OperC = OpCode.Gpr39(); + ShaderIrOperGpr operC = opCode.Gpr39(); - ShaderIrNode Tmp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB); + ShaderIrNode tmp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB); - ShaderIrNode Final = new ShaderIrOp(ShaderIrInst.Add, Tmp, OperC); + ShaderIrNode final = new ShaderIrOp(ShaderIrInst.Add, tmp, operC); - int Shr = OpCode.Read(51, 3); + int shr = opCode.Read(51, 3); - if (Shr != 0) + if (shr != 0) { - int Shift = (Shr == 2) ? 15 : 7; + int shift = (shr == 2) ? 15 : 7; - Final = new ShaderIrOp(ShaderIrInst.Lsr, Final, new ShaderIrOperImm(Shift)); + final = new ShaderIrOp(ShaderIrInst.Lsr, final, new ShaderIrOperImm(shift)); } - Block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c")); + block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c")); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Final))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), final))); } - public static void Xmad_CR(ShaderIrBlock Block, long OpCode, int Position) + public static void Xmad_CR(ShaderIrBlock block, long opCode, int position) { - EmitXmad(Block, OpCode, ShaderOper.CR); + EmitXmad(block, opCode, ShaderOper.Cr); } - public static void Xmad_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Xmad_I(ShaderIrBlock block, long opCode, int position) { - EmitXmad(Block, OpCode, ShaderOper.Imm); + EmitXmad(block, opCode, ShaderOper.Imm); } - public static void Xmad_RC(ShaderIrBlock Block, long OpCode, int Position) + public static void Xmad_RC(ShaderIrBlock block, long opCode, int position) { - EmitXmad(Block, OpCode, ShaderOper.RC); + EmitXmad(block, opCode, ShaderOper.Rc); } - public static void Xmad_RR(ShaderIrBlock Block, long OpCode, int Position) + public static void Xmad_RR(ShaderIrBlock block, long opCode, int position) { - EmitXmad(Block, OpCode, ShaderOper.RR); + EmitXmad(block, opCode, ShaderOper.Rr); } private static void EmitAluBinary( - ShaderIrBlock Block, - long OpCode, - ShaderOper Oper, - ShaderIrInst Inst) + ShaderIrBlock block, + long opCode, + ShaderOper oper, + ShaderIrInst inst) { - ShaderIrNode OperA = OpCode.Gpr8(), OperB; + ShaderIrNode operA = opCode.Gpr8(), operB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB); + ShaderIrNode op = new ShaderIrOp(inst, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - private static void EmitBfe(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitBfe(ShaderIrBlock block, long opCode, ShaderOper oper) { //TODO: Handle the case where position + length //is greater than the word size, in this case the sign bit //needs to be replicated to fill the remaining space. - bool NegB = OpCode.Read(48); - bool NegA = OpCode.Read(49); + bool negB = opCode.Read(48); + bool negA = opCode.Read(49); - ShaderIrNode OperA = OpCode.Gpr8(), OperB; + ShaderIrNode operA = opCode.Gpr8(), operB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - ShaderIrNode Op; + ShaderIrNode op; - bool Signed = OpCode.Read(48); //? + bool signed = opCode.Read(48); //? - if (OperB is ShaderIrOperImm PosLen) + if (operB is ShaderIrOperImm posLen) { - int Position = (PosLen.Value >> 0) & 0xff; - int Length = (PosLen.Value >> 8) & 0xff; + int position = (posLen.Value >> 0) & 0xff; + int length = (posLen.Value >> 8) & 0xff; - int LSh = 32 - (Position + Length); + int lSh = 32 - (position + length); - ShaderIrInst RightShift = Signed + ShaderIrInst rightShift = signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; - Op = new ShaderIrOp(ShaderIrInst.Lsl, OperA, new ShaderIrOperImm(LSh)); - Op = new ShaderIrOp(RightShift, Op, new ShaderIrOperImm(LSh + Position)); + op = new ShaderIrOp(ShaderIrInst.Lsl, operA, new ShaderIrOperImm(lSh)); + op = new ShaderIrOp(rightShift, op, new ShaderIrOperImm(lSh + position)); } else { - ShaderIrOperImm Shift = new ShaderIrOperImm(8); - ShaderIrOperImm Mask = new ShaderIrOperImm(0xff); + ShaderIrOperImm shift = new ShaderIrOperImm(8); + ShaderIrOperImm mask = new ShaderIrOperImm(0xff); - ShaderIrNode OpPos, OpLen; + ShaderIrNode opPos, opLen; - OpPos = new ShaderIrOp(ShaderIrInst.And, OperB, Mask); - OpLen = new ShaderIrOp(ShaderIrInst.Lsr, OperB, Shift); - OpLen = new ShaderIrOp(ShaderIrInst.And, OpLen, Mask); + opPos = new ShaderIrOp(ShaderIrInst.And, operB, mask); + opLen = new ShaderIrOp(ShaderIrInst.Lsr, operB, shift); + opLen = new ShaderIrOp(ShaderIrInst.And, opLen, mask); - Op = new ShaderIrOp(ShaderIrInst.Lsr, OperA, OpPos); + op = new ShaderIrOp(ShaderIrInst.Lsr, operA, opPos); - Op = ExtendTo32(Op, Signed, OpLen); + op = ExtendTo32(op, signed, opLen); } - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - private static void EmitFadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitFadd(ShaderIrBlock block, long opCode, ShaderOper oper) { - bool NegB = OpCode.Read(45); - bool AbsA = OpCode.Read(46); - bool NegA = OpCode.Read(48); - bool AbsB = OpCode.Read(49); - bool Sat = OpCode.Read(50); + bool negB = opCode.Read(45); + bool absA = opCode.Read(46); + bool negA = opCode.Read(48); + bool absB = opCode.Read(49); + bool sat = opCode.Read(50); - ShaderIrNode OperA = OpCode.Gpr8(), OperB; + ShaderIrNode operA = opCode.Gpr8(), operB; - OperA = GetAluFabsFneg(OperA, AbsA, NegA); + operA = GetAluFabsFneg(operA, absA, negA); - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Immf: operB = opCode.Immf19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperB = GetAluFabsFneg(OperB, AbsB, NegB); + operB = GetAluFabsFneg(operB, absB, negB); - ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB); + ShaderIrNode op = new ShaderIrOp(ShaderIrInst.Fadd, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat)))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat)))); } - private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitFmul(ShaderIrBlock block, long opCode, ShaderOper oper) { - bool NegB = OpCode.Read(48); - bool Sat = OpCode.Read(50); + bool negB = opCode.Read(48); + bool sat = opCode.Read(50); - ShaderIrNode OperA = OpCode.Gpr8(), OperB; + ShaderIrNode operA = opCode.Gpr8(), operB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Immf: operB = opCode.Immf19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperB = GetAluFneg(OperB, NegB); + operB = GetAluFneg(operB, negB); - ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB); + ShaderIrNode op = new ShaderIrOp(ShaderIrInst.Fmul, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat)))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat)))); } - private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitFfma(ShaderIrBlock block, long opCode, ShaderOper oper) { - bool NegB = OpCode.Read(48); - bool NegC = OpCode.Read(49); - bool Sat = OpCode.Read(50); + bool negB = opCode.Read(48); + bool negC = opCode.Read(49); + bool sat = opCode.Read(50); - ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC; + ShaderIrNode operA = opCode.Gpr8(), operB, operC; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break; - case ShaderOper.RC: OperB = OpCode.Gpr39(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Immf: operB = opCode.Immf19_20(); break; + case ShaderOper.Rc: operB = opCode.Gpr39(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperB = GetAluFneg(OperB, NegB); + operB = GetAluFneg(operB, negB); - if (Oper == ShaderOper.RC) + if (oper == ShaderOper.Rc) { - OperC = GetAluFneg(OpCode.Cbuf34(), NegC); + operC = GetAluFneg(opCode.Cbuf34(), negC); } else { - OperC = GetAluFneg(OpCode.Gpr39(), NegC); + operC = GetAluFneg(opCode.Gpr39(), negC); } - ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC); + ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Ffma, operA, operB, operC); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat)))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat)))); } - private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitIadd(ShaderIrBlock block, long opCode, ShaderOper oper) { - ShaderIrNode OperA = OpCode.Gpr8(); - ShaderIrNode OperB; + ShaderIrNode operA = opCode.Gpr8(); + ShaderIrNode operB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - bool NegA = OpCode.Read(49); - bool NegB = OpCode.Read(48); + bool negA = opCode.Read(49); + bool negB = opCode.Read(48); - OperA = GetAluIneg(OperA, NegA); - OperB = GetAluIneg(OperB, NegB); + operA = GetAluIneg(operA, negA); + operB = GetAluIneg(operB, negB); - ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB); + ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Add, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - private static void EmitIadd3(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitIadd3(ShaderIrBlock block, long opCode, ShaderOper oper) { - int Mode = OpCode.Read(37, 3); + int mode = opCode.Read(37, 3); - bool Neg1 = OpCode.Read(51); - bool Neg2 = OpCode.Read(50); - bool Neg3 = OpCode.Read(49); + bool neg1 = opCode.Read(51); + bool neg2 = opCode.Read(50); + bool neg3 = opCode.Read(49); - int Height1 = OpCode.Read(35, 3); - int Height2 = OpCode.Read(33, 3); - int Height3 = OpCode.Read(31, 3); + int height1 = opCode.Read(35, 3); + int height2 = opCode.Read(33, 3); + int height3 = opCode.Read(31, 3); - ShaderIrNode OperB; + ShaderIrNode operB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - ShaderIrNode ApplyHeight(ShaderIrNode Src, int Height) + ShaderIrNode ApplyHeight(ShaderIrNode src, int height) { - if (Oper != ShaderOper.RR) + if (oper != ShaderOper.Rr) { - return Src; + return src; } - switch (Height) + switch (height) { - case 0: return Src; - case 1: return new ShaderIrOp(ShaderIrInst.And, Src, new ShaderIrOperImm(0xffff)); - case 2: return new ShaderIrOp(ShaderIrInst.Lsr, Src, new ShaderIrOperImm(16)); + case 0: return src; + case 1: return new ShaderIrOp(ShaderIrInst.And, src, new ShaderIrOperImm(0xffff)); + case 2: return new ShaderIrOp(ShaderIrInst.Lsr, src, new ShaderIrOperImm(16)); default: throw new InvalidOperationException(); } } - ShaderIrNode Src1 = GetAluIneg(ApplyHeight(OpCode.Gpr8(), Height1), Neg1); - ShaderIrNode Src2 = GetAluIneg(ApplyHeight(OperB, Height2), Neg2); - ShaderIrNode Src3 = GetAluIneg(ApplyHeight(OpCode.Gpr39(), Height3), Neg3); + ShaderIrNode src1 = GetAluIneg(ApplyHeight(opCode.Gpr8(), height1), neg1); + ShaderIrNode src2 = GetAluIneg(ApplyHeight(operB, height2), neg2); + ShaderIrNode src3 = GetAluIneg(ApplyHeight(opCode.Gpr39(), height3), neg3); - ShaderIrOp Sum = new ShaderIrOp(ShaderIrInst.Add, Src1, Src2); + ShaderIrOp sum = new ShaderIrOp(ShaderIrInst.Add, src1, src2); - if (Oper == ShaderOper.RR) + if (oper == ShaderOper.Rr) { - switch (Mode) + switch (mode) { - case 1: Sum = new ShaderIrOp(ShaderIrInst.Lsr, Sum, new ShaderIrOperImm(16)); break; - case 2: Sum = new ShaderIrOp(ShaderIrInst.Lsl, Sum, new ShaderIrOperImm(16)); break; + case 1: sum = new ShaderIrOp(ShaderIrInst.Lsr, sum, new ShaderIrOperImm(16)); break; + case 2: sum = new ShaderIrOp(ShaderIrInst.Lsl, sum, new ShaderIrOperImm(16)); break; } } //Note: Here there should be a "+ 1" when carry flag is set //but since carry is mostly ignored by other instructions, it's excluded for now - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), new ShaderIrOp(ShaderIrInst.Add, Sum, Src3)))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), new ShaderIrOp(ShaderIrInst.Add, sum, src3)))); } - private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitIscadd(ShaderIrBlock block, long opCode, ShaderOper oper) { - bool NegB = OpCode.Read(48); - bool NegA = OpCode.Read(49); + bool negB = opCode.Read(48); + bool negA = opCode.Read(49); - ShaderIrNode OperA = OpCode.Gpr8(), OperB; + ShaderIrNode operA = opCode.Gpr8(), operB; - ShaderIrOperImm Scale = OpCode.Imm5_39(); + ShaderIrOperImm scale = opCode.Imm5_39(); - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperA = GetAluIneg(OperA, NegA); - OperB = GetAluIneg(OperB, NegB); + operA = GetAluIneg(operA, negA); + operB = GetAluIneg(operB, negB); - ShaderIrOp ScaleOp = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Scale); - ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, OperB, ScaleOp); + ShaderIrOp scaleOp = new ShaderIrOp(ShaderIrInst.Lsl, operA, scale); + ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, operB, scaleOp); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp))); } - private static void EmitFmnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitFmnmx(ShaderIrBlock block, long opCode, ShaderOper oper) { - EmitMnmx(Block, OpCode, true, Oper); + EmitMnmx(block, opCode, true, oper); } - private static void EmitImnmx(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitImnmx(ShaderIrBlock block, long opCode, ShaderOper oper) { - EmitMnmx(Block, OpCode, false, Oper); + EmitMnmx(block, opCode, false, oper); } - private static void EmitMnmx(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper) + private static void EmitMnmx(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper) { - bool NegB = OpCode.Read(45); - bool AbsA = OpCode.Read(46); - bool NegA = OpCode.Read(48); - bool AbsB = OpCode.Read(49); + bool negB = opCode.Read(45); + bool absA = opCode.Read(46); + bool negA = opCode.Read(48); + bool absB = opCode.Read(49); - ShaderIrNode OperA = OpCode.Gpr8(), OperB; + ShaderIrNode operA = opCode.Gpr8(), operB; - if (IsFloat) + if (isFloat) { - OperA = GetAluFabsFneg(OperA, AbsA, NegA); + operA = GetAluFabsFneg(operA, absA, negA); } else { - OperA = GetAluIabsIneg(OperA, AbsA, NegA); + operA = GetAluIabsIneg(operA, absA, negA); } - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Immf: operB = opCode.Immf19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - if (IsFloat) + if (isFloat) { - OperB = GetAluFabsFneg(OperB, AbsB, NegB); + operB = GetAluFabsFneg(operB, absB, negB); } else { - OperB = GetAluIabsIneg(OperB, AbsB, NegB); + operB = GetAluIabsIneg(operB, absB, negB); } - ShaderIrOperPred Pred = OpCode.Pred39(); + ShaderIrOperPred pred = opCode.Pred39(); - ShaderIrOp Op; + ShaderIrOp op; - ShaderIrInst MaxInst = IsFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max; - ShaderIrInst MinInst = IsFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min; + ShaderIrInst maxInst = isFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max; + ShaderIrInst minInst = isFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min; - if (Pred.IsConst) + if (pred.IsConst) { - bool IsMax = OpCode.Read(42); + bool isMax = opCode.Read(42); - Op = new ShaderIrOp(IsMax - ? MaxInst - : MinInst, OperA, OperB); + op = new ShaderIrOp(isMax + ? maxInst + : minInst, operA, operB); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } else { - ShaderIrNode PredN = OpCode.Pred39N(); + ShaderIrNode predN = opCode.Pred39N(); - ShaderIrOp OpMax = new ShaderIrOp(MaxInst, OperA, OperB); - ShaderIrOp OpMin = new ShaderIrOp(MinInst, OperA, OperB); + ShaderIrOp opMax = new ShaderIrOp(maxInst, operA, operB); + ShaderIrOp opMin = new ShaderIrOp(minInst, operA, operB); - ShaderIrAsg AsgMax = new ShaderIrAsg(OpCode.Gpr0(), OpMax); - ShaderIrAsg AsgMin = new ShaderIrAsg(OpCode.Gpr0(), OpMin); + ShaderIrAsg asgMax = new ShaderIrAsg(opCode.Gpr0(), opMax); + ShaderIrAsg asgMin = new ShaderIrAsg(opCode.Gpr0(), opMin); - Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMax, Not: true))); - Block.AddNode(OpCode.PredNode(new ShaderIrCond(PredN, AsgMin, Not: false))); + block.AddNode(opCode.PredNode(new ShaderIrCond(predN, asgMax, not: true))); + block.AddNode(opCode.PredNode(new ShaderIrCond(predN, asgMin, not: false))); } } - private static void EmitRro(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitRro(ShaderIrBlock block, long opCode, ShaderOper oper) { //Note: this is a range reduction instruction and is supposed to //be used with Mufu, here it just moves the value and ignores the operation. - bool NegA = OpCode.Read(45); - bool AbsA = OpCode.Read(49); + bool negA = opCode.Read(45); + bool absA = opCode.Read(49); - ShaderIrNode OperA; + ShaderIrNode operA; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperA = OpCode.Cbuf34(); break; - case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperA = OpCode.Gpr20(); break; + case ShaderOper.Cr: operA = opCode.Cbuf34(); break; + case ShaderOper.Immf: operA = opCode.Immf19_20(); break; + case ShaderOper.Rr: operA = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperA = GetAluFabsFneg(OperA, AbsA, NegA); + operA = GetAluFabsFneg(operA, absA, negA); - Block.AddNode(new ShaderIrCmnt("Stubbed.")); + block.AddNode(new ShaderIrCmnt("Stubbed.")); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperA))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA))); } - private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitFset(ShaderIrBlock block, long opCode, ShaderOper oper) { - EmitSet(Block, OpCode, true, Oper); + EmitSet(block, opCode, true, oper); } - private static void EmitIset(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitIset(ShaderIrBlock block, long opCode, ShaderOper oper) { - EmitSet(Block, OpCode, false, Oper); + EmitSet(block, opCode, false, oper); } - private static void EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper) + private static void EmitSet(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper) { - bool NegA = OpCode.Read(43); - bool AbsB = OpCode.Read(44); - bool NegB = OpCode.Read(53); - bool AbsA = OpCode.Read(54); + bool negA = opCode.Read(43); + bool absB = opCode.Read(44); + bool negB = opCode.Read(53); + bool absA = opCode.Read(54); - bool BoolFloat = OpCode.Read(IsFloat ? 52 : 44); + bool boolFloat = opCode.Read(isFloat ? 52 : 44); - ShaderIrNode OperA = OpCode.Gpr8(), OperB; + ShaderIrNode operA = opCode.Gpr8(), operB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Immf: operB = opCode.Immf19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - ShaderIrInst CmpInst; + ShaderIrInst cmpInst; - if (IsFloat) + if (isFloat) { - OperA = GetAluFabsFneg(OperA, AbsA, NegA); - OperB = GetAluFabsFneg(OperB, AbsB, NegB); + operA = GetAluFabsFneg(operA, absA, negA); + operB = GetAluFabsFneg(operB, absB, negB); - CmpInst = OpCode.CmpF(); + cmpInst = opCode.CmpF(); } else { - CmpInst = OpCode.Cmp(); + cmpInst = opCode.Cmp(); } - ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB); + ShaderIrOp op = new ShaderIrOp(cmpInst, operA, operB); - ShaderIrInst LopInst = OpCode.BLop45(); + ShaderIrInst lopInst = opCode.BLop45(); - ShaderIrOperPred PNode = OpCode.Pred39(); + ShaderIrOperPred pNode = opCode.Pred39(); - ShaderIrNode Imm0, Imm1; + ShaderIrNode imm0, imm1; - if (BoolFloat) + if (boolFloat) { - Imm0 = new ShaderIrOperImmf(0); - Imm1 = new ShaderIrOperImmf(1); + imm0 = new ShaderIrOperImmf(0); + imm1 = new ShaderIrOperImmf(1); } else { - Imm0 = new ShaderIrOperImm(0); - Imm1 = new ShaderIrOperImm(-1); + imm0 = new ShaderIrOperImm(0); + imm1 = new ShaderIrOperImm(-1); } - ShaderIrNode Asg0 = new ShaderIrAsg(OpCode.Gpr0(), Imm0); - ShaderIrNode Asg1 = new ShaderIrAsg(OpCode.Gpr0(), Imm1); + ShaderIrNode asg0 = new ShaderIrAsg(opCode.Gpr0(), imm0); + ShaderIrNode asg1 = new ShaderIrAsg(opCode.Gpr0(), imm1); - if (LopInst != ShaderIrInst.Band || !PNode.IsConst) + if (lopInst != ShaderIrInst.Band || !pNode.IsConst) { - ShaderIrOp Op2 = new ShaderIrOp(LopInst, Op, PNode); + ShaderIrOp op2 = new ShaderIrOp(lopInst, op, pNode); - Asg0 = new ShaderIrCond(Op2, Asg0, Not: true); - Asg1 = new ShaderIrCond(Op2, Asg1, Not: false); + asg0 = new ShaderIrCond(op2, asg0, not: true); + asg1 = new ShaderIrCond(op2, asg1, not: false); } else { - Asg0 = new ShaderIrCond(Op, Asg0, Not: true); - Asg1 = new ShaderIrCond(Op, Asg1, Not: false); + asg0 = new ShaderIrCond(op, asg0, not: true); + asg1 = new ShaderIrCond(op, asg1, not: false); } - Block.AddNode(OpCode.PredNode(Asg0)); - Block.AddNode(OpCode.PredNode(Asg1)); + block.AddNode(opCode.PredNode(asg0)); + block.AddNode(opCode.PredNode(asg1)); } - private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitFsetp(ShaderIrBlock block, long opCode, ShaderOper oper) { - EmitSetp(Block, OpCode, true, Oper); + EmitSetp(block, opCode, true, oper); } - private static void EmitIsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitIsetp(ShaderIrBlock block, long opCode, ShaderOper oper) { - EmitSetp(Block, OpCode, false, Oper); + EmitSetp(block, opCode, false, oper); } - private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper) + private static void EmitSetp(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper) { - bool AbsA = OpCode.Read(7); - bool NegP = OpCode.Read(42); - bool NegA = OpCode.Read(43); - bool AbsB = OpCode.Read(44); + bool absA = opCode.Read(7); + bool negP = opCode.Read(42); + bool negA = opCode.Read(43); + bool absB = opCode.Read(44); - ShaderIrNode OperA = OpCode.Gpr8(), OperB; + ShaderIrNode operA = opCode.Gpr8(), operB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.Immf: OperB = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Immf: operB = opCode.Immf19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - ShaderIrInst CmpInst; + ShaderIrInst cmpInst; - if (IsFloat) + if (isFloat) { - OperA = GetAluFabsFneg(OperA, AbsA, NegA); - OperB = GetAluFabs (OperB, AbsB); + operA = GetAluFabsFneg(operA, absA, negA); + operB = GetAluFabs (operB, absB); - CmpInst = OpCode.CmpF(); + cmpInst = opCode.CmpF(); } else { - CmpInst = OpCode.Cmp(); + cmpInst = opCode.Cmp(); } - ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB); + ShaderIrOp op = new ShaderIrOp(cmpInst, operA, operB); - ShaderIrOperPred P0Node = OpCode.Pred3(); - ShaderIrOperPred P1Node = OpCode.Pred0(); - ShaderIrOperPred P2Node = OpCode.Pred39(); + ShaderIrOperPred p0Node = opCode.Pred3(); + ShaderIrOperPred p1Node = opCode.Pred0(); + ShaderIrOperPred p2Node = opCode.Pred39(); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op))); - ShaderIrInst LopInst = OpCode.BLop45(); + ShaderIrInst lopInst = opCode.BLop45(); - if (LopInst == ShaderIrInst.Band && P1Node.IsConst && P2Node.IsConst) + if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst) { return; } - ShaderIrNode P2NNode = P2Node; + ShaderIrNode p2NNode = p2Node; - if (NegP) + if (negP) { - P2NNode = new ShaderIrOp(ShaderIrInst.Bnot, P2NNode); + p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode); } - Op = new ShaderIrOp(ShaderIrInst.Bnot, P0Node); + op = new ShaderIrOp(ShaderIrInst.Bnot, p0Node); - Op = new ShaderIrOp(LopInst, Op, P2NNode); + op = new ShaderIrOp(lopInst, op, p2NNode); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P1Node, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(p1Node, op))); - Op = new ShaderIrOp(LopInst, P0Node, P2NNode); + op = new ShaderIrOp(lopInst, p0Node, p2NNode); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(P0Node, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op))); } - private static void EmitBinaryHalfOp(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst) + private static void EmitBinaryHalfOp(ShaderIrBlock block, long opCode, ShaderIrInst inst) { - bool AbsB = OpCode.Read(30); - bool NegB = OpCode.Read(31); - bool Sat = OpCode.Read(32); - bool AbsA = OpCode.Read(44); + bool absB = opCode.Read(30); + bool negB = opCode.Read(31); + bool sat = opCode.Read(32); + bool absA = opCode.Read(44); - ShaderIrOperGpr[] VecA = OpCode.GprHalfVec8(); - ShaderIrOperGpr[] VecB = OpCode.GprHalfVec20(); + ShaderIrOperGpr[] vecA = opCode.GprHalfVec8(); + ShaderIrOperGpr[] vecB = opCode.GprHalfVec20(); - HalfOutputType OutputType = (HalfOutputType)OpCode.Read(49, 3); + HalfOutputType outputType = (HalfOutputType)opCode.Read(49, 3); - int Elems = OutputType == HalfOutputType.PackedFp16 ? 2 : 1; - int First = OutputType == HalfOutputType.MergeH1 ? 1 : 0; + int elems = outputType == HalfOutputType.PackedFp16 ? 2 : 1; + int first = outputType == HalfOutputType.MergeH1 ? 1 : 0; - for (int Index = First; Index < Elems; Index++) + for (int index = first; index < elems; index++) { - ShaderIrNode OperA = GetAluFabs (VecA[Index], AbsA); - ShaderIrNode OperB = GetAluFabsFneg(VecB[Index], AbsB, NegB); + ShaderIrNode operA = GetAluFabs (vecA[index], absA); + ShaderIrNode operB = GetAluFabsFneg(vecB[index], absB, negB); - ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB); + ShaderIrNode op = new ShaderIrOp(inst, operA, operB); - ShaderIrOperGpr Dst = GetHalfDst(OpCode, OutputType, Index); + ShaderIrOperGpr dst = GetHalfDst(opCode, outputType, index); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, GetAluFsat(Op, Sat)))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, GetAluFsat(op, sat)))); } } - private static ShaderIrOperGpr GetHalfDst(long OpCode, HalfOutputType OutputType, int Index) + private static ShaderIrOperGpr GetHalfDst(long opCode, HalfOutputType outputType, int index) { - switch (OutputType) + switch (outputType) { - case HalfOutputType.PackedFp16: return OpCode.GprHalf0(Index); - case HalfOutputType.Fp32: return OpCode.Gpr0(); - case HalfOutputType.MergeH0: return OpCode.GprHalf0(0); - case HalfOutputType.MergeH1: return OpCode.GprHalf0(1); + case HalfOutputType.PackedFp16: return opCode.GprHalf0(index); + case HalfOutputType.Fp32: return opCode.Gpr0(); + case HalfOutputType.MergeH0: return opCode.GprHalf0(0); + case HalfOutputType.MergeH1: return opCode.GprHalf0(1); } - throw new ArgumentException(nameof(OutputType)); + throw new ArgumentException(nameof(outputType)); } - private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitLop(ShaderIrBlock block, long opCode, ShaderOper oper) { - int SubOp = OpCode.Read(41, 3); + int subOp = opCode.Read(41, 3); - bool InvA = OpCode.Read(39); - bool InvB = OpCode.Read(40); + bool invA = opCode.Read(39); + bool invB = opCode.Read(40); - ShaderIrInst Inst = 0; + ShaderIrInst inst = 0; - switch (SubOp) + switch (subOp) { - case 0: Inst = ShaderIrInst.And; break; - case 1: Inst = ShaderIrInst.Or; break; - case 2: Inst = ShaderIrInst.Xor; break; + case 0: inst = ShaderIrInst.And; break; + case 1: inst = ShaderIrInst.Or; break; + case 2: inst = ShaderIrInst.Xor; break; } - ShaderIrNode OperA = GetAluNot(OpCode.Gpr8(), InvA); - ShaderIrNode OperB; + ShaderIrNode operA = GetAluNot(opCode.Gpr8(), invA); + ShaderIrNode operB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.Imm19_20(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperB = GetAluNot(OperB, InvB); + operB = GetAluNot(operB, invB); - ShaderIrNode Op; + ShaderIrNode op; - if (SubOp < 3) + if (subOp < 3) { - Op = new ShaderIrOp(Inst, OperA, OperB); + op = new ShaderIrOp(inst, operA, operB); } else { - Op = OperB; + op = operB; } - ShaderIrNode Compare = new ShaderIrOp(ShaderIrInst.Cne, Op, new ShaderIrOperImm(0)); + ShaderIrNode compare = new ShaderIrOp(ShaderIrInst.Cne, op, new ShaderIrOperImm(0)); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Pred48(), Compare))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Pred48(), compare))); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } private enum XmadMode @@ -1157,143 +1157,143 @@ namespace Ryujinx.Graphics.Gal.Shader Cbcc = 4 } - private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitXmad(ShaderIrBlock block, long opCode, ShaderOper oper) { - bool SignedA = OpCode.Read(48); - bool SignedB = OpCode.Read(49); - bool HighB = OpCode.Read(52); - bool HighA = OpCode.Read(53); + bool signedA = opCode.Read(48); + bool signedB = opCode.Read(49); + bool highB = opCode.Read(52); + bool highA = opCode.Read(53); - int Mode = OpCode.Read(50, 7); + int mode = opCode.Read(50, 7); - ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC; + ShaderIrNode operA = opCode.Gpr8(), operB, operC; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperB = OpCode.ImmU16_20(); break; - case ShaderOper.RC: OperB = OpCode.Gpr39(); break; - case ShaderOper.RR: OperB = OpCode.Gpr20(); break; + case ShaderOper.Cr: operB = opCode.Cbuf34(); break; + case ShaderOper.Imm: operB = opCode.ImmU16_20(); break; + case ShaderOper.Rc: operB = opCode.Gpr39(); break; + case ShaderOper.Rr: operB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - ShaderIrNode OperB2 = OperB; + ShaderIrNode operB2 = operB; - if (Oper == ShaderOper.Imm) + if (oper == ShaderOper.Imm) { - int Imm = ((ShaderIrOperImm)OperB2).Value; + int imm = ((ShaderIrOperImm)operB2).Value; - if (!HighB) + if (!highB) { - Imm <<= 16; + imm <<= 16; } - if (SignedB) + if (signedB) { - Imm >>= 16; + imm >>= 16; } else { - Imm = (int)((uint)Imm >> 16); + imm = (int)((uint)imm >> 16); } - OperB2 = new ShaderIrOperImm(Imm); + operB2 = new ShaderIrOperImm(imm); } - ShaderIrOperImm Imm16 = new ShaderIrOperImm(16); + ShaderIrOperImm imm16 = new ShaderIrOperImm(16); //If we are working with the lower 16-bits of the A/B operands, //we need to shift the lower 16-bits to the top 16-bits. Later, //they will be right shifted. For U16 types, this will be a logical //right shift, and for S16 types, a arithmetic right shift. - if (!HighA) + if (!highA) { - OperA = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Imm16); + operA = new ShaderIrOp(ShaderIrInst.Lsl, operA, imm16); } - if (!HighB && Oper != ShaderOper.Imm) + if (!highB && oper != ShaderOper.Imm) { - OperB2 = new ShaderIrOp(ShaderIrInst.Lsl, OperB2, Imm16); + operB2 = new ShaderIrOp(ShaderIrInst.Lsl, operB2, imm16); } - ShaderIrInst ShiftA = SignedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr; - ShaderIrInst ShiftB = SignedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr; + ShaderIrInst shiftA = signedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr; + ShaderIrInst shiftB = signedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr; - OperA = new ShaderIrOp(ShiftA, OperA, Imm16); + operA = new ShaderIrOp(shiftA, operA, imm16); - if (Oper != ShaderOper.Imm) + if (oper != ShaderOper.Imm) { - OperB2 = new ShaderIrOp(ShiftB, OperB2, Imm16); + operB2 = new ShaderIrOp(shiftB, operB2, imm16); } - bool ProductShiftLeft = false; - bool Merge = false; + bool productShiftLeft = false; + bool merge = false; - if (Oper == ShaderOper.RC) + if (oper == ShaderOper.Rc) { - OperC = OpCode.Cbuf34(); + operC = opCode.Cbuf34(); } else { - OperC = OpCode.Gpr39(); + operC = opCode.Gpr39(); - ProductShiftLeft = OpCode.Read(36); - Merge = OpCode.Read(37); + productShiftLeft = opCode.Read(36); + merge = opCode.Read(37); } - ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB2); + ShaderIrOp mulOp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB2); - if (ProductShiftLeft) + if (productShiftLeft) { - MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16); + mulOp = new ShaderIrOp(ShaderIrInst.Lsl, mulOp, imm16); } - switch ((XmadMode)Mode) + switch ((XmadMode)mode) { - case XmadMode.Clo: OperC = ExtendTo32(OperC, Signed: false, Size: 16); break; + case XmadMode.Clo: operC = ExtendTo32(operC, signed: false, size: 16); break; - case XmadMode.Chi: OperC = new ShaderIrOp(ShaderIrInst.Lsr, OperC, Imm16); break; + case XmadMode.Chi: operC = new ShaderIrOp(ShaderIrInst.Lsr, operC, imm16); break; case XmadMode.Cbcc: { - ShaderIrOp OperBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16); + ShaderIrOp operBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16); - OperC = new ShaderIrOp(ShaderIrInst.Add, OperC, OperBLsh16); + operC = new ShaderIrOp(ShaderIrInst.Add, operC, operBLsh16); break; } case XmadMode.Csfu: { - ShaderIrOperImm Imm31 = new ShaderIrOperImm(31); + ShaderIrOperImm imm31 = new ShaderIrOperImm(31); - ShaderIrOp SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, OperA, Imm31); - ShaderIrOp SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, OperB2, Imm31); + ShaderIrOp signAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, operA, imm31); + ShaderIrOp signAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, operB2, imm31); - SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustA, Imm16); - SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustB, Imm16); + signAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustA, imm16); + signAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustB, imm16); - ShaderIrOp SignAdjust = new ShaderIrOp(ShaderIrInst.Add, SignAdjustA, SignAdjustB); + ShaderIrOp signAdjust = new ShaderIrOp(ShaderIrInst.Add, signAdjustA, signAdjustB); - OperC = new ShaderIrOp(ShaderIrInst.Sub, OperC, SignAdjust); + operC = new ShaderIrOp(ShaderIrInst.Sub, operC, signAdjust); break; } } - ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC); + ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, mulOp, operC); - if (Merge) + if (merge) { - ShaderIrOperImm Imm16Mask = new ShaderIrOperImm(0xffff); + ShaderIrOperImm imm16Mask = new ShaderIrOperImm(0xffff); - AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, Imm16Mask); - OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16); - AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB); + addOp = new ShaderIrOp(ShaderIrInst.And, addOp, imm16Mask); + operB = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16); + addOp = new ShaderIrOp(ShaderIrInst.Or, addOp, operB); } - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), AddOp))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp))); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs index bc2539bd7e..fc9926934d 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs @@ -4,54 +4,54 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - public static void Bra(ShaderIrBlock Block, long OpCode, int Position) + public static void Bra(ShaderIrBlock block, long opCode, int position) { - if ((OpCode & 0x20) != 0) + if ((opCode & 0x20) != 0) { //This reads the target offset from the constant buffer. //Almost impossible to support with GLSL. throw new NotImplementedException(); } - ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch()); + ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch()); - Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, Imm))); + block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, imm))); } - public static void Exit(ShaderIrBlock Block, long OpCode, int Position) + public static void Exit(ShaderIrBlock block, long opCode, int position) { - int CCode = (int)OpCode & 0x1f; + int cCode = (int)opCode & 0x1f; //TODO: Figure out what the other condition codes mean... - if (CCode == 0xf) + if (cCode == 0xf) { - Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit))); + block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit))); } } - public static void Kil(ShaderIrBlock Block, long OpCode, int Position) + public static void Kil(ShaderIrBlock block, long opCode, int position) { - Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil))); + block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil))); } - public static void Ssy(ShaderIrBlock Block, long OpCode, int Position) + public static void Ssy(ShaderIrBlock block, long opCode, int position) { - if ((OpCode & 0x20) != 0) + if ((opCode & 0x20) != 0) { //This reads the target offset from the constant buffer. //Almost impossible to support with GLSL. throw new NotImplementedException(); } - ShaderIrOperImm Imm = new ShaderIrOperImm(Position + OpCode.Branch()); + ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch()); - Block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, Imm)); + block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, imm)); } - public static void Sync(ShaderIrBlock Block, long OpCode, int Position) + public static void Sync(ShaderIrBlock block, long opCode, int position) { //TODO: Implement Sync condition codes - Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync))); + block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync))); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs index 73248aa0c7..cc385aa4ea 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs @@ -1,4 +1,4 @@ namespace Ryujinx.Graphics.Gal.Shader { - delegate void ShaderDecodeFunc(ShaderIrBlock Block, long OpCode, int Position); + delegate void ShaderDecodeFunc(ShaderIrBlock block, long opCode, int position); } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs index d07bcd9171..9a84e6129c 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs @@ -5,74 +5,74 @@ namespace Ryujinx.Graphics.Gal.Shader private static readonly ShaderIrOperImmf ImmfZero = new ShaderIrOperImmf(0); private static readonly ShaderIrOperImmf ImmfOne = new ShaderIrOperImmf(1); - public static ShaderIrNode GetAluFabsFneg(ShaderIrNode Node, bool Abs, bool Neg) + public static ShaderIrNode GetAluFabsFneg(ShaderIrNode node, bool abs, bool neg) { - return GetAluFneg(GetAluFabs(Node, Abs), Neg); + return GetAluFneg(GetAluFabs(node, abs), neg); } - public static ShaderIrNode GetAluFabs(ShaderIrNode Node, bool Abs) + public static ShaderIrNode GetAluFabs(ShaderIrNode node, bool abs) { - return Abs ? new ShaderIrOp(ShaderIrInst.Fabs, Node) : Node; + return abs ? new ShaderIrOp(ShaderIrInst.Fabs, node) : node; } - public static ShaderIrNode GetAluFneg(ShaderIrNode Node, bool Neg) + public static ShaderIrNode GetAluFneg(ShaderIrNode node, bool neg) { - return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node; + return neg ? new ShaderIrOp(ShaderIrInst.Fneg, node) : node; } - public static ShaderIrNode GetAluFsat(ShaderIrNode Node, bool Sat) + public static ShaderIrNode GetAluFsat(ShaderIrNode node, bool sat) { - return Sat ? new ShaderIrOp(ShaderIrInst.Fclamp, Node, ImmfZero, ImmfOne) : Node; + return sat ? new ShaderIrOp(ShaderIrInst.Fclamp, node, ImmfZero, ImmfOne) : node; } - public static ShaderIrNode GetAluIabsIneg(ShaderIrNode Node, bool Abs, bool Neg) + public static ShaderIrNode GetAluIabsIneg(ShaderIrNode node, bool abs, bool neg) { - return GetAluIneg(GetAluIabs(Node, Abs), Neg); + return GetAluIneg(GetAluIabs(node, abs), neg); } - public static ShaderIrNode GetAluIabs(ShaderIrNode Node, bool Abs) + public static ShaderIrNode GetAluIabs(ShaderIrNode node, bool abs) { - return Abs ? new ShaderIrOp(ShaderIrInst.Abs, Node) : Node; + return abs ? new ShaderIrOp(ShaderIrInst.Abs, node) : node; } - public static ShaderIrNode GetAluIneg(ShaderIrNode Node, bool Neg) + public static ShaderIrNode GetAluIneg(ShaderIrNode node, bool neg) { - return Neg ? new ShaderIrOp(ShaderIrInst.Neg, Node) : Node; + return neg ? new ShaderIrOp(ShaderIrInst.Neg, node) : node; } - public static ShaderIrNode GetAluNot(ShaderIrNode Node, bool Not) + public static ShaderIrNode GetAluNot(ShaderIrNode node, bool not) { - return Not ? new ShaderIrOp(ShaderIrInst.Not, Node) : Node; + return not ? new ShaderIrOp(ShaderIrInst.Not, node) : node; } - public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, int Size) + public static ShaderIrNode ExtendTo32(ShaderIrNode node, bool signed, int size) { - int Shift = 32 - Size; + int shift = 32 - size; - ShaderIrInst RightShift = Signed + ShaderIrInst rightShift = signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; - Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, new ShaderIrOperImm(Shift)); - Node = new ShaderIrOp(RightShift, Node, new ShaderIrOperImm(Shift)); + node = new ShaderIrOp(ShaderIrInst.Lsl, node, new ShaderIrOperImm(shift)); + node = new ShaderIrOp(rightShift, node, new ShaderIrOperImm(shift)); - return Node; + return node; } - public static ShaderIrNode ExtendTo32(ShaderIrNode Node, bool Signed, ShaderIrNode Size) + public static ShaderIrNode ExtendTo32(ShaderIrNode node, bool signed, ShaderIrNode size) { - ShaderIrOperImm WordSize = new ShaderIrOperImm(32); + ShaderIrOperImm wordSize = new ShaderIrOperImm(32); - ShaderIrOp Shift = new ShaderIrOp(ShaderIrInst.Sub, WordSize, Size); + ShaderIrOp shift = new ShaderIrOp(ShaderIrInst.Sub, wordSize, size); - ShaderIrInst RightShift = Signed + ShaderIrInst rightShift = signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; - Node = new ShaderIrOp(ShaderIrInst.Lsl, Node, Shift); - Node = new ShaderIrOp(RightShift, Node, Shift); + node = new ShaderIrOp(ShaderIrInst.Lsl, node, shift); + node = new ShaderIrOp(rightShift, node, shift); - return Node; + return node; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs index 8b4eacdf20..7ce126b0c4 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs @@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { + // ReSharper disable InconsistentNaming private const int ____ = 0x0; private const int R___ = 0x1; private const int _G__ = 0x2; @@ -21,8 +22,9 @@ namespace Ryujinx.Graphics.Gal.Shader private const int R_BA = 0xd; private const int _GBA = 0xe; private const int RGBA = 0xf; + // ReSharper restore InconsistentNaming - private static int[,] MaskLut = new int[,] + private static int[,] _maskLut = new int[,] { { ____, ____, ____, ____, ____, ____, ____, ____ }, { R___, _G__, __B_, ___A, RG__, R__A, _G_A, __BA }, @@ -30,28 +32,28 @@ namespace Ryujinx.Graphics.Gal.Shader { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ } }; - private static GalTextureTarget TexToTextureTarget(int TexType, bool IsArray) + private static GalTextureTarget TexToTextureTarget(int texType, bool isArray) { - switch (TexType) + switch (texType) { case 0: - return IsArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD; + return isArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD; case 2: - return IsArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD; + return isArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD; case 4: - if (IsArray) - throw new InvalidOperationException($"ARRAY bit set on a TEX with 3D texture!"); + if (isArray) + throw new InvalidOperationException("ARRAY bit set on a TEX with 3D texture!"); return GalTextureTarget.ThreeD; case 6: - return IsArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap; + return isArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap; default: throw new InvalidOperationException(); } } - private static GalTextureTarget TexsToTextureTarget(int TexType) + private static GalTextureTarget TexsToTextureTarget(int texType) { - switch (TexType) + switch (texType) { case 0: return GalTextureTarget.OneD; @@ -77,9 +79,9 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static GalTextureTarget TldsToTextureTarget(int TexType) + public static GalTextureTarget TldsToTextureTarget(int texType) { - switch (TexType) + switch (texType) { case 0: case 2: @@ -99,566 +101,566 @@ namespace Ryujinx.Graphics.Gal.Shader } } - public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position) + public static void Ld_A(ShaderIrBlock block, long opCode, int position) { - ShaderIrNode[] Opers = OpCode.Abuf20(); + ShaderIrNode[] opers = opCode.Abuf20(); //Used by GS - ShaderIrOperGpr Vertex = OpCode.Gpr39(); + ShaderIrOperGpr vertex = opCode.Gpr39(); - int Index = 0; + int index = 0; - foreach (ShaderIrNode OperA in Opers) + foreach (ShaderIrNode operA in opers) { - ShaderIrOperGpr OperD = OpCode.Gpr0(); + ShaderIrOperGpr operD = opCode.Gpr0(); - OperD.Index += Index++; + operD.Index += index++; - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, OperA))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, operA))); } } - public static void Ld_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Ld_C(ShaderIrBlock block, long opCode, int position) { - int CbufPos = OpCode.Read(22, 0x3fff); - int CbufIndex = OpCode.Read(36, 0x1f); - int Type = OpCode.Read(48, 7); + int cbufPos = opCode.Read(22, 0x3fff); + int cbufIndex = opCode.Read(36, 0x1f); + int type = opCode.Read(48, 7); - if (Type > 5) + if (type > 5) { throw new InvalidOperationException(); } - ShaderIrOperGpr Temp = ShaderIrOperGpr.MakeTemporary(); + ShaderIrOperGpr temp = ShaderIrOperGpr.MakeTemporary(); - Block.AddNode(new ShaderIrAsg(Temp, OpCode.Gpr8())); + block.AddNode(new ShaderIrAsg(temp, opCode.Gpr8())); - int Count = Type == 5 ? 2 : 1; + int count = type == 5 ? 2 : 1; - for (int Index = 0; Index < Count; Index++) + for (int index = 0; index < count; index++) { - ShaderIrOperCbuf OperA = new ShaderIrOperCbuf(CbufIndex, CbufPos, Temp); + ShaderIrOperCbuf operA = new ShaderIrOperCbuf(cbufIndex, cbufPos, temp); - ShaderIrOperGpr OperD = OpCode.Gpr0(); + ShaderIrOperGpr operD = opCode.Gpr0(); - OperA.Pos += Index; - OperD.Index += Index; + operA.Pos += index; + operD.Index += index; - if (!OperD.IsValidRegister) + if (!operD.IsValidRegister) { break; } - ShaderIrNode Node = OperA; + ShaderIrNode node = operA; - if (Type < 4) + if (type < 4) { //This is a 8 or 16 bits type. - bool Signed = (Type & 1) != 0; + bool signed = (type & 1) != 0; - int Size = 8 << (Type >> 1); + int size = 8 << (type >> 1); - Node = ExtendTo32(Node, Signed, Size); + node = ExtendTo32(node, signed, size); } - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, Node))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, node))); } } - public static void St_A(ShaderIrBlock Block, long OpCode, int Position) + public static void St_A(ShaderIrBlock block, long opCode, int position) { - ShaderIrNode[] Opers = OpCode.Abuf20(); + ShaderIrNode[] opers = opCode.Abuf20(); - int Index = 0; + int index = 0; - foreach (ShaderIrNode OperA in Opers) + foreach (ShaderIrNode operA in opers) { - ShaderIrOperGpr OperD = OpCode.Gpr0(); + ShaderIrOperGpr operD = opCode.Gpr0(); - OperD.Index += Index++; + operD.Index += index++; - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, OperD))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(operA, operD))); } } - public static void Texq(ShaderIrBlock Block, long OpCode, int Position) + public static void Texq(ShaderIrBlock block, long opCode, int position) { - ShaderIrNode OperD = OpCode.Gpr0(); - ShaderIrNode OperA = OpCode.Gpr8(); + ShaderIrNode operD = opCode.Gpr0(); + ShaderIrNode operA = opCode.Gpr8(); - ShaderTexqInfo Info = (ShaderTexqInfo)(OpCode.Read(22, 0x1f)); + ShaderTexqInfo info = (ShaderTexqInfo)(opCode.Read(22, 0x1f)); - ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0); - ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1); + ShaderIrMetaTexq meta0 = new ShaderIrMetaTexq(info, 0); + ShaderIrMetaTexq meta1 = new ShaderIrMetaTexq(info, 1); - ShaderIrNode OperC = OpCode.Imm13_36(); + ShaderIrNode operC = opCode.Imm13_36(); - ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0); - ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1); + ShaderIrOp op0 = new ShaderIrOp(ShaderIrInst.Texq, operA, null, operC, meta0); + ShaderIrOp op1 = new ShaderIrOp(ShaderIrInst.Texq, operA, null, operC, meta1); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperD, Op0))); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OperA, Op1))); //Is this right? + block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, op0))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(operA, op1))); //Is this right? } - public static void Tex(ShaderIrBlock Block, long OpCode, int Position) + public static void Tex(ShaderIrBlock block, long opCode, int position) { - TextureInstructionSuffix Suffix; + TextureInstructionSuffix suffix; - int RawSuffix = OpCode.Read(0x34, 0x38); + int rawSuffix = opCode.Read(0x34, 0x38); - switch (RawSuffix) + switch (rawSuffix) { case 0: - Suffix = TextureInstructionSuffix.None; + suffix = TextureInstructionSuffix.None; break; case 0x8: - Suffix = TextureInstructionSuffix.LZ; + suffix = TextureInstructionSuffix.Lz; break; case 0x10: - Suffix = TextureInstructionSuffix.LB; + suffix = TextureInstructionSuffix.Lb; break; case 0x18: - Suffix = TextureInstructionSuffix.LL; + suffix = TextureInstructionSuffix.Ll; break; case 0x30: - Suffix = TextureInstructionSuffix.LBA; + suffix = TextureInstructionSuffix.Lba; break; case 0x38: - Suffix = TextureInstructionSuffix.LLA; + suffix = TextureInstructionSuffix.Lla; break; default: - throw new InvalidOperationException($"Invalid Suffix for TEX instruction {RawSuffix}"); + throw new InvalidOperationException($"Invalid Suffix for TEX instruction {rawSuffix}"); } - bool IsOffset = OpCode.Read(0x36); + bool isOffset = opCode.Read(0x36); - if (IsOffset) - Suffix |= TextureInstructionSuffix.AOffI; + if (isOffset) + suffix |= TextureInstructionSuffix.AOffI; - EmitTex(Block, OpCode, Suffix, GprHandle: false); + EmitTex(block, opCode, suffix, gprHandle: false); } - public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position) + public static void Tex_B(ShaderIrBlock block, long opCode, int position) { - TextureInstructionSuffix Suffix; + TextureInstructionSuffix suffix; - int RawSuffix = OpCode.Read(0x24, 0xe); + int rawSuffix = opCode.Read(0x24, 0xe); - switch (RawSuffix) + switch (rawSuffix) { case 0: - Suffix = TextureInstructionSuffix.None; + suffix = TextureInstructionSuffix.None; break; case 0x2: - Suffix = TextureInstructionSuffix.LZ; + suffix = TextureInstructionSuffix.Lz; break; case 0x4: - Suffix = TextureInstructionSuffix.LB; + suffix = TextureInstructionSuffix.Lb; break; case 0x6: - Suffix = TextureInstructionSuffix.LL; + suffix = TextureInstructionSuffix.Ll; break; case 0xc: - Suffix = TextureInstructionSuffix.LBA; + suffix = TextureInstructionSuffix.Lba; break; case 0xe: - Suffix = TextureInstructionSuffix.LLA; + suffix = TextureInstructionSuffix.Lla; break; default: - throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {RawSuffix}"); + throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {rawSuffix}"); } - bool IsOffset = OpCode.Read(0x23); + bool isOffset = opCode.Read(0x23); - if (IsOffset) - Suffix |= TextureInstructionSuffix.AOffI; + if (isOffset) + suffix |= TextureInstructionSuffix.AOffI; - EmitTex(Block, OpCode, Suffix, GprHandle: true); + EmitTex(block, opCode, suffix, gprHandle: true); } - private static void EmitTex(ShaderIrBlock Block, long OpCode, TextureInstructionSuffix TextureInstructionSuffix, bool GprHandle) + private static void EmitTex(ShaderIrBlock block, long opCode, TextureInstructionSuffix textureInstructionSuffix, bool gprHandle) { - bool IsArray = OpCode.HasArray(); + bool isArray = opCode.HasArray(); - GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray); + GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray); - bool HasDepthCompare = OpCode.Read(0x32); + bool hasDepthCompare = opCode.Read(0x32); - if (HasDepthCompare) + if (hasDepthCompare) { - TextureInstructionSuffix |= TextureInstructionSuffix.DC; + textureInstructionSuffix |= TextureInstructionSuffix.Dc; } - ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)]; + ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; - int IndexExtraCoord = 0; + int indexExtraCoord = 0; - if (IsArray) + if (isArray) { - IndexExtraCoord++; + indexExtraCoord++; - Coords[Coords.Length - 1] = OpCode.Gpr8(); + coords[coords.Length - 1] = opCode.Gpr8(); } - for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++) + for (int index = 0; index < coords.Length - indexExtraCoord; index++) { - ShaderIrOperGpr CoordReg = OpCode.Gpr8(); + ShaderIrOperGpr coordReg = opCode.Gpr8(); - CoordReg.Index += Index; + coordReg.Index += index; - CoordReg.Index += IndexExtraCoord; + coordReg.Index += indexExtraCoord; - if (!CoordReg.IsValidRegister) + if (!coordReg.IsValidRegister) { - CoordReg.Index = ShaderIrOperGpr.ZRIndex; + coordReg.Index = ShaderIrOperGpr.ZrIndex; } - Coords[Index] = CoordReg; + coords[index] = coordReg; } - int ChMask = OpCode.Read(31, 0xf); + int chMask = opCode.Read(31, 0xf); - ShaderIrOperGpr LevelOfDetail = null; - ShaderIrOperGpr Offset = null; - ShaderIrOperGpr DepthCompare = null; + ShaderIrOperGpr levelOfDetail = null; + ShaderIrOperGpr offset = null; + ShaderIrOperGpr depthCompare = null; // TODO: determine first argument when TEX.B is used - int OperBIndex = GprHandle ? 1 : 0; + int operBIndex = gprHandle ? 1 : 0; - if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0 || - (TextureInstructionSuffix & TextureInstructionSuffix.LB) != 0 || - (TextureInstructionSuffix & TextureInstructionSuffix.LBA) != 0 || - (TextureInstructionSuffix & TextureInstructionSuffix.LLA) != 0) + if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0 || + (textureInstructionSuffix & TextureInstructionSuffix.Lb) != 0 || + (textureInstructionSuffix & TextureInstructionSuffix.Lba) != 0 || + (textureInstructionSuffix & TextureInstructionSuffix.Lla) != 0) { - LevelOfDetail = OpCode.Gpr20(); - LevelOfDetail.Index += OperBIndex; + levelOfDetail = opCode.Gpr20(); + levelOfDetail.Index += operBIndex; - OperBIndex++; + operBIndex++; } - if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) + if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { - Offset = OpCode.Gpr20(); - Offset.Index += OperBIndex; + offset = opCode.Gpr20(); + offset.Index += operBIndex; - OperBIndex++; + operBIndex++; } - if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { - DepthCompare = OpCode.Gpr20(); - DepthCompare.Index += OperBIndex; + depthCompare = opCode.Gpr20(); + depthCompare.Index += operBIndex; - OperBIndex++; + operBIndex++; } // ??? - ShaderIrNode OperC = GprHandle - ? (ShaderIrNode)OpCode.Gpr20() - : (ShaderIrNode)OpCode.Imm13_36(); + ShaderIrNode operC = gprHandle + ? (ShaderIrNode)opCode.Gpr20() + : (ShaderIrNode)opCode.Imm13_36(); - ShaderIrInst Inst = GprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs; + ShaderIrInst inst = gprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs; - Coords = CoordsRegistersToTempRegisters(Block, Coords); + coords = CoordsRegistersToTempRegisters(block, coords); - int RegInc = 0; + int regInc = 0; - for (int Ch = 0; Ch < 4; Ch++) + for (int ch = 0; ch < 4; ch++) { - if (!IsChannelUsed(ChMask, Ch)) + if (!IsChannelUsed(chMask, ch)) { continue; } - ShaderIrOperGpr Dst = OpCode.Gpr0(); + ShaderIrOperGpr dst = opCode.Gpr0(); - Dst.Index += RegInc++; + dst.Index += regInc++; - if (!Dst.IsValidRegister || Dst.IsConst) + if (!dst.IsValidRegister || dst.IsConst) { continue; } - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords) + ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) { - LevelOfDetail = LevelOfDetail, - Offset = Offset, - DepthCompare = DepthCompare + LevelOfDetail = levelOfDetail, + Offset = offset, + DepthCompare = depthCompare }; - ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords.Length > 1 ? Coords[1] : null, OperC, Meta); + ShaderIrOp op = new ShaderIrOp(inst, coords[0], coords.Length > 1 ? coords[1] : null, operC, meta); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } } - public static void Texs(ShaderIrBlock Block, long OpCode, int Position) + public static void Texs(ShaderIrBlock block, long opCode, int position) { - TextureInstructionSuffix Suffix; + TextureInstructionSuffix suffix; - int RawSuffix = OpCode.Read(0x34, 0x1e); + int rawSuffix = opCode.Read(0x34, 0x1e); - switch (RawSuffix) + switch (rawSuffix) { case 0: case 0x4: case 0x10: case 0x16: - Suffix = TextureInstructionSuffix.LZ; + suffix = TextureInstructionSuffix.Lz; break; case 0x6: case 0x1a: - Suffix = TextureInstructionSuffix.LL; + suffix = TextureInstructionSuffix.Ll; break; case 0x8: - Suffix = TextureInstructionSuffix.DC; + suffix = TextureInstructionSuffix.Dc; break; case 0x2: case 0xe: case 0x14: case 0x18: - Suffix = TextureInstructionSuffix.None; + suffix = TextureInstructionSuffix.None; break; case 0xa: - Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.DC; + suffix = TextureInstructionSuffix.Ll | TextureInstructionSuffix.Dc; break; case 0xc: case 0x12: - Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.DC; + suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.Dc; break; default: - throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {RawSuffix}"); + throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {rawSuffix}"); } - GalTextureTarget TextureTarget = TexsToTextureTarget(OpCode.Read(52, 0x1e)); + GalTextureTarget textureTarget = TexsToTextureTarget(opCode.Read(52, 0x1e)); - EmitTexs(Block, OpCode, ShaderIrInst.Texs, TextureTarget, Suffix); + EmitTexs(block, opCode, ShaderIrInst.Texs, textureTarget, suffix); } - public static void Tlds(ShaderIrBlock Block, long OpCode, int Position) + public static void Tlds(ShaderIrBlock block, long opCode, int position) { - TextureInstructionSuffix Suffix; + TextureInstructionSuffix suffix; - int RawSuffix = OpCode.Read(0x34, 0x1e); + int rawSuffix = opCode.Read(0x34, 0x1e); - switch (RawSuffix) + switch (rawSuffix) { case 0: case 0x4: case 0x8: - Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.AOffI; + suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.AOffI; break; case 0xc: - Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.MZ; + suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.Mz; break; case 0xe: case 0x10: - Suffix = TextureInstructionSuffix.LZ; + suffix = TextureInstructionSuffix.Lz; break; case 0x2: case 0xa: - Suffix = TextureInstructionSuffix.LL; + suffix = TextureInstructionSuffix.Ll; break; case 0x18: - Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.AOffI; + suffix = TextureInstructionSuffix.Ll | TextureInstructionSuffix.AOffI; break; default: - throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {RawSuffix}"); + throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {rawSuffix}"); } - GalTextureTarget TextureTarget = TldsToTextureTarget(OpCode.Read(52, 0x1e)); + GalTextureTarget textureTarget = TldsToTextureTarget(opCode.Read(52, 0x1e)); - EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureTarget, Suffix); + EmitTexs(block, opCode, ShaderIrInst.Txlf, textureTarget, suffix); } - public static void Tld4(ShaderIrBlock Block, long OpCode, int Position) + public static void Tld4(ShaderIrBlock block, long opCode, int position) { - TextureInstructionSuffix Suffix; + TextureInstructionSuffix suffix; - int RawSuffix = OpCode.Read(0x34, 0xc); + int rawSuffix = opCode.Read(0x34, 0xc); - switch (RawSuffix) + switch (rawSuffix) { case 0: - Suffix = TextureInstructionSuffix.None; + suffix = TextureInstructionSuffix.None; break; case 0x4: - Suffix = TextureInstructionSuffix.AOffI; + suffix = TextureInstructionSuffix.AOffI; break; case 0x8: - Suffix = TextureInstructionSuffix.PTP; + suffix = TextureInstructionSuffix.Ptp; break; default: - throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {RawSuffix}"); + throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {rawSuffix}"); } - bool IsShadow = OpCode.Read(0x32); + bool isShadow = opCode.Read(0x32); - bool IsArray = OpCode.HasArray(); - int ChMask = OpCode.Read(31, 0xf); + bool isArray = opCode.HasArray(); + int chMask = opCode.Read(31, 0xf); - GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray); + GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray); - if (IsShadow) + if (isShadow) { - Suffix |= TextureInstructionSuffix.DC; + suffix |= TextureInstructionSuffix.Dc; } - EmitTld4(Block, OpCode, TextureTarget, Suffix, ChMask, OpCode.Read(0x38, 0x3), false); + EmitTld4(block, opCode, textureTarget, suffix, chMask, opCode.Read(0x38, 0x3), false); } - public static void Tld4s(ShaderIrBlock Block, long OpCode, int Position) + public static void Tld4S(ShaderIrBlock block, long opCode, int position) { - TextureInstructionSuffix Suffix = TextureInstructionSuffix.None; + TextureInstructionSuffix suffix = TextureInstructionSuffix.None; - bool IsOffset = OpCode.Read(0x33); - bool IsShadow = OpCode.Read(0x32); + bool isOffset = opCode.Read(0x33); + bool isShadow = opCode.Read(0x32); - if (IsOffset) + if (isOffset) { - Suffix |= TextureInstructionSuffix.AOffI; + suffix |= TextureInstructionSuffix.AOffI; } - if (IsShadow) + if (isShadow) { - Suffix |= TextureInstructionSuffix.DC; + suffix |= TextureInstructionSuffix.Dc; } // TLD4S seems to only support 2D textures with RGBA mask? - EmitTld4(Block, OpCode, GalTextureTarget.TwoD, Suffix, RGBA, OpCode.Read(0x34, 0x3), true); + EmitTld4(block, opCode, GalTextureTarget.TwoD, suffix, RGBA, opCode.Read(0x34, 0x3), true); } - private static void EmitTexs(ShaderIrBlock Block, - long OpCode, - ShaderIrInst Inst, - GalTextureTarget TextureTarget, - TextureInstructionSuffix TextureInstructionSuffix) + private static void EmitTexs(ShaderIrBlock block, + long opCode, + ShaderIrInst inst, + GalTextureTarget textureTarget, + TextureInstructionSuffix textureInstructionSuffix) { - if (Inst == ShaderIrInst.Txlf && TextureTarget == GalTextureTarget.CubeArray) + if (inst == ShaderIrInst.Txlf && textureTarget == GalTextureTarget.CubeArray) { throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!"); } - bool IsArray = ImageUtils.IsArray(TextureTarget); + bool isArray = ImageUtils.IsArray(textureTarget); - ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)]; + ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; - ShaderIrOperGpr OperA = OpCode.Gpr8(); - ShaderIrOperGpr OperB = OpCode.Gpr20(); + ShaderIrOperGpr operA = opCode.Gpr8(); + ShaderIrOperGpr operB = opCode.Gpr20(); - ShaderIrOperGpr SuffixExtra = OpCode.Gpr20(); - SuffixExtra.Index += 1; + ShaderIrOperGpr suffixExtra = opCode.Gpr20(); + suffixExtra.Index += 1; - int CoordStartIndex = 0; + int coordStartIndex = 0; - if (IsArray) + if (isArray) { - CoordStartIndex++; - Coords[Coords.Length - 1] = OpCode.Gpr8(); + coordStartIndex++; + coords[coords.Length - 1] = opCode.Gpr8(); } - switch (Coords.Length - CoordStartIndex) + switch (coords.Length - coordStartIndex) { case 1: - Coords[0] = OpCode.Gpr8(); + coords[0] = opCode.Gpr8(); break; case 2: - Coords[0] = OpCode.Gpr8(); - Coords[0].Index += CoordStartIndex; + coords[0] = opCode.Gpr8(); + coords[0].Index += coordStartIndex; break; case 3: - Coords[0] = OpCode.Gpr8(); - Coords[0].Index += CoordStartIndex; + coords[0] = opCode.Gpr8(); + coords[0].Index += coordStartIndex; - Coords[1] = OpCode.Gpr8(); - Coords[1].Index += 1 + CoordStartIndex; + coords[1] = opCode.Gpr8(); + coords[1].Index += 1 + coordStartIndex; break; default: - throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TEXS"); + throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TEXS"); } - int OperBIndex = 0; + int operBIndex = 0; - ShaderIrOperGpr LevelOfDetail = null; - ShaderIrOperGpr Offset = null; - ShaderIrOperGpr DepthCompare = null; + ShaderIrOperGpr levelOfDetail = null; + ShaderIrOperGpr offset = null; + ShaderIrOperGpr depthCompare = null; // OperB is always the last value // Not applicable to 1d textures - if (Coords.Length - CoordStartIndex != 1) + if (coords.Length - coordStartIndex != 1) { - Coords[Coords.Length - CoordStartIndex - 1] = OperB; - OperBIndex++; + coords[coords.Length - coordStartIndex - 1] = operB; + operBIndex++; } // Encoding of TEXS/TLDS is a bit special and change for 2d textures // NOTE: OperA seems to hold at best two args. // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB. - if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureInstructionSuffix != TextureInstructionSuffix.LZ && TextureTarget == GalTextureTarget.TwoD) + if (textureInstructionSuffix != TextureInstructionSuffix.None && textureInstructionSuffix != TextureInstructionSuffix.Lz && textureTarget == GalTextureTarget.TwoD) { - Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8(); - Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1; - OperBIndex--; + coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); + coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; + operBIndex--; } // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?) - if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0) + if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0) { - LevelOfDetail = OpCode.Gpr20(); - LevelOfDetail.Index += OperBIndex; - OperBIndex++; + levelOfDetail = opCode.Gpr20(); + levelOfDetail.Index += operBIndex; + operBIndex++; } - if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) + if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { - Offset = OpCode.Gpr20(); - Offset.Index += OperBIndex; - OperBIndex++; + offset = opCode.Gpr20(); + offset.Index += operBIndex; + operBIndex++; } - if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { - DepthCompare = OpCode.Gpr20(); - DepthCompare.Index += OperBIndex; - OperBIndex++; + depthCompare = opCode.Gpr20(); + depthCompare.Index += operBIndex; + operBIndex++; } - int LutIndex; + int lutIndex; - LutIndex = !OpCode.Gpr0().IsConst ? 1 : 0; - LutIndex |= !OpCode.Gpr28().IsConst ? 2 : 0; + lutIndex = !opCode.Gpr0().IsConst ? 1 : 0; + lutIndex |= !opCode.Gpr28().IsConst ? 2 : 0; - if (LutIndex == 0) + if (lutIndex == 0) { //Both destination registers are RZ, do nothing. return; } - bool Fp16 = !OpCode.Read(59); + bool fp16 = !opCode.Read(59); - int DstIncrement = 0; + int dstIncrement = 0; ShaderIrOperGpr GetDst() { - ShaderIrOperGpr Dst; + ShaderIrOperGpr dst; - if (Fp16) + if (fp16) { //FP16 mode, two components are packed on the two //halfs of a 32-bits register, as two half-float values. - int HalfPart = DstIncrement & 1; + int halfPart = dstIncrement & 1; - switch (LutIndex) + switch (lutIndex) { - case 1: Dst = OpCode.GprHalf0(HalfPart); break; - case 2: Dst = OpCode.GprHalf28(HalfPart); break; - case 3: Dst = (DstIncrement >> 1) != 0 - ? OpCode.GprHalf28(HalfPart) - : OpCode.GprHalf0(HalfPart); break; + case 1: dst = opCode.GprHalf0(halfPart); break; + case 2: dst = opCode.GprHalf28(halfPart); break; + case 3: dst = (dstIncrement >> 1) != 0 + ? opCode.GprHalf28(halfPart) + : opCode.GprHalf0(halfPart); break; default: throw new InvalidOperationException(); } @@ -667,210 +669,210 @@ namespace Ryujinx.Graphics.Gal.Shader { //32-bits mode, each component uses one register. //Two components uses two consecutive registers. - switch (LutIndex) + switch (lutIndex) { - case 1: Dst = OpCode.Gpr0(); break; - case 2: Dst = OpCode.Gpr28(); break; - case 3: Dst = (DstIncrement >> 1) != 0 - ? OpCode.Gpr28() - : OpCode.Gpr0(); break; + case 1: dst = opCode.Gpr0(); break; + case 2: dst = opCode.Gpr28(); break; + case 3: dst = (dstIncrement >> 1) != 0 + ? opCode.Gpr28() + : opCode.Gpr0(); break; default: throw new InvalidOperationException(); } - Dst.Index += DstIncrement & 1; + dst.Index += dstIncrement & 1; } - DstIncrement++; + dstIncrement++; - return Dst; + return dst; } - int ChMask = MaskLut[LutIndex, OpCode.Read(50, 7)]; + int chMask = _maskLut[lutIndex, opCode.Read(50, 7)]; - if (ChMask == 0) + if (chMask == 0) { //All channels are disabled, do nothing. return; } - ShaderIrNode OperC = OpCode.Imm13_36(); - Coords = CoordsRegistersToTempRegisters(Block, Coords); + ShaderIrNode operC = opCode.Imm13_36(); + coords = CoordsRegistersToTempRegisters(block, coords); - for (int Ch = 0; Ch < 4; Ch++) + for (int ch = 0; ch < 4; ch++) { - if (!IsChannelUsed(ChMask, Ch)) + if (!IsChannelUsed(chMask, ch)) { continue; } - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords) + ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) { - LevelOfDetail = LevelOfDetail, - Offset = Offset, - DepthCompare = DepthCompare + LevelOfDetail = levelOfDetail, + Offset = offset, + DepthCompare = depthCompare }; - ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta); + ShaderIrOp op = new ShaderIrOp(inst, operA, operB, operC, meta); - ShaderIrOperGpr Dst = GetDst(); + ShaderIrOperGpr dst = GetDst(); - if (Dst.IsValidRegister && !Dst.IsConst) + if (dst.IsValidRegister && !dst.IsConst) { - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } } } - private static void EmitTld4(ShaderIrBlock Block, long OpCode, GalTextureTarget TextureType, TextureInstructionSuffix TextureInstructionSuffix, int ChMask, int Component, bool Scalar) + private static void EmitTld4(ShaderIrBlock block, long opCode, GalTextureTarget textureType, TextureInstructionSuffix textureInstructionSuffix, int chMask, int component, bool scalar) { - ShaderIrOperGpr OperA = OpCode.Gpr8(); - ShaderIrOperGpr OperB = OpCode.Gpr20(); - ShaderIrOperImm OperC = OpCode.Imm13_36(); + ShaderIrOperGpr operA = opCode.Gpr8(); + ShaderIrOperGpr operB = opCode.Gpr20(); + ShaderIrOperImm operC = opCode.Imm13_36(); - ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureType)]; + ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureType)]; - ShaderIrOperGpr Offset = null; - ShaderIrOperGpr DepthCompare = null; + ShaderIrOperGpr offset = null; + ShaderIrOperGpr depthCompare = null; - bool IsArray = ImageUtils.IsArray(TextureType); + bool isArray = ImageUtils.IsArray(textureType); - int OperBIndex = 0; + int operBIndex = 0; - if (Scalar) + if (scalar) { - int CoordStartIndex = 0; + int coordStartIndex = 0; - if (IsArray) + if (isArray) { - CoordStartIndex++; - Coords[Coords.Length - 1] = OperB; + coordStartIndex++; + coords[coords.Length - 1] = operB; } - switch (Coords.Length - CoordStartIndex) + switch (coords.Length - coordStartIndex) { case 1: - Coords[0] = OpCode.Gpr8(); + coords[0] = opCode.Gpr8(); break; case 2: - Coords[0] = OpCode.Gpr8(); - Coords[0].Index += CoordStartIndex; + coords[0] = opCode.Gpr8(); + coords[0].Index += coordStartIndex; break; case 3: - Coords[0] = OpCode.Gpr8(); - Coords[0].Index += CoordStartIndex; + coords[0] = opCode.Gpr8(); + coords[0].Index += coordStartIndex; - Coords[1] = OpCode.Gpr8(); - Coords[1].Index += 1 + CoordStartIndex; + coords[1] = opCode.Gpr8(); + coords[1].Index += 1 + coordStartIndex; break; default: - throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TLD4S"); + throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TLD4S"); } - if (Coords.Length - CoordStartIndex != 1) + if (coords.Length - coordStartIndex != 1) { - Coords[Coords.Length - CoordStartIndex - 1] = OperB; - OperBIndex++; + coords[coords.Length - coordStartIndex - 1] = operB; + operBIndex++; } - if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureType == GalTextureTarget.TwoD) + if (textureInstructionSuffix != TextureInstructionSuffix.None && textureType == GalTextureTarget.TwoD) { - Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8(); - Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1; - OperBIndex--; + coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); + coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; + operBIndex--; } } else { - int IndexExtraCoord = 0; + int indexExtraCoord = 0; - if (IsArray) + if (isArray) { - IndexExtraCoord++; + indexExtraCoord++; - Coords[Coords.Length - 1] = OpCode.Gpr8(); + coords[coords.Length - 1] = opCode.Gpr8(); } - for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++) + for (int index = 0; index < coords.Length - indexExtraCoord; index++) { - Coords[Index] = OpCode.Gpr8(); + coords[index] = opCode.Gpr8(); - Coords[Index].Index += Index; + coords[index].Index += index; - Coords[Index].Index += IndexExtraCoord; + coords[index].Index += indexExtraCoord; - if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex) + if (coords[index].Index > ShaderIrOperGpr.ZrIndex) { - Coords[Index].Index = ShaderIrOperGpr.ZRIndex; + coords[index].Index = ShaderIrOperGpr.ZrIndex; } } } - if ((TextureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) + if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) { - Offset = OpCode.Gpr20(); - Offset.Index += OperBIndex; - OperBIndex++; + offset = opCode.Gpr20(); + offset.Index += operBIndex; + operBIndex++; } - if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0) + if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) { - DepthCompare = OpCode.Gpr20(); - DepthCompare.Index += OperBIndex; - OperBIndex++; + depthCompare = opCode.Gpr20(); + depthCompare.Index += operBIndex; + operBIndex++; } - Coords = CoordsRegistersToTempRegisters(Block, Coords); + coords = CoordsRegistersToTempRegisters(block, coords); - int RegInc = 0; + int regInc = 0; - for (int Ch = 0; Ch < 4; Ch++) + for (int ch = 0; ch < 4; ch++) { - if (!IsChannelUsed(ChMask, Ch)) + if (!IsChannelUsed(chMask, ch)) { continue; } - ShaderIrOperGpr Dst = OpCode.Gpr0(); + ShaderIrOperGpr dst = opCode.Gpr0(); - Dst.Index += RegInc++; + dst.Index += regInc++; - if (!Dst.IsValidRegister || Dst.IsConst) + if (!dst.IsValidRegister || dst.IsConst) { continue; } - ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords) + ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureType, textureInstructionSuffix, coords) { - Component = Component, - Offset = Offset, - DepthCompare = DepthCompare + Component = component, + Offset = offset, + DepthCompare = depthCompare }; - ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Tld4, OperA, OperB, OperC, Meta); + ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Tld4, operA, operB, operC, meta); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); } } - private static bool IsChannelUsed(int ChMask, int Ch) + private static bool IsChannelUsed(int chMask, int ch) { - return (ChMask & (1 << Ch)) != 0; + return (chMask & (1 << ch)) != 0; } - private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock Block, params ShaderIrOperGpr[] Registers) + private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock block, params ShaderIrOperGpr[] registers) { - ShaderIrOperGpr[] Res = new ShaderIrOperGpr[Registers.Length]; + ShaderIrOperGpr[] res = new ShaderIrOperGpr[registers.Length]; - for (int Index = 0; Index < Res.Length; Index++) + for (int index = 0; index < res.Length; index++) { - Res[Index] = ShaderIrOperGpr.MakeTemporary(Index); - Block.AddNode(new ShaderIrAsg(Res[Index], Registers[Index])); + res[index] = ShaderIrOperGpr.MakeTemporary(index); + block.AddNode(new ShaderIrAsg(res[index], registers[index])); } - return Res; + return res; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs index cd602db7c1..0a2b4232bb 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs @@ -25,400 +25,400 @@ namespace Ryujinx.Graphics.Gal.Shader F64 = 3 } - public static void F2f_C(ShaderIrBlock Block, long OpCode, int Position) + public static void F2f_C(ShaderIrBlock block, long opCode, int position) { - EmitF2f(Block, OpCode, ShaderOper.CR); + EmitF2F(block, opCode, ShaderOper.Cr); } - public static void F2f_I(ShaderIrBlock Block, long OpCode, int Position) + public static void F2f_I(ShaderIrBlock block, long opCode, int position) { - EmitF2f(Block, OpCode, ShaderOper.Immf); + EmitF2F(block, opCode, ShaderOper.Immf); } - public static void F2f_R(ShaderIrBlock Block, long OpCode, int Position) + public static void F2f_R(ShaderIrBlock block, long opCode, int position) { - EmitF2f(Block, OpCode, ShaderOper.RR); + EmitF2F(block, opCode, ShaderOper.Rr); } - public static void F2i_C(ShaderIrBlock Block, long OpCode, int Position) + public static void F2i_C(ShaderIrBlock block, long opCode, int position) { - EmitF2i(Block, OpCode, ShaderOper.CR); + EmitF2I(block, opCode, ShaderOper.Cr); } - public static void F2i_I(ShaderIrBlock Block, long OpCode, int Position) + public static void F2i_I(ShaderIrBlock block, long opCode, int position) { - EmitF2i(Block, OpCode, ShaderOper.Immf); + EmitF2I(block, opCode, ShaderOper.Immf); } - public static void F2i_R(ShaderIrBlock Block, long OpCode, int Position) + public static void F2i_R(ShaderIrBlock block, long opCode, int position) { - EmitF2i(Block, OpCode, ShaderOper.RR); + EmitF2I(block, opCode, ShaderOper.Rr); } - public static void I2f_C(ShaderIrBlock Block, long OpCode, int Position) + public static void I2f_C(ShaderIrBlock block, long opCode, int position) { - EmitI2f(Block, OpCode, ShaderOper.CR); + EmitI2F(block, opCode, ShaderOper.Cr); } - public static void I2f_I(ShaderIrBlock Block, long OpCode, int Position) + public static void I2f_I(ShaderIrBlock block, long opCode, int position) { - EmitI2f(Block, OpCode, ShaderOper.Imm); + EmitI2F(block, opCode, ShaderOper.Imm); } - public static void I2f_R(ShaderIrBlock Block, long OpCode, int Position) + public static void I2f_R(ShaderIrBlock block, long opCode, int position) { - EmitI2f(Block, OpCode, ShaderOper.RR); + EmitI2F(block, opCode, ShaderOper.Rr); } - public static void I2i_C(ShaderIrBlock Block, long OpCode, int Position) + public static void I2i_C(ShaderIrBlock block, long opCode, int position) { - EmitI2i(Block, OpCode, ShaderOper.CR); + EmitI2I(block, opCode, ShaderOper.Cr); } - public static void I2i_I(ShaderIrBlock Block, long OpCode, int Position) + public static void I2i_I(ShaderIrBlock block, long opCode, int position) { - EmitI2i(Block, OpCode, ShaderOper.Imm); + EmitI2I(block, opCode, ShaderOper.Imm); } - public static void I2i_R(ShaderIrBlock Block, long OpCode, int Position) + public static void I2i_R(ShaderIrBlock block, long opCode, int position) { - EmitI2i(Block, OpCode, ShaderOper.RR); + EmitI2I(block, opCode, ShaderOper.Rr); } - public static void Isberd(ShaderIrBlock Block, long OpCode, int Position) + public static void Isberd(ShaderIrBlock block, long opCode, int position) { //This instruction seems to be used to translate from an address to a vertex index in a GS //Stub it as such - Block.AddNode(new ShaderIrCmnt("Stubbed.")); + block.AddNode(new ShaderIrCmnt("Stubbed.")); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OpCode.Gpr8()))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), opCode.Gpr8()))); } - public static void Mov_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Mov_C(ShaderIrBlock block, long opCode, int position) { - ShaderIrOperCbuf Cbuf = OpCode.Cbuf34(); + ShaderIrOperCbuf cbuf = opCode.Cbuf34(); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Cbuf))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), cbuf))); } - public static void Mov_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Mov_I(ShaderIrBlock block, long opCode, int position) { - ShaderIrOperImm Imm = OpCode.Imm19_20(); + ShaderIrOperImm imm = opCode.Imm19_20(); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm))); } - public static void Mov_I32(ShaderIrBlock Block, long OpCode, int Position) + public static void Mov_I32(ShaderIrBlock block, long opCode, int position) { - ShaderIrOperImm Imm = OpCode.Imm32_20(); + ShaderIrOperImm imm = opCode.Imm32_20(); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Imm))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm))); } - public static void Mov_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Mov_R(ShaderIrBlock block, long opCode, int position) { - ShaderIrOperGpr Gpr = OpCode.Gpr20(); + ShaderIrOperGpr gpr = opCode.Gpr20(); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Gpr))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), gpr))); } - public static void Sel_C(ShaderIrBlock Block, long OpCode, int Position) + public static void Sel_C(ShaderIrBlock block, long opCode, int position) { - EmitSel(Block, OpCode, ShaderOper.CR); + EmitSel(block, opCode, ShaderOper.Cr); } - public static void Sel_I(ShaderIrBlock Block, long OpCode, int Position) + public static void Sel_I(ShaderIrBlock block, long opCode, int position) { - EmitSel(Block, OpCode, ShaderOper.Imm); + EmitSel(block, opCode, ShaderOper.Imm); } - public static void Sel_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Sel_R(ShaderIrBlock block, long opCode, int position) { - EmitSel(Block, OpCode, ShaderOper.RR); + EmitSel(block, opCode, ShaderOper.Rr); } - public static void Mov_S(ShaderIrBlock Block, long OpCode, int Position) + public static void Mov_S(ShaderIrBlock block, long opCode, int position) { - Block.AddNode(new ShaderIrCmnt("Stubbed.")); + block.AddNode(new ShaderIrCmnt("Stubbed.")); //Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS - ShaderIrNode Source = new ShaderIrOperImm(0); + ShaderIrNode source = new ShaderIrOperImm(0); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Source))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), source))); } - private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitF2F(ShaderIrBlock block, long opCode, ShaderOper oper) { - bool NegA = OpCode.Read(45); - bool AbsA = OpCode.Read(49); + bool negA = opCode.Read(45); + bool absA = opCode.Read(49); - ShaderIrNode OperA; + ShaderIrNode operA; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperA = OpCode.Cbuf34(); break; - case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperA = OpCode.Gpr20(); break; + case ShaderOper.Cr: operA = opCode.Cbuf34(); break; + case ShaderOper.Immf: operA = opCode.Immf19_20(); break; + case ShaderOper.Rr: operA = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperA = GetAluFabsFneg(OperA, AbsA, NegA); + operA = GetAluFabsFneg(operA, absA, negA); - ShaderIrInst RoundInst = GetRoundInst(OpCode); + ShaderIrInst roundInst = GetRoundInst(opCode); - if (RoundInst != ShaderIrInst.Invalid) + if (roundInst != ShaderIrInst.Invalid) { - OperA = new ShaderIrOp(RoundInst, OperA); + operA = new ShaderIrOp(roundInst, operA); } - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperA))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA))); } - private static void EmitF2i(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitF2I(ShaderIrBlock block, long opCode, ShaderOper oper) { - IntType Type = GetIntType(OpCode); + IntType type = GetIntType(opCode); - if (Type == IntType.U64 || - Type == IntType.S64) + if (type == IntType.U64 || + type == IntType.S64) { //TODO: 64-bits support. //Note: GLSL doesn't support 64-bits integers. throw new NotImplementedException(); } - bool NegA = OpCode.Read(45); - bool AbsA = OpCode.Read(49); + bool negA = opCode.Read(45); + bool absA = opCode.Read(49); - ShaderIrNode OperA; + ShaderIrNode operA; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperA = OpCode.Cbuf34(); break; - case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperA = OpCode.Gpr20(); break; + case ShaderOper.Cr: operA = opCode.Cbuf34(); break; + case ShaderOper.Immf: operA = opCode.Immf19_20(); break; + case ShaderOper.Rr: operA = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperA = GetAluFabsFneg(OperA, AbsA, NegA); + operA = GetAluFabsFneg(operA, absA, negA); - ShaderIrInst RoundInst = GetRoundInst(OpCode); + ShaderIrInst roundInst = GetRoundInst(opCode); - if (RoundInst != ShaderIrInst.Invalid) + if (roundInst != ShaderIrInst.Invalid) { - OperA = new ShaderIrOp(RoundInst, OperA); + operA = new ShaderIrOp(roundInst, operA); } - bool Signed = Type >= IntType.S8; + bool signed = type >= IntType.S8; - int Size = 8 << ((int)Type & 3); + int size = 8 << ((int)type & 3); - if (Size < 32) + if (size < 32) { - uint Mask = uint.MaxValue >> (32 - Size); + uint mask = uint.MaxValue >> (32 - size); - float CMin = 0; - float CMax = Mask; + float cMin = 0; + float cMax = mask; - if (Signed) + if (signed) { - uint HalfMask = Mask >> 1; + uint halfMask = mask >> 1; - CMin -= HalfMask + 1; - CMax = HalfMask; + cMin -= halfMask + 1; + cMax = halfMask; } - ShaderIrOperImmf IMin = new ShaderIrOperImmf(CMin); - ShaderIrOperImmf IMax = new ShaderIrOperImmf(CMax); + ShaderIrOperImmf min = new ShaderIrOperImmf(cMin); + ShaderIrOperImmf max = new ShaderIrOperImmf(cMax); - OperA = new ShaderIrOp(ShaderIrInst.Fclamp, OperA, IMin, IMax); + operA = new ShaderIrOp(ShaderIrInst.Fclamp, operA, min, max); } - ShaderIrInst Inst = Signed + ShaderIrInst inst = signed ? ShaderIrInst.Ftos : ShaderIrInst.Ftou; - ShaderIrNode Op = new ShaderIrOp(Inst, OperA); + ShaderIrNode op = new ShaderIrOp(inst, operA); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - private static void EmitI2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitI2F(ShaderIrBlock block, long opCode, ShaderOper oper) { - IntType Type = GetIntType(OpCode); + IntType type = GetIntType(opCode); - if (Type == IntType.U64 || - Type == IntType.S64) + if (type == IntType.U64 || + type == IntType.S64) { //TODO: 64-bits support. //Note: GLSL doesn't support 64-bits integers. throw new NotImplementedException(); } - int Sel = OpCode.Read(41, 3); + int sel = opCode.Read(41, 3); - bool NegA = OpCode.Read(45); - bool AbsA = OpCode.Read(49); + bool negA = opCode.Read(45); + bool absA = opCode.Read(49); - ShaderIrNode OperA; + ShaderIrNode operA; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperA = OpCode.Cbuf34(); break; - case ShaderOper.Imm: OperA = OpCode.Imm19_20(); break; - case ShaderOper.RR: OperA = OpCode.Gpr20(); break; + case ShaderOper.Cr: operA = opCode.Cbuf34(); break; + case ShaderOper.Imm: operA = opCode.Imm19_20(); break; + case ShaderOper.Rr: operA = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperA = GetAluIabsIneg(OperA, AbsA, NegA); + operA = GetAluIabsIneg(operA, absA, negA); - bool Signed = Type >= IntType.S8; + bool signed = type >= IntType.S8; - int Shift = Sel * 8; + int shift = sel * 8; - int Size = 8 << ((int)Type & 3); + int size = 8 << ((int)type & 3); - if (Shift != 0) + if (shift != 0) { - OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift)); + operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift)); } - if (Size < 32) + if (size < 32) { - OperA = ExtendTo32(OperA, Signed, Size); + operA = ExtendTo32(operA, signed, size); } - ShaderIrInst Inst = Signed + ShaderIrInst inst = signed ? ShaderIrInst.Stof : ShaderIrInst.Utof; - ShaderIrNode Op = new ShaderIrOp(Inst, OperA); + ShaderIrNode op = new ShaderIrOp(inst, operA); - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); } - private static void EmitI2i(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitI2I(ShaderIrBlock block, long opCode, ShaderOper oper) { - IntType Type = GetIntType(OpCode); + IntType type = GetIntType(opCode); - if (Type == IntType.U64 || - Type == IntType.S64) + if (type == IntType.U64 || + type == IntType.S64) { //TODO: 64-bits support. //Note: GLSL doesn't support 64-bits integers. throw new NotImplementedException(); } - int Sel = OpCode.Read(41, 3); + int sel = opCode.Read(41, 3); - bool NegA = OpCode.Read(45); - bool AbsA = OpCode.Read(49); - bool SatA = OpCode.Read(50); + bool negA = opCode.Read(45); + bool absA = opCode.Read(49); + bool satA = opCode.Read(50); - ShaderIrNode OperA; + ShaderIrNode operA; - switch (Oper) + switch (oper) { - case ShaderOper.CR: OperA = OpCode.Cbuf34(); break; - case ShaderOper.Immf: OperA = OpCode.Immf19_20(); break; - case ShaderOper.RR: OperA = OpCode.Gpr20(); break; + case ShaderOper.Cr: operA = opCode.Cbuf34(); break; + case ShaderOper.Immf: operA = opCode.Immf19_20(); break; + case ShaderOper.Rr: operA = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - OperA = GetAluIabsIneg(OperA, AbsA, NegA); + operA = GetAluIabsIneg(operA, absA, negA); - bool Signed = Type >= IntType.S8; + bool signed = type >= IntType.S8; - int Shift = Sel * 8; + int shift = sel * 8; - int Size = 8 << ((int)Type & 3); + int size = 8 << ((int)type & 3); - if (Shift != 0) + if (shift != 0) { - OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift)); + operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift)); } - if (Size < 32) + if (size < 32) { - uint Mask = uint.MaxValue >> (32 - Size); + uint mask = uint.MaxValue >> (32 - size); - if (SatA) + if (satA) { - uint CMin = 0; - uint CMax = Mask; + uint cMin = 0; + uint cMax = mask; - if (Signed) + if (signed) { - uint HalfMask = Mask >> 1; + uint halfMask = mask >> 1; - CMin -= HalfMask + 1; - CMax = HalfMask; + cMin -= halfMask + 1; + cMax = halfMask; } - ShaderIrOperImm IMin = new ShaderIrOperImm((int)CMin); - ShaderIrOperImm IMax = new ShaderIrOperImm((int)CMax); + ShaderIrOperImm min = new ShaderIrOperImm((int)cMin); + ShaderIrOperImm max = new ShaderIrOperImm((int)cMax); - OperA = new ShaderIrOp(Signed + operA = new ShaderIrOp(signed ? ShaderIrInst.Clamps - : ShaderIrInst.Clampu, OperA, IMin, IMax); + : ShaderIrInst.Clampu, operA, min, max); } else { - OperA = ExtendTo32(OperA, Signed, Size); + operA = ExtendTo32(operA, signed, size); } } - Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), OperA))); + block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA))); } - private static void EmitSel(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + private static void EmitSel(ShaderIrBlock block, long opCode, ShaderOper oper) { - ShaderIrOperGpr Dst = OpCode.Gpr0(); - ShaderIrNode Pred = OpCode.Pred39N(); + ShaderIrOperGpr dst = opCode.Gpr0(); + ShaderIrNode pred = opCode.Pred39N(); - ShaderIrNode ResultA = OpCode.Gpr8(); - ShaderIrNode ResultB; + ShaderIrNode resultA = opCode.Gpr8(); + ShaderIrNode resultB; - switch (Oper) + switch (oper) { - case ShaderOper.CR: ResultB = OpCode.Cbuf34(); break; - case ShaderOper.Imm: ResultB = OpCode.Imm19_20(); break; - case ShaderOper.RR: ResultB = OpCode.Gpr20(); break; + case ShaderOper.Cr: resultB = opCode.Cbuf34(); break; + case ShaderOper.Imm: resultB = opCode.Imm19_20(); break; + case ShaderOper.Rr: resultB = opCode.Gpr20(); break; - default: throw new ArgumentException(nameof(Oper)); + default: throw new ArgumentException(nameof(oper)); } - Block.AddNode(OpCode.PredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultA), false))); + block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultA), false))); - Block.AddNode(OpCode.PredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultB), true))); + block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultB), true))); } - private static IntType GetIntType(long OpCode) + private static IntType GetIntType(long opCode) { - bool Signed = OpCode.Read(13); + bool signed = opCode.Read(13); - IntType Type = (IntType)(OpCode.Read(10, 3)); + IntType type = (IntType)(opCode.Read(10, 3)); - if (Signed) + if (signed) { - Type += (int)IntType.S8; + type += (int)IntType.S8; } - return Type; + return type; } - private static FloatType GetFloatType(long OpCode) + private static FloatType GetFloatType(long opCode) { - return (FloatType)(OpCode.Read(8, 3)); + return (FloatType)(opCode.Read(8, 3)); } - private static ShaderIrInst GetRoundInst(long OpCode) + private static ShaderIrInst GetRoundInst(long opCode) { - switch (OpCode.Read(39, 3)) + switch (opCode.Read(39, 3)) { case 1: return ShaderIrInst.Floor; case 2: return ShaderIrInst.Ceil; diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs index e241e1ca58..4b1e404692 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs @@ -4,227 +4,227 @@ namespace Ryujinx.Graphics.Gal.Shader { static partial class ShaderDecode { - private static int Read(this long OpCode, int Position, int Mask) + private static int Read(this long opCode, int position, int mask) { - return (int)(OpCode >> Position) & Mask; + return (int)(opCode >> position) & mask; } - private static bool Read(this long OpCode, int Position) + private static bool Read(this long opCode, int position) { - return ((OpCode >> Position) & 1) != 0; + return ((opCode >> position) & 1) != 0; } - private static int Branch(this long OpCode) + private static int Branch(this long opCode) { - return ((int)(OpCode >> 20) << 8) >> 8; + return ((int)(opCode >> 20) << 8) >> 8; } - private static bool HasArray(this long OpCode) + private static bool HasArray(this long opCode) { - return OpCode.Read(0x1c); + return opCode.Read(0x1c); } - private static ShaderIrOperAbuf[] Abuf20(this long OpCode) + private static ShaderIrOperAbuf[] Abuf20(this long opCode) { - int Abuf = OpCode.Read(20, 0x3ff); - int Size = OpCode.Read(47, 3); + int abuf = opCode.Read(20, 0x3ff); + int size = opCode.Read(47, 3); - ShaderIrOperGpr Vertex = OpCode.Gpr39(); + ShaderIrOperGpr vertex = opCode.Gpr39(); - ShaderIrOperAbuf[] Opers = new ShaderIrOperAbuf[Size + 1]; + ShaderIrOperAbuf[] opers = new ShaderIrOperAbuf[size + 1]; - for (int Index = 0; Index <= Size; Index++) + for (int index = 0; index <= size; index++) { - Opers[Index] = new ShaderIrOperAbuf(Abuf + Index * 4, Vertex); + opers[index] = new ShaderIrOperAbuf(abuf + index * 4, vertex); } - return Opers; + return opers; } - private static ShaderIrOperAbuf Abuf28(this long OpCode) + private static ShaderIrOperAbuf Abuf28(this long opCode) { - int Abuf = OpCode.Read(28, 0x3ff); + int abuf = opCode.Read(28, 0x3ff); - return new ShaderIrOperAbuf(Abuf, OpCode.Gpr39()); + return new ShaderIrOperAbuf(abuf, opCode.Gpr39()); } - private static ShaderIrOperCbuf Cbuf34(this long OpCode) + private static ShaderIrOperCbuf Cbuf34(this long opCode) { return new ShaderIrOperCbuf( - OpCode.Read(34, 0x1f), - OpCode.Read(20, 0x3fff)); + opCode.Read(34, 0x1f), + opCode.Read(20, 0x3fff)); } - private static ShaderIrOperGpr Gpr8(this long OpCode) + private static ShaderIrOperGpr Gpr8(this long opCode) { - return new ShaderIrOperGpr(OpCode.Read(8, 0xff)); + return new ShaderIrOperGpr(opCode.Read(8, 0xff)); } - private static ShaderIrOperGpr Gpr20(this long OpCode) + private static ShaderIrOperGpr Gpr20(this long opCode) { - return new ShaderIrOperGpr(OpCode.Read(20, 0xff)); + return new ShaderIrOperGpr(opCode.Read(20, 0xff)); } - private static ShaderIrOperGpr Gpr39(this long OpCode) + private static ShaderIrOperGpr Gpr39(this long opCode) { - return new ShaderIrOperGpr(OpCode.Read(39, 0xff)); + return new ShaderIrOperGpr(opCode.Read(39, 0xff)); } - private static ShaderIrOperGpr Gpr0(this long OpCode) + private static ShaderIrOperGpr Gpr0(this long opCode) { - return new ShaderIrOperGpr(OpCode.Read(0, 0xff)); + return new ShaderIrOperGpr(opCode.Read(0, 0xff)); } - private static ShaderIrOperGpr Gpr28(this long OpCode) + private static ShaderIrOperGpr Gpr28(this long opCode) { - return new ShaderIrOperGpr(OpCode.Read(28, 0xff)); + return new ShaderIrOperGpr(opCode.Read(28, 0xff)); } - private static ShaderIrOperGpr[] GprHalfVec8(this long OpCode) + private static ShaderIrOperGpr[] GprHalfVec8(this long opCode) { - return GetGprHalfVec2(OpCode.Read(8, 0xff), OpCode.Read(47, 3)); + return GetGprHalfVec2(opCode.Read(8, 0xff), opCode.Read(47, 3)); } - private static ShaderIrOperGpr[] GprHalfVec20(this long OpCode) + private static ShaderIrOperGpr[] GprHalfVec20(this long opCode) { - return GetGprHalfVec2(OpCode.Read(20, 0xff), OpCode.Read(28, 3)); + return GetGprHalfVec2(opCode.Read(20, 0xff), opCode.Read(28, 3)); } - private static ShaderIrOperGpr[] GetGprHalfVec2(int Gpr, int Mask) + private static ShaderIrOperGpr[] GetGprHalfVec2(int gpr, int mask) { - if (Mask == 1) + if (mask == 1) { //This value is used for FP32, the whole 32-bits register //is used as each element on the vector. return new ShaderIrOperGpr[] { - new ShaderIrOperGpr(Gpr), - new ShaderIrOperGpr(Gpr) + new ShaderIrOperGpr(gpr), + new ShaderIrOperGpr(gpr) }; } - ShaderIrOperGpr Low = new ShaderIrOperGpr(Gpr, 0); - ShaderIrOperGpr High = new ShaderIrOperGpr(Gpr, 1); + ShaderIrOperGpr low = new ShaderIrOperGpr(gpr, 0); + ShaderIrOperGpr high = new ShaderIrOperGpr(gpr, 1); return new ShaderIrOperGpr[] { - (Mask & 1) != 0 ? High : Low, - (Mask & 2) != 0 ? High : Low + (mask & 1) != 0 ? high : low, + (mask & 2) != 0 ? high : low }; } - private static ShaderIrOperGpr GprHalf0(this long OpCode, int HalfPart) + private static ShaderIrOperGpr GprHalf0(this long opCode, int halfPart) { - return new ShaderIrOperGpr(OpCode.Read(0, 0xff), HalfPart); + return new ShaderIrOperGpr(opCode.Read(0, 0xff), halfPart); } - private static ShaderIrOperGpr GprHalf28(this long OpCode, int HalfPart) + private static ShaderIrOperGpr GprHalf28(this long opCode, int halfPart) { - return new ShaderIrOperGpr(OpCode.Read(28, 0xff), HalfPart); + return new ShaderIrOperGpr(opCode.Read(28, 0xff), halfPart); } - private static ShaderIrOperImm Imm5_39(this long OpCode) + private static ShaderIrOperImm Imm5_39(this long opCode) { - return new ShaderIrOperImm(OpCode.Read(39, 0x1f)); + return new ShaderIrOperImm(opCode.Read(39, 0x1f)); } - private static ShaderIrOperImm Imm13_36(this long OpCode) + private static ShaderIrOperImm Imm13_36(this long opCode) { - return new ShaderIrOperImm(OpCode.Read(36, 0x1fff)); + return new ShaderIrOperImm(opCode.Read(36, 0x1fff)); } - private static ShaderIrOperImm Imm32_20(this long OpCode) + private static ShaderIrOperImm Imm32_20(this long opCode) { - return new ShaderIrOperImm((int)(OpCode >> 20)); + return new ShaderIrOperImm((int)(opCode >> 20)); } - private static ShaderIrOperImmf Immf32_20(this long OpCode) + private static ShaderIrOperImmf Immf32_20(this long opCode) { - return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(OpCode >> 20))); + return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(opCode >> 20))); } - private static ShaderIrOperImm ImmU16_20(this long OpCode) + private static ShaderIrOperImm ImmU16_20(this long opCode) { - return new ShaderIrOperImm(OpCode.Read(20, 0xffff)); + return new ShaderIrOperImm(opCode.Read(20, 0xffff)); } - private static ShaderIrOperImm Imm19_20(this long OpCode) + private static ShaderIrOperImm Imm19_20(this long opCode) { - int Value = OpCode.Read(20, 0x7ffff); + int value = opCode.Read(20, 0x7ffff); - bool Neg = OpCode.Read(56); + bool neg = opCode.Read(56); - if (Neg) + if (neg) { - Value = -Value; + value = -value; } - return new ShaderIrOperImm(Value); + return new ShaderIrOperImm(value); } - private static ShaderIrOperImmf Immf19_20(this long OpCode) + private static ShaderIrOperImmf Immf19_20(this long opCode) { - uint Imm = (uint)(OpCode >> 20) & 0x7ffff; + uint imm = (uint)(opCode >> 20) & 0x7ffff; - bool Neg = OpCode.Read(56); + bool neg = opCode.Read(56); - Imm <<= 12; + imm <<= 12; - if (Neg) + if (neg) { - Imm |= 0x80000000; + imm |= 0x80000000; } - float Value = BitConverter.Int32BitsToSingle((int)Imm); + float value = BitConverter.Int32BitsToSingle((int)imm); - return new ShaderIrOperImmf(Value); + return new ShaderIrOperImmf(value); } - private static ShaderIrOperPred Pred0(this long OpCode) + private static ShaderIrOperPred Pred0(this long opCode) { - return new ShaderIrOperPred(OpCode.Read(0, 7)); + return new ShaderIrOperPred(opCode.Read(0, 7)); } - private static ShaderIrOperPred Pred3(this long OpCode) + private static ShaderIrOperPred Pred3(this long opCode) { - return new ShaderIrOperPred(OpCode.Read(3, 7)); + return new ShaderIrOperPred(opCode.Read(3, 7)); } - private static ShaderIrOperPred Pred12(this long OpCode) + private static ShaderIrOperPred Pred12(this long opCode) { - return new ShaderIrOperPred(OpCode.Read(12, 7)); + return new ShaderIrOperPred(opCode.Read(12, 7)); } - private static ShaderIrOperPred Pred29(this long OpCode) + private static ShaderIrOperPred Pred29(this long opCode) { - return new ShaderIrOperPred(OpCode.Read(29, 7)); + return new ShaderIrOperPred(opCode.Read(29, 7)); } - private static ShaderIrNode Pred39N(this long OpCode) + private static ShaderIrNode Pred39N(this long opCode) { - ShaderIrNode Node = OpCode.Pred39(); + ShaderIrNode node = opCode.Pred39(); - if (OpCode.Read(42)) + if (opCode.Read(42)) { - Node = new ShaderIrOp(ShaderIrInst.Bnot, Node); + node = new ShaderIrOp(ShaderIrInst.Bnot, node); } - return Node; + return node; } - private static ShaderIrOperPred Pred39(this long OpCode) + private static ShaderIrOperPred Pred39(this long opCode) { - return new ShaderIrOperPred(OpCode.Read(39, 7)); + return new ShaderIrOperPred(opCode.Read(39, 7)); } - private static ShaderIrOperPred Pred48(this long OpCode) + private static ShaderIrOperPred Pred48(this long opCode) { - return new ShaderIrOperPred(OpCode.Read(48, 7)); + return new ShaderIrOperPred(opCode.Read(48, 7)); } - private static ShaderIrInst Cmp(this long OpCode) + private static ShaderIrInst Cmp(this long opCode) { - switch (OpCode.Read(49, 7)) + switch (opCode.Read(49, 7)) { case 1: return ShaderIrInst.Clt; case 2: return ShaderIrInst.Ceq; @@ -234,12 +234,12 @@ namespace Ryujinx.Graphics.Gal.Shader case 6: return ShaderIrInst.Cge; } - throw new ArgumentException(nameof(OpCode)); + throw new ArgumentException(nameof(opCode)); } - private static ShaderIrInst CmpF(this long OpCode) + private static ShaderIrInst CmpF(this long opCode) { - switch (OpCode.Read(48, 0xf)) + switch (opCode.Read(48, 0xf)) { case 0x1: return ShaderIrInst.Fclt; case 0x2: return ShaderIrInst.Fceq; @@ -257,57 +257,57 @@ namespace Ryujinx.Graphics.Gal.Shader case 0xe: return ShaderIrInst.Fcgeu; } - throw new ArgumentException(nameof(OpCode)); + throw new ArgumentException(nameof(opCode)); } - private static ShaderIrInst BLop45(this long OpCode) + private static ShaderIrInst BLop45(this long opCode) { - switch (OpCode.Read(45, 3)) + switch (opCode.Read(45, 3)) { case 0: return ShaderIrInst.Band; case 1: return ShaderIrInst.Bor; case 2: return ShaderIrInst.Bxor; } - throw new ArgumentException(nameof(OpCode)); + throw new ArgumentException(nameof(opCode)); } - private static ShaderIrInst BLop24(this long OpCode) + private static ShaderIrInst BLop24(this long opCode) { - switch (OpCode.Read(24, 3)) + switch (opCode.Read(24, 3)) { case 0: return ShaderIrInst.Band; case 1: return ShaderIrInst.Bor; case 2: return ShaderIrInst.Bxor; } - throw new ArgumentException(nameof(OpCode)); + throw new ArgumentException(nameof(opCode)); } - private static ShaderIrNode PredNode(this long OpCode, ShaderIrNode Node) + private static ShaderIrNode PredNode(this long opCode, ShaderIrNode node) { - ShaderIrOperPred Pred = OpCode.PredNode(); + ShaderIrOperPred pred = opCode.PredNode(); - if (Pred.Index != ShaderIrOperPred.UnusedIndex) + if (pred.Index != ShaderIrOperPred.UnusedIndex) { - bool Inv = OpCode.Read(19); + bool inv = opCode.Read(19); - Node = new ShaderIrCond(Pred, Node, Inv); + node = new ShaderIrCond(pred, node, inv); } - return Node; + return node; } - private static ShaderIrOperPred PredNode(this long OpCode) + private static ShaderIrOperPred PredNode(this long opCode) { - int Pred = OpCode.Read(16, 0xf); + int pred = opCode.Read(16, 0xf); - if (Pred != 0xf) + if (pred != 0xf) { - Pred &= 7; + pred &= 7; } - return new ShaderIrOperPred(Pred); + return new ShaderIrOperPred(pred); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs index 35abdb7641..9098ca5e55 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs @@ -2,23 +2,23 @@ { static partial class ShaderDecode { - public static void Out_R(ShaderIrBlock Block, long OpCode, int Position) + public static void Out_R(ShaderIrBlock block, long opCode, int position) { //TODO: Those registers have to be used for something - ShaderIrOperGpr Gpr0 = OpCode.Gpr0(); - ShaderIrOperGpr Gpr8 = OpCode.Gpr8(); - ShaderIrOperGpr Gpr20 = OpCode.Gpr20(); + ShaderIrOperGpr gpr0 = opCode.Gpr0(); + ShaderIrOperGpr gpr8 = opCode.Gpr8(); + ShaderIrOperGpr gpr20 = opCode.Gpr20(); - int Type = OpCode.Read(39, 3); + int type = opCode.Read(39, 3); - if ((Type & 1) != 0) + if ((type & 1) != 0) { - Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Emit))); + block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Emit))); } - if ((Type & 2) != 0) + if ((type & 2) != 0) { - Block.AddNode(OpCode.PredNode(new ShaderIrOp(ShaderIrInst.Cut))); + block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Cut))); } } } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs index f8c07f31ab..4b23f8d0fa 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs @@ -8,74 +8,74 @@ namespace Ryujinx.Graphics.Gal.Shader private const bool AddDbgComments = true; - public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start) + public static ShaderIrBlock[] Decode(IGalMemory memory, long start) { - Dictionary Visited = new Dictionary(); - Dictionary VisitedEnd = new Dictionary(); + Dictionary visited = new Dictionary(); + Dictionary visitedEnd = new Dictionary(); - Queue Blocks = new Queue(); + Queue blocks = new Queue(); - long Beginning = Start + HeaderSize; + long beginning = start + HeaderSize; - ShaderIrBlock Enqueue(int Position, ShaderIrBlock Source = null) + ShaderIrBlock Enqueue(int position, ShaderIrBlock source = null) { - if (!Visited.TryGetValue(Position, out ShaderIrBlock Output)) + if (!visited.TryGetValue(position, out ShaderIrBlock output)) { - Output = new ShaderIrBlock(Position); + output = new ShaderIrBlock(position); - Blocks.Enqueue(Output); + blocks.Enqueue(output); - Visited.Add(Position, Output); + visited.Add(position, output); } - if (Source != null) + if (source != null) { - Output.Sources.Add(Source); + output.Sources.Add(source); } - return Output; + return output; } - ShaderIrBlock Entry = Enqueue(0); + ShaderIrBlock entry = Enqueue(0); - while (Blocks.Count > 0) + while (blocks.Count > 0) { - ShaderIrBlock Current = Blocks.Dequeue(); + ShaderIrBlock current = blocks.Dequeue(); - FillBlock(Memory, Current, Beginning); + FillBlock(memory, current, beginning); //Set child blocks. "Branch" is the block the branch instruction //points to (when taken), "Next" is the block at the next address, //executed when the branch is not taken. For Unconditional Branches //or end of shader, Next is null. - if (Current.Nodes.Count > 0) + if (current.Nodes.Count > 0) { - ShaderIrNode LastNode = Current.GetLastNode(); + ShaderIrNode lastNode = current.GetLastNode(); - ShaderIrOp InnerOp = GetInnermostOp(LastNode); + ShaderIrOp innerOp = GetInnermostOp(lastNode); - if (InnerOp?.Inst == ShaderIrInst.Bra) + if (innerOp?.Inst == ShaderIrInst.Bra) { - int Target = ((ShaderIrOperImm)InnerOp.OperandA).Value; + int target = ((ShaderIrOperImm)innerOp.OperandA).Value; - Current.Branch = Enqueue(Target, Current); + current.Branch = Enqueue(target, current); } - foreach (ShaderIrNode Node in Current.Nodes) + foreach (ShaderIrNode node in current.Nodes) { - InnerOp = GetInnermostOp(Node); + innerOp = GetInnermostOp(node); - if (InnerOp is ShaderIrOp CurrOp && CurrOp.Inst == ShaderIrInst.Ssy) + if (innerOp is ShaderIrOp currOp && currOp.Inst == ShaderIrInst.Ssy) { - int Target = ((ShaderIrOperImm)CurrOp.OperandA).Value; + int target = ((ShaderIrOperImm)currOp.OperandA).Value; - Enqueue(Target, Current); + Enqueue(target, current); } } - if (NodeHasNext(LastNode)) + if (NodeHasNext(lastNode)) { - Current.Next = Enqueue(Current.EndPosition); + current.Next = Enqueue(current.EndPosition); } } @@ -83,136 +83,136 @@ namespace Ryujinx.Graphics.Gal.Shader //then we need to split the bigger block and have two small blocks, //the end position of the bigger "Current" block should then be == to //the position of the "Smaller" block. - while (VisitedEnd.TryGetValue(Current.EndPosition, out ShaderIrBlock Smaller)) + while (visitedEnd.TryGetValue(current.EndPosition, out ShaderIrBlock smaller)) { - if (Current.Position > Smaller.Position) + if (current.Position > smaller.Position) { - ShaderIrBlock Temp = Smaller; + ShaderIrBlock temp = smaller; - Smaller = Current; - Current = Temp; + smaller = current; + current = temp; } - Current.EndPosition = Smaller.Position; - Current.Next = Smaller; - Current.Branch = null; + current.EndPosition = smaller.Position; + current.Next = smaller; + current.Branch = null; - Current.Nodes.RemoveRange( - Current.Nodes.Count - Smaller.Nodes.Count, - Smaller.Nodes.Count); + current.Nodes.RemoveRange( + current.Nodes.Count - smaller.Nodes.Count, + smaller.Nodes.Count); - VisitedEnd[Smaller.EndPosition] = Smaller; + visitedEnd[smaller.EndPosition] = smaller; } - VisitedEnd.Add(Current.EndPosition, Current); + visitedEnd.Add(current.EndPosition, current); } //Make and sort Graph blocks array by position. - ShaderIrBlock[] Graph = new ShaderIrBlock[Visited.Count]; + ShaderIrBlock[] graph = new ShaderIrBlock[visited.Count]; - while (Visited.Count > 0) + while (visited.Count > 0) { - uint FirstPos = uint.MaxValue; + uint firstPos = uint.MaxValue; - foreach (ShaderIrBlock Block in Visited.Values) + foreach (ShaderIrBlock block in visited.Values) { - if (FirstPos > (uint)Block.Position) - FirstPos = (uint)Block.Position; + if (firstPos > (uint)block.Position) + firstPos = (uint)block.Position; } - ShaderIrBlock Current = Visited[(int)FirstPos]; + ShaderIrBlock current = visited[(int)firstPos]; do { - Graph[Graph.Length - Visited.Count] = Current; + graph[graph.Length - visited.Count] = current; - Visited.Remove(Current.Position); + visited.Remove(current.Position); - Current = Current.Next; + current = current.Next; } - while (Current != null); + while (current != null); } - return Graph; + return graph; } - private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning) + private static void FillBlock(IGalMemory memory, ShaderIrBlock block, long beginning) { - int Position = Block.Position; + int position = block.Position; do { //Ignore scheduling instructions, which are written every 32 bytes. - if ((Position & 0x1f) == 0) + if ((position & 0x1f) == 0) { - Position += 8; + position += 8; continue; } - uint Word0 = (uint)Memory.ReadInt32(Position + Beginning + 0); - uint Word1 = (uint)Memory.ReadInt32(Position + Beginning + 4); + uint word0 = (uint)memory.ReadInt32(position + beginning + 0); + uint word1 = (uint)memory.ReadInt32(position + beginning + 4); - Position += 8; + position += 8; - long OpCode = Word0 | (long)Word1 << 32; + long opCode = word0 | (long)word1 << 32; - ShaderDecodeFunc Decode = ShaderOpCodeTable.GetDecoder(OpCode); + ShaderDecodeFunc decode = ShaderOpCodeTable.GetDecoder(opCode); if (AddDbgComments) { - string DbgOpCode = $"0x{(Position - 8):x16}: 0x{OpCode:x16} "; + string dbgOpCode = $"0x{(position - 8):x16}: 0x{opCode:x16} "; - DbgOpCode += (Decode?.Method.Name ?? "???"); + dbgOpCode += (decode?.Method.Name ?? "???"); - if (Decode == ShaderDecode.Bra || Decode == ShaderDecode.Ssy) + if (decode == ShaderDecode.Bra || decode == ShaderDecode.Ssy) { - int Offset = ((int)(OpCode >> 20) << 8) >> 8; + int offset = ((int)(opCode >> 20) << 8) >> 8; - long Target = Position + Offset; + long target = position + offset; - DbgOpCode += " (0x" + Target.ToString("x16") + ")"; + dbgOpCode += " (0x" + target.ToString("x16") + ")"; } - Block.AddNode(new ShaderIrCmnt(DbgOpCode)); + block.AddNode(new ShaderIrCmnt(dbgOpCode)); } - if (Decode == null) + if (decode == null) { continue; } - Decode(Block, OpCode, Position); + decode(block, opCode, position); } - while (!IsFlowChange(Block.GetLastNode())); + while (!IsFlowChange(block.GetLastNode())); - Block.EndPosition = Position; + block.EndPosition = position; } - private static bool IsFlowChange(ShaderIrNode Node) + private static bool IsFlowChange(ShaderIrNode node) { - return !NodeHasNext(GetInnermostOp(Node)); + return !NodeHasNext(GetInnermostOp(node)); } - private static ShaderIrOp GetInnermostOp(ShaderIrNode Node) + private static ShaderIrOp GetInnermostOp(ShaderIrNode node) { - if (Node is ShaderIrCond Cond) + if (node is ShaderIrCond cond) { - Node = Cond.Child; + node = cond.Child; } - return Node is ShaderIrOp Op ? Op : null; + return node is ShaderIrOp op ? op : null; } - private static bool NodeHasNext(ShaderIrNode Node) + private static bool NodeHasNext(ShaderIrNode node) { - if (!(Node is ShaderIrOp Op)) + if (!(node is ShaderIrOp op)) { return true; } - return Op.Inst != ShaderIrInst.Exit && - Op.Inst != ShaderIrInst.Bra; + return op.Inst != ShaderIrInst.Exit && + op.Inst != ShaderIrInst.Bra; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs index eca90fc3aa..2f9326e121 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs @@ -11,9 +11,9 @@ namespace Ryujinx.Graphics.Gal.Shader public bool Enabled => Red || Green || Blue || Alpha; - public bool ComponentEnabled(int Component) + public bool ComponentEnabled(int component) { - switch (Component) + switch (component) { case 0: return Red; case 1: return Green; @@ -21,7 +21,7 @@ namespace Ryujinx.Graphics.Gal.Shader case 3: return Alpha; } - throw new ArgumentException(nameof(Component)); + throw new ArgumentException(nameof(component)); } } @@ -59,88 +59,88 @@ namespace Ryujinx.Graphics.Gal.Shader public bool OmapSampleMask { get; private set; } public bool OmapDepth { get; private set; } - public ShaderHeader(IGalMemory Memory, long Position) + public ShaderHeader(IGalMemory memory, long position) { - uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0); - uint CommonWord1 = (uint)Memory.ReadInt32(Position + 4); - uint CommonWord2 = (uint)Memory.ReadInt32(Position + 8); - uint CommonWord3 = (uint)Memory.ReadInt32(Position + 12); - uint CommonWord4 = (uint)Memory.ReadInt32(Position + 16); + uint commonWord0 = (uint)memory.ReadInt32(position + 0); + uint commonWord1 = (uint)memory.ReadInt32(position + 4); + uint commonWord2 = (uint)memory.ReadInt32(position + 8); + uint commonWord3 = (uint)memory.ReadInt32(position + 12); + uint commonWord4 = (uint)memory.ReadInt32(position + 16); - SphType = ReadBits(CommonWord0, 0, 5); - Version = ReadBits(CommonWord0, 5, 5); - ShaderType = ReadBits(CommonWord0, 10, 4); - MrtEnable = ReadBits(CommonWord0, 14, 1) != 0; - KillsPixels = ReadBits(CommonWord0, 15, 1) != 0; - DoesGlobalStore = ReadBits(CommonWord0, 16, 1) != 0; - SassVersion = ReadBits(CommonWord0, 17, 4); - DoesLoadOrStore = ReadBits(CommonWord0, 26, 1) != 0; - DoesFp64 = ReadBits(CommonWord0, 27, 1) != 0; - StreamOutMask = ReadBits(CommonWord0, 28, 4); + SphType = ReadBits(commonWord0, 0, 5); + Version = ReadBits(commonWord0, 5, 5); + ShaderType = ReadBits(commonWord0, 10, 4); + MrtEnable = ReadBits(commonWord0, 14, 1) != 0; + KillsPixels = ReadBits(commonWord0, 15, 1) != 0; + DoesGlobalStore = ReadBits(commonWord0, 16, 1) != 0; + SassVersion = ReadBits(commonWord0, 17, 4); + DoesLoadOrStore = ReadBits(commonWord0, 26, 1) != 0; + DoesFp64 = ReadBits(commonWord0, 27, 1) != 0; + StreamOutMask = ReadBits(commonWord0, 28, 4); - ShaderLocalMemoryLowSize = ReadBits(CommonWord1, 0, 24); - PerPatchAttributeCount = ReadBits(CommonWord1, 24, 8); + ShaderLocalMemoryLowSize = ReadBits(commonWord1, 0, 24); + PerPatchAttributeCount = ReadBits(commonWord1, 24, 8); - ShaderLocalMemoryHighSize = ReadBits(CommonWord2, 0, 24); - ThreadsPerInputPrimitive = ReadBits(CommonWord2, 24, 8); + ShaderLocalMemoryHighSize = ReadBits(commonWord2, 0, 24); + ThreadsPerInputPrimitive = ReadBits(commonWord2, 24, 8); - ShaderLocalMemoryCrsSize = ReadBits(CommonWord3, 0, 24); - OutputTopology = ReadBits(CommonWord3, 24, 4); + ShaderLocalMemoryCrsSize = ReadBits(commonWord3, 0, 24); + OutputTopology = ReadBits(commonWord3, 24, 4); - MaxOutputVertexCount = ReadBits(CommonWord4, 0, 12); - StoreReqStart = ReadBits(CommonWord4, 12, 8); - StoreReqEnd = ReadBits(CommonWord4, 24, 8); + MaxOutputVertexCount = ReadBits(commonWord4, 0, 12); + StoreReqStart = ReadBits(commonWord4, 12, 8); + StoreReqEnd = ReadBits(commonWord4, 24, 8); //Type 2 (fragment?) reading - uint Type2OmapTarget = (uint)Memory.ReadInt32(Position + 72); - uint Type2Omap = (uint)Memory.ReadInt32(Position + 76); + uint type2OmapTarget = (uint)memory.ReadInt32(position + 72); + uint type2Omap = (uint)memory.ReadInt32(position + 76); OmapTargets = new OmapTarget[8]; for (int i = 0; i < OmapTargets.Length; i++) { - int Offset = i * 4; + int offset = i * 4; OmapTargets[i] = new OmapTarget { - Red = ReadBits(Type2OmapTarget, Offset + 0, 1) != 0, - Green = ReadBits(Type2OmapTarget, Offset + 1, 1) != 0, - Blue = ReadBits(Type2OmapTarget, Offset + 2, 1) != 0, - Alpha = ReadBits(Type2OmapTarget, Offset + 3, 1) != 0 + Red = ReadBits(type2OmapTarget, offset + 0, 1) != 0, + Green = ReadBits(type2OmapTarget, offset + 1, 1) != 0, + Blue = ReadBits(type2OmapTarget, offset + 2, 1) != 0, + Alpha = ReadBits(type2OmapTarget, offset + 3, 1) != 0 }; } - OmapSampleMask = ReadBits(Type2Omap, 0, 1) != 0; - OmapDepth = ReadBits(Type2Omap, 1, 1) != 0; + OmapSampleMask = ReadBits(type2Omap, 0, 1) != 0; + OmapDepth = ReadBits(type2Omap, 1, 1) != 0; } public int DepthRegister { get { - int Count = 0; + int count = 0; - for (int Index = 0; Index < OmapTargets.Length; Index++) + for (int index = 0; index < OmapTargets.Length; index++) { - for (int Component = 0; Component < 4; Component++) + for (int component = 0; component < 4; component++) { - if (OmapTargets[Index].ComponentEnabled(Component)) + if (OmapTargets[index].ComponentEnabled(component)) { - Count++; + count++; } } } // Depth register is always two registers after the last color output - return Count + 1; + return count + 1; } } - private static int ReadBits(uint Word, int Offset, int BitWidth) + private static int ReadBits(uint word, int offset, int bitWidth) { - uint Mask = (1u << BitWidth) - 1u; + uint mask = (1u << bitWidth) - 1u; - return (int)((Word >> Offset) & Mask); + return (int)((word >> offset) & mask); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs index 00f8f6a5e5..53871a1451 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs @@ -5,10 +5,10 @@ namespace Ryujinx.Graphics.Gal.Shader public ShaderIrNode Dst { get; set; } public ShaderIrNode Src { get; set; } - public ShaderIrAsg(ShaderIrNode Dst, ShaderIrNode Src) + public ShaderIrAsg(ShaderIrNode dst, ShaderIrNode src) { - this.Dst = Dst; - this.Src = Src; + Dst = dst; + Src = src; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs index 782f96261b..49257d2834 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs @@ -14,18 +14,18 @@ namespace Ryujinx.Graphics.Gal.Shader public List Nodes { get; private set; } - public ShaderIrBlock(int Position) + public ShaderIrBlock(int position) { - this.Position = Position; + Position = position; Sources = new List(); Nodes = new List(); } - public void AddNode(ShaderIrNode Node) + public void AddNode(ShaderIrNode node) { - Nodes.Add(Node); + Nodes.Add(node); } public ShaderIrNode[] GetNodes() diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs index 03031ec5b7..5da04e5ee2 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs @@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader { public string Comment { get; private set; } - public ShaderIrCmnt(string Comment) + public ShaderIrCmnt(string comment) { - this.Comment = Comment; + Comment = comment; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs index 8fb01660cf..34acf90d7e 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs @@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal.Shader public bool Not { get; private set; } - public ShaderIrCond(ShaderIrNode Pred, ShaderIrNode Child, bool Not) + public ShaderIrCond(ShaderIrNode pred, ShaderIrNode child, bool not) { - this.Pred = Pred; - this.Child = Child; - this.Not = Not; + Pred = pred; + Child = child; + Not = not; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs index 3b884621b0..07db646757 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs @@ -4,9 +4,9 @@ { public ShaderIpaMode Mode { get; private set; } - public ShaderIrMetaIpa(ShaderIpaMode Mode) + public ShaderIrMetaIpa(ShaderIpaMode mode) { - this.Mode = Mode; + Mode = mode; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs index 72ea221ad3..e0265138c8 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs @@ -13,12 +13,12 @@ namespace Ryujinx.Graphics.Gal.Shader public ShaderIrOperGpr DepthCompare; public int Component; // for TLD4(S) - public ShaderIrMetaTex(int Elem, GalTextureTarget TextureTarget, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates) + public ShaderIrMetaTex(int elem, GalTextureTarget textureTarget, TextureInstructionSuffix textureInstructionSuffix, params ShaderIrNode[] coordinates) { - this.Elem = Elem; - this.TextureTarget = TextureTarget; - this.TextureInstructionSuffix = TextureInstructionSuffix; - this.Coordinates = Coordinates; + Elem = elem; + TextureTarget = textureTarget; + TextureInstructionSuffix = textureInstructionSuffix; + Coordinates = coordinates; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs index 92871137f6..c925ea4e1a 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs @@ -6,10 +6,10 @@ namespace Ryujinx.Graphics.Gal.Shader public int Elem { get; private set; } - public ShaderIrMetaTexq(ShaderTexqInfo Info, int Elem) + public ShaderIrMetaTexq(ShaderTexqInfo info, int elem) { - this.Info = Info; - this.Elem = Elem; + Info = info; + Elem = elem; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs index 12a6123c31..c91c392653 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs @@ -9,17 +9,17 @@ namespace Ryujinx.Graphics.Gal.Shader public ShaderIrMeta MetaData { get; set; } public ShaderIrOp( - ShaderIrInst Inst, - ShaderIrNode OperandA = null, - ShaderIrNode OperandB = null, - ShaderIrNode OperandC = null, - ShaderIrMeta MetaData = null) + ShaderIrInst inst, + ShaderIrNode operandA = null, + ShaderIrNode operandB = null, + ShaderIrNode operandC = null, + ShaderIrMeta metaData = null) { - this.Inst = Inst; - this.OperandA = OperandA; - this.OperandB = OperandB; - this.OperandC = OperandC; - this.MetaData = MetaData; + Inst = inst; + OperandA = operandA; + OperandB = operandB; + OperandC = operandC; + MetaData = metaData; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs index f17d9c0e62..1f339e8051 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs @@ -6,10 +6,10 @@ namespace Ryujinx.Graphics.Gal.Shader public ShaderIrNode Vertex { get; private set; } - public ShaderIrOperAbuf(int Offs, ShaderIrNode Vertex) + public ShaderIrOperAbuf(int offs, ShaderIrNode vertex) { - this.Offs = Offs; - this.Vertex = Vertex; + Offs = offs; + Vertex = vertex; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs index b040c5c63e..9f419bbbec 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs @@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal.Shader public ShaderIrNode Offs { get; private set; } - public ShaderIrOperCbuf(int Index, int Pos, ShaderIrNode Offs = null) + public ShaderIrOperCbuf(int index, int pos, ShaderIrNode offs = null) { - this.Index = Index; - this.Pos = Pos; - this.Offs = Offs; + Index = index; + Pos = pos; + Offs = offs; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs index b4a5cab4d4..0d102d8978 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs @@ -2,35 +2,35 @@ namespace Ryujinx.Graphics.Gal.Shader { class ShaderIrOperGpr : ShaderIrNode { - public const int ZRIndex = 0xff; + public const int ZrIndex = 0xff; - public bool IsConst => Index == ZRIndex; + public bool IsConst => Index == ZrIndex; - public bool IsValidRegister => (uint)Index <= ZRIndex; + public bool IsValidRegister => (uint)Index <= ZrIndex; public int Index { get; set; } public int HalfPart { get; set; } public ShaderRegisterSize RegisterSize { get; private set; } - public ShaderIrOperGpr(int Index) + public ShaderIrOperGpr(int index) { - this.Index = Index; + Index = index; RegisterSize = ShaderRegisterSize.Single; } - public ShaderIrOperGpr(int Index, int HalfPart) + public ShaderIrOperGpr(int index, int halfPart) { - this.Index = Index; - this.HalfPart = HalfPart; + Index = index; + HalfPart = halfPart; RegisterSize = ShaderRegisterSize.Half; } - public static ShaderIrOperGpr MakeTemporary(int Index = 0) + public static ShaderIrOperGpr MakeTemporary(int index = 0) { - return new ShaderIrOperGpr(0x100 + Index); + return new ShaderIrOperGpr(0x100 + index); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs index ba2c2c9b24..6b23b36574 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs @@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader { public int Value { get; private set; } - public ShaderIrOperImm(int Value) + public ShaderIrOperImm(int value) { - this.Value = Value; + Value = value; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs index 3c27e48361..5b08c5b1c9 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs @@ -4,9 +4,9 @@ namespace Ryujinx.Graphics.Gal.Shader { public float Value { get; private set; } - public ShaderIrOperImmf(float Value) + public ShaderIrOperImmf(float value) { - this.Value = Value; + Value = value; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs index 74cca0efef..6c16a145d9 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs @@ -9,9 +9,9 @@ namespace Ryujinx.Graphics.Gal.Shader public int Index { get; set; } - public ShaderIrOperPred(int Index) + public ShaderIrOperPred(int index) { - this.Index = Index; + Index = index; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index d2bbd38c6b..1edf91a015 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -12,18 +12,18 @@ namespace Ryujinx.Graphics.Gal.Shader public int XBits; - public ShaderDecodeEntry(ShaderDecodeFunc Func, int XBits) + public ShaderDecodeEntry(ShaderDecodeFunc func, int xBits) { - this.Func = Func; - this.XBits = XBits; + Func = func; + XBits = xBits; } } - private static ShaderDecodeEntry[] OpCodes; + private static ShaderDecodeEntry[] _opCodes; static ShaderOpCodeTable() { - OpCodes = new ShaderDecodeEntry[1 << EncodingBits]; + _opCodes = new ShaderDecodeEntry[1 << EncodingBits]; #region Instructions Set("0100110000000x", ShaderDecode.Bfe_C); @@ -123,7 +123,7 @@ namespace Ryujinx.Graphics.Gal.Shader Set("1101x00xxxxxxx", ShaderDecode.Texs); Set("1101101xxxxxxx", ShaderDecode.Tlds); Set("110010xxxx111x", ShaderDecode.Tld4); - Set("1101111100xxxx", ShaderDecode.Tld4s); + Set("1101111100xxxx", ShaderDecode.Tld4S); Set("01011111xxxxxx", ShaderDecode.Vmad); Set("0100111xxxxxxx", ShaderDecode.Xmad_CR); Set("0011011x00xxxx", ShaderDecode.Xmad_I); @@ -132,59 +132,59 @@ namespace Ryujinx.Graphics.Gal.Shader #endregion } - private static void Set(string Encoding, ShaderDecodeFunc Func) + private static void Set(string encoding, ShaderDecodeFunc func) { - if (Encoding.Length != EncodingBits) + if (encoding.Length != EncodingBits) { - throw new ArgumentException(nameof(Encoding)); + throw new ArgumentException(nameof(encoding)); } - int Bit = Encoding.Length - 1; - int Value = 0; - int XMask = 0; - int XBits = 0; + int bit = encoding.Length - 1; + int value = 0; + int xMask = 0; + int xBits = 0; - int[] XPos = new int[Encoding.Length]; + int[] xPos = new int[encoding.Length]; - for (int Index = 0; Index < Encoding.Length; Index++, Bit--) + for (int index = 0; index < encoding.Length; index++, bit--) { - char Chr = Encoding[Index]; + char chr = encoding[index]; - if (Chr == '1') + if (chr == '1') { - Value |= 1 << Bit; + value |= 1 << bit; } - else if (Chr == 'x') + else if (chr == 'x') { - XMask |= 1 << Bit; + xMask |= 1 << bit; - XPos[XBits++] = Bit; + xPos[xBits++] = bit; } } - XMask = ~XMask; + xMask = ~xMask; - ShaderDecodeEntry Entry = new ShaderDecodeEntry(Func, XBits); + ShaderDecodeEntry entry = new ShaderDecodeEntry(func, xBits); - for (int Index = 0; Index < (1 << XBits); Index++) + for (int index = 0; index < (1 << xBits); index++) { - Value &= XMask; + value &= xMask; - for (int X = 0; X < XBits; X++) + for (int x = 0; x < xBits; x++) { - Value |= ((Index >> X) & 1) << XPos[X]; + value |= ((index >> x) & 1) << xPos[x]; } - if (OpCodes[Value] == null || OpCodes[Value].XBits > XBits) + if (_opCodes[value] == null || _opCodes[value].XBits > xBits) { - OpCodes[Value] = Entry; + _opCodes[value] = entry; } } } - public static ShaderDecodeFunc GetDecoder(long OpCode) + public static ShaderDecodeFunc GetDecoder(long opCode) { - return OpCodes[(ulong)OpCode >> (64 - EncodingBits)]?.Func; + return _opCodes[(ulong)opCode >> (64 - EncodingBits)]?.Func; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs index aa48548282..22a2ab85cd 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs @@ -2,10 +2,10 @@ namespace Ryujinx.Graphics.Gal.Shader { enum ShaderOper { - CR, + Cr, Imm, Immf, - RC, - RR + Rc, + Rr } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs index ed1955cdbb..f1f4650c8f 100644 --- a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs +++ b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs @@ -16,29 +16,29 @@ namespace Ryujinx.Graphics.Gal public TextureInstructionSuffix TextureSuffix { get; private set; } public ShaderDeclInfo( - string Name, - int Index, - bool IsCb = false, - int Cbuf = 0, - int Size = 1, - GalTextureTarget TextureTarget = GalTextureTarget.TwoD, - TextureInstructionSuffix TextureSuffix = TextureInstructionSuffix.None) + string name, + int index, + bool isCb = false, + int cbuf = 0, + int size = 1, + GalTextureTarget textureTarget = GalTextureTarget.TwoD, + TextureInstructionSuffix textureSuffix = TextureInstructionSuffix.None) { - this.Name = Name; - this.Index = Index; - this.IsCb = IsCb; - this.Cbuf = Cbuf; - this.Size = Size; + Name = name; + Index = index; + IsCb = isCb; + Cbuf = cbuf; + Size = size; - this.TextureTarget = TextureTarget; - this.TextureSuffix = TextureSuffix; + TextureTarget = textureTarget; + TextureSuffix = textureSuffix; } - internal void Enlarge(int NewSize) + internal void Enlarge(int newSize) { - if (Size < NewSize) + if (Size < newSize) { - Size = NewSize; + Size = newSize; } } } diff --git a/Ryujinx.Graphics/Gal/ShaderDumper.cs b/Ryujinx.Graphics/Gal/ShaderDumper.cs index 21e92491a7..726447e426 100644 --- a/Ryujinx.Graphics/Gal/ShaderDumper.cs +++ b/Ryujinx.Graphics/Gal/ShaderDumper.cs @@ -5,67 +5,67 @@ namespace Ryujinx.Graphics.Gal { static class ShaderDumper { - private static string RuntimeDir; + private static string _runtimeDir; public static int DumpIndex { get; private set; } = 1; - public static void Dump(IGalMemory Memory, long Position, GalShaderType Type, string ExtSuffix = "") + public static void Dump(IGalMemory memory, long position, GalShaderType type, string extSuffix = "") { if (!IsDumpEnabled()) { return; } - string FileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(Type) + ExtSuffix + ".bin"; + string fileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(type) + extSuffix + ".bin"; - string FullPath = Path.Combine(FullDir(), FileName); - string CodePath = Path.Combine(CodeDir(), FileName); + string fullPath = Path.Combine(FullDir(), fileName); + string codePath = Path.Combine(CodeDir(), fileName); DumpIndex++; - using (FileStream FullFile = File.Create(FullPath)) - using (FileStream CodeFile = File.Create(CodePath)) + using (FileStream fullFile = File.Create(fullPath)) + using (FileStream codeFile = File.Create(codePath)) { - BinaryWriter FullWriter = new BinaryWriter(FullFile); - BinaryWriter CodeWriter = new BinaryWriter(CodeFile); + BinaryWriter fullWriter = new BinaryWriter(fullFile); + BinaryWriter codeWriter = new BinaryWriter(codeFile); for (long i = 0; i < 0x50; i += 4) { - FullWriter.Write(Memory.ReadInt32(Position + i)); + fullWriter.Write(memory.ReadInt32(position + i)); } - long Offset = 0; + long offset = 0; - ulong Instruction = 0; + ulong instruction = 0; //Dump until a NOP instruction is found - while ((Instruction >> 48 & 0xfff8) != 0x50b0) + while ((instruction >> 48 & 0xfff8) != 0x50b0) { - uint Word0 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 0); - uint Word1 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 4); + uint word0 = (uint)memory.ReadInt32(position + 0x50 + offset + 0); + uint word1 = (uint)memory.ReadInt32(position + 0x50 + offset + 4); - Instruction = Word0 | (ulong)Word1 << 32; + instruction = word0 | (ulong)word1 << 32; //Zero instructions (other kind of NOP) stop immediatly, //this is to avoid two rows of zeroes - if (Instruction == 0) + if (instruction == 0) { break; } - FullWriter.Write(Instruction); - CodeWriter.Write(Instruction); + fullWriter.Write(instruction); + codeWriter.Write(instruction); - Offset += 8; + offset += 8; } //Align to meet nvdisasm requeriments - while (Offset % 0x20 != 0) + while (offset % 0x20 != 0) { - FullWriter.Write(0); - CodeWriter.Write(0); + fullWriter.Write(0); + codeWriter.Write(0); - Offset += 4; + offset += 4; } } } @@ -87,37 +87,37 @@ namespace Ryujinx.Graphics.Gal private static string DumpDir() { - if (string.IsNullOrEmpty(RuntimeDir)) + if (string.IsNullOrEmpty(_runtimeDir)) { - int Index = 1; + int index = 1; do { - RuntimeDir = Path.Combine(GraphicsConfig.ShadersDumpPath, "Dumps" + Index.ToString("d2")); + _runtimeDir = Path.Combine(GraphicsConfig.ShadersDumpPath, "Dumps" + index.ToString("d2")); - Index++; + index++; } - while (Directory.Exists(RuntimeDir)); + while (Directory.Exists(_runtimeDir)); - Directory.CreateDirectory(RuntimeDir); + Directory.CreateDirectory(_runtimeDir); } - return RuntimeDir; + return _runtimeDir; } - private static string CreateAndReturn(string Dir) + private static string CreateAndReturn(string dir) { - if (!Directory.Exists(Dir)) + if (!Directory.Exists(dir)) { - Directory.CreateDirectory(Dir); + Directory.CreateDirectory(dir); } - return Dir; + return dir; } - private static string ShaderExtension(GalShaderType Type) + private static string ShaderExtension(GalShaderType type) { - switch (Type) + switch (type) { case GalShaderType.Vertex: return "vert"; case GalShaderType.TessControl: return "tesc"; @@ -125,7 +125,7 @@ namespace Ryujinx.Graphics.Gal case GalShaderType.Geometry: return "geom"; case GalShaderType.Fragment: return "frag"; - default: throw new ArgumentException(nameof(Type)); + default: throw new ArgumentException(nameof(type)); } } } diff --git a/Ryujinx.Graphics/Gal/ShaderException.cs b/Ryujinx.Graphics/Gal/ShaderException.cs index 9bc87ff3db..b0aff42bf5 100644 --- a/Ryujinx.Graphics/Gal/ShaderException.cs +++ b/Ryujinx.Graphics/Gal/ShaderException.cs @@ -6,6 +6,6 @@ namespace Ryujinx.Graphics.Gal { public ShaderException() : base() { } - public ShaderException(string Message) : base(Message) { } + public ShaderException(string message) : base(message) { } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/GpuMethodCall.cs b/Ryujinx.Graphics/GpuMethodCall.cs index 762d10f1d0..4a310b0751 100644 --- a/Ryujinx.Graphics/GpuMethodCall.cs +++ b/Ryujinx.Graphics/GpuMethodCall.cs @@ -10,15 +10,15 @@ namespace Ryujinx.Graphics public bool IsLastCall => MethodCount <= 1; public GpuMethodCall( - int Method, - int Argument, - int SubChannel = 0, - int MethodCount = 0) + int method, + int argument, + int subChannel = 0, + int methodCount = 0) { - this.Method = Method; - this.Argument = Argument; - this.SubChannel = SubChannel; - this.MethodCount = MethodCount; + Method = method; + Argument = argument; + SubChannel = subChannel; + MethodCount = methodCount; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/GpuResourceManager.cs b/Ryujinx.Graphics/GpuResourceManager.cs index 4f2d92b03a..740e6be86d 100644 --- a/Ryujinx.Graphics/GpuResourceManager.cs +++ b/Ryujinx.Graphics/GpuResourceManager.cs @@ -1,8 +1,6 @@ -using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; -using System; using System.Collections.Generic; namespace Ryujinx.Graphics @@ -18,124 +16,124 @@ namespace Ryujinx.Graphics ZetaBuffer } - private NvGpu Gpu; + private NvGpu _gpu; - private HashSet[] UploadedKeys; + private HashSet[] _uploadedKeys; - private Dictionary ImageTypes; - private Dictionary MirroredTextures; + private Dictionary _imageTypes; + private Dictionary _mirroredTextures; - public GpuResourceManager(NvGpu Gpu) + public GpuResourceManager(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; - UploadedKeys = new HashSet[(int)NvGpuBufferType.Count]; + _uploadedKeys = new HashSet[(int)NvGpuBufferType.Count]; - for (int Index = 0; Index < UploadedKeys.Length; Index++) + for (int index = 0; index < _uploadedKeys.Length; index++) { - UploadedKeys[Index] = new HashSet(); + _uploadedKeys[index] = new HashSet(); } - ImageTypes = new Dictionary(); - MirroredTextures = new Dictionary(); + _imageTypes = new Dictionary(); + _mirroredTextures = new Dictionary(); } - public void SendColorBuffer(NvGpuVmm Vmm, long Position, int Attachment, GalImage NewImage) + public void SendColorBuffer(NvGpuVmm vmm, long position, int attachment, GalImage newImage) { - long Size = (uint)ImageUtils.GetSize(NewImage); + long size = (uint)ImageUtils.GetSize(newImage); - ImageTypes[Position] = ImageType.ColorBuffer; + _imageTypes[position] = ImageType.ColorBuffer; - if (!TryReuse(Vmm, Position, NewImage)) + if (!TryReuse(vmm, position, newImage)) { - Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); + _gpu.Renderer.Texture.Create(position, (int)size, newImage); } - Gpu.Renderer.RenderTarget.BindColor(Position, Attachment); + _gpu.Renderer.RenderTarget.BindColor(position, attachment); } - public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage) + public void SendZetaBuffer(NvGpuVmm vmm, long position, GalImage newImage) { - long Size = (uint)ImageUtils.GetSize(NewImage); + long size = (uint)ImageUtils.GetSize(newImage); - ImageTypes[Position] = ImageType.ZetaBuffer; + _imageTypes[position] = ImageType.ZetaBuffer; - if (!TryReuse(Vmm, Position, NewImage)) + if (!TryReuse(vmm, position, newImage)) { - Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage); + _gpu.Renderer.Texture.Create(position, (int)size, newImage); } - Gpu.Renderer.RenderTarget.BindZeta(Position); + _gpu.Renderer.RenderTarget.BindZeta(position); } - public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage) + public void SendTexture(NvGpuVmm vmm, long position, GalImage newImage) { - PrepareSendTexture(Vmm, Position, NewImage); + PrepareSendTexture(vmm, position, newImage); - ImageTypes[Position] = ImageType.Texture; + _imageTypes[position] = ImageType.Texture; } - public bool TryGetTextureLayer(long Position, out int LayerIndex) + public bool TryGetTextureLayer(long position, out int layerIndex) { - if (MirroredTextures.TryGetValue(Position, out LayerIndex)) + if (_mirroredTextures.TryGetValue(position, out layerIndex)) { - ImageType Type = ImageTypes[Position]; + ImageType type = _imageTypes[position]; // FIXME(thog): I'm actually unsure if we should deny all other image type, gpu testing needs to be done here. - if (Type != ImageType.Texture && Type != ImageType.TextureArrayLayer) + if (type != ImageType.Texture && type != ImageType.TextureArrayLayer) { - LayerIndex = -1; + layerIndex = -1; return false; } return true; } - LayerIndex = -1; + layerIndex = -1; return false; } - public void SetTextureArrayLayer(long Position, int LayerIndex) + public void SetTextureArrayLayer(long position, int layerIndex) { - ImageTypes[Position] = ImageType.TextureArrayLayer; - MirroredTextures[Position] = LayerIndex; + _imageTypes[position] = ImageType.TextureArrayLayer; + _mirroredTextures[position] = layerIndex; } - private void PrepareSendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage) + private void PrepareSendTexture(NvGpuVmm vmm, long position, GalImage newImage) { - long Size = ImageUtils.GetSize(NewImage); + long size = ImageUtils.GetSize(newImage); - bool SkipCheck = false; + bool skipCheck = false; - if (ImageTypes.TryGetValue(Position, out ImageType OldType)) + if (_imageTypes.TryGetValue(position, out ImageType oldType)) { - if (OldType == ImageType.ColorBuffer || OldType == ImageType.ZetaBuffer) + if (oldType == ImageType.ColorBuffer || oldType == ImageType.ZetaBuffer) { //Avoid data destruction - MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture); + MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture); - SkipCheck = true; + skipCheck = true; } } - if (SkipCheck || !MemoryRegionModified(Vmm, Position, Size, NvGpuBufferType.Texture)) + if (skipCheck || !MemoryRegionModified(vmm, position, size, NvGpuBufferType.Texture)) { - if (TryReuse(Vmm, Position, NewImage)) + if (TryReuse(vmm, position, newImage)) { return; } } - byte[] Data = ImageUtils.ReadTexture(Vmm, NewImage, Position); + byte[] data = ImageUtils.ReadTexture(vmm, newImage, position); - Gpu.Renderer.Texture.Create(Position, Data, NewImage); + _gpu.Renderer.Texture.Create(position, data, newImage); } - private bool TryReuse(NvGpuVmm Vmm, long Position, GalImage NewImage) + private bool TryReuse(NvGpuVmm vmm, long position, GalImage newImage) { - if (Gpu.Renderer.Texture.TryGetImage(Position, out GalImage CachedImage) && CachedImage.TextureTarget == NewImage.TextureTarget && CachedImage.SizeMatches(NewImage)) + if (_gpu.Renderer.Texture.TryGetImage(position, out GalImage cachedImage) && cachedImage.TextureTarget == newImage.TextureTarget && cachedImage.SizeMatches(newImage)) { - Gpu.Renderer.RenderTarget.Reinterpret(Position, NewImage); + _gpu.Renderer.RenderTarget.Reinterpret(position, newImage); return true; } @@ -143,29 +141,29 @@ namespace Ryujinx.Graphics return false; } - public bool MemoryRegionModified(NvGpuVmm Vmm, long Position, long Size, NvGpuBufferType Type) + public bool MemoryRegionModified(NvGpuVmm vmm, long position, long size, NvGpuBufferType type) { - HashSet Uploaded = UploadedKeys[(int)Type]; + HashSet uploaded = _uploadedKeys[(int)type]; - if (!Uploaded.Add(Position)) + if (!uploaded.Add(position)) { return false; } - return Vmm.IsRegionModified(Position, Size, Type); + return vmm.IsRegionModified(position, size, type); } public void ClearPbCache() { - for (int Index = 0; Index < UploadedKeys.Length; Index++) + for (int index = 0; index < _uploadedKeys.Length; index++) { - UploadedKeys[Index].Clear(); + _uploadedKeys[index].Clear(); } } - public void ClearPbCache(NvGpuBufferType Type) + public void ClearPbCache(NvGpuBufferType type) { - UploadedKeys[(int)Type].Clear(); + _uploadedKeys[(int)type].Clear(); } } } diff --git a/Ryujinx.Graphics/Graphics3d/INvGpuEngine.cs b/Ryujinx.Graphics/Graphics3d/INvGpuEngine.cs index c2474a1718..aa0db6826f 100644 --- a/Ryujinx.Graphics/Graphics3d/INvGpuEngine.cs +++ b/Ryujinx.Graphics/Graphics3d/INvGpuEngine.cs @@ -6,6 +6,6 @@ namespace Ryujinx.Graphics.Graphics3d { int[] Registers { get; } - void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall); + void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/MacroInterpreter.cs b/Ryujinx.Graphics/Graphics3d/MacroInterpreter.cs index a124aca484..845762133c 100644 --- a/Ryujinx.Graphics/Graphics3d/MacroInterpreter.cs +++ b/Ryujinx.Graphics/Graphics3d/MacroInterpreter.cs @@ -42,78 +42,78 @@ namespace Ryujinx.Graphics.Graphics3d BitwiseNotAnd = 12 } - private NvGpuFifo PFifo; - private INvGpuEngine Engine; + private NvGpuFifo _pFifo; + private INvGpuEngine _engine; public Queue Fifo { get; private set; } - private int[] Gprs; + private int[] _gprs; - private int MethAddr; - private int MethIncr; + private int _methAddr; + private int _methIncr; - private bool Carry; + private bool _carry; - private int OpCode; + private int _opCode; - private int PipeOp; + private int _pipeOp; - private int Pc; + private int _pc; - public MacroInterpreter(NvGpuFifo PFifo, INvGpuEngine Engine) + public MacroInterpreter(NvGpuFifo pFifo, INvGpuEngine engine) { - this.PFifo = PFifo; - this.Engine = Engine; + _pFifo = pFifo; + _engine = engine; Fifo = new Queue(); - Gprs = new int[8]; + _gprs = new int[8]; } - public void Execute(NvGpuVmm Vmm, int[] Mme, int Position, int Param) + public void Execute(NvGpuVmm vmm, int[] mme, int position, int param) { Reset(); - Gprs[1] = Param; + _gprs[1] = param; - Pc = Position; + _pc = position; - FetchOpCode(Mme); + FetchOpCode(mme); - while (Step(Vmm, Mme)); + while (Step(vmm, mme)); //Due to the delay slot, we still need to execute //one more instruction before we actually exit. - Step(Vmm, Mme); + Step(vmm, mme); } private void Reset() { - for (int Index = 0; Index < Gprs.Length; Index++) + for (int index = 0; index < _gprs.Length; index++) { - Gprs[Index] = 0; + _gprs[index] = 0; } - MethAddr = 0; - MethIncr = 0; + _methAddr = 0; + _methIncr = 0; - Carry = false; + _carry = false; } - private bool Step(NvGpuVmm Vmm, int[] Mme) + private bool Step(NvGpuVmm vmm, int[] mme) { - int BaseAddr = Pc - 1; + int baseAddr = _pc - 1; - FetchOpCode(Mme); + FetchOpCode(mme); - if ((OpCode & 7) < 7) + if ((_opCode & 7) < 7) { //Operation produces a value. - AssignmentOperation AsgOp = (AssignmentOperation)((OpCode >> 4) & 7); + AssignmentOperation asgOp = (AssignmentOperation)((_opCode >> 4) & 7); - int Result = GetAluResult(); + int result = GetAluResult(); - switch (AsgOp) + switch (asgOp) { //Fetch parameter and ignore result. case AssignmentOperation.IgnoreAndFetch: @@ -126,7 +126,7 @@ namespace Ryujinx.Graphics.Graphics3d //Move result. case AssignmentOperation.Move: { - SetDstGpr(Result); + SetDstGpr(result); break; } @@ -134,9 +134,9 @@ namespace Ryujinx.Graphics.Graphics3d //Move result and use as Method Address. case AssignmentOperation.MoveAndSetMaddr: { - SetDstGpr(Result); + SetDstGpr(result); - SetMethAddr(Result); + SetMethAddr(result); break; } @@ -146,7 +146,7 @@ namespace Ryujinx.Graphics.Graphics3d { SetDstGpr(FetchParam()); - Send(Vmm, Result); + Send(vmm, result); break; } @@ -154,9 +154,9 @@ namespace Ryujinx.Graphics.Graphics3d //Move and send result. case AssignmentOperation.MoveAndSend: { - SetDstGpr(Result); + SetDstGpr(result); - Send(Vmm, Result); + Send(vmm, result); break; } @@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.Graphics3d { SetDstGpr(FetchParam()); - SetMethAddr(Result); + SetMethAddr(result); break; } @@ -174,11 +174,11 @@ namespace Ryujinx.Graphics.Graphics3d //Move result and use as Method Address, then fetch and send paramter. case AssignmentOperation.MoveAndSetMaddrThenFetchAndSend: { - SetDstGpr(Result); + SetDstGpr(result); - SetMethAddr(Result); + SetMethAddr(result); - Send(Vmm, FetchParam()); + Send(vmm, FetchParam()); break; } @@ -186,11 +186,11 @@ namespace Ryujinx.Graphics.Graphics3d //Move result and use as Method Address, then send bits 17:12 of result. case AssignmentOperation.MoveAndSetMaddrThenSendHigh: { - SetDstGpr(Result); + SetDstGpr(result); - SetMethAddr(Result); + SetMethAddr(result); - Send(Vmm, (Result >> 12) & 0x3f); + Send(vmm, (result >> 12) & 0x3f); break; } @@ -199,50 +199,50 @@ namespace Ryujinx.Graphics.Graphics3d else { //Branch. - bool OnNotZero = ((OpCode >> 4) & 1) != 0; + bool onNotZero = ((_opCode >> 4) & 1) != 0; - bool Taken = OnNotZero + bool taken = onNotZero ? GetGprA() != 0 : GetGprA() == 0; - if (Taken) + if (taken) { - Pc = BaseAddr + GetImm(); + _pc = baseAddr + GetImm(); - bool NoDelays = (OpCode & 0x20) != 0; + bool noDelays = (_opCode & 0x20) != 0; - if (NoDelays) + if (noDelays) { - FetchOpCode(Mme); + FetchOpCode(mme); } return true; } } - bool Exit = (OpCode & 0x80) != 0; + bool exit = (_opCode & 0x80) != 0; - return !Exit; + return !exit; } - private void FetchOpCode(int[] Mme) + private void FetchOpCode(int[] mme) { - OpCode = PipeOp; + _opCode = _pipeOp; - PipeOp = Mme[Pc++]; + _pipeOp = mme[_pc++]; } private int GetAluResult() { - AluOperation Op = (AluOperation)(OpCode & 7); + AluOperation op = (AluOperation)(_opCode & 7); - switch (Op) + switch (op) { case AluOperation.AluReg: { - AluRegOperation AluOp = (AluRegOperation)((OpCode >> 17) & 0x1f); + AluRegOperation aluOp = (AluRegOperation)((_opCode >> 17) & 0x1f); - return GetAluResult(AluOp, GetGprA(), GetGprB()); + return GetAluResult(aluOp, GetGprA(), GetGprB()); } case AluOperation.AddImmediate: @@ -254,40 +254,40 @@ namespace Ryujinx.Graphics.Graphics3d case AluOperation.BitfieldExtractLslImm: case AluOperation.BitfieldExtractLslReg: { - int BfSrcBit = (OpCode >> 17) & 0x1f; - int BfSize = (OpCode >> 22) & 0x1f; - int BfDstBit = (OpCode >> 27) & 0x1f; + int bfSrcBit = (_opCode >> 17) & 0x1f; + int bfSize = (_opCode >> 22) & 0x1f; + int bfDstBit = (_opCode >> 27) & 0x1f; - int BfMask = (1 << BfSize) - 1; + int bfMask = (1 << bfSize) - 1; - int Dst = GetGprA(); - int Src = GetGprB(); + int dst = GetGprA(); + int src = GetGprB(); - switch (Op) + switch (op) { case AluOperation.BitfieldReplace: { - Src = (int)((uint)Src >> BfSrcBit) & BfMask; + src = (int)((uint)src >> bfSrcBit) & bfMask; - Dst &= ~(BfMask << BfDstBit); + dst &= ~(bfMask << bfDstBit); - Dst |= Src << BfDstBit; + dst |= src << bfDstBit; - return Dst; + return dst; } case AluOperation.BitfieldExtractLslImm: { - Src = (int)((uint)Src >> Dst) & BfMask; + src = (int)((uint)src >> dst) & bfMask; - return Src << BfDstBit; + return src << bfDstBit; } case AluOperation.BitfieldExtractLslReg: { - Src = (int)((uint)Src >> BfSrcBit) & BfMask; + src = (int)((uint)src >> bfSrcBit) & bfMask; - return Src << Dst; + return src << dst; } } @@ -300,117 +300,117 @@ namespace Ryujinx.Graphics.Graphics3d } } - throw new ArgumentException(nameof(OpCode)); + throw new ArgumentException(nameof(_opCode)); } - private int GetAluResult(AluRegOperation AluOp, int A, int B) + private int GetAluResult(AluRegOperation aluOp, int a, int b) { - switch (AluOp) + switch (aluOp) { case AluRegOperation.Add: { - ulong Result = (ulong)A + (ulong)B; + ulong result = (ulong)a + (ulong)b; - Carry = Result > 0xffffffff; + _carry = result > 0xffffffff; - return (int)Result; + return (int)result; } case AluRegOperation.AddWithCarry: { - ulong Result = (ulong)A + (ulong)B + (Carry ? 1UL : 0UL); + ulong result = (ulong)a + (ulong)b + (_carry ? 1UL : 0UL); - Carry = Result > 0xffffffff; + _carry = result > 0xffffffff; - return (int)Result; + return (int)result; } case AluRegOperation.Subtract: { - ulong Result = (ulong)A - (ulong)B; + ulong result = (ulong)a - (ulong)b; - Carry = Result < 0x100000000; + _carry = result < 0x100000000; - return (int)Result; + return (int)result; } case AluRegOperation.SubtractWithBorrow: { - ulong Result = (ulong)A - (ulong)B - (Carry ? 0UL : 1UL); + ulong result = (ulong)a - (ulong)b - (_carry ? 0UL : 1UL); - Carry = Result < 0x100000000; + _carry = result < 0x100000000; - return (int)Result; + return (int)result; } - case AluRegOperation.BitwiseExclusiveOr: return A ^ B; - case AluRegOperation.BitwiseOr: return A | B; - case AluRegOperation.BitwiseAnd: return A & B; - case AluRegOperation.BitwiseAndNot: return A & ~B; - case AluRegOperation.BitwiseNotAnd: return ~(A & B); + case AluRegOperation.BitwiseExclusiveOr: return a ^ b; + case AluRegOperation.BitwiseOr: return a | b; + case AluRegOperation.BitwiseAnd: return a & b; + case AluRegOperation.BitwiseAndNot: return a & ~b; + case AluRegOperation.BitwiseNotAnd: return ~(a & b); } - throw new ArgumentOutOfRangeException(nameof(AluOp)); + throw new ArgumentOutOfRangeException(nameof(aluOp)); } private int GetImm() { //Note: The immediate is signed, the sign-extension is intended here. - return OpCode >> 14; + return _opCode >> 14; } - private void SetMethAddr(int Value) + private void SetMethAddr(int value) { - MethAddr = (Value >> 0) & 0xfff; - MethIncr = (Value >> 12) & 0x3f; + _methAddr = (value >> 0) & 0xfff; + _methIncr = (value >> 12) & 0x3f; } - private void SetDstGpr(int Value) + private void SetDstGpr(int value) { - Gprs[(OpCode >> 8) & 7] = Value; + _gprs[(_opCode >> 8) & 7] = value; } private int GetGprA() { - return GetGprValue((OpCode >> 11) & 7); + return GetGprValue((_opCode >> 11) & 7); } private int GetGprB() { - return GetGprValue((OpCode >> 14) & 7); + return GetGprValue((_opCode >> 14) & 7); } - private int GetGprValue(int Index) + private int GetGprValue(int index) { - return Index != 0 ? Gprs[Index] : 0; + return index != 0 ? _gprs[index] : 0; } private int FetchParam() { - int Value; + int value; - if (!Fifo.TryDequeue(out Value)) + if (!Fifo.TryDequeue(out value)) { Logger.PrintWarning(LogClass.Gpu, "Macro attempted to fetch an inexistent argument."); return 0; } - return Value; + return value; } - private int Read(int Reg) + private int Read(int reg) { - return Engine.Registers[Reg]; + return _engine.Registers[reg]; } - private void Send(NvGpuVmm Vmm, int Value) + private void Send(NvGpuVmm vmm, int value) { - GpuMethodCall MethCall = new GpuMethodCall(MethAddr, Value); + GpuMethodCall methCall = new GpuMethodCall(_methAddr, value); - Engine.CallMethod(Vmm, MethCall); + _engine.CallMethod(vmm, methCall); - MethAddr += MethIncr; + _methAddr += _methIncr; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs index 3295f6da05..361b170610 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs @@ -1,4 +1,3 @@ -using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; @@ -20,187 +19,187 @@ namespace Ryujinx.Graphics.Graphics3d public int[] Registers { get; private set; } - private NvGpu Gpu; + private NvGpu _gpu; - public NvGpuEngine2d(NvGpu Gpu) + public NvGpuEngine2d(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; Registers = new int[0x238]; } - public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - WriteRegister(MethCall); + WriteRegister(methCall); - if ((NvGpuEngine2dReg)MethCall.Method == NvGpuEngine2dReg.BlitSrcYInt) + if ((NvGpuEngine2dReg)methCall.Method == NvGpuEngine2dReg.BlitSrcYInt) { - TextureCopy(Vmm); + TextureCopy(vmm); } } - private void TextureCopy(NvGpuVmm Vmm) + private void TextureCopy(NvGpuVmm vmm) { - CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation); + CopyOperation operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation); - int DstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat); - bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0; - int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth); - int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight); - int DstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth); - int DstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer); - int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch); - int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions); + int dstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat); + bool dstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0; + int dstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth); + int dstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight); + int dstDepth = ReadRegister(NvGpuEngine2dReg.DstDepth); + int dstLayer = ReadRegister(NvGpuEngine2dReg.DstLayer); + int dstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch); + int dstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions); - int SrcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat); - bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0; - int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth); - int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight); - int SrcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth); - int SrcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer); - int SrcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch); - int SrcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions); + int srcFormat = ReadRegister(NvGpuEngine2dReg.SrcFormat); + bool srcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0; + int srcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth); + int srcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight); + int srcDepth = ReadRegister(NvGpuEngine2dReg.SrcDepth); + int srcLayer = ReadRegister(NvGpuEngine2dReg.SrcLayer); + int srcPitch = ReadRegister(NvGpuEngine2dReg.SrcPitch); + int srcBlkDim = ReadRegister(NvGpuEngine2dReg.SrcBlockDimensions); - int DstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX); - int DstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY); - int DstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW); - int DstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH); + int dstBlitX = ReadRegister(NvGpuEngine2dReg.BlitDstX); + int dstBlitY = ReadRegister(NvGpuEngine2dReg.BlitDstY); + int dstBlitW = ReadRegister(NvGpuEngine2dReg.BlitDstW); + int dstBlitH = ReadRegister(NvGpuEngine2dReg.BlitDstH); - long BlitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract); - long BlitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract); + long blitDuDx = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDuDxFract); + long blitDvDy = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitDvDyFract); - long SrcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract); - long SrcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract); + long srcBlitX = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcXFract); + long srcBlitY = ReadRegisterFixed1_31_32(NvGpuEngine2dReg.BlitSrcYFract); - GalImageFormat SrcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)SrcFormat); - GalImageFormat DstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)DstFormat); + GalImageFormat srcImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)srcFormat); + GalImageFormat dstImgFormat = ImageUtils.ConvertSurface((GalSurfaceFormat)dstFormat); - GalMemoryLayout SrcLayout = GetLayout(SrcLinear); - GalMemoryLayout DstLayout = GetLayout(DstLinear); + GalMemoryLayout srcLayout = GetLayout(srcLinear); + GalMemoryLayout dstLayout = GetLayout(dstLinear); - int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf); - int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); + int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf); + int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf); - long SrcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); - long DstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress); + long srcAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); + long dstAddress = MakeInt64From2xInt32(NvGpuEngine2dReg.DstAddress); - long SrcKey = Vmm.GetPhysicalAddress(SrcAddress); - long DstKey = Vmm.GetPhysicalAddress(DstAddress); + long srcKey = vmm.GetPhysicalAddress(srcAddress); + long dstKey = vmm.GetPhysicalAddress(dstAddress); - bool IsSrcLayered = false; - bool IsDstLayered = false; + bool isSrcLayered = false; + bool isDstLayered = false; - GalTextureTarget SrcTarget = GalTextureTarget.TwoD; + GalTextureTarget srcTarget = GalTextureTarget.TwoD; - if (SrcDepth != 0) + if (srcDepth != 0) { - SrcTarget = GalTextureTarget.TwoDArray; - SrcDepth++; - IsSrcLayered = true; + srcTarget = GalTextureTarget.TwoDArray; + srcDepth++; + isSrcLayered = true; } else { - SrcDepth = 1; + srcDepth = 1; } - GalTextureTarget DstTarget = GalTextureTarget.TwoD; + GalTextureTarget dstTarget = GalTextureTarget.TwoD; - if (DstDepth != 0) + if (dstDepth != 0) { - DstTarget = GalTextureTarget.TwoDArray; - DstDepth++; - IsDstLayered = true; + dstTarget = GalTextureTarget.TwoDArray; + dstDepth++; + isDstLayered = true; } else { - DstDepth = 1; + dstDepth = 1; } - GalImage SrcTexture = new GalImage( - SrcWidth, - SrcHeight, - 1, SrcDepth, 1, - SrcBlockHeight, 1, - SrcLayout, - SrcImgFormat, - SrcTarget); + GalImage srcTexture = new GalImage( + srcWidth, + srcHeight, + 1, srcDepth, 1, + srcBlockHeight, 1, + srcLayout, + srcImgFormat, + srcTarget); - GalImage DstTexture = new GalImage( - DstWidth, - DstHeight, - 1, DstDepth, 1, - DstBlockHeight, 1, - DstLayout, - DstImgFormat, - DstTarget); + GalImage dstTexture = new GalImage( + dstWidth, + dstHeight, + 1, dstDepth, 1, + dstBlockHeight, 1, + dstLayout, + dstImgFormat, + dstTarget); - SrcTexture.Pitch = SrcPitch; - DstTexture.Pitch = DstPitch; + srcTexture.Pitch = srcPitch; + dstTexture.Pitch = dstPitch; - long GetLayerOffset(GalImage Image, int Layer) + long GetLayerOffset(GalImage image, int layer) { - int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1; - return ImageUtils.GetLayerOffset(Image, TargetMipLevel) * Layer; + int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1; + return ImageUtils.GetLayerOffset(image, targetMipLevel) * layer; } - int SrcLayerIndex = -1; + int srcLayerIndex = -1; - if (IsSrcLayered && Gpu.ResourceManager.TryGetTextureLayer(SrcKey, out SrcLayerIndex) && SrcLayerIndex != 0) + if (isSrcLayered && _gpu.ResourceManager.TryGetTextureLayer(srcKey, out srcLayerIndex) && srcLayerIndex != 0) { - SrcKey = SrcKey - GetLayerOffset(SrcTexture, SrcLayerIndex); + srcKey = srcKey - GetLayerOffset(srcTexture, srcLayerIndex); } - int DstLayerIndex = -1; + int dstLayerIndex = -1; - if (IsDstLayered && Gpu.ResourceManager.TryGetTextureLayer(DstKey, out DstLayerIndex) && DstLayerIndex != 0) + if (isDstLayered && _gpu.ResourceManager.TryGetTextureLayer(dstKey, out dstLayerIndex) && dstLayerIndex != 0) { - DstKey = DstKey - GetLayerOffset(DstTexture, DstLayerIndex); + dstKey = dstKey - GetLayerOffset(dstTexture, dstLayerIndex); } - Gpu.ResourceManager.SendTexture(Vmm, SrcKey, SrcTexture); - Gpu.ResourceManager.SendTexture(Vmm, DstKey, DstTexture); + _gpu.ResourceManager.SendTexture(vmm, srcKey, srcTexture); + _gpu.ResourceManager.SendTexture(vmm, dstKey, dstTexture); - if (IsSrcLayered && SrcLayerIndex == -1) + if (isSrcLayered && srcLayerIndex == -1) { - for (int Layer = 0; Layer < SrcTexture.LayerCount; Layer++) + for (int layer = 0; layer < srcTexture.LayerCount; layer++) { - Gpu.ResourceManager.SetTextureArrayLayer(SrcKey + GetLayerOffset(SrcTexture, Layer), Layer); + _gpu.ResourceManager.SetTextureArrayLayer(srcKey + GetLayerOffset(srcTexture, layer), layer); } - SrcLayerIndex = 0; + srcLayerIndex = 0; } - if (IsDstLayered && DstLayerIndex == -1) + if (isDstLayered && dstLayerIndex == -1) { - for (int Layer = 0; Layer < DstTexture.LayerCount; Layer++) + for (int layer = 0; layer < dstTexture.LayerCount; layer++) { - Gpu.ResourceManager.SetTextureArrayLayer(DstKey + GetLayerOffset(DstTexture, Layer), Layer); + _gpu.ResourceManager.SetTextureArrayLayer(dstKey + GetLayerOffset(dstTexture, layer), layer); } - DstLayerIndex = 0; + dstLayerIndex = 0; } - int SrcBlitX1 = (int)(SrcBlitX >> 32); - int SrcBlitY1 = (int)(SrcBlitY >> 32); + int srcBlitX1 = (int)(srcBlitX >> 32); + int srcBlitY1 = (int)(srcBlitY >> 32); - int SrcBlitX2 = (int)(SrcBlitX + DstBlitW * BlitDuDx >> 32); - int SrcBlitY2 = (int)(SrcBlitY + DstBlitH * BlitDvDy >> 32); + int srcBlitX2 = (int)(srcBlitX + dstBlitW * blitDuDx >> 32); + int srcBlitY2 = (int)(srcBlitY + dstBlitH * blitDvDy >> 32); - Gpu.Renderer.RenderTarget.Copy( - SrcTexture, - DstTexture, - SrcKey, - DstKey, - SrcLayerIndex, - DstLayerIndex, - SrcBlitX1, - SrcBlitY1, - SrcBlitX2, - SrcBlitY2, - DstBlitX, - DstBlitY, - DstBlitX + DstBlitW, - DstBlitY + DstBlitH); + _gpu.Renderer.RenderTarget.Copy( + srcTexture, + dstTexture, + srcKey, + dstKey, + srcLayerIndex, + dstLayerIndex, + srcBlitX1, + srcBlitY1, + srcBlitX2, + srcBlitY2, + dstBlitX, + dstBlitY, + dstBlitX + dstBlitW, + dstBlitY + dstBlitH); //Do a guest side copy aswell. This is necessary when //the texture is modified by the guest, however it doesn't @@ -209,51 +208,51 @@ namespace Ryujinx.Graphics.Graphics3d // FIXME: SUPPORT MULTILAYER CORRECTLY HERE (this will cause weird stuffs on the first layer) ImageUtils.CopyTexture( - Vmm, - SrcTexture, - DstTexture, - SrcAddress, - DstAddress, - SrcBlitX1, - SrcBlitY1, - DstBlitX, - DstBlitY, - DstBlitW, - DstBlitH); + vmm, + srcTexture, + dstTexture, + srcAddress, + dstAddress, + srcBlitX1, + srcBlitY1, + dstBlitX, + dstBlitY, + dstBlitW, + dstBlitH); - Vmm.IsRegionModified(DstKey, ImageUtils.GetSize(DstTexture), NvGpuBufferType.Texture); + vmm.IsRegionModified(dstKey, ImageUtils.GetSize(dstTexture), NvGpuBufferType.Texture); } - private static GalMemoryLayout GetLayout(bool Linear) + private static GalMemoryLayout GetLayout(bool linear) { - return Linear + return linear ? GalMemoryLayout.Pitch : GalMemoryLayout.BlockLinear; } - private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg) + private long MakeInt64From2xInt32(NvGpuEngine2dReg reg) { return - (long)Registers[(int)Reg + 0] << 32 | - (uint)Registers[(int)Reg + 1]; + (long)Registers[(int)reg + 0] << 32 | + (uint)Registers[(int)reg + 1]; } - private void WriteRegister(GpuMethodCall MethCall) + private void WriteRegister(GpuMethodCall methCall) { - Registers[MethCall.Method] = MethCall.Argument; + Registers[methCall.Method] = methCall.Argument; } - private long ReadRegisterFixed1_31_32(NvGpuEngine2dReg Reg) + private long ReadRegisterFixed1_31_32(NvGpuEngine2dReg reg) { - long Low = (uint)ReadRegister(Reg + 0); - long High = (uint)ReadRegister(Reg + 1); + long low = (uint)ReadRegister(reg + 0); + long high = (uint)ReadRegister(reg + 1); - return Low | (High << 32); + return low | (high << 32); } - private int ReadRegister(NvGpuEngine2dReg Reg) + private int ReadRegister(NvGpuEngine2dReg reg) { - return Registers[(int)Reg]; + return Registers[(int)reg]; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs index 370fe1fa86..605cbda816 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs @@ -1,5 +1,4 @@ using Ryujinx.Common; -using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; @@ -12,9 +11,9 @@ namespace Ryujinx.Graphics.Graphics3d { public int[] Registers { get; private set; } - private NvGpu Gpu; + private NvGpu _gpu; - private Dictionary Methods; + private Dictionary _methods; private struct ConstBuffer { @@ -23,33 +22,33 @@ namespace Ryujinx.Graphics.Graphics3d public int Size; } - private ConstBuffer[][] ConstBuffers; + private ConstBuffer[][] _constBuffers; // Viewport dimensions kept for scissor test limits - private int ViewportX0 = 0; - private int ViewportY0 = 0; - private int ViewportX1 = 0; - private int ViewportY1 = 0; - private int ViewportWidth = 0; - private int ViewportHeight = 0; + private int _viewportX0 = 0; + private int _viewportY0 = 0; + private int _viewportX1 = 0; + private int _viewportY1 = 0; + private int _viewportWidth = 0; + private int _viewportHeight = 0; - private int CurrentInstance = 0; + private int _currentInstance = 0; - public NvGpuEngine3d(NvGpu Gpu) + public NvGpuEngine3d(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; Registers = new int[0xe00]; - Methods = new Dictionary(); + _methods = new Dictionary(); - void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) + void AddMethod(int meth, int count, int stride, NvGpuMethod method) { - while (Count-- > 0) + while (count-- > 0) { - Methods.Add(Meth, Method); + _methods.Add(meth, method); - Meth += Stride; + meth += stride; } } @@ -59,11 +58,11 @@ namespace Ryujinx.Graphics.Graphics3d AddMethod(0x8e4, 16, 1, CbData); AddMethod(0x904, 5, 8, CbBind); - ConstBuffers = new ConstBuffer[6][]; + _constBuffers = new ConstBuffer[6][]; - for (int Index = 0; Index < ConstBuffers.Length; Index++) + for (int index = 0; index < _constBuffers.Length; index++) { - ConstBuffers[Index] = new ConstBuffer[18]; + _constBuffers[index] = new ConstBuffer[18]; } //Ensure that all components are enabled by default. @@ -72,227 +71,227 @@ namespace Ryujinx.Graphics.Graphics3d WriteRegister(NvGpuEngine3dReg.FrameBufferSrgb, 1); - WriteRegister(NvGpuEngine3dReg.FrontFace, (int)GalFrontFace.CW); + WriteRegister(NvGpuEngine3dReg.FrontFace, (int)GalFrontFace.Cw); - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) { - WriteRegister(NvGpuEngine3dReg.IBlendNEquationRgb + Index * 8, (int)GalBlendEquation.FuncAdd); - WriteRegister(NvGpuEngine3dReg.IBlendNFuncSrcRgb + Index * 8, (int)GalBlendFactor.One); - WriteRegister(NvGpuEngine3dReg.IBlendNFuncDstRgb + Index * 8, (int)GalBlendFactor.Zero); - WriteRegister(NvGpuEngine3dReg.IBlendNEquationAlpha + Index * 8, (int)GalBlendEquation.FuncAdd); - WriteRegister(NvGpuEngine3dReg.IBlendNFuncSrcAlpha + Index * 8, (int)GalBlendFactor.One); - WriteRegister(NvGpuEngine3dReg.IBlendNFuncDstAlpha + Index * 8, (int)GalBlendFactor.Zero); + WriteRegister(NvGpuEngine3dReg.IBlendNEquationRgb + index * 8, (int)GalBlendEquation.FuncAdd); + WriteRegister(NvGpuEngine3dReg.IBlendNFuncSrcRgb + index * 8, (int)GalBlendFactor.One); + WriteRegister(NvGpuEngine3dReg.IBlendNFuncDstRgb + index * 8, (int)GalBlendFactor.Zero); + WriteRegister(NvGpuEngine3dReg.IBlendNEquationAlpha + index * 8, (int)GalBlendEquation.FuncAdd); + WriteRegister(NvGpuEngine3dReg.IBlendNFuncSrcAlpha + index * 8, (int)GalBlendFactor.One); + WriteRegister(NvGpuEngine3dReg.IBlendNFuncDstAlpha + index * 8, (int)GalBlendFactor.Zero); } } - public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - if (Methods.TryGetValue(MethCall.Method, out NvGpuMethod Method)) + if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method)) { - Method(Vmm, MethCall); + method(vmm, methCall); } else { - WriteRegister(MethCall); + WriteRegister(methCall); } } - private void VertexEndGl(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void VertexEndGl(NvGpuVmm vmm, GpuMethodCall methCall) { LockCaches(); - GalPipelineState State = new GalPipelineState(); + GalPipelineState state = new GalPipelineState(); // Framebuffer must be run configured because viewport dimensions may be used in other methods - SetFrameBuffer(State); + SetFrameBuffer(state); - for (int FbIndex = 0; FbIndex < 8; FbIndex++) + for (int fbIndex = 0; fbIndex < 8; fbIndex++) { - SetFrameBuffer(Vmm, FbIndex); + SetFrameBuffer(vmm, fbIndex); } - SetFrontFace(State); - SetCullFace(State); - SetDepth(State); - SetStencil(State); - SetScissor(State); - SetBlending(State); - SetColorMask(State); - SetPrimitiveRestart(State); + SetFrontFace(state); + SetCullFace(state); + SetDepth(state); + SetStencil(state); + SetScissor(state); + SetBlending(state); + SetColorMask(state); + SetPrimitiveRestart(state); - SetZeta(Vmm); + SetZeta(vmm); SetRenderTargets(); - long[] Keys = UploadShaders(Vmm); + long[] keys = UploadShaders(vmm); - Gpu.Renderer.Shader.BindProgram(); + _gpu.Renderer.Shader.BindProgram(); - UploadTextures(Vmm, State, Keys); - UploadConstBuffers(Vmm, State, Keys); - UploadVertexArrays(Vmm, State); + UploadTextures(vmm, state, keys); + UploadConstBuffers(vmm, state, keys); + UploadVertexArrays(vmm, state); - DispatchRender(Vmm, State); + DispatchRender(vmm, state); UnlockCaches(); } private void LockCaches() { - Gpu.Renderer.Buffer.LockCache(); - Gpu.Renderer.Rasterizer.LockCaches(); - Gpu.Renderer.Texture.LockCache(); + _gpu.Renderer.Buffer.LockCache(); + _gpu.Renderer.Rasterizer.LockCaches(); + _gpu.Renderer.Texture.LockCache(); } private void UnlockCaches() { - Gpu.Renderer.Buffer.UnlockCache(); - Gpu.Renderer.Rasterizer.UnlockCaches(); - Gpu.Renderer.Texture.UnlockCache(); + _gpu.Renderer.Buffer.UnlockCache(); + _gpu.Renderer.Rasterizer.UnlockCaches(); + _gpu.Renderer.Texture.UnlockCache(); } - private void ClearBuffers(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void ClearBuffers(NvGpuVmm vmm, GpuMethodCall methCall) { - int Attachment = (MethCall.Argument >> 6) & 0xf; + int attachment = (methCall.Argument >> 6) & 0xf; - GalClearBufferFlags Flags = (GalClearBufferFlags)(MethCall.Argument & 0x3f); + GalClearBufferFlags flags = (GalClearBufferFlags)(methCall.Argument & 0x3f); - float Red = ReadRegisterFloat(NvGpuEngine3dReg.ClearNColor + 0); - float Green = ReadRegisterFloat(NvGpuEngine3dReg.ClearNColor + 1); - float Blue = ReadRegisterFloat(NvGpuEngine3dReg.ClearNColor + 2); - float Alpha = ReadRegisterFloat(NvGpuEngine3dReg.ClearNColor + 3); + float red = ReadRegisterFloat(NvGpuEngine3dReg.ClearNColor + 0); + float green = ReadRegisterFloat(NvGpuEngine3dReg.ClearNColor + 1); + float blue = ReadRegisterFloat(NvGpuEngine3dReg.ClearNColor + 2); + float alpha = ReadRegisterFloat(NvGpuEngine3dReg.ClearNColor + 3); - float Depth = ReadRegisterFloat(NvGpuEngine3dReg.ClearDepth); + float depth = ReadRegisterFloat(NvGpuEngine3dReg.ClearDepth); - int Stencil = ReadRegister(NvGpuEngine3dReg.ClearStencil); + int stencil = ReadRegister(NvGpuEngine3dReg.ClearStencil); - SetFrameBuffer(Vmm, Attachment); + SetFrameBuffer(vmm, attachment); - SetZeta(Vmm); + SetZeta(vmm); SetRenderTargets(); - Gpu.Renderer.RenderTarget.Bind(); + _gpu.Renderer.RenderTarget.Bind(); - Gpu.Renderer.Rasterizer.ClearBuffers(Flags, Attachment, Red, Green, Blue, Alpha, Depth, Stencil); + _gpu.Renderer.Rasterizer.ClearBuffers(flags, attachment, red, green, blue, alpha, depth, stencil); - Gpu.Renderer.Pipeline.ResetDepthMask(); - Gpu.Renderer.Pipeline.ResetColorMask(Attachment); + _gpu.Renderer.Pipeline.ResetDepthMask(); + _gpu.Renderer.Pipeline.ResetColorMask(attachment); } - private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex) + private void SetFrameBuffer(NvGpuVmm vmm, int fbIndex) { - long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + FbIndex * 0x10); + long va = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + fbIndex * 0x10); - int SurfFormat = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + FbIndex * 0x10); + int surfFormat = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + fbIndex * 0x10); - if (VA == 0 || SurfFormat == 0) + if (va == 0 || surfFormat == 0) { - Gpu.Renderer.RenderTarget.UnbindColor(FbIndex); + _gpu.Renderer.RenderTarget.UnbindColor(fbIndex); return; } - long Key = Vmm.GetPhysicalAddress(VA); + long key = vmm.GetPhysicalAddress(va); - int Width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + FbIndex * 0x10); - int Height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + FbIndex * 0x10); + int width = ReadRegister(NvGpuEngine3dReg.FrameBufferNWidth + fbIndex * 0x10); + int height = ReadRegister(NvGpuEngine3dReg.FrameBufferNHeight + fbIndex * 0x10); - int ArrayMode = ReadRegister(NvGpuEngine3dReg.FrameBufferNArrayMode + FbIndex * 0x10); - int LayerCount = ArrayMode & 0xFFFF; - int LayerStride = ReadRegister(NvGpuEngine3dReg.FrameBufferNLayerStride + FbIndex * 0x10); - int BaseLayer = ReadRegister(NvGpuEngine3dReg.FrameBufferNBaseLayer + FbIndex * 0x10); - int BlockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + FbIndex * 0x10); + int arrayMode = ReadRegister(NvGpuEngine3dReg.FrameBufferNArrayMode + fbIndex * 0x10); + int layerCount = arrayMode & 0xFFFF; + int layerStride = ReadRegister(NvGpuEngine3dReg.FrameBufferNLayerStride + fbIndex * 0x10); + int baseLayer = ReadRegister(NvGpuEngine3dReg.FrameBufferNBaseLayer + fbIndex * 0x10); + int blockDim = ReadRegister(NvGpuEngine3dReg.FrameBufferNBlockDim + fbIndex * 0x10); - int GobBlockHeight = 1 << ((BlockDim >> 4) & 7); + int gobBlockHeight = 1 << ((blockDim >> 4) & 7); - GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1); + GalMemoryLayout layout = (GalMemoryLayout)((blockDim >> 12) & 1); - float TX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + FbIndex * 8); - float TY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + FbIndex * 8); + float tx = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateX + fbIndex * 8); + float ty = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNTranslateY + fbIndex * 8); - float SX = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + FbIndex * 8); - float SY = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + FbIndex * 8); + float sx = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleX + fbIndex * 8); + float sy = ReadRegisterFloat(NvGpuEngine3dReg.ViewportNScaleY + fbIndex * 8); - ViewportX0 = (int)MathF.Max(0, TX - MathF.Abs(SX)); - ViewportY0 = (int)MathF.Max(0, TY - MathF.Abs(SY)); + _viewportX0 = (int)MathF.Max(0, tx - MathF.Abs(sx)); + _viewportY0 = (int)MathF.Max(0, ty - MathF.Abs(sy)); - ViewportX1 = (int)(TX + MathF.Abs(SX)); - ViewportY1 = (int)(TY + MathF.Abs(SY)); + _viewportX1 = (int)(tx + MathF.Abs(sx)); + _viewportY1 = (int)(ty + MathF.Abs(sy)); - GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat); + GalImageFormat format = ImageUtils.ConvertSurface((GalSurfaceFormat)surfFormat); - GalImage Image = new GalImage(Width, Height, 1, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD); + GalImage image = new GalImage(width, height, 1, 1, 1, gobBlockHeight, 1, layout, format, GalTextureTarget.TwoD); - Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image); + _gpu.ResourceManager.SendColorBuffer(vmm, key, fbIndex, image); - Gpu.Renderer.RenderTarget.SetViewport(FbIndex, ViewportX0, ViewportY0, ViewportX1 - ViewportX0, ViewportY1 - ViewportY0); + _gpu.Renderer.RenderTarget.SetViewport(fbIndex, _viewportX0, _viewportY0, _viewportX1 - _viewportX0, _viewportY1 - _viewportY0); } - private void SetFrameBuffer(GalPipelineState State) + private void SetFrameBuffer(GalPipelineState state) { - State.FramebufferSrgb = ReadRegisterBool(NvGpuEngine3dReg.FrameBufferSrgb); + state.FramebufferSrgb = ReadRegisterBool(NvGpuEngine3dReg.FrameBufferSrgb); - State.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); - State.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); + state.FlipX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); + state.FlipY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); - int ScreenYControl = ReadRegister(NvGpuEngine3dReg.ScreenYControl); + int screenYControl = ReadRegister(NvGpuEngine3dReg.ScreenYControl); - bool NegateY = (ScreenYControl & 1) != 0; + bool negateY = (screenYControl & 1) != 0; - if (NegateY) + if (negateY) { - State.FlipY = -State.FlipY; + state.FlipY = -state.FlipY; } } - private void SetZeta(NvGpuVmm Vmm) + private void SetZeta(NvGpuVmm vmm) { - long VA = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); + long va = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress); - int ZetaFormat = ReadRegister(NvGpuEngine3dReg.ZetaFormat); + int zetaFormat = ReadRegister(NvGpuEngine3dReg.ZetaFormat); - int BlockDim = ReadRegister(NvGpuEngine3dReg.ZetaBlockDimensions); + int blockDim = ReadRegister(NvGpuEngine3dReg.ZetaBlockDimensions); - int GobBlockHeight = 1 << ((BlockDim >> 4) & 7); + int gobBlockHeight = 1 << ((blockDim >> 4) & 7); - GalMemoryLayout Layout = (GalMemoryLayout)((BlockDim >> 12) & 1); //? + GalMemoryLayout layout = (GalMemoryLayout)((blockDim >> 12) & 1); //? - bool ZetaEnable = ReadRegisterBool(NvGpuEngine3dReg.ZetaEnable); + bool zetaEnable = ReadRegisterBool(NvGpuEngine3dReg.ZetaEnable); - if (VA == 0 || ZetaFormat == 0 || !ZetaEnable) + if (va == 0 || zetaFormat == 0 || !zetaEnable) { - Gpu.Renderer.RenderTarget.UnbindZeta(); + _gpu.Renderer.RenderTarget.UnbindZeta(); return; } - long Key = Vmm.GetPhysicalAddress(VA); + long key = vmm.GetPhysicalAddress(va); - int Width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz); - int Height = ReadRegister(NvGpuEngine3dReg.ZetaVert); + int width = ReadRegister(NvGpuEngine3dReg.ZetaHoriz); + int height = ReadRegister(NvGpuEngine3dReg.ZetaVert); - GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat); + GalImageFormat format = ImageUtils.ConvertZeta((GalZetaFormat)zetaFormat); // TODO: Support non 2D? - GalImage Image = new GalImage(Width, Height, 1, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD); + GalImage image = new GalImage(width, height, 1, 1, 1, gobBlockHeight, 1, layout, format, GalTextureTarget.TwoD); - Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image); + _gpu.ResourceManager.SendZetaBuffer(vmm, key, image); } - private long[] UploadShaders(NvGpuVmm Vmm) + private long[] UploadShaders(NvGpuVmm vmm) { - long[] Keys = new long[5]; + long[] keys = new long[5]; - long BasePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); + long basePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); - int Index = 1; + int index = 1; - int VpAControl = ReadRegister(NvGpuEngine3dReg.ShaderNControl); + int vpAControl = ReadRegister(NvGpuEngine3dReg.ShaderNControl); - bool VpAEnable = (VpAControl & 1) != 0; + bool vpAEnable = (vpAControl & 1) != 0; - if (VpAEnable) + if (vpAEnable) { //Note: The maxwell supports 2 vertex programs, usually //only VP B is used, but in some cases VP A is also used. @@ -300,51 +299,51 @@ namespace Ryujinx.Graphics.Graphics3d //shader stage. //The graphics abstraction layer has a special overload for this //case, which should merge the two shaders into one vertex shader. - int VpAOffset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset); - int VpBOffset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + 0x10); + int vpAOffset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset); + int vpBOffset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + 0x10); - long VpAPos = BasePosition + (uint)VpAOffset; - long VpBPos = BasePosition + (uint)VpBOffset; + long vpAPos = basePosition + (uint)vpAOffset; + long vpBPos = basePosition + (uint)vpBOffset; - Keys[(int)GalShaderType.Vertex] = VpBPos; + keys[(int)GalShaderType.Vertex] = vpBPos; - Gpu.Renderer.Shader.Create(Vmm, VpAPos, VpBPos, GalShaderType.Vertex); - Gpu.Renderer.Shader.Bind(VpBPos); + _gpu.Renderer.Shader.Create(vmm, vpAPos, vpBPos, GalShaderType.Vertex); + _gpu.Renderer.Shader.Bind(vpBPos); - Index = 2; + index = 2; } - for (; Index < 6; Index++) + for (; index < 6; index++) { - GalShaderType Type = GetTypeFromProgram(Index); + GalShaderType type = GetTypeFromProgram(index); - int Control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + Index * 0x10); - int Offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + Index * 0x10); + int control = ReadRegister(NvGpuEngine3dReg.ShaderNControl + index * 0x10); + int offset = ReadRegister(NvGpuEngine3dReg.ShaderNOffset + index * 0x10); //Note: Vertex Program (B) is always enabled. - bool Enable = (Control & 1) != 0 || Index == 1; + bool enable = (control & 1) != 0 || index == 1; - if (!Enable) + if (!enable) { - Gpu.Renderer.Shader.Unbind(Type); + _gpu.Renderer.Shader.Unbind(type); continue; } - long Key = BasePosition + (uint)Offset; + long key = basePosition + (uint)offset; - Keys[(int)Type] = Key; + keys[(int)type] = key; - Gpu.Renderer.Shader.Create(Vmm, Key, Type); - Gpu.Renderer.Shader.Bind(Key); + _gpu.Renderer.Shader.Create(vmm, key, type); + _gpu.Renderer.Shader.Bind(key); } - return Keys; + return keys; } - private static GalShaderType GetTypeFromProgram(int Program) + private static GalShaderType GetTypeFromProgram(int program) { - switch (Program) + switch (program) { case 0: case 1: return GalShaderType.Vertex; @@ -354,104 +353,104 @@ namespace Ryujinx.Graphics.Graphics3d case 5: return GalShaderType.Fragment; } - throw new ArgumentOutOfRangeException(nameof(Program)); + throw new ArgumentOutOfRangeException(nameof(program)); } - private void SetFrontFace(GalPipelineState State) + private void SetFrontFace(GalPipelineState state) { - float SignX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); - float SignY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); + float signX = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleX); + float signY = GetFlipSign(NvGpuEngine3dReg.ViewportNScaleY); - GalFrontFace FrontFace = (GalFrontFace)ReadRegister(NvGpuEngine3dReg.FrontFace); + GalFrontFace frontFace = (GalFrontFace)ReadRegister(NvGpuEngine3dReg.FrontFace); //Flipping breaks facing. Flipping front facing too fixes it - if (SignX != SignY) + if (signX != signY) { - switch (FrontFace) + switch (frontFace) { - case GalFrontFace.CW: FrontFace = GalFrontFace.CCW; break; - case GalFrontFace.CCW: FrontFace = GalFrontFace.CW; break; + case GalFrontFace.Cw: frontFace = GalFrontFace.Ccw; break; + case GalFrontFace.Ccw: frontFace = GalFrontFace.Cw; break; } } - State.FrontFace = FrontFace; + state.FrontFace = frontFace; } - private void SetCullFace(GalPipelineState State) + private void SetCullFace(GalPipelineState state) { - State.CullFaceEnabled = ReadRegisterBool(NvGpuEngine3dReg.CullFaceEnable); + state.CullFaceEnabled = ReadRegisterBool(NvGpuEngine3dReg.CullFaceEnable); - if (State.CullFaceEnabled) + if (state.CullFaceEnabled) { - State.CullFace = (GalCullFace)ReadRegister(NvGpuEngine3dReg.CullFace); + state.CullFace = (GalCullFace)ReadRegister(NvGpuEngine3dReg.CullFace); } } - private void SetDepth(GalPipelineState State) + private void SetDepth(GalPipelineState state) { - State.DepthTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthTestEnable); + state.DepthTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthTestEnable); - State.DepthWriteEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthWriteEnable); + state.DepthWriteEnabled = ReadRegisterBool(NvGpuEngine3dReg.DepthWriteEnable); - if (State.DepthTestEnabled) + if (state.DepthTestEnabled) { - State.DepthFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.DepthTestFunction); + state.DepthFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.DepthTestFunction); } - State.DepthRangeNear = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNNear); - State.DepthRangeFar = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNFar); + state.DepthRangeNear = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNNear); + state.DepthRangeFar = ReadRegisterFloat(NvGpuEngine3dReg.DepthRangeNFar); } - private void SetStencil(GalPipelineState State) + private void SetStencil(GalPipelineState state) { - State.StencilTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.StencilEnable); + state.StencilTestEnabled = ReadRegisterBool(NvGpuEngine3dReg.StencilEnable); - if (State.StencilTestEnabled) + if (state.StencilTestEnabled) { - State.StencilBackFuncFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.StencilBackFuncFunc); - State.StencilBackFuncRef = ReadRegister(NvGpuEngine3dReg.StencilBackFuncRef); - State.StencilBackFuncMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilBackFuncMask); - State.StencilBackOpFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpFail); - State.StencilBackOpZFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpZFail); - State.StencilBackOpZPass = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpZPass); - State.StencilBackMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilBackMask); + state.StencilBackFuncFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.StencilBackFuncFunc); + state.StencilBackFuncRef = ReadRegister(NvGpuEngine3dReg.StencilBackFuncRef); + state.StencilBackFuncMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilBackFuncMask); + state.StencilBackOpFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpFail); + state.StencilBackOpZFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpZFail); + state.StencilBackOpZPass = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilBackOpZPass); + state.StencilBackMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilBackMask); - State.StencilFrontFuncFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.StencilFrontFuncFunc); - State.StencilFrontFuncRef = ReadRegister(NvGpuEngine3dReg.StencilFrontFuncRef); - State.StencilFrontFuncMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilFrontFuncMask); - State.StencilFrontOpFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpFail); - State.StencilFrontOpZFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpZFail); - State.StencilFrontOpZPass = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpZPass); - State.StencilFrontMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilFrontMask); + state.StencilFrontFuncFunc = (GalComparisonOp)ReadRegister(NvGpuEngine3dReg.StencilFrontFuncFunc); + state.StencilFrontFuncRef = ReadRegister(NvGpuEngine3dReg.StencilFrontFuncRef); + state.StencilFrontFuncMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilFrontFuncMask); + state.StencilFrontOpFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpFail); + state.StencilFrontOpZFail = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpZFail); + state.StencilFrontOpZPass = (GalStencilOp)ReadRegister(NvGpuEngine3dReg.StencilFrontOpZPass); + state.StencilFrontMask = (uint)ReadRegister(NvGpuEngine3dReg.StencilFrontMask); } } - private void SetScissor(GalPipelineState State) + private void SetScissor(GalPipelineState state) { int count = 0; - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) { - State.ScissorTestEnabled[Index] = ReadRegisterBool(NvGpuEngine3dReg.ScissorEnable + Index * 4); + state.ScissorTestEnabled[index] = ReadRegisterBool(NvGpuEngine3dReg.ScissorEnable + index * 4); - if (State.ScissorTestEnabled[Index]) + if (state.ScissorTestEnabled[index]) { - uint ScissorHorizontal = (uint)ReadRegister(NvGpuEngine3dReg.ScissorHorizontal + Index * 4); - uint ScissorVertical = (uint)ReadRegister(NvGpuEngine3dReg.ScissorVertical + Index * 4); + uint scissorHorizontal = (uint)ReadRegister(NvGpuEngine3dReg.ScissorHorizontal + index * 4); + uint scissorVertical = (uint)ReadRegister(NvGpuEngine3dReg.ScissorVertical + index * 4); - int left = (int)(ScissorHorizontal & 0xFFFF); // Left, lower 16 bits - int right = (int)(ScissorHorizontal >> 16); // Right, upper 16 bits + int left = (int)(scissorHorizontal & 0xFFFF); // Left, lower 16 bits + int right = (int)(scissorHorizontal >> 16); // Right, upper 16 bits - int bottom = (int)(ScissorVertical & 0xFFFF); // Bottom, lower 16 bits - int top = (int)(ScissorVertical >> 16); // Top, upper 16 bits + int bottom = (int)(scissorVertical & 0xFFFF); // Bottom, lower 16 bits + int top = (int)(scissorVertical >> 16); // Top, upper 16 bits int width = Math.Abs(right - left); int height = Math.Abs(top - bottom); - // If the scissor test covers the whole possible viewport, i.e. uninititalized, disable scissor test + // If the scissor test covers the whole possible viewport, i.e. uninitialized, disable scissor test if ((width > NvGpu.MaxViewportSize && height > NvGpu.MaxViewportSize) || width <= 0 || height <= 0) { - State.ScissorTestEnabled[Index] = false; + state.ScissorTestEnabled[index] = false; continue; } @@ -460,10 +459,10 @@ namespace Ryujinx.Graphics.Graphics3d count++; // Flip X - if (State.FlipX == -1) + if (state.FlipX == -1) { - left = ViewportX1 - (left - ViewportX0); - right = ViewportX1 - (right - ViewportX0); + left = _viewportX1 - (left - _viewportX0); + right = _viewportX1 - (right - _viewportX0); } // Ensure X is in the right order @@ -475,10 +474,10 @@ namespace Ryujinx.Graphics.Graphics3d } // Flip Y - if (State.FlipY == -1) + if (state.FlipY == -1) { - bottom = ViewportY1 - (bottom - ViewportY0); - top = ViewportY1 - (top - ViewportY0); + bottom = _viewportY1 - (bottom - _viewportY0); + top = _viewportY1 - (top - _viewportY0); } // Ensure Y is in the right order @@ -490,102 +489,102 @@ namespace Ryujinx.Graphics.Graphics3d } // Handle out of active viewport dimensions - left = Math.Clamp(left, ViewportX0, ViewportX1); - right = Math.Clamp(right, ViewportX0, ViewportX1); - top = Math.Clamp(top, ViewportY0, ViewportY1); - bottom = Math.Clamp(bottom, ViewportY0, ViewportY1); + left = Math.Clamp(left, _viewportX0, _viewportX1); + right = Math.Clamp(right, _viewportX0, _viewportX1); + top = Math.Clamp(top, _viewportY0, _viewportY1); + bottom = Math.Clamp(bottom, _viewportY0, _viewportY1); // Save values to state - State.ScissorTestX[Index] = left; - State.ScissorTestY[Index] = bottom; + state.ScissorTestX[index] = left; + state.ScissorTestY[index] = bottom; - State.ScissorTestWidth[Index] = right - left; - State.ScissorTestHeight[Index] = top - bottom; + state.ScissorTestWidth[index] = right - left; + state.ScissorTestHeight[index] = top - bottom; } } - State.ScissorTestCount = count; + state.ScissorTestCount = count; } - private void SetBlending(GalPipelineState State) + private void SetBlending(GalPipelineState state) { - bool BlendIndependent = ReadRegisterBool(NvGpuEngine3dReg.BlendIndependent); + bool blendIndependent = ReadRegisterBool(NvGpuEngine3dReg.BlendIndependent); - State.BlendIndependent = BlendIndependent; + state.BlendIndependent = blendIndependent; - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) { - if (BlendIndependent) + if (blendIndependent) { - State.Blends[Index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable + Index); + state.Blends[index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable + index); - if (State.Blends[Index].Enabled) + if (state.Blends[index].Enabled) { - State.Blends[Index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha + Index * 8); + state.Blends[index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.IBlendNSeparateAlpha + index * 8); - State.Blends[Index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationRgb + Index * 8); - State.Blends[Index].FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcRgb + Index * 8); - State.Blends[Index].FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstRgb + Index * 8); - State.Blends[Index].EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationAlpha + Index * 8); - State.Blends[Index].FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcAlpha + Index * 8); - State.Blends[Index].FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstAlpha + Index * 8); + state.Blends[index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationRgb + index * 8); + state.Blends[index].FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcRgb + index * 8); + state.Blends[index].FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstRgb + index * 8); + state.Blends[index].EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.IBlendNEquationAlpha + index * 8); + state.Blends[index].FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncSrcAlpha + index * 8); + state.Blends[index].FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.IBlendNFuncDstAlpha + index * 8); } } else { //It seems that even when independent blend is disabled, the first IBlend enable //register is still set to indicate whenever blend is enabled or not (?). - State.Blends[Index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable); + state.Blends[index].Enabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable); - if (State.Blends[Index].Enabled) + if (state.Blends[index].Enabled) { - State.Blends[Index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.BlendSeparateAlpha); + state.Blends[index].SeparateAlpha = ReadRegisterBool(NvGpuEngine3dReg.BlendSeparateAlpha); - State.Blends[Index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationRgb); - State.Blends[Index].FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcRgb); - State.Blends[Index].FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstRgb); - State.Blends[Index].EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationAlpha); - State.Blends[Index].FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcAlpha); - State.Blends[Index].FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstAlpha); + state.Blends[index].EquationRgb = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationRgb); + state.Blends[index].FuncSrcRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcRgb); + state.Blends[index].FuncDstRgb = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstRgb); + state.Blends[index].EquationAlpha = ReadBlendEquation(NvGpuEngine3dReg.BlendEquationAlpha); + state.Blends[index].FuncSrcAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncSrcAlpha); + state.Blends[index].FuncDstAlpha = ReadBlendFactor (NvGpuEngine3dReg.BlendFuncDstAlpha); } } } } - private GalBlendEquation ReadBlendEquation(NvGpuEngine3dReg Register) + private GalBlendEquation ReadBlendEquation(NvGpuEngine3dReg register) { - return (GalBlendEquation)ReadRegister(Register); + return (GalBlendEquation)ReadRegister(register); } - private GalBlendFactor ReadBlendFactor(NvGpuEngine3dReg Register) + private GalBlendFactor ReadBlendFactor(NvGpuEngine3dReg register) { - return (GalBlendFactor)ReadRegister(Register); + return (GalBlendFactor)ReadRegister(register); } - private void SetColorMask(GalPipelineState State) + private void SetColorMask(GalPipelineState state) { - bool ColorMaskCommon = ReadRegisterBool(NvGpuEngine3dReg.ColorMaskCommon); + bool colorMaskCommon = ReadRegisterBool(NvGpuEngine3dReg.ColorMaskCommon); - State.ColorMaskCommon = ColorMaskCommon; + state.ColorMaskCommon = colorMaskCommon; - for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++) + for (int index = 0; index < GalPipelineState.RenderTargetsCount; index++) { - int ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMaskN + (ColorMaskCommon ? 0 : Index)); + int colorMask = ReadRegister(NvGpuEngine3dReg.ColorMaskN + (colorMaskCommon ? 0 : index)); - State.ColorMasks[Index].Red = ((ColorMask >> 0) & 0xf) != 0; - State.ColorMasks[Index].Green = ((ColorMask >> 4) & 0xf) != 0; - State.ColorMasks[Index].Blue = ((ColorMask >> 8) & 0xf) != 0; - State.ColorMasks[Index].Alpha = ((ColorMask >> 12) & 0xf) != 0; + state.ColorMasks[index].Red = ((colorMask >> 0) & 0xf) != 0; + state.ColorMasks[index].Green = ((colorMask >> 4) & 0xf) != 0; + state.ColorMasks[index].Blue = ((colorMask >> 8) & 0xf) != 0; + state.ColorMasks[index].Alpha = ((colorMask >> 12) & 0xf) != 0; } } - private void SetPrimitiveRestart(GalPipelineState State) + private void SetPrimitiveRestart(GalPipelineState state) { - State.PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable); + state.PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable); - if (State.PrimitiveRestartEnabled) + if (state.PrimitiveRestartEnabled) { - State.PrimitiveRestartIndex = (uint)ReadRegister(NvGpuEngine3dReg.PrimRestartIndex); + state.PrimitiveRestartIndex = (uint)ReadRegister(NvGpuEngine3dReg.PrimRestartIndex); } } @@ -594,461 +593,461 @@ namespace Ryujinx.Graphics.Graphics3d //Commercial games do not seem to //bool SeparateFragData = ReadRegisterBool(NvGpuEngine3dReg.RTSeparateFragData); - uint Control = (uint)(ReadRegister(NvGpuEngine3dReg.RTControl)); + uint control = (uint)(ReadRegister(NvGpuEngine3dReg.RtControl)); - uint Count = Control & 0xf; + uint count = control & 0xf; - if (Count > 0) + if (count > 0) { - int[] Map = new int[Count]; + int[] map = new int[count]; - for (int Index = 0; Index < Count; Index++) + for (int index = 0; index < count; index++) { - int Shift = 4 + Index * 3; + int shift = 4 + index * 3; - Map[Index] = (int)((Control >> Shift) & 7); + map[index] = (int)((control >> shift) & 7); } - Gpu.Renderer.RenderTarget.SetMap(Map); + _gpu.Renderer.RenderTarget.SetMap(map); } else { - Gpu.Renderer.RenderTarget.SetMap(null); + _gpu.Renderer.RenderTarget.SetMap(null); } } - private void UploadTextures(NvGpuVmm Vmm, GalPipelineState State, long[] Keys) + private void UploadTextures(NvGpuVmm vmm, GalPipelineState state, long[] keys) { - long BaseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); + long baseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress); - int TextureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex); + int textureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex); - List<(long, GalImage, GalTextureSampler)> UnboundTextures = new List<(long, GalImage, GalTextureSampler)>(); + List<(long, GalImage, GalTextureSampler)> unboundTextures = new List<(long, GalImage, GalTextureSampler)>(); - for (int Index = 0; Index < Keys.Length; Index++) + for (int index = 0; index < keys.Length; index++) { - foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.Shader.GetTextureUsage(Keys[Index])) + foreach (ShaderDeclInfo declInfo in _gpu.Renderer.Shader.GetTextureUsage(keys[index])) { - long Position; + long position; - if (DeclInfo.IsCb) + if (declInfo.IsCb) { - Position = ConstBuffers[Index][DeclInfo.Cbuf].Position; + position = _constBuffers[index][declInfo.Cbuf].Position; } else { - Position = ConstBuffers[Index][TextureCbIndex].Position; + position = _constBuffers[index][textureCbIndex].Position; } - int TextureHandle = Vmm.ReadInt32(Position + DeclInfo.Index * 4); + int textureHandle = vmm.ReadInt32(position + declInfo.Index * 4); - UnboundTextures.Add(UploadTexture(Vmm, TextureHandle)); + unboundTextures.Add(UploadTexture(vmm, textureHandle)); } } - for (int Index = 0; Index < UnboundTextures.Count; Index++) + for (int index = 0; index < unboundTextures.Count; index++) { - (long Key, GalImage Image, GalTextureSampler Sampler) = UnboundTextures[Index]; + (long key, GalImage image, GalTextureSampler sampler) = unboundTextures[index]; - if (Key == 0) + if (key == 0) { continue; } - Gpu.Renderer.Texture.Bind(Key, Index, Image); - Gpu.Renderer.Texture.SetSampler(Image, Sampler); + _gpu.Renderer.Texture.Bind(key, index, image); + _gpu.Renderer.Texture.SetSampler(image, sampler); } } - private (long, GalImage, GalTextureSampler) UploadTexture(NvGpuVmm Vmm, int TextureHandle) + private (long, GalImage, GalTextureSampler) UploadTexture(NvGpuVmm vmm, int textureHandle) { - if (TextureHandle == 0) + if (textureHandle == 0) { //FIXME: Some games like puyo puyo will use handles with the value 0. //This is a bug, most likely caused by sync issues. return (0, default(GalImage), default(GalTextureSampler)); } - bool LinkedTsc = ReadRegisterBool(NvGpuEngine3dReg.LinkedTsc); + bool linkedTsc = ReadRegisterBool(NvGpuEngine3dReg.LinkedTsc); - int TicIndex = (TextureHandle >> 0) & 0xfffff; + int ticIndex = (textureHandle >> 0) & 0xfffff; - int TscIndex = LinkedTsc ? TicIndex : (TextureHandle >> 20) & 0xfff; + int tscIndex = linkedTsc ? ticIndex : (textureHandle >> 20) & 0xfff; - long TicPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset); - long TscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset); + long ticPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexHeaderPoolOffset); + long tscPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.TexSamplerPoolOffset); - TicPosition += TicIndex * 0x20; - TscPosition += TscIndex * 0x20; + ticPosition += ticIndex * 0x20; + tscPosition += tscIndex * 0x20; - GalImage Image = TextureFactory.MakeTexture(Vmm, TicPosition); + GalImage image = TextureFactory.MakeTexture(vmm, ticPosition); - GalTextureSampler Sampler = TextureFactory.MakeSampler(Gpu, Vmm, TscPosition); + GalTextureSampler sampler = TextureFactory.MakeSampler(_gpu, vmm, tscPosition); - long Key = Vmm.ReadInt64(TicPosition + 4) & 0xffffffffffff; + long key = vmm.ReadInt64(ticPosition + 4) & 0xffffffffffff; - if (Image.Layout == GalMemoryLayout.BlockLinear) + if (image.Layout == GalMemoryLayout.BlockLinear) { - Key &= ~0x1ffL; + key &= ~0x1ffL; } - else if (Image.Layout == GalMemoryLayout.Pitch) + else if (image.Layout == GalMemoryLayout.Pitch) { - Key &= ~0x1fL; + key &= ~0x1fL; } - Key = Vmm.GetPhysicalAddress(Key); + key = vmm.GetPhysicalAddress(key); - if (Key == -1) + if (key == -1) { //FIXME: Shouldn't ignore invalid addresses. return (0, default(GalImage), default(GalTextureSampler)); } - Gpu.ResourceManager.SendTexture(Vmm, Key, Image); + _gpu.ResourceManager.SendTexture(vmm, key, image); - return (Key, Image, Sampler); + return (key, image, sampler); } - private void UploadConstBuffers(NvGpuVmm Vmm, GalPipelineState State, long[] Keys) + private void UploadConstBuffers(NvGpuVmm vmm, GalPipelineState state, long[] keys) { - for (int Stage = 0; Stage < Keys.Length; Stage++) + for (int stage = 0; stage < keys.Length; stage++) { - foreach (ShaderDeclInfo DeclInfo in Gpu.Renderer.Shader.GetConstBufferUsage(Keys[Stage])) + foreach (ShaderDeclInfo declInfo in _gpu.Renderer.Shader.GetConstBufferUsage(keys[stage])) { - ConstBuffer Cb = ConstBuffers[Stage][DeclInfo.Cbuf]; + ConstBuffer cb = _constBuffers[stage][declInfo.Cbuf]; - if (!Cb.Enabled) + if (!cb.Enabled) { continue; } - long Key = Vmm.GetPhysicalAddress(Cb.Position); + long key = vmm.GetPhysicalAddress(cb.Position); - if (Gpu.ResourceManager.MemoryRegionModified(Vmm, Key, Cb.Size, NvGpuBufferType.ConstBuffer)) + if (_gpu.ResourceManager.MemoryRegionModified(vmm, key, cb.Size, NvGpuBufferType.ConstBuffer)) { - if (Vmm.TryGetHostAddress(Cb.Position, Cb.Size, out IntPtr CbPtr)) + if (vmm.TryGetHostAddress(cb.Position, cb.Size, out IntPtr cbPtr)) { - Gpu.Renderer.Buffer.SetData(Key, Cb.Size, CbPtr); + _gpu.Renderer.Buffer.SetData(key, cb.Size, cbPtr); } else { - Gpu.Renderer.Buffer.SetData(Key, Vmm.ReadBytes(Cb.Position, Cb.Size)); + _gpu.Renderer.Buffer.SetData(key, vmm.ReadBytes(cb.Position, cb.Size)); } } - State.ConstBufferKeys[Stage][DeclInfo.Cbuf] = Key; + state.ConstBufferKeys[stage][declInfo.Cbuf] = key; } } } - private void UploadVertexArrays(NvGpuVmm Vmm, GalPipelineState State) + private void UploadVertexArrays(NvGpuVmm vmm, GalPipelineState state) { - long IbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); + long ibPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); - long IboKey = Vmm.GetPhysicalAddress(IbPosition); + long iboKey = vmm.GetPhysicalAddress(ibPosition); - int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat); - int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); - int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl); + int indexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat); + int indexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); + int primCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl); - GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff); + GalPrimitiveType primType = (GalPrimitiveType)(primCtrl & 0xffff); - GalIndexFormat IndexFormat = (GalIndexFormat)IndexEntryFmt; + GalIndexFormat indexFormat = (GalIndexFormat)indexEntryFmt; - int IndexEntrySize = 1 << IndexEntryFmt; + int indexEntrySize = 1 << indexEntryFmt; - if (IndexEntrySize > 4) + if (indexEntrySize > 4) { - throw new InvalidOperationException("Invalid index entry size \"" + IndexEntrySize + "\"!"); + throw new InvalidOperationException("Invalid index entry size \"" + indexEntrySize + "\"!"); } - if (IndexCount != 0) + if (indexCount != 0) { - int IbSize = IndexCount * IndexEntrySize; + int ibSize = indexCount * indexEntrySize; - bool IboCached = Gpu.Renderer.Rasterizer.IsIboCached(IboKey, (uint)IbSize); + bool iboCached = _gpu.Renderer.Rasterizer.IsIboCached(iboKey, (uint)ibSize); - bool UsesLegacyQuads = - PrimType == GalPrimitiveType.Quads || - PrimType == GalPrimitiveType.QuadStrip; + bool usesLegacyQuads = + primType == GalPrimitiveType.Quads || + primType == GalPrimitiveType.QuadStrip; - if (!IboCached || Gpu.ResourceManager.MemoryRegionModified(Vmm, IboKey, (uint)IbSize, NvGpuBufferType.Index)) + if (!iboCached || _gpu.ResourceManager.MemoryRegionModified(vmm, iboKey, (uint)ibSize, NvGpuBufferType.Index)) { - if (!UsesLegacyQuads) + if (!usesLegacyQuads) { - if (Vmm.TryGetHostAddress(IbPosition, IbSize, out IntPtr IbPtr)) + if (vmm.TryGetHostAddress(ibPosition, ibSize, out IntPtr ibPtr)) { - Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, IbPtr); + _gpu.Renderer.Rasterizer.CreateIbo(iboKey, ibSize, ibPtr); } else { - Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, Vmm.ReadBytes(IbPosition, IbSize)); + _gpu.Renderer.Rasterizer.CreateIbo(iboKey, ibSize, vmm.ReadBytes(ibPosition, ibSize)); } } else { - byte[] Buffer = Vmm.ReadBytes(IbPosition, IbSize); + byte[] buffer = vmm.ReadBytes(ibPosition, ibSize); - if (PrimType == GalPrimitiveType.Quads) + if (primType == GalPrimitiveType.Quads) { - Buffer = QuadHelper.ConvertQuadsToTris(Buffer, IndexEntrySize, IndexCount); + buffer = QuadHelper.ConvertQuadsToTris(buffer, indexEntrySize, indexCount); } else /* if (PrimType == GalPrimitiveType.QuadStrip) */ { - Buffer = QuadHelper.ConvertQuadStripToTris(Buffer, IndexEntrySize, IndexCount); + buffer = QuadHelper.ConvertQuadStripToTris(buffer, indexEntrySize, indexCount); } - Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, Buffer); + _gpu.Renderer.Rasterizer.CreateIbo(iboKey, ibSize, buffer); } } - if (!UsesLegacyQuads) + if (!usesLegacyQuads) { - Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat); + _gpu.Renderer.Rasterizer.SetIndexArray(ibSize, indexFormat); } else { - if (PrimType == GalPrimitiveType.Quads) + if (primType == GalPrimitiveType.Quads) { - Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertSizeQuadsToTris(IbSize), IndexFormat); + _gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertSizeQuadsToTris(ibSize), indexFormat); } else /* if (PrimType == GalPrimitiveType.QuadStrip) */ { - Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertSizeQuadStripToTris(IbSize), IndexFormat); + _gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertSizeQuadStripToTris(ibSize), indexFormat); } } } - List[] Attribs = new List[32]; + List[] attribs = new List[32]; - for (int Attr = 0; Attr < 16; Attr++) + for (int attr = 0; attr < 16; attr++) { - int Packed = ReadRegister(NvGpuEngine3dReg.VertexAttribNFormat + Attr); + int packed = ReadRegister(NvGpuEngine3dReg.VertexAttribNFormat + attr); - int ArrayIndex = Packed & 0x1f; + int arrayIndex = packed & 0x1f; - if (Attribs[ArrayIndex] == null) + if (attribs[arrayIndex] == null) { - Attribs[ArrayIndex] = new List(); + attribs[arrayIndex] = new List(); } - long VbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + ArrayIndex * 4); + long vbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + arrayIndex * 4); - if (VbPosition == 0) + if (vbPosition == 0) { continue; } - bool IsConst = ((Packed >> 6) & 1) != 0; + bool isConst = ((packed >> 6) & 1) != 0; - int Offset = (Packed >> 7) & 0x3fff; + int offset = (packed >> 7) & 0x3fff; - GalVertexAttribSize Size = (GalVertexAttribSize)((Packed >> 21) & 0x3f); - GalVertexAttribType Type = (GalVertexAttribType)((Packed >> 27) & 0x7); + GalVertexAttribSize size = (GalVertexAttribSize)((packed >> 21) & 0x3f); + GalVertexAttribType type = (GalVertexAttribType)((packed >> 27) & 0x7); - bool IsRgba = ((Packed >> 31) & 1) != 0; + bool isRgba = ((packed >> 31) & 1) != 0; // Check vertex array is enabled to avoid out of bounds exception when reading bytes - bool Enable = (ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + ArrayIndex * 4) & 0x1000) != 0; + bool enable = (ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + arrayIndex * 4) & 0x1000) != 0; //Note: 16 is the maximum size of an attribute, //having a component size of 32-bits with 4 elements (a vec4). - if (Enable) + if (enable) { - byte[] Data = Vmm.ReadBytes(VbPosition + Offset, 16); + byte[] data = vmm.ReadBytes(vbPosition + offset, 16); - Attribs[ArrayIndex].Add(new GalVertexAttrib(Attr, IsConst, Offset, Data, Size, Type, IsRgba)); + attribs[arrayIndex].Add(new GalVertexAttrib(attr, isConst, offset, data, size, type, isRgba)); } } - State.VertexBindings = new GalVertexBinding[32]; + state.VertexBindings = new GalVertexBinding[32]; - for (int Index = 0; Index < 32; Index++) + for (int index = 0; index < 32; index++) { - if (Attribs[Index] == null) + if (attribs[index] == null) { continue; } - int Control = ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + Index * 4); + int control = ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + index * 4); - bool Enable = (Control & 0x1000) != 0; + bool enable = (control & 0x1000) != 0; - if (!Enable) + if (!enable) { continue; } - long VbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + Index * 4); - long VbEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + Index * 2); + long vbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + index * 4); + long vbEndPos = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNEndAddr + index * 2); - int VertexDivisor = ReadRegister(NvGpuEngine3dReg.VertexArrayNDivisor + Index * 4); + int vertexDivisor = ReadRegister(NvGpuEngine3dReg.VertexArrayNDivisor + index * 4); - bool Instanced = ReadRegisterBool(NvGpuEngine3dReg.VertexArrayNInstance + Index); + bool instanced = ReadRegisterBool(NvGpuEngine3dReg.VertexArrayNInstance + index); - int Stride = Control & 0xfff; + int stride = control & 0xfff; - if (Instanced && VertexDivisor != 0) + if (instanced && vertexDivisor != 0) { - VbPosition += Stride * (CurrentInstance / VertexDivisor); + vbPosition += stride * (_currentInstance / vertexDivisor); } - if (VbPosition > VbEndPos) + if (vbPosition > vbEndPos) { //Instance is invalid, ignore the draw call continue; } - long VboKey = Vmm.GetPhysicalAddress(VbPosition); + long vboKey = vmm.GetPhysicalAddress(vbPosition); - long VbSize = (VbEndPos - VbPosition) + 1; - int ModifiedVbSize = (int)VbSize; + long vbSize = (vbEndPos - vbPosition) + 1; + int modifiedVbSize = (int)vbSize; // If quads convert size to triangle length - if (Stride == 0) + if (stride == 0) { - if (PrimType == GalPrimitiveType.Quads) + if (primType == GalPrimitiveType.Quads) { - ModifiedVbSize = QuadHelper.ConvertSizeQuadsToTris(ModifiedVbSize); + modifiedVbSize = QuadHelper.ConvertSizeQuadsToTris(modifiedVbSize); } - else if (PrimType == GalPrimitiveType.QuadStrip) + else if (primType == GalPrimitiveType.QuadStrip) { - ModifiedVbSize = QuadHelper.ConvertSizeQuadStripToTris(ModifiedVbSize); + modifiedVbSize = QuadHelper.ConvertSizeQuadStripToTris(modifiedVbSize); } } - bool VboCached = Gpu.Renderer.Rasterizer.IsVboCached(VboKey, ModifiedVbSize); + bool vboCached = _gpu.Renderer.Rasterizer.IsVboCached(vboKey, modifiedVbSize); - if (!VboCached || Gpu.ResourceManager.MemoryRegionModified(Vmm, VboKey, VbSize, NvGpuBufferType.Vertex)) + if (!vboCached || _gpu.ResourceManager.MemoryRegionModified(vmm, vboKey, vbSize, NvGpuBufferType.Vertex)) { - if ((PrimType == GalPrimitiveType.Quads | PrimType == GalPrimitiveType.QuadStrip) && Stride != 0) + if ((primType == GalPrimitiveType.Quads | primType == GalPrimitiveType.QuadStrip) && stride != 0) { // Convert quad buffer to triangles - byte[] data = Vmm.ReadBytes(VbPosition, VbSize); + byte[] data = vmm.ReadBytes(vbPosition, vbSize); - if (PrimType == GalPrimitiveType.Quads) + if (primType == GalPrimitiveType.Quads) { - data = QuadHelper.ConvertQuadsToTris(data, Stride, (int)(VbSize / Stride)); + data = QuadHelper.ConvertQuadsToTris(data, stride, (int)(vbSize / stride)); } else { - data = QuadHelper.ConvertQuadStripToTris(data, Stride, (int)(VbSize / Stride)); + data = QuadHelper.ConvertQuadStripToTris(data, stride, (int)(vbSize / stride)); } - Gpu.Renderer.Rasterizer.CreateVbo(VboKey, data); + _gpu.Renderer.Rasterizer.CreateVbo(vboKey, data); } - else if (Vmm.TryGetHostAddress(VbPosition, VbSize, out IntPtr VbPtr)) + else if (vmm.TryGetHostAddress(vbPosition, vbSize, out IntPtr vbPtr)) { - Gpu.Renderer.Rasterizer.CreateVbo(VboKey, (int)VbSize, VbPtr); + _gpu.Renderer.Rasterizer.CreateVbo(vboKey, (int)vbSize, vbPtr); } else { - Gpu.Renderer.Rasterizer.CreateVbo(VboKey, Vmm.ReadBytes(VbPosition, VbSize)); + _gpu.Renderer.Rasterizer.CreateVbo(vboKey, vmm.ReadBytes(vbPosition, vbSize)); } } - State.VertexBindings[Index].Enabled = true; - State.VertexBindings[Index].Stride = Stride; - State.VertexBindings[Index].VboKey = VboKey; - State.VertexBindings[Index].Instanced = Instanced; - State.VertexBindings[Index].Divisor = VertexDivisor; - State.VertexBindings[Index].Attribs = Attribs[Index].ToArray(); + state.VertexBindings[index].Enabled = true; + state.VertexBindings[index].Stride = stride; + state.VertexBindings[index].VboKey = vboKey; + state.VertexBindings[index].Instanced = instanced; + state.VertexBindings[index].Divisor = vertexDivisor; + state.VertexBindings[index].Attribs = attribs[index].ToArray(); } } - private void DispatchRender(NvGpuVmm Vmm, GalPipelineState State) + private void DispatchRender(NvGpuVmm vmm, GalPipelineState state) { - int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); - int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl); + int indexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount); + int primCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl); - GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff); + GalPrimitiveType primType = (GalPrimitiveType)(primCtrl & 0xffff); - bool InstanceNext = ((PrimCtrl >> 26) & 1) != 0; - bool InstanceCont = ((PrimCtrl >> 27) & 1) != 0; + bool instanceNext = ((primCtrl >> 26) & 1) != 0; + bool instanceCont = ((primCtrl >> 27) & 1) != 0; - if (InstanceNext && InstanceCont) + if (instanceNext && instanceCont) { throw new InvalidOperationException("GPU tried to increase and reset instance count at the same time"); } - if (InstanceNext) + if (instanceNext) { - CurrentInstance++; + _currentInstance++; } - else if (!InstanceCont) + else if (!instanceCont) { - CurrentInstance = 0; + _currentInstance = 0; } - State.Instance = CurrentInstance; + state.Instance = _currentInstance; - Gpu.Renderer.Pipeline.Bind(State); + _gpu.Renderer.Pipeline.Bind(state); - Gpu.Renderer.RenderTarget.Bind(); + _gpu.Renderer.RenderTarget.Bind(); - if (IndexCount != 0) + if (indexCount != 0) { - int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat); - int IndexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst); - int VertexBase = ReadRegister(NvGpuEngine3dReg.VertexArrayElemBase); + int indexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat); + int indexFirst = ReadRegister(NvGpuEngine3dReg.IndexBatchFirst); + int vertexBase = ReadRegister(NvGpuEngine3dReg.VertexArrayElemBase); - long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); + long indexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress); - long IboKey = Vmm.GetPhysicalAddress(IndexPosition); + long iboKey = vmm.GetPhysicalAddress(indexPosition); //Quad primitive types were deprecated on OpenGL 3.x, //they are converted to a triangles index buffer on IB creation, //so we should use the triangles type here too. - if (PrimType == GalPrimitiveType.Quads || PrimType == GalPrimitiveType.QuadStrip) + if (primType == GalPrimitiveType.Quads || primType == GalPrimitiveType.QuadStrip) { //Note: We assume that index first points to the first //vertex of a quad, if it points to the middle of a //quad (First % 4 != 0 for Quads) then it will not work properly. - if (PrimType == GalPrimitiveType.Quads) + if (primType == GalPrimitiveType.Quads) { - IndexFirst = QuadHelper.ConvertSizeQuadsToTris(IndexFirst); + indexFirst = QuadHelper.ConvertSizeQuadsToTris(indexFirst); } else // QuadStrip { - IndexFirst = QuadHelper.ConvertSizeQuadStripToTris(IndexFirst); + indexFirst = QuadHelper.ConvertSizeQuadStripToTris(indexFirst); } - PrimType = GalPrimitiveType.Triangles; + primType = GalPrimitiveType.Triangles; } - Gpu.Renderer.Rasterizer.DrawElements(IboKey, IndexFirst, VertexBase, PrimType); + _gpu.Renderer.Rasterizer.DrawElements(iboKey, indexFirst, vertexBase, primType); } else { - int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst); - int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount); + int vertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst); + int vertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount); //Quad primitive types were deprecated on OpenGL 3.x, //they are converted to a triangles index buffer on IB creation, //so we should use the triangles type here too. - if (PrimType == GalPrimitiveType.Quads || PrimType == GalPrimitiveType.QuadStrip) + if (primType == GalPrimitiveType.Quads || primType == GalPrimitiveType.QuadStrip) { //Note: We assume that index first points to the first //vertex of a quad, if it points to the middle of a //quad (First % 4 != 0 for Quads) then it will not work properly. - if (PrimType == GalPrimitiveType.Quads) + if (primType == GalPrimitiveType.Quads) { - VertexFirst = QuadHelper.ConvertSizeQuadsToTris(VertexFirst); + vertexFirst = QuadHelper.ConvertSizeQuadsToTris(vertexFirst); } else // QuadStrip { - VertexFirst = QuadHelper.ConvertSizeQuadStripToTris(VertexFirst); + vertexFirst = QuadHelper.ConvertSizeQuadStripToTris(vertexFirst); } - PrimType = GalPrimitiveType.Triangles; - VertexCount = QuadHelper.ConvertSizeQuadsToTris(VertexCount); + primType = GalPrimitiveType.Triangles; + vertexCount = QuadHelper.ConvertSizeQuadsToTris(vertexCount); } - Gpu.Renderer.Rasterizer.DrawArrays(VertexFirst, VertexCount, PrimType); + _gpu.Renderer.Rasterizer.DrawArrays(vertexFirst, vertexCount, primType); } // Reset pipeline for host OpenGL calls - Gpu.Renderer.Pipeline.Unbind(State); + _gpu.Renderer.Pipeline.Unbind(state); //Is the GPU really clearing those registers after draw? WriteRegister(NvGpuEngine3dReg.IndexBatchFirst, 0); @@ -1062,115 +1061,115 @@ namespace Ryujinx.Graphics.Graphics3d WriteCounterAndTimestamp } - private void QueryControl(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void QueryControl(NvGpuVmm vmm, GpuMethodCall methCall) { - WriteRegister(MethCall); + WriteRegister(methCall); - long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress); + long position = MakeInt64From2xInt32(NvGpuEngine3dReg.QueryAddress); - int Seq = Registers[(int)NvGpuEngine3dReg.QuerySequence]; - int Ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl]; + int seq = Registers[(int)NvGpuEngine3dReg.QuerySequence]; + int ctrl = Registers[(int)NvGpuEngine3dReg.QueryControl]; - QueryMode Mode = (QueryMode)(Ctrl & 3); + QueryMode mode = (QueryMode)(ctrl & 3); - switch (Mode) + switch (mode) { - case QueryMode.WriteSeq: Vmm.WriteInt32(Position, Seq); break; + case QueryMode.WriteSeq: vmm.WriteInt32(position, seq); break; case QueryMode.WriteCounterAndTimestamp: { //TODO: Implement counters. - long Counter = 1; + long counter = 1; - long Timestamp = PerformanceCounter.ElapsedMilliseconds; + long timestamp = PerformanceCounter.ElapsedMilliseconds; - Vmm.WriteInt64(Position + 0, Counter); - Vmm.WriteInt64(Position + 8, Timestamp); + vmm.WriteInt64(position + 0, counter); + vmm.WriteInt64(position + 8, timestamp); break; } } } - private void CbData(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void CbData(NvGpuVmm vmm, GpuMethodCall methCall) { - long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); + long position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); - int Offset = ReadRegister(NvGpuEngine3dReg.ConstBufferOffset); + int offset = ReadRegister(NvGpuEngine3dReg.ConstBufferOffset); - Vmm.WriteInt32(Position + Offset, MethCall.Argument); + vmm.WriteInt32(position + offset, methCall.Argument); - WriteRegister(NvGpuEngine3dReg.ConstBufferOffset, Offset + 4); + WriteRegister(NvGpuEngine3dReg.ConstBufferOffset, offset + 4); - Gpu.ResourceManager.ClearPbCache(NvGpuBufferType.ConstBuffer); + _gpu.ResourceManager.ClearPbCache(NvGpuBufferType.ConstBuffer); } - private void CbBind(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void CbBind(NvGpuVmm vmm, GpuMethodCall methCall) { - int Stage = (MethCall.Method - 0x904) >> 3; + int stage = (methCall.Method - 0x904) >> 3; - int Index = MethCall.Argument; + int index = methCall.Argument; - bool Enabled = (Index & 1) != 0; + bool enabled = (index & 1) != 0; - Index = (Index >> 4) & 0x1f; + index = (index >> 4) & 0x1f; - long Position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); + long position = MakeInt64From2xInt32(NvGpuEngine3dReg.ConstBufferAddress); - long CbKey = Vmm.GetPhysicalAddress(Position); + long cbKey = vmm.GetPhysicalAddress(position); - int Size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize); + int size = ReadRegister(NvGpuEngine3dReg.ConstBufferSize); - if (!Gpu.Renderer.Buffer.IsCached(CbKey, Size)) + if (!_gpu.Renderer.Buffer.IsCached(cbKey, size)) { - Gpu.Renderer.Buffer.Create(CbKey, Size); + _gpu.Renderer.Buffer.Create(cbKey, size); } - ConstBuffer Cb = ConstBuffers[Stage][Index]; + ConstBuffer cb = _constBuffers[stage][index]; - if (Cb.Position != Position || Cb.Enabled != Enabled || Cb.Size != Size) + if (cb.Position != position || cb.Enabled != enabled || cb.Size != size) { - ConstBuffers[Stage][Index].Position = Position; - ConstBuffers[Stage][Index].Enabled = Enabled; - ConstBuffers[Stage][Index].Size = Size; + _constBuffers[stage][index].Position = position; + _constBuffers[stage][index].Enabled = enabled; + _constBuffers[stage][index].Size = size; } } - private float GetFlipSign(NvGpuEngine3dReg Reg) + private float GetFlipSign(NvGpuEngine3dReg reg) { - return MathF.Sign(ReadRegisterFloat(Reg)); + return MathF.Sign(ReadRegisterFloat(reg)); } - private long MakeInt64From2xInt32(NvGpuEngine3dReg Reg) + private long MakeInt64From2xInt32(NvGpuEngine3dReg reg) { return - (long)Registers[(int)Reg + 0] << 32 | - (uint)Registers[(int)Reg + 1]; + (long)Registers[(int)reg + 0] << 32 | + (uint)Registers[(int)reg + 1]; } - private void WriteRegister(GpuMethodCall MethCall) + private void WriteRegister(GpuMethodCall methCall) { - Registers[MethCall.Method] = MethCall.Argument; + Registers[methCall.Method] = methCall.Argument; } - private int ReadRegister(NvGpuEngine3dReg Reg) + private int ReadRegister(NvGpuEngine3dReg reg) { - return Registers[(int)Reg]; + return Registers[(int)reg]; } - private float ReadRegisterFloat(NvGpuEngine3dReg Reg) + private float ReadRegisterFloat(NvGpuEngine3dReg reg) { - return BitConverter.Int32BitsToSingle(ReadRegister(Reg)); + return BitConverter.Int32BitsToSingle(ReadRegister(reg)); } - private bool ReadRegisterBool(NvGpuEngine3dReg Reg) + private bool ReadRegisterBool(NvGpuEngine3dReg reg) { - return (ReadRegister(Reg) & 1) != 0; + return (ReadRegister(reg) & 1) != 0; } - private void WriteRegister(NvGpuEngine3dReg Reg, int Value) + private void WriteRegister(NvGpuEngine3dReg reg, int value) { - Registers[(int)Reg] = Value; + Registers[(int)reg] = value; } } } diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs index 9134646403..c6596a309a 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3dReg.cs @@ -32,13 +32,13 @@ namespace Ryujinx.Graphics.Graphics3d StencilBackMask = 0x3d6, StencilBackFuncMask = 0x3d7, ColorMaskCommon = 0x3e4, - RTSeparateFragData = 0x3eb, + RtSeparateFragData = 0x3eb, ZetaAddress = 0x3f8, ZetaFormat = 0x3fa, ZetaBlockDimensions = 0x3fb, ZetaLayerStride = 0x3fc, VertexAttribNFormat = 0x458, - RTControl = 0x487, + RtControl = 0x487, ZetaHoriz = 0x48a, ZetaVert = 0x48b, ZetaArrayMode = 0x48c, diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs index 2f1df3d377..c0f444c379 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs @@ -1,4 +1,3 @@ -using Ryujinx.Common.Logging; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; using System.Collections.Generic; @@ -9,188 +8,188 @@ namespace Ryujinx.Graphics.Graphics3d { public int[] Registers { get; private set; } - private NvGpu Gpu; + private NvGpu _gpu; - private Dictionary Methods; + private Dictionary _methods; - public NvGpuEngineM2mf(NvGpu Gpu) + public NvGpuEngineM2mf(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; Registers = new int[0x1d6]; - Methods = new Dictionary(); + _methods = new Dictionary(); - void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) + void AddMethod(int meth, int count, int stride, NvGpuMethod method) { - while (Count-- > 0) + while (count-- > 0) { - Methods.Add(Meth, Method); + _methods.Add(meth, method); - Meth += Stride; + meth += stride; } } AddMethod(0xc0, 1, 1, Execute); } - public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - if (Methods.TryGetValue(MethCall.Method, out NvGpuMethod Method)) + if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method)) { - Method(Vmm, MethCall); + method(vmm, methCall); } else { - WriteRegister(MethCall); + WriteRegister(methCall); } } - private void Execute(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void Execute(NvGpuVmm vmm, GpuMethodCall methCall) { //TODO: Some registers and copy modes are still not implemented. - int Control = MethCall.Argument; + int control = methCall.Argument; - bool SrcLinear = ((Control >> 7) & 1) != 0; - bool DstLinear = ((Control >> 8) & 1) != 0; - bool Copy2d = ((Control >> 9) & 1) != 0; + bool srcLinear = ((control >> 7) & 1) != 0; + bool dstLinear = ((control >> 8) & 1) != 0; + bool copy2D = ((control >> 9) & 1) != 0; - long SrcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress); - long DstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress); + long srcAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.SrcAddress); + long dstAddress = MakeInt64From2xInt32(NvGpuEngineM2mfReg.DstAddress); - int SrcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch); - int DstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch); + int srcPitch = ReadRegister(NvGpuEngineM2mfReg.SrcPitch); + int dstPitch = ReadRegister(NvGpuEngineM2mfReg.DstPitch); - int XCount = ReadRegister(NvGpuEngineM2mfReg.XCount); - int YCount = ReadRegister(NvGpuEngineM2mfReg.YCount); + int xCount = ReadRegister(NvGpuEngineM2mfReg.XCount); + int yCount = ReadRegister(NvGpuEngineM2mfReg.YCount); - int Swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle); + int swizzle = ReadRegister(NvGpuEngineM2mfReg.Swizzle); - int DstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim); - int DstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX); - int DstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY); - int DstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ); - int DstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY); - int DstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ); + int dstBlkDim = ReadRegister(NvGpuEngineM2mfReg.DstBlkDim); + int dstSizeX = ReadRegister(NvGpuEngineM2mfReg.DstSizeX); + int dstSizeY = ReadRegister(NvGpuEngineM2mfReg.DstSizeY); + int dstSizeZ = ReadRegister(NvGpuEngineM2mfReg.DstSizeZ); + int dstPosXY = ReadRegister(NvGpuEngineM2mfReg.DstPosXY); + int dstPosZ = ReadRegister(NvGpuEngineM2mfReg.DstPosZ); - int SrcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim); - int SrcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX); - int SrcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY); - int SrcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ); - int SrcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY); - int SrcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ); + int srcBlkDim = ReadRegister(NvGpuEngineM2mfReg.SrcBlkDim); + int srcSizeX = ReadRegister(NvGpuEngineM2mfReg.SrcSizeX); + int srcSizeY = ReadRegister(NvGpuEngineM2mfReg.SrcSizeY); + int srcSizeZ = ReadRegister(NvGpuEngineM2mfReg.SrcSizeZ); + int srcPosXY = ReadRegister(NvGpuEngineM2mfReg.SrcPosXY); + int srcPosZ = ReadRegister(NvGpuEngineM2mfReg.SrcPosZ); - int SrcCpp = ((Swizzle >> 20) & 7) + 1; - int DstCpp = ((Swizzle >> 24) & 7) + 1; + int srcCpp = ((swizzle >> 20) & 7) + 1; + int dstCpp = ((swizzle >> 24) & 7) + 1; - int DstPosX = (DstPosXY >> 0) & 0xffff; - int DstPosY = (DstPosXY >> 16) & 0xffff; + int dstPosX = (dstPosXY >> 0) & 0xffff; + int dstPosY = (dstPosXY >> 16) & 0xffff; - int SrcPosX = (SrcPosXY >> 0) & 0xffff; - int SrcPosY = (SrcPosXY >> 16) & 0xffff; + int srcPosX = (srcPosXY >> 0) & 0xffff; + int srcPosY = (srcPosXY >> 16) & 0xffff; - int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf); - int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); + int srcBlockHeight = 1 << ((srcBlkDim >> 4) & 0xf); + int dstBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf); - long SrcPA = Vmm.GetPhysicalAddress(SrcAddress); - long DstPA = Vmm.GetPhysicalAddress(DstAddress); + long srcPa = vmm.GetPhysicalAddress(srcAddress); + long dstPa = vmm.GetPhysicalAddress(dstAddress); - if (Copy2d) + if (copy2D) { - if (SrcLinear) + if (srcLinear) { - SrcPosX = SrcPosY = SrcPosZ = 0; + srcPosX = srcPosY = srcPosZ = 0; } - if (DstLinear) + if (dstLinear) { - DstPosX = DstPosY = DstPosZ = 0; + dstPosX = dstPosY = dstPosZ = 0; } - if (SrcLinear && DstLinear) + if (srcLinear && dstLinear) { - for (int Y = 0; Y < YCount; Y++) + for (int y = 0; y < yCount; y++) { - int SrcOffset = (SrcPosY + Y) * SrcPitch + SrcPosX * SrcCpp; - int DstOffset = (DstPosY + Y) * DstPitch + DstPosX * DstCpp; + int srcOffset = (srcPosY + y) * srcPitch + srcPosX * srcCpp; + int dstOffset = (dstPosY + y) * dstPitch + dstPosX * dstCpp; - long Src = SrcPA + (uint)SrcOffset; - long Dst = DstPA + (uint)DstOffset; + long src = srcPa + (uint)srcOffset; + long dst = dstPa + (uint)dstOffset; - Vmm.Memory.CopyBytes(Src, Dst, XCount * SrcCpp); + vmm.Memory.CopyBytes(src, dst, xCount * srcCpp); } } else { - ISwizzle SrcSwizzle; + ISwizzle srcSwizzle; - if (SrcLinear) + if (srcLinear) { - SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp, SrcSizeX, SrcSizeY); + srcSwizzle = new LinearSwizzle(srcPitch, srcCpp, srcSizeX, srcSizeY); } else { - SrcSwizzle = new BlockLinearSwizzle( - SrcSizeX, - SrcSizeY, 1, - SrcBlockHeight, 1, - SrcCpp); + srcSwizzle = new BlockLinearSwizzle( + srcSizeX, + srcSizeY, 1, + srcBlockHeight, 1, + srcCpp); } - ISwizzle DstSwizzle; + ISwizzle dstSwizzle; - if (DstLinear) + if (dstLinear) { - DstSwizzle = new LinearSwizzle(DstPitch, DstCpp, SrcSizeX, SrcSizeY); + dstSwizzle = new LinearSwizzle(dstPitch, dstCpp, srcSizeX, srcSizeY); } else { - DstSwizzle = new BlockLinearSwizzle( - DstSizeX, - DstSizeY, 1, - DstBlockHeight, 1, - DstCpp); + dstSwizzle = new BlockLinearSwizzle( + dstSizeX, + dstSizeY, 1, + dstBlockHeight, 1, + dstCpp); } - for (int Y = 0; Y < YCount; Y++) - for (int X = 0; X < XCount; X++) + for (int y = 0; y < yCount; y++) + for (int x = 0; x < xCount; x++) { - int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y, 0); - int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y, 0); + int srcOffset = srcSwizzle.GetSwizzleOffset(srcPosX + x, srcPosY + y, 0); + int dstOffset = dstSwizzle.GetSwizzleOffset(dstPosX + x, dstPosY + y, 0); - long Src = SrcPA + (uint)SrcOffset; - long Dst = DstPA + (uint)DstOffset; + long src = srcPa + (uint)srcOffset; + long dst = dstPa + (uint)dstOffset; - Vmm.Memory.CopyBytes(Src, Dst, SrcCpp); + vmm.Memory.CopyBytes(src, dst, srcCpp); } } } else { - Vmm.Memory.CopyBytes(SrcPA, DstPA, XCount); + vmm.Memory.CopyBytes(srcPa, dstPa, xCount); } } - private long MakeInt64From2xInt32(NvGpuEngineM2mfReg Reg) + private long MakeInt64From2xInt32(NvGpuEngineM2mfReg reg) { return - (long)Registers[(int)Reg + 0] << 32 | - (uint)Registers[(int)Reg + 1]; + (long)Registers[(int)reg + 0] << 32 | + (uint)Registers[(int)reg + 1]; } - private void WriteRegister(GpuMethodCall MethCall) + private void WriteRegister(GpuMethodCall methCall) { - Registers[MethCall.Method] = MethCall.Argument; + Registers[methCall.Method] = methCall.Argument; } - private int ReadRegister(NvGpuEngineM2mfReg Reg) + private int ReadRegister(NvGpuEngineM2mfReg reg) { - return Registers[(int)Reg]; + return Registers[(int)reg]; } - private void WriteRegister(NvGpuEngineM2mfReg Reg, int Value) + private void WriteRegister(NvGpuEngineM2mfReg reg, int value) { - Registers[(int)Reg] = Value; + Registers[(int)reg] = value; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs index 62872ba15c..d24f2303d9 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs @@ -1,4 +1,3 @@ -using Ryujinx.Common.Logging; using Ryujinx.Graphics.Memory; using Ryujinx.Graphics.Texture; using System.Collections.Generic; @@ -9,41 +8,41 @@ namespace Ryujinx.Graphics.Graphics3d { public int[] Registers { get; private set; } - private NvGpu Gpu; + private NvGpu _gpu; - private Dictionary Methods; + private Dictionary _methods; - private int CopyStartX; - private int CopyStartY; + private int _copyStartX; + private int _copyStartY; - private int CopyWidth; - private int CopyHeight; - private int CopyGobBlockHeight; + private int _copyWidth; + private int _copyHeight; + private int _copyGobBlockHeight; - private long CopyAddress; + private long _copyAddress; - private int CopyOffset; - private int CopySize; + private int _copyOffset; + private int _copySize; - private bool CopyLinear; + private bool _copyLinear; - private byte[] Buffer; + private byte[] _buffer; - public NvGpuEngineP2mf(NvGpu Gpu) + public NvGpuEngineP2mf(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; Registers = new int[0x80]; - Methods = new Dictionary(); + _methods = new Dictionary(); - void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) + void AddMethod(int meth, int count, int stride, NvGpuMethod method) { - while (Count-- > 0) + while (count-- > 0) { - Methods.Add(Meth, Method); + _methods.Add(meth, method); - Meth += Stride; + meth += stride; } } @@ -51,115 +50,115 @@ namespace Ryujinx.Graphics.Graphics3d AddMethod(0x6d, 1, 1, PushData); } - public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - if (Methods.TryGetValue(MethCall.Method, out NvGpuMethod Method)) + if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method)) { - Method(Vmm, MethCall); + method(vmm, methCall); } else { - WriteRegister(MethCall); + WriteRegister(methCall); } } - private void Execute(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void Execute(NvGpuVmm vmm, GpuMethodCall methCall) { //TODO: Some registers and copy modes are still not implemented. - int Control = MethCall.Argument; + int control = methCall.Argument; - long DstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress); + long dstAddress = MakeInt64From2xInt32(NvGpuEngineP2mfReg.DstAddress); - int DstPitch = ReadRegister(NvGpuEngineP2mfReg.DstPitch); - int DstBlkDim = ReadRegister(NvGpuEngineP2mfReg.DstBlockDim); + int dstPitch = ReadRegister(NvGpuEngineP2mfReg.DstPitch); + int dstBlkDim = ReadRegister(NvGpuEngineP2mfReg.DstBlockDim); - int DstX = ReadRegister(NvGpuEngineP2mfReg.DstX); - int DstY = ReadRegister(NvGpuEngineP2mfReg.DstY); + int dstX = ReadRegister(NvGpuEngineP2mfReg.DstX); + int dstY = ReadRegister(NvGpuEngineP2mfReg.DstY); - int DstWidth = ReadRegister(NvGpuEngineP2mfReg.DstWidth); - int DstHeight = ReadRegister(NvGpuEngineP2mfReg.DstHeight); + int dstWidth = ReadRegister(NvGpuEngineP2mfReg.DstWidth); + int dstHeight = ReadRegister(NvGpuEngineP2mfReg.DstHeight); - int LineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn); - int LineCount = ReadRegister(NvGpuEngineP2mfReg.LineCount); + int lineLengthIn = ReadRegister(NvGpuEngineP2mfReg.LineLengthIn); + int lineCount = ReadRegister(NvGpuEngineP2mfReg.LineCount); - CopyLinear = (Control & 1) != 0; + _copyLinear = (control & 1) != 0; - CopyGobBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); + _copyGobBlockHeight = 1 << ((dstBlkDim >> 4) & 0xf); - CopyStartX = DstX; - CopyStartY = DstY; + _copyStartX = dstX; + _copyStartY = dstY; - CopyWidth = DstWidth; - CopyHeight = DstHeight; + _copyWidth = dstWidth; + _copyHeight = dstHeight; - CopyAddress = DstAddress; + _copyAddress = dstAddress; - CopyOffset = 0; - CopySize = LineLengthIn * LineCount; + _copyOffset = 0; + _copySize = lineLengthIn * lineCount; - Buffer = new byte[CopySize]; + _buffer = new byte[_copySize]; } - private void PushData(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void PushData(NvGpuVmm vmm, GpuMethodCall methCall) { - if (Buffer == null) + if (_buffer == null) { return; } - for (int Shift = 0; Shift < 32 && CopyOffset < CopySize; Shift += 8, CopyOffset++) + for (int shift = 0; shift < 32 && _copyOffset < _copySize; shift += 8, _copyOffset++) { - Buffer[CopyOffset] = (byte)(MethCall.Argument >> Shift); + _buffer[_copyOffset] = (byte)(methCall.Argument >> shift); } - if (MethCall.IsLastCall) + if (methCall.IsLastCall) { - if (CopyLinear) + if (_copyLinear) { - Vmm.WriteBytes(CopyAddress, Buffer); + vmm.WriteBytes(_copyAddress, _buffer); } else { - BlockLinearSwizzle Swizzle = new BlockLinearSwizzle( - CopyWidth, - CopyHeight, 1, - CopyGobBlockHeight, 1, 1); + BlockLinearSwizzle swizzle = new BlockLinearSwizzle( + _copyWidth, + _copyHeight, 1, + _copyGobBlockHeight, 1, 1); - int SrcOffset = 0; + int srcOffset = 0; - for (int Y = CopyStartY; Y < CopyHeight && SrcOffset < CopySize; Y++) - for (int X = CopyStartX; X < CopyWidth && SrcOffset < CopySize; X++) + for (int y = _copyStartY; y < _copyHeight && srcOffset < _copySize; y++) + for (int x = _copyStartX; x < _copyWidth && srcOffset < _copySize; x++) { - int DstOffset = Swizzle.GetSwizzleOffset(X, Y, 0); + int dstOffset = swizzle.GetSwizzleOffset(x, y, 0); - Vmm.WriteByte(CopyAddress + DstOffset, Buffer[SrcOffset++]); + vmm.WriteByte(_copyAddress + dstOffset, _buffer[srcOffset++]); } } - Buffer = null; + _buffer = null; } } - private long MakeInt64From2xInt32(NvGpuEngineP2mfReg Reg) + private long MakeInt64From2xInt32(NvGpuEngineP2mfReg reg) { return - (long)Registers[(int)Reg + 0] << 32 | - (uint)Registers[(int)Reg + 1]; + (long)Registers[(int)reg + 0] << 32 | + (uint)Registers[(int)reg + 1]; } - private void WriteRegister(GpuMethodCall MethCall) + private void WriteRegister(GpuMethodCall methCall) { - Registers[MethCall.Method] = MethCall.Argument; + Registers[methCall.Method] = methCall.Argument; } - private int ReadRegister(NvGpuEngineP2mfReg Reg) + private int ReadRegister(NvGpuEngineP2mfReg reg) { - return Registers[(int)Reg]; + return Registers[(int)reg]; } - private void WriteRegister(NvGpuEngineP2mfReg Reg, int Value) + private void WriteRegister(NvGpuEngineP2mfReg reg, int value) { - Registers[(int)Reg] = Value; + Registers[(int)reg] = value; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuFifo.cs b/Ryujinx.Graphics/Graphics3d/NvGpuFifo.cs index f834ade78d..25c1a9cd9c 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuFifo.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuFifo.cs @@ -11,166 +11,166 @@ namespace Ryujinx.Graphics.Graphics3d //a guess here and use 256kb as the size. Increase if needed. private const int MmeWords = 256 * 256; - private NvGpu Gpu; + private NvGpu _gpu; - private NvGpuEngine[] SubChannels; + private NvGpuEngine[] _subChannels; private struct CachedMacro { public int Position { get; private set; } - private bool ExecutionPending; - private int Argument; + private bool _executionPending; + private int _argument; - private MacroInterpreter Interpreter; + private MacroInterpreter _interpreter; - public CachedMacro(NvGpuFifo PFifo, INvGpuEngine Engine, int Position) + public CachedMacro(NvGpuFifo pFifo, INvGpuEngine engine, int position) { - this.Position = Position; + Position = position; - ExecutionPending = false; - Argument = 0; + _executionPending = false; + _argument = 0; - Interpreter = new MacroInterpreter(PFifo, Engine); + _interpreter = new MacroInterpreter(pFifo, engine); } - public void StartExecution(int Argument) + public void StartExecution(int argument) { - this.Argument = Argument; + _argument = argument; - ExecutionPending = true; + _executionPending = true; } - public void Execute(NvGpuVmm Vmm, int[] Mme) + public void Execute(NvGpuVmm vmm, int[] mme) { - if (ExecutionPending) + if (_executionPending) { - ExecutionPending = false; + _executionPending = false; - Interpreter?.Execute(Vmm, Mme, Position, Argument); + _interpreter?.Execute(vmm, mme, Position, _argument); } } - public void PushArgument(int Argument) + public void PushArgument(int argument) { - Interpreter?.Fifo.Enqueue(Argument); + _interpreter?.Fifo.Enqueue(argument); } } - private int CurrMacroPosition; - private int CurrMacroBindIndex; + private int _currMacroPosition; + private int _currMacroBindIndex; - private CachedMacro[] Macros; + private CachedMacro[] _macros; - private int[] Mme; + private int[] _mme; - public NvGpuFifo(NvGpu Gpu) + public NvGpuFifo(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; - SubChannels = new NvGpuEngine[8]; + _subChannels = new NvGpuEngine[8]; - Macros = new CachedMacro[MacrosCount]; + _macros = new CachedMacro[MacrosCount]; - Mme = new int[MmeWords]; + _mme = new int[MmeWords]; } - public void CallMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + public void CallMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - if ((NvGpuFifoMeth)MethCall.Method == NvGpuFifoMeth.BindChannel) + if ((NvGpuFifoMeth)methCall.Method == NvGpuFifoMeth.BindChannel) { - NvGpuEngine Engine = (NvGpuEngine)MethCall.Argument; + NvGpuEngine engine = (NvGpuEngine)methCall.Argument; - SubChannels[MethCall.SubChannel] = Engine; + _subChannels[methCall.SubChannel] = engine; } else { - switch (SubChannels[MethCall.SubChannel]) + switch (_subChannels[methCall.SubChannel]) { - case NvGpuEngine._2d: Call2dMethod (Vmm, MethCall); break; - case NvGpuEngine._3d: Call3dMethod (Vmm, MethCall); break; - case NvGpuEngine.P2mf: CallP2mfMethod(Vmm, MethCall); break; - case NvGpuEngine.M2mf: CallM2mfMethod(Vmm, MethCall); break; + case NvGpuEngine._2d: Call2dMethod (vmm, methCall); break; + case NvGpuEngine._3d: Call3dMethod (vmm, methCall); break; + case NvGpuEngine.P2mf: CallP2mfMethod(vmm, methCall); break; + case NvGpuEngine.M2mf: CallM2mfMethod(vmm, methCall); break; } } } - private void Call2dMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void Call2dMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - Gpu.Engine2d.CallMethod(Vmm, MethCall); + _gpu.Engine2d.CallMethod(vmm, methCall); } - private void Call3dMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void Call3dMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - if (MethCall.Method < 0x80) + if (methCall.Method < 0x80) { - switch ((NvGpuFifoMeth)MethCall.Method) + switch ((NvGpuFifoMeth)methCall.Method) { case NvGpuFifoMeth.SetMacroUploadAddress: { - CurrMacroPosition = MethCall.Argument; + _currMacroPosition = methCall.Argument; break; } case NvGpuFifoMeth.SendMacroCodeData: { - Mme[CurrMacroPosition++] = MethCall.Argument; + _mme[_currMacroPosition++] = methCall.Argument; break; } case NvGpuFifoMeth.SetMacroBindingIndex: { - CurrMacroBindIndex = MethCall.Argument; + _currMacroBindIndex = methCall.Argument; break; } case NvGpuFifoMeth.BindMacro: { - int Position = MethCall.Argument; + int position = methCall.Argument; - Macros[CurrMacroBindIndex] = new CachedMacro(this, Gpu.Engine3d, Position); + _macros[_currMacroBindIndex] = new CachedMacro(this, _gpu.Engine3d, position); break; } - default: CallP2mfMethod(Vmm, MethCall); break; + default: CallP2mfMethod(vmm, methCall); break; } } - else if (MethCall.Method < 0xe00) + else if (methCall.Method < 0xe00) { - Gpu.Engine3d.CallMethod(Vmm, MethCall); + _gpu.Engine3d.CallMethod(vmm, methCall); } else { - int MacroIndex = (MethCall.Method >> 1) & MacroIndexMask; + int macroIndex = (methCall.Method >> 1) & MacroIndexMask; - if ((MethCall.Method & 1) != 0) + if ((methCall.Method & 1) != 0) { - Macros[MacroIndex].PushArgument(MethCall.Argument); + _macros[macroIndex].PushArgument(methCall.Argument); } else { - Macros[MacroIndex].StartExecution(MethCall.Argument); + _macros[macroIndex].StartExecution(methCall.Argument); } - if (MethCall.IsLastCall) + if (methCall.IsLastCall) { - Macros[MacroIndex].Execute(Vmm, Mme); + _macros[macroIndex].Execute(vmm, _mme); } } } - private void CallP2mfMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void CallP2mfMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - Gpu.EngineP2mf.CallMethod(Vmm, MethCall); + _gpu.EngineP2mf.CallMethod(vmm, methCall); } - private void CallM2mfMethod(NvGpuVmm Vmm, GpuMethodCall MethCall) + private void CallM2mfMethod(NvGpuVmm vmm, GpuMethodCall methCall) { - Gpu.EngineM2mf.CallMethod(Vmm, MethCall); + _gpu.EngineM2mf.CallMethod(vmm, methCall); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuMethod.cs b/Ryujinx.Graphics/Graphics3d/NvGpuMethod.cs index 8730d1448c..23185c81fc 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuMethod.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuMethod.cs @@ -2,5 +2,5 @@ using Ryujinx.Graphics.Memory; namespace Ryujinx.Graphics.Graphics3d { - delegate void NvGpuMethod(NvGpuVmm Vmm, GpuMethodCall MethCall); + delegate void NvGpuMethod(NvGpuVmm vmm, GpuMethodCall methCall); } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs deleted file mode 100644 index 00158dc103..0000000000 --- a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs +++ /dev/null @@ -1,1385 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; - -namespace Ryujinx.Graphics.Texture -{ - public class ASTCDecoderException : Exception - { - public ASTCDecoderException(string ExMsg) : base(ExMsg) { } - } - - //https://github.com/GammaUNC/FasTC/blob/master/ASTCEncoder/src/Decompressor.cpp - public static class ASTCDecoder - { - struct TexelWeightParams - { - public int Width; - public int Height; - public bool DualPlane; - public int MaxWeight; - public bool Error; - public bool VoidExtentLDR; - public bool VoidExtentHDR; - - public int GetPackedBitSize() - { - // How many indices do we have? - int Indices = Height * Width; - - if (DualPlane) - { - Indices *= 2; - } - - IntegerEncoded IntEncoded = IntegerEncoded.CreateEncoding(MaxWeight); - - return IntEncoded.GetBitLength(Indices); - } - - public int GetNumWeightValues() - { - int Ret = Width * Height; - - if (DualPlane) - { - Ret *= 2; - } - - return Ret; - } - } - - public static byte[] DecodeToRGBA8888( - byte[] InputBuffer, - int BlockX, - int BlockY, - int BlockZ, - int X, - int Y, - int Z) - { - using (MemoryStream InputStream = new MemoryStream(InputBuffer)) - { - BinaryReader BinReader = new BinaryReader(InputStream); - - if (BlockX > 12 || BlockY > 12) - { - throw new ASTCDecoderException("Block size unsupported!"); - } - - if (BlockZ != 1 || Z != 1) - { - // TODO: Support 3D textures? - throw new ASTCDecoderException("3D compressed textures unsupported!"); - } - - using (MemoryStream OutputStream = new MemoryStream()) - { - int BlockIndex = 0; - - for (int j = 0; j < Y; j += BlockY) - { - for (int i = 0; i < X; i += BlockX) - { - int[] DecompressedData = new int[144]; - - DecompressBlock(BinReader.ReadBytes(0x10), DecompressedData, BlockX, BlockY); - - int DecompressedWidth = Math.Min(BlockX, X - i); - int DecompressedHeight = Math.Min(BlockY, Y - j); - int BaseOffsets = (j * X + i) * 4; - - for (int jj = 0; jj < DecompressedHeight; jj++) - { - OutputStream.Seek(BaseOffsets + jj * X * 4, SeekOrigin.Begin); - - byte[] OutputBuffer = new byte[DecompressedData.Length * sizeof(int)]; - Buffer.BlockCopy(DecompressedData, 0, OutputBuffer, 0, OutputBuffer.Length); - - OutputStream.Write(OutputBuffer, jj * BlockX * 4, DecompressedWidth * 4); - } - - BlockIndex++; - } - } - - return OutputStream.ToArray(); - } - } - } - - public static bool DecompressBlock( - byte[] InputBuffer, - int[] OutputBuffer, - int BlockWidth, - int BlockHeight) - { - BitArrayStream BitStream = new BitArrayStream(new BitArray(InputBuffer)); - TexelWeightParams TexelParams = DecodeBlockInfo(BitStream); - - if (TexelParams.Error) - { - throw new ASTCDecoderException("Invalid block mode"); - } - - if (TexelParams.VoidExtentLDR) - { - FillVoidExtentLDR(BitStream, OutputBuffer, BlockWidth, BlockHeight); - - return true; - } - - if (TexelParams.VoidExtentHDR) - { - throw new ASTCDecoderException("HDR void extent blocks are unsupported!"); - } - - if (TexelParams.Width > BlockWidth) - { - throw new ASTCDecoderException("Texel weight grid width should be smaller than block width"); - } - - if (TexelParams.Height > BlockHeight) - { - throw new ASTCDecoderException("Texel weight grid height should be smaller than block height"); - } - - // Read num partitions - int NumberPartitions = BitStream.ReadBits(2) + 1; - Debug.Assert(NumberPartitions <= 4); - - if (NumberPartitions == 4 && TexelParams.DualPlane) - { - throw new ASTCDecoderException("Dual plane mode is incompatible with four partition blocks"); - } - - // Based on the number of partitions, read the color endpoint mode for - // each partition. - - // Determine partitions, partition index, and color endpoint modes - int PlaneIndices = -1; - int PartitionIndex; - uint[] ColorEndpointMode = { 0, 0, 0, 0 }; - - BitArrayStream ColorEndpointStream = new BitArrayStream(new BitArray(16 * 8)); - - // Read extra config data... - uint BaseColorEndpointMode = 0; - - if (NumberPartitions == 1) - { - ColorEndpointMode[0] = (uint)BitStream.ReadBits(4); - PartitionIndex = 0; - } - else - { - PartitionIndex = BitStream.ReadBits(10); - BaseColorEndpointMode = (uint)BitStream.ReadBits(6); - } - - uint BaseMode = (BaseColorEndpointMode & 3); - - // Remaining bits are color endpoint data... - int NumberWeightBits = TexelParams.GetPackedBitSize(); - int RemainingBits = 128 - NumberWeightBits - BitStream.Position; - - // Consider extra bits prior to texel data... - uint ExtraColorEndpointModeBits = 0; - - if (BaseMode != 0) - { - switch (NumberPartitions) - { - case 2: ExtraColorEndpointModeBits += 2; break; - case 3: ExtraColorEndpointModeBits += 5; break; - case 4: ExtraColorEndpointModeBits += 8; break; - default: Debug.Assert(false); break; - } - } - - RemainingBits -= (int)ExtraColorEndpointModeBits; - - // Do we have a dual plane situation? - int PlaneSelectorBits = 0; - - if (TexelParams.DualPlane) - { - PlaneSelectorBits = 2; - } - - RemainingBits -= PlaneSelectorBits; - - // Read color data... - int ColorDataBits = RemainingBits; - - while (RemainingBits > 0) - { - int NumberBits = Math.Min(RemainingBits, 8); - int Bits = BitStream.ReadBits(NumberBits); - ColorEndpointStream.WriteBits(Bits, NumberBits); - RemainingBits -= 8; - } - - // Read the plane selection bits - PlaneIndices = BitStream.ReadBits(PlaneSelectorBits); - - // Read the rest of the CEM - if (BaseMode != 0) - { - uint ExtraColorEndpointMode = (uint)BitStream.ReadBits((int)ExtraColorEndpointModeBits); - uint TempColorEndpointMode = (ExtraColorEndpointMode << 6) | BaseColorEndpointMode; - TempColorEndpointMode >>= 2; - - bool[] C = new bool[4]; - - for (int i = 0; i < NumberPartitions; i++) - { - C[i] = (TempColorEndpointMode & 1) != 0; - TempColorEndpointMode >>= 1; - } - - byte[] M = new byte[4]; - - for (int i = 0; i < NumberPartitions; i++) - { - M[i] = (byte)(TempColorEndpointMode & 3); - TempColorEndpointMode >>= 2; - Debug.Assert(M[i] <= 3); - } - - for (int i = 0; i < NumberPartitions; i++) - { - ColorEndpointMode[i] = BaseMode; - if (!(C[i])) ColorEndpointMode[i] -= 1; - ColorEndpointMode[i] <<= 2; - ColorEndpointMode[i] |= M[i]; - } - } - else if (NumberPartitions > 1) - { - uint TempColorEndpointMode = BaseColorEndpointMode >> 2; - - for (uint i = 0; i < NumberPartitions; i++) - { - ColorEndpointMode[i] = TempColorEndpointMode; - } - } - - // Make sure everything up till here is sane. - for (int i = 0; i < NumberPartitions; i++) - { - Debug.Assert(ColorEndpointMode[i] < 16); - } - Debug.Assert(BitStream.Position + TexelParams.GetPackedBitSize() == 128); - - // Decode both color data and texel weight data - int[] ColorValues = new int[32]; // Four values * two endpoints * four maximum partitions - DecodeColorValues(ColorValues, ColorEndpointStream.ToByteArray(), ColorEndpointMode, NumberPartitions, ColorDataBits); - - ASTCPixel[][] EndPoints = new ASTCPixel[4][]; - EndPoints[0] = new ASTCPixel[2]; - EndPoints[1] = new ASTCPixel[2]; - EndPoints[2] = new ASTCPixel[2]; - EndPoints[3] = new ASTCPixel[2]; - - int ColorValuesPosition = 0; - - for (int i = 0; i < NumberPartitions; i++) - { - ComputeEndpoints(EndPoints[i], ColorValues, ColorEndpointMode[i], ref ColorValuesPosition); - } - - // Read the texel weight data. - byte[] TexelWeightData = (byte[])InputBuffer.Clone(); - - // Reverse everything - for (int i = 0; i < 8; i++) - { - byte a = ReverseByte(TexelWeightData[i]); - byte b = ReverseByte(TexelWeightData[15 - i]); - - TexelWeightData[i] = b; - TexelWeightData[15 - i] = a; - } - - // Make sure that higher non-texel bits are set to zero - int ClearByteStart = (TexelParams.GetPackedBitSize() >> 3) + 1; - TexelWeightData[ClearByteStart - 1] &= (byte)((1 << (TexelParams.GetPackedBitSize() % 8)) - 1); - - int cLen = 16 - ClearByteStart; - for (int i = ClearByteStart; i < ClearByteStart + cLen; i++) TexelWeightData[i] = 0; - - List TexelWeightValues = new List(); - BitArrayStream WeightBitStream = new BitArrayStream(new BitArray(TexelWeightData)); - - IntegerEncoded.DecodeIntegerSequence(TexelWeightValues, WeightBitStream, TexelParams.MaxWeight, TexelParams.GetNumWeightValues()); - - // Blocks can be at most 12x12, so we can have as many as 144 weights - int[][] Weights = new int[2][]; - Weights[0] = new int[144]; - Weights[1] = new int[144]; - - UnquantizeTexelWeights(Weights, TexelWeightValues, TexelParams, BlockWidth, BlockHeight); - - // Now that we have endpoints and weights, we can interpolate and generate - // the proper decoding... - for (int j = 0; j < BlockHeight; j++) - { - for (int i = 0; i < BlockWidth; i++) - { - int Partition = Select2DPartition(PartitionIndex, i, j, NumberPartitions, ((BlockHeight * BlockWidth) < 32)); - Debug.Assert(Partition < NumberPartitions); - - ASTCPixel Pixel = new ASTCPixel(0, 0, 0, 0); - for (int Component = 0; Component < 4; Component++) - { - int Component0 = EndPoints[Partition][0].GetComponent(Component); - Component0 = BitArrayStream.Replicate(Component0, 8, 16); - int Component1 = EndPoints[Partition][1].GetComponent(Component); - Component1 = BitArrayStream.Replicate(Component1, 8, 16); - - int Plane = 0; - - if (TexelParams.DualPlane && (((PlaneIndices + 1) & 3) == Component)) - { - Plane = 1; - } - - int Weight = Weights[Plane][j * BlockWidth + i]; - int FinalComponent = (Component0 * (64 - Weight) + Component1 * Weight + 32) / 64; - - if (FinalComponent == 65535) - { - Pixel.SetComponent(Component, 255); - } - else - { - double FinalComponentFloat = FinalComponent; - Pixel.SetComponent(Component, (int)(255.0 * (FinalComponentFloat / 65536.0) + 0.5)); - } - } - - OutputBuffer[j * BlockWidth + i] = Pixel.Pack(); - } - } - - return true; - } - - private static int Select2DPartition(int Seed, int X, int Y, int PartitionCount, bool IsSmallBlock) - { - return SelectPartition(Seed, X, Y, 0, PartitionCount, IsSmallBlock); - } - - private static int SelectPartition(int Seed, int X, int Y, int Z, int PartitionCount, bool IsSmallBlock) - { - if (PartitionCount == 1) - { - return 0; - } - - if (IsSmallBlock) - { - X <<= 1; - Y <<= 1; - Z <<= 1; - } - - Seed += (PartitionCount - 1) * 1024; - - int RightNum = Hash52((uint)Seed); - byte Seed01 = (byte)(RightNum & 0xF); - byte Seed02 = (byte)((RightNum >> 4) & 0xF); - byte Seed03 = (byte)((RightNum >> 8) & 0xF); - byte Seed04 = (byte)((RightNum >> 12) & 0xF); - byte Seed05 = (byte)((RightNum >> 16) & 0xF); - byte Seed06 = (byte)((RightNum >> 20) & 0xF); - byte Seed07 = (byte)((RightNum >> 24) & 0xF); - byte Seed08 = (byte)((RightNum >> 28) & 0xF); - byte Seed09 = (byte)((RightNum >> 18) & 0xF); - byte Seed10 = (byte)((RightNum >> 22) & 0xF); - byte Seed11 = (byte)((RightNum >> 26) & 0xF); - byte Seed12 = (byte)(((RightNum >> 30) | (RightNum << 2)) & 0xF); - - Seed01 *= Seed01; Seed02 *= Seed02; - Seed03 *= Seed03; Seed04 *= Seed04; - Seed05 *= Seed05; Seed06 *= Seed06; - Seed07 *= Seed07; Seed08 *= Seed08; - Seed09 *= Seed09; Seed10 *= Seed10; - Seed11 *= Seed11; Seed12 *= Seed12; - - int SeedHash1, SeedHash2, SeedHash3; - - if ((Seed & 1) != 0) - { - SeedHash1 = (Seed & 2) != 0 ? 4 : 5; - SeedHash2 = (PartitionCount == 3) ? 6 : 5; - } - else - { - SeedHash1 = (PartitionCount == 3) ? 6 : 5; - SeedHash2 = (Seed & 2) != 0 ? 4 : 5; - } - - SeedHash3 = (Seed & 0x10) != 0 ? SeedHash1 : SeedHash2; - - Seed01 >>= SeedHash1; Seed02 >>= SeedHash2; Seed03 >>= SeedHash1; Seed04 >>= SeedHash2; - Seed05 >>= SeedHash1; Seed06 >>= SeedHash2; Seed07 >>= SeedHash1; Seed08 >>= SeedHash2; - Seed09 >>= SeedHash3; Seed10 >>= SeedHash3; Seed11 >>= SeedHash3; Seed12 >>= SeedHash3; - - int a = Seed01 * X + Seed02 * Y + Seed11 * Z + (RightNum >> 14); - int b = Seed03 * X + Seed04 * Y + Seed12 * Z + (RightNum >> 10); - int c = Seed05 * X + Seed06 * Y + Seed09 * Z + (RightNum >> 6); - int d = Seed07 * X + Seed08 * Y + Seed10 * Z + (RightNum >> 2); - - a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F; - - if (PartitionCount < 4) d = 0; - if (PartitionCount < 3) c = 0; - - if (a >= b && a >= c && a >= d) return 0; - else if (b >= c && b >= d) return 1; - else if (c >= d) return 2; - return 3; - } - - static int Hash52(uint Val) - { - Val ^= Val >> 15; Val -= Val << 17; Val += Val << 7; Val += Val << 4; - Val ^= Val >> 5; Val += Val << 16; Val ^= Val >> 7; Val ^= Val >> 3; - Val ^= Val << 6; Val ^= Val >> 17; - - return (int)Val; - } - - static void UnquantizeTexelWeights( - int[][] OutputBuffer, - List Weights, - TexelWeightParams TexelParams, - int BlockWidth, - int BlockHeight) - { - int WeightIndices = 0; - int[][] Unquantized = new int[2][]; - Unquantized[0] = new int[144]; - Unquantized[1] = new int[144]; - - for (int i = 0; i < Weights.Count; i++) - { - Unquantized[0][WeightIndices] = UnquantizeTexelWeight(Weights[i]); - - if (TexelParams.DualPlane) - { - i++; - Unquantized[1][WeightIndices] = UnquantizeTexelWeight(Weights[i]); - - if (i == Weights.Count) - { - break; - } - } - - if (++WeightIndices >= (TexelParams.Width * TexelParams.Height)) break; - } - - // Do infill if necessary (Section C.2.18) ... - int Ds = (1024 + (BlockWidth / 2)) / (BlockWidth - 1); - int Dt = (1024 + (BlockHeight / 2)) / (BlockHeight - 1); - - int PlaneScale = TexelParams.DualPlane ? 2 : 1; - - for (int Plane = 0; Plane < PlaneScale; Plane++) - { - for (int t = 0; t < BlockHeight; t++) - { - for (int s = 0; s < BlockWidth; s++) - { - int cs = Ds * s; - int ct = Dt * t; - - int gs = (cs * (TexelParams.Width - 1) + 32) >> 6; - int gt = (ct * (TexelParams.Height - 1) + 32) >> 6; - - int js = gs >> 4; - int fs = gs & 0xF; - - int jt = gt >> 4; - int ft = gt & 0x0F; - - int w11 = (fs * ft + 8) >> 4; - int w10 = ft - w11; - int w01 = fs - w11; - int w00 = 16 - fs - ft + w11; - - int v0 = js + jt * TexelParams.Width; - - int p00 = 0; - int p01 = 0; - int p10 = 0; - int p11 = 0; - - if (v0 < (TexelParams.Width * TexelParams.Height)) - { - p00 = Unquantized[Plane][v0]; - } - - if (v0 + 1 < (TexelParams.Width * TexelParams.Height)) - { - p01 = Unquantized[Plane][v0 + 1]; - } - - if (v0 + TexelParams.Width < (TexelParams.Width * TexelParams.Height)) - { - p10 = Unquantized[Plane][v0 + TexelParams.Width]; - } - - if (v0 + TexelParams.Width + 1 < (TexelParams.Width * TexelParams.Height)) - { - p11 = Unquantized[Plane][v0 + TexelParams.Width + 1]; - } - - OutputBuffer[Plane][t * BlockWidth + s] = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4; - } - } - } - } - - static int UnquantizeTexelWeight(IntegerEncoded IntEncoded) - { - int BitValue = IntEncoded.BitValue; - int BitLength = IntEncoded.NumberBits; - - int A = BitArrayStream.Replicate(BitValue & 1, 1, 7); - int B = 0, C = 0, D = 0; - - int Result = 0; - - switch (IntEncoded.GetEncoding()) - { - case IntegerEncoded.EIntegerEncoding.JustBits: - Result = BitArrayStream.Replicate(BitValue, BitLength, 6); - break; - - case IntegerEncoded.EIntegerEncoding.Trit: - { - D = IntEncoded.TritValue; - Debug.Assert(D < 3); - - switch (BitLength) - { - case 0: - { - int[] Results = { 0, 32, 63 }; - Result = Results[D]; - - break; - } - - case 1: - { - C = 50; - break; - } - - case 2: - { - C = 23; - int b = (BitValue >> 1) & 1; - B = (b << 6) | (b << 2) | b; - - break; - } - - case 3: - { - C = 11; - int cb = (BitValue >> 1) & 3; - B = (cb << 5) | cb; - - break; - } - - default: - throw new ASTCDecoderException("Invalid trit encoding for texel weight"); - } - - break; - } - - case IntegerEncoded.EIntegerEncoding.Quint: - { - D = IntEncoded.QuintValue; - Debug.Assert(D < 5); - - switch (BitLength) - { - case 0: - { - int[] Results = { 0, 16, 32, 47, 63 }; - Result = Results[D]; - - break; - } - - case 1: - { - C = 28; - - break; - } - - case 2: - { - C = 13; - int b = (BitValue >> 1) & 1; - B = (b << 6) | (b << 1); - - break; - } - - default: - throw new ASTCDecoderException("Invalid quint encoding for texel weight"); - } - - break; - } - } - - if (IntEncoded.GetEncoding() != IntegerEncoded.EIntegerEncoding.JustBits && BitLength > 0) - { - // Decode the value... - Result = D * C + B; - Result ^= A; - Result = (A & 0x20) | (Result >> 2); - } - - Debug.Assert(Result < 64); - - // Change from [0,63] to [0,64] - if (Result > 32) - { - Result += 1; - } - - return Result; - } - - static byte ReverseByte(byte b) - { - // Taken from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits - return (byte)((((b) * 0x80200802L) & 0x0884422110L) * 0x0101010101L >> 32); - } - - static uint[] ReadUintColorValues(int Number, int[] ColorValues, ref int ColorValuesPosition) - { - uint[] Ret = new uint[Number]; - - for (int i = 0; i < Number; i++) - { - Ret[i] = (uint)ColorValues[ColorValuesPosition++]; - } - - return Ret; - } - - static int[] ReadIntColorValues(int Number, int[] ColorValues, ref int ColorValuesPosition) - { - int[] Ret = new int[Number]; - - for (int i = 0; i < Number; i++) - { - Ret[i] = ColorValues[ColorValuesPosition++]; - } - - return Ret; - } - - static void ComputeEndpoints( - ASTCPixel[] EndPoints, - int[] ColorValues, - uint ColorEndpointMode, - ref int ColorValuesPosition) - { - switch (ColorEndpointMode) - { - case 0: - { - uint[] Val = ReadUintColorValues(2, ColorValues, ref ColorValuesPosition); - - EndPoints[0] = new ASTCPixel(0xFF, (short)Val[0], (short)Val[0], (short)Val[0]); - EndPoints[1] = new ASTCPixel(0xFF, (short)Val[1], (short)Val[1], (short)Val[1]); - - break; - } - - - case 1: - { - uint[] Val = ReadUintColorValues(2, ColorValues, ref ColorValuesPosition); - int L0 = (int)((Val[0] >> 2) | (Val[1] & 0xC0)); - int L1 = (int)Math.Max(L0 + (Val[1] & 0x3F), 0xFFU); - - EndPoints[0] = new ASTCPixel(0xFF, (short)L0, (short)L0, (short)L0); - EndPoints[1] = new ASTCPixel(0xFF, (short)L1, (short)L1, (short)L1); - - break; - } - - case 4: - { - uint[] Val = ReadUintColorValues(4, ColorValues, ref ColorValuesPosition); - - EndPoints[0] = new ASTCPixel((short)Val[2], (short)Val[0], (short)Val[0], (short)Val[0]); - EndPoints[1] = new ASTCPixel((short)Val[3], (short)Val[1], (short)Val[1], (short)Val[1]); - - break; - } - - case 5: - { - int[] Val = ReadIntColorValues(4, ColorValues, ref ColorValuesPosition); - - BitArrayStream.BitTransferSigned(ref Val[1], ref Val[0]); - BitArrayStream.BitTransferSigned(ref Val[3], ref Val[2]); - - EndPoints[0] = new ASTCPixel((short)Val[2], (short)Val[0], (short)Val[0], (short)Val[0]); - EndPoints[1] = new ASTCPixel((short)(Val[2] + Val[3]), (short)(Val[0] + Val[1]), (short)(Val[0] + Val[1]), (short)(Val[0] + Val[1])); - - EndPoints[0].ClampByte(); - EndPoints[1].ClampByte(); - - break; - } - - case 6: - { - uint[] Val = ReadUintColorValues(4, ColorValues, ref ColorValuesPosition); - - EndPoints[0] = new ASTCPixel(0xFF, (short)(Val[0] * Val[3] >> 8), (short)(Val[1] * Val[3] >> 8), (short)(Val[2] * Val[3] >> 8)); - EndPoints[1] = new ASTCPixel(0xFF, (short)Val[0], (short)Val[1], (short)Val[2]); - - break; - } - - case 8: - { - uint[] Val = ReadUintColorValues(6, ColorValues, ref ColorValuesPosition); - - if (Val[1] + Val[3] + Val[5] >= Val[0] + Val[2] + Val[4]) - { - EndPoints[0] = new ASTCPixel(0xFF, (short)Val[0], (short)Val[2], (short)Val[4]); - EndPoints[1] = new ASTCPixel(0xFF, (short)Val[1], (short)Val[3], (short)Val[5]); - } - else - { - EndPoints[0] = ASTCPixel.BlueContract(0xFF, (short)Val[1], (short)Val[3], (short)Val[5]); - EndPoints[1] = ASTCPixel.BlueContract(0xFF, (short)Val[0], (short)Val[2], (short)Val[4]); - } - - break; - } - - case 9: - { - int[] Val = ReadIntColorValues(6, ColorValues, ref ColorValuesPosition); - - BitArrayStream.BitTransferSigned(ref Val[1], ref Val[0]); - BitArrayStream.BitTransferSigned(ref Val[3], ref Val[2]); - BitArrayStream.BitTransferSigned(ref Val[5], ref Val[4]); - - if (Val[1] + Val[3] + Val[5] >= 0) - { - EndPoints[0] = new ASTCPixel(0xFF, (short)Val[0], (short)Val[2], (short)Val[4]); - EndPoints[1] = new ASTCPixel(0xFF, (short)(Val[0] + Val[1]), (short)(Val[2] + Val[3]), (short)(Val[4] + Val[5])); - } - else - { - EndPoints[0] = ASTCPixel.BlueContract(0xFF, Val[0] + Val[1], Val[2] + Val[3], Val[4] + Val[5]); - EndPoints[1] = ASTCPixel.BlueContract(0xFF, Val[0], Val[2], Val[4]); - } - - EndPoints[0].ClampByte(); - EndPoints[1].ClampByte(); - - break; - } - - case 10: - { - uint[] Val = ReadUintColorValues(6, ColorValues, ref ColorValuesPosition); - - EndPoints[0] = new ASTCPixel((short)Val[4], (short)(Val[0] * Val[3] >> 8), (short)(Val[1] * Val[3] >> 8), (short)(Val[2] * Val[3] >> 8)); - EndPoints[1] = new ASTCPixel((short)Val[5], (short)Val[0], (short)Val[1], (short)Val[2]); - - break; - } - - case 12: - { - uint[] Val = ReadUintColorValues(8, ColorValues, ref ColorValuesPosition); - - if (Val[1] + Val[3] + Val[5] >= Val[0] + Val[2] + Val[4]) - { - EndPoints[0] = new ASTCPixel((short)Val[6], (short)Val[0], (short)Val[2], (short)Val[4]); - EndPoints[1] = new ASTCPixel((short)Val[7], (short)Val[1], (short)Val[3], (short)Val[5]); - } - else - { - EndPoints[0] = ASTCPixel.BlueContract((short)Val[7], (short)Val[1], (short)Val[3], (short)Val[5]); - EndPoints[1] = ASTCPixel.BlueContract((short)Val[6], (short)Val[0], (short)Val[2], (short)Val[4]); - } - - break; - } - - case 13: - { - int[] Val = ReadIntColorValues(8, ColorValues, ref ColorValuesPosition); - - BitArrayStream.BitTransferSigned(ref Val[1], ref Val[0]); - BitArrayStream.BitTransferSigned(ref Val[3], ref Val[2]); - BitArrayStream.BitTransferSigned(ref Val[5], ref Val[4]); - BitArrayStream.BitTransferSigned(ref Val[7], ref Val[6]); - - if (Val[1] + Val[3] + Val[5] >= 0) - { - EndPoints[0] = new ASTCPixel((short)Val[6], (short)Val[0], (short)Val[2], (short)Val[4]); - EndPoints[1] = new ASTCPixel((short)(Val[7] + Val[6]), (short)(Val[0] + Val[1]), (short)(Val[2] + Val[3]), (short)(Val[4] + Val[5])); - } - else - { - EndPoints[0] = ASTCPixel.BlueContract(Val[6] + Val[7], Val[0] + Val[1], Val[2] + Val[3], Val[4] + Val[5]); - EndPoints[1] = ASTCPixel.BlueContract(Val[6], Val[0], Val[2], Val[4]); - } - - EndPoints[0].ClampByte(); - EndPoints[1].ClampByte(); - - break; - } - - default: - throw new ASTCDecoderException("Unsupported color endpoint mode (is it HDR?)"); - } - } - - static void DecodeColorValues( - int[] OutputValues, - byte[] InputData, - uint[] Modes, - int NumberPartitions, - int NumberBitsForColorData) - { - // First figure out how many color values we have - int NumberValues = 0; - - for (int i = 0; i < NumberPartitions; i++) - { - NumberValues += (int)((Modes[i] >> 2) + 1) << 1; - } - - // Then based on the number of values and the remaining number of bits, - // figure out the max value for each of them... - int Range = 256; - - while (--Range > 0) - { - IntegerEncoded IntEncoded = IntegerEncoded.CreateEncoding(Range); - int BitLength = IntEncoded.GetBitLength(NumberValues); - - if (BitLength <= NumberBitsForColorData) - { - // Find the smallest possible range that matches the given encoding - while (--Range > 0) - { - IntegerEncoded NewIntEncoded = IntegerEncoded.CreateEncoding(Range); - if (!NewIntEncoded.MatchesEncoding(IntEncoded)) - { - break; - } - } - - // Return to last matching range. - Range++; - break; - } - } - - // We now have enough to decode our integer sequence. - List IntegerEncodedSequence = new List(); - BitArrayStream ColorBitStream = new BitArrayStream(new BitArray(InputData)); - - IntegerEncoded.DecodeIntegerSequence(IntegerEncodedSequence, ColorBitStream, Range, NumberValues); - - // Once we have the decoded values, we need to dequantize them to the 0-255 range - // This procedure is outlined in ASTC spec C.2.13 - int OutputIndices = 0; - - foreach (IntegerEncoded IntEncoded in IntegerEncodedSequence) - { - int BitLength = IntEncoded.NumberBits; - int BitValue = IntEncoded.BitValue; - - Debug.Assert(BitLength >= 1); - - int A = 0, B = 0, C = 0, D = 0; - // A is just the lsb replicated 9 times. - A = BitArrayStream.Replicate(BitValue & 1, 1, 9); - - switch (IntEncoded.GetEncoding()) - { - case IntegerEncoded.EIntegerEncoding.JustBits: - { - OutputValues[OutputIndices++] = BitArrayStream.Replicate(BitValue, BitLength, 8); - - break; - } - - case IntegerEncoded.EIntegerEncoding.Trit: - { - D = IntEncoded.TritValue; - - switch (BitLength) - { - case 1: - { - C = 204; - - break; - } - - case 2: - { - C = 93; - // B = b000b0bb0 - int b = (BitValue >> 1) & 1; - B = (b << 8) | (b << 4) | (b << 2) | (b << 1); - - break; - } - - case 3: - { - C = 44; - // B = cb000cbcb - int cb = (BitValue >> 1) & 3; - B = (cb << 7) | (cb << 2) | cb; - - break; - } - - - case 4: - { - C = 22; - // B = dcb000dcb - int dcb = (BitValue >> 1) & 7; - B = (dcb << 6) | dcb; - - break; - } - - case 5: - { - C = 11; - // B = edcb000ed - int edcb = (BitValue >> 1) & 0xF; - B = (edcb << 5) | (edcb >> 2); - - break; - } - - case 6: - { - C = 5; - // B = fedcb000f - int fedcb = (BitValue >> 1) & 0x1F; - B = (fedcb << 4) | (fedcb >> 4); - - break; - } - - default: - throw new ASTCDecoderException("Unsupported trit encoding for color values!"); - } - - break; - } - - case IntegerEncoded.EIntegerEncoding.Quint: - { - D = IntEncoded.QuintValue; - - switch (BitLength) - { - case 1: - { - C = 113; - - break; - } - - case 2: - { - C = 54; - // B = b0000bb00 - int b = (BitValue >> 1) & 1; - B = (b << 8) | (b << 3) | (b << 2); - - break; - } - - case 3: - { - C = 26; - // B = cb0000cbc - int cb = (BitValue >> 1) & 3; - B = (cb << 7) | (cb << 1) | (cb >> 1); - - break; - } - - case 4: - { - C = 13; - // B = dcb0000dc - int dcb = (BitValue >> 1) & 7; - B = (dcb << 6) | (dcb >> 1); - - break; - } - - case 5: - { - C = 6; - // B = edcb0000e - int edcb = (BitValue >> 1) & 0xF; - B = (edcb << 5) | (edcb >> 3); - - break; - } - - default: - throw new ASTCDecoderException("Unsupported quint encoding for color values!"); - } - break; - } - } - - if (IntEncoded.GetEncoding() != IntegerEncoded.EIntegerEncoding.JustBits) - { - int T = D * C + B; - T ^= A; - T = (A & 0x80) | (T >> 2); - - OutputValues[OutputIndices++] = T; - } - } - - // Make sure that each of our values is in the proper range... - for (int i = 0; i < NumberValues; i++) - { - Debug.Assert(OutputValues[i] <= 255); - } - } - - static void FillVoidExtentLDR(BitArrayStream BitStream, int[] OutputBuffer, int BlockWidth, int BlockHeight) - { - // Don't actually care about the void extent, just read the bits... - for (int i = 0; i < 4; ++i) - { - BitStream.ReadBits(13); - } - - // Decode the RGBA components and renormalize them to the range [0, 255] - ushort R = (ushort)BitStream.ReadBits(16); - ushort G = (ushort)BitStream.ReadBits(16); - ushort B = (ushort)BitStream.ReadBits(16); - ushort A = (ushort)BitStream.ReadBits(16); - - int RGBA = (R >> 8) | (G & 0xFF00) | ((B) & 0xFF00) << 8 | ((A) & 0xFF00) << 16; - - for (int j = 0; j < BlockHeight; j++) - { - for (int i = 0; i < BlockWidth; i++) - { - OutputBuffer[j * BlockWidth + i] = RGBA; - } - } - } - - static TexelWeightParams DecodeBlockInfo(BitArrayStream BitStream) - { - TexelWeightParams TexelParams = new TexelWeightParams(); - - // Read the entire block mode all at once - ushort ModeBits = (ushort)BitStream.ReadBits(11); - - // Does this match the void extent block mode? - if ((ModeBits & 0x01FF) == 0x1FC) - { - if ((ModeBits & 0x200) != 0) - { - TexelParams.VoidExtentHDR = true; - } - else - { - TexelParams.VoidExtentLDR = true; - } - - // Next two bits must be one. - if ((ModeBits & 0x400) == 0 || BitStream.ReadBits(1) == 0) - { - TexelParams.Error = true; - } - - return TexelParams; - } - - // First check if the last four bits are zero - if ((ModeBits & 0xF) == 0) - { - TexelParams.Error = true; - return TexelParams; - } - - // If the last two bits are zero, then if bits - // [6-8] are all ones, this is also reserved. - if ((ModeBits & 0x3) == 0 && (ModeBits & 0x1C0) == 0x1C0) - { - TexelParams.Error = true; - - return TexelParams; - } - - // Otherwise, there is no error... Figure out the layout - // of the block mode. Layout is determined by a number - // between 0 and 9 corresponding to table C.2.8 of the - // ASTC spec. - int Layout = 0; - - if ((ModeBits & 0x1) != 0 || (ModeBits & 0x2) != 0) - { - // layout is in [0-4] - if ((ModeBits & 0x8) != 0) - { - // layout is in [2-4] - if ((ModeBits & 0x4) != 0) - { - // layout is in [3-4] - if ((ModeBits & 0x100) != 0) - { - Layout = 4; - } - else - { - Layout = 3; - } - } - else - { - Layout = 2; - } - } - else - { - // layout is in [0-1] - if ((ModeBits & 0x4) != 0) - { - Layout = 1; - } - else - { - Layout = 0; - } - } - } - else - { - // layout is in [5-9] - if ((ModeBits & 0x100) != 0) - { - // layout is in [7-9] - if ((ModeBits & 0x80) != 0) - { - // layout is in [7-8] - Debug.Assert((ModeBits & 0x40) == 0); - - if ((ModeBits & 0x20) != 0) - { - Layout = 8; - } - else - { - Layout = 7; - } - } - else - { - Layout = 9; - } - } - else - { - // layout is in [5-6] - if ((ModeBits & 0x80) != 0) - { - Layout = 6; - } - else - { - Layout = 5; - } - } - } - - Debug.Assert(Layout < 10); - - // Determine R - int R = (ModeBits >> 4) & 1; - if (Layout < 5) - { - R |= (ModeBits & 0x3) << 1; - } - else - { - R |= (ModeBits & 0xC) >> 1; - } - - Debug.Assert(2 <= R && R <= 7); - - // Determine width & height - switch (Layout) - { - case 0: - { - int A = (ModeBits >> 5) & 0x3; - int B = (ModeBits >> 7) & 0x3; - - TexelParams.Width = B + 4; - TexelParams.Height = A + 2; - - break; - } - - case 1: - { - int A = (ModeBits >> 5) & 0x3; - int B = (ModeBits >> 7) & 0x3; - - TexelParams.Width = B + 8; - TexelParams.Height = A + 2; - - break; - } - - case 2: - { - int A = (ModeBits >> 5) & 0x3; - int B = (ModeBits >> 7) & 0x3; - - TexelParams.Width = A + 2; - TexelParams.Height = B + 8; - - break; - } - - case 3: - { - int A = (ModeBits >> 5) & 0x3; - int B = (ModeBits >> 7) & 0x1; - - TexelParams.Width = A + 2; - TexelParams.Height = B + 6; - - break; - } - - case 4: - { - int A = (ModeBits >> 5) & 0x3; - int B = (ModeBits >> 7) & 0x1; - - TexelParams.Width = B + 2; - TexelParams.Height = A + 2; - - break; - } - - case 5: - { - int A = (ModeBits >> 5) & 0x3; - - TexelParams.Width = 12; - TexelParams.Height = A + 2; - - break; - } - - case 6: - { - int A = (ModeBits >> 5) & 0x3; - - TexelParams.Width = A + 2; - TexelParams.Height = 12; - - break; - } - - case 7: - { - TexelParams.Width = 6; - TexelParams.Height = 10; - - break; - } - - case 8: - { - TexelParams.Width = 10; - TexelParams.Height = 6; - break; - } - - case 9: - { - int A = (ModeBits >> 5) & 0x3; - int B = (ModeBits >> 9) & 0x3; - - TexelParams.Width = A + 6; - TexelParams.Height = B + 6; - - break; - } - - default: - //Don't know this layout... - TexelParams.Error = true; - break; - } - - // Determine whether or not we're using dual planes - // and/or high precision layouts. - bool D = ((Layout != 9) && ((ModeBits & 0x400) != 0)); - bool H = (Layout != 9) && ((ModeBits & 0x200) != 0); - - if (H) - { - int[] MaxWeights = { 9, 11, 15, 19, 23, 31 }; - TexelParams.MaxWeight = MaxWeights[R - 2]; - } - else - { - int[] MaxWeights = { 1, 2, 3, 4, 5, 7 }; - TexelParams.MaxWeight = MaxWeights[R - 2]; - } - - TexelParams.DualPlane = D; - - return TexelParams; - } - } -} diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ASTCPixel.cs b/Ryujinx.Graphics/Graphics3d/Texture/ASTCPixel.cs deleted file mode 100644 index c43eaf9380..0000000000 --- a/Ryujinx.Graphics/Graphics3d/Texture/ASTCPixel.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.Diagnostics; - -namespace Ryujinx.Graphics.Texture -{ - class ASTCPixel - { - public short R { get; set; } - public short G { get; set; } - public short B { get; set; } - public short A { get; set; } - - byte[] BitDepth = new byte[4]; - - public ASTCPixel(short _A, short _R, short _G, short _B) - { - A = _A; - R = _R; - G = _G; - B = _B; - - for (int i = 0; i < 4; i++) - BitDepth[i] = 8; - } - - public void ClampByte() - { - R = Math.Min(Math.Max(R, (short)0), (short)255); - G = Math.Min(Math.Max(G, (short)0), (short)255); - B = Math.Min(Math.Max(B, (short)0), (short)255); - A = Math.Min(Math.Max(A, (short)0), (short)255); - } - - public short GetComponent(int Index) - { - switch(Index) - { - case 0: return A; - case 1: return R; - case 2: return G; - case 3: return B; - } - - return 0; - } - - public void SetComponent(int Index, int Value) - { - switch (Index) - { - case 0: - A = (short)Value; - break; - case 1: - R = (short)Value; - break; - case 2: - G = (short)Value; - break; - case 3: - B = (short)Value; - break; - } - } - - public void ChangeBitDepth(byte[] Depth) - { - for(int i = 0; i< 4; i++) - { - int Value = ChangeBitDepth(GetComponent(i), BitDepth[i], Depth[i]); - - SetComponent(i, Value); - BitDepth[i] = Depth[i]; - } - } - - short ChangeBitDepth(short Value, byte OldDepth, byte NewDepth) - { - Debug.Assert(NewDepth <= 8); - Debug.Assert(OldDepth <= 8); - - if (OldDepth == NewDepth) - { - // Do nothing - return Value; - } - else if (OldDepth == 0 && NewDepth != 0) - { - return (short)((1 << NewDepth) - 1); - } - else if (NewDepth > OldDepth) - { - return (short)BitArrayStream.Replicate(Value, OldDepth, NewDepth); - } - else - { - // oldDepth > newDepth - if (NewDepth == 0) - { - return 0xFF; - } - else - { - byte BitsWasted = (byte)(OldDepth - NewDepth); - short TempValue = Value; - - TempValue = (short)((TempValue + (1 << (BitsWasted - 1))) >> BitsWasted); - TempValue = Math.Min(Math.Max((short)0, TempValue), (short)((1 << NewDepth) - 1)); - - return (byte)(TempValue); - } - } - } - - public int Pack() - { - ASTCPixel NewPixel = new ASTCPixel(A, R, G, B); - byte[] eightBitDepth = { 8, 8, 8, 8 }; - - NewPixel.ChangeBitDepth(eightBitDepth); - - return (byte)NewPixel.A << 24 | - (byte)NewPixel.B << 16 | - (byte)NewPixel.G << 8 | - (byte)NewPixel.R << 0; - } - - // Adds more precision to the blue channel as described - // in C.2.14 - public static ASTCPixel BlueContract(int a, int r, int g, int b) - { - return new ASTCPixel((short)(a), - (short)((r + b) >> 1), - (short)((g + b) >> 1), - (short)(b)); - } - } -} diff --git a/Ryujinx.Graphics/Graphics3d/Texture/AstcDecoder.cs b/Ryujinx.Graphics/Graphics3d/Texture/AstcDecoder.cs new file mode 100644 index 0000000000..99b166f33e --- /dev/null +++ b/Ryujinx.Graphics/Graphics3d/Texture/AstcDecoder.cs @@ -0,0 +1,1385 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace Ryujinx.Graphics.Texture +{ + public class AstcDecoderException : Exception + { + public AstcDecoderException(string exMsg) : base(exMsg) { } + } + + //https://github.com/GammaUNC/FasTC/blob/master/ASTCEncoder/src/Decompressor.cpp + public static class AstcDecoder + { + struct TexelWeightParams + { + public int Width; + public int Height; + public bool DualPlane; + public int MaxWeight; + public bool Error; + public bool VoidExtentLdr; + public bool VoidExtentHdr; + + public int GetPackedBitSize() + { + // How many indices do we have? + int indices = Height * Width; + + if (DualPlane) + { + indices *= 2; + } + + IntegerEncoded intEncoded = IntegerEncoded.CreateEncoding(MaxWeight); + + return intEncoded.GetBitLength(indices); + } + + public int GetNumWeightValues() + { + int ret = Width * Height; + + if (DualPlane) + { + ret *= 2; + } + + return ret; + } + } + + public static byte[] DecodeToRgba8888( + byte[] inputBuffer, + int blockX, + int blockY, + int blockZ, + int x, + int y, + int z) + { + using (MemoryStream inputStream = new MemoryStream(inputBuffer)) + { + BinaryReader binReader = new BinaryReader(inputStream); + + if (blockX > 12 || blockY > 12) + { + throw new AstcDecoderException("Block size unsupported!"); + } + + if (blockZ != 1 || z != 1) + { + // TODO: Support 3D textures? + throw new AstcDecoderException("3D compressed textures unsupported!"); + } + + using (MemoryStream outputStream = new MemoryStream()) + { + int blockIndex = 0; + + for (int j = 0; j < y; j += blockY) + { + for (int i = 0; i < x; i += blockX) + { + int[] decompressedData = new int[144]; + + DecompressBlock(binReader.ReadBytes(0x10), decompressedData, blockX, blockY); + + int decompressedWidth = Math.Min(blockX, x - i); + int decompressedHeight = Math.Min(blockY, y - j); + int baseOffsets = (j * x + i) * 4; + + for (int jj = 0; jj < decompressedHeight; jj++) + { + outputStream.Seek(baseOffsets + jj * x * 4, SeekOrigin.Begin); + + byte[] outputBuffer = new byte[decompressedData.Length * sizeof(int)]; + Buffer.BlockCopy(decompressedData, 0, outputBuffer, 0, outputBuffer.Length); + + outputStream.Write(outputBuffer, jj * blockX * 4, decompressedWidth * 4); + } + + blockIndex++; + } + } + + return outputStream.ToArray(); + } + } + } + + public static bool DecompressBlock( + byte[] inputBuffer, + int[] outputBuffer, + int blockWidth, + int blockHeight) + { + BitArrayStream bitStream = new BitArrayStream(new BitArray(inputBuffer)); + TexelWeightParams texelParams = DecodeBlockInfo(bitStream); + + if (texelParams.Error) + { + throw new AstcDecoderException("Invalid block mode"); + } + + if (texelParams.VoidExtentLdr) + { + FillVoidExtentLdr(bitStream, outputBuffer, blockWidth, blockHeight); + + return true; + } + + if (texelParams.VoidExtentHdr) + { + throw new AstcDecoderException("HDR void extent blocks are unsupported!"); + } + + if (texelParams.Width > blockWidth) + { + throw new AstcDecoderException("Texel weight grid width should be smaller than block width"); + } + + if (texelParams.Height > blockHeight) + { + throw new AstcDecoderException("Texel weight grid height should be smaller than block height"); + } + + // Read num partitions + int numberPartitions = bitStream.ReadBits(2) + 1; + Debug.Assert(numberPartitions <= 4); + + if (numberPartitions == 4 && texelParams.DualPlane) + { + throw new AstcDecoderException("Dual plane mode is incompatible with four partition blocks"); + } + + // Based on the number of partitions, read the color endpoint mode for + // each partition. + + // Determine partitions, partition index, and color endpoint modes + int planeIndices = -1; + int partitionIndex; + uint[] colorEndpointMode = { 0, 0, 0, 0 }; + + BitArrayStream colorEndpointStream = new BitArrayStream(new BitArray(16 * 8)); + + // Read extra config data... + uint baseColorEndpointMode = 0; + + if (numberPartitions == 1) + { + colorEndpointMode[0] = (uint)bitStream.ReadBits(4); + partitionIndex = 0; + } + else + { + partitionIndex = bitStream.ReadBits(10); + baseColorEndpointMode = (uint)bitStream.ReadBits(6); + } + + uint baseMode = (baseColorEndpointMode & 3); + + // Remaining bits are color endpoint data... + int numberWeightBits = texelParams.GetPackedBitSize(); + int remainingBits = 128 - numberWeightBits - bitStream.Position; + + // Consider extra bits prior to texel data... + uint extraColorEndpointModeBits = 0; + + if (baseMode != 0) + { + switch (numberPartitions) + { + case 2: extraColorEndpointModeBits += 2; break; + case 3: extraColorEndpointModeBits += 5; break; + case 4: extraColorEndpointModeBits += 8; break; + default: Debug.Assert(false); break; + } + } + + remainingBits -= (int)extraColorEndpointModeBits; + + // Do we have a dual plane situation? + int planeSelectorBits = 0; + + if (texelParams.DualPlane) + { + planeSelectorBits = 2; + } + + remainingBits -= planeSelectorBits; + + // Read color data... + int colorDataBits = remainingBits; + + while (remainingBits > 0) + { + int numberBits = Math.Min(remainingBits, 8); + int bits = bitStream.ReadBits(numberBits); + colorEndpointStream.WriteBits(bits, numberBits); + remainingBits -= 8; + } + + // Read the plane selection bits + planeIndices = bitStream.ReadBits(planeSelectorBits); + + // Read the rest of the CEM + if (baseMode != 0) + { + uint extraColorEndpointMode = (uint)bitStream.ReadBits((int)extraColorEndpointModeBits); + uint tempColorEndpointMode = (extraColorEndpointMode << 6) | baseColorEndpointMode; + tempColorEndpointMode >>= 2; + + bool[] c = new bool[4]; + + for (int i = 0; i < numberPartitions; i++) + { + c[i] = (tempColorEndpointMode & 1) != 0; + tempColorEndpointMode >>= 1; + } + + byte[] m = new byte[4]; + + for (int i = 0; i < numberPartitions; i++) + { + m[i] = (byte)(tempColorEndpointMode & 3); + tempColorEndpointMode >>= 2; + Debug.Assert(m[i] <= 3); + } + + for (int i = 0; i < numberPartitions; i++) + { + colorEndpointMode[i] = baseMode; + if (!(c[i])) colorEndpointMode[i] -= 1; + colorEndpointMode[i] <<= 2; + colorEndpointMode[i] |= m[i]; + } + } + else if (numberPartitions > 1) + { + uint tempColorEndpointMode = baseColorEndpointMode >> 2; + + for (uint i = 0; i < numberPartitions; i++) + { + colorEndpointMode[i] = tempColorEndpointMode; + } + } + + // Make sure everything up till here is sane. + for (int i = 0; i < numberPartitions; i++) + { + Debug.Assert(colorEndpointMode[i] < 16); + } + Debug.Assert(bitStream.Position + texelParams.GetPackedBitSize() == 128); + + // Decode both color data and texel weight data + int[] colorValues = new int[32]; // Four values * two endpoints * four maximum partitions + DecodeColorValues(colorValues, colorEndpointStream.ToByteArray(), colorEndpointMode, numberPartitions, colorDataBits); + + AstcPixel[][] endPoints = new AstcPixel[4][]; + endPoints[0] = new AstcPixel[2]; + endPoints[1] = new AstcPixel[2]; + endPoints[2] = new AstcPixel[2]; + endPoints[3] = new AstcPixel[2]; + + int colorValuesPosition = 0; + + for (int i = 0; i < numberPartitions; i++) + { + ComputeEndpoints(endPoints[i], colorValues, colorEndpointMode[i], ref colorValuesPosition); + } + + // Read the texel weight data. + byte[] texelWeightData = (byte[])inputBuffer.Clone(); + + // Reverse everything + for (int i = 0; i < 8; i++) + { + byte a = ReverseByte(texelWeightData[i]); + byte b = ReverseByte(texelWeightData[15 - i]); + + texelWeightData[i] = b; + texelWeightData[15 - i] = a; + } + + // Make sure that higher non-texel bits are set to zero + int clearByteStart = (texelParams.GetPackedBitSize() >> 3) + 1; + texelWeightData[clearByteStart - 1] &= (byte)((1 << (texelParams.GetPackedBitSize() % 8)) - 1); + + int cLen = 16 - clearByteStart; + for (int i = clearByteStart; i < clearByteStart + cLen; i++) texelWeightData[i] = 0; + + List texelWeightValues = new List(); + BitArrayStream weightBitStream = new BitArrayStream(new BitArray(texelWeightData)); + + IntegerEncoded.DecodeIntegerSequence(texelWeightValues, weightBitStream, texelParams.MaxWeight, texelParams.GetNumWeightValues()); + + // Blocks can be at most 12x12, so we can have as many as 144 weights + int[][] weights = new int[2][]; + weights[0] = new int[144]; + weights[1] = new int[144]; + + UnquantizeTexelWeights(weights, texelWeightValues, texelParams, blockWidth, blockHeight); + + // Now that we have endpoints and weights, we can interpolate and generate + // the proper decoding... + for (int j = 0; j < blockHeight; j++) + { + for (int i = 0; i < blockWidth; i++) + { + int partition = Select2dPartition(partitionIndex, i, j, numberPartitions, ((blockHeight * blockWidth) < 32)); + Debug.Assert(partition < numberPartitions); + + AstcPixel pixel = new AstcPixel(0, 0, 0, 0); + for (int component = 0; component < 4; component++) + { + int component0 = endPoints[partition][0].GetComponent(component); + component0 = BitArrayStream.Replicate(component0, 8, 16); + int component1 = endPoints[partition][1].GetComponent(component); + component1 = BitArrayStream.Replicate(component1, 8, 16); + + int plane = 0; + + if (texelParams.DualPlane && (((planeIndices + 1) & 3) == component)) + { + plane = 1; + } + + int weight = weights[plane][j * blockWidth + i]; + int finalComponent = (component0 * (64 - weight) + component1 * weight + 32) / 64; + + if (finalComponent == 65535) + { + pixel.SetComponent(component, 255); + } + else + { + double finalComponentFloat = finalComponent; + pixel.SetComponent(component, (int)(255.0 * (finalComponentFloat / 65536.0) + 0.5)); + } + } + + outputBuffer[j * blockWidth + i] = pixel.Pack(); + } + } + + return true; + } + + private static int Select2dPartition(int seed, int x, int y, int partitionCount, bool isSmallBlock) + { + return SelectPartition(seed, x, y, 0, partitionCount, isSmallBlock); + } + + private static int SelectPartition(int seed, int x, int y, int z, int partitionCount, bool isSmallBlock) + { + if (partitionCount == 1) + { + return 0; + } + + if (isSmallBlock) + { + x <<= 1; + y <<= 1; + z <<= 1; + } + + seed += (partitionCount - 1) * 1024; + + int rightNum = Hash52((uint)seed); + byte seed01 = (byte)(rightNum & 0xF); + byte seed02 = (byte)((rightNum >> 4) & 0xF); + byte seed03 = (byte)((rightNum >> 8) & 0xF); + byte seed04 = (byte)((rightNum >> 12) & 0xF); + byte seed05 = (byte)((rightNum >> 16) & 0xF); + byte seed06 = (byte)((rightNum >> 20) & 0xF); + byte seed07 = (byte)((rightNum >> 24) & 0xF); + byte seed08 = (byte)((rightNum >> 28) & 0xF); + byte seed09 = (byte)((rightNum >> 18) & 0xF); + byte seed10 = (byte)((rightNum >> 22) & 0xF); + byte seed11 = (byte)((rightNum >> 26) & 0xF); + byte seed12 = (byte)(((rightNum >> 30) | (rightNum << 2)) & 0xF); + + seed01 *= seed01; seed02 *= seed02; + seed03 *= seed03; seed04 *= seed04; + seed05 *= seed05; seed06 *= seed06; + seed07 *= seed07; seed08 *= seed08; + seed09 *= seed09; seed10 *= seed10; + seed11 *= seed11; seed12 *= seed12; + + int seedHash1, seedHash2, seedHash3; + + if ((seed & 1) != 0) + { + seedHash1 = (seed & 2) != 0 ? 4 : 5; + seedHash2 = (partitionCount == 3) ? 6 : 5; + } + else + { + seedHash1 = (partitionCount == 3) ? 6 : 5; + seedHash2 = (seed & 2) != 0 ? 4 : 5; + } + + seedHash3 = (seed & 0x10) != 0 ? seedHash1 : seedHash2; + + seed01 >>= seedHash1; seed02 >>= seedHash2; seed03 >>= seedHash1; seed04 >>= seedHash2; + seed05 >>= seedHash1; seed06 >>= seedHash2; seed07 >>= seedHash1; seed08 >>= seedHash2; + seed09 >>= seedHash3; seed10 >>= seedHash3; seed11 >>= seedHash3; seed12 >>= seedHash3; + + int a = seed01 * x + seed02 * y + seed11 * z + (rightNum >> 14); + int b = seed03 * x + seed04 * y + seed12 * z + (rightNum >> 10); + int c = seed05 * x + seed06 * y + seed09 * z + (rightNum >> 6); + int d = seed07 * x + seed08 * y + seed10 * z + (rightNum >> 2); + + a &= 0x3F; b &= 0x3F; c &= 0x3F; d &= 0x3F; + + if (partitionCount < 4) d = 0; + if (partitionCount < 3) c = 0; + + if (a >= b && a >= c && a >= d) return 0; + else if (b >= c && b >= d) return 1; + else if (c >= d) return 2; + return 3; + } + + static int Hash52(uint val) + { + val ^= val >> 15; val -= val << 17; val += val << 7; val += val << 4; + val ^= val >> 5; val += val << 16; val ^= val >> 7; val ^= val >> 3; + val ^= val << 6; val ^= val >> 17; + + return (int)val; + } + + static void UnquantizeTexelWeights( + int[][] outputBuffer, + List weights, + TexelWeightParams texelParams, + int blockWidth, + int blockHeight) + { + int weightIndices = 0; + int[][] unquantized = new int[2][]; + unquantized[0] = new int[144]; + unquantized[1] = new int[144]; + + for (int i = 0; i < weights.Count; i++) + { + unquantized[0][weightIndices] = UnquantizeTexelWeight(weights[i]); + + if (texelParams.DualPlane) + { + i++; + unquantized[1][weightIndices] = UnquantizeTexelWeight(weights[i]); + + if (i == weights.Count) + { + break; + } + } + + if (++weightIndices >= (texelParams.Width * texelParams.Height)) break; + } + + // Do infill if necessary (Section C.2.18) ... + int ds = (1024 + (blockWidth / 2)) / (blockWidth - 1); + int dt = (1024 + (blockHeight / 2)) / (blockHeight - 1); + + int planeScale = texelParams.DualPlane ? 2 : 1; + + for (int plane = 0; plane < planeScale; plane++) + { + for (int t = 0; t < blockHeight; t++) + { + for (int s = 0; s < blockWidth; s++) + { + int cs = ds * s; + int ct = dt * t; + + int gs = (cs * (texelParams.Width - 1) + 32) >> 6; + int gt = (ct * (texelParams.Height - 1) + 32) >> 6; + + int js = gs >> 4; + int fs = gs & 0xF; + + int jt = gt >> 4; + int ft = gt & 0x0F; + + int w11 = (fs * ft + 8) >> 4; + int w10 = ft - w11; + int w01 = fs - w11; + int w00 = 16 - fs - ft + w11; + + int v0 = js + jt * texelParams.Width; + + int p00 = 0; + int p01 = 0; + int p10 = 0; + int p11 = 0; + + if (v0 < (texelParams.Width * texelParams.Height)) + { + p00 = unquantized[plane][v0]; + } + + if (v0 + 1 < (texelParams.Width * texelParams.Height)) + { + p01 = unquantized[plane][v0 + 1]; + } + + if (v0 + texelParams.Width < (texelParams.Width * texelParams.Height)) + { + p10 = unquantized[plane][v0 + texelParams.Width]; + } + + if (v0 + texelParams.Width + 1 < (texelParams.Width * texelParams.Height)) + { + p11 = unquantized[plane][v0 + texelParams.Width + 1]; + } + + outputBuffer[plane][t * blockWidth + s] = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11 + 8) >> 4; + } + } + } + } + + static int UnquantizeTexelWeight(IntegerEncoded intEncoded) + { + int bitValue = intEncoded.BitValue; + int bitLength = intEncoded.NumberBits; + + int a = BitArrayStream.Replicate(bitValue & 1, 1, 7); + int b = 0, c = 0, d = 0; + + int result = 0; + + switch (intEncoded.GetEncoding()) + { + case IntegerEncoded.EIntegerEncoding.JustBits: + result = BitArrayStream.Replicate(bitValue, bitLength, 6); + break; + + case IntegerEncoded.EIntegerEncoding.Trit: + { + d = intEncoded.TritValue; + Debug.Assert(d < 3); + + switch (bitLength) + { + case 0: + { + int[] results = { 0, 32, 63 }; + result = results[d]; + + break; + } + + case 1: + { + c = 50; + break; + } + + case 2: + { + c = 23; + int b2 = (bitValue >> 1) & 1; + b = (b2 << 6) | (b2 << 2) | b2; + + break; + } + + case 3: + { + c = 11; + int cb = (bitValue >> 1) & 3; + b = (cb << 5) | cb; + + break; + } + + default: + throw new AstcDecoderException("Invalid trit encoding for texel weight"); + } + + break; + } + + case IntegerEncoded.EIntegerEncoding.Quint: + { + d = intEncoded.QuintValue; + Debug.Assert(d < 5); + + switch (bitLength) + { + case 0: + { + int[] results = { 0, 16, 32, 47, 63 }; + result = results[d]; + + break; + } + + case 1: + { + c = 28; + + break; + } + + case 2: + { + c = 13; + int b2 = (bitValue >> 1) & 1; + b = (b2 << 6) | (b2 << 1); + + break; + } + + default: + throw new AstcDecoderException("Invalid quint encoding for texel weight"); + } + + break; + } + } + + if (intEncoded.GetEncoding() != IntegerEncoded.EIntegerEncoding.JustBits && bitLength > 0) + { + // Decode the value... + result = d * c + b; + result ^= a; + result = (a & 0x20) | (result >> 2); + } + + Debug.Assert(result < 64); + + // Change from [0,63] to [0,64] + if (result > 32) + { + result += 1; + } + + return result; + } + + static byte ReverseByte(byte b) + { + // Taken from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits + return (byte)((((b) * 0x80200802L) & 0x0884422110L) * 0x0101010101L >> 32); + } + + static uint[] ReadUintColorValues(int number, int[] colorValues, ref int colorValuesPosition) + { + uint[] ret = new uint[number]; + + for (int i = 0; i < number; i++) + { + ret[i] = (uint)colorValues[colorValuesPosition++]; + } + + return ret; + } + + static int[] ReadIntColorValues(int number, int[] colorValues, ref int colorValuesPosition) + { + int[] ret = new int[number]; + + for (int i = 0; i < number; i++) + { + ret[i] = colorValues[colorValuesPosition++]; + } + + return ret; + } + + static void ComputeEndpoints( + AstcPixel[] endPoints, + int[] colorValues, + uint colorEndpointMode, + ref int colorValuesPosition) + { + switch (colorEndpointMode) + { + case 0: + { + uint[] val = ReadUintColorValues(2, colorValues, ref colorValuesPosition); + + endPoints[0] = new AstcPixel(0xFF, (short)val[0], (short)val[0], (short)val[0]); + endPoints[1] = new AstcPixel(0xFF, (short)val[1], (short)val[1], (short)val[1]); + + break; + } + + + case 1: + { + uint[] val = ReadUintColorValues(2, colorValues, ref colorValuesPosition); + int l0 = (int)((val[0] >> 2) | (val[1] & 0xC0)); + int l1 = (int)Math.Max(l0 + (val[1] & 0x3F), 0xFFU); + + endPoints[0] = new AstcPixel(0xFF, (short)l0, (short)l0, (short)l0); + endPoints[1] = new AstcPixel(0xFF, (short)l1, (short)l1, (short)l1); + + break; + } + + case 4: + { + uint[] val = ReadUintColorValues(4, colorValues, ref colorValuesPosition); + + endPoints[0] = new AstcPixel((short)val[2], (short)val[0], (short)val[0], (short)val[0]); + endPoints[1] = new AstcPixel((short)val[3], (short)val[1], (short)val[1], (short)val[1]); + + break; + } + + case 5: + { + int[] val = ReadIntColorValues(4, colorValues, ref colorValuesPosition); + + BitArrayStream.BitTransferSigned(ref val[1], ref val[0]); + BitArrayStream.BitTransferSigned(ref val[3], ref val[2]); + + endPoints[0] = new AstcPixel((short)val[2], (short)val[0], (short)val[0], (short)val[0]); + endPoints[1] = new AstcPixel((short)(val[2] + val[3]), (short)(val[0] + val[1]), (short)(val[0] + val[1]), (short)(val[0] + val[1])); + + endPoints[0].ClampByte(); + endPoints[1].ClampByte(); + + break; + } + + case 6: + { + uint[] val = ReadUintColorValues(4, colorValues, ref colorValuesPosition); + + endPoints[0] = new AstcPixel(0xFF, (short)(val[0] * val[3] >> 8), (short)(val[1] * val[3] >> 8), (short)(val[2] * val[3] >> 8)); + endPoints[1] = new AstcPixel(0xFF, (short)val[0], (short)val[1], (short)val[2]); + + break; + } + + case 8: + { + uint[] val = ReadUintColorValues(6, colorValues, ref colorValuesPosition); + + if (val[1] + val[3] + val[5] >= val[0] + val[2] + val[4]) + { + endPoints[0] = new AstcPixel(0xFF, (short)val[0], (short)val[2], (short)val[4]); + endPoints[1] = new AstcPixel(0xFF, (short)val[1], (short)val[3], (short)val[5]); + } + else + { + endPoints[0] = AstcPixel.BlueContract(0xFF, (short)val[1], (short)val[3], (short)val[5]); + endPoints[1] = AstcPixel.BlueContract(0xFF, (short)val[0], (short)val[2], (short)val[4]); + } + + break; + } + + case 9: + { + int[] val = ReadIntColorValues(6, colorValues, ref colorValuesPosition); + + BitArrayStream.BitTransferSigned(ref val[1], ref val[0]); + BitArrayStream.BitTransferSigned(ref val[3], ref val[2]); + BitArrayStream.BitTransferSigned(ref val[5], ref val[4]); + + if (val[1] + val[3] + val[5] >= 0) + { + endPoints[0] = new AstcPixel(0xFF, (short)val[0], (short)val[2], (short)val[4]); + endPoints[1] = new AstcPixel(0xFF, (short)(val[0] + val[1]), (short)(val[2] + val[3]), (short)(val[4] + val[5])); + } + else + { + endPoints[0] = AstcPixel.BlueContract(0xFF, val[0] + val[1], val[2] + val[3], val[4] + val[5]); + endPoints[1] = AstcPixel.BlueContract(0xFF, val[0], val[2], val[4]); + } + + endPoints[0].ClampByte(); + endPoints[1].ClampByte(); + + break; + } + + case 10: + { + uint[] val = ReadUintColorValues(6, colorValues, ref colorValuesPosition); + + endPoints[0] = new AstcPixel((short)val[4], (short)(val[0] * val[3] >> 8), (short)(val[1] * val[3] >> 8), (short)(val[2] * val[3] >> 8)); + endPoints[1] = new AstcPixel((short)val[5], (short)val[0], (short)val[1], (short)val[2]); + + break; + } + + case 12: + { + uint[] val = ReadUintColorValues(8, colorValues, ref colorValuesPosition); + + if (val[1] + val[3] + val[5] >= val[0] + val[2] + val[4]) + { + endPoints[0] = new AstcPixel((short)val[6], (short)val[0], (short)val[2], (short)val[4]); + endPoints[1] = new AstcPixel((short)val[7], (short)val[1], (short)val[3], (short)val[5]); + } + else + { + endPoints[0] = AstcPixel.BlueContract((short)val[7], (short)val[1], (short)val[3], (short)val[5]); + endPoints[1] = AstcPixel.BlueContract((short)val[6], (short)val[0], (short)val[2], (short)val[4]); + } + + break; + } + + case 13: + { + int[] val = ReadIntColorValues(8, colorValues, ref colorValuesPosition); + + BitArrayStream.BitTransferSigned(ref val[1], ref val[0]); + BitArrayStream.BitTransferSigned(ref val[3], ref val[2]); + BitArrayStream.BitTransferSigned(ref val[5], ref val[4]); + BitArrayStream.BitTransferSigned(ref val[7], ref val[6]); + + if (val[1] + val[3] + val[5] >= 0) + { + endPoints[0] = new AstcPixel((short)val[6], (short)val[0], (short)val[2], (short)val[4]); + endPoints[1] = new AstcPixel((short)(val[7] + val[6]), (short)(val[0] + val[1]), (short)(val[2] + val[3]), (short)(val[4] + val[5])); + } + else + { + endPoints[0] = AstcPixel.BlueContract(val[6] + val[7], val[0] + val[1], val[2] + val[3], val[4] + val[5]); + endPoints[1] = AstcPixel.BlueContract(val[6], val[0], val[2], val[4]); + } + + endPoints[0].ClampByte(); + endPoints[1].ClampByte(); + + break; + } + + default: + throw new AstcDecoderException("Unsupported color endpoint mode (is it HDR?)"); + } + } + + static void DecodeColorValues( + int[] outputValues, + byte[] inputData, + uint[] modes, + int numberPartitions, + int numberBitsForColorData) + { + // First figure out how many color values we have + int numberValues = 0; + + for (int i = 0; i < numberPartitions; i++) + { + numberValues += (int)((modes[i] >> 2) + 1) << 1; + } + + // Then based on the number of values and the remaining number of bits, + // figure out the max value for each of them... + int range = 256; + + while (--range > 0) + { + IntegerEncoded intEncoded = IntegerEncoded.CreateEncoding(range); + int bitLength = intEncoded.GetBitLength(numberValues); + + if (bitLength <= numberBitsForColorData) + { + // Find the smallest possible range that matches the given encoding + while (--range > 0) + { + IntegerEncoded newIntEncoded = IntegerEncoded.CreateEncoding(range); + if (!newIntEncoded.MatchesEncoding(intEncoded)) + { + break; + } + } + + // Return to last matching range. + range++; + break; + } + } + + // We now have enough to decode our integer sequence. + List integerEncodedSequence = new List(); + BitArrayStream colorBitStream = new BitArrayStream(new BitArray(inputData)); + + IntegerEncoded.DecodeIntegerSequence(integerEncodedSequence, colorBitStream, range, numberValues); + + // Once we have the decoded values, we need to dequantize them to the 0-255 range + // This procedure is outlined in ASTC spec C.2.13 + int outputIndices = 0; + + foreach (IntegerEncoded intEncoded in integerEncodedSequence) + { + int bitLength = intEncoded.NumberBits; + int bitValue = intEncoded.BitValue; + + Debug.Assert(bitLength >= 1); + + int a = 0, b = 0, c = 0, d = 0; + // A is just the lsb replicated 9 times. + a = BitArrayStream.Replicate(bitValue & 1, 1, 9); + + switch (intEncoded.GetEncoding()) + { + case IntegerEncoded.EIntegerEncoding.JustBits: + { + outputValues[outputIndices++] = BitArrayStream.Replicate(bitValue, bitLength, 8); + + break; + } + + case IntegerEncoded.EIntegerEncoding.Trit: + { + d = intEncoded.TritValue; + + switch (bitLength) + { + case 1: + { + c = 204; + + break; + } + + case 2: + { + c = 93; + // B = b000b0bb0 + int b2 = (bitValue >> 1) & 1; + b = (b2 << 8) | (b2 << 4) | (b2 << 2) | (b2 << 1); + + break; + } + + case 3: + { + c = 44; + // B = cb000cbcb + int cb = (bitValue >> 1) & 3; + b = (cb << 7) | (cb << 2) | cb; + + break; + } + + + case 4: + { + c = 22; + // B = dcb000dcb + int dcb = (bitValue >> 1) & 7; + b = (dcb << 6) | dcb; + + break; + } + + case 5: + { + c = 11; + // B = edcb000ed + int edcb = (bitValue >> 1) & 0xF; + b = (edcb << 5) | (edcb >> 2); + + break; + } + + case 6: + { + c = 5; + // B = fedcb000f + int fedcb = (bitValue >> 1) & 0x1F; + b = (fedcb << 4) | (fedcb >> 4); + + break; + } + + default: + throw new AstcDecoderException("Unsupported trit encoding for color values!"); + } + + break; + } + + case IntegerEncoded.EIntegerEncoding.Quint: + { + d = intEncoded.QuintValue; + + switch (bitLength) + { + case 1: + { + c = 113; + + break; + } + + case 2: + { + c = 54; + // B = b0000bb00 + int b2 = (bitValue >> 1) & 1; + b = (b2 << 8) | (b2 << 3) | (b2 << 2); + + break; + } + + case 3: + { + c = 26; + // B = cb0000cbc + int cb = (bitValue >> 1) & 3; + b = (cb << 7) | (cb << 1) | (cb >> 1); + + break; + } + + case 4: + { + c = 13; + // B = dcb0000dc + int dcb = (bitValue >> 1) & 7; + b = (dcb << 6) | (dcb >> 1); + + break; + } + + case 5: + { + c = 6; + // B = edcb0000e + int edcb = (bitValue >> 1) & 0xF; + b = (edcb << 5) | (edcb >> 3); + + break; + } + + default: + throw new AstcDecoderException("Unsupported quint encoding for color values!"); + } + break; + } + } + + if (intEncoded.GetEncoding() != IntegerEncoded.EIntegerEncoding.JustBits) + { + int T = d * c + b; + T ^= a; + T = (a & 0x80) | (T >> 2); + + outputValues[outputIndices++] = T; + } + } + + // Make sure that each of our values is in the proper range... + for (int i = 0; i < numberValues; i++) + { + Debug.Assert(outputValues[i] <= 255); + } + } + + static void FillVoidExtentLdr(BitArrayStream bitStream, int[] outputBuffer, int blockWidth, int blockHeight) + { + // Don't actually care about the void extent, just read the bits... + for (int i = 0; i < 4; ++i) + { + bitStream.ReadBits(13); + } + + // Decode the RGBA components and renormalize them to the range [0, 255] + ushort r = (ushort)bitStream.ReadBits(16); + ushort g = (ushort)bitStream.ReadBits(16); + ushort b = (ushort)bitStream.ReadBits(16); + ushort a = (ushort)bitStream.ReadBits(16); + + int rgba = (r >> 8) | (g & 0xFF00) | ((b) & 0xFF00) << 8 | ((a) & 0xFF00) << 16; + + for (int j = 0; j < blockHeight; j++) + { + for (int i = 0; i < blockWidth; i++) + { + outputBuffer[j * blockWidth + i] = rgba; + } + } + } + + static TexelWeightParams DecodeBlockInfo(BitArrayStream bitStream) + { + TexelWeightParams texelParams = new TexelWeightParams(); + + // Read the entire block mode all at once + ushort modeBits = (ushort)bitStream.ReadBits(11); + + // Does this match the void extent block mode? + if ((modeBits & 0x01FF) == 0x1FC) + { + if ((modeBits & 0x200) != 0) + { + texelParams.VoidExtentHdr = true; + } + else + { + texelParams.VoidExtentLdr = true; + } + + // Next two bits must be one. + if ((modeBits & 0x400) == 0 || bitStream.ReadBits(1) == 0) + { + texelParams.Error = true; + } + + return texelParams; + } + + // First check if the last four bits are zero + if ((modeBits & 0xF) == 0) + { + texelParams.Error = true; + return texelParams; + } + + // If the last two bits are zero, then if bits + // [6-8] are all ones, this is also reserved. + if ((modeBits & 0x3) == 0 && (modeBits & 0x1C0) == 0x1C0) + { + texelParams.Error = true; + + return texelParams; + } + + // Otherwise, there is no error... Figure out the layout + // of the block mode. Layout is determined by a number + // between 0 and 9 corresponding to table C.2.8 of the + // ASTC spec. + int layout = 0; + + if ((modeBits & 0x1) != 0 || (modeBits & 0x2) != 0) + { + // layout is in [0-4] + if ((modeBits & 0x8) != 0) + { + // layout is in [2-4] + if ((modeBits & 0x4) != 0) + { + // layout is in [3-4] + if ((modeBits & 0x100) != 0) + { + layout = 4; + } + else + { + layout = 3; + } + } + else + { + layout = 2; + } + } + else + { + // layout is in [0-1] + if ((modeBits & 0x4) != 0) + { + layout = 1; + } + else + { + layout = 0; + } + } + } + else + { + // layout is in [5-9] + if ((modeBits & 0x100) != 0) + { + // layout is in [7-9] + if ((modeBits & 0x80) != 0) + { + // layout is in [7-8] + Debug.Assert((modeBits & 0x40) == 0); + + if ((modeBits & 0x20) != 0) + { + layout = 8; + } + else + { + layout = 7; + } + } + else + { + layout = 9; + } + } + else + { + // layout is in [5-6] + if ((modeBits & 0x80) != 0) + { + layout = 6; + } + else + { + layout = 5; + } + } + } + + Debug.Assert(layout < 10); + + // Determine R + int r = (modeBits >> 4) & 1; + if (layout < 5) + { + r |= (modeBits & 0x3) << 1; + } + else + { + r |= (modeBits & 0xC) >> 1; + } + + Debug.Assert(2 <= r && r <= 7); + + // Determine width & height + switch (layout) + { + case 0: + { + int a = (modeBits >> 5) & 0x3; + int b = (modeBits >> 7) & 0x3; + + texelParams.Width = b + 4; + texelParams.Height = a + 2; + + break; + } + + case 1: + { + int a = (modeBits >> 5) & 0x3; + int b = (modeBits >> 7) & 0x3; + + texelParams.Width = b + 8; + texelParams.Height = a + 2; + + break; + } + + case 2: + { + int a = (modeBits >> 5) & 0x3; + int b = (modeBits >> 7) & 0x3; + + texelParams.Width = a + 2; + texelParams.Height = b + 8; + + break; + } + + case 3: + { + int a = (modeBits >> 5) & 0x3; + int b = (modeBits >> 7) & 0x1; + + texelParams.Width = a + 2; + texelParams.Height = b + 6; + + break; + } + + case 4: + { + int a = (modeBits >> 5) & 0x3; + int b = (modeBits >> 7) & 0x1; + + texelParams.Width = b + 2; + texelParams.Height = a + 2; + + break; + } + + case 5: + { + int a = (modeBits >> 5) & 0x3; + + texelParams.Width = 12; + texelParams.Height = a + 2; + + break; + } + + case 6: + { + int a = (modeBits >> 5) & 0x3; + + texelParams.Width = a + 2; + texelParams.Height = 12; + + break; + } + + case 7: + { + texelParams.Width = 6; + texelParams.Height = 10; + + break; + } + + case 8: + { + texelParams.Width = 10; + texelParams.Height = 6; + break; + } + + case 9: + { + int a = (modeBits >> 5) & 0x3; + int b = (modeBits >> 9) & 0x3; + + texelParams.Width = a + 6; + texelParams.Height = b + 6; + + break; + } + + default: + //Don't know this layout... + texelParams.Error = true; + break; + } + + // Determine whether or not we're using dual planes + // and/or high precision layouts. + bool d = ((layout != 9) && ((modeBits & 0x400) != 0)); + bool h = (layout != 9) && ((modeBits & 0x200) != 0); + + if (h) + { + int[] maxWeights = { 9, 11, 15, 19, 23, 31 }; + texelParams.MaxWeight = maxWeights[r - 2]; + } + else + { + int[] maxWeights = { 1, 2, 3, 4, 5, 7 }; + texelParams.MaxWeight = maxWeights[r - 2]; + } + + texelParams.DualPlane = d; + + return texelParams; + } + } +} diff --git a/Ryujinx.Graphics/Graphics3d/Texture/AstcPixel.cs b/Ryujinx.Graphics/Graphics3d/Texture/AstcPixel.cs new file mode 100644 index 0000000000..cd30accab3 --- /dev/null +++ b/Ryujinx.Graphics/Graphics3d/Texture/AstcPixel.cs @@ -0,0 +1,138 @@ +using System; +using System.Diagnostics; + +namespace Ryujinx.Graphics.Texture +{ + class AstcPixel + { + public short R { get; set; } + public short G { get; set; } + public short B { get; set; } + public short A { get; set; } + + byte[] _bitDepth = new byte[4]; + + public AstcPixel(short a, short r, short g, short b) + { + A = a; + R = r; + G = g; + B = b; + + for (int i = 0; i < 4; i++) + _bitDepth[i] = 8; + } + + public void ClampByte() + { + R = Math.Min(Math.Max(R, (short)0), (short)255); + G = Math.Min(Math.Max(G, (short)0), (short)255); + B = Math.Min(Math.Max(B, (short)0), (short)255); + A = Math.Min(Math.Max(A, (short)0), (short)255); + } + + public short GetComponent(int index) + { + switch(index) + { + case 0: return A; + case 1: return R; + case 2: return G; + case 3: return B; + } + + return 0; + } + + public void SetComponent(int index, int value) + { + switch (index) + { + case 0: + A = (short)value; + break; + case 1: + R = (short)value; + break; + case 2: + G = (short)value; + break; + case 3: + B = (short)value; + break; + } + } + + public void ChangeBitDepth(byte[] depth) + { + for(int i = 0; i< 4; i++) + { + int value = ChangeBitDepth(GetComponent(i), _bitDepth[i], depth[i]); + + SetComponent(i, value); + _bitDepth[i] = depth[i]; + } + } + + short ChangeBitDepth(short value, byte oldDepth, byte newDepth) + { + Debug.Assert(newDepth <= 8); + Debug.Assert(oldDepth <= 8); + + if (oldDepth == newDepth) + { + // Do nothing + return value; + } + else if (oldDepth == 0 && newDepth != 0) + { + return (short)((1 << newDepth) - 1); + } + else if (newDepth > oldDepth) + { + return (short)BitArrayStream.Replicate(value, oldDepth, newDepth); + } + else + { + // oldDepth > newDepth + if (newDepth == 0) + { + return 0xFF; + } + else + { + byte bitsWasted = (byte)(oldDepth - newDepth); + short tempValue = value; + + tempValue = (short)((tempValue + (1 << (bitsWasted - 1))) >> bitsWasted); + tempValue = Math.Min(Math.Max((short)0, tempValue), (short)((1 << newDepth) - 1)); + + return (byte)(tempValue); + } + } + } + + public int Pack() + { + AstcPixel newPixel = new AstcPixel(A, R, G, B); + byte[] eightBitDepth = { 8, 8, 8, 8 }; + + newPixel.ChangeBitDepth(eightBitDepth); + + return (byte)newPixel.A << 24 | + (byte)newPixel.B << 16 | + (byte)newPixel.G << 8 | + (byte)newPixel.R << 0; + } + + // Adds more precision to the blue channel as described + // in C.2.14 + public static AstcPixel BlueContract(int a, int r, int g, int b) + { + return new AstcPixel((short)(a), + (short)((r + b) >> 1), + (short)((g + b) >> 1), + (short)(b)); + } + } +} diff --git a/Ryujinx.Graphics/Graphics3d/Texture/BitArrayStream.cs b/Ryujinx.Graphics/Graphics3d/Texture/BitArrayStream.cs index 2a8ed09105..24069d722b 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/BitArrayStream.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/BitArrayStream.cs @@ -9,103 +9,103 @@ namespace Ryujinx.Graphics.Texture public int Position { get; private set; } - public BitArrayStream(BitArray BitArray) + public BitArrayStream(BitArray bitArray) { - BitsArray = BitArray; + BitsArray = bitArray; Position = 0; } - public short ReadBits(int Length) + public short ReadBits(int length) { - int RetValue = 0; - for (int i = Position; i < Position + Length; i++) + int retValue = 0; + for (int i = Position; i < Position + length; i++) { if (BitsArray[i]) { - RetValue |= 1 << (i - Position); + retValue |= 1 << (i - Position); } } - Position += Length; - return (short)RetValue; + Position += length; + return (short)retValue; } - public int ReadBits(int Start, int End) + public int ReadBits(int start, int end) { - int RetValue = 0; - for (int i = Start; i <= End; i++) + int retValue = 0; + for (int i = start; i <= end; i++) { if (BitsArray[i]) { - RetValue |= 1 << (i - Start); + retValue |= 1 << (i - start); } } - return RetValue; + return retValue; } - public int ReadBit(int Index) + public int ReadBit(int index) { - return Convert.ToInt32(BitsArray[Index]); + return Convert.ToInt32(BitsArray[index]); } - public void WriteBits(int Value, int Length) + public void WriteBits(int value, int length) { - for (int i = Position; i < Position + Length; i++) + for (int i = Position; i < Position + length; i++) { - BitsArray[i] = ((Value >> (i - Position)) & 1) != 0; + BitsArray[i] = ((value >> (i - Position)) & 1) != 0; } - Position += Length; + Position += length; } public byte[] ToByteArray() { - byte[] RetArray = new byte[(BitsArray.Length + 7) / 8]; - BitsArray.CopyTo(RetArray, 0); - return RetArray; + byte[] retArray = new byte[(BitsArray.Length + 7) / 8]; + BitsArray.CopyTo(retArray, 0); + return retArray; } - public static int Replicate(int Value, int NumberBits, int ToBit) + public static int Replicate(int value, int numberBits, int toBit) { - if (NumberBits == 0) return 0; - if (ToBit == 0) return 0; + if (numberBits == 0) return 0; + if (toBit == 0) return 0; - int TempValue = Value & ((1 << NumberBits) - 1); - int RetValue = TempValue; - int ResLength = NumberBits; + int tempValue = value & ((1 << numberBits) - 1); + int retValue = tempValue; + int resLength = numberBits; - while (ResLength < ToBit) + while (resLength < toBit) { - int Comp = 0; - if (NumberBits > ToBit - ResLength) + int comp = 0; + if (numberBits > toBit - resLength) { - int NewShift = ToBit - ResLength; - Comp = NumberBits - NewShift; - NumberBits = NewShift; + int newShift = toBit - resLength; + comp = numberBits - newShift; + numberBits = newShift; } - RetValue <<= NumberBits; - RetValue |= TempValue >> Comp; - ResLength += NumberBits; + retValue <<= numberBits; + retValue |= tempValue >> comp; + resLength += numberBits; } - return RetValue; + return retValue; } - public static int PopCnt(int Number) + public static int PopCnt(int number) { - int Counter; - for (Counter = 0; Number != 0; Counter++) + int counter; + for (counter = 0; number != 0; counter++) { - Number &= Number - 1; + number &= number - 1; } - return Counter; + return counter; } public static void Swap(ref T lhs, ref T rhs) { - T Temp = lhs; + T temp = lhs; lhs = rhs; - rhs = Temp; + rhs = temp; } // Transfers a bit as described in C.2.14 diff --git a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs index 1be0644283..682f7d671d 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs @@ -10,98 +10,98 @@ namespace Ryujinx.Graphics.Texture private const int GobSize = GobWidth * GobHeight; - private int TexWidth; - private int TexHeight; - private int TexDepth; - private int TexGobBlockHeight; - private int TexGobBlockDepth; - private int TexBpp; + private int _texWidth; + private int _texHeight; + private int _texDepth; + private int _texGobBlockHeight; + private int _texGobBlockDepth; + private int _texBpp; - private int BhMask; - private int BdMask; + private int _bhMask; + private int _bdMask; - private int BhShift; - private int BdShift; - private int BppShift; + private int _bhShift; + private int _bdShift; + private int _bppShift; - private int XShift; + private int _xShift; - private int RobSize; - private int SliceSize; + private int _robSize; + private int _sliceSize; - private int BaseOffset; + private int _baseOffset; public BlockLinearSwizzle( - int Width, - int Height, - int Depth, - int GobBlockHeight, - int GobBlockDepth, - int Bpp) + int width, + int height, + int depth, + int gobBlockHeight, + int gobBlockDepth, + int bpp) { - TexWidth = Width; - TexHeight = Height; - TexDepth = Depth; - TexGobBlockHeight = GobBlockHeight; - TexGobBlockDepth = GobBlockDepth; - TexBpp = Bpp; + _texWidth = width; + _texHeight = height; + _texDepth = depth; + _texGobBlockHeight = gobBlockHeight; + _texGobBlockDepth = gobBlockDepth; + _texBpp = bpp; - BppShift = BitUtils.CountTrailingZeros32(Bpp); + _bppShift = BitUtils.CountTrailingZeros32(bpp); SetMipLevel(0); } - public void SetMipLevel(int Level) + public void SetMipLevel(int level) { - BaseOffset = GetMipOffset(Level); + _baseOffset = GetMipOffset(level); - int Width = Math.Max(1, TexWidth >> Level); - int Height = Math.Max(1, TexHeight >> Level); - int Depth = Math.Max(1, TexDepth >> Level); + int width = Math.Max(1, _texWidth >> level); + int height = Math.Max(1, _texHeight >> level); + int depth = Math.Max(1, _texDepth >> level); - GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth); + GobBlockSizes gbSizes = AdjustGobBlockSizes(height, depth); - BhMask = GbSizes.Height - 1; - BdMask = GbSizes.Depth - 1; + _bhMask = gbSizes.Height - 1; + _bdMask = gbSizes.Depth - 1; - BhShift = BitUtils.CountTrailingZeros32(GbSizes.Height); - BdShift = BitUtils.CountTrailingZeros32(GbSizes.Depth); + _bhShift = BitUtils.CountTrailingZeros32(gbSizes.Height); + _bdShift = BitUtils.CountTrailingZeros32(gbSizes.Depth); - XShift = BitUtils.CountTrailingZeros32(GobSize * GbSizes.Height * GbSizes.Depth); + _xShift = BitUtils.CountTrailingZeros32(GobSize * gbSizes.Height * gbSizes.Depth); - RobAndSliceSizes GsSizes = GetRobAndSliceSizes(Width, Height, GbSizes); + RobAndSliceSizes gsSizes = GetRobAndSliceSizes(width, height, gbSizes); - RobSize = GsSizes.RobSize; - SliceSize = GsSizes.SliceSize; + _robSize = gsSizes.RobSize; + _sliceSize = gsSizes.SliceSize; } - public int GetImageSize(int MipsCount) + public int GetImageSize(int mipsCount) { - int Size = GetMipOffset(MipsCount); + int size = GetMipOffset(mipsCount); - Size = (Size + 0x1fff) & ~0x1fff; + size = (size + 0x1fff) & ~0x1fff; - return Size; + return size; } - public int GetMipOffset(int Level) + public int GetMipOffset(int level) { - int TotalSize = 0; + int totalSize = 0; - for (int Index = 0; Index < Level; Index++) + for (int index = 0; index < level; index++) { - int Width = Math.Max(1, TexWidth >> Index); - int Height = Math.Max(1, TexHeight >> Index); - int Depth = Math.Max(1, TexDepth >> Index); + int width = Math.Max(1, _texWidth >> index); + int height = Math.Max(1, _texHeight >> index); + int depth = Math.Max(1, _texDepth >> index); - GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth); + GobBlockSizes gbSizes = AdjustGobBlockSizes(height, depth); - RobAndSliceSizes RsSizes = GetRobAndSliceSizes(Width, Height, GbSizes); + RobAndSliceSizes rsSizes = GetRobAndSliceSizes(width, height, gbSizes); - TotalSize += BitUtils.DivRoundUp(Depth, GbSizes.Depth) * RsSizes.SliceSize; + totalSize += BitUtils.DivRoundUp(depth, gbSizes.Depth) * rsSizes.SliceSize; } - return TotalSize; + return totalSize; } private struct GobBlockSizes @@ -109,32 +109,32 @@ namespace Ryujinx.Graphics.Texture public int Height; public int Depth; - public GobBlockSizes(int GobBlockHeight, int GobBlockDepth) + public GobBlockSizes(int gobBlockHeight, int gobBlockDepth) { - this.Height = GobBlockHeight; - this.Depth = GobBlockDepth; + Height = gobBlockHeight; + Depth = gobBlockDepth; } } - private GobBlockSizes AdjustGobBlockSizes(int Height, int Depth) + private GobBlockSizes AdjustGobBlockSizes(int height, int depth) { - int GobBlockHeight = TexGobBlockHeight; - int GobBlockDepth = TexGobBlockDepth; + int gobBlockHeight = _texGobBlockHeight; + int gobBlockDepth = _texGobBlockDepth; - int Pow2Height = BitUtils.Pow2RoundUp(Height); - int Pow2Depth = BitUtils.Pow2RoundUp(Depth); + int pow2Height = BitUtils.Pow2RoundUp(height); + int pow2Depth = BitUtils.Pow2RoundUp(depth); - while (GobBlockHeight * GobHeight > Pow2Height && GobBlockHeight > 1) + while (gobBlockHeight * GobHeight > pow2Height && gobBlockHeight > 1) { - GobBlockHeight >>= 1; + gobBlockHeight >>= 1; } - while (GobBlockDepth > Pow2Depth && GobBlockDepth > 1) + while (gobBlockDepth > pow2Depth && gobBlockDepth > 1) { - GobBlockDepth >>= 1; + gobBlockDepth >>= 1; } - return new GobBlockSizes(GobBlockHeight, GobBlockDepth); + return new GobBlockSizes(gobBlockHeight, gobBlockDepth); } private struct RobAndSliceSizes @@ -142,45 +142,45 @@ namespace Ryujinx.Graphics.Texture public int RobSize; public int SliceSize; - public RobAndSliceSizes(int RobSize, int SliceSize) + public RobAndSliceSizes(int robSize, int sliceSize) { - this.RobSize = RobSize; - this.SliceSize = SliceSize; + RobSize = robSize; + SliceSize = sliceSize; } } - private RobAndSliceSizes GetRobAndSliceSizes(int Width, int Height, GobBlockSizes GbSizes) + private RobAndSliceSizes GetRobAndSliceSizes(int width, int height, GobBlockSizes gbSizes) { - int WidthInGobs = BitUtils.DivRoundUp(Width * TexBpp, GobWidth); + int widthInGobs = BitUtils.DivRoundUp(width * _texBpp, GobWidth); - int RobSize = GobSize * GbSizes.Height * GbSizes.Depth * WidthInGobs; + int robSize = GobSize * gbSizes.Height * gbSizes.Depth * widthInGobs; - int SliceSize = BitUtils.DivRoundUp(Height, GbSizes.Height * GobHeight) * RobSize; + int sliceSize = BitUtils.DivRoundUp(height, gbSizes.Height * GobHeight) * robSize; - return new RobAndSliceSizes(RobSize, SliceSize); + return new RobAndSliceSizes(robSize, sliceSize); } - public int GetSwizzleOffset(int X, int Y, int Z) + public int GetSwizzleOffset(int x, int y, int z) { - X <<= BppShift; + x <<= _bppShift; - int YH = Y / GobHeight; + int yh = y / GobHeight; - int Position = (Z >> BdShift) * SliceSize + (YH >> BhShift) * RobSize; + int position = (z >> _bdShift) * _sliceSize + (yh >> _bhShift) * _robSize; - Position += (X / GobWidth) << XShift; + position += (x / GobWidth) << _xShift; - Position += (YH & BhMask) * GobSize; + position += (yh & _bhMask) * GobSize; - Position += ((Z & BdMask) * GobSize) << BhShift; + position += ((z & _bdMask) * GobSize) << _bhShift; - Position += ((X & 0x3f) >> 5) << 8; - Position += ((Y & 0x07) >> 1) << 6; - Position += ((X & 0x1f) >> 4) << 5; - Position += ((Y & 0x01) >> 0) << 4; - Position += ((X & 0x0f) >> 0) << 0; + position += ((x & 0x3f) >> 5) << 8; + position += ((y & 0x07) >> 1) << 6; + position += ((x & 0x1f) >> 4) << 5; + position += ((y & 0x01) >> 0) << 4; + position += ((x & 0x0f) >> 0) << 0; - return BaseOffset + Position; + return _baseOffset + position; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs index 2e0e8aedd4..fae3eada87 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs @@ -2,12 +2,12 @@ namespace Ryujinx.Graphics.Texture { interface ISwizzle { - int GetSwizzleOffset(int X, int Y, int Z); + int GetSwizzleOffset(int x, int y, int z); - void SetMipLevel(int Level); + void SetMipLevel(int level); - int GetMipOffset(int Level); + int GetMipOffset(int level); - int GetImageSize(int MipsCount); + int GetImageSize(int mipsCount); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs index c4208935c3..bd9b4327c3 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs @@ -1,6 +1,5 @@ using ChocolArm64.Memory; using OpenTK.Graphics.OpenGL; -using Ryujinx.Common; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using System; @@ -29,13 +28,13 @@ namespace Ryujinx.Graphics.Texture public TargetBuffer Target { get; private set; } - public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, int BlockDepth, TargetBuffer Target) + public ImageDescriptor(int bytesPerPixel, int blockWidth, int blockHeight, int blockDepth, TargetBuffer target) { - this.BytesPerPixel = BytesPerPixel; - this.BlockWidth = BlockWidth; - this.BlockHeight = BlockHeight; - this.BlockDepth = BlockDepth; - this.Target = Target; + BytesPerPixel = bytesPerPixel; + BlockWidth = blockWidth; + BlockHeight = blockHeight; + BlockDepth = blockDepth; + Target = target; } } @@ -46,26 +45,26 @@ namespace Ryujinx.Graphics.Texture private const GalImageFormat Float = GalImageFormat.Float; private const GalImageFormat Srgb = GalImageFormat.Srgb; - private static readonly Dictionary s_TextureTable = + private static readonly Dictionary TextureTable = new Dictionary() { - { GalTextureFormat.RGBA32, GalImageFormat.RGBA32 | Sint | Uint | Float }, - { GalTextureFormat.RGBA16, GalImageFormat.RGBA16 | Snorm | Unorm | Sint | Uint | Float }, - { GalTextureFormat.RG32, GalImageFormat.RG32 | Sint | Uint | Float }, - { GalTextureFormat.RGBA8, GalImageFormat.RGBA8 | Snorm | Unorm | Sint | Uint | Srgb }, - { GalTextureFormat.RGB10A2, GalImageFormat.RGB10A2 | Snorm | Unorm | Sint | Uint }, - { GalTextureFormat.RG8, GalImageFormat.RG8 | Snorm | Unorm | Sint | Uint }, + { GalTextureFormat.Rgba32, GalImageFormat.Rgba32 | Sint | Uint | Float }, + { GalTextureFormat.Rgba16, GalImageFormat.Rgba16 | Snorm | Unorm | Sint | Uint | Float }, + { GalTextureFormat.Rg32, GalImageFormat.Rg32 | Sint | Uint | Float }, + { GalTextureFormat.Rgba8, GalImageFormat.Rgba8 | Snorm | Unorm | Sint | Uint | Srgb }, + { GalTextureFormat.Rgb10A2, GalImageFormat.Rgb10A2 | Snorm | Unorm | Sint | Uint }, + { GalTextureFormat.Rg8, GalImageFormat.Rg8 | Snorm | Unorm | Sint | Uint }, { GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Float }, { GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint }, - { GalTextureFormat.RG16, GalImageFormat.RG16 | Snorm | Unorm | Sint | Float }, + { GalTextureFormat.Rg16, GalImageFormat.Rg16 | Snorm | Unorm | Sint | Float }, { GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Float }, - { GalTextureFormat.RGBA4, GalImageFormat.RGBA4 | Unorm }, - { GalTextureFormat.RGB5A1, GalImageFormat.RGB5A1 | Unorm }, - { GalTextureFormat.RGB565, GalImageFormat.RGB565 | Unorm }, + { GalTextureFormat.Rgba4, GalImageFormat.Rgba4 | Unorm }, + { GalTextureFormat.Rgb5A1, GalImageFormat.Rgb5A1 | Unorm }, + { GalTextureFormat.Rgb565, GalImageFormat.Rgb565 | Unorm }, { GalTextureFormat.R11G11B10F, GalImageFormat.R11G11B10 | Float }, { GalTextureFormat.D24S8, GalImageFormat.D24S8 | Unorm | Uint }, { GalTextureFormat.D32F, GalImageFormat.D32 | Float }, - { GalTextureFormat.D32FX24S8, GalImageFormat.D32S8 | Float }, + { GalTextureFormat.D32Fx24S8, GalImageFormat.D32S8 | Float }, { GalTextureFormat.D16, GalImageFormat.D16 | Unorm }, //Compressed formats @@ -93,27 +92,27 @@ namespace Ryujinx.Graphics.Texture { GalTextureFormat.Astc2D10x6, GalImageFormat.Astc2D10x6 | Unorm | Srgb } }; - private static readonly Dictionary s_ImageTable = + private static readonly Dictionary ImageTable = new Dictionary() { - { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rgba32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rgba16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rg32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rgbx8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rgba8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Bgra8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rgb10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rgba4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, - { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Bgr5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rgb5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rgb565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Bgr565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) }, - { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, - { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rg16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, + { GalImageFormat.Rg8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) }, { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, 1, TargetBuffer.Color) }, { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) }, @@ -145,77 +144,77 @@ namespace Ryujinx.Graphics.Texture }; public static GalImageFormat ConvertTexture( - GalTextureFormat Format, - GalTextureType RType, - GalTextureType GType, - GalTextureType BType, - GalTextureType AType, - bool ConvSrgb) + GalTextureFormat format, + GalTextureType rType, + GalTextureType gType, + GalTextureType bType, + GalTextureType aType, + bool convSrgb) { - if (!s_TextureTable.TryGetValue(Format, out GalImageFormat ImageFormat)) + if (!TextureTable.TryGetValue(format, out GalImageFormat imageFormat)) { - throw new NotImplementedException($"Format 0x{((int)Format):x} not implemented!"); + throw new NotImplementedException($"Format 0x{((int)format):x} not implemented!"); } - if (!HasDepth(ImageFormat) && (RType != GType || RType != BType || RType != AType)) + if (!HasDepth(imageFormat) && (rType != gType || rType != bType || rType != aType)) { - throw new NotImplementedException($"Per component types are not implemented!"); + throw new NotImplementedException("Per component types are not implemented!"); } - GalImageFormat FormatType = ConvSrgb ? Srgb : GetFormatType(RType); + GalImageFormat formatType = convSrgb ? Srgb : GetFormatType(rType); - GalImageFormat CombinedFormat = (ImageFormat & GalImageFormat.FormatMask) | FormatType; + GalImageFormat combinedFormat = (imageFormat & GalImageFormat.FormatMask) | formatType; - if (!ImageFormat.HasFlag(FormatType)) + if (!imageFormat.HasFlag(formatType)) { - throw new NotImplementedException($"Format \"{CombinedFormat}\" not implemented!"); + throw new NotImplementedException($"Format \"{combinedFormat}\" not implemented!"); } - return CombinedFormat; + return combinedFormat; } - public static GalImageFormat ConvertSurface(GalSurfaceFormat Format) + public static GalImageFormat ConvertSurface(GalSurfaceFormat format) { - switch (Format) + switch (format) { - case GalSurfaceFormat.RGBA32Float: return GalImageFormat.RGBA32 | Float; - case GalSurfaceFormat.RGBA32Uint: return GalImageFormat.RGBA32 | Uint; - case GalSurfaceFormat.RGBA16Float: return GalImageFormat.RGBA16 | Float; - case GalSurfaceFormat.RGBA16Unorm: return GalImageFormat.RGBA16 | Unorm; - case GalSurfaceFormat.RG32Float: return GalImageFormat.RG32 | Float; - case GalSurfaceFormat.RG32Sint: return GalImageFormat.RG32 | Sint; - case GalSurfaceFormat.RG32Uint: return GalImageFormat.RG32 | Uint; - case GalSurfaceFormat.BGRA8Unorm: return GalImageFormat.BGRA8 | Unorm; - case GalSurfaceFormat.BGRA8Srgb: return GalImageFormat.BGRA8 | Srgb; - case GalSurfaceFormat.RGB10A2Unorm: return GalImageFormat.RGB10A2 | Unorm; - case GalSurfaceFormat.RGBA8Unorm: return GalImageFormat.RGBA8 | Unorm; - case GalSurfaceFormat.RGBA8Srgb: return GalImageFormat.RGBA8 | Srgb; - case GalSurfaceFormat.RGBA8Snorm: return GalImageFormat.RGBA8 | Snorm; - case GalSurfaceFormat.RG16Snorm: return GalImageFormat.RG16 | Snorm; - case GalSurfaceFormat.RG16Unorm: return GalImageFormat.RG16 | Unorm; - case GalSurfaceFormat.RG16Sint: return GalImageFormat.RG16 | Sint; - case GalSurfaceFormat.RG16Float: return GalImageFormat.RG16 | Float; + case GalSurfaceFormat.Rgba32Float: return GalImageFormat.Rgba32 | Float; + case GalSurfaceFormat.Rgba32Uint: return GalImageFormat.Rgba32 | Uint; + case GalSurfaceFormat.Rgba16Float: return GalImageFormat.Rgba16 | Float; + case GalSurfaceFormat.Rgba16Unorm: return GalImageFormat.Rgba16 | Unorm; + case GalSurfaceFormat.Rg32Float: return GalImageFormat.Rg32 | Float; + case GalSurfaceFormat.Rg32Sint: return GalImageFormat.Rg32 | Sint; + case GalSurfaceFormat.Rg32Uint: return GalImageFormat.Rg32 | Uint; + case GalSurfaceFormat.Bgra8Unorm: return GalImageFormat.Bgra8 | Unorm; + case GalSurfaceFormat.Bgra8Srgb: return GalImageFormat.Bgra8 | Srgb; + case GalSurfaceFormat.Rgb10A2Unorm: return GalImageFormat.Rgb10A2 | Unorm; + case GalSurfaceFormat.Rgba8Unorm: return GalImageFormat.Rgba8 | Unorm; + case GalSurfaceFormat.Rgba8Srgb: return GalImageFormat.Rgba8 | Srgb; + case GalSurfaceFormat.Rgba8Snorm: return GalImageFormat.Rgba8 | Snorm; + case GalSurfaceFormat.Rg16Snorm: return GalImageFormat.Rg16 | Snorm; + case GalSurfaceFormat.Rg16Unorm: return GalImageFormat.Rg16 | Unorm; + case GalSurfaceFormat.Rg16Sint: return GalImageFormat.Rg16 | Sint; + case GalSurfaceFormat.Rg16Float: return GalImageFormat.Rg16 | Float; case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.R11G11B10 | Float; case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Float; case GalSurfaceFormat.R32Uint: return GalImageFormat.R32 | Uint; - case GalSurfaceFormat.RG8Unorm: return GalImageFormat.RG8 | Unorm; - case GalSurfaceFormat.RG8Snorm: return GalImageFormat.RG8 | Snorm; + case GalSurfaceFormat.Rg8Unorm: return GalImageFormat.Rg8 | Unorm; + case GalSurfaceFormat.Rg8Snorm: return GalImageFormat.Rg8 | Snorm; case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Float; case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm; case GalSurfaceFormat.R16Uint: return GalImageFormat.R16 | Uint; case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm; case GalSurfaceFormat.R8Uint: return GalImageFormat.R8 | Uint; - case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.RGB565 | Unorm; - case GalSurfaceFormat.BGR5A1Unorm: return GalImageFormat.BGR5A1 | Unorm; - case GalSurfaceFormat.RGBX8Unorm: return GalImageFormat.RGBX8 | Unorm; + case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.Rgb565 | Unorm; + case GalSurfaceFormat.Bgr5A1Unorm: return GalImageFormat.Bgr5A1 | Unorm; + case GalSurfaceFormat.Rgbx8Unorm: return GalImageFormat.Rgbx8 | Unorm; } - throw new NotImplementedException(Format.ToString()); + throw new NotImplementedException(format.ToString()); } - public static GalImageFormat ConvertZeta(GalZetaFormat Format) + public static GalImageFormat ConvertZeta(GalZetaFormat format) { - switch (Format) + switch (format) { case GalZetaFormat.D32Float: return GalImageFormat.D32 | Float; case GalZetaFormat.S8D24Unorm: return GalImageFormat.D24S8 | Unorm; @@ -225,268 +224,268 @@ namespace Ryujinx.Graphics.Texture case GalZetaFormat.D32S8X24Float: return GalImageFormat.D32S8 | Float; } - throw new NotImplementedException(Format.ToString()); + throw new NotImplementedException(format.ToString()); } - public static byte[] ReadTexture(IMemory Memory, GalImage Image, long Position) + public static byte[] ReadTexture(IMemory memory, GalImage image, long position) { - MemoryManager CpuMemory; + MemoryManager cpuMemory; - if (Memory is NvGpuVmm Vmm) + if (memory is NvGpuVmm vmm) { - CpuMemory = Vmm.Memory; + cpuMemory = vmm.Memory; } else { - CpuMemory = (MemoryManager)Memory; + cpuMemory = (MemoryManager)memory; } - ISwizzle Swizzle = TextureHelper.GetSwizzle(Image); + ISwizzle swizzle = TextureHelper.GetSwizzle(image); - ImageDescriptor Desc = GetImageDescriptor(Image.Format); + ImageDescriptor desc = GetImageDescriptor(image.Format); - (int Width, int Height, int Depth) = GetImageSizeInBlocks(Image); + (int width, int height, int depth) = GetImageSizeInBlocks(image); - int BytesPerPixel = Desc.BytesPerPixel; + int bytesPerPixel = desc.BytesPerPixel; //Note: Each row of the texture needs to be aligned to 4 bytes. - int Pitch = (Width * BytesPerPixel + 3) & ~3; + int pitch = (width * bytesPerPixel + 3) & ~3; - int DataLayerSize = Height * Pitch * Depth; - byte[] Data = new byte[DataLayerSize * Image.LayerCount]; + int dataLayerSize = height * pitch * depth; + byte[] data = new byte[dataLayerSize * image.LayerCount]; - int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1; - int LayerOffset = ImageUtils.GetLayerOffset(Image, TargetMipLevel); + int targetMipLevel = image.MaxMipmapLevel <= 1 ? 1 : image.MaxMipmapLevel - 1; + int layerOffset = GetLayerOffset(image, targetMipLevel); - for (int Layer = 0; Layer < Image.LayerCount; Layer++) + for (int layer = 0; layer < image.LayerCount; layer++) { - for (int Z = 0; Z < Depth; Z++) + for (int z = 0; z < depth; z++) { - for (int Y = 0; Y < Height; Y++) + for (int y = 0; y < height; y++) { - int OutOffs = (DataLayerSize * Layer) + Y * Pitch + (Z * Width * Height * BytesPerPixel); + int outOffs = (dataLayerSize * layer) + y * pitch + (z * width * height * bytesPerPixel); - for (int X = 0; X < Width; X++) + for (int x = 0; x < width; x++) { - long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z); + long offset = (uint)swizzle.GetSwizzleOffset(x, y, z); - CpuMemory.ReadBytes(Position + (LayerOffset * Layer) + Offset, Data, OutOffs, BytesPerPixel); + cpuMemory.ReadBytes(position + (layerOffset * layer) + offset, data, outOffs, bytesPerPixel); - OutOffs += BytesPerPixel; + outOffs += bytesPerPixel; } } } } - return Data; + return data; } - public static void WriteTexture(NvGpuVmm Vmm, GalImage Image, long Position, byte[] Data) + public static void WriteTexture(NvGpuVmm vmm, GalImage image, long position, byte[] data) { - ISwizzle Swizzle = TextureHelper.GetSwizzle(Image); + ISwizzle swizzle = TextureHelper.GetSwizzle(image); - ImageDescriptor Desc = GetImageDescriptor(Image.Format); + ImageDescriptor desc = GetImageDescriptor(image.Format); - (int Width, int Height, int Depth) = ImageUtils.GetImageSizeInBlocks(Image); + (int width, int height, int depth) = GetImageSizeInBlocks(image); - int BytesPerPixel = Desc.BytesPerPixel; + int bytesPerPixel = desc.BytesPerPixel; - int InOffs = 0; + int inOffs = 0; - for (int Z = 0; Z < Depth; Z++) - for (int Y = 0; Y < Height; Y++) - for (int X = 0; X < Width; X++) + for (int z = 0; z < depth; z++) + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++) { - long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z); + long offset = (uint)swizzle.GetSwizzleOffset(x, y, z); - Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel); + vmm.Memory.WriteBytes(position + offset, data, inOffs, bytesPerPixel); - InOffs += BytesPerPixel; + inOffs += bytesPerPixel; } } // TODO: Support non 2D public static bool CopyTexture( - NvGpuVmm Vmm, - GalImage SrcImage, - GalImage DstImage, - long SrcAddress, - long DstAddress, - int SrcX, - int SrcY, - int DstX, - int DstY, - int Width, - int Height) + NvGpuVmm vmm, + GalImage srcImage, + GalImage dstImage, + long srcAddress, + long dstAddress, + int srcX, + int srcY, + int dstX, + int dstY, + int width, + int height) { - ISwizzle SrcSwizzle = TextureHelper.GetSwizzle(SrcImage); - ISwizzle DstSwizzle = TextureHelper.GetSwizzle(DstImage); + ISwizzle srcSwizzle = TextureHelper.GetSwizzle(srcImage); + ISwizzle dstSwizzle = TextureHelper.GetSwizzle(dstImage); - ImageDescriptor Desc = GetImageDescriptor(SrcImage.Format); + ImageDescriptor desc = GetImageDescriptor(srcImage.Format); - if (GetImageDescriptor(DstImage.Format).BytesPerPixel != Desc.BytesPerPixel) + if (GetImageDescriptor(dstImage.Format).BytesPerPixel != desc.BytesPerPixel) { return false; } - int BytesPerPixel = Desc.BytesPerPixel; + int bytesPerPixel = desc.BytesPerPixel; - for (int Y = 0; Y < Height; Y++) - for (int X = 0; X < Width; X++) + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++) { - long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y, 0); - long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y, 0); + long srcOffset = (uint)srcSwizzle.GetSwizzleOffset(srcX + x, srcY + y, 0); + long dstOffset = (uint)dstSwizzle.GetSwizzleOffset(dstX + x, dstY + y, 0); - byte[] Texel = Vmm.ReadBytes(SrcAddress + SrcOffset, BytesPerPixel); + byte[] texel = vmm.ReadBytes(srcAddress + srcOffset, bytesPerPixel); - Vmm.WriteBytes(DstAddress + DstOffset, Texel); + vmm.WriteBytes(dstAddress + dstOffset, texel); } return true; } - public static int GetSize(GalImage Image) + public static int GetSize(GalImage image) { - ImageDescriptor Desc = GetImageDescriptor(Image.Format); + ImageDescriptor desc = GetImageDescriptor(image.Format); - int ComponentCount = GetCoordsCountTextureTarget(Image.TextureTarget); + int componentCount = GetCoordsCountTextureTarget(image.TextureTarget); - if (IsArray(Image.TextureTarget)) - ComponentCount--; + if (IsArray(image.TextureTarget)) + componentCount--; - int Width = DivRoundUp(Image.Width, Desc.BlockWidth); - int Height = DivRoundUp(Image.Height, Desc.BlockHeight); - int Depth = DivRoundUp(Image.Depth, Desc.BlockDepth); + int width = DivRoundUp(image.Width, desc.BlockWidth); + int height = DivRoundUp(image.Height, desc.BlockHeight); + int depth = DivRoundUp(image.Depth, desc.BlockDepth); - switch (ComponentCount) + switch (componentCount) { case 1: - return Desc.BytesPerPixel * Width * Image.LayerCount; + return desc.BytesPerPixel * width * image.LayerCount; case 2: - return Desc.BytesPerPixel * Width * Height * Image.LayerCount; + return desc.BytesPerPixel * width * height * image.LayerCount; case 3: - return Desc.BytesPerPixel * Width * Height * Depth * Image.LayerCount; + return desc.BytesPerPixel * width * height * depth * image.LayerCount; default: - throw new InvalidOperationException($"Invalid component count: {ComponentCount}"); + throw new InvalidOperationException($"Invalid component count: {componentCount}"); } } - public static int GetGpuSize(GalImage Image, bool forcePitch = false) + public static int GetGpuSize(GalImage image, bool forcePitch = false) { - return TextureHelper.GetSwizzle(Image).GetImageSize(Image.MaxMipmapLevel) * Image.LayerCount; + return TextureHelper.GetSwizzle(image).GetImageSize(image.MaxMipmapLevel) * image.LayerCount; } - public static int GetLayerOffset(GalImage Image, int MipLevel) + public static int GetLayerOffset(GalImage image, int mipLevel) { - if (MipLevel <= 0) + if (mipLevel <= 0) { - MipLevel = 1; + mipLevel = 1; } - return TextureHelper.GetSwizzle(Image).GetMipOffset(MipLevel); + return TextureHelper.GetSwizzle(image).GetMipOffset(mipLevel); } - public static int GetPitch(GalImageFormat Format, int Width) + public static int GetPitch(GalImageFormat format, int width) { - ImageDescriptor Desc = GetImageDescriptor(Format); + ImageDescriptor desc = GetImageDescriptor(format); - int Pitch = Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth); + int pitch = desc.BytesPerPixel * DivRoundUp(width, desc.BlockWidth); - Pitch = (Pitch + 0x1f) & ~0x1f; + pitch = (pitch + 0x1f) & ~0x1f; - return Pitch; + return pitch; } - public static int GetBlockWidth(GalImageFormat Format) + public static int GetBlockWidth(GalImageFormat format) { - return GetImageDescriptor(Format).BlockWidth; + return GetImageDescriptor(format).BlockWidth; } - public static int GetBlockHeight(GalImageFormat Format) + public static int GetBlockHeight(GalImageFormat format) { - return GetImageDescriptor(Format).BlockHeight; + return GetImageDescriptor(format).BlockHeight; } - public static int GetBlockDepth(GalImageFormat Format) + public static int GetBlockDepth(GalImageFormat format) { - return GetImageDescriptor(Format).BlockDepth; + return GetImageDescriptor(format).BlockDepth; } - public static int GetAlignedWidth(GalImage Image) + public static int GetAlignedWidth(GalImage image) { - ImageDescriptor Desc = GetImageDescriptor(Image.Format); + ImageDescriptor desc = GetImageDescriptor(image.Format); - int AlignMask; + int alignMask; - if (Image.Layout == GalMemoryLayout.BlockLinear) + if (image.Layout == GalMemoryLayout.BlockLinear) { - AlignMask = Image.TileWidth * (64 / Desc.BytesPerPixel) - 1; + alignMask = image.TileWidth * (64 / desc.BytesPerPixel) - 1; } else { - AlignMask = (32 / Desc.BytesPerPixel) - 1; + alignMask = (32 / desc.BytesPerPixel) - 1; } - return (Image.Width + AlignMask) & ~AlignMask; + return (image.Width + alignMask) & ~alignMask; } - public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage Image) + public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage image) { - ImageDescriptor Desc = GetImageDescriptor(Image.Format); + ImageDescriptor desc = GetImageDescriptor(image.Format); - return (DivRoundUp(Image.Width, Desc.BlockWidth), - DivRoundUp(Image.Height, Desc.BlockHeight), - DivRoundUp(Image.Depth, Desc.BlockDepth)); + return (DivRoundUp(image.Width, desc.BlockWidth), + DivRoundUp(image.Height, desc.BlockHeight), + DivRoundUp(image.Depth, desc.BlockDepth)); } - public static int GetBytesPerPixel(GalImageFormat Format) + public static int GetBytesPerPixel(GalImageFormat format) { - return GetImageDescriptor(Format).BytesPerPixel; + return GetImageDescriptor(format).BytesPerPixel; } - private static int DivRoundUp(int LHS, int RHS) + private static int DivRoundUp(int lhs, int rhs) { - return (LHS + (RHS - 1)) / RHS; + return (lhs + (rhs - 1)) / rhs; } - public static bool HasColor(GalImageFormat Format) + public static bool HasColor(GalImageFormat format) { - return (GetImageDescriptor(Format).Target & TargetBuffer.Color) != 0; + return (GetImageDescriptor(format).Target & TargetBuffer.Color) != 0; } - public static bool HasDepth(GalImageFormat Format) + public static bool HasDepth(GalImageFormat format) { - return (GetImageDescriptor(Format).Target & TargetBuffer.Depth) != 0; + return (GetImageDescriptor(format).Target & TargetBuffer.Depth) != 0; } - public static bool HasStencil(GalImageFormat Format) + public static bool HasStencil(GalImageFormat format) { - return (GetImageDescriptor(Format).Target & TargetBuffer.Stencil) != 0; + return (GetImageDescriptor(format).Target & TargetBuffer.Stencil) != 0; } - public static bool IsCompressed(GalImageFormat Format) + public static bool IsCompressed(GalImageFormat format) { - ImageDescriptor Desc = GetImageDescriptor(Format); + ImageDescriptor desc = GetImageDescriptor(format); - return (Desc.BlockWidth | Desc.BlockHeight) != 1; + return (desc.BlockWidth | desc.BlockHeight) != 1; } - private static ImageDescriptor GetImageDescriptor(GalImageFormat Format) + private static ImageDescriptor GetImageDescriptor(GalImageFormat format) { - GalImageFormat PixelFormat = Format & GalImageFormat.FormatMask; + GalImageFormat pixelFormat = format & GalImageFormat.FormatMask; - if (s_ImageTable.TryGetValue(PixelFormat, out ImageDescriptor Descriptor)) + if (ImageTable.TryGetValue(pixelFormat, out ImageDescriptor descriptor)) { - return Descriptor; + return descriptor; } - throw new NotImplementedException($"Format \"{PixelFormat}\" not implemented!"); + throw new NotImplementedException($"Format \"{pixelFormat}\" not implemented!"); } - private static GalImageFormat GetFormatType(GalTextureType Type) + private static GalImageFormat GetFormatType(GalTextureType type) { - switch (Type) + switch (type) { case GalTextureType.Snorm: return Snorm; case GalTextureType.Unorm: return Unorm; @@ -494,13 +493,13 @@ namespace Ryujinx.Graphics.Texture case GalTextureType.Uint: return Uint; case GalTextureType.Float: return Float; - default: throw new NotImplementedException(((int)Type).ToString()); + default: throw new NotImplementedException(((int)type).ToString()); } } - public static TextureTarget GetTextureTarget(GalTextureTarget GalTextureTarget) + public static TextureTarget GetTextureTarget(GalTextureTarget galTextureTarget) { - switch (GalTextureTarget) + switch (galTextureTarget) { case GalTextureTarget.OneD: return TextureTarget.Texture1D; @@ -520,13 +519,13 @@ namespace Ryujinx.Graphics.Texture case GalTextureTarget.CubeArray: return TextureTarget.TextureCubeMapArray; default: - throw new NotSupportedException($"Texture target {GalTextureTarget} currently not supported!"); + throw new NotSupportedException($"Texture target {galTextureTarget} currently not supported!"); } } - public static bool IsArray(GalTextureTarget TextureTarget) + public static bool IsArray(GalTextureTarget textureTarget) { - switch (TextureTarget) + switch (textureTarget) { case GalTextureTarget.OneDArray: case GalTextureTarget.TwoDArray: @@ -537,9 +536,9 @@ namespace Ryujinx.Graphics.Texture } } - public static int GetCoordsCountTextureTarget(GalTextureTarget TextureTarget) + public static int GetCoordsCountTextureTarget(GalTextureTarget textureTarget) { - switch (TextureTarget) + switch (textureTarget) { case GalTextureTarget.OneD: return 1; @@ -555,7 +554,7 @@ namespace Ryujinx.Graphics.Texture case GalTextureTarget.CubeArray: return 4; default: - throw new NotImplementedException($"TextureTarget.{TextureTarget} not implemented yet."); + throw new NotImplementedException($"TextureTarget.{textureTarget} not implemented yet."); } } } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/IntegerEncoded.cs b/Ryujinx.Graphics/Graphics3d/Texture/IntegerEncoded.cs index 683cb77049..e6d67058e0 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/IntegerEncoded.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/IntegerEncoded.cs @@ -12,81 +12,81 @@ namespace Ryujinx.Graphics.Texture Trit } - EIntegerEncoding Encoding; + EIntegerEncoding _encoding; public int NumberBits { get; private set; } public int BitValue { get; private set; } public int TritValue { get; private set; } public int QuintValue { get; private set; } - public IntegerEncoded(EIntegerEncoding _Encoding, int NumBits) + public IntegerEncoded(EIntegerEncoding encoding, int numBits) { - Encoding = _Encoding; - NumberBits = NumBits; + _encoding = encoding; + NumberBits = numBits; BitValue = 0; TritValue = 0; QuintValue = 0; } - public bool MatchesEncoding(IntegerEncoded Other) + public bool MatchesEncoding(IntegerEncoded other) { - return Encoding == Other.Encoding && NumberBits == Other.NumberBits; + return _encoding == other._encoding && NumberBits == other.NumberBits; } public EIntegerEncoding GetEncoding() { - return Encoding; + return _encoding; } - public int GetBitLength(int NumberVals) + public int GetBitLength(int numberVals) { - int TotalBits = NumberBits * NumberVals; - if (Encoding == EIntegerEncoding.Trit) + int totalBits = NumberBits * numberVals; + if (_encoding == EIntegerEncoding.Trit) { - TotalBits += (NumberVals * 8 + 4) / 5; + totalBits += (numberVals * 8 + 4) / 5; } - else if (Encoding == EIntegerEncoding.Quint) + else if (_encoding == EIntegerEncoding.Quint) { - TotalBits += (NumberVals * 7 + 2) / 3; + totalBits += (numberVals * 7 + 2) / 3; } - return TotalBits; + return totalBits; } - public static IntegerEncoded CreateEncoding(int MaxVal) + public static IntegerEncoded CreateEncoding(int maxVal) { - while (MaxVal > 0) + while (maxVal > 0) { - int Check = MaxVal + 1; + int check = maxVal + 1; // Is maxVal a power of two? - if ((Check & (Check - 1)) == 0) + if ((check & (check - 1)) == 0) { - return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(MaxVal)); + return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(maxVal)); } // Is maxVal of the type 3*2^n - 1? - if ((Check % 3 == 0) && ((Check / 3) & ((Check / 3) - 1)) == 0) + if ((check % 3 == 0) && ((check / 3) & ((check / 3) - 1)) == 0) { - return new IntegerEncoded(EIntegerEncoding.Trit, BitArrayStream.PopCnt(Check / 3 - 1)); + return new IntegerEncoded(EIntegerEncoding.Trit, BitArrayStream.PopCnt(check / 3 - 1)); } // Is maxVal of the type 5*2^n - 1? - if ((Check % 5 == 0) && ((Check / 5) & ((Check / 5) - 1)) == 0) + if ((check % 5 == 0) && ((check / 5) & ((check / 5) - 1)) == 0) { - return new IntegerEncoded(EIntegerEncoding.Quint, BitArrayStream.PopCnt(Check / 5 - 1)); + return new IntegerEncoded(EIntegerEncoding.Quint, BitArrayStream.PopCnt(check / 5 - 1)); } // Apparently it can't be represented with a bounded integer sequence... // just iterate. - MaxVal--; + maxVal--; } return new IntegerEncoded(EIntegerEncoding.JustBits, 0); } public static void DecodeTritBlock( - BitArrayStream BitStream, - List ListIntegerEncoded, - int NumberBitsPerValue) + BitArrayStream bitStream, + List listIntegerEncoded, + int numberBitsPerValue) { // Implement the algorithm in section C.2.12 int[] m = new int[5]; @@ -95,170 +95,170 @@ namespace Ryujinx.Graphics.Texture // Read the trit encoded block according to // table C.2.14 - m[0] = BitStream.ReadBits(NumberBitsPerValue); - T = BitStream.ReadBits(2); - m[1] = BitStream.ReadBits(NumberBitsPerValue); - T |= BitStream.ReadBits(2) << 2; - m[2] = BitStream.ReadBits(NumberBitsPerValue); - T |= BitStream.ReadBits(1) << 4; - m[3] = BitStream.ReadBits(NumberBitsPerValue); - T |= BitStream.ReadBits(2) << 5; - m[4] = BitStream.ReadBits(NumberBitsPerValue); - T |= BitStream.ReadBits(1) << 7; + m[0] = bitStream.ReadBits(numberBitsPerValue); + T = bitStream.ReadBits(2); + m[1] = bitStream.ReadBits(numberBitsPerValue); + T |= bitStream.ReadBits(2) << 2; + m[2] = bitStream.ReadBits(numberBitsPerValue); + T |= bitStream.ReadBits(1) << 4; + m[3] = bitStream.ReadBits(numberBitsPerValue); + T |= bitStream.ReadBits(2) << 5; + m[4] = bitStream.ReadBits(numberBitsPerValue); + T |= bitStream.ReadBits(1) << 7; - int C = 0; + int c = 0; - BitArrayStream Tb = new BitArrayStream(new BitArray(new int[] { T })); - if (Tb.ReadBits(2, 4) == 7) + BitArrayStream tb = new BitArrayStream(new BitArray(new int[] { T })); + if (tb.ReadBits(2, 4) == 7) { - C = (Tb.ReadBits(5, 7) << 2) | Tb.ReadBits(0, 1); + c = (tb.ReadBits(5, 7) << 2) | tb.ReadBits(0, 1); t[4] = t[3] = 2; } else { - C = Tb.ReadBits(0, 4); - if (Tb.ReadBits(5, 6) == 3) + c = tb.ReadBits(0, 4); + if (tb.ReadBits(5, 6) == 3) { t[4] = 2; - t[3] = Tb.ReadBit(7); + t[3] = tb.ReadBit(7); } else { - t[4] = Tb.ReadBit(7); - t[3] = Tb.ReadBits(5, 6); + t[4] = tb.ReadBit(7); + t[3] = tb.ReadBits(5, 6); } } - BitArrayStream Cb = new BitArrayStream(new BitArray(new int[] { C })); - if (Cb.ReadBits(0, 1) == 3) + BitArrayStream cb = new BitArrayStream(new BitArray(new int[] { c })); + if (cb.ReadBits(0, 1) == 3) { t[2] = 2; - t[1] = Cb.ReadBit(4); - t[0] = (Cb.ReadBit(3) << 1) | (Cb.ReadBit(2) & ~Cb.ReadBit(3)); + t[1] = cb.ReadBit(4); + t[0] = (cb.ReadBit(3) << 1) | (cb.ReadBit(2) & ~cb.ReadBit(3)); } - else if (Cb.ReadBits(2, 3) == 3) + else if (cb.ReadBits(2, 3) == 3) { t[2] = 2; t[1] = 2; - t[0] = Cb.ReadBits(0, 1); + t[0] = cb.ReadBits(0, 1); } else { - t[2] = Cb.ReadBit(4); - t[1] = Cb.ReadBits(2, 3); - t[0] = (Cb.ReadBit(1) << 1) | (Cb.ReadBit(0) & ~Cb.ReadBit(1)); + t[2] = cb.ReadBit(4); + t[1] = cb.ReadBits(2, 3); + t[0] = (cb.ReadBit(1) << 1) | (cb.ReadBit(0) & ~cb.ReadBit(1)); } for (int i = 0; i < 5; i++) { - IntegerEncoded IntEncoded = new IntegerEncoded(EIntegerEncoding.Trit, NumberBitsPerValue) + IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Trit, numberBitsPerValue) { BitValue = m[i], TritValue = t[i] }; - ListIntegerEncoded.Add(IntEncoded); + listIntegerEncoded.Add(intEncoded); } } public static void DecodeQuintBlock( - BitArrayStream BitStream, - List ListIntegerEncoded, - int NumberBitsPerValue) + BitArrayStream bitStream, + List listIntegerEncoded, + int numberBitsPerValue) { // Implement the algorithm in section C.2.12 int[] m = new int[3]; - int[] q = new int[3]; - int Q; + int[] qa = new int[3]; + int q; // Read the trit encoded block according to // table C.2.15 - m[0] = BitStream.ReadBits(NumberBitsPerValue); - Q = BitStream.ReadBits(3); - m[1] = BitStream.ReadBits(NumberBitsPerValue); - Q |= BitStream.ReadBits(2) << 3; - m[2] = BitStream.ReadBits(NumberBitsPerValue); - Q |= BitStream.ReadBits(2) << 5; + m[0] = bitStream.ReadBits(numberBitsPerValue); + q = bitStream.ReadBits(3); + m[1] = bitStream.ReadBits(numberBitsPerValue); + q |= bitStream.ReadBits(2) << 3; + m[2] = bitStream.ReadBits(numberBitsPerValue); + q |= bitStream.ReadBits(2) << 5; - BitArrayStream Qb = new BitArrayStream(new BitArray(new int[] { Q })); - if (Qb.ReadBits(1, 2) == 3 && Qb.ReadBits(5, 6) == 0) + BitArrayStream qb = new BitArrayStream(new BitArray(new int[] { q })); + if (qb.ReadBits(1, 2) == 3 && qb.ReadBits(5, 6) == 0) { - q[0] = q[1] = 4; - q[2] = (Qb.ReadBit(0) << 2) | ((Qb.ReadBit(4) & ~Qb.ReadBit(0)) << 1) | (Qb.ReadBit(3) & ~Qb.ReadBit(0)); + qa[0] = qa[1] = 4; + qa[2] = (qb.ReadBit(0) << 2) | ((qb.ReadBit(4) & ~qb.ReadBit(0)) << 1) | (qb.ReadBit(3) & ~qb.ReadBit(0)); } else { - int C = 0; - if (Qb.ReadBits(1, 2) == 3) + int c = 0; + if (qb.ReadBits(1, 2) == 3) { - q[2] = 4; - C = (Qb.ReadBits(3, 4) << 3) | ((~Qb.ReadBits(5, 6) & 3) << 1) | Qb.ReadBit(0); + qa[2] = 4; + c = (qb.ReadBits(3, 4) << 3) | ((~qb.ReadBits(5, 6) & 3) << 1) | qb.ReadBit(0); } else { - q[2] = Qb.ReadBits(5, 6); - C = Qb.ReadBits(0, 4); + qa[2] = qb.ReadBits(5, 6); + c = qb.ReadBits(0, 4); } - BitArrayStream Cb = new BitArrayStream(new BitArray(new int[] { C })); - if (Cb.ReadBits(0, 2) == 5) + BitArrayStream cb = new BitArrayStream(new BitArray(new int[] { c })); + if (cb.ReadBits(0, 2) == 5) { - q[1] = 4; - q[0] = Cb.ReadBits(3, 4); + qa[1] = 4; + qa[0] = cb.ReadBits(3, 4); } else { - q[1] = Cb.ReadBits(3, 4); - q[0] = Cb.ReadBits(0, 2); + qa[1] = cb.ReadBits(3, 4); + qa[0] = cb.ReadBits(0, 2); } } for (int i = 0; i < 3; i++) { - IntegerEncoded IntEncoded = new IntegerEncoded(EIntegerEncoding.Quint, NumberBitsPerValue) + IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Quint, numberBitsPerValue) { BitValue = m[i], - QuintValue = q[i] + QuintValue = qa[i] }; - ListIntegerEncoded.Add(IntEncoded); + listIntegerEncoded.Add(intEncoded); } } public static void DecodeIntegerSequence( - List DecodeIntegerSequence, - BitArrayStream BitStream, - int MaxRange, - int NumberValues) + List decodeIntegerSequence, + BitArrayStream bitStream, + int maxRange, + int numberValues) { // Determine encoding parameters - IntegerEncoded IntEncoded = CreateEncoding(MaxRange); + IntegerEncoded intEncoded = CreateEncoding(maxRange); // Start decoding - int NumberValuesDecoded = 0; - while (NumberValuesDecoded < NumberValues) + int numberValuesDecoded = 0; + while (numberValuesDecoded < numberValues) { - switch (IntEncoded.GetEncoding()) + switch (intEncoded.GetEncoding()) { case EIntegerEncoding.Quint: { - DecodeQuintBlock(BitStream, DecodeIntegerSequence, IntEncoded.NumberBits); - NumberValuesDecoded += 3; + DecodeQuintBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits); + numberValuesDecoded += 3; break; } case EIntegerEncoding.Trit: { - DecodeTritBlock(BitStream, DecodeIntegerSequence, IntEncoded.NumberBits); - NumberValuesDecoded += 5; + DecodeTritBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits); + numberValuesDecoded += 5; break; } case EIntegerEncoding.JustBits: { - IntEncoded.BitValue = BitStream.ReadBits(IntEncoded.NumberBits); - DecodeIntegerSequence.Add(IntEncoded); - NumberValuesDecoded++; + intEncoded.BitValue = bitStream.ReadBits(intEncoded.NumberBits); + decodeIntegerSequence.Add(intEncoded); + numberValuesDecoded++; break; } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs index e6509baa6a..fb1bd0985f 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs @@ -4,42 +4,42 @@ namespace Ryujinx.Graphics.Texture { class LinearSwizzle : ISwizzle { - private int Pitch; - private int Bpp; + private int _pitch; + private int _bpp; - private int SliceSize; + private int _sliceSize; - public LinearSwizzle(int Pitch, int Bpp, int Width, int Height) + public LinearSwizzle(int pitch, int bpp, int width, int height) { - this.Pitch = Pitch; - this.Bpp = Bpp; - SliceSize = Width * Height * Bpp; + _pitch = pitch; + _bpp = bpp; + _sliceSize = width * height * bpp; } - public void SetMipLevel(int Level) + public void SetMipLevel(int level) { throw new NotImplementedException(); } - public int GetMipOffset(int Level) + public int GetMipOffset(int level) { - if (Level == 1) - return SliceSize; + if (level == 1) + return _sliceSize; throw new NotImplementedException(); } - public int GetImageSize(int MipsCount) + public int GetImageSize(int mipsCount) { - int Size = GetMipOffset(MipsCount); + int size = GetMipOffset(mipsCount); - Size = (Size + 0x1fff) & ~0x1fff; + size = (size + 0x1fff) & ~0x1fff; - return Size; + return size; } - public int GetSwizzleOffset(int X, int Y, int Z) + public int GetSwizzleOffset(int x, int y, int z) { - return Z * SliceSize + X * Bpp + Y * Pitch; + return z * _sliceSize + x * _bpp + y * _pitch; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs index a2ce86f56d..28c9050253 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs @@ -6,161 +6,161 @@ namespace Ryujinx.Graphics.Texture { static class TextureFactory { - public static GalImage MakeTexture(NvGpuVmm Vmm, long TicPosition) + public static GalImage MakeTexture(NvGpuVmm vmm, long ticPosition) { - int[] Tic = ReadWords(Vmm, TicPosition, 8); + int[] tic = ReadWords(vmm, ticPosition, 8); - GalImageFormat Format = GetImageFormat(Tic); + GalImageFormat format = GetImageFormat(tic); - GalTextureTarget TextureTarget = (GalTextureTarget)((Tic[4] >> 23) & 0xF); + GalTextureTarget textureTarget = (GalTextureTarget)((tic[4] >> 23) & 0xF); - GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7); - GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7); - GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7); - GalTextureSource WSource = (GalTextureSource)((Tic[0] >> 28) & 7); + GalTextureSource xSource = (GalTextureSource)((tic[0] >> 19) & 7); + GalTextureSource ySource = (GalTextureSource)((tic[0] >> 22) & 7); + GalTextureSource zSource = (GalTextureSource)((tic[0] >> 25) & 7); + GalTextureSource wSource = (GalTextureSource)((tic[0] >> 28) & 7); - TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7); + TextureSwizzle swizzle = (TextureSwizzle)((tic[2] >> 21) & 7); - int MaxMipmapLevel = (Tic[3] >> 28) & 0xF + 1; + int maxMipmapLevel = (tic[3] >> 28) & 0xF + 1; - GalMemoryLayout Layout; + GalMemoryLayout layout; - if (Swizzle == TextureSwizzle.BlockLinear || - Swizzle == TextureSwizzle.BlockLinearColorKey) + if (swizzle == TextureSwizzle.BlockLinear || + swizzle == TextureSwizzle.BlockLinearColorKey) { - Layout = GalMemoryLayout.BlockLinear; + layout = GalMemoryLayout.BlockLinear; } else { - Layout = GalMemoryLayout.Pitch; + layout = GalMemoryLayout.Pitch; } - int GobBlockHeightLog2 = (Tic[3] >> 3) & 7; - int GobBlockDepthLog2 = (Tic[3] >> 6) & 7; - int TileWidthLog2 = (Tic[3] >> 10) & 7; + int gobBlockHeightLog2 = (tic[3] >> 3) & 7; + int gobBlockDepthLog2 = (tic[3] >> 6) & 7; + int tileWidthLog2 = (tic[3] >> 10) & 7; - int GobBlockHeight = 1 << GobBlockHeightLog2; - int GobBlockDepth = 1 << GobBlockDepthLog2; - int TileWidth = 1 << TileWidthLog2; + int gobBlockHeight = 1 << gobBlockHeightLog2; + int gobBlockDepth = 1 << gobBlockDepthLog2; + int tileWidth = 1 << tileWidthLog2; - int Width = ((Tic[4] >> 0) & 0xffff) + 1; - int Height = ((Tic[5] >> 0) & 0xffff) + 1; - int Depth = ((Tic[5] >> 16) & 0x3fff) + 1; + int width = ((tic[4] >> 0) & 0xffff) + 1; + int height = ((tic[5] >> 0) & 0xffff) + 1; + int depth = ((tic[5] >> 16) & 0x3fff) + 1; - int LayoutCount = 1; + int layoutCount = 1; // TODO: check this - if (ImageUtils.IsArray(TextureTarget)) + if (ImageUtils.IsArray(textureTarget)) { - LayoutCount = Depth; - Depth = 1; + layoutCount = depth; + depth = 1; } - if (TextureTarget == GalTextureTarget.OneD) + if (textureTarget == GalTextureTarget.OneD) { - Height = 1; + height = 1; } - if (TextureTarget == GalTextureTarget.TwoD || TextureTarget == GalTextureTarget.OneD) + if (textureTarget == GalTextureTarget.TwoD || textureTarget == GalTextureTarget.OneD) { - Depth = 1; + depth = 1; } - else if (TextureTarget == GalTextureTarget.CubeMap) + else if (textureTarget == GalTextureTarget.CubeMap) { // FIXME: This is a bit hacky but I guess it's fine for now - LayoutCount = 6; - Depth = 1; + layoutCount = 6; + depth = 1; } - else if (TextureTarget == GalTextureTarget.CubeArray) + else if (textureTarget == GalTextureTarget.CubeArray) { // FIXME: This is a really really hacky but I guess it's fine for now - LayoutCount *= 6; - Depth = 1; + layoutCount *= 6; + depth = 1; } - GalImage Image = new GalImage( - Width, - Height, - Depth, - LayoutCount, - TileWidth, - GobBlockHeight, - GobBlockDepth, - Layout, - Format, - TextureTarget, - MaxMipmapLevel, - XSource, - YSource, - ZSource, - WSource); + GalImage image = new GalImage( + width, + height, + depth, + layoutCount, + tileWidth, + gobBlockHeight, + gobBlockDepth, + layout, + format, + textureTarget, + maxMipmapLevel, + xSource, + ySource, + zSource, + wSource); - if (Layout == GalMemoryLayout.Pitch) + if (layout == GalMemoryLayout.Pitch) { - Image.Pitch = (Tic[3] & 0xffff) << 5; + image.Pitch = (tic[3] & 0xffff) << 5; } - return Image; + return image; } - public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition) + public static GalTextureSampler MakeSampler(NvGpu gpu, NvGpuVmm vmm, long tscPosition) { - int[] Tsc = ReadWords(Vmm, TscPosition, 8); + int[] tsc = ReadWords(vmm, tscPosition, 8); - GalTextureWrap AddressU = (GalTextureWrap)((Tsc[0] >> 0) & 7); - GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7); - GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7); + GalTextureWrap addressU = (GalTextureWrap)((tsc[0] >> 0) & 7); + GalTextureWrap addressV = (GalTextureWrap)((tsc[0] >> 3) & 7); + GalTextureWrap addressP = (GalTextureWrap)((tsc[0] >> 6) & 7); - bool DepthCompare = ((Tsc[0] >> 9) & 1) == 1; + bool depthCompare = ((tsc[0] >> 9) & 1) == 1; - DepthCompareFunc DepthCompareFunc = (DepthCompareFunc)((Tsc[0] >> 10) & 7); + DepthCompareFunc depthCompareFunc = (DepthCompareFunc)((tsc[0] >> 10) & 7); - GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3); - GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3); - GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3); + GalTextureFilter magFilter = (GalTextureFilter) ((tsc[1] >> 0) & 3); + GalTextureFilter minFilter = (GalTextureFilter) ((tsc[1] >> 4) & 3); + GalTextureMipFilter mipFilter = (GalTextureMipFilter)((tsc[1] >> 6) & 3); - GalColorF BorderColor = new GalColorF( - BitConverter.Int32BitsToSingle(Tsc[4]), - BitConverter.Int32BitsToSingle(Tsc[5]), - BitConverter.Int32BitsToSingle(Tsc[6]), - BitConverter.Int32BitsToSingle(Tsc[7])); + GalColorF borderColor = new GalColorF( + BitConverter.Int32BitsToSingle(tsc[4]), + BitConverter.Int32BitsToSingle(tsc[5]), + BitConverter.Int32BitsToSingle(tsc[6]), + BitConverter.Int32BitsToSingle(tsc[7])); return new GalTextureSampler( - AddressU, - AddressV, - AddressP, - MinFilter, - MagFilter, - MipFilter, - BorderColor, - DepthCompare, - DepthCompareFunc); + addressU, + addressV, + addressP, + minFilter, + magFilter, + mipFilter, + borderColor, + depthCompare, + depthCompareFunc); } - private static GalImageFormat GetImageFormat(int[] Tic) + private static GalImageFormat GetImageFormat(int[] tic) { - GalTextureType RType = (GalTextureType)((Tic[0] >> 7) & 7); - GalTextureType GType = (GalTextureType)((Tic[0] >> 10) & 7); - GalTextureType BType = (GalTextureType)((Tic[0] >> 13) & 7); - GalTextureType AType = (GalTextureType)((Tic[0] >> 16) & 7); + GalTextureType rType = (GalTextureType)((tic[0] >> 7) & 7); + GalTextureType gType = (GalTextureType)((tic[0] >> 10) & 7); + GalTextureType bType = (GalTextureType)((tic[0] >> 13) & 7); + GalTextureType aType = (GalTextureType)((tic[0] >> 16) & 7); - GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f); + GalTextureFormat format = (GalTextureFormat)(tic[0] & 0x7f); - bool ConvSrgb = ((Tic[4] >> 22) & 1) != 0; + bool convSrgb = ((tic[4] >> 22) & 1) != 0; - return ImageUtils.ConvertTexture(Format, RType, GType, BType, AType, ConvSrgb); + return ImageUtils.ConvertTexture(format, rType, gType, bType, aType, convSrgb); } - private static int[] ReadWords(NvGpuVmm Vmm, long Position, int Count) + private static int[] ReadWords(NvGpuVmm vmm, long position, int count) { - int[] Words = new int[Count]; + int[] words = new int[count]; - for (int Index = 0; Index < Count; Index++, Position += 4) + for (int index = 0; index < count; index++, position += 4) { - Words[Index] = Vmm.ReadInt32(Position); + words[index] = vmm.ReadInt32(position); } - return Words; + return words; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs index 33ccb0aa51..1de81008ee 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs @@ -7,47 +7,47 @@ namespace Ryujinx.Graphics.Texture { static class TextureHelper { - public static ISwizzle GetSwizzle(GalImage Image) + public static ISwizzle GetSwizzle(GalImage image) { - int BlockWidth = ImageUtils.GetBlockWidth (Image.Format); - int BlockHeight = ImageUtils.GetBlockHeight (Image.Format); - int BlockDepth = ImageUtils.GetBlockDepth (Image.Format); - int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format); + int blockWidth = ImageUtils.GetBlockWidth (image.Format); + int blockHeight = ImageUtils.GetBlockHeight (image.Format); + int blockDepth = ImageUtils.GetBlockDepth (image.Format); + int bytesPerPixel = ImageUtils.GetBytesPerPixel(image.Format); - int Width = BitUtils.DivRoundUp(Image.Width, BlockWidth); - int Height = BitUtils.DivRoundUp(Image.Height, BlockHeight); - int Depth = BitUtils.DivRoundUp(Image.Depth, BlockDepth); + int width = BitUtils.DivRoundUp(image.Width, blockWidth); + int height = BitUtils.DivRoundUp(image.Height, blockHeight); + int depth = BitUtils.DivRoundUp(image.Depth, blockDepth); - if (Image.Layout == GalMemoryLayout.BlockLinear) + if (image.Layout == GalMemoryLayout.BlockLinear) { - int AlignMask = Image.TileWidth * (64 / BytesPerPixel) - 1; + int alignMask = image.TileWidth * (64 / bytesPerPixel) - 1; - Width = (Width + AlignMask) & ~AlignMask; + width = (width + alignMask) & ~alignMask; return new BlockLinearSwizzle( - Width, - Height, - Depth, - Image.GobBlockHeight, - Image.GobBlockDepth, - BytesPerPixel); + width, + height, + depth, + image.GobBlockHeight, + image.GobBlockDepth, + bytesPerPixel); } else { - return new LinearSwizzle(Image.Pitch, BytesPerPixel, Width, Height); + return new LinearSwizzle(image.Pitch, bytesPerPixel, width, height); } } public static (MemoryManager Memory, long Position) GetMemoryAndPosition( - IMemory Memory, - long Position) + IMemory memory, + long position) { - if (Memory is NvGpuVmm Vmm) + if (memory is NvGpuVmm vmm) { - return (Vmm.Memory, Vmm.GetPhysicalAddress(Position)); + return (vmm.Memory, vmm.GetPhysicalAddress(position)); } - return ((MemoryManager)Memory, Position); + return ((MemoryManager)memory, position); } } } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureSwizzle.cs index c67a5367ec..2cc426ab9d 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureSwizzle.cs @@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Texture { public enum TextureSwizzle { - _1dBuffer = 0, + _1DBuffer = 0, PitchColorKey = 1, Pitch = 2, BlockLinear = 3, diff --git a/Ryujinx.Graphics/Memory/NvGpuVmm.cs b/Ryujinx.Graphics/Memory/NvGpuVmm.cs index 7fdef4734a..ac1b765ace 100644 --- a/Ryujinx.Graphics/Memory/NvGpuVmm.cs +++ b/Ryujinx.Graphics/Memory/NvGpuVmm.cs @@ -8,177 +8,177 @@ namespace Ryujinx.Graphics.Memory { public const long AddrSize = 1L << 40; - private const int PTLvl0Bits = 14; - private const int PTLvl1Bits = 14; - private const int PTPageBits = 12; + private const int PtLvl0Bits = 14; + private const int PtLvl1Bits = 14; + private const int PtPageBits = 12; - private const int PTLvl0Size = 1 << PTLvl0Bits; - private const int PTLvl1Size = 1 << PTLvl1Bits; - public const int PageSize = 1 << PTPageBits; + private const int PtLvl0Size = 1 << PtLvl0Bits; + private const int PtLvl1Size = 1 << PtLvl1Bits; + public const int PageSize = 1 << PtPageBits; - private const int PTLvl0Mask = PTLvl0Size - 1; - private const int PTLvl1Mask = PTLvl1Size - 1; + private const int PtLvl0Mask = PtLvl0Size - 1; + private const int PtLvl1Mask = PtLvl1Size - 1; public const int PageMask = PageSize - 1; - private const int PTLvl0Bit = PTPageBits + PTLvl1Bits; - private const int PTLvl1Bit = PTPageBits; + private const int PtLvl0Bit = PtPageBits + PtLvl1Bits; + private const int PtLvl1Bit = PtPageBits; public MemoryManager Memory { get; private set; } - private NvGpuVmmCache Cache; + private NvGpuVmmCache _cache; private const long PteUnmapped = -1; private const long PteReserved = -2; - private long[][] PageTable; + private long[][] _pageTable; - public NvGpuVmm(MemoryManager Memory) + public NvGpuVmm(MemoryManager memory) { - this.Memory = Memory; + Memory = memory; - Cache = new NvGpuVmmCache(Memory); + _cache = new NvGpuVmmCache(memory); - PageTable = new long[PTLvl0Size][]; + _pageTable = new long[PtLvl0Size][]; } - public long Map(long PA, long VA, long Size) + public long Map(long pa, long va, long size) { - lock (PageTable) + lock (_pageTable) { - for (long Offset = 0; Offset < Size; Offset += PageSize) + for (long offset = 0; offset < size; offset += PageSize) { - SetPte(VA + Offset, PA + Offset); + SetPte(va + offset, pa + offset); } } - return VA; + return va; } - public long Map(long PA, long Size) + public long Map(long pa, long size) { - lock (PageTable) + lock (_pageTable) { - long VA = GetFreePosition(Size); + long va = GetFreePosition(size); - if (VA != -1) + if (va != -1) { - for (long Offset = 0; Offset < Size; Offset += PageSize) + for (long offset = 0; offset < size; offset += PageSize) { - SetPte(VA + Offset, PA + Offset); + SetPte(va + offset, pa + offset); } } - return VA; + return va; } } - public long MapLow(long PA, long Size) + public long MapLow(long pa, long size) { - lock (PageTable) + lock (_pageTable) { - long VA = GetFreePosition(Size, 1, PageSize); + long va = GetFreePosition(size, 1, PageSize); - if (VA != -1 && (ulong)VA <= uint.MaxValue && (ulong)(VA + Size) <= uint.MaxValue) + if (va != -1 && (ulong)va <= uint.MaxValue && (ulong)(va + size) <= uint.MaxValue) { - for (long Offset = 0; Offset < Size; Offset += PageSize) + for (long offset = 0; offset < size; offset += PageSize) { - SetPte(VA + Offset, PA + Offset); + SetPte(va + offset, pa + offset); } } else { - VA = -1; + va = -1; } - return VA; + return va; } } - public long ReserveFixed(long VA, long Size) + public long ReserveFixed(long va, long size) { - lock (PageTable) + lock (_pageTable) { - for (long Offset = 0; Offset < Size; Offset += PageSize) + for (long offset = 0; offset < size; offset += PageSize) { - if (IsPageInUse(VA + Offset)) + if (IsPageInUse(va + offset)) { return -1; } } - for (long Offset = 0; Offset < Size; Offset += PageSize) + for (long offset = 0; offset < size; offset += PageSize) { - SetPte(VA + Offset, PteReserved); + SetPte(va + offset, PteReserved); } } - return VA; + return va; } - public long Reserve(long Size, long Align) + public long Reserve(long size, long align) { - lock (PageTable) + lock (_pageTable) { - long Position = GetFreePosition(Size, Align); + long position = GetFreePosition(size, align); - if (Position != -1) + if (position != -1) { - for (long Offset = 0; Offset < Size; Offset += PageSize) + for (long offset = 0; offset < size; offset += PageSize) { - SetPte(Position + Offset, PteReserved); + SetPte(position + offset, PteReserved); } } - return Position; + return position; } } - public void Free(long VA, long Size) + public void Free(long va, long size) { - lock (PageTable) + lock (_pageTable) { - for (long Offset = 0; Offset < Size; Offset += PageSize) + for (long offset = 0; offset < size; offset += PageSize) { - SetPte(VA + Offset, PteUnmapped); + SetPte(va + offset, PteUnmapped); } } } - private long GetFreePosition(long Size, long Align = 1, long Start = 1L << 32) + private long GetFreePosition(long size, long align = 1, long start = 1L << 32) { //Note: Address 0 is not considered valid by the driver, //when 0 is returned it's considered a mapping error. - long Position = Start; - long FreeSize = 0; + long position = start; + long freeSize = 0; - if (Align < 1) + if (align < 1) { - Align = 1; + align = 1; } - Align = (Align + PageMask) & ~PageMask; + align = (align + PageMask) & ~PageMask; - while (Position + FreeSize < AddrSize) + while (position + freeSize < AddrSize) { - if (!IsPageInUse(Position + FreeSize)) + if (!IsPageInUse(position + freeSize)) { - FreeSize += PageSize; + freeSize += PageSize; - if (FreeSize >= Size) + if (freeSize >= size) { - return Position; + return position; } } else { - Position += FreeSize + PageSize; - FreeSize = 0; + position += freeSize + PageSize; + freeSize = 0; - long Remainder = Position % Align; + long remainder = position % align; - if (Remainder != 0) + if (remainder != 0) { - Position = (Position - Remainder) + Align; + position = (position - remainder) + align; } } } @@ -186,23 +186,23 @@ namespace Ryujinx.Graphics.Memory return -1; } - public long GetPhysicalAddress(long VA) + public long GetPhysicalAddress(long va) { - long BasePos = GetPte(VA); + long basePos = GetPte(va); - if (BasePos < 0) + if (basePos < 0) { return -1; } - return BasePos + (VA & PageMask); + return basePos + (va & PageMask); } - public bool IsRegionFree(long VA, long Size) + public bool IsRegionFree(long va, long size) { - for (long Offset = 0; Offset < Size; Offset += PageSize) + for (long offset = 0; offset < size; offset += PageSize) { - if (IsPageInUse(VA + Offset)) + if (IsPageInUse(va + offset)) { return false; } @@ -211,189 +211,189 @@ namespace Ryujinx.Graphics.Memory return true; } - private bool IsPageInUse(long VA) + private bool IsPageInUse(long va) { - if (VA >> PTLvl0Bits + PTLvl1Bits + PTPageBits != 0) + if (va >> PtLvl0Bits + PtLvl1Bits + PtPageBits != 0) { return false; } - long L0 = (VA >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (VA >> PTLvl1Bit) & PTLvl1Mask; + long l0 = (va >> PtLvl0Bit) & PtLvl0Mask; + long l1 = (va >> PtLvl1Bit) & PtLvl1Mask; - if (PageTable[L0] == null) + if (_pageTable[l0] == null) { return false; } - return PageTable[L0][L1] != PteUnmapped; + return _pageTable[l0][l1] != PteUnmapped; } - private long GetPte(long Position) + private long GetPte(long position) { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; + long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; - if (PageTable[L0] == null) + if (_pageTable[l0] == null) { return -1; } - return PageTable[L0][L1]; + return _pageTable[l0][l1]; } - private void SetPte(long Position, long TgtAddr) + private void SetPte(long position, long tgtAddr) { - long L0 = (Position >> PTLvl0Bit) & PTLvl0Mask; - long L1 = (Position >> PTLvl1Bit) & PTLvl1Mask; + long l0 = (position >> PtLvl0Bit) & PtLvl0Mask; + long l1 = (position >> PtLvl1Bit) & PtLvl1Mask; - if (PageTable[L0] == null) + if (_pageTable[l0] == null) { - PageTable[L0] = new long[PTLvl1Size]; + _pageTable[l0] = new long[PtLvl1Size]; - for (int Index = 0; Index < PTLvl1Size; Index++) + for (int index = 0; index < PtLvl1Size; index++) { - PageTable[L0][Index] = PteUnmapped; + _pageTable[l0][index] = PteUnmapped; } } - PageTable[L0][L1] = TgtAddr; + _pageTable[l0][l1] = tgtAddr; } - public bool IsRegionModified(long PA, long Size, NvGpuBufferType BufferType) + public bool IsRegionModified(long pa, long size, NvGpuBufferType bufferType) { - return Cache.IsRegionModified(PA, Size, BufferType); + return _cache.IsRegionModified(pa, size, bufferType); } - public bool TryGetHostAddress(long Position, long Size, out IntPtr Ptr) + public bool TryGetHostAddress(long position, long size, out IntPtr ptr) { - return Memory.TryGetHostAddress(GetPhysicalAddress(Position), Size, out Ptr); + return Memory.TryGetHostAddress(GetPhysicalAddress(position), size, out ptr); } - public byte ReadByte(long Position) + public byte ReadByte(long position) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadByte(Position); + return Memory.ReadByte(position); } - public ushort ReadUInt16(long Position) + public ushort ReadUInt16(long position) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadUInt16(Position); + return Memory.ReadUInt16(position); } - public uint ReadUInt32(long Position) + public uint ReadUInt32(long position) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadUInt32(Position); + return Memory.ReadUInt32(position); } - public ulong ReadUInt64(long Position) + public ulong ReadUInt64(long position) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadUInt64(Position); + return Memory.ReadUInt64(position); } - public sbyte ReadSByte(long Position) + public sbyte ReadSByte(long position) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadSByte(Position); + return Memory.ReadSByte(position); } - public short ReadInt16(long Position) + public short ReadInt16(long position) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadInt16(Position); + return Memory.ReadInt16(position); } - public int ReadInt32(long Position) + public int ReadInt32(long position) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadInt32(Position); + return Memory.ReadInt32(position); } - public long ReadInt64(long Position) + public long ReadInt64(long position) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadInt64(Position); + return Memory.ReadInt64(position); } - public byte[] ReadBytes(long Position, long Size) + public byte[] ReadBytes(long position, long size) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - return Memory.ReadBytes(Position, Size); + return Memory.ReadBytes(position, size); } - public void WriteByte(long Position, byte Value) + public void WriteByte(long position, byte value) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteByte(Position, Value); + Memory.WriteByte(position, value); } - public void WriteUInt16(long Position, ushort Value) + public void WriteUInt16(long position, ushort value) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteUInt16(Position, Value); + Memory.WriteUInt16(position, value); } - public void WriteUInt32(long Position, uint Value) + public void WriteUInt32(long position, uint value) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteUInt32(Position, Value); + Memory.WriteUInt32(position, value); } - public void WriteUInt64(long Position, ulong Value) + public void WriteUInt64(long position, ulong value) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteUInt64(Position, Value); + Memory.WriteUInt64(position, value); } - public void WriteSByte(long Position, sbyte Value) + public void WriteSByte(long position, sbyte value) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteSByte(Position, Value); + Memory.WriteSByte(position, value); } - public void WriteInt16(long Position, short Value) + public void WriteInt16(long position, short value) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteInt16(Position, Value); + Memory.WriteInt16(position, value); } - public void WriteInt32(long Position, int Value) + public void WriteInt32(long position, int value) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteInt32(Position, Value); + Memory.WriteInt32(position, value); } - public void WriteInt64(long Position, long Value) + public void WriteInt64(long position, long value) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteInt64(Position, Value); + Memory.WriteInt64(position, value); } - public void WriteBytes(long Position, byte[] Data) + public void WriteBytes(long position, byte[] data) { - Position = GetPhysicalAddress(Position); + position = GetPhysicalAddress(position); - Memory.WriteBytes(Position, Data); + Memory.WriteBytes(position, data); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs index 053c216137..ab5ea288c6 100644 --- a/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs +++ b/Ryujinx.Graphics/Memory/NvGpuVmmCache.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Memory private const long PageSize = MemoryManager.PageSize; private const long PageMask = MemoryManager.PageMask; - private ConcurrentDictionary[] CachedPages; + private ConcurrentDictionary[] _cachedPages; private MemoryManager _memory; @@ -18,7 +18,7 @@ namespace Ryujinx.Graphics.Memory { _memory = memory; - CachedPages = new ConcurrentDictionary[1 << 20]; + _cachedPages = new ConcurrentDictionary[1 << 20]; } public bool IsRegionModified(long position, long size, NvGpuBufferType bufferType) @@ -41,17 +41,17 @@ namespace Ryujinx.Graphics.Memory { long page = _memory.GetPhysicalAddress(va) >> PageBits; - ConcurrentDictionary dictionary = CachedPages[page]; + ConcurrentDictionary dictionary = _cachedPages[page]; if (dictionary == null) { dictionary = new ConcurrentDictionary(); - CachedPages[page] = dictionary; + _cachedPages[page] = dictionary; } else if (modified) { - CachedPages[page].Clear(); + _cachedPages[page].Clear(); } if (dictionary.TryGetValue(pa, out int currBuffMask)) diff --git a/Ryujinx.Graphics/NvGpu.cs b/Ryujinx.Graphics/NvGpu.cs index 4669c8998c..baac0b2d2a 100644 --- a/Ryujinx.Graphics/NvGpu.cs +++ b/Ryujinx.Graphics/NvGpu.cs @@ -22,13 +22,13 @@ namespace Ryujinx.Graphics internal NvGpuEngineM2mf EngineM2mf { get; private set; } internal NvGpuEngineP2mf EngineP2mf { get; private set; } - private CdmaProcessor CdmaProcessor; + private CdmaProcessor _cdmaProcessor; internal VideoDecoder VideoDecoder { get; private set; } internal VideoImageComposer VideoImageComposer { get; private set; } - public NvGpu(IGalRenderer Renderer) + public NvGpu(IGalRenderer renderer) { - this.Renderer = Renderer; + Renderer = renderer; ResourceManager = new GpuResourceManager(this); @@ -40,22 +40,22 @@ namespace Ryujinx.Graphics EngineM2mf = new NvGpuEngineM2mf(this); EngineP2mf = new NvGpuEngineP2mf(this); - CdmaProcessor = new CdmaProcessor(this); + _cdmaProcessor = new CdmaProcessor(this); VideoDecoder = new VideoDecoder(this); VideoImageComposer = new VideoImageComposer(this); } - public void PushCommandBuffer(NvGpuVmm Vmm, int[] CmdBuffer) + public void PushCommandBuffer(NvGpuVmm vmm, int[] cmdBuffer) { - lock (CdmaProcessor) + lock (_cdmaProcessor) { - CdmaProcessor.PushCommands(Vmm, CmdBuffer); + _cdmaProcessor.PushCommands(vmm, cmdBuffer); } } public void UninitializeVideoDecoder() { - lock (CdmaProcessor) + lock (_cdmaProcessor) { FFmpegWrapper.Uninitialize(); } diff --git a/Ryujinx.Graphics/QuadHelper.cs b/Ryujinx.Graphics/QuadHelper.cs index d5fea9abd5..49c679e3dc 100644 --- a/Ryujinx.Graphics/QuadHelper.cs +++ b/Ryujinx.Graphics/QuadHelper.cs @@ -4,33 +4,33 @@ namespace Ryujinx.Graphics { static class QuadHelper { - public static int ConvertSizeQuadsToTris(int Size) + public static int ConvertSizeQuadsToTris(int size) { - return Size <= 0 ? 0 : (Size / 4) * 6; + return size <= 0 ? 0 : (size / 4) * 6; } - public static int ConvertSizeQuadStripToTris(int Size) + public static int ConvertSizeQuadStripToTris(int size) { - return Size <= 1 ? 0 : ((Size - 2) / 2) * 6; + return size <= 1 ? 0 : ((size - 2) / 2) * 6; } - public static byte[] ConvertQuadsToTris(byte[] Data, int EntrySize, int Count) + public static byte[] ConvertQuadsToTris(byte[] data, int entrySize, int count) { - int PrimitivesCount = Count / 4; + int primitivesCount = count / 4; - int QuadPrimSize = 4 * EntrySize; - int TrisPrimSize = 6 * EntrySize; + int quadPrimSize = 4 * entrySize; + int trisPrimSize = 6 * entrySize; - byte[] Output = new byte[PrimitivesCount * 6 * EntrySize]; + byte[] output = new byte[primitivesCount * 6 * entrySize]; - for (int Prim = 0; Prim < PrimitivesCount; Prim++) + for (int prim = 0; prim < primitivesCount; prim++) { - void AssignIndex(int Src, int Dst, int CopyCount = 1) + void AssignIndex(int src, int dst, int copyCount = 1) { - Src = Prim * QuadPrimSize + Src * EntrySize; - Dst = Prim * TrisPrimSize + Dst * EntrySize; + src = prim * quadPrimSize + src * entrySize; + dst = prim * trisPrimSize + dst * entrySize; - Buffer.BlockCopy(Data, Src, Output, Dst, CopyCount * EntrySize); + Buffer.BlockCopy(data, src, output, dst, copyCount * entrySize); } //0 1 2 -> 0 1 2. @@ -43,26 +43,26 @@ namespace Ryujinx.Graphics AssignIndex(0, 5); } - return Output; + return output; } - public static byte[] ConvertQuadStripToTris(byte[] Data, int EntrySize, int Count) + public static byte[] ConvertQuadStripToTris(byte[] data, int entrySize, int count) { - int PrimitivesCount = (Count - 2) / 2; + int primitivesCount = (count - 2) / 2; - int QuadPrimSize = 2 * EntrySize; - int TrisPrimSize = 6 * EntrySize; + int quadPrimSize = 2 * entrySize; + int trisPrimSize = 6 * entrySize; - byte[] Output = new byte[PrimitivesCount * 6 * EntrySize]; + byte[] output = new byte[primitivesCount * 6 * entrySize]; - for (int Prim = 0; Prim < PrimitivesCount; Prim++) + for (int prim = 0; prim < primitivesCount; prim++) { - void AssignIndex(int Src, int Dst, int CopyCount = 1) + void AssignIndex(int src, int dst, int copyCount = 1) { - Src = Prim * QuadPrimSize + Src * EntrySize + 2 * EntrySize; - Dst = Prim * TrisPrimSize + Dst * EntrySize; + src = prim * quadPrimSize + src * entrySize + 2 * entrySize; + dst = prim * trisPrimSize + dst * entrySize; - Buffer.BlockCopy(Data, Src, Output, Dst, CopyCount * EntrySize); + Buffer.BlockCopy(data, src, output, dst, copyCount * entrySize); } //-2 -1 0 -> 0 1 2. @@ -75,7 +75,7 @@ namespace Ryujinx.Graphics AssignIndex(-2, 5); } - return Output; + return output; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs index bcb64af0be..65a8f356b2 100644 --- a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs +++ b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs @@ -6,14 +6,14 @@ namespace Ryujinx.Graphics.Texture public enum TextureInstructionSuffix { None = 0x00, // No Modifier - LZ = 0x02, // Load LOD Zero - LB = 0x08, // Load Bias - LL = 0x10, // Load LOD - LBA = 0x20, // Load Bias with OperA? Auto? - LLA = 0x40, // Load LOD with OperA? Auto? - DC = 0x80, // Depth Compare + Lz = 0x02, // Load LOD Zero + Lb = 0x08, // Load Bias + Ll = 0x10, // Load LOD + Lba = 0x20, // Load Bias with OperA? Auto? + Lla = 0x40, // Load LOD with OperA? Auto? + Dc = 0x80, // Depth Compare AOffI = 0x100, // Offset - MZ = 0x200, // Multisample Zero? - PTP = 0x400 // ??? + Mz = 0x200, // Multisample Zero? + Ptp = 0x400 // ??? } } diff --git a/Ryujinx.Graphics/VDec/BitStreamWriter.cs b/Ryujinx.Graphics/VDec/BitStreamWriter.cs index 44d07906af..db2d39e593 100644 --- a/Ryujinx.Graphics/VDec/BitStreamWriter.cs +++ b/Ryujinx.Graphics/VDec/BitStreamWriter.cs @@ -6,69 +6,69 @@ namespace Ryujinx.Graphics.VDec { private const int BufferSize = 8; - private Stream BaseStream; + private Stream _baseStream; - private int Buffer; - private int BufferPos; + private int _buffer; + private int _bufferPos; - public BitStreamWriter(Stream BaseStream) + public BitStreamWriter(Stream baseStream) { - this.BaseStream = BaseStream; + _baseStream = baseStream; } - public void WriteBit(bool Value) + public void WriteBit(bool value) { - WriteBits(Value ? 1 : 0, 1); + WriteBits(value ? 1 : 0, 1); } - public void WriteBits(int Value, int ValueSize) + public void WriteBits(int value, int valueSize) { - int ValuePos = 0; + int valuePos = 0; - int Remaining = ValueSize; + int remaining = valueSize; - while (Remaining > 0) + while (remaining > 0) { - int CopySize = Remaining; + int copySize = remaining; - int Free = GetFreeBufferBits(); + int free = GetFreeBufferBits(); - if (CopySize > Free) + if (copySize > free) { - CopySize = Free; + copySize = free; } - int Mask = (1 << CopySize) - 1; + int mask = (1 << copySize) - 1; - int SrcShift = (ValueSize - ValuePos) - CopySize; - int DstShift = (BufferSize - BufferPos) - CopySize; + int srcShift = (valueSize - valuePos) - copySize; + int dstShift = (BufferSize - _bufferPos) - copySize; - Buffer |= ((Value >> SrcShift) & Mask) << DstShift; + _buffer |= ((value >> srcShift) & mask) << dstShift; - ValuePos += CopySize; - BufferPos += CopySize; - Remaining -= CopySize; + valuePos += copySize; + _bufferPos += copySize; + remaining -= copySize; } } private int GetFreeBufferBits() { - if (BufferPos == BufferSize) + if (_bufferPos == BufferSize) { Flush(); } - return BufferSize - BufferPos; + return BufferSize - _bufferPos; } public void Flush() { - if (BufferPos != 0) + if (_bufferPos != 0) { - BaseStream.WriteByte((byte)Buffer); + _baseStream.WriteByte((byte)_buffer); - Buffer = 0; - BufferPos = 0; + _buffer = 0; + _bufferPos = 0; } } } diff --git a/Ryujinx.Graphics/VDec/DecoderHelper.cs b/Ryujinx.Graphics/VDec/DecoderHelper.cs index 485bb42b63..4f17d8d109 100644 --- a/Ryujinx.Graphics/VDec/DecoderHelper.cs +++ b/Ryujinx.Graphics/VDec/DecoderHelper.cs @@ -4,14 +4,14 @@ namespace Ryujinx.Graphics.VDec { static class DecoderHelper { - public static byte[] Combine(byte[] Arr0, byte[] Arr1) + public static byte[] Combine(byte[] arr0, byte[] arr1) { - byte[] Output = new byte[Arr0.Length + Arr1.Length]; + byte[] output = new byte[arr0.Length + arr1.Length]; - Buffer.BlockCopy(Arr0, 0, Output, 0, Arr0.Length); - Buffer.BlockCopy(Arr1, 0, Output, Arr0.Length, Arr1.Length); + Buffer.BlockCopy(arr0, 0, output, 0, arr0.Length); + Buffer.BlockCopy(arr1, 0, output, arr0.Length, arr1.Length); - return Output; + return output; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/VDec/FFmpeg.cs b/Ryujinx.Graphics/VDec/FFmpeg.cs index 183d077922..ccd01f0d3d 100644 --- a/Ryujinx.Graphics/VDec/FFmpeg.cs +++ b/Ryujinx.Graphics/VDec/FFmpeg.cs @@ -4,15 +4,15 @@ using System.Runtime.InteropServices; namespace Ryujinx.Graphics.VDec { - unsafe static class FFmpegWrapper + static unsafe class FFmpegWrapper { - private static AVCodec* Codec; - private static AVCodecContext* Context; - private static AVFrame* Frame; - private static SwsContext* ScalerCtx; + private static AVCodec* _codec; + private static AVCodecContext* _context; + private static AVFrame* _frame; + private static SwsContext* _scalerCtx; - private static int ScalerWidth; - private static int ScalerHeight; + private static int _scalerWidth; + private static int _scalerHeight; public static bool IsInitialized { get; private set; } @@ -26,42 +26,42 @@ namespace Ryujinx.Graphics.VDec EnsureCodecInitialized(AVCodecID.AV_CODEC_ID_VP9); } - private static void EnsureCodecInitialized(AVCodecID CodecId) + private static void EnsureCodecInitialized(AVCodecID codecId) { if (IsInitialized) { Uninitialize(); } - Codec = ffmpeg.avcodec_find_decoder(CodecId); - Context = ffmpeg.avcodec_alloc_context3(Codec); - Frame = ffmpeg.av_frame_alloc(); + _codec = ffmpeg.avcodec_find_decoder(codecId); + _context = ffmpeg.avcodec_alloc_context3(_codec); + _frame = ffmpeg.av_frame_alloc(); - ffmpeg.avcodec_open2(Context, Codec, null); + ffmpeg.avcodec_open2(_context, _codec, null); IsInitialized = true; } - public static int DecodeFrame(byte[] Data) + public static int DecodeFrame(byte[] data) { if (!IsInitialized) { throw new InvalidOperationException("Tried to use uninitialized codec!"); } - AVPacket Packet; + AVPacket packet; - ffmpeg.av_init_packet(&Packet); + ffmpeg.av_init_packet(&packet); - fixed (byte* Ptr = Data) + fixed (byte* ptr = data) { - Packet.data = Ptr; - Packet.size = Data.Length; + packet.data = ptr; + packet.size = data.Length; - ffmpeg.avcodec_send_packet(Context, &Packet); + ffmpeg.avcodec_send_packet(_context, &packet); } - return ffmpeg.avcodec_receive_frame(Context, Frame); + return ffmpeg.avcodec_receive_frame(_context, _frame); } public static FFmpegFrame GetFrame() @@ -71,18 +71,18 @@ namespace Ryujinx.Graphics.VDec throw new InvalidOperationException("Tried to use uninitialized codec!"); } - AVFrame ManagedFrame = Marshal.PtrToStructure((IntPtr)Frame); + AVFrame managedFrame = Marshal.PtrToStructure((IntPtr)_frame); - byte*[] Data = ManagedFrame.data.ToArray(); + byte*[] data = managedFrame.data.ToArray(); return new FFmpegFrame() { - Width = ManagedFrame.width, - Height = ManagedFrame.height, + Width = managedFrame.width, + Height = managedFrame.height, - LumaPtr = Data[0], - ChromaBPtr = Data[1], - ChromaRPtr = Data[2] + LumaPtr = data[0], + ChromaBPtr = data[1], + ChromaRPtr = data[2] }; } @@ -93,51 +93,51 @@ namespace Ryujinx.Graphics.VDec throw new InvalidOperationException("Tried to use uninitialized codec!"); } - AVFrame ManagedFrame = Marshal.PtrToStructure((IntPtr)Frame); + AVFrame managedFrame = Marshal.PtrToStructure((IntPtr)_frame); - EnsureScalerSetup(ManagedFrame.width, ManagedFrame.height); + EnsureScalerSetup(managedFrame.width, managedFrame.height); - byte*[] Data = ManagedFrame.data.ToArray(); + byte*[] data = managedFrame.data.ToArray(); - int[] LineSizes = ManagedFrame.linesize.ToArray(); + int[] lineSizes = managedFrame.linesize.ToArray(); - byte[] Dst = new byte[ManagedFrame.width * ManagedFrame.height * 4]; + byte[] dst = new byte[managedFrame.width * managedFrame.height * 4]; - fixed (byte* Ptr = Dst) + fixed (byte* ptr = dst) { - byte*[] DstData = new byte*[] { Ptr }; + byte*[] dstData = new byte*[] { ptr }; - int[] DstLineSizes = new int[] { ManagedFrame.width * 4 }; + int[] dstLineSizes = new int[] { managedFrame.width * 4 }; - ffmpeg.sws_scale(ScalerCtx, Data, LineSizes, 0, ManagedFrame.height, DstData, DstLineSizes); + ffmpeg.sws_scale(_scalerCtx, data, lineSizes, 0, managedFrame.height, dstData, dstLineSizes); } return new FFmpegFrame() { - Width = ManagedFrame.width, - Height = ManagedFrame.height, + Width = managedFrame.width, + Height = managedFrame.height, - Data = Dst + Data = dst }; } - private static void EnsureScalerSetup(int Width, int Height) + private static void EnsureScalerSetup(int width, int height) { - if (Width == 0 || Height == 0) + if (width == 0 || height == 0) { return; } - if (ScalerCtx == null || ScalerWidth != Width || ScalerHeight != Height) + if (_scalerCtx == null || _scalerWidth != width || _scalerHeight != height) { FreeScaler(); - ScalerCtx = ffmpeg.sws_getContext( - Width, Height, AVPixelFormat.AV_PIX_FMT_YUV420P, - Width, Height, AVPixelFormat.AV_PIX_FMT_RGBA, 0, null, null, null); + _scalerCtx = ffmpeg.sws_getContext( + width, height, AVPixelFormat.AV_PIX_FMT_YUV420P, + width, height, AVPixelFormat.AV_PIX_FMT_RGBA, 0, null, null, null); - ScalerWidth = Width; - ScalerHeight = Height; + _scalerWidth = width; + _scalerHeight = height; } } @@ -145,9 +145,9 @@ namespace Ryujinx.Graphics.VDec { if (IsInitialized) { - ffmpeg.av_frame_unref(Frame); - ffmpeg.av_free(Frame); - ffmpeg.avcodec_close(Context); + ffmpeg.av_frame_unref(_frame); + ffmpeg.av_free(_frame); + ffmpeg.avcodec_close(_context); FreeScaler(); @@ -157,11 +157,11 @@ namespace Ryujinx.Graphics.VDec private static void FreeScaler() { - if (ScalerCtx != null) + if (_scalerCtx != null) { - ffmpeg.sws_freeContext(ScalerCtx); + ffmpeg.sws_freeContext(_scalerCtx); - ScalerCtx = null; + _scalerCtx = null; } } } diff --git a/Ryujinx.Graphics/VDec/H264BitStreamWriter.cs b/Ryujinx.Graphics/VDec/H264BitStreamWriter.cs index b388a2aafb..b4fad59be3 100644 --- a/Ryujinx.Graphics/VDec/H264BitStreamWriter.cs +++ b/Ryujinx.Graphics/VDec/H264BitStreamWriter.cs @@ -4,21 +4,21 @@ namespace Ryujinx.Graphics.VDec { class H264BitStreamWriter : BitStreamWriter { - public H264BitStreamWriter(Stream BaseStream) : base(BaseStream) { } + public H264BitStreamWriter(Stream baseStream) : base(baseStream) { } - public void WriteU(int Value, int ValueSize) + public void WriteU(int value, int valueSize) { - WriteBits(Value, ValueSize); + WriteBits(value, valueSize); } - public void WriteSe(int Value) + public void WriteSe(int value) { - WriteExpGolombCodedInt(Value); + WriteExpGolombCodedInt(value); } - public void WriteUe(int Value) + public void WriteUe(int value) { - WriteExpGolombCodedUInt((uint)Value); + WriteExpGolombCodedUInt((uint)value); } public void End() @@ -28,52 +28,52 @@ namespace Ryujinx.Graphics.VDec Flush(); } - private void WriteExpGolombCodedInt(int Value) + private void WriteExpGolombCodedInt(int value) { - int Sign = Value <= 0 ? 0 : 1; + int sign = value <= 0 ? 0 : 1; - if (Value < 0) + if (value < 0) { - Value = -Value; + value = -value; } - Value = (Value << 1) - Sign; + value = (value << 1) - sign; - WriteExpGolombCodedUInt((uint)Value); + WriteExpGolombCodedUInt((uint)value); } - private void WriteExpGolombCodedUInt(uint Value) + private void WriteExpGolombCodedUInt(uint value) { - int Size = 32 - CountLeadingZeros((int)Value + 1); + int size = 32 - CountLeadingZeros((int)value + 1); - WriteBits(1, Size); + WriteBits(1, size); - Value -= (1u << (Size - 1)) - 1; + value -= (1u << (size - 1)) - 1; - WriteBits((int)Value, Size - 1); + WriteBits((int)value, size - 1); } private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }; - private static int CountLeadingZeros(int Value) + private static int CountLeadingZeros(int value) { - if (Value == 0) + if (value == 0) { return 32; } - int NibbleIdx = 32; - int PreCount, Count = 0; + int nibbleIdx = 32; + int preCount, count = 0; do { - NibbleIdx -= 4; - PreCount = ClzNibbleTbl[(Value >> NibbleIdx) & 0b1111]; - Count += PreCount; + nibbleIdx -= 4; + preCount = ClzNibbleTbl[(value >> nibbleIdx) & 0b1111]; + count += preCount; } - while (PreCount == 4); + while (preCount == 4); - return Count; + return count; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/VDec/H264Decoder.cs b/Ryujinx.Graphics/VDec/H264Decoder.cs index d5d4671348..01085a733f 100644 --- a/Ryujinx.Graphics/VDec/H264Decoder.cs +++ b/Ryujinx.Graphics/VDec/H264Decoder.cs @@ -4,195 +4,195 @@ namespace Ryujinx.Graphics.VDec { class H264Decoder { - private int Log2MaxPicOrderCntLsbMinus4; - private bool DeltaPicOrderAlwaysZeroFlag; - private bool FrameMbsOnlyFlag; - private int PicWidthInMbs; - private int PicHeightInMapUnits; - private bool EntropyCodingModeFlag; - private bool BottomFieldPicOrderInFramePresentFlag; - private int NumRefIdxL0DefaultActiveMinus1; - private int NumRefIdxL1DefaultActiveMinus1; - private bool DeblockingFilterControlPresentFlag; - private bool RedundantPicCntPresentFlag; - private bool Transform8x8ModeFlag; - private bool MbAdaptiveFrameFieldFlag; - private bool Direct8x8InferenceFlag; - private bool WeightedPredFlag; - private bool ConstrainedIntraPredFlag; - private bool FieldPicFlag; - private bool BottomFieldFlag; - private int Log2MaxFrameNumMinus4; - private int ChromaFormatIdc; - private int PicOrderCntType; - private int PicInitQpMinus26; - private int ChromaQpIndexOffset; - private int ChromaQpIndexOffset2; - private int WeightedBipredIdc; - private int FrameNumber; - private byte[] ScalingMatrix4; - private byte[] ScalingMatrix8; + private int _log2MaxPicOrderCntLsbMinus4; + private bool _deltaPicOrderAlwaysZeroFlag; + private bool _frameMbsOnlyFlag; + private int _picWidthInMbs; + private int _picHeightInMapUnits; + private bool _entropyCodingModeFlag; + private bool _bottomFieldPicOrderInFramePresentFlag; + private int _numRefIdxL0DefaultActiveMinus1; + private int _numRefIdxL1DefaultActiveMinus1; + private bool _deblockingFilterControlPresentFlag; + private bool _redundantPicCntPresentFlag; + private bool _transform8x8ModeFlag; + private bool _mbAdaptiveFrameFieldFlag; + private bool _direct8x8InferenceFlag; + private bool _weightedPredFlag; + private bool _constrainedIntraPredFlag; + private bool _fieldPicFlag; + private bool _bottomFieldFlag; + private int _log2MaxFrameNumMinus4; + private int _chromaFormatIdc; + private int _picOrderCntType; + private int _picInitQpMinus26; + private int _chromaQpIndexOffset; + private int _chromaQpIndexOffset2; + private int _weightedBipredIdc; + private int _frameNumber; + private byte[] _scalingMatrix4; + private byte[] _scalingMatrix8; - public void Decode(H264ParameterSets Params, H264Matrices Matrices, byte[] FrameData) + public void Decode(H264ParameterSets Params, H264Matrices matrices, byte[] frameData) { - Log2MaxPicOrderCntLsbMinus4 = Params.Log2MaxPicOrderCntLsbMinus4; - DeltaPicOrderAlwaysZeroFlag = Params.DeltaPicOrderAlwaysZeroFlag; - FrameMbsOnlyFlag = Params.FrameMbsOnlyFlag; - PicWidthInMbs = Params.PicWidthInMbs; - PicHeightInMapUnits = Params.PicHeightInMapUnits; - EntropyCodingModeFlag = Params.EntropyCodingModeFlag; - BottomFieldPicOrderInFramePresentFlag = Params.BottomFieldPicOrderInFramePresentFlag; - NumRefIdxL0DefaultActiveMinus1 = Params.NumRefIdxL0DefaultActiveMinus1; - NumRefIdxL1DefaultActiveMinus1 = Params.NumRefIdxL1DefaultActiveMinus1; - DeblockingFilterControlPresentFlag = Params.DeblockingFilterControlPresentFlag; - RedundantPicCntPresentFlag = Params.RedundantPicCntPresentFlag; - Transform8x8ModeFlag = Params.Transform8x8ModeFlag; + _log2MaxPicOrderCntLsbMinus4 = Params.Log2MaxPicOrderCntLsbMinus4; + _deltaPicOrderAlwaysZeroFlag = Params.DeltaPicOrderAlwaysZeroFlag; + _frameMbsOnlyFlag = Params.FrameMbsOnlyFlag; + _picWidthInMbs = Params.PicWidthInMbs; + _picHeightInMapUnits = Params.PicHeightInMapUnits; + _entropyCodingModeFlag = Params.EntropyCodingModeFlag; + _bottomFieldPicOrderInFramePresentFlag = Params.BottomFieldPicOrderInFramePresentFlag; + _numRefIdxL0DefaultActiveMinus1 = Params.NumRefIdxL0DefaultActiveMinus1; + _numRefIdxL1DefaultActiveMinus1 = Params.NumRefIdxL1DefaultActiveMinus1; + _deblockingFilterControlPresentFlag = Params.DeblockingFilterControlPresentFlag; + _redundantPicCntPresentFlag = Params.RedundantPicCntPresentFlag; + _transform8x8ModeFlag = Params.Transform8x8ModeFlag; - MbAdaptiveFrameFieldFlag = ((Params.Flags >> 0) & 1) != 0; - Direct8x8InferenceFlag = ((Params.Flags >> 1) & 1) != 0; - WeightedPredFlag = ((Params.Flags >> 2) & 1) != 0; - ConstrainedIntraPredFlag = ((Params.Flags >> 3) & 1) != 0; - FieldPicFlag = ((Params.Flags >> 5) & 1) != 0; - BottomFieldFlag = ((Params.Flags >> 6) & 1) != 0; + _mbAdaptiveFrameFieldFlag = ((Params.Flags >> 0) & 1) != 0; + _direct8x8InferenceFlag = ((Params.Flags >> 1) & 1) != 0; + _weightedPredFlag = ((Params.Flags >> 2) & 1) != 0; + _constrainedIntraPredFlag = ((Params.Flags >> 3) & 1) != 0; + _fieldPicFlag = ((Params.Flags >> 5) & 1) != 0; + _bottomFieldFlag = ((Params.Flags >> 6) & 1) != 0; - Log2MaxFrameNumMinus4 = (int)(Params.Flags >> 8) & 0xf; - ChromaFormatIdc = (int)(Params.Flags >> 12) & 0x3; - PicOrderCntType = (int)(Params.Flags >> 14) & 0x3; - PicInitQpMinus26 = (int)(Params.Flags >> 16) & 0x3f; - ChromaQpIndexOffset = (int)(Params.Flags >> 22) & 0x1f; - ChromaQpIndexOffset2 = (int)(Params.Flags >> 27) & 0x1f; - WeightedBipredIdc = (int)(Params.Flags >> 32) & 0x3; - FrameNumber = (int)(Params.Flags >> 46) & 0x1ffff; + _log2MaxFrameNumMinus4 = (int)(Params.Flags >> 8) & 0xf; + _chromaFormatIdc = (int)(Params.Flags >> 12) & 0x3; + _picOrderCntType = (int)(Params.Flags >> 14) & 0x3; + _picInitQpMinus26 = (int)(Params.Flags >> 16) & 0x3f; + _chromaQpIndexOffset = (int)(Params.Flags >> 22) & 0x1f; + _chromaQpIndexOffset2 = (int)(Params.Flags >> 27) & 0x1f; + _weightedBipredIdc = (int)(Params.Flags >> 32) & 0x3; + _frameNumber = (int)(Params.Flags >> 46) & 0x1ffff; - PicInitQpMinus26 = (PicInitQpMinus26 << 26) >> 26; - ChromaQpIndexOffset = (ChromaQpIndexOffset << 27) >> 27; - ChromaQpIndexOffset2 = (ChromaQpIndexOffset2 << 27) >> 27; + _picInitQpMinus26 = (_picInitQpMinus26 << 26) >> 26; + _chromaQpIndexOffset = (_chromaQpIndexOffset << 27) >> 27; + _chromaQpIndexOffset2 = (_chromaQpIndexOffset2 << 27) >> 27; - ScalingMatrix4 = Matrices.ScalingMatrix4; - ScalingMatrix8 = Matrices.ScalingMatrix8; + _scalingMatrix4 = matrices.ScalingMatrix4; + _scalingMatrix8 = matrices.ScalingMatrix8; if (FFmpegWrapper.IsInitialized) { - FFmpegWrapper.DecodeFrame(FrameData); + FFmpegWrapper.DecodeFrame(frameData); } else { FFmpegWrapper.H264Initialize(); - FFmpegWrapper.DecodeFrame(DecoderHelper.Combine(EncodeHeader(), FrameData)); + FFmpegWrapper.DecodeFrame(DecoderHelper.Combine(EncodeHeader(), frameData)); } } private byte[] EncodeHeader() { - using (MemoryStream Data = new MemoryStream()) + using (MemoryStream data = new MemoryStream()) { - H264BitStreamWriter Writer = new H264BitStreamWriter(Data); + H264BitStreamWriter writer = new H264BitStreamWriter(data); //Sequence Parameter Set. - Writer.WriteU(1, 24); - Writer.WriteU(0, 1); - Writer.WriteU(3, 2); - Writer.WriteU(7, 5); - Writer.WriteU(100, 8); - Writer.WriteU(0, 8); - Writer.WriteU(31, 8); - Writer.WriteUe(0); - Writer.WriteUe(ChromaFormatIdc); + writer.WriteU(1, 24); + writer.WriteU(0, 1); + writer.WriteU(3, 2); + writer.WriteU(7, 5); + writer.WriteU(100, 8); + writer.WriteU(0, 8); + writer.WriteU(31, 8); + writer.WriteUe(0); + writer.WriteUe(_chromaFormatIdc); - if (ChromaFormatIdc == 3) + if (_chromaFormatIdc == 3) { - Writer.WriteBit(false); + writer.WriteBit(false); } - Writer.WriteUe(0); - Writer.WriteUe(0); - Writer.WriteBit(false); - Writer.WriteBit(false); //Scaling matrix present flag + writer.WriteUe(0); + writer.WriteUe(0); + writer.WriteBit(false); + writer.WriteBit(false); //Scaling matrix present flag - Writer.WriteUe(Log2MaxFrameNumMinus4); - Writer.WriteUe(PicOrderCntType); + writer.WriteUe(_log2MaxFrameNumMinus4); + writer.WriteUe(_picOrderCntType); - if (PicOrderCntType == 0) + if (_picOrderCntType == 0) { - Writer.WriteUe(Log2MaxPicOrderCntLsbMinus4); + writer.WriteUe(_log2MaxPicOrderCntLsbMinus4); } - else if (PicOrderCntType == 1) + else if (_picOrderCntType == 1) { - Writer.WriteBit(DeltaPicOrderAlwaysZeroFlag); + writer.WriteBit(_deltaPicOrderAlwaysZeroFlag); - Writer.WriteSe(0); - Writer.WriteSe(0); - Writer.WriteUe(0); + writer.WriteSe(0); + writer.WriteSe(0); + writer.WriteUe(0); } - int PicHeightInMbs = PicHeightInMapUnits / (FrameMbsOnlyFlag ? 1 : 2); + int picHeightInMbs = _picHeightInMapUnits / (_frameMbsOnlyFlag ? 1 : 2); - Writer.WriteUe(16); - Writer.WriteBit(false); - Writer.WriteUe(PicWidthInMbs - 1); - Writer.WriteUe(PicHeightInMbs - 1); - Writer.WriteBit(FrameMbsOnlyFlag); + writer.WriteUe(16); + writer.WriteBit(false); + writer.WriteUe(_picWidthInMbs - 1); + writer.WriteUe(picHeightInMbs - 1); + writer.WriteBit(_frameMbsOnlyFlag); - if (!FrameMbsOnlyFlag) + if (!_frameMbsOnlyFlag) { - Writer.WriteBit(MbAdaptiveFrameFieldFlag); + writer.WriteBit(_mbAdaptiveFrameFieldFlag); } - Writer.WriteBit(Direct8x8InferenceFlag); - Writer.WriteBit(false); //Frame cropping flag - Writer.WriteBit(false); //VUI parameter present flag + writer.WriteBit(_direct8x8InferenceFlag); + writer.WriteBit(false); //Frame cropping flag + writer.WriteBit(false); //VUI parameter present flag - Writer.End(); + writer.End(); //Picture Parameter Set. - Writer.WriteU(1, 24); - Writer.WriteU(0, 1); - Writer.WriteU(3, 2); - Writer.WriteU(8, 5); + writer.WriteU(1, 24); + writer.WriteU(0, 1); + writer.WriteU(3, 2); + writer.WriteU(8, 5); - Writer.WriteUe(0); - Writer.WriteUe(0); + writer.WriteUe(0); + writer.WriteUe(0); - Writer.WriteBit(EntropyCodingModeFlag); - Writer.WriteBit(false); - Writer.WriteUe(0); - Writer.WriteUe(NumRefIdxL0DefaultActiveMinus1); - Writer.WriteUe(NumRefIdxL1DefaultActiveMinus1); - Writer.WriteBit(WeightedPredFlag); - Writer.WriteU(WeightedBipredIdc, 2); - Writer.WriteSe(PicInitQpMinus26); - Writer.WriteSe(0); - Writer.WriteSe(ChromaQpIndexOffset); - Writer.WriteBit(DeblockingFilterControlPresentFlag); - Writer.WriteBit(ConstrainedIntraPredFlag); - Writer.WriteBit(RedundantPicCntPresentFlag); - Writer.WriteBit(Transform8x8ModeFlag); + writer.WriteBit(_entropyCodingModeFlag); + writer.WriteBit(false); + writer.WriteUe(0); + writer.WriteUe(_numRefIdxL0DefaultActiveMinus1); + writer.WriteUe(_numRefIdxL1DefaultActiveMinus1); + writer.WriteBit(_weightedPredFlag); + writer.WriteU(_weightedBipredIdc, 2); + writer.WriteSe(_picInitQpMinus26); + writer.WriteSe(0); + writer.WriteSe(_chromaQpIndexOffset); + writer.WriteBit(_deblockingFilterControlPresentFlag); + writer.WriteBit(_constrainedIntraPredFlag); + writer.WriteBit(_redundantPicCntPresentFlag); + writer.WriteBit(_transform8x8ModeFlag); - Writer.WriteBit(true); + writer.WriteBit(true); - for (int Index = 0; Index < 6; Index++) + for (int index = 0; index < 6; index++) { - Writer.WriteBit(true); + writer.WriteBit(true); - WriteScalingList(Writer, ScalingMatrix4, Index * 16, 16); + WriteScalingList(writer, _scalingMatrix4, index * 16, 16); } - if (Transform8x8ModeFlag) + if (_transform8x8ModeFlag) { - for (int Index = 0; Index < 2; Index++) + for (int index = 0; index < 2; index++) { - Writer.WriteBit(true); + writer.WriteBit(true); - WriteScalingList(Writer, ScalingMatrix8, Index * 64, 64); + WriteScalingList(writer, _scalingMatrix8, index * 64, 64); } } - Writer.WriteSe(ChromaQpIndexOffset2); + writer.WriteSe(_chromaQpIndexOffset2); - Writer.End(); + writer.End(); - return Data.ToArray(); + return data.ToArray(); } } @@ -217,21 +217,21 @@ namespace Ryujinx.Graphics.VDec 3 + 1 * 4, 3 + 2 * 4, 2 + 3 * 4, 3 + 3 * 4 }; - private static void WriteScalingList(H264BitStreamWriter Writer, byte[] List, int Start, int Count) + private static void WriteScalingList(H264BitStreamWriter writer, byte[] list, int start, int count) { - byte[] Scan = Count == 16 ? ZigZagScan : ZigZagDirect; + byte[] scan = count == 16 ? ZigZagScan : ZigZagDirect; - int LastScale = 8; + int lastScale = 8; - for (int Index = 0; Index < Count; Index++) + for (int index = 0; index < count; index++) { - byte Value = List[Start + Scan[Index]]; + byte value = list[start + scan[index]]; - int DeltaScale = Value - LastScale; + int deltaScale = value - lastScale; - Writer.WriteSe(DeltaScale); + writer.WriteSe(deltaScale); - LastScale = Value; + lastScale = value; } } } diff --git a/Ryujinx.Graphics/VDec/VideoDecoder.cs b/Ryujinx.Graphics/VDec/VideoDecoder.cs index be53b1a02c..2be47a30b7 100644 --- a/Ryujinx.Graphics/VDec/VideoDecoder.cs +++ b/Ryujinx.Graphics/VDec/VideoDecoder.cs @@ -9,124 +9,124 @@ namespace Ryujinx.Graphics.VDec { unsafe class VideoDecoder { - private NvGpu Gpu; + private NvGpu _gpu; - private H264Decoder H264Decoder; - private Vp9Decoder Vp9Decoder; + private H264Decoder _h264Decoder; + private Vp9Decoder _vp9Decoder; - private VideoCodec CurrentVideoCodec; + private VideoCodec _currentVideoCodec; - private long DecoderContextAddress; - private long FrameDataAddress; - private long VpxCurrLumaAddress; - private long VpxRef0LumaAddress; - private long VpxRef1LumaAddress; - private long VpxRef2LumaAddress; - private long VpxCurrChromaAddress; - private long VpxRef0ChromaAddress; - private long VpxRef1ChromaAddress; - private long VpxRef2ChromaAddress; - private long VpxProbTablesAddress; + private long _decoderContextAddress; + private long _frameDataAddress; + private long _vpxCurrLumaAddress; + private long _vpxRef0LumaAddress; + private long _vpxRef1LumaAddress; + private long _vpxRef2LumaAddress; + private long _vpxCurrChromaAddress; + private long _vpxRef0ChromaAddress; + private long _vpxRef1ChromaAddress; + private long _vpxRef2ChromaAddress; + private long _vpxProbTablesAddress; - public VideoDecoder(NvGpu Gpu) + public VideoDecoder(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; - H264Decoder = new H264Decoder(); - Vp9Decoder = new Vp9Decoder(); + _h264Decoder = new H264Decoder(); + _vp9Decoder = new Vp9Decoder(); } - public void Process(NvGpuVmm Vmm, int MethodOffset, int[] Arguments) + public void Process(NvGpuVmm vmm, int methodOffset, int[] arguments) { - VideoDecoderMeth Method = (VideoDecoderMeth)MethodOffset; + VideoDecoderMeth method = (VideoDecoderMeth)methodOffset; - switch (Method) + switch (method) { - case VideoDecoderMeth.SetVideoCodec: SetVideoCodec (Vmm, Arguments); break; - case VideoDecoderMeth.Execute: Execute (Vmm, Arguments); break; - case VideoDecoderMeth.SetDecoderCtxAddr: SetDecoderCtxAddr (Vmm, Arguments); break; - case VideoDecoderMeth.SetFrameDataAddr: SetFrameDataAddr (Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxCurrLumaAddr: SetVpxCurrLumaAddr (Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxRef0LumaAddr: SetVpxRef0LumaAddr (Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxRef1LumaAddr: SetVpxRef1LumaAddr (Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxRef2LumaAddr: SetVpxRef2LumaAddr (Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxCurrChromaAddr: SetVpxCurrChromaAddr(Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxRef0ChromaAddr: SetVpxRef0ChromaAddr(Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxRef1ChromaAddr: SetVpxRef1ChromaAddr(Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxRef2ChromaAddr: SetVpxRef2ChromaAddr(Vmm, Arguments); break; - case VideoDecoderMeth.SetVpxProbTablesAddr: SetVpxProbTablesAddr(Vmm, Arguments); break; + case VideoDecoderMeth.SetVideoCodec: SetVideoCodec (vmm, arguments); break; + case VideoDecoderMeth.Execute: Execute (vmm, arguments); break; + case VideoDecoderMeth.SetDecoderCtxAddr: SetDecoderCtxAddr (vmm, arguments); break; + case VideoDecoderMeth.SetFrameDataAddr: SetFrameDataAddr (vmm, arguments); break; + case VideoDecoderMeth.SetVpxCurrLumaAddr: SetVpxCurrLumaAddr (vmm, arguments); break; + case VideoDecoderMeth.SetVpxRef0LumaAddr: SetVpxRef0LumaAddr (vmm, arguments); break; + case VideoDecoderMeth.SetVpxRef1LumaAddr: SetVpxRef1LumaAddr (vmm, arguments); break; + case VideoDecoderMeth.SetVpxRef2LumaAddr: SetVpxRef2LumaAddr (vmm, arguments); break; + case VideoDecoderMeth.SetVpxCurrChromaAddr: SetVpxCurrChromaAddr(vmm, arguments); break; + case VideoDecoderMeth.SetVpxRef0ChromaAddr: SetVpxRef0ChromaAddr(vmm, arguments); break; + case VideoDecoderMeth.SetVpxRef1ChromaAddr: SetVpxRef1ChromaAddr(vmm, arguments); break; + case VideoDecoderMeth.SetVpxRef2ChromaAddr: SetVpxRef2ChromaAddr(vmm, arguments); break; + case VideoDecoderMeth.SetVpxProbTablesAddr: SetVpxProbTablesAddr(vmm, arguments); break; } } - private void SetVideoCodec(NvGpuVmm Vmm, int[] Arguments) + private void SetVideoCodec(NvGpuVmm vmm, int[] arguments) { - CurrentVideoCodec = (VideoCodec)Arguments[0]; + _currentVideoCodec = (VideoCodec)arguments[0]; } - private void Execute(NvGpuVmm Vmm, int[] Arguments) + private void Execute(NvGpuVmm vmm, int[] arguments) { - if (CurrentVideoCodec == VideoCodec.H264) + if (_currentVideoCodec == VideoCodec.H264) { - int FrameDataSize = Vmm.ReadInt32(DecoderContextAddress + 0x48); + int frameDataSize = vmm.ReadInt32(_decoderContextAddress + 0x48); - H264ParameterSets Params = MemoryHelper.Read(Vmm.Memory, Vmm.GetPhysicalAddress(DecoderContextAddress + 0x58)); + H264ParameterSets Params = MemoryHelper.Read(vmm.Memory, vmm.GetPhysicalAddress(_decoderContextAddress + 0x58)); - H264Matrices Matrices = new H264Matrices() + H264Matrices matrices = new H264Matrices() { - ScalingMatrix4 = Vmm.ReadBytes(DecoderContextAddress + 0x1c0, 6 * 16), - ScalingMatrix8 = Vmm.ReadBytes(DecoderContextAddress + 0x220, 2 * 64) + ScalingMatrix4 = vmm.ReadBytes(_decoderContextAddress + 0x1c0, 6 * 16), + ScalingMatrix8 = vmm.ReadBytes(_decoderContextAddress + 0x220, 2 * 64) }; - byte[] FrameData = Vmm.ReadBytes(FrameDataAddress, FrameDataSize); + byte[] frameData = vmm.ReadBytes(_frameDataAddress, frameDataSize); - H264Decoder.Decode(Params, Matrices, FrameData); + _h264Decoder.Decode(Params, matrices, frameData); } - else if (CurrentVideoCodec == VideoCodec.Vp9) + else if (_currentVideoCodec == VideoCodec.Vp9) { - int FrameDataSize = Vmm.ReadInt32(DecoderContextAddress + 0x30); + int frameDataSize = vmm.ReadInt32(_decoderContextAddress + 0x30); - Vp9FrameKeys Keys = new Vp9FrameKeys() + Vp9FrameKeys keys = new Vp9FrameKeys() { - CurrKey = Vmm.GetPhysicalAddress(VpxCurrLumaAddress), - Ref0Key = Vmm.GetPhysicalAddress(VpxRef0LumaAddress), - Ref1Key = Vmm.GetPhysicalAddress(VpxRef1LumaAddress), - Ref2Key = Vmm.GetPhysicalAddress(VpxRef2LumaAddress) + CurrKey = vmm.GetPhysicalAddress(_vpxCurrLumaAddress), + Ref0Key = vmm.GetPhysicalAddress(_vpxRef0LumaAddress), + Ref1Key = vmm.GetPhysicalAddress(_vpxRef1LumaAddress), + Ref2Key = vmm.GetPhysicalAddress(_vpxRef2LumaAddress) }; - Vp9FrameHeader Header = MemoryHelper.Read(Vmm.Memory, Vmm.GetPhysicalAddress(DecoderContextAddress + 0x48)); + Vp9FrameHeader header = MemoryHelper.Read(vmm.Memory, vmm.GetPhysicalAddress(_decoderContextAddress + 0x48)); - Vp9ProbabilityTables Probs = new Vp9ProbabilityTables() + Vp9ProbabilityTables probs = new Vp9ProbabilityTables() { - SegmentationTreeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x387, 0x7), - SegmentationPredProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x38e, 0x3), - Tx8x8Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x470, 0x2), - Tx16x16Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x472, 0x4), - Tx32x32Probs = Vmm.ReadBytes(VpxProbTablesAddress + 0x476, 0x6), - CoefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x5a0, 0x900), - SkipProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x537, 0x3), - InterModeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x400, 0x1c), - InterpFilterProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x52a, 0x8), - IsInterProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x41c, 0x4), - CompModeProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x532, 0x5), - SingleRefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x580, 0xa), - CompRefProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x58a, 0x5), - YModeProbs0 = Vmm.ReadBytes(VpxProbTablesAddress + 0x480, 0x20), - YModeProbs1 = Vmm.ReadBytes(VpxProbTablesAddress + 0x47c, 0x4), - PartitionProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x4e0, 0x40), - MvJointProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x53b, 0x3), - MvSignProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x53e, 0x3), - MvClassProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x54c, 0x14), - MvClass0BitProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x540, 0x3), - MvBitsProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x56c, 0x14), - MvClass0FrProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x560, 0xc), - MvFrProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x542, 0x6), - MvClass0HpProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x548, 0x2), - MvHpProbs = Vmm.ReadBytes(VpxProbTablesAddress + 0x54a, 0x2) + SegmentationTreeProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x387, 0x7), + SegmentationPredProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x38e, 0x3), + Tx8x8Probs = vmm.ReadBytes(_vpxProbTablesAddress + 0x470, 0x2), + Tx16x16Probs = vmm.ReadBytes(_vpxProbTablesAddress + 0x472, 0x4), + Tx32x32Probs = vmm.ReadBytes(_vpxProbTablesAddress + 0x476, 0x6), + CoefProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x5a0, 0x900), + SkipProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x537, 0x3), + InterModeProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x400, 0x1c), + InterpFilterProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x52a, 0x8), + IsInterProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x41c, 0x4), + CompModeProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x532, 0x5), + SingleRefProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x580, 0xa), + CompRefProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x58a, 0x5), + YModeProbs0 = vmm.ReadBytes(_vpxProbTablesAddress + 0x480, 0x20), + YModeProbs1 = vmm.ReadBytes(_vpxProbTablesAddress + 0x47c, 0x4), + PartitionProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x4e0, 0x40), + MvJointProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x53b, 0x3), + MvSignProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x53e, 0x3), + MvClassProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x54c, 0x14), + MvClass0BitProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x540, 0x3), + MvBitsProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x56c, 0x14), + MvClass0FrProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x560, 0xc), + MvFrProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x542, 0x6), + MvClass0HpProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x548, 0x2), + MvHpProbs = vmm.ReadBytes(_vpxProbTablesAddress + 0x54a, 0x2) }; - byte[] FrameData = Vmm.ReadBytes(FrameDataAddress, FrameDataSize); + byte[] frameData = vmm.ReadBytes(_frameDataAddress, frameDataSize); - Vp9Decoder.Decode(Keys, Header, Probs, FrameData); + _vp9Decoder.Decode(keys, header, probs, frameData); } else { @@ -134,148 +134,148 @@ namespace Ryujinx.Graphics.VDec } } - private void SetDecoderCtxAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetDecoderCtxAddr(NvGpuVmm vmm, int[] arguments) { - DecoderContextAddress = GetAddress(Arguments); + _decoderContextAddress = GetAddress(arguments); } - private void SetFrameDataAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetFrameDataAddr(NvGpuVmm vmm, int[] arguments) { - FrameDataAddress = GetAddress(Arguments); + _frameDataAddress = GetAddress(arguments); } - private void SetVpxCurrLumaAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxCurrLumaAddr(NvGpuVmm vmm, int[] arguments) { - VpxCurrLumaAddress = GetAddress(Arguments); + _vpxCurrLumaAddress = GetAddress(arguments); } - private void SetVpxRef0LumaAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxRef0LumaAddr(NvGpuVmm vmm, int[] arguments) { - VpxRef0LumaAddress = GetAddress(Arguments); + _vpxRef0LumaAddress = GetAddress(arguments); } - private void SetVpxRef1LumaAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxRef1LumaAddr(NvGpuVmm vmm, int[] arguments) { - VpxRef1LumaAddress = GetAddress(Arguments); + _vpxRef1LumaAddress = GetAddress(arguments); } - private void SetVpxRef2LumaAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxRef2LumaAddr(NvGpuVmm vmm, int[] arguments) { - VpxRef2LumaAddress = GetAddress(Arguments); + _vpxRef2LumaAddress = GetAddress(arguments); } - private void SetVpxCurrChromaAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxCurrChromaAddr(NvGpuVmm vmm, int[] arguments) { - VpxCurrChromaAddress = GetAddress(Arguments); + _vpxCurrChromaAddress = GetAddress(arguments); } - private void SetVpxRef0ChromaAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxRef0ChromaAddr(NvGpuVmm vmm, int[] arguments) { - VpxRef0ChromaAddress = GetAddress(Arguments); + _vpxRef0ChromaAddress = GetAddress(arguments); } - private void SetVpxRef1ChromaAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxRef1ChromaAddr(NvGpuVmm vmm, int[] arguments) { - VpxRef1ChromaAddress = GetAddress(Arguments); + _vpxRef1ChromaAddress = GetAddress(arguments); } - private void SetVpxRef2ChromaAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxRef2ChromaAddr(NvGpuVmm vmm, int[] arguments) { - VpxRef2ChromaAddress = GetAddress(Arguments); + _vpxRef2ChromaAddress = GetAddress(arguments); } - private void SetVpxProbTablesAddr(NvGpuVmm Vmm, int[] Arguments) + private void SetVpxProbTablesAddr(NvGpuVmm vmm, int[] arguments) { - VpxProbTablesAddress = GetAddress(Arguments); + _vpxProbTablesAddress = GetAddress(arguments); } - private static long GetAddress(int[] Arguments) + private static long GetAddress(int[] arguments) { - return (long)(uint)Arguments[0] << 8; + return (long)(uint)arguments[0] << 8; } - internal void CopyPlanes(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig) + internal void CopyPlanes(NvGpuVmm vmm, SurfaceOutputConfig outputConfig) { - switch (OutputConfig.PixelFormat) + switch (outputConfig.PixelFormat) { - case SurfacePixelFormat.RGBA8: CopyPlanesRgba8 (Vmm, OutputConfig); break; - case SurfacePixelFormat.YUV420P: CopyPlanesYuv420p(Vmm, OutputConfig); break; + case SurfacePixelFormat.Rgba8: CopyPlanesRgba8 (vmm, outputConfig); break; + case SurfacePixelFormat.Yuv420P: CopyPlanesYuv420P(vmm, outputConfig); break; - default: ThrowUnimplementedPixelFormat(OutputConfig.PixelFormat); break; + default: ThrowUnimplementedPixelFormat(outputConfig.PixelFormat); break; } } - private void CopyPlanesRgba8(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig) + private void CopyPlanesRgba8(NvGpuVmm vmm, SurfaceOutputConfig outputConfig) { - FFmpegFrame Frame = FFmpegWrapper.GetFrameRgba(); + FFmpegFrame frame = FFmpegWrapper.GetFrameRgba(); - if ((Frame.Width | Frame.Height) == 0) + if ((frame.Width | frame.Height) == 0) { return; } - GalImage Image = new GalImage( - OutputConfig.SurfaceWidth, - OutputConfig.SurfaceHeight, 1, 1, 1, - OutputConfig.GobBlockHeight, 1, + GalImage image = new GalImage( + outputConfig.SurfaceWidth, + outputConfig.SurfaceHeight, 1, 1, 1, + outputConfig.GobBlockHeight, 1, GalMemoryLayout.BlockLinear, - GalImageFormat.RGBA8 | GalImageFormat.Unorm, + GalImageFormat.Rgba8 | GalImageFormat.Unorm, GalTextureTarget.TwoD); - ImageUtils.WriteTexture(Vmm, Image, Vmm.GetPhysicalAddress(OutputConfig.SurfaceLumaAddress), Frame.Data); + ImageUtils.WriteTexture(vmm, image, vmm.GetPhysicalAddress(outputConfig.SurfaceLumaAddress), frame.Data); } - private void CopyPlanesYuv420p(NvGpuVmm Vmm, SurfaceOutputConfig OutputConfig) + private void CopyPlanesYuv420P(NvGpuVmm vmm, SurfaceOutputConfig outputConfig) { - FFmpegFrame Frame = FFmpegWrapper.GetFrame(); + FFmpegFrame frame = FFmpegWrapper.GetFrame(); - if ((Frame.Width | Frame.Height) == 0) + if ((frame.Width | frame.Height) == 0) { return; } - int HalfSrcWidth = Frame.Width / 2; + int halfSrcWidth = frame.Width / 2; - int HalfWidth = Frame.Width / 2; - int HalfHeight = Frame.Height / 2; + int halfWidth = frame.Width / 2; + int halfHeight = frame.Height / 2; - int AlignedWidth = (OutputConfig.SurfaceWidth + 0xff) & ~0xff; + int alignedWidth = (outputConfig.SurfaceWidth + 0xff) & ~0xff; - for (int Y = 0; Y < Frame.Height; Y++) + for (int y = 0; y < frame.Height; y++) { - int Src = Y * Frame.Width; - int Dst = Y * AlignedWidth; + int src = y * frame.Width; + int dst = y * alignedWidth; - int Size = Frame.Width; + int size = frame.Width; - for (int Offset = 0; Offset < Size; Offset++) + for (int offset = 0; offset < size; offset++) { - Vmm.WriteByte(OutputConfig.SurfaceLumaAddress + Dst + Offset, *(Frame.LumaPtr + Src + Offset)); + vmm.WriteByte(outputConfig.SurfaceLumaAddress + dst + offset, *(frame.LumaPtr + src + offset)); } } //Copy chroma data from both channels with interleaving. - for (int Y = 0; Y < HalfHeight; Y++) + for (int y = 0; y < halfHeight; y++) { - int Src = Y * HalfSrcWidth; - int Dst = Y * AlignedWidth; + int src = y * halfSrcWidth; + int dst = y * alignedWidth; - for (int X = 0; X < HalfWidth; X++) + for (int x = 0; x < halfWidth; x++) { - Vmm.WriteByte(OutputConfig.SurfaceChromaUAddress + Dst + X * 2 + 0, *(Frame.ChromaBPtr + Src + X)); - Vmm.WriteByte(OutputConfig.SurfaceChromaUAddress + Dst + X * 2 + 1, *(Frame.ChromaRPtr + Src + X)); + vmm.WriteByte(outputConfig.SurfaceChromaUAddress + dst + x * 2 + 0, *(frame.ChromaBPtr + src + x)); + vmm.WriteByte(outputConfig.SurfaceChromaUAddress + dst + x * 2 + 1, *(frame.ChromaRPtr + src + x)); } } } private void ThrowUnimplementedCodec() { - throw new NotImplementedException("Codec \"" + CurrentVideoCodec + "\" is not supported!"); + throw new NotImplementedException("Codec \"" + _currentVideoCodec + "\" is not supported!"); } - private void ThrowUnimplementedPixelFormat(SurfacePixelFormat PixelFormat) + private void ThrowUnimplementedPixelFormat(SurfacePixelFormat pixelFormat) { - throw new NotImplementedException("Pixel format \"" + PixelFormat + "\" is not supported!"); + throw new NotImplementedException("Pixel format \"" + pixelFormat + "\" is not supported!"); } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/VDec/Vp9Decoder.cs b/Ryujinx.Graphics/VDec/Vp9Decoder.cs index 6e3fc1f295..d77bc6c4a5 100644 --- a/Ryujinx.Graphics/VDec/Vp9Decoder.cs +++ b/Ryujinx.Graphics/VDec/Vp9Decoder.cs @@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.VDec private byte[] DefaultTx16x16Probs = new byte[] { 20, 152, 15, 101 }; private byte[] DefaultTx32x32Probs = new byte[] { 3, 136, 37, 5, 52, 13 }; - private byte[] DefaultCoefProbs = new byte[] + private byte[] _defaultCoefProbs = new byte[] { 195, 29, 183, 0, 84, 49, 136, 0, 8, 42, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 107, 169, 0, 35, 99, 159, 0, @@ -181,39 +181,39 @@ namespace Ryujinx.Graphics.VDec 1, 115, 166, 0, 1, 84, 121, 0, 1, 51, 67, 0, 1, 16, 6, 0 }; - private byte[] DefaultSkipProbs = new byte[] { 192, 128, 64 }; + private byte[] _defaultSkipProbs = new byte[] { 192, 128, 64 }; - private byte[] DefaultInterModeProbs = new byte[] + private byte[] _defaultInterModeProbs = new byte[] { 2, 173, 34, 0, 7, 145, 85, 0, 7, 166, 63, 0, 7, 94, 66, 0, 8, 64, 46, 0, 17, 81, 31, 0, 25, 29, 30, 0 }; - private byte[] DefaultInterpFilterProbs = new byte[] + private byte[] _defaultInterpFilterProbs = new byte[] { 235, 162, 36, 255, 34, 3, 149, 144 }; - private byte[] DefaultIsInterProbs = new byte[] { 9, 102, 187, 225 }; + private byte[] _defaultIsInterProbs = new byte[] { 9, 102, 187, 225 }; - private byte[] DefaultCompModeProbs = new byte[] { 239, 183, 119, 96, 41 }; + private byte[] _defaultCompModeProbs = new byte[] { 239, 183, 119, 96, 41 }; - private byte[] DefaultSingleRefProbs = new byte[] + private byte[] _defaultSingleRefProbs = new byte[] { 33, 16, 77, 74, 142, 142, 172, 170, 238, 247 }; - private byte[] DefaultCompRefProbs = new byte[] { 50, 126, 123, 221, 226 }; + private byte[] _defaultCompRefProbs = new byte[] { 50, 126, 123, 221, 226 }; - private byte[] DefaultYModeProbs0 = new byte[] + private byte[] _defaultYModeProbs0 = new byte[] { 65, 32, 18, 144, 162, 194, 41, 51, 132, 68, 18, 165, 217, 196, 45, 40, 173, 80, 19, 176, 240, 193, 64, 35, 221, 135, 38, 194, 248, 121, 96, 85 }; - private byte[] DefaultYModeProbs1 = new byte[] { 98, 78, 46, 29 }; + private byte[] _defaultYModeProbs1 = new byte[] { 98, 78, 46, 29 }; - private byte[] DefaultPartitionProbs = new byte[] + private byte[] _defaultPartitionProbs = new byte[] { 199, 122, 141, 0, 147, 63, 159, 0, 148, 133, 118, 0, 121, 104, 114, 0, 174, 73, 87, 0, 92, 41, 83, 0, 82, 99, 50, 0, 53, 39, 39, 0, @@ -221,184 +221,184 @@ namespace Ryujinx.Graphics.VDec 222, 34, 30, 0, 72, 16, 44, 0, 58, 32, 12, 0, 10, 7, 6, 0 }; - private byte[] DefaultMvJointProbs = new byte[] { 32, 64, 96 }; + private byte[] _defaultMvJointProbs = new byte[] { 32, 64, 96 }; - private byte[] DefaultMvSignProbs = new byte[] { 128, 128 }; + private byte[] _defaultMvSignProbs = new byte[] { 128, 128 }; - private byte[] DefaultMvClassProbs = new byte[] + private byte[] _defaultMvClassProbs = new byte[] { 224, 144, 192, 168, 192, 176, 192, 198, 198, 245, 216, 128, 176, 160, 176, 176, 192, 198, 198, 208 }; - private byte[] DefaultMvClass0BitProbs = new byte[] { 216, 208 }; + private byte[] _defaultMvClass0BitProbs = new byte[] { 216, 208 }; - private byte[] DefaultMvBitsProbs = new byte[] + private byte[] _defaultMvBitsProbs = new byte[] { 136, 140, 148, 160, 176, 192, 224, 234, 234, 240, 136, 140, 148, 160, 176, 192, 224, 234, 234, 240 }; - private byte[] DefaultMvClass0FrProbs = new byte[] + private byte[] _defaultMvClass0FrProbs = new byte[] { 128, 128, 64, 96, 112, 64, 128, 128, 64, 96, 112, 64 }; - private byte[] DefaultMvFrProbs = new byte[] { 64, 96, 64, 64, 96, 64 }; + private byte[] _defaultMvFrProbs = new byte[] { 64, 96, 64, 64, 96, 64 }; - private byte[] DefaultMvClass0HpProbs = new byte[] { 160, 160 }; + private byte[] _defaultMvClass0HpProbs = new byte[] { 160, 160 }; - private byte[] DefaultMvHpProbs = new byte[] { 128, 128 }; + private byte[] _defaultMvHpProbs = new byte[] { 128, 128 }; - private sbyte[] LoopFilterRefDeltas; - private sbyte[] LoopFilterModeDeltas; + private sbyte[] _loopFilterRefDeltas; + private sbyte[] _loopFilterModeDeltas; - private LinkedList FrameSlotByLastUse; + private LinkedList _frameSlotByLastUse; - private Dictionary> CachedRefFrames; + private Dictionary> _cachedRefFrames; public Vp9Decoder() { - LoopFilterRefDeltas = new sbyte[4]; - LoopFilterModeDeltas = new sbyte[2]; + _loopFilterRefDeltas = new sbyte[4]; + _loopFilterModeDeltas = new sbyte[2]; - FrameSlotByLastUse = new LinkedList(); + _frameSlotByLastUse = new LinkedList(); - for (int Slot = 0; Slot < 8; Slot++) + for (int slot = 0; slot < 8; slot++) { - FrameSlotByLastUse.AddFirst(Slot); + _frameSlotByLastUse.AddFirst(slot); } - CachedRefFrames = new Dictionary>(); + _cachedRefFrames = new Dictionary>(); } public void Decode( - Vp9FrameKeys Keys, - Vp9FrameHeader Header, - Vp9ProbabilityTables Probs, - byte[] FrameData) + Vp9FrameKeys keys, + Vp9FrameHeader header, + Vp9ProbabilityTables probs, + byte[] frameData) { - bool IsKeyFrame = ((Header.Flags >> 0) & 1) != 0; - bool LastIsKeyFrame = ((Header.Flags >> 1) & 1) != 0; - bool FrameSizeChanged = ((Header.Flags >> 2) & 1) != 0; - bool ErrorResilientMode = ((Header.Flags >> 3) & 1) != 0; - bool LastShowFrame = ((Header.Flags >> 4) & 1) != 0; - bool IsFrameIntra = ((Header.Flags >> 5) & 1) != 0; + bool isKeyFrame = ((header.Flags >> 0) & 1) != 0; + bool lastIsKeyFrame = ((header.Flags >> 1) & 1) != 0; + bool frameSizeChanged = ((header.Flags >> 2) & 1) != 0; + bool errorResilientMode = ((header.Flags >> 3) & 1) != 0; + bool lastShowFrame = ((header.Flags >> 4) & 1) != 0; + bool isFrameIntra = ((header.Flags >> 5) & 1) != 0; - bool ShowFrame = !IsFrameIntra; + bool showFrame = !isFrameIntra; //Write compressed header. - byte[] CompressedHeaderData; + byte[] compressedHeaderData; - using (MemoryStream CompressedHeader = new MemoryStream()) + using (MemoryStream compressedHeader = new MemoryStream()) { - VpxRangeEncoder Writer = new VpxRangeEncoder(CompressedHeader); + VpxRangeEncoder writer = new VpxRangeEncoder(compressedHeader); - if (!Header.Lossless) + if (!header.Lossless) { - if ((uint)Header.TxMode >= 3) + if ((uint)header.TxMode >= 3) { - Writer.Write(3, 2); - Writer.Write(Header.TxMode == 4); + writer.Write(3, 2); + writer.Write(header.TxMode == 4); } else { - Writer.Write(Header.TxMode, 2); + writer.Write(header.TxMode, 2); } } - if (Header.TxMode == 4) + if (header.TxMode == 4) { - WriteProbabilityUpdate(Writer, Probs.Tx8x8Probs, DefaultTx8x8Probs); - WriteProbabilityUpdate(Writer, Probs.Tx16x16Probs, DefaultTx16x16Probs); - WriteProbabilityUpdate(Writer, Probs.Tx32x32Probs, DefaultTx32x32Probs); + WriteProbabilityUpdate(writer, probs.Tx8x8Probs, DefaultTx8x8Probs); + WriteProbabilityUpdate(writer, probs.Tx16x16Probs, DefaultTx16x16Probs); + WriteProbabilityUpdate(writer, probs.Tx32x32Probs, DefaultTx32x32Probs); } - WriteCoefProbabilityUpdate(Writer, Header.TxMode, Probs.CoefProbs, DefaultCoefProbs); + WriteCoefProbabilityUpdate(writer, header.TxMode, probs.CoefProbs, _defaultCoefProbs); - WriteProbabilityUpdate(Writer, Probs.SkipProbs, DefaultSkipProbs); + WriteProbabilityUpdate(writer, probs.SkipProbs, _defaultSkipProbs); - if (!IsFrameIntra) + if (!isFrameIntra) { - WriteProbabilityUpdateAligned4(Writer, Probs.InterModeProbs, DefaultInterModeProbs); + WriteProbabilityUpdateAligned4(writer, probs.InterModeProbs, _defaultInterModeProbs); - if (Header.RawInterpolationFilter == 4) + if (header.RawInterpolationFilter == 4) { - WriteProbabilityUpdate(Writer, Probs.InterpFilterProbs, DefaultInterpFilterProbs); + WriteProbabilityUpdate(writer, probs.InterpFilterProbs, _defaultInterpFilterProbs); } - WriteProbabilityUpdate(Writer, Probs.IsInterProbs, DefaultIsInterProbs); + WriteProbabilityUpdate(writer, probs.IsInterProbs, _defaultIsInterProbs); - if ((Header.RefFrameSignBias[1] & 1) != (Header.RefFrameSignBias[2] & 1) || - (Header.RefFrameSignBias[1] & 1) != (Header.RefFrameSignBias[3] & 1)) + if ((header.RefFrameSignBias[1] & 1) != (header.RefFrameSignBias[2] & 1) || + (header.RefFrameSignBias[1] & 1) != (header.RefFrameSignBias[3] & 1)) { - if ((uint)Header.CompPredMode >= 1) + if ((uint)header.CompPredMode >= 1) { - Writer.Write(1, 1); - Writer.Write(Header.CompPredMode == 2); + writer.Write(1, 1); + writer.Write(header.CompPredMode == 2); } else { - Writer.Write(0, 1); + writer.Write(0, 1); } } - if (Header.CompPredMode == 2) + if (header.CompPredMode == 2) { - WriteProbabilityUpdate(Writer, Probs.CompModeProbs, DefaultCompModeProbs); + WriteProbabilityUpdate(writer, probs.CompModeProbs, _defaultCompModeProbs); } - if (Header.CompPredMode != 1) + if (header.CompPredMode != 1) { - WriteProbabilityUpdate(Writer, Probs.SingleRefProbs, DefaultSingleRefProbs); + WriteProbabilityUpdate(writer, probs.SingleRefProbs, _defaultSingleRefProbs); } - if (Header.CompPredMode != 0) + if (header.CompPredMode != 0) { - WriteProbabilityUpdate(Writer, Probs.CompRefProbs, DefaultCompRefProbs); + WriteProbabilityUpdate(writer, probs.CompRefProbs, _defaultCompRefProbs); } - for (int Index = 0; Index < 4; Index++) + for (int index = 0; index < 4; index++) { - int i = Index * 8; - int j = Index; + int i = index * 8; + int j = index; - WriteProbabilityUpdate(Writer, Probs.YModeProbs0[i + 0], DefaultYModeProbs0[i + 0]); - WriteProbabilityUpdate(Writer, Probs.YModeProbs0[i + 1], DefaultYModeProbs0[i + 1]); - WriteProbabilityUpdate(Writer, Probs.YModeProbs0[i + 2], DefaultYModeProbs0[i + 2]); - WriteProbabilityUpdate(Writer, Probs.YModeProbs0[i + 3], DefaultYModeProbs0[i + 3]); - WriteProbabilityUpdate(Writer, Probs.YModeProbs0[i + 4], DefaultYModeProbs0[i + 4]); - WriteProbabilityUpdate(Writer, Probs.YModeProbs0[i + 5], DefaultYModeProbs0[i + 5]); - WriteProbabilityUpdate(Writer, Probs.YModeProbs0[i + 6], DefaultYModeProbs0[i + 6]); - WriteProbabilityUpdate(Writer, Probs.YModeProbs0[i + 7], DefaultYModeProbs0[i + 7]); - WriteProbabilityUpdate(Writer, Probs.YModeProbs1[j + 0], DefaultYModeProbs1[j + 0]); + WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 0], _defaultYModeProbs0[i + 0]); + WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 1], _defaultYModeProbs0[i + 1]); + WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 2], _defaultYModeProbs0[i + 2]); + WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 3], _defaultYModeProbs0[i + 3]); + WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 4], _defaultYModeProbs0[i + 4]); + WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 5], _defaultYModeProbs0[i + 5]); + WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 6], _defaultYModeProbs0[i + 6]); + WriteProbabilityUpdate(writer, probs.YModeProbs0[i + 7], _defaultYModeProbs0[i + 7]); + WriteProbabilityUpdate(writer, probs.YModeProbs1[j + 0], _defaultYModeProbs1[j + 0]); } - WriteProbabilityUpdateAligned4(Writer, Probs.PartitionProbs, DefaultPartitionProbs); + WriteProbabilityUpdateAligned4(writer, probs.PartitionProbs, _defaultPartitionProbs); for (int i = 0; i < 3; i++) { - WriteMvProbabilityUpdate(Writer, Probs.MvJointProbs[i], DefaultMvJointProbs[i]); + WriteMvProbabilityUpdate(writer, probs.MvJointProbs[i], _defaultMvJointProbs[i]); } for (int i = 0; i < 2; i++) { - WriteMvProbabilityUpdate(Writer, Probs.MvSignProbs[i], DefaultMvSignProbs[i]); + WriteMvProbabilityUpdate(writer, probs.MvSignProbs[i], _defaultMvSignProbs[i]); for (int j = 0; j < 10; j++) { - int Index = i * 10 + j; + int index = i * 10 + j; - WriteMvProbabilityUpdate(Writer, Probs.MvClassProbs[Index], DefaultMvClassProbs[Index]); + WriteMvProbabilityUpdate(writer, probs.MvClassProbs[index], _defaultMvClassProbs[index]); } - WriteMvProbabilityUpdate(Writer, Probs.MvClass0BitProbs[i], DefaultMvClass0BitProbs[i]); + WriteMvProbabilityUpdate(writer, probs.MvClass0BitProbs[i], _defaultMvClass0BitProbs[i]); for (int j = 0; j < 10; j++) { - int Index = i * 10 + j; + int index = i * 10 + j; - WriteMvProbabilityUpdate(Writer, Probs.MvBitsProbs[Index], DefaultMvBitsProbs[Index]); + WriteMvProbabilityUpdate(writer, probs.MvBitsProbs[index], _defaultMvBitsProbs[index]); } } @@ -408,249 +408,249 @@ namespace Ryujinx.Graphics.VDec { for (int k = 0; k < 3; k++) { - int Index = i * 2 * 3 + j * 3 + k; + int index = i * 2 * 3 + j * 3 + k; - WriteMvProbabilityUpdate(Writer, Probs.MvClass0FrProbs[Index], DefaultMvClass0FrProbs[Index]); + WriteMvProbabilityUpdate(writer, probs.MvClass0FrProbs[index], _defaultMvClass0FrProbs[index]); } } for (int j = 0; j < 3; j++) { - int Index = i * 3 + j; + int index = i * 3 + j; - WriteMvProbabilityUpdate(Writer, Probs.MvFrProbs[Index], DefaultMvFrProbs[Index]); + WriteMvProbabilityUpdate(writer, probs.MvFrProbs[index], _defaultMvFrProbs[index]); } } - if (Header.AllowHighPrecisionMv) + if (header.AllowHighPrecisionMv) { - for (int Index = 0; Index < 2; Index++) + for (int index = 0; index < 2; index++) { - WriteMvProbabilityUpdate(Writer, Probs.MvClass0HpProbs[Index], DefaultMvClass0HpProbs[Index]); - WriteMvProbabilityUpdate(Writer, Probs.MvHpProbs[Index], DefaultMvHpProbs[Index]); + WriteMvProbabilityUpdate(writer, probs.MvClass0HpProbs[index], _defaultMvClass0HpProbs[index]); + WriteMvProbabilityUpdate(writer, probs.MvHpProbs[index], _defaultMvHpProbs[index]); } } } - Writer.End(); + writer.End(); - CompressedHeaderData = CompressedHeader.ToArray(); + compressedHeaderData = compressedHeader.ToArray(); } //Write uncompressed header. - using (MemoryStream EncodedHeader = new MemoryStream()) + using (MemoryStream encodedHeader = new MemoryStream()) { - VpxBitStreamWriter Writer = new VpxBitStreamWriter(EncodedHeader); + VpxBitStreamWriter writer = new VpxBitStreamWriter(encodedHeader); - Writer.WriteU(2, 2); //Frame marker. - Writer.WriteU(0, 2); //Profile. - Writer.WriteBit(false); //Show existing frame. - Writer.WriteBit(!IsKeyFrame); - Writer.WriteBit(ShowFrame); - Writer.WriteBit(ErrorResilientMode); + writer.WriteU(2, 2); //Frame marker. + writer.WriteU(0, 2); //Profile. + writer.WriteBit(false); //Show existing frame. + writer.WriteBit(!isKeyFrame); + writer.WriteBit(showFrame); + writer.WriteBit(errorResilientMode); - if (IsKeyFrame) + if (isKeyFrame) { - Writer.WriteU(FrameSyncCode, 24); - Writer.WriteU(0, 3); //Color space. - Writer.WriteU(0, 1); //Color range. - Writer.WriteU(Header.CurrentFrame.Width - 1, 16); - Writer.WriteU(Header.CurrentFrame.Height - 1, 16); - Writer.WriteBit(false); //Render and frame size different. + writer.WriteU(FrameSyncCode, 24); + writer.WriteU(0, 3); //Color space. + writer.WriteU(0, 1); //Color range. + writer.WriteU(header.CurrentFrame.Width - 1, 16); + writer.WriteU(header.CurrentFrame.Height - 1, 16); + writer.WriteBit(false); //Render and frame size different. - CachedRefFrames.Clear(); + _cachedRefFrames.Clear(); //On key frames, all frame slots are set to the current frame, //so the value of the selected slot doesn't really matter. - GetNewFrameSlot(Keys.CurrKey); + GetNewFrameSlot(keys.CurrKey); } else { - if (!ShowFrame) + if (!showFrame) { - Writer.WriteBit(IsFrameIntra); + writer.WriteBit(isFrameIntra); } - if (!ErrorResilientMode) + if (!errorResilientMode) { - Writer.WriteU(0, 2); //Reset frame context. + writer.WriteU(0, 2); //Reset frame context. } - int RefreshFrameFlags = 1 << GetNewFrameSlot(Keys.CurrKey); + int refreshFrameFlags = 1 << GetNewFrameSlot(keys.CurrKey); - if (IsFrameIntra) + if (isFrameIntra) { - Writer.WriteU(FrameSyncCode, 24); - Writer.WriteU(RefreshFrameFlags, 8); - Writer.WriteU(Header.CurrentFrame.Width - 1, 16); - Writer.WriteU(Header.CurrentFrame.Height - 1, 16); - Writer.WriteBit(false); //Render and frame size different. + writer.WriteU(FrameSyncCode, 24); + writer.WriteU(refreshFrameFlags, 8); + writer.WriteU(header.CurrentFrame.Width - 1, 16); + writer.WriteU(header.CurrentFrame.Height - 1, 16); + writer.WriteBit(false); //Render and frame size different. } else { - Writer.WriteU(RefreshFrameFlags, 8); + writer.WriteU(refreshFrameFlags, 8); - int[] RefFrameIndex = new int[] + int[] refFrameIndex = new int[] { - GetFrameSlot(Keys.Ref0Key), - GetFrameSlot(Keys.Ref1Key), - GetFrameSlot(Keys.Ref2Key) + GetFrameSlot(keys.Ref0Key), + GetFrameSlot(keys.Ref1Key), + GetFrameSlot(keys.Ref2Key) }; - byte[] RefFrameSignBias = Header.RefFrameSignBias; + byte[] refFrameSignBias = header.RefFrameSignBias; - for (int Index = 1; Index < 4; Index++) + for (int index = 1; index < 4; index++) { - Writer.WriteU(RefFrameIndex[Index - 1], 3); - Writer.WriteU(RefFrameSignBias[Index], 1); + writer.WriteU(refFrameIndex[index - 1], 3); + writer.WriteU(refFrameSignBias[index], 1); } - Writer.WriteBit(true); //Frame size with refs. - Writer.WriteBit(false); //Render and frame size different. - Writer.WriteBit(Header.AllowHighPrecisionMv); - Writer.WriteBit(Header.RawInterpolationFilter == 4); + writer.WriteBit(true); //Frame size with refs. + writer.WriteBit(false); //Render and frame size different. + writer.WriteBit(header.AllowHighPrecisionMv); + writer.WriteBit(header.RawInterpolationFilter == 4); - if (Header.RawInterpolationFilter != 4) + if (header.RawInterpolationFilter != 4) { - Writer.WriteU(Header.RawInterpolationFilter, 2); + writer.WriteU(header.RawInterpolationFilter, 2); } } } - if (!ErrorResilientMode) + if (!errorResilientMode) { - Writer.WriteBit(false); //Refresh frame context. - Writer.WriteBit(true); //Frame parallel decoding mode. + writer.WriteBit(false); //Refresh frame context. + writer.WriteBit(true); //Frame parallel decoding mode. } - Writer.WriteU(0, 2); //Frame context index. + writer.WriteU(0, 2); //Frame context index. - Writer.WriteU(Header.LoopFilterLevel, 6); - Writer.WriteU(Header.LoopFilterSharpness, 3); - Writer.WriteBit(Header.LoopFilterDeltaEnabled); + writer.WriteU(header.LoopFilterLevel, 6); + writer.WriteU(header.LoopFilterSharpness, 3); + writer.WriteBit(header.LoopFilterDeltaEnabled); - if (Header.LoopFilterDeltaEnabled) + if (header.LoopFilterDeltaEnabled) { - bool[] UpdateLoopFilterRefDeltas = new bool[4]; - bool[] UpdateLoopFilterModeDeltas = new bool[2]; + bool[] updateLoopFilterRefDeltas = new bool[4]; + bool[] updateLoopFilterModeDeltas = new bool[2]; - bool LoopFilterDeltaUpdate = false; + bool loopFilterDeltaUpdate = false; - for (int Index = 0; Index < Header.LoopFilterRefDeltas.Length; Index++) + for (int index = 0; index < header.LoopFilterRefDeltas.Length; index++) { - sbyte Old = LoopFilterRefDeltas[Index]; - sbyte New = Header.LoopFilterRefDeltas[Index]; + sbyte old = _loopFilterRefDeltas[index]; + sbyte New = header.LoopFilterRefDeltas[index]; - LoopFilterDeltaUpdate |= (UpdateLoopFilterRefDeltas[Index] = Old != New); + loopFilterDeltaUpdate |= (updateLoopFilterRefDeltas[index] = old != New); } - for (int Index = 0; Index < Header.LoopFilterModeDeltas.Length; Index++) + for (int index = 0; index < header.LoopFilterModeDeltas.Length; index++) { - sbyte Old = LoopFilterModeDeltas[Index]; - sbyte New = Header.LoopFilterModeDeltas[Index]; + sbyte old = _loopFilterModeDeltas[index]; + sbyte New = header.LoopFilterModeDeltas[index]; - LoopFilterDeltaUpdate |= (UpdateLoopFilterModeDeltas[Index] = Old != New); + loopFilterDeltaUpdate |= (updateLoopFilterModeDeltas[index] = old != New); } - Writer.WriteBit(LoopFilterDeltaUpdate); + writer.WriteBit(loopFilterDeltaUpdate); - if (LoopFilterDeltaUpdate) + if (loopFilterDeltaUpdate) { - for (int Index = 0; Index < Header.LoopFilterRefDeltas.Length; Index++) + for (int index = 0; index < header.LoopFilterRefDeltas.Length; index++) { - Writer.WriteBit(UpdateLoopFilterRefDeltas[Index]); + writer.WriteBit(updateLoopFilterRefDeltas[index]); - if (UpdateLoopFilterRefDeltas[Index]) + if (updateLoopFilterRefDeltas[index]) { - Writer.WriteS(Header.LoopFilterRefDeltas[Index], 6); + writer.WriteS(header.LoopFilterRefDeltas[index], 6); } } - for (int Index = 0; Index < Header.LoopFilterModeDeltas.Length; Index++) + for (int index = 0; index < header.LoopFilterModeDeltas.Length; index++) { - Writer.WriteBit(UpdateLoopFilterModeDeltas[Index]); + writer.WriteBit(updateLoopFilterModeDeltas[index]); - if (UpdateLoopFilterModeDeltas[Index]) + if (updateLoopFilterModeDeltas[index]) { - Writer.WriteS(Header.LoopFilterModeDeltas[Index], 6); + writer.WriteS(header.LoopFilterModeDeltas[index], 6); } } } } - Writer.WriteU(Header.BaseQIndex, 8); + writer.WriteU(header.BaseQIndex, 8); - Writer.WriteDeltaQ(Header.DeltaQYDc); - Writer.WriteDeltaQ(Header.DeltaQUvDc); - Writer.WriteDeltaQ(Header.DeltaQUvAc); + writer.WriteDeltaQ(header.DeltaQYDc); + writer.WriteDeltaQ(header.DeltaQUvDc); + writer.WriteDeltaQ(header.DeltaQUvAc); - Writer.WriteBit(false); //Segmentation enabled (TODO). + writer.WriteBit(false); //Segmentation enabled (TODO). - int MinTileColsLog2 = CalcMinLog2TileCols(Header.CurrentFrame.Width); - int MaxTileColsLog2 = CalcMaxLog2TileCols(Header.CurrentFrame.Width); + int minTileColsLog2 = CalcMinLog2TileCols(header.CurrentFrame.Width); + int maxTileColsLog2 = CalcMaxLog2TileCols(header.CurrentFrame.Width); - int TileColsLog2Diff = Header.TileColsLog2 - MinTileColsLog2; + int tileColsLog2Diff = header.TileColsLog2 - minTileColsLog2; - int TileColsLog2IncMask = (1 << TileColsLog2Diff) - 1; + int tileColsLog2IncMask = (1 << tileColsLog2Diff) - 1; //If it's less than the maximum, we need to add an extra 0 on the bitstream //to indicate that it should stop reading. - if (Header.TileColsLog2 < MaxTileColsLog2) + if (header.TileColsLog2 < maxTileColsLog2) { - Writer.WriteU(TileColsLog2IncMask << 1, TileColsLog2Diff + 1); + writer.WriteU(tileColsLog2IncMask << 1, tileColsLog2Diff + 1); } else { - Writer.WriteU(TileColsLog2IncMask, TileColsLog2Diff); + writer.WriteU(tileColsLog2IncMask, tileColsLog2Diff); } - bool TileRowsLog2IsNonZero = Header.TileRowsLog2 != 0; + bool tileRowsLog2IsNonZero = header.TileRowsLog2 != 0; - Writer.WriteBit(TileRowsLog2IsNonZero); + writer.WriteBit(tileRowsLog2IsNonZero); - if (TileRowsLog2IsNonZero) + if (tileRowsLog2IsNonZero) { - Writer.WriteBit(Header.TileRowsLog2 > 1); + writer.WriteBit(header.TileRowsLog2 > 1); } - Writer.WriteU(CompressedHeaderData.Length, 16); + writer.WriteU(compressedHeaderData.Length, 16); - Writer.Flush(); + writer.Flush(); - EncodedHeader.Write(CompressedHeaderData, 0, CompressedHeaderData.Length); + encodedHeader.Write(compressedHeaderData, 0, compressedHeaderData.Length); if (!FFmpegWrapper.IsInitialized) { FFmpegWrapper.Vp9Initialize(); } - FFmpegWrapper.DecodeFrame(DecoderHelper.Combine(EncodedHeader.ToArray(), FrameData)); + FFmpegWrapper.DecodeFrame(DecoderHelper.Combine(encodedHeader.ToArray(), frameData)); } - LoopFilterRefDeltas = Header.LoopFilterRefDeltas; - LoopFilterModeDeltas = Header.LoopFilterModeDeltas; + _loopFilterRefDeltas = header.LoopFilterRefDeltas; + _loopFilterModeDeltas = header.LoopFilterModeDeltas; } - private int GetNewFrameSlot(long Key) + private int GetNewFrameSlot(long key) { - LinkedListNode Node = FrameSlotByLastUse.Last; + LinkedListNode node = _frameSlotByLastUse.Last; - FrameSlotByLastUse.RemoveLast(); - FrameSlotByLastUse.AddFirst(Node); + _frameSlotByLastUse.RemoveLast(); + _frameSlotByLastUse.AddFirst(node); - CachedRefFrames[Key] = Node; + _cachedRefFrames[key] = node; - return Node.Value; + return node.Value; } - private int GetFrameSlot(long Key) + private int GetFrameSlot(long key) { - if (CachedRefFrames.TryGetValue(Key, out LinkedListNode Node)) + if (_cachedRefFrames.TryGetValue(key, out LinkedListNode node)) { - FrameSlotByLastUse.Remove(Node); - FrameSlotByLastUse.AddFirst(Node); + _frameSlotByLastUse.Remove(node); + _frameSlotByLastUse.AddFirst(node); - return Node.Value; + return node.Value; } //Reference frame was lost. @@ -658,53 +658,53 @@ namespace Ryujinx.Graphics.VDec return 0; } - private void WriteProbabilityUpdate(VpxRangeEncoder Writer, byte[] New, byte[] Old) + private void WriteProbabilityUpdate(VpxRangeEncoder writer, byte[] New, byte[] old) { - for (int Offset = 0; Offset < New.Length; Offset++) + for (int offset = 0; offset < New.Length; offset++) { - WriteProbabilityUpdate(Writer, New[Offset], Old[Offset]); + WriteProbabilityUpdate(writer, New[offset], old[offset]); } } - private void WriteCoefProbabilityUpdate(VpxRangeEncoder Writer, int TxMode, byte[] New, byte[] Old) + private void WriteCoefProbabilityUpdate(VpxRangeEncoder writer, int txMode, byte[] New, byte[] old) { //Note: There's 1 byte added on each packet for alignment, //this byte is ignored when doing updates. - const int BlockBytes = 2 * 2 * 6 * 6 * 4; + const int blockBytes = 2 * 2 * 6 * 6 * 4; - bool NeedsUpdate(int BaseIndex) + bool NeedsUpdate(int baseIndex) { - int Index = BaseIndex; + int index = baseIndex; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) for (int k = 0; k < 6; k++) for (int l = 0; l < 6; l++) { - if (New[Index + 0] != Old[Index + 0] || - New[Index + 1] != Old[Index + 1] || - New[Index + 2] != Old[Index + 2]) + if (New[index + 0] != old[index + 0] || + New[index + 1] != old[index + 1] || + New[index + 2] != old[index + 2]) { return true; } - Index += 4; + index += 4; } return false; } - for (int BlockIndex = 0; BlockIndex < 4; BlockIndex++) + for (int blockIndex = 0; blockIndex < 4; blockIndex++) { - int BaseIndex = BlockIndex * BlockBytes; + int baseIndex = blockIndex * blockBytes; - bool Update = NeedsUpdate(BaseIndex); + bool update = NeedsUpdate(baseIndex); - Writer.Write(Update); + writer.Write(update); - if (Update) + if (update) { - int Index = BaseIndex; + int index = baseIndex; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) @@ -713,167 +713,167 @@ namespace Ryujinx.Graphics.VDec { if (k != 0 || l < 3) { - WriteProbabilityUpdate(Writer, New[Index + 0], Old[Index + 0]); - WriteProbabilityUpdate(Writer, New[Index + 1], Old[Index + 1]); - WriteProbabilityUpdate(Writer, New[Index + 2], Old[Index + 2]); + WriteProbabilityUpdate(writer, New[index + 0], old[index + 0]); + WriteProbabilityUpdate(writer, New[index + 1], old[index + 1]); + WriteProbabilityUpdate(writer, New[index + 2], old[index + 2]); } - Index += 4; + index += 4; } } - if (BlockIndex == TxMode) + if (blockIndex == txMode) { break; } } } - private void WriteProbabilityUpdateAligned4(VpxRangeEncoder Writer, byte[] New, byte[] Old) + private void WriteProbabilityUpdateAligned4(VpxRangeEncoder writer, byte[] New, byte[] old) { - for (int Offset = 0; Offset < New.Length; Offset += 4) + for (int offset = 0; offset < New.Length; offset += 4) { - WriteProbabilityUpdate(Writer, New[Offset + 0], Old[Offset + 0]); - WriteProbabilityUpdate(Writer, New[Offset + 1], Old[Offset + 1]); - WriteProbabilityUpdate(Writer, New[Offset + 2], Old[Offset + 2]); + WriteProbabilityUpdate(writer, New[offset + 0], old[offset + 0]); + WriteProbabilityUpdate(writer, New[offset + 1], old[offset + 1]); + WriteProbabilityUpdate(writer, New[offset + 2], old[offset + 2]); } } - private void WriteProbabilityUpdate(VpxRangeEncoder Writer, byte New, byte Old) + private void WriteProbabilityUpdate(VpxRangeEncoder writer, byte New, byte old) { - bool Update = New != Old; + bool update = New != old; - Writer.Write(Update, DiffUpdateProbability); + writer.Write(update, DiffUpdateProbability); - if (Update) + if (update) { - WriteProbabilityDelta(Writer, New, Old); + WriteProbabilityDelta(writer, New, old); } } - private void WriteProbabilityDelta(VpxRangeEncoder Writer, int New, int Old) + private void WriteProbabilityDelta(VpxRangeEncoder writer, int New, int old) { - int Delta = RemapProbability(New, Old); + int delta = RemapProbability(New, old); - EncodeTermSubExp(Writer, Delta); + EncodeTermSubExp(writer, delta); } - private int RemapProbability(int New, int Old) + private int RemapProbability(int New, int old) { New--; - Old--; + old--; - int Index; + int index; - if (Old * 2 <= 0xff) + if (old * 2 <= 0xff) { - Index = RecenterNonNeg(New, Old) - 1; + index = RecenterNonNeg(New, old) - 1; } else { - Index = RecenterNonNeg(0xff - 1 - New, 0xff - 1 - Old) - 1; + index = RecenterNonNeg(0xff - 1 - New, 0xff - 1 - old) - 1; } - return MapLut[Index]; + return MapLut[index]; } - private int RecenterNonNeg(int New, int Old) + private int RecenterNonNeg(int New, int old) { - if (New > Old * 2) + if (New > old * 2) { return New; } - else if (New >= Old) + else if (New >= old) { - return (New - Old) * 2; + return (New - old) * 2; } else /* if (New < Old) */ { - return (Old - New) * 2 - 1; + return (old - New) * 2 - 1; } } - private void EncodeTermSubExp(VpxRangeEncoder Writer, int Value) + private void EncodeTermSubExp(VpxRangeEncoder writer, int value) { - if (WriteLessThan(Writer, Value, 16)) + if (WriteLessThan(writer, value, 16)) { - Writer.Write(Value, 4); + writer.Write(value, 4); } - else if (WriteLessThan(Writer, Value, 32)) + else if (WriteLessThan(writer, value, 32)) { - Writer.Write(Value - 16, 4); + writer.Write(value - 16, 4); } - else if (WriteLessThan(Writer, Value, 64)) + else if (WriteLessThan(writer, value, 64)) { - Writer.Write(Value - 32, 5); + writer.Write(value - 32, 5); } else { - Value -= 64; + value -= 64; - const int Size = 8; + const int size = 8; - int Mask = (1 << Size) - 191; + int mask = (1 << size) - 191; - int Delta = Value - Mask; + int delta = value - mask; - if (Delta < 0) + if (delta < 0) { - Writer.Write(Value, Size - 1); + writer.Write(value, size - 1); } else { - Writer.Write(Delta / 2 + Mask, Size - 1); - Writer.Write(Delta & 1, 1); + writer.Write(delta / 2 + mask, size - 1); + writer.Write(delta & 1, 1); } } } - private bool WriteLessThan(VpxRangeEncoder Writer, int Value, int Test) + private bool WriteLessThan(VpxRangeEncoder writer, int value, int test) { - bool IsLessThan = Value < Test; + bool isLessThan = value < test; - Writer.Write(!IsLessThan); + writer.Write(!isLessThan); - return IsLessThan; + return isLessThan; } - private void WriteMvProbabilityUpdate(VpxRangeEncoder Writer, byte New, byte Old) + private void WriteMvProbabilityUpdate(VpxRangeEncoder writer, byte New, byte old) { - bool Update = New != Old; + bool update = New != old; - Writer.Write(Update, DiffUpdateProbability); + writer.Write(update, DiffUpdateProbability); - if (Update) + if (update) { - Writer.Write(New >> 1, 7); + writer.Write(New >> 1, 7); } } - private static int CalcMinLog2TileCols(int FrameWidth) + private static int CalcMinLog2TileCols(int frameWidth) { - int Sb64Cols = (FrameWidth + 63) / 64; - int MinLog2 = 0; + int sb64Cols = (frameWidth + 63) / 64; + int minLog2 = 0; - while ((64 << MinLog2) < Sb64Cols) + while ((64 << minLog2) < sb64Cols) { - MinLog2++; + minLog2++; } - return MinLog2; + return minLog2; } - private static int CalcMaxLog2TileCols(int FrameWidth) + private static int CalcMaxLog2TileCols(int frameWidth) { - int Sb64Cols = (FrameWidth + 63) / 64; - int MaxLog2 = 1; + int sb64Cols = (frameWidth + 63) / 64; + int maxLog2 = 1; - while ((Sb64Cols >> MaxLog2) >= 4) + while ((sb64Cols >> maxLog2) >= 4) { - MaxLog2++; + maxLog2++; } - return MaxLog2 - 1; + return maxLog2 - 1; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/VDec/VpxBitStreamWriter.cs b/Ryujinx.Graphics/VDec/VpxBitStreamWriter.cs index 0c712d2c4d..97ada333e7 100644 --- a/Ryujinx.Graphics/VDec/VpxBitStreamWriter.cs +++ b/Ryujinx.Graphics/VDec/VpxBitStreamWriter.cs @@ -4,34 +4,34 @@ namespace Ryujinx.Graphics.VDec { class VpxBitStreamWriter : BitStreamWriter { - public VpxBitStreamWriter(Stream BaseStream) : base(BaseStream) { } + public VpxBitStreamWriter(Stream baseStream) : base(baseStream) { } - public void WriteU(int Value, int ValueSize) + public void WriteU(int value, int valueSize) { - WriteBits(Value, ValueSize); + WriteBits(value, valueSize); } - public void WriteS(int Value, int ValueSize) + public void WriteS(int value, int valueSize) { - bool Sign = Value < 0; + bool sign = value < 0; - if (Sign) + if (sign) { - Value = -Value; + value = -value; } - WriteBits((Value << 1) | (Sign ? 1 : 0), ValueSize + 1); + WriteBits((value << 1) | (sign ? 1 : 0), valueSize + 1); } - public void WriteDeltaQ(int Value) + public void WriteDeltaQ(int value) { - bool DeltaCoded = Value != 0; + bool deltaCoded = value != 0; - WriteBit(DeltaCoded); + WriteBit(deltaCoded); - if (DeltaCoded) + if (deltaCoded) { - WriteBits(Value, 4); + WriteBits(value, 4); } } } diff --git a/Ryujinx.Graphics/VDec/VpxRangeEncoder.cs b/Ryujinx.Graphics/VDec/VpxRangeEncoder.cs index 3e381d2c16..c854c9d9de 100644 --- a/Ryujinx.Graphics/VDec/VpxRangeEncoder.cs +++ b/Ryujinx.Graphics/VDec/VpxRangeEncoder.cs @@ -26,106 +26,106 @@ namespace Ryujinx.Graphics.VDec 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - private Stream BaseStream; + private Stream _baseStream; - private uint LowValue; - private uint Range; - private int Count; + private uint _lowValue; + private uint _range; + private int _count; - public VpxRangeEncoder(Stream BaseStream) + public VpxRangeEncoder(Stream baseStream) { - this.BaseStream = BaseStream; + _baseStream = baseStream; - Range = 0xff; - Count = -24; + _range = 0xff; + _count = -24; Write(false); } - public void WriteByte(byte Value) + public void WriteByte(byte value) { - Write(Value, 8); + Write(value, 8); } - public void Write(int Value, int ValueSize) + public void Write(int value, int valueSize) { - for (int Bit = ValueSize - 1; Bit >= 0; Bit--) + for (int bit = valueSize - 1; bit >= 0; bit--) { - Write(((Value >> Bit) & 1) != 0); + Write(((value >> bit) & 1) != 0); } } - public void Write(bool Bit) + public void Write(bool bit) { - Write(Bit, HalfProbability); + Write(bit, HalfProbability); } - public void Write(bool Bit, int Probability) + public void Write(bool bit, int probability) { - uint Range = this.Range; + uint range = _range; - uint Split = 1 + (((Range - 1) * (uint)Probability) >> 8); + uint split = 1 + (((range - 1) * (uint)probability) >> 8); - Range = Split; + range = split; - if (Bit) + if (bit) { - LowValue += Split; - Range = this.Range - Split; + _lowValue += split; + range = _range - split; } - int Shift = NormLut[Range]; + int shift = NormLut[range]; - Range <<= Shift; - Count += Shift; + range <<= shift; + _count += shift; - if (Count >= 0) + if (_count >= 0) { - int Offset = Shift - Count; + int offset = shift - _count; - if (((LowValue << (Offset - 1)) >> 31) != 0) + if (((_lowValue << (offset - 1)) >> 31) != 0) { - long CurrentPos = BaseStream.Position; + long currentPos = _baseStream.Position; - BaseStream.Seek(-1, SeekOrigin.Current); + _baseStream.Seek(-1, SeekOrigin.Current); - while (BaseStream.Position >= 0 && PeekByte() == 0xff) + while (_baseStream.Position >= 0 && PeekByte() == 0xff) { - BaseStream.WriteByte(0); + _baseStream.WriteByte(0); - BaseStream.Seek(-2, SeekOrigin.Current); + _baseStream.Seek(-2, SeekOrigin.Current); } - BaseStream.WriteByte((byte)(PeekByte() + 1)); + _baseStream.WriteByte((byte)(PeekByte() + 1)); - BaseStream.Seek(CurrentPos, SeekOrigin.Begin); + _baseStream.Seek(currentPos, SeekOrigin.Begin); } - BaseStream.WriteByte((byte)(LowValue >> (24 - Offset))); + _baseStream.WriteByte((byte)(_lowValue >> (24 - offset))); - LowValue <<= Offset; - Shift = Count; - LowValue &= 0xffffff; - Count -= 8; + _lowValue <<= offset; + shift = _count; + _lowValue &= 0xffffff; + _count -= 8; } - LowValue <<= Shift; + _lowValue <<= shift; - this.Range = Range; + _range = range; } private byte PeekByte() { - byte Value = (byte)BaseStream.ReadByte(); + byte value = (byte)_baseStream.ReadByte(); - BaseStream.Seek(-1, SeekOrigin.Current); + _baseStream.Seek(-1, SeekOrigin.Current); - return Value; + return value; } public void End() { - for (int Index = 0; Index < 32; Index++) + for (int index = 0; index < 32; index++) { Write(false); } diff --git a/Ryujinx.Graphics/Vic/StructUnpacker.cs b/Ryujinx.Graphics/Vic/StructUnpacker.cs index 62777aadd2..6b6b9795c7 100644 --- a/Ryujinx.Graphics/Vic/StructUnpacker.cs +++ b/Ryujinx.Graphics/Vic/StructUnpacker.cs @@ -5,64 +5,64 @@ namespace Ryujinx.Graphics.Vic { class StructUnpacker { - private NvGpuVmm Vmm; + private NvGpuVmm _vmm; - private long Position; + private long _position; - private ulong Buffer; - private int BuffPos; + private ulong _buffer; + private int _buffPos; - public StructUnpacker(NvGpuVmm Vmm, long Position) + public StructUnpacker(NvGpuVmm vmm, long position) { - this.Vmm = Vmm; - this.Position = Position; + _vmm = vmm; + _position = position; - BuffPos = 64; + _buffPos = 64; } - public int Read(int Bits) + public int Read(int bits) { - if ((uint)Bits > 32) + if ((uint)bits > 32) { - throw new ArgumentOutOfRangeException(nameof(Bits)); + throw new ArgumentOutOfRangeException(nameof(bits)); } - int Value = 0; + int value = 0; - while (Bits > 0) + while (bits > 0) { RefillBufferIfNeeded(); - int ReadBits = Bits; + int readBits = bits; - int MaxReadBits = 64 - BuffPos; + int maxReadBits = 64 - _buffPos; - if (ReadBits > MaxReadBits) + if (readBits > maxReadBits) { - ReadBits = MaxReadBits; + readBits = maxReadBits; } - Value <<= ReadBits; + value <<= readBits; - Value |= (int)(Buffer >> BuffPos) & (int)(0xffffffff >> (32 - ReadBits)); + value |= (int)(_buffer >> _buffPos) & (int)(0xffffffff >> (32 - readBits)); - BuffPos += ReadBits; + _buffPos += readBits; - Bits -= ReadBits; + bits -= readBits; } - return Value; + return value; } private void RefillBufferIfNeeded() { - if (BuffPos >= 64) + if (_buffPos >= 64) { - Buffer = Vmm.ReadUInt64(Position); + _buffer = _vmm.ReadUInt64(_position); - Position += 8; + _position += 8; - BuffPos = 0; + _buffPos = 0; } } } diff --git a/Ryujinx.Graphics/Vic/SurfaceOutputConfig.cs b/Ryujinx.Graphics/Vic/SurfaceOutputConfig.cs index 0a232744c3..bdd55fc7c8 100644 --- a/Ryujinx.Graphics/Vic/SurfaceOutputConfig.cs +++ b/Ryujinx.Graphics/Vic/SurfaceOutputConfig.cs @@ -13,21 +13,21 @@ namespace Ryujinx.Graphics.Vic public long SurfaceChromaVAddress; public SurfaceOutputConfig( - SurfacePixelFormat PixelFormat, - int SurfaceWidth, - int SurfaceHeight, - int GobBlockHeight, - long OutputSurfaceLumaAddress, - long OutputSurfaceChromaUAddress, - long OutputSurfaceChromaVAddress) + SurfacePixelFormat pixelFormat, + int surfaceWidth, + int surfaceHeight, + int gobBlockHeight, + long outputSurfaceLumaAddress, + long outputSurfaceChromaUAddress, + long outputSurfaceChromaVAddress) { - this.PixelFormat = PixelFormat; - this.SurfaceWidth = SurfaceWidth; - this.SurfaceHeight = SurfaceHeight; - this.GobBlockHeight = GobBlockHeight; - this.SurfaceLumaAddress = OutputSurfaceLumaAddress; - this.SurfaceChromaUAddress = OutputSurfaceChromaUAddress; - this.SurfaceChromaVAddress = OutputSurfaceChromaVAddress; + PixelFormat = pixelFormat; + SurfaceWidth = surfaceWidth; + SurfaceHeight = surfaceHeight; + GobBlockHeight = gobBlockHeight; + SurfaceLumaAddress = outputSurfaceLumaAddress; + SurfaceChromaUAddress = outputSurfaceChromaUAddress; + SurfaceChromaVAddress = outputSurfaceChromaVAddress; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Vic/SurfacePixelFormat.cs b/Ryujinx.Graphics/Vic/SurfacePixelFormat.cs index ee56ac0535..8dabd09423 100644 --- a/Ryujinx.Graphics/Vic/SurfacePixelFormat.cs +++ b/Ryujinx.Graphics/Vic/SurfacePixelFormat.cs @@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Vic { enum SurfacePixelFormat { - RGBA8 = 0x1f, - YUV420P = 0x44 + Rgba8 = 0x1f, + Yuv420P = 0x44 } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Vic/VideoImageComposer.cs b/Ryujinx.Graphics/Vic/VideoImageComposer.cs index 758382fa88..e05bcfdb65 100644 --- a/Ryujinx.Graphics/Vic/VideoImageComposer.cs +++ b/Ryujinx.Graphics/Vic/VideoImageComposer.cs @@ -4,104 +4,104 @@ namespace Ryujinx.Graphics.Vic { class VideoImageComposer { - private NvGpu Gpu; + private NvGpu _gpu; - private long ConfigStructAddress; - private long OutputSurfaceLumaAddress; - private long OutputSurfaceChromaUAddress; - private long OutputSurfaceChromaVAddress; + private long _configStructAddress; + private long _outputSurfaceLumaAddress; + private long _outputSurfaceChromaUAddress; + private long _outputSurfaceChromaVAddress; - public VideoImageComposer(NvGpu Gpu) + public VideoImageComposer(NvGpu gpu) { - this.Gpu = Gpu; + _gpu = gpu; } - public void Process(NvGpuVmm Vmm, int MethodOffset, int[] Arguments) + public void Process(NvGpuVmm vmm, int methodOffset, int[] arguments) { - VideoImageComposerMeth Method = (VideoImageComposerMeth)MethodOffset; + VideoImageComposerMeth method = (VideoImageComposerMeth)methodOffset; - switch (Method) + switch (method) { case VideoImageComposerMeth.Execute: - Execute(Vmm, Arguments); + Execute(vmm, arguments); break; case VideoImageComposerMeth.SetConfigStructOffset: - SetConfigStructOffset(Vmm, Arguments); + SetConfigStructOffset(vmm, arguments); break; case VideoImageComposerMeth.SetOutputSurfaceLumaOffset: - SetOutputSurfaceLumaOffset(Vmm, Arguments); + SetOutputSurfaceLumaOffset(vmm, arguments); break; case VideoImageComposerMeth.SetOutputSurfaceChromaUOffset: - SetOutputSurfaceChromaUOffset(Vmm, Arguments); + SetOutputSurfaceChromaUOffset(vmm, arguments); break; case VideoImageComposerMeth.SetOutputSurfaceChromaVOffset: - SetOutputSurfaceChromaVOffset(Vmm, Arguments); + SetOutputSurfaceChromaVOffset(vmm, arguments); break; } } - private void Execute(NvGpuVmm Vmm, int[] Arguments) + private void Execute(NvGpuVmm vmm, int[] arguments) { - StructUnpacker Unpacker = new StructUnpacker(Vmm, ConfigStructAddress + 0x20); + StructUnpacker unpacker = new StructUnpacker(vmm, _configStructAddress + 0x20); - SurfacePixelFormat PixelFormat = (SurfacePixelFormat)Unpacker.Read(7); + SurfacePixelFormat pixelFormat = (SurfacePixelFormat)unpacker.Read(7); - int ChromaLocHoriz = Unpacker.Read(2); - int ChromaLocVert = Unpacker.Read(2); + int chromaLocHoriz = unpacker.Read(2); + int chromaLocVert = unpacker.Read(2); - int BlockLinearKind = Unpacker.Read(4); - int BlockLinearHeightLog2 = Unpacker.Read(4); + int blockLinearKind = unpacker.Read(4); + int blockLinearHeightLog2 = unpacker.Read(4); - int Reserved0 = Unpacker.Read(3); - int Reserved1 = Unpacker.Read(10); + int reserved0 = unpacker.Read(3); + int reserved1 = unpacker.Read(10); - int SurfaceWidthMinus1 = Unpacker.Read(14); - int SurfaceHeightMinus1 = Unpacker.Read(14); + int surfaceWidthMinus1 = unpacker.Read(14); + int surfaceHeightMinus1 = unpacker.Read(14); - int GobBlockHeight = 1 << BlockLinearHeightLog2; + int gobBlockHeight = 1 << blockLinearHeightLog2; - int SurfaceWidth = SurfaceWidthMinus1 + 1; - int SurfaceHeight = SurfaceHeightMinus1 + 1; + int surfaceWidth = surfaceWidthMinus1 + 1; + int surfaceHeight = surfaceHeightMinus1 + 1; - SurfaceOutputConfig OutputConfig = new SurfaceOutputConfig( - PixelFormat, - SurfaceWidth, - SurfaceHeight, - GobBlockHeight, - OutputSurfaceLumaAddress, - OutputSurfaceChromaUAddress, - OutputSurfaceChromaVAddress); + SurfaceOutputConfig outputConfig = new SurfaceOutputConfig( + pixelFormat, + surfaceWidth, + surfaceHeight, + gobBlockHeight, + _outputSurfaceLumaAddress, + _outputSurfaceChromaUAddress, + _outputSurfaceChromaVAddress); - Gpu.VideoDecoder.CopyPlanes(Vmm, OutputConfig); + _gpu.VideoDecoder.CopyPlanes(vmm, outputConfig); } - private void SetConfigStructOffset(NvGpuVmm Vmm, int[] Arguments) + private void SetConfigStructOffset(NvGpuVmm vmm, int[] arguments) { - ConfigStructAddress = GetAddress(Arguments); + _configStructAddress = GetAddress(arguments); } - private void SetOutputSurfaceLumaOffset(NvGpuVmm Vmm, int[] Arguments) + private void SetOutputSurfaceLumaOffset(NvGpuVmm vmm, int[] arguments) { - OutputSurfaceLumaAddress = GetAddress(Arguments); + _outputSurfaceLumaAddress = GetAddress(arguments); } - private void SetOutputSurfaceChromaUOffset(NvGpuVmm Vmm, int[] Arguments) + private void SetOutputSurfaceChromaUOffset(NvGpuVmm vmm, int[] arguments) { - OutputSurfaceChromaUAddress = GetAddress(Arguments); + _outputSurfaceChromaUAddress = GetAddress(arguments); } - private void SetOutputSurfaceChromaVOffset(NvGpuVmm Vmm, int[] Arguments) + private void SetOutputSurfaceChromaVOffset(NvGpuVmm vmm, int[] arguments) { - OutputSurfaceChromaVAddress = GetAddress(Arguments); + _outputSurfaceChromaVAddress = GetAddress(arguments); } - private static long GetAddress(int[] Arguments) + private static long GetAddress(int[] arguments) { - return (long)(uint)Arguments[0] << 8; + return (long)(uint)arguments[0] << 8; } } } \ No newline at end of file diff --git a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs index dbf255beee..66c3327916 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/NvFlinger.cs @@ -357,15 +357,15 @@ namespace Ryujinx.HLE.HOS.Services.Android switch (colorFormat) { case ColorFormat.A8B8G8R8: - return GalImageFormat.RGBA8 | GalImageFormat.Unorm; + return GalImageFormat.Rgba8 | GalImageFormat.Unorm; case ColorFormat.X8B8G8R8: - return GalImageFormat.RGBX8 | GalImageFormat.Unorm; + return GalImageFormat.Rgbx8 | GalImageFormat.Unorm; case ColorFormat.R5G6B5: - return GalImageFormat.BGR565 | GalImageFormat.Unorm; + return GalImageFormat.Bgr565 | GalImageFormat.Unorm; case ColorFormat.A8R8G8B8: - return GalImageFormat.BGRA8 | GalImageFormat.Unorm; + return GalImageFormat.Bgra8 | GalImageFormat.Unorm; case ColorFormat.A4B4G4R4: - return GalImageFormat.RGBA4 | GalImageFormat.Unorm; + return GalImageFormat.Rgba4 | GalImageFormat.Unorm; default: throw new NotImplementedException($"Color Format \"{colorFormat}\" not implemented!"); } diff --git a/Ryujinx.sln.DotSettings b/Ryujinx.sln.DotSettings index 737b56880c..579d97a459 100644 --- a/Ryujinx.sln.DotSettings +++ b/Ryujinx.sln.DotSettings @@ -4,4 +4,11 @@ UseExplicitType UseExplicitType <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="I" Suffix="" Style="AaBb" /></Policy> + True + True + True + True + True + True + True \ No newline at end of file diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index 52c85d568c..1b26b39188 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -16,7 +16,7 @@ namespace Ryujinx { Console.Title = "Ryujinx Console"; - IGalRenderer renderer = new OGLRenderer(); + IGalRenderer renderer = new OglRenderer(); IAalOutput audioOut = InitializeAudioEngine(); From a2a46501084d3463203da970632640a95e32e423 Mon Sep 17 00:00:00 2001 From: BaronKiko Date: Mon, 4 Mar 2019 02:51:23 +0000 Subject: [PATCH 21/36] Rebased, in theory (#610) --- Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs index f836702f5e..21edd89ee8 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs @@ -177,6 +177,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL data.Length, data); break; + case TextureTarget.TextureCubeMap: + Span array = new Span(data); + + int faceSize = ImageUtils.GetSize(image) / 6; + + for (int Face = 0; Face < 6; Face++) + { + GL.CompressedTexImage2D( + TextureTarget.TextureCubeMapPositiveX + Face, + level, + internalFmt, + image.Width, + image.Height, + border, + faceSize, + array.Slice(Face * faceSize, faceSize).ToArray()); + } + break; default: throw new NotImplementedException($"Unsupported texture target type: {target}"); } From a0aecd1ff85437890bb6a86fcc71fc90e80a4d24 Mon Sep 17 00:00:00 2001 From: BaronKiko Date: Tue, 12 Mar 2019 04:59:12 +0000 Subject: [PATCH 22/36] Compressed M2mf texture copy fix (#612) Correctly calculates the number of iterations required to copy all the data from compressed textures --- Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs index c0f444c379..45b0bbd792 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs @@ -151,6 +151,14 @@ namespace Ryujinx.Graphics.Graphics3d dstCpp); } + // Calculate the bits per pixel + int bpp = srcPitch / xCount; + + // Copying all the bits at the same time corrupts the texture, unknown why but probably because the texture isn't linear + // To avoid this we will simply loop more times to cover all the bits, + // this allows up to recalculate the memory locations for each iteration around the loop + xCount *= bpp / srcCpp; + for (int y = 0; y < yCount; y++) for (int x = 0; x < xCount; x++) { From 1bef70c068f8aeb6a3a518b8ca635de19122da14 Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Wed, 13 Mar 2019 09:23:52 +0100 Subject: [PATCH 23/36] Add Rshrn_V & Shrn_V Sse opt.. Add Mla_V, Mls_V & Mul_V Sse opt.; add Tests. (#614) * Update CountLeadingZeros(). * Remove obsolete Tests. * Follow-up. * Follow-up. * Follow-up. * Add Mla_V, Mls_V & Mul_V Tests. * Update PackageReferences. * Remove EmitLd/Stvectmp2(). * Remove Dup. Nits. * Remove EmitLd/Stvectmp2() & Dup; nits. * Remove Tmp stuff & Dup; rework Fcvtz() as Fcvtn(). * Remove Tmp stuff, EmitLd/Stvectmp2() & Dup. Nits. * Add (R)shrn_V Sse opt.; add "Part" & "Shift" opt.. Remove Tmp stuff; remove Dup. Nits. * Add Mla/Mls/Mul_V Sse opt.. Add "Part" opt.. Remove EmitLd/Stvectmp2(), remove Dup. Nits. * Nits. * Nits. * Nit. * Add "Part" opt.. Nit. * Nit. * Nit. * Add Cmhi_V & Cmhs_V Sse opt.. --- .../Instructions/InstEmitSimdArithmetic.cs | 407 ++++++++++++------ ChocolArm64/Instructions/InstEmitSimdCmp.cs | 109 +++-- ChocolArm64/Instructions/InstEmitSimdCvt.cs | 195 +++------ .../Instructions/InstEmitSimdHelper.cs | 83 ++-- .../Instructions/InstEmitSimdLogical.cs | 33 +- ChocolArm64/Instructions/InstEmitSimdShift.cs | 187 +++++--- ChocolArm64/Translation/ILEmitterCtx.cs | 6 +- Ryujinx.Common/Utilities/BitUtils.cs | 4 +- Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs | 34 -- Ryujinx.Tests/Cpu/CpuTestSimdExt.cs | 7 +- Ryujinx.Tests/Cpu/CpuTestSimdIns.cs | 11 +- Ryujinx.Tests/Cpu/CpuTestSimdReg.cs | 64 +++ Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs | 47 +- Ryujinx.Tests/Ryujinx.Tests.csproj | 4 +- 14 files changed, 707 insertions(+), 484 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs index f7236e9a4a..5ceea77491 100644 --- a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs +++ b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs @@ -1,4 +1,5 @@ // https://github.com/intel/ARM_NEON_2_x86_SSE/blob/master/NEON_2_SSE.h +// https://www.agner.org/optimize/#vectorclass @ vectori128.h using ChocolArm64.Decoders; using ChocolArm64.State; @@ -184,8 +185,8 @@ namespace ChocolArm64.Instructions if (sizeF == 0) { - Type[] typesSsv = new Type[] { typeof(float) }; - Type[] typesSubAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSsv = new Type[] { typeof(float) }; + Type[] typesSubAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdc_R4(-0f); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetScalarVector128), typesSsv)); @@ -193,8 +194,8 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), typesSubAndNot)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAndNot)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), typesSubAnt)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAnt)); context.EmitStvec(op.Rd); @@ -202,8 +203,8 @@ namespace ChocolArm64.Instructions } else /* if (sizeF == 1) */ { - Type[] typesSsv = new Type[] { typeof(double) }; - Type[] typesSubAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSsv = new Type[] { typeof(double) }; + Type[] typesSubAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); @@ -211,8 +212,8 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesSubAndNot)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SubtractScalar), typesSubAnt)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAnt)); context.EmitStvec(op.Rd); @@ -240,8 +241,8 @@ namespace ChocolArm64.Instructions if (sizeF == 0) { - Type[] typesSav = new Type[] { typeof(float) }; - Type[] typesSubAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(float) }; + Type[] typesSubAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdc_R4(-0f); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetAllVector128), typesSav)); @@ -249,8 +250,8 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesSubAndNot)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAndNot)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesSubAnt)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesSubAnt)); context.EmitStvec(op.Rd); @@ -261,8 +262,8 @@ namespace ChocolArm64.Instructions } else /* if (sizeF == 1) */ { - Type[] typesSav = new Type[] { typeof(double) }; - Type[] typesSubAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(double) }; + Type[] typesSubAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); @@ -270,8 +271,8 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSubAndNot)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSubAnt)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesSubAnt)); context.EmitStvec(op.Rd); } @@ -295,15 +296,15 @@ namespace ChocolArm64.Instructions if (op.Size == 0) { - Type[] typesSsv = new Type[] { typeof(float) }; - Type[] typesAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSsv = new Type[] { typeof(float) }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdc_R4(-0f); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetScalarVector128), typesSsv)); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesAndNot)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesAnt)); context.EmitStvec(op.Rd); @@ -311,15 +312,15 @@ namespace ChocolArm64.Instructions } else /* if (op.Size == 1) */ { - Type[] typesSsv = new Type[] { typeof(double) }; - Type[] typesAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSsv = new Type[] { typeof(double) }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetScalarVector128), typesSsv)); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); context.EmitStvec(op.Rd); @@ -345,15 +346,15 @@ namespace ChocolArm64.Instructions if (sizeF == 0) { - Type[] typesSav = new Type[] { typeof(float) }; - Type[] typesAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(float) }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdc_R4(-0f); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.SetAllVector128), typesSav)); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesAndNot)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.AndNot), typesAnt)); context.EmitStvec(op.Rd); @@ -364,15 +365,15 @@ namespace ChocolArm64.Instructions } else /* if (sizeF == 1) */ { - Type[] typesSav = new Type[] { typeof(double) }; - Type[] typesAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(double) }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdc_R8(-0d); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); context.EmitStvec(op.Rd); } @@ -429,7 +430,7 @@ namespace ChocolArm64.Instructions Type[] typesAddH = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse3).GetMethod(nameof(Sse3.HorizontalAdd), typesAddH)); @@ -442,7 +443,7 @@ namespace ChocolArm64.Instructions Type[] typesAddH = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); + context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse3).GetMethod(nameof(Sse3.HorizontalAdd), typesAddH)); @@ -748,11 +749,13 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); + + context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulAdd)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Add), typesMulAdd)); @@ -770,11 +773,13 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); + + context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulAdd)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesMulAdd)); @@ -863,11 +868,13 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); + + context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulSub)); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), typesMulSub)); @@ -885,11 +892,13 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); + + context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMulSub)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesMulSub)); @@ -1000,11 +1009,13 @@ namespace ChocolArm64.Instructions Type[] typesMul = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); + + context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 2 | op.Index << 4 | op.Index << 6); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMul)); context.EmitStvec(op.Rd); @@ -1020,11 +1031,13 @@ namespace ChocolArm64.Instructions Type[] typesMul = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); + + context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); context.EmitLdc_I4(op.Index | op.Index << 1); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Shuffle), typesSfl)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesMul)); context.EmitStvec(op.Rd); @@ -1772,11 +1785,18 @@ namespace ChocolArm64.Instructions public static void Mla_V(ILEmitterCtx context) { - EmitVectorTernaryOpZx(context, () => + if (Optimizations.UseSse41) { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Add); - }); + EmitSse41Mul_AddSub(context, nameof(Sse2.Add)); + } + else + { + EmitVectorTernaryOpZx(context, () => + { + context.Emit(OpCodes.Mul); + context.Emit(OpCodes.Add); + }); + } } public static void Mla_Ve(ILEmitterCtx context) @@ -1790,11 +1810,18 @@ namespace ChocolArm64.Instructions public static void Mls_V(ILEmitterCtx context) { - EmitVectorTernaryOpZx(context, () => + if (Optimizations.UseSse41) { - context.Emit(OpCodes.Mul); - context.Emit(OpCodes.Sub); - }); + EmitSse41Mul_AddSub(context, nameof(Sse2.Subtract)); + } + else + { + EmitVectorTernaryOpZx(context, () => + { + context.Emit(OpCodes.Mul); + context.Emit(OpCodes.Sub); + }); + } } public static void Mls_Ve(ILEmitterCtx context) @@ -1808,7 +1835,14 @@ namespace ChocolArm64.Instructions public static void Mul_V(ILEmitterCtx context) { - EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Mul)); + if (Optimizations.UseSse41) + { + EmitSse41Mul_AddSub(context); + } + else + { + EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Mul)); + } } public static void Mul_Ve(ILEmitterCtx context) @@ -1923,19 +1957,23 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -1969,13 +2007,14 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -1999,25 +2038,19 @@ namespace ChocolArm64.Instructions Type[] typesAndXorAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; context.EmitLdvec(op.Rn); - - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); - context.EmitStvectmp2(); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXorAdd)); - context.EmitLdvectmp(); - context.EmitLdvectmp2(); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXorAdd)); - context.EmitLdc_I4(1); + context.Emit(OpCodes.Ldc_I4_1); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesSra)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); context.EmitStvec(op.Rd); @@ -2185,20 +2218,24 @@ namespace ChocolArm64.Instructions ? nameof(Sse41.ConvertToVector128Int16) : nameof(Sse41.ConvertToVector128Int32); - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); @@ -2244,20 +2281,24 @@ namespace ChocolArm64.Instructions ? nameof(Sse41.ConvertToVector128Int16) : nameof(Sse41.ConvertToVector128Int32); - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); @@ -2441,19 +2482,23 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -2482,13 +2527,14 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -2594,19 +2640,23 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -2659,13 +2709,14 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -2689,25 +2740,19 @@ namespace ChocolArm64.Instructions Type[] typesAndXorAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; context.EmitLdvec(op.Rn); - - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); - context.EmitStvectmp2(); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXorAdd)); - context.EmitLdvectmp(); - context.EmitLdvectmp2(); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXorAdd)); - context.EmitLdc_I4(1); + context.Emit(OpCodes.Ldc_I4_1); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAndXorAdd)); context.EmitStvec(op.Rd); @@ -2737,8 +2782,7 @@ namespace ChocolArm64.Instructions Type[] typesAvgSub = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); - + context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Average), typesAvgSub)); @@ -2862,20 +2906,24 @@ namespace ChocolArm64.Instructions ? nameof(Sse41.ConvertToVector128Int16) : nameof(Sse41.ConvertToVector128Int32); - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); @@ -2921,20 +2969,24 @@ namespace ChocolArm64.Instructions ? nameof(Sse41.ConvertToVector128Int16) : nameof(Sse41.ConvertToVector128Int32); - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); @@ -3063,19 +3115,23 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -3104,13 +3160,14 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -3253,5 +3310,77 @@ namespace ChocolArm64.Instructions EmitVectorZeroUpper(context, op.Rd); } } + + private static void EmitSse41Mul_AddSub(ILEmitterCtx context, string nameAddSub = null) + { + OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; + + if (nameAddSub != null) + { + context.EmitLdvec(op.Rd); + } + + if (op.Size == 0) + { + Type[] typesBle = new Type[] { typeof(Vector128), typeof(Vector128), typeof(Vector128) }; + Type[] typesMul = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesShs = new Type[] { typeof(Vector128), typeof(byte) }; + Type[] typesSav = new Type[] { typeof(int) }; + + context.EmitLdvec(op.Rn); + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); + + context.EmitLdvec(op.Rm); + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyLow), typesMul)); + + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyLow), typesMul)); + + context.EmitLdc_I4(0x00FF00FF); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), typesBle)); + } + else if (op.Size == 1) + { + Type[] typesMul = new Type[] { typeof(Vector128), typeof(Vector128) }; + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MultiplyLow), typesMul)); + } + else /* if (op.Size == 2) */ + { + Type[] typesMul = new Type[] { typeof(Vector128), typeof(Vector128) }; + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + + context.EmitCall(typeof(Sse41).GetMethod(nameof(Sse41.MultiplyLow), typesMul)); + } + + if (nameAddSub != null) + { + Type[] typesAddSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; + + context.EmitCall(typeof(Sse2).GetMethod(nameAddSub, typesAddSub)); + } + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } } } diff --git a/ChocolArm64/Instructions/InstEmitSimdCmp.cs b/ChocolArm64/Instructions/InstEmitSimdCmp.cs index c29dcd9dc5..62cf772091 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCmp.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCmp.cs @@ -86,7 +86,42 @@ namespace ChocolArm64.Instructions public static void Cmhi_V(ILEmitterCtx context) { - EmitCmpOp(context, OpCodes.Bgt_Un_S, scalar: false); + OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; + + if (Optimizations.UseSse41 && op.Size < 3) + { + Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; + Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(byte) }; + + Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); + + context.EmitLdvec(op.Rm); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); + + context.EmitLdvec(op.Rm); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmp)); + + context.EmitLdc_I4(byte.MaxValue); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else + { + EmitCmpOp(context, OpCodes.Bgt_Un_S, scalar: false); + } } public static void Cmhs_S(ILEmitterCtx context) @@ -96,7 +131,35 @@ namespace ChocolArm64.Instructions public static void Cmhs_V(ILEmitterCtx context) { - EmitCmpOp(context, OpCodes.Bge_Un_S, scalar: false); + OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; + + if (Optimizations.UseSse41 && op.Size < 3) + { + Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; + Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; + + Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + + context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmp)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else + { + EmitCmpOp(context, OpCodes.Bge_Un_S, scalar: false); + } } public static void Cmle_S(ILEmitterCtx context) @@ -318,9 +381,6 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - if (cmpWithZero) { VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); @@ -331,7 +391,7 @@ namespace ChocolArm64.Instructions } context.Emit(OpCodes.Dup); - context.EmitStvectmp2(); + context.EmitStvectmp(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), typesCmp)); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); @@ -340,18 +400,18 @@ namespace ChocolArm64.Instructions context.Emit(OpCodes.Brtrue_S, lblNaN); - context.EmitLdc_I4(0); + context.Emit(OpCodes.Ldc_I4_0); + context.EmitLdvec(op.Rn); context.EmitLdvectmp(); - context.EmitLdvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualOrderedScalar), typesCmp)); + context.EmitLdvec(op.Rn); context.EmitLdvectmp(); - context.EmitLdvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), typesCmp)); + context.EmitLdvec(op.Rn); context.EmitLdvectmp(); - context.EmitLdvectmp2(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrderedScalar), typesCmp)); context.EmitStflg((int)PState.NBit); @@ -363,10 +423,10 @@ namespace ChocolArm64.Instructions context.MarkLabel(lblNaN); - context.EmitLdc_I4(1); - context.Emit(OpCodes.Dup); - context.EmitLdc_I4(0); - context.Emit(OpCodes.Dup); + context.Emit(OpCodes.Ldc_I4_1); + context.Emit(OpCodes.Ldc_I4_1); + context.Emit(OpCodes.Ldc_I4_0); + context.Emit(OpCodes.Ldc_I4_0); context.EmitStflg((int)PState.NBit); context.EmitStflg((int)PState.ZBit); @@ -384,9 +444,6 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - if (cmpWithZero) { VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); @@ -397,7 +454,7 @@ namespace ChocolArm64.Instructions } context.Emit(OpCodes.Dup); - context.EmitStvectmp2(); + context.EmitStvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrderedScalar), typesCmp)); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); @@ -406,18 +463,18 @@ namespace ChocolArm64.Instructions context.Emit(OpCodes.Brtrue_S, lblNaN); - context.EmitLdc_I4(0); + context.Emit(OpCodes.Ldc_I4_0); + context.EmitLdvec(op.Rn); context.EmitLdvectmp(); - context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqualOrderedScalar), typesCmp)); + context.EmitLdvec(op.Rn); context.EmitLdvectmp(); - context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp)); + context.EmitLdvec(op.Rn); context.EmitLdvectmp(); - context.EmitLdvectmp2(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareLessThanOrderedScalar), typesCmp)); context.EmitStflg((int)PState.NBit); @@ -429,10 +486,10 @@ namespace ChocolArm64.Instructions context.MarkLabel(lblNaN); - context.EmitLdc_I4(1); - context.Emit(OpCodes.Dup); - context.EmitLdc_I4(0); - context.Emit(OpCodes.Dup); + context.Emit(OpCodes.Ldc_I4_1); + context.Emit(OpCodes.Ldc_I4_1); + context.Emit(OpCodes.Ldc_I4_0); + context.Emit(OpCodes.Ldc_I4_0); context.EmitStflg((int)PState.NBit); context.EmitStflg((int)PState.ZBit); diff --git a/ChocolArm64/Instructions/InstEmitSimdCvt.cs b/ChocolArm64/Instructions/InstEmitSimdCvt.cs index 78a86a33eb..c5c61bcca5 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCvt.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCvt.cs @@ -21,26 +21,24 @@ namespace ChocolArm64.Instructions if (op.Size == 1 && op.Opc == 0) { //Double -> Single. - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + Type[] typesCvt = new Type[] { typeof(Vector128), typeof(Vector128) }; + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitLdvec(op.Rn); - Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Single), types)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Single), typesCvt)); context.EmitStvec(op.Rd); } else if (op.Size == 0 && op.Opc == 1) { //Single -> Double. - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); + Type[] typesCvt = new Type[] { typeof(Vector128), typeof(Vector128) }; + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); context.EmitLdvec(op.Rn); - Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), types)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), typesCvt)); context.EmitStvec(op.Rd); } @@ -80,14 +78,14 @@ namespace ChocolArm64.Instructions { Type[] typesCvt = new Type[] { typeof(Vector128) }; - string nameMov = op.RegisterSize == RegisterSize.Simd128 - ? nameof(Sse.MoveHighToLow) - : nameof(Sse.MoveLowToHigh); - context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); - context.EmitCall(typeof(Sse).GetMethod(nameMov)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveHighToLow))); + } context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Double), typesCvt)); @@ -249,12 +247,12 @@ namespace ChocolArm64.Instructions public static void Fcvtzs_S(ILEmitterCtx context) { - EmitScalarFcvtzs(context); + EmitFcvtz(context, signed: true, scalar: true); } public static void Fcvtzs_V(ILEmitterCtx context) { - EmitVectorFcvtzs(context); + EmitFcvtz(context, signed: true, scalar: false); } public static void Fcvtzu_Gp(ILEmitterCtx context) @@ -269,12 +267,12 @@ namespace ChocolArm64.Instructions public static void Fcvtzu_S(ILEmitterCtx context) { - EmitScalarFcvtzu(context); + EmitFcvtz(context, signed: false, scalar: true); } public static void Fcvtzu_V(ILEmitterCtx context) { - EmitVectorFcvtzu(context); + EmitFcvtz(context, signed: false, scalar: false); } public static void Scvtf_Gp(ILEmitterCtx context) @@ -415,11 +413,6 @@ namespace ChocolArm64.Instructions int bytes = op.GetBitsCount() >> 3; int elems = !scalar ? bytes >> sizeI : 1; - if (scalar && (sizeF == 0)) - { - EmitVectorZeroLowerTmp(context); - } - for (int index = 0; index < elems; index++) { EmitVectorExtractF(context, op.Rn, index, sizeF); @@ -441,13 +434,62 @@ namespace ChocolArm64.Instructions : nameof(VectorHelper.SatF64ToU64)); } - EmitVectorInsertTmp(context, index, sizeI); + if (scalar) + { + EmitVectorZeroAll(context, op.Rd); + } + + EmitVectorInsert(context, op.Rd, index, sizeI); } - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) + private static void EmitFcvtz(ILEmitterCtx context, bool signed, bool scalar) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + int sizeF = op.Size & 1; + int sizeI = sizeF + 2; + + int fBits = GetFBits(context); + + int bytes = op.GetBitsCount() >> 3; + int elems = !scalar ? bytes >> sizeI : 1; + + for (int index = 0; index < elems; index++) + { + EmitVectorExtractF(context, op.Rn, index, sizeF); + + EmitF2iFBitsMul(context, sizeF, fBits); + + if (sizeF == 0) + { + VectorHelper.EmitCall(context, signed + ? nameof(VectorHelper.SatF32ToS32) + : nameof(VectorHelper.SatF32ToU32)); + + context.Emit(OpCodes.Conv_U8); + } + else /* if (sizeF == 1) */ + { + VectorHelper.EmitCall(context, signed + ? nameof(VectorHelper.SatF64ToS64) + : nameof(VectorHelper.SatF64ToU64)); + } + + if (scalar) + { + EmitVectorZeroAll(context, op.Rd); + } + + EmitVectorInsert(context, op.Rd, index, sizeI); + } + + if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } @@ -555,105 +597,6 @@ namespace ChocolArm64.Instructions } } - private static void EmitScalarFcvtzs(ILEmitterCtx context) - { - EmitScalarFcvtz(context, true); - } - - private static void EmitScalarFcvtzu(ILEmitterCtx context) - { - EmitScalarFcvtz(context, false); - } - - private static void EmitScalarFcvtz(ILEmitterCtx context, bool signed) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - int sizeI = sizeF + 2; - - int fBits = GetFBits(context); - - EmitVectorExtractF(context, op.Rn, 0, sizeF); - - EmitF2iFBitsMul(context, sizeF, fBits); - - if (sizeF == 0) - { - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.SatF32ToS32) - : nameof(VectorHelper.SatF32ToU32)); - } - else /* if (sizeF == 1) */ - { - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.SatF64ToS64) - : nameof(VectorHelper.SatF64ToU64)); - } - - if (sizeF == 0) - { - context.Emit(OpCodes.Conv_U8); - } - - EmitScalarSet(context, op.Rd, sizeI); - } - - private static void EmitVectorFcvtzs(ILEmitterCtx context) - { - EmitVectorFcvtz(context, true); - } - - private static void EmitVectorFcvtzu(ILEmitterCtx context) - { - EmitVectorFcvtz(context, false); - } - - private static void EmitVectorFcvtz(ILEmitterCtx context, bool signed) - { - OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - - int sizeF = op.Size & 1; - int sizeI = sizeF + 2; - - int fBits = GetFBits(context); - - int bytes = op.GetBitsCount() >> 3; - int elems = bytes >> sizeI; - - for (int index = 0; index < elems; index++) - { - EmitVectorExtractF(context, op.Rn, index, sizeF); - - EmitF2iFBitsMul(context, sizeF, fBits); - - if (sizeF == 0) - { - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.SatF32ToS32) - : nameof(VectorHelper.SatF32ToU32)); - } - else /* if (sizeF == 1) */ - { - VectorHelper.EmitCall(context, signed - ? nameof(VectorHelper.SatF64ToS64) - : nameof(VectorHelper.SatF64ToU64)); - } - - if (sizeF == 0) - { - context.Emit(OpCodes.Conv_U8); - } - - EmitVectorInsert(context, op.Rd, index, sizeI); - } - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } - } - private static int GetFBits(ILEmitterCtx context) { if (context.CurrOp is OpCodeSimdShImm64 op) diff --git a/ChocolArm64/Instructions/InstEmitSimdHelper.cs b/ChocolArm64/Instructions/InstEmitSimdHelper.cs index b7dd09b4bb..10b86a3e17 100644 --- a/ChocolArm64/Instructions/InstEmitSimdHelper.cs +++ b/ChocolArm64/Instructions/InstEmitSimdHelper.cs @@ -592,12 +592,9 @@ namespace ChocolArm64.Instructions emit(); - EmitVectorInsertTmp(context, index, op.Size); + EmitVectorInsert(context, op.Rd, index, op.Size); } - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); @@ -898,20 +895,13 @@ namespace ChocolArm64.Instructions Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); - - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); - context.EmitStvectmp2(); - context.EmitLdc_I4(2 << 6 | 0 << 4 | 2 << 2 | 0 << 0); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); - context.EmitLdvectmp(); - context.EmitLdvectmp2(); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitLdc_I4(3 << 6 | 1 << 4 | 3 << 2 | 1 << 0); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Shuffle), typesSfl)); @@ -926,19 +916,12 @@ namespace ChocolArm64.Instructions Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); - - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); - context.EmitStvectmp2(); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackLow), types)); - context.EmitLdvectmp(); - context.EmitLdvectmp2(); + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); @@ -985,11 +968,6 @@ namespace ChocolArm64.Instructions int bytes = op.GetBitsCount() >> 3; int elems = !scalar ? bytes >> op.Size : 1; - if (scalar) - { - EmitVectorZeroLowerTmp(context); - } - for (int index = 0; index < elems; index++) { EmitVectorExtractSx(context, op.Rn, index, op.Size); @@ -1005,13 +983,15 @@ namespace ChocolArm64.Instructions EmitUnarySignedSatQAbsOrNeg(context); } - EmitVectorInsertTmp(context, index, op.Size); + if (scalar) + { + EmitVectorZeroAll(context, op.Rd); + } + + EmitVectorInsert(context, op.Rd, index, op.Size); } - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) + if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } @@ -1052,11 +1032,6 @@ namespace ChocolArm64.Instructions int bytes = op.GetBitsCount() >> 3; int elems = !scalar ? bytes >> op.Size : 1; - if (scalar) - { - EmitVectorZeroLowerTmp(context); - } - if (add || sub) { for (int index = 0; index < elems; index++) @@ -1082,7 +1057,12 @@ namespace ChocolArm64.Instructions } } - EmitVectorInsertTmp(context, index, op.Size); + if (scalar) + { + EmitVectorZeroAll(context, op.Rd); + } + + EmitVectorInsert(context, op.Rd, index, op.Size); } } else if (accumulate) @@ -1103,7 +1083,12 @@ namespace ChocolArm64.Instructions EmitBinarySatQAccumulate(context, signed); } - EmitVectorInsertTmp(context, index, op.Size); + if (scalar) + { + EmitVectorZeroAll(context, op.Rd); + } + + EmitVectorInsert(context, op.Rd, index, op.Size); } } else @@ -1117,14 +1102,16 @@ namespace ChocolArm64.Instructions EmitSatQ(context, op.Size, true, signed); - EmitVectorInsertTmp(context, index, op.Size); + if (scalar) + { + EmitVectorZeroAll(context, op.Rd); + } + + EmitVectorInsert(context, op.Rd, index, op.Size); } } - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) + if (op.RegisterSize == RegisterSize.Simd64) { EmitVectorZeroUpper(context, op.Rd); } @@ -1190,7 +1177,7 @@ namespace ChocolArm64.Instructions // TSrc (16bit, 32bit, 64bit; signed, unsigned) > TDst (8bit, 16bit, 32bit; signed, unsigned). public static void EmitSatQ(ILEmitterCtx context, int sizeDst, bool signedSrc, bool signedDst) { - if ((uint)sizeDst > 2) + if ((uint)sizeDst > 2u) { throw new ArgumentOutOfRangeException(nameof(sizeDst)); } @@ -1381,15 +1368,15 @@ namespace ChocolArm64.Instructions if (Optimizations.UseSse) { //TODO: Use Sse2.MoveScalar once it is fixed, - //as of the time of writing it just crashes the JIT (SDK 2.1.503). + //as of the time of writing it just crashes the JIT (SDK 2.1.504). /*Type[] typesMov = new Type[] { typeof(Vector128) }; - EmitLdvecWithUnsignedCast(context, reg, 3); + context.EmitLdvec(reg); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MoveScalar), typesMov)); - EmitStvecWithUnsignedCast(context, reg, 3);*/ + context.EmitStvec(reg);*/ context.EmitLdvec(reg); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); diff --git a/ChocolArm64/Instructions/InstEmitSimdLogical.cs b/ChocolArm64/Instructions/InstEmitSimdLogical.cs index 6c718182db..bf80bada3e 100644 --- a/ChocolArm64/Instructions/InstEmitSimdLogical.cs +++ b/ChocolArm64/Instructions/InstEmitSimdLogical.cs @@ -30,12 +30,12 @@ namespace ChocolArm64.Instructions { OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - Type[] typesAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); context.EmitStvec(op.Rd); @@ -79,18 +79,18 @@ namespace ChocolArm64.Instructions if (Optimizations.UseSse2) { - Type[] typesXorAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesXorAnd = new Type[] { typeof(Vector128), typeof(Vector128) }; - string nameAndNot = notRm ? nameof(Sse2.AndNot) : nameof(Sse2.And); + string nameAnd = notRm ? nameof(Sse2.AndNot) : nameof(Sse2.And); context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rd); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAndNot)); - context.EmitCall(typeof(Sse2).GetMethod(nameAndNot, typesXorAndNot)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); + context.EmitCall(typeof(Sse2).GetMethod(nameAnd, typesXorAnd)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); context.EmitStvec(op.Rd); @@ -120,7 +120,6 @@ namespace ChocolArm64.Instructions } context.Emit(OpCodes.And); - context.Emit(OpCodes.Xor); EmitVectorInsert(context, op.Rd, index, 3); @@ -142,8 +141,7 @@ namespace ChocolArm64.Instructions Type[] typesXorAnd = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rm); - context.Emit(OpCodes.Dup); - + context.EmitLdvec(op.Rm); context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); @@ -151,7 +149,6 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rd); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesXorAnd)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesXorAnd)); context.EmitStvec(op.Rd); @@ -196,15 +193,15 @@ namespace ChocolArm64.Instructions { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - Type[] typesSav = new Type[] { typeof(byte) }; - Type[] typesAndNot = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(byte) }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); context.EmitLdc_I4(byte.MaxValue); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNot)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); context.EmitStvec(op.Rd); @@ -225,8 +222,8 @@ namespace ChocolArm64.Instructions { OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - Type[] typesSav = new Type[] { typeof(byte) }; - Type[] typesAndNotOr = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(byte) }; + Type[] typesAntOr = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); @@ -234,8 +231,8 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(byte.MaxValue); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndNotOr)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndNotOr)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAntOr)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAntOr)); context.EmitStvec(op.Rd); diff --git a/ChocolArm64/Instructions/InstEmitSimdShift.cs b/ChocolArm64/Instructions/InstEmitSimdShift.cs index c0b20d7ea6..6865948ae0 100644 --- a/ChocolArm64/Instructions/InstEmitSimdShift.cs +++ b/ChocolArm64/Instructions/InstEmitSimdShift.cs @@ -5,6 +5,7 @@ using ChocolArm64.State; using ChocolArm64.Translation; using System; using System.Reflection.Emit; +using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using static ChocolArm64.Instructions.InstEmitSimdHelper; @@ -13,9 +14,65 @@ namespace ChocolArm64.Instructions { static partial class InstEmit { +#region "Masks" + private static readonly long[] _masks_RshrnShrn = new long[] + { + 14L << 56 | 12L << 48 | 10L << 40 | 08L << 32 | 06L << 24 | 04L << 16 | 02L << 8 | 00L << 0, + 13L << 56 | 12L << 48 | 09L << 40 | 08L << 32 | 05L << 24 | 04L << 16 | 01L << 8 | 00L << 0, + 11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 03L << 24 | 02L << 16 | 01L << 8 | 00L << 0 + }; +#endregion + public static void Rshrn_V(ILEmitterCtx context) { - EmitVectorShrImmNarrowOpZx(context, round: true); + if (Optimizations.UseSsse3) + { + OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; + + Type[] typesAdd = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], VectorUIntTypesPerSizeLog2[op.Size + 1] }; + Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], typeof(byte) }; + Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { UIntTypesPerSizeLog2[op.Size + 1] }; + Type[] typesSve = new Type[] { typeof(long), typeof(long) }; + + string nameMov = op.RegisterSize == RegisterSize.Simd128 + ? nameof(Sse.MoveLowToHigh) + : nameof(Sse.MoveHighToLow); + + int shift = GetImmShr(op); + + long roundConst = 1L << (shift - 1); + + context.EmitLdvec(op.Rd); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); + + context.EmitLdvec(op.Rn); + + context.EmitLdc_I8(roundConst); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); + + context.EmitLdc_I4(shift); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); // value + + context.EmitLdc_I8(_masks_RshrnShrn[op.Size]); // mask + context.Emit(OpCodes.Dup); // mask + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); + + context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); + + context.EmitCall(typeof(Sse).GetMethod(nameMov)); + + context.EmitStvec(op.Rd); + } + else + { + EmitVectorShrImmNarrowOpZx(context, round: true); + } } public static void Shl_S(ILEmitterCtx context) @@ -80,12 +137,13 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); @@ -102,7 +160,45 @@ namespace ChocolArm64.Instructions public static void Shrn_V(ILEmitterCtx context) { - EmitVectorShrImmNarrowOpZx(context, round: false); + if (Optimizations.UseSsse3) + { + OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; + + Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], typeof(byte) }; + Type[] typesSfl = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSve = new Type[] { typeof(long), typeof(long) }; + + string nameMov = op.RegisterSize == RegisterSize.Simd128 + ? nameof(Sse.MoveLowToHigh) + : nameof(Sse.MoveHighToLow); + + int shift = GetImmShr(op); + + context.EmitLdvec(op.Rd); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.MoveLowToHigh))); + + context.EmitLdvec(op.Rn); + + context.EmitLdc_I4(shift); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); // value + + context.EmitLdc_I8(_masks_RshrnShrn[op.Size]); // mask + context.Emit(OpCodes.Dup); // mask + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSve)); + + context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesSfl)); + + context.EmitCall(typeof(Sse).GetMethod(nameMov)); + + context.EmitStvec(op.Rd); + } + else + { + EmitVectorShrImmNarrowOpZx(context, round: false); + } } public static void Sli_V(ILEmitterCtx context) @@ -271,8 +367,7 @@ namespace ChocolArm64.Instructions { OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - if (Optimizations.UseSse2 && op.Size > 0 - && op.Size < 3) + if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) { Type[] typesShs = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; @@ -282,16 +377,13 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - context.EmitLdc_I4(eSize - shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); context.EmitLdc_I4(eSize - 1); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - context.EmitLdvectmp(); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesShs)); @@ -320,8 +412,7 @@ namespace ChocolArm64.Instructions { OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - if (Optimizations.UseSse2 && op.Size > 0 - && op.Size < 3) + if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) { Type[] typesShs = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; @@ -332,16 +423,13 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - context.EmitLdc_I4(eSize - shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); context.EmitLdc_I4(eSize - 1); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - context.EmitLdvectmp(); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesShs)); @@ -403,17 +491,21 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); + if (shift != 0) + { + context.EmitLdc_I4(shift); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); + } context.EmitStvec(op.Rd); } @@ -432,8 +524,7 @@ namespace ChocolArm64.Instructions { OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - if (Optimizations.UseSse2 && op.Size > 0 - && op.Size < 3) + if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) { Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; @@ -464,8 +555,7 @@ namespace ChocolArm64.Instructions { OpCodeSimdShImm64 op = (OpCodeSimdShImm64)context.CurrOp; - if (Optimizations.UseSse2 && op.Size > 0 - && op.Size < 3) + if (Optimizations.UseSse2 && op.Size > 0 && op.Size < 3) { Type[] typesSra = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; Type[] typesAdd = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; @@ -474,8 +564,8 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); context.EmitLdc_I4(GetImmShr(op)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), typesSra)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); context.EmitStvec(op.Rd); @@ -612,16 +702,13 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - context.EmitLdc_I4(eSize - shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); context.EmitLdc_I4(eSize - 1); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - context.EmitLdvectmp(); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); @@ -661,16 +748,13 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rd); context.EmitLdvec(op.Rn); - context.Emit(OpCodes.Dup); - context.EmitStvectmp(); - context.EmitLdc_I4(eSize - shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesShs)); context.EmitLdc_I4(eSize - 1); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); - context.EmitLdvectmp(); + context.EmitLdvec(op.Rn); context.EmitLdc_I4(shift); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesShs)); @@ -732,17 +816,21 @@ namespace ChocolArm64.Instructions nameof(Sse41.ConvertToVector128Int32), nameof(Sse41.ConvertToVector128Int64) }; - int numBytes = op.RegisterSize == RegisterSize.Simd128 ? 8 : 0; - context.EmitLdvec(op.Rn); - context.EmitLdc_I4(numBytes); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSll)); + } context.EmitCall(typeof(Sse41).GetMethod(namesCvt[op.Size], typesCvt)); - context.EmitLdc_I4(shift); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); + if (shift != 0) + { + context.EmitLdc_I4(shift); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSll)); + } context.EmitStvec(op.Rd); } @@ -801,8 +889,8 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rn); context.EmitLdc_I4(GetImmShr(op)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrl)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); context.EmitStvec(op.Rd); @@ -899,12 +987,9 @@ namespace ChocolArm64.Instructions context.Emit(OpCodes.Add); } - EmitVectorInsertTmp(context, index, op.Size); + EmitVectorInsert(context, op.Rd, index, op.Size); } - context.EmitLdvectmp(); - context.EmitStvec(op.Rd); - if ((op.RegisterSize == RegisterSize.Simd64) || scalar) { EmitVectorZeroUpper(context, op.Rd); @@ -1044,11 +1129,7 @@ namespace ChocolArm64.Instructions } // dst64 = (Int(src64, signed) + roundConst) >> shift; - private static void EmitShrImm64( - ILEmitterCtx context, - bool signed, - long roundConst, - int shift) + private static void EmitShrImm64(ILEmitterCtx context, bool signed, long roundConst, int shift) { context.EmitLdc_I8(roundConst); context.EmitLdc_I4(shift); diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs index 91b72b13ae..f39bd37112 100644 --- a/ChocolArm64/Translation/ILEmitterCtx.cs +++ b/ChocolArm64/Translation/ILEmitterCtx.cs @@ -61,8 +61,7 @@ namespace ChocolArm64.Translation //Vectors are part of another "set" of locals. private const int VecGpTmp1Index = ReservedLocalsCount + 0; - private const int VecGpTmp2Index = ReservedLocalsCount + 1; - private const int UserVecTempStart = ReservedLocalsCount + 2; + private const int UserVecTempStart = ReservedLocalsCount + 1; private static int _userIntTempCount; private static int _userVecTempCount; @@ -630,9 +629,6 @@ namespace ChocolArm64.Translation public void EmitLdvectmp() => EmitLdvec(VecGpTmp1Index); public void EmitStvectmp() => EmitStvec(VecGpTmp1Index); - public void EmitLdvectmp2() => EmitLdvec(VecGpTmp2Index); - public void EmitStvectmp2() => EmitStvec(VecGpTmp2Index); - public void EmitLdint(int index) => Ldloc(index, VarType.Int); public void EmitStint(int index) => Stloc(index, VarType.Int); diff --git a/Ryujinx.Common/Utilities/BitUtils.cs b/Ryujinx.Common/Utilities/BitUtils.cs index b6fba4fba1..5f70f742a0 100644 --- a/Ryujinx.Common/Utilities/BitUtils.cs +++ b/Ryujinx.Common/Utilities/BitUtils.cs @@ -100,7 +100,7 @@ namespace Ryujinx.Common do { nibbleIdx -= 4; - preCount = ClzNibbleTbl[(value >> nibbleIdx) & 0b1111]; + preCount = ClzNibbleTbl[(int)(value >> nibbleIdx) & 0b1111]; count += preCount; } while (preCount == 4); @@ -136,4 +136,4 @@ namespace Ryujinx.Common return (value >> 32) | (value << 32); } } -} \ No newline at end of file +} diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs index 2f8604ebac..63e0bda83c 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdArithmetic.cs @@ -8,26 +8,6 @@ namespace Ryujinx.Tests.Cpu { public class CpuTestSimdArithmetic : CpuTest { - [TestCase(0x00000000u, 0x7F800000u)] - [TestCase(0x80000000u, 0xFF800000u)] - [TestCase(0x00FFF000u, 0x7E000000u)] - [TestCase(0x41200000u, 0x3DCC8000u)] - [TestCase(0xC1200000u, 0xBDCC8000u)] - [TestCase(0x001FFFFFu, 0x7F800000u)] - [TestCase(0x007FF000u, 0x7E800000u)] - public void Frecpe_S(uint a, uint result) - { - uint opcode = 0x5EA1D820; // FRECPE S0, S1 - - Vector128 v1 = MakeVectorE0(a); - - CpuThreadState threadState = SingleOpcode(opcode, v1: v1); - - Assert.That(GetVectorE0(threadState.V0), Is.EqualTo(result)); - - CompareAgainstUnicorn(); - } - [TestCase(0x3FE66666u, false, 0x40000000u)] [TestCase(0x3F99999Au, false, 0x3F800000u)] [TestCase(0x404CCCCDu, false, 0x40400000u)] @@ -601,19 +581,5 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } - - [TestCase(0x41200000u, 0x3EA18000u)] - public void Frsqrte_S(uint a, uint result) - { - uint opcode = 0x7EA1D820; // FRSQRTE S0, S1 - - Vector128 v1 = MakeVectorE0(a); - - CpuThreadState threadState = SingleOpcode(opcode, v1: v1); - - Assert.That(GetVectorE0(threadState.V0), Is.EqualTo(result)); - - CompareAgainstUnicorn(); - } } } diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs b/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs index f232989f77..b8548169be 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs @@ -19,7 +19,8 @@ namespace Ryujinx.Tests.Cpu } #endregion - private const int RndCnt = 2; + private const int RndCnt = 2; + private const int RndCntIndex = 2; [Test, Pairwise, Description("EXT .8B, .8B, .8B, #")] public void Ext_V_8B([Values(0u)] uint rd, @@ -28,7 +29,7 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_8B_")] [Random(RndCnt)] ulong z, [ValueSource("_8B_")] [Random(RndCnt)] ulong a, [ValueSource("_8B_")] [Random(RndCnt)] ulong b, - [Range(0u, 7u)] uint index) + [Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index) { uint imm4 = index & 0x7u; @@ -52,7 +53,7 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_8B_")] [Random(RndCnt)] ulong z, [ValueSource("_8B_")] [Random(RndCnt)] ulong a, [ValueSource("_8B_")] [Random(RndCnt)] ulong b, - [Range(0u, 15u)] uint index) + [Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index) { uint imm4 = index & 0xFu; diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs b/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs index 4ca54a2b42..fe93f06e37 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs @@ -67,7 +67,8 @@ namespace Ryujinx.Tests.Cpu } #endregion - private const int RndCnt = 2; + private const int RndCnt = 2; + private const int RndCntIndex = 2; [Test, Pairwise, Description("DUP ., ")] public void Dup_Gp_W([Values(0u)] uint rd, @@ -109,7 +110,7 @@ namespace Ryujinx.Tests.Cpu [Test, Pairwise, Description("DUP B0, V1.B[]")] public void Dup_S_B([ValueSource("_8B_")] [Random(RndCnt)] ulong a, - [Range(0u, 15u)] uint index) + [Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index) { const int size = 0; @@ -129,7 +130,7 @@ namespace Ryujinx.Tests.Cpu [Test, Pairwise, Description("DUP H0, V1.H[]")] public void Dup_S_H([ValueSource("_4H_")] [Random(RndCnt)] ulong a, - [Range(0u, 7u)] uint index) + [Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index) { const int size = 1; @@ -192,7 +193,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_8B_")] [Random(RndCnt)] ulong z, [ValueSource("_8B_")] [Random(RndCnt)] ulong a, - [Range(0u, 15u)] uint index, + [Values(0u, 15u)] [Random(1u, 14u, RndCntIndex)] uint index, [Values(0b0u, 0b1u)] uint q) // <8B, 16B> { const int size = 0; @@ -217,7 +218,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_4H_")] [Random(RndCnt)] ulong z, [ValueSource("_4H_")] [Random(RndCnt)] ulong a, - [Range(0u, 7u)] uint index, + [Values(0u, 7u)] [Random(1u, 6u, RndCntIndex)] uint index, [Values(0b0u, 0b1u)] uint q) // <4H, 8H> { const int size = 1; diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs b/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs index 8d2f4e9a34..1c418341b6 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs @@ -434,6 +434,26 @@ namespace Ryujinx.Tests.Cpu }; } + private static uint[] _Mla_Mls_Mul_V_8B_4H_2S_() + { + return new uint[] + { + 0x0E209400u, // MLA V0.8B, V0.8B, V0.8B + 0x2E209400u, // MLS V0.8B, V0.8B, V0.8B + 0x0E209C00u // MUL V0.8B, V0.8B, V0.8B + }; + } + + private static uint[] _Mla_Mls_Mul_V_16B_8H_4S_() + { + return new uint[] + { + 0x4E209400u, // MLA V0.16B, V0.16B, V0.16B + 0x6E209400u, // MLS V0.16B, V0.16B, V0.16B + 0x4E209C00u // MUL V0.16B, V0.16B, V0.16B + }; + } + private static uint[] _Sha1c_Sha1m_Sha1p_Sha1su0_V_() { return new uint[] @@ -1786,6 +1806,50 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(Fpsr.Ioc | Fpsr.Idc, FpSkips.IfUnderflow, FpTolerances.UpToOneUlpsD); } + [Test, Pairwise] + public void Mla_Mls_Mul_V_8B_4H_2S([ValueSource("_Mla_Mls_Mul_V_8B_4H_2S_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [Values(2u, 0u)] uint rm, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong a, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <8B, 4H, 2S> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((size & 3) << 22); + + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0(a); + Vector128 v2 = MakeVectorE0(b); + + SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void Mla_Mls_Mul_V_16B_8H_4S([ValueSource("_Mla_Mls_Mul_V_16B_8H_4S_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [Values(2u, 0u)] uint rm, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong a, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b, + [Values(0b00u, 0b01u, 0b10u)] uint size) // <16B, 8H, 4S> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((size & 3) << 22); + + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(a, a); + Vector128 v2 = MakeVectorE0E1(b, b); + + SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } + [Test, Pairwise, Description("ORN ., ., .")] public void Orn_V_8B([Values(0u)] uint rd, [Values(1u, 0u)] uint rn, diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs index f026158cc7..9a295d5ed1 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs @@ -258,14 +258,15 @@ namespace Ryujinx.Tests.Cpu } #endregion - private const int RndCnt = 2; + private const int RndCnt = 2; + private const int RndCntShift = 2; [Test, Pairwise, Description("SHL , , #")] public void Shl_S_D([Values(0u)] uint rd, [Values(1u, 0u)] uint rn, [ValueSource("_1D_")] [Random(RndCnt)] ulong z, [ValueSource("_1D_")] [Random(RndCnt)] ulong a, - [Range(0u, 63u)] uint shift) + [Values(0u, 63u)] [Random(1u, 62u, RndCntShift)] uint shift) { uint immHb = (64 + shift) & 0x7F; @@ -286,7 +287,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_8B_")] [Random(RndCnt)] ulong z, [ValueSource("_8B_")] [Random(RndCnt)] ulong a, - [Range(0u, 7u)] uint shift, + [Values(0u, 7u)] [Random(1u, 6u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <8B, 16B> { uint immHb = (8 + shift) & 0x7F; @@ -309,7 +310,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_4H_")] [Random(RndCnt)] ulong z, [ValueSource("_4H_")] [Random(RndCnt)] ulong a, - [Range(0u, 15u)] uint shift, + [Values(0u, 15u)] [Random(1u, 14u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <4H, 8H> { uint immHb = (16 + shift) & 0x7F; @@ -332,7 +333,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_2S_")] [Random(RndCnt)] ulong z, [ValueSource("_2S_")] [Random(RndCnt)] ulong a, - [Range(0u, 31u)] uint shift, + [Values(0u, 31u)] [Random(1u, 30u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <2S, 4S> { uint immHb = (32 + shift) & 0x7F; @@ -355,7 +356,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_1D_")] [Random(RndCnt)] ulong z, [ValueSource("_1D_")] [Random(RndCnt)] ulong a, - [Range(0u, 63u)] uint shift) + [Values(0u, 63u)] [Random(1u, 62u, RndCntShift)] uint shift) { uint immHb = (64 + shift) & 0x7F; @@ -377,7 +378,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_8B_")] [Random(RndCnt)] ulong z, [ValueSource("_8B_")] [Random(RndCnt)] ulong a, - [Range(0u, 7u)] uint shift, + [Values(0u, 7u)] [Random(1u, 6u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <8B8H, 16B8H> { uint immHb = (8 + shift) & 0x7F; @@ -400,7 +401,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_4H_")] [Random(RndCnt)] ulong z, [ValueSource("_4H_")] [Random(RndCnt)] ulong a, - [Range(0u, 15u)] uint shift, + [Values(0u, 15u)] [Random(1u, 14u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <4H4S, 8H4S> { uint immHb = (16 + shift) & 0x7F; @@ -423,7 +424,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_2S_")] [Random(RndCnt)] ulong z, [ValueSource("_2S_")] [Random(RndCnt)] ulong a, - [Range(0u, 31u)] uint shift, + [Values(0u, 31u)] [Random(1u, 30u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <2S2D, 4S2D> { uint immHb = (32 + shift) & 0x7F; @@ -446,7 +447,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_1D_")] [Random(RndCnt)] ulong z, [ValueSource("_1D_")] [Random(RndCnt)] ulong a, - [Range(1u, 64u)] uint shift) + [Values(1u, 64u)] [Random(2u, 63u, RndCntShift)] uint shift) { uint immHb = (128 - shift) & 0x7F; @@ -467,7 +468,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_8B_")] [Random(RndCnt)] ulong z, [ValueSource("_8B_")] [Random(RndCnt)] ulong a, - [Range(1u, 8u)] uint shift, + [Values(1u, 8u)] [Random(2u, 7u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <8B, 16B> { uint immHb = (16 - shift) & 0x7F; @@ -490,7 +491,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_4H_")] [Random(RndCnt)] ulong z, [ValueSource("_4H_")] [Random(RndCnt)] ulong a, - [Range(1u, 16u)] uint shift, + [Values(1u, 16u)] [Random(2u, 15u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <4H, 8H> { uint immHb = (32 - shift) & 0x7F; @@ -513,7 +514,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_2S_")] [Random(RndCnt)] ulong z, [ValueSource("_2S_")] [Random(RndCnt)] ulong a, - [Range(1u, 32u)] uint shift, + [Values(1u, 32u)] [Random(2u, 31u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <2S, 4S> { uint immHb = (64 - shift) & 0x7F; @@ -536,7 +537,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_1D_")] [Random(RndCnt)] ulong z, [ValueSource("_1D_")] [Random(RndCnt)] ulong a, - [Range(1u, 64u)] uint shift) + [Values(1u, 64u)] [Random(2u, 63u, RndCntShift)] uint shift) { uint immHb = (128 - shift) & 0x7F; @@ -557,7 +558,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_4H_")] [Random(RndCnt)] ulong z, [ValueSource("_4H_")] [Random(RndCnt)] ulong a, - [Range(1u, 8u)] uint shift, + [Values(1u, 8u)] [Random(2u, 7u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <8H8B, 8H16B> { uint immHb = (16 - shift) & 0x7F; @@ -580,7 +581,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_2S_")] [Random(RndCnt)] ulong z, [ValueSource("_2S_")] [Random(RndCnt)] ulong a, - [Range(1u, 16u)] uint shift, + [Values(1u, 16u)] [Random(2u, 15u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <4S4H, 4S8H> { uint immHb = (32 - shift) & 0x7F; @@ -603,7 +604,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_1D_")] [Random(RndCnt)] ulong z, [ValueSource("_1D_")] [Random(RndCnt)] ulong a, - [Range(1u, 32u)] uint shift, + [Values(1u, 32u)] [Random(2u, 31u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <2D2S, 2D4S> { uint immHb = (64 - shift) & 0x7F; @@ -626,7 +627,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_1H_")] [Random(RndCnt)] ulong z, [ValueSource("_1H_")] [Random(RndCnt)] ulong a, - [Range(1u, 8u)] uint shift) + [Values(1u, 8u)] [Random(2u, 7u, RndCntShift)] uint shift) { uint immHb = (16 - shift) & 0x7F; @@ -647,7 +648,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_1S_")] [Random(RndCnt)] ulong z, [ValueSource("_1S_")] [Random(RndCnt)] ulong a, - [Range(1u, 16u)] uint shift) + [Values(1u, 16u)] [Random(2u, 15u, RndCntShift)] uint shift) { uint immHb = (32 - shift) & 0x7F; @@ -668,7 +669,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_1D_")] [Random(RndCnt)] ulong z, [ValueSource("_1D_")] [Random(RndCnt)] ulong a, - [Range(1u, 32u)] uint shift) + [Values(1u, 32u)] [Random(2u, 31u, RndCntShift)] uint shift) { uint immHb = (64 - shift) & 0x7F; @@ -689,7 +690,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_4H_")] [Random(RndCnt)] ulong z, [ValueSource("_4H_")] [Random(RndCnt)] ulong a, - [Range(1u, 8u)] uint shift, + [Values(1u, 8u)] [Random(2u, 7u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <8H8B, 8H16B> { uint immHb = (16 - shift) & 0x7F; @@ -712,7 +713,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_2S_")] [Random(RndCnt)] ulong z, [ValueSource("_2S_")] [Random(RndCnt)] ulong a, - [Range(1u, 16u)] uint shift, + [Values(1u, 16u)] [Random(2u, 15u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <4S4H, 4S8H> { uint immHb = (32 - shift) & 0x7F; @@ -735,7 +736,7 @@ namespace Ryujinx.Tests.Cpu [Values(1u, 0u)] uint rn, [ValueSource("_1D_")] [Random(RndCnt)] ulong z, [ValueSource("_1D_")] [Random(RndCnt)] ulong a, - [Range(1u, 32u)] uint shift, + [Values(1u, 32u)] [Random(2u, 31u, RndCntShift)] uint shift, [Values(0b0u, 0b1u)] uint q) // <2D2S, 2D4S> { uint immHb = (64 - shift) & 0x7F; diff --git a/Ryujinx.Tests/Ryujinx.Tests.csproj b/Ryujinx.Tests/Ryujinx.Tests.csproj index 35405c769f..ce94326d24 100644 --- a/Ryujinx.Tests/Ryujinx.Tests.csproj +++ b/Ryujinx.Tests/Ryujinx.Tests.csproj @@ -16,9 +16,9 @@ - + - + From efebd8f94de03ef5cab63803f0cf37fc39258682 Mon Sep 17 00:00:00 2001 From: jduncanator <1518948+jduncanator@users.noreply.github.com> Date: Fri, 15 Mar 2019 14:37:54 +1100 Subject: [PATCH 24/36] Print Guest Stack Trace in ServiceNotImplemented Exception (#650) * Print Guest Stack Trace in ServiceNotImplemented Exception * Remove PrintGuestStackTrace * Print Process Name and PID at the start of guest stack trace --- .../ServiceNotImplementedException.cs | 84 +++++++++++-------- Ryujinx.HLE/HOS/Ipc/IpcHandler.cs | 3 + .../HOS/Kernel/Process/HleProcessDebugger.cs | 17 ++-- .../HOS/Kernel/SupervisorCall/SvcIpc.cs | 1 + Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs | 14 +++- Ryujinx.HLE/HOS/ServiceCtx.cs | 4 + 6 files changed, 76 insertions(+), 47 deletions(-) diff --git a/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs b/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs index d5ea3bbfa1..893ce26e7b 100644 --- a/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs +++ b/Ryujinx.HLE/Exceptions/ServiceNotImplementedException.cs @@ -76,60 +76,70 @@ namespace Ryujinx.HLE.Exceptions } } + sb.AppendLine("Guest Stack Trace:"); + sb.AppendLine(Context.Thread.GetGuestStackTrace()); + // Print buffer information - sb.AppendLine("Buffer Information"); - - if (Request.PtrBuff.Count > 0) + if (Request.PtrBuff.Count > 0 || + Request.SendBuff.Count > 0 || + Request.ReceiveBuff.Count > 0 || + Request.ExchangeBuff.Count > 0 || + Request.RecvListBuff.Count > 0) { - sb.AppendLine("\tPtrBuff:"); + sb.AppendLine("Buffer Information:"); - foreach (var buff in Request.PtrBuff) + if (Request.PtrBuff.Count > 0) { - sb.AppendLine($"\t[{buff.Index}] Position: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}"); + sb.AppendLine("\tPtrBuff:"); + + foreach (var buff in Request.PtrBuff) + { + sb.AppendLine($"\t[{buff.Index}] Position: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}"); + } } - } - if (Request.SendBuff.Count > 0) - { - sb.AppendLine("\tSendBuff:"); - - foreach (var buff in Request.SendBuff) + if (Request.SendBuff.Count > 0) { - sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); + sb.AppendLine("\tSendBuff:"); + + foreach (var buff in Request.SendBuff) + { + sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); + } } - } - if (Request.ReceiveBuff.Count > 0) - { - sb.AppendLine("\tReceiveBuff:"); - - foreach (var buff in Request.ReceiveBuff) + if (Request.ReceiveBuff.Count > 0) { - sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); + sb.AppendLine("\tReceiveBuff:"); + + foreach (var buff in Request.ReceiveBuff) + { + sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); + } } - } - if (Request.ExchangeBuff.Count > 0) - { - sb.AppendLine("\tExchangeBuff:"); - - foreach (var buff in Request.ExchangeBuff) + if (Request.ExchangeBuff.Count > 0) { - sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); + sb.AppendLine("\tExchangeBuff:"); + + foreach (var buff in Request.ExchangeBuff) + { + sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16} Flags: {buff.Flags}"); + } } - } - if (Request.RecvListBuff.Count > 0) - { - sb.AppendLine("\tRecvListBuff:"); - - foreach (var buff in Request.RecvListBuff) + if (Request.RecvListBuff.Count > 0) { - sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}"); - } - } + sb.AppendLine("\tRecvListBuff:"); - sb.AppendLine(); + foreach (var buff in Request.RecvListBuff) + { + sb.AppendLine($"\tPosition: 0x{buff.Position:x16} Size: 0x{buff.Size:x16}"); + } + } + + sb.AppendLine(); + } sb.AppendLine("Raw Request Data:"); sb.Append(HexUtils.HexTable(Request.RawData)); diff --git a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs index 1eba4b4124..9f087a1a04 100644 --- a/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs +++ b/Ryujinx.HLE/HOS/Ipc/IpcHandler.cs @@ -2,6 +2,7 @@ using ChocolArm64.Memory; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Ipc; using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Kernel.Threading; using System; using System.IO; @@ -13,6 +14,7 @@ namespace Ryujinx.HLE.HOS.Ipc Switch device, KProcess process, MemoryManager memory, + KThread thread, KClientSession session, IpcMessage request, long cmdPtr) @@ -36,6 +38,7 @@ namespace Ryujinx.HLE.HOS.Ipc device, process, memory, + thread, session, request, response, diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs index 0268de7d07..d31f95b43e 100644 --- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs +++ b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs @@ -4,6 +4,7 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Diagnostics.Demangler; using Ryujinx.HLE.HOS.Kernel.Memory; using Ryujinx.HLE.Loaders.Elf; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -41,14 +42,12 @@ namespace Ryujinx.HLE.HOS.Kernel.Process _images = new List(); } - public void PrintGuestStackTrace(CpuThreadState threadState) + public string GetGuestStackTrace(CpuThreadState threadState) { EnsureLoaded(); StringBuilder trace = new StringBuilder(); - trace.AppendLine("Guest stack trace:"); - void AppendTrace(long address) { Image image = GetImage(address, out int imageIndex); @@ -68,22 +67,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Process string imageName = GetGuessedNsoNameFromIndex(imageIndex); - string imageNameAndOffset = $"[{_owner.Name}] {imageName}:0x{offset:x8}"; - - trace.AppendLine($" {imageNameAndOffset} {subName}"); + trace.AppendLine($" {imageName}:0x{offset:x8} {subName}"); } else { - trace.AppendLine($" [{_owner.Name}] ??? {subName}"); + trace.AppendLine($" ??? {subName}"); } } //TODO: ARM32. long framePointer = (long)threadState.X29; + trace.AppendLine($"Process: {_owner.Name}, PID: {_owner.Pid}"); + while (framePointer != 0) { - if ((framePointer & 7) != 0 || + if ((framePointer & 7) != 0 || !_owner.CpuMemory.IsMapped(framePointer) || !_owner.CpuMemory.IsMapped(framePointer + 8)) { @@ -97,7 +96,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process framePointer = _owner.CpuMemory.ReadInt64(framePointer); } - Logger.PrintInfo(LogClass.Cpu, trace.ToString()); + return trace.ToString(); } private bool TryGetSubName(Image image, long address, out string name) diff --git a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs index e19d9d2687..eb7595c0a2 100644 --- a/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs +++ b/Ryujinx.HLE/HOS/Kernel/SupervisorCall/SvcIpc.cs @@ -143,6 +143,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall _device, _process, _process.CpuMemory, + ipcMessage.Thread, ipcMessage.Session, ipcMessage.Message, ipcMessage.MessagePtr); diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs index 17e0f3c3bf..ebde34baf1 100644 --- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs +++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs @@ -1,10 +1,12 @@ using ChocolArm64; using ChocolArm64.Memory; +using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Process; using System; using System.Collections.Generic; using System.Linq; +using System.Text; namespace Ryujinx.HLE.HOS.Kernel.Threading { @@ -1009,9 +1011,19 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading ReleaseAndResume(); } + public string GetGuestStackTrace() + { + return Owner.Debugger.GetGuestStackTrace(Context.ThreadState); + } + public void PrintGuestStackTrace() { - Owner.Debugger.PrintGuestStackTrace(Context.ThreadState); + StringBuilder trace = new StringBuilder(); + + trace.AppendLine("Guest stack trace:"); + trace.AppendLine(GetGuestStackTrace()); + + Logger.PrintInfo(LogClass.Cpu, trace.ToString()); } private void ThreadFinishedHandler(object sender, EventArgs e) diff --git a/Ryujinx.HLE/HOS/ServiceCtx.cs b/Ryujinx.HLE/HOS/ServiceCtx.cs index af42d41762..99b2d5afe6 100644 --- a/Ryujinx.HLE/HOS/ServiceCtx.cs +++ b/Ryujinx.HLE/HOS/ServiceCtx.cs @@ -2,6 +2,7 @@ using ChocolArm64.Memory; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Ipc; using Ryujinx.HLE.HOS.Kernel.Process; +using Ryujinx.HLE.HOS.Kernel.Threading; using System.IO; namespace Ryujinx.HLE.HOS @@ -11,6 +12,7 @@ namespace Ryujinx.HLE.HOS public Switch Device { get; } public KProcess Process { get; } public MemoryManager Memory { get; } + public KThread Thread { get; } public KClientSession Session { get; } public IpcMessage Request { get; } public IpcMessage Response { get; } @@ -21,6 +23,7 @@ namespace Ryujinx.HLE.HOS Switch device, KProcess process, MemoryManager memory, + KThread thread, KClientSession session, IpcMessage request, IpcMessage response, @@ -30,6 +33,7 @@ namespace Ryujinx.HLE.HOS Device = device; Process = process; Memory = memory; + Thread = thread; Session = session; Request = request; Response = response; From 1b2e430e887fc2eac372c46255c18ecceb032fd1 Mon Sep 17 00:00:00 2001 From: BaronKiko Date: Sun, 17 Mar 2019 22:55:02 +0000 Subject: [PATCH 25/36] Cubemap array support (#649) --- Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs index 21edd89ee8..191f6e3deb 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs @@ -165,6 +165,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL data.Length, data); break; + // Cube map arrays are just 2D texture arrays with 6 entries + // per cube map so we can handle them in the same way + case TextureTarget.TextureCubeMapArray: case TextureTarget.Texture2DArray: GL.CompressedTexImage3D( target, @@ -263,6 +266,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL type, data); break; + // Cube map arrays are just 2D texture arrays with 6 entries + // per cube map so we can handle them in the same way + case TextureTarget.TextureCubeMapArray: case TextureTarget.Texture2DArray: GL.TexImage3D( target, From c106ae994425e384a9ad8d6d00747af71e8475a6 Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Sat, 23 Mar 2019 19:50:19 +0100 Subject: [PATCH 26/36] Add Tbl_V Sse opt. with Tests. (#651) * Add v4, v5, v30, v31 required for Tbl_V Tests. * Add Tests for Tbl_V. * Add Tbl_V Sse opt.. * Nit. * Small opt. on comparison constant vector. * Nit. * Add EmitLd/Stvectmp2/3. * Nit. --- ChocolArm64/Instructions/InstEmitSimdMove.cs | 101 ++++-- ChocolArm64/Translation/ILEmitterCtx.cs | 10 +- Ryujinx.Tests/Cpu/CpuTest.cs | 50 ++- Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs | 315 +++++++++++++++++++ 4 files changed, 437 insertions(+), 39 deletions(-) create mode 100644 Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs diff --git a/ChocolArm64/Instructions/InstEmitSimdMove.cs b/ChocolArm64/Instructions/InstEmitSimdMove.cs index 20647ce09d..cdd351718c 100644 --- a/ChocolArm64/Instructions/InstEmitSimdMove.cs +++ b/ChocolArm64/Instructions/InstEmitSimdMove.cs @@ -355,35 +355,94 @@ namespace ChocolArm64.Instructions { OpCodeSimdTbl64 op = (OpCodeSimdTbl64)context.CurrOp; - context.EmitLdvec(op.Rm); - - for (int index = 0; index < op.Size; index++) + if (Optimizations.UseSsse3) { - context.EmitLdvec((op.Rn + index) & 0x1f); - } + Type[] typesCmpSflSub = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesOr = new Type[] { typeof(Vector128 ), typeof(Vector128 ) }; + Type[] typesSav = new Type[] { typeof(long) }; - switch (op.Size) + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + + context.EmitLdc_I8(0x0F0F0F0F0F0F0F0FL); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitStvectmp2(); + context.EmitLdvectmp2(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSflSub)); + + context.EmitLdvec(op.Rm); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); + + context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesCmpSflSub)); + + for (int index = 1; index < op.Size; index++) + { + context.EmitLdvec((op.Rn + index) & 0x1F); + context.EmitLdvec(op.Rm); + + context.EmitLdc_I8(0x1010101010101010L * index); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSflSub)); + + context.EmitStvectmp(); + context.EmitLdvectmp(); + + context.EmitLdvectmp2(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSflSub)); + + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); + + context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), typesCmpSflSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesOr)); + } + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else { - case 1: VectorHelper.EmitCall(context, - nameof(VectorHelper.Tbl1_V64), - nameof(VectorHelper.Tbl1_V128)); break; + context.EmitLdvec(op.Rm); - case 2: VectorHelper.EmitCall(context, - nameof(VectorHelper.Tbl2_V64), - nameof(VectorHelper.Tbl2_V128)); break; + for (int index = 0; index < op.Size; index++) + { + context.EmitLdvec((op.Rn + index) & 0x1F); + } - case 3: VectorHelper.EmitCall(context, - nameof(VectorHelper.Tbl3_V64), - nameof(VectorHelper.Tbl3_V128)); break; + switch (op.Size) + { + case 1: VectorHelper.EmitCall(context, + nameof(VectorHelper.Tbl1_V64), + nameof(VectorHelper.Tbl1_V128)); break; - case 4: VectorHelper.EmitCall(context, - nameof(VectorHelper.Tbl4_V64), - nameof(VectorHelper.Tbl4_V128)); break; + case 2: VectorHelper.EmitCall(context, + nameof(VectorHelper.Tbl2_V64), + nameof(VectorHelper.Tbl2_V128)); break; - default: throw new InvalidOperationException(); + case 3: VectorHelper.EmitCall(context, + nameof(VectorHelper.Tbl3_V64), + nameof(VectorHelper.Tbl3_V128)); break; + + case 4: VectorHelper.EmitCall(context, + nameof(VectorHelper.Tbl4_V64), + nameof(VectorHelper.Tbl4_V128)); break; + + default: throw new InvalidOperationException(); + } + + context.EmitStvec(op.Rd); } - - context.EmitStvec(op.Rd); } public static void Trn1_V(ILEmitterCtx context) diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs index f39bd37112..8804521c57 100644 --- a/ChocolArm64/Translation/ILEmitterCtx.cs +++ b/ChocolArm64/Translation/ILEmitterCtx.cs @@ -61,7 +61,9 @@ namespace ChocolArm64.Translation //Vectors are part of another "set" of locals. private const int VecGpTmp1Index = ReservedLocalsCount + 0; - private const int UserVecTempStart = ReservedLocalsCount + 1; + private const int VecGpTmp2Index = ReservedLocalsCount + 1; + private const int VecGpTmp3Index = ReservedLocalsCount + 2; + private const int UserVecTempStart = ReservedLocalsCount + 3; private static int _userIntTempCount; private static int _userVecTempCount; @@ -629,6 +631,12 @@ namespace ChocolArm64.Translation public void EmitLdvectmp() => EmitLdvec(VecGpTmp1Index); public void EmitStvectmp() => EmitStvec(VecGpTmp1Index); + public void EmitLdvectmp2() => EmitLdvec(VecGpTmp2Index); + public void EmitStvectmp2() => EmitStvec(VecGpTmp2Index); + + public void EmitLdvectmp3() => EmitLdvec(VecGpTmp3Index); + public void EmitStvectmp3() => EmitStvec(VecGpTmp3Index); + public void EmitLdint(int index) => Ldloc(index, VarType.Int); public void EmitStint(int index) => Stloc(index, VarType.Int); diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index 47feb573eb..b147cf4468 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -93,10 +93,14 @@ namespace Ryujinx.Tests.Cpu } protected void SetThreadState(ulong x0 = 0, ulong x1 = 0, ulong x2 = 0, ulong x3 = 0, ulong x31 = 0, - Vector128 v0 = default(Vector128), - Vector128 v1 = default(Vector128), - Vector128 v2 = default(Vector128), - Vector128 v3 = default(Vector128), + Vector128 v0 = default(Vector128), + Vector128 v1 = default(Vector128), + Vector128 v2 = default(Vector128), + Vector128 v3 = default(Vector128), + Vector128 v4 = default(Vector128), + Vector128 v5 = default(Vector128), + Vector128 v30 = default(Vector128), + Vector128 v31 = default(Vector128), bool overflow = false, bool carry = false, bool zero = false, bool negative = false, int fpcr = 0x0, int fpsr = 0x0) { @@ -107,10 +111,14 @@ namespace Ryujinx.Tests.Cpu _thread.ThreadState.X31 = x31; - _thread.ThreadState.V0 = v0; - _thread.ThreadState.V1 = v1; - _thread.ThreadState.V2 = v2; - _thread.ThreadState.V3 = v3; + _thread.ThreadState.V0 = v0; + _thread.ThreadState.V1 = v1; + _thread.ThreadState.V2 = v2; + _thread.ThreadState.V3 = v3; + _thread.ThreadState.V4 = v4; + _thread.ThreadState.V5 = v5; + _thread.ThreadState.V30 = v30; + _thread.ThreadState.V31 = v31; _thread.ThreadState.Overflow = overflow; _thread.ThreadState.Carry = carry; @@ -129,10 +137,14 @@ namespace Ryujinx.Tests.Cpu _unicornEmu.SP = x31; - _unicornEmu.Q[0] = v0; - _unicornEmu.Q[1] = v1; - _unicornEmu.Q[2] = v2; - _unicornEmu.Q[3] = v3; + _unicornEmu.Q[0] = v0; + _unicornEmu.Q[1] = v1; + _unicornEmu.Q[2] = v2; + _unicornEmu.Q[3] = v3; + _unicornEmu.Q[4] = v4; + _unicornEmu.Q[5] = v5; + _unicornEmu.Q[30] = v30; + _unicornEmu.Q[31] = v31; _unicornEmu.OverflowFlag = overflow; _unicornEmu.CarryFlag = carry; @@ -165,17 +177,21 @@ namespace Ryujinx.Tests.Cpu protected CpuThreadState SingleOpcode(uint opcode, ulong x0 = 0, ulong x1 = 0, ulong x2 = 0, ulong x3 = 0, ulong x31 = 0, - Vector128 v0 = default(Vector128), - Vector128 v1 = default(Vector128), - Vector128 v2 = default(Vector128), - Vector128 v3 = default(Vector128), + Vector128 v0 = default(Vector128), + Vector128 v1 = default(Vector128), + Vector128 v2 = default(Vector128), + Vector128 v3 = default(Vector128), + Vector128 v4 = default(Vector128), + Vector128 v5 = default(Vector128), + Vector128 v30 = default(Vector128), + Vector128 v31 = default(Vector128), bool overflow = false, bool carry = false, bool zero = false, bool negative = false, int fpcr = 0x0, int fpsr = 0x0) { Opcode(opcode); Opcode(0xD4200000); // BRK #0 Opcode(0xD65F03C0); // RET - SetThreadState(x0, x1, x2, x3, x31, v0, v1, v2, v3, overflow, carry, zero, negative, fpcr, fpsr); + SetThreadState(x0, x1, x2, x3, x31, v0, v1, v2, v3, v4, v5, v30, v31, overflow, carry, zero, negative, fpcr, fpsr); ExecuteOpcodes(); return GetThreadState(); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs b/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs new file mode 100644 index 0000000000..69195af206 --- /dev/null +++ b/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs @@ -0,0 +1,315 @@ +#define SimdTbl + +using NUnit.Framework; + +using System.Collections.Generic; +using System.Runtime.Intrinsics; + +namespace Ryujinx.Tests.Cpu +{ + [Category("SimdTbl")] + public sealed class CpuTestSimdTbl : CpuTest + { +#if SimdTbl + +#region "Helper methods" + private static ulong GenIdxsForTbls(int regs) + { + const byte idxInRngMin = (byte)0; + byte idxInRngMax = (byte)((16 * regs) - 1); + byte idxOutRngMin = (byte) (16 * regs); + const byte idxOutRngMax = (byte)255; + + ulong idxs = 0ul; + + for (int cnt = 1; cnt <= 8; cnt++) + { + ulong idxInRng = (ulong)TestContext.CurrentContext.Random.NextByte(idxInRngMin, idxInRngMax); + ulong idxOutRng = (ulong)TestContext.CurrentContext.Random.NextByte(idxOutRngMin, idxOutRngMax); + + ulong idx = TestContext.CurrentContext.Random.NextBool() ? idxInRng : idxOutRng; + + idxs = (idxs << 8) | idx; + } + + return idxs; + } +#endregion + +#region "ValueSource (Types)" + private static ulong[] _8B_() + { + return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful, + 0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul }; + } + + private static IEnumerable _GenIdxsForTbl1_() + { + yield return 0x0000000000000000ul; + yield return 0x7F7F7F7F7F7F7F7Ful; + yield return 0x8080808080808080ul; + yield return 0xFFFFFFFFFFFFFFFFul; + + for (int cnt = 1; cnt <= RndCntIdxs; cnt++) + { + yield return GenIdxsForTbls(regs: 1); + } + } + + private static IEnumerable _GenIdxsForTbl2_() + { + yield return 0x0000000000000000ul; + yield return 0x7F7F7F7F7F7F7F7Ful; + yield return 0x8080808080808080ul; + yield return 0xFFFFFFFFFFFFFFFFul; + + for (int cnt = 1; cnt <= RndCntIdxs; cnt++) + { + yield return GenIdxsForTbls(regs: 2); + } + } + + private static IEnumerable _GenIdxsForTbl3_() + { + yield return 0x0000000000000000ul; + yield return 0x7F7F7F7F7F7F7F7Ful; + yield return 0x8080808080808080ul; + yield return 0xFFFFFFFFFFFFFFFFul; + + for (int cnt = 1; cnt <= RndCntIdxs; cnt++) + { + yield return GenIdxsForTbls(regs: 3); + } + } + + private static IEnumerable _GenIdxsForTbl4_() + { + yield return 0x0000000000000000ul; + yield return 0x7F7F7F7F7F7F7F7Ful; + yield return 0x8080808080808080ul; + yield return 0xFFFFFFFFFFFFFFFFul; + + for (int cnt = 1; cnt <= RndCntIdxs; cnt++) + { + yield return GenIdxsForTbls(regs: 4); + } + } +#endregion + +#region "ValueSource (Opcodes)" + private static uint[] _SingleRegTbl_V_8B_16B_() + { + return new uint[] + { + 0x0E000000u, // TBL V0.8B, { V0.16B }, V0.8B + }; + } + + private static uint[] _TwoRegTbl_V_8B_16B_() + { + return new uint[] + { + 0x0E002000u, // TBL V0.8B, { V0.16B, V1.16B }, V0.8B + }; + } + + private static uint[] _ThreeRegTbl_V_8B_16B_() + { + return new uint[] + { + 0x0E004000u, // TBL V0.8B, { V0.16B, V1.16B, V2.16B }, V0.8B + }; + } + + private static uint[] _FourRegTbl_V_8B_16B_() + { + return new uint[] + { + 0x0E006000u, // TBL V0.8B, { V0.16B, V1.16B, V2.16B, V3.16B }, V0.8B + }; + } +#endregion + + private const int RndCntTbls = 2; + private const int RndCntIdxs = 2; + + [Test, Pairwise, Description("TBL ., { .16B }, .")] + public void SingleRegTbl_V_8B_16B([ValueSource("_SingleRegTbl_V_8B_16B_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u)] uint rn, + [Values(2u)] uint rm, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table0, + [ValueSource("_GenIdxsForTbl1_")] ulong indexes, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(table0, table0); + Vector128 v2 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); + + SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise, Description("TBL ., { .16B, .16B }, .")] + public void TwoRegTbl_V_8B_16B([ValueSource("_TwoRegTbl_V_8B_16B_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u)] uint rn, + [Values(3u)] uint rm, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table0, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table1, + [ValueSource("_GenIdxsForTbl2_")] ulong indexes, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(table0, table0); + Vector128 v2 = MakeVectorE0E1(table1, table1); + Vector128 v3 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); + + SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise, Description("TBL ., { .16B, .16B }, .")] + public void Mod_TwoRegTbl_V_8B_16B([ValueSource("_TwoRegTbl_V_8B_16B_")] uint opcodes, + [Values(30u, 1u)] uint rd, + [Values(31u)] uint rn, + [Values(1u, 30u)] uint rm, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table0, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table1, + [ValueSource("_GenIdxsForTbl2_")] ulong indexes, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v30 = MakeVectorE0E1(z, z); + Vector128 v31 = MakeVectorE0E1(table0, table0); + Vector128 v0 = MakeVectorE0E1(table1, table1); + Vector128 v1 = MakeVectorE0E1(indexes, indexes); + + SingleOpcode(opcodes, v0: v0, v1: v1, v30: v30, v31: v31); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise, Description("TBL ., { .16B, .16B, .16B }, .")] + public void ThreeRegTbl_V_8B_16B([ValueSource("_ThreeRegTbl_V_8B_16B_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u)] uint rn, + [Values(4u)] uint rm, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table0, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table1, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table2, + [ValueSource("_GenIdxsForTbl3_")] ulong indexes, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(table0, table0); + Vector128 v2 = MakeVectorE0E1(table1, table1); + Vector128 v3 = MakeVectorE0E1(table2, table2); + Vector128 v4 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); + + SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v4: v4); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise, Description("TBL ., { .16B, .16B, .16B }, .")] + public void Mod_ThreeRegTbl_V_8B_16B([ValueSource("_ThreeRegTbl_V_8B_16B_")] uint opcodes, + [Values(30u, 2u)] uint rd, + [Values(31u)] uint rn, + [Values(2u, 30u)] uint rm, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table0, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table1, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table2, + [ValueSource("_GenIdxsForTbl3_")] ulong indexes, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v30 = MakeVectorE0E1(z, z); + Vector128 v31 = MakeVectorE0E1(table0, table0); + Vector128 v0 = MakeVectorE0E1(table1, table1); + Vector128 v1 = MakeVectorE0E1(table2, table2); + Vector128 v2 = MakeVectorE0E1(indexes, indexes); + + SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v30: v30, v31: v31); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise, Description("TBL ., { .16B, .16B, .16B, .16B }, .")] + public void FourRegTbl_V_8B_16B([ValueSource("_FourRegTbl_V_8B_16B_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u)] uint rn, + [Values(5u)] uint rm, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table0, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table1, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table2, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table3, + [ValueSource("_GenIdxsForTbl4_")] ulong indexes, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(table0, table0); + Vector128 v2 = MakeVectorE0E1(table1, table1); + Vector128 v3 = MakeVectorE0E1(table2, table2); + Vector128 v4 = MakeVectorE0E1(table3, table3); + Vector128 v5 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); + + SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v4: v4, v5: v5); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise, Description("TBL ., { .16B, .16B, .16B, .16B }, .")] + public void Mod_FourRegTbl_V_8B_16B([ValueSource("_FourRegTbl_V_8B_16B_")] uint opcodes, + [Values(30u, 3u)] uint rd, + [Values(31u)] uint rn, + [Values(3u, 30u)] uint rm, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table0, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table1, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table2, + [ValueSource("_8B_")] [Random(RndCntTbls)] ulong table3, + [ValueSource("_GenIdxsForTbl4_")] ulong indexes, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= ((q & 1) << 30); + + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v30 = MakeVectorE0E1(z, z); + Vector128 v31 = MakeVectorE0E1(table0, table0); + Vector128 v0 = MakeVectorE0E1(table1, table1); + Vector128 v1 = MakeVectorE0E1(table2, table2); + Vector128 v2 = MakeVectorE0E1(table3, table3); + Vector128 v3 = MakeVectorE0E1(indexes, indexes); + + SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v30: v30, v31: v31); + + CompareAgainstUnicorn(); + } +#endif + } +} From ec40ecd49905885e7ae2c766aedb52cb7c82462c Mon Sep 17 00:00:00 2001 From: Thomas Guillemard Date: Sun, 24 Mar 2019 05:54:38 +0100 Subject: [PATCH 27/36] Complete ColorFormat enums (#652) After some reversing and hardware testing, I found the previous unknown color spaces. With this, the ColorFormat definition can be considered done. --- Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs | 499 ++++++++++----------- 1 file changed, 249 insertions(+), 250 deletions(-) diff --git a/Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs b/Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs index d4fc6adc10..67848b4347 100644 --- a/Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs +++ b/Ryujinx.HLE/HOS/Services/Vi/ColorFormat.cs @@ -4,7 +4,6 @@ { public const int Swizzle = 16; public const int DataType = 14; - // FIXME: check this one public const int Space = 32; public const int Component = 8; } @@ -102,265 +101,265 @@ enum ColorSpace : ulong { - NonColor = 0x0L << ColorShift.Space, - LinearRGBA = 0x1L << ColorShift.Space, - SRGB = 0x2L << ColorShift.Space, + NonColor = 0x0L << ColorShift.Space, + LinearRGBA = 0x1L << ColorShift.Space, + SRGB = 0x2L << ColorShift.Space, - Unknown3 = 0x3L << ColorShift.Space, - Unknown4 = 0x4L << ColorShift.Space, - Unknown5 = 0x5L << ColorShift.Space, - Unknown6 = 0x6L << ColorShift.Space, - Unknown7 = 0x7L << ColorShift.Space, - Unknown8 = 0x8L << ColorShift.Space, + RGB709 = 0x3L << ColorShift.Space, + LinearRGB709 = 0x4L << ColorShift.Space, - ColorIndex = 0x9L << ColorShift.Space, - YCbCr601 = 0xAL << ColorShift.Space, - YCbCr601_RR = 0xBL << ColorShift.Space, + LinearScRGB = 0x5L << ColorShift.Space, - UnknownC = 0xCL << ColorShift.Space, + RGB2020 = 0x6L << ColorShift.Space, + LinearRGB2020 = 0x7L << ColorShift.Space, + RGB2020_PQ = 0x8L << ColorShift.Space, - YCbCr709 = 0xDL << ColorShift.Space, + ColorIndex = 0x9L << ColorShift.Space, - UnknownE = 0xEL << ColorShift.Space, + YCbCr601 = 0xAL << ColorShift.Space, + YCbCr601_RR = 0xBL << ColorShift.Space, + YCbCr601_ER = 0xCL << ColorShift.Space, + YCbCr709 = 0xDL << ColorShift.Space, + YCbCr709_ER = 0xEL << ColorShift.Space, - BayerRGGB = 0x10L << ColorShift.Space, - BayerBGGR = 0x11L << ColorShift.Space, - BayerGRBG = 0x12L << ColorShift.Space, - BayerGBRG = 0x13L << ColorShift.Space, + BayerRGGB = 0x10L << ColorShift.Space, + BayerBGGR = 0x11L << ColorShift.Space, + BayerGRBG = 0x12L << ColorShift.Space, + BayerGBRG = 0x13L << ColorShift.Space, - Unknown14 = 0x14L << ColorShift.Space, + XYZ = 0x14L << ColorShift.Space, } enum ColorFormat : ulong { - NonColor8 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - NonColor16 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - NonColor24 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X24 | ColorDataType.Integer, - NonColor32 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X32 | ColorDataType.Integer, - X4C4 = ColorSpace.NonColor | ColorSwizzle.Y000 | ColorComponent.Y4X4 | ColorDataType.Integer, - A4L4 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.Y4X4 | ColorDataType.Integer, - A8L8 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.Y8X8 | ColorDataType.Integer, - Float_A16L16 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.X16Y16 | ColorDataType.Float, - A1B5G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - A4B4G4R4 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, - A5B5G5R1 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - A2B10G10R10 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_A16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - A1R5G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - A4R4G4B4 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, - A5R1G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X5Y1Z5W5 | ColorDataType.Integer, - A2R10G10B10 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8R8G8B8 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A1 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X1 | ColorDataType.Integer, - A2 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X2 | ColorDataType.Integer, - A4 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X4 | ColorDataType.Integer, - A8 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X8 | ColorDataType.Integer, - A16 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X16 | ColorDataType.Integer, - A32 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X32 | ColorDataType.Integer, - Float_A16 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X16 | ColorDataType.Float, - L4A4 = ColorSpace.LinearRGBA | ColorSwizzle.XXXY | ColorComponent.Y4X4 | ColorDataType.Integer, - L8A8 = ColorSpace.LinearRGBA | ColorSwizzle.XXXY | ColorComponent.Y8X8 | ColorDataType.Integer, - B4G4R4A4 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, - B5G5R1A5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X5Y5Z1W5 | ColorDataType.Integer, - B5G5R5A1 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - B8G8R8A8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - B10G10R10A2 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R1G5B5A5 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - R4G4B4A4 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, - R5G5B5A1 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - R8G8B8A8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - R10G10B10A2 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - L1 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X1 | ColorDataType.Integer, - L2 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X2 | ColorDataType.Integer, - L4 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X4 | ColorDataType.Integer, - L8 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X8 | ColorDataType.Integer, - L16 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X16 | ColorDataType.Integer, - L32 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X32 | ColorDataType.Integer, - Float_L16 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X16 | ColorDataType.Float, - B5G6R5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X5Y6Z5 | ColorDataType.Integer, - B6G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X6Y5Z5 | ColorDataType.Integer, - B5G5R5X1 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - B8_G8_R8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, - B8G8R8X8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - Float_B10G11R11 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X11Y11Z10 | ColorDataType.Float, - X1B5G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - X8B8G8R8 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_X16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - R3G3B2 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X3Y3Z2 | ColorDataType.Integer, - R5G5B6 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.Z5Y5X6 | ColorDataType.Integer, - R5G6B5 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X5Y6Z5 | ColorDataType.Integer, - R5G5B5X1 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, - R8_G8_B8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, - R8G8B8X8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X1R5G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZW1 | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, - X8R8G8B8 = ColorSpace.LinearRGBA | ColorSwizzle.YZW1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - RG8 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.Y8X8 | ColorDataType.Integer, - R16G16 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.X16Y16 | ColorDataType.Integer, - Float_R16G16 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.X16Y16 | ColorDataType.Float, - R8 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X8 | ColorDataType.Integer, - R16 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X16 | ColorDataType.Integer, - Float_R16 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X16 | ColorDataType.Float, - A2B10G10R10_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2R10G10B10_sRGB = ColorSpace.SRGB | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_sRGB = ColorSpace.SRGB | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_sRGB = ColorSpace.SRGB | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_sRGB = ColorSpace.SRGB | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_sRGB = ColorSpace.SRGB | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2B10G10R10_709 = ColorSpace.Unknown3 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_709 = ColorSpace.Unknown3 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_709 = ColorSpace.Unknown3 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2R10G10B10_709 = ColorSpace.Unknown3 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_709 = ColorSpace.Unknown3 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_709 = ColorSpace.Unknown3 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_709 = ColorSpace.Unknown3 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_709 = ColorSpace.Unknown3 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2B10G10R10_709_Linear = ColorSpace.Unknown4 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_709_Linear = ColorSpace.Unknown4 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_709_Linear = ColorSpace.Unknown4 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2R10G10B10_709_Linear = ColorSpace.Unknown4 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_709_Linear = ColorSpace.Unknown4 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_709_Linear = ColorSpace.Unknown4 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_709_Linear = ColorSpace.Unknown4 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_709_Linear = ColorSpace.Unknown4 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_A16B16G16R16_scRGB_Linear = ColorSpace.Unknown5 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - A2B10G10R10_2020 = ColorSpace.Unknown6 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_2020 = ColorSpace.Unknown6 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_2020 = ColorSpace.Unknown6 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2R10G10B10_2020 = ColorSpace.Unknown6 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_2020 = ColorSpace.Unknown6 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_2020 = ColorSpace.Unknown6 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_2020 = ColorSpace.Unknown6 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_2020 = ColorSpace.Unknown6 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - A2B10G10R10_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - A8B8G8R8_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16B16G16R16_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_A16B16G16R16_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - A2R10G10B10_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, - B10G10R10A2_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - R10G10B10A2_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, - X8B8G8R8_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - X16B16G16R16_2020_Linear = ColorSpace.Unknown7 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Float_A16B16G16R16_2020_PQ = ColorSpace.Unknown8 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, - A4I4 = ColorSpace.ColorIndex | ColorSwizzle.X00X | ColorComponent.Y4X4 | ColorDataType.Integer, - A8I8 = ColorSpace.ColorIndex | ColorSwizzle.X00X | ColorComponent.Y8X8 | ColorDataType.Integer, - I4A4 = ColorSpace.ColorIndex | ColorSwizzle.X00Y | ColorComponent.Y4X4 | ColorDataType.Integer, - I8A8 = ColorSpace.ColorIndex | ColorSwizzle.X00Y | ColorComponent.Y8X8 | ColorDataType.Integer, - I1 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X1 | ColorDataType.Integer, - I2 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X2 | ColorDataType.Integer, - I4 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X4 | ColorDataType.Integer, - I8 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - A8Y8U8V8 = ColorSpace.YCbCr601 | ColorSwizzle.YZWX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - A16Y16U16V16 = ColorSpace.YCbCr601 | ColorSwizzle.YZWX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, - Y8U8V8A8 = ColorSpace.YCbCr601 | ColorSwizzle.XYZW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, - V8_U8 = ColorSpace.YCbCr601 | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8 = ColorSpace.YCbCr601 | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V10U10 = ColorSpace.YCbCr601 | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, - V12U12 = ColorSpace.YCbCr601 | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, - V8 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - V10 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, - V12 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, - U8_V8 = ColorSpace.YCbCr601 | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8 = ColorSpace.YCbCr601 | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U10V10 = ColorSpace.YCbCr601 | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, - U12V12 = ColorSpace.YCbCr601 | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, - U8 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - U10 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, - U12 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, - Y8 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Y10 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, - Y12 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, - YVYU = ColorSpace.YCbCr601 | ColorSwizzle.XZY1 | ColorComponent.X8Y8X8Z8 | ColorDataType.Integer, - VYUY = ColorSpace.YCbCr601 | ColorSwizzle.XZY1 | ColorComponent.Y8X8Z8X8 | ColorDataType.Integer, - UYVY = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.Y8X8Z8X8 | ColorDataType.Integer, - YUYV = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.X8Y8X8Z8 | ColorDataType.Integer, - Y8_U8_V8 = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, - V8_U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - U8_V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - Y8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - V8_U8_ER = ColorSpace.UnknownC | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8_ER = ColorSpace.UnknownC | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V8_ER = ColorSpace.UnknownC | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - U8_V8_ER = ColorSpace.UnknownC | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8_ER = ColorSpace.UnknownC | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U8_ER = ColorSpace.UnknownC | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - Y8_ER = ColorSpace.UnknownC | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - V8_U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V10U10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, - V12U12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, - V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - V10_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, - V12_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, - U8_V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U10V10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, - U12V12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, - U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - U10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, - U12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, - Y8_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Y10_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, - Y12_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, - V8_U8_709_ER = ColorSpace.UnknownE | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, - V8U8_709_ER = ColorSpace.UnknownE | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, - V10U10_709_ER = ColorSpace.UnknownE | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, - V12U12_709_ER = ColorSpace.UnknownE | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, - V8_709_ER = ColorSpace.UnknownE | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, - V10_709_ER = ColorSpace.UnknownE | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, - V12_709_ER = ColorSpace.UnknownE | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, - U8_V8_709_ER = ColorSpace.UnknownE | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, - U8V8_709_ER = ColorSpace.UnknownE | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, - U10V10_709_ER = ColorSpace.UnknownE | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, - U12V12_709_ER = ColorSpace.UnknownE | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, - U8_709_ER = ColorSpace.UnknownE | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, - U10_709_ER = ColorSpace.UnknownE | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, - U12_709_ER = ColorSpace.UnknownE | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, - Y8_709_ER = ColorSpace.UnknownE | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Y10_709_ER = ColorSpace.UnknownE | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, - Y12_709_ER = ColorSpace.UnknownE | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, - V10U10_2020 = ColorSpace.UnknownE | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, - V12U12_2020 = ColorSpace.UnknownE | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, - V10_2020 = ColorSpace.UnknownE | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, - V12_2020 = ColorSpace.UnknownE | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, - U10V10_2020 = ColorSpace.UnknownE | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, - U12V12_2020 = ColorSpace.UnknownE | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, - U10_2020 = ColorSpace.UnknownE | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, - U12_2020 = ColorSpace.UnknownE | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, - Y10_2020 = ColorSpace.UnknownE | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, - Y12_2020 = ColorSpace.UnknownE | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, - Bayer8RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Bayer16RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - BayerS16RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, - X2Bayer14RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, - X4Bayer12RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, - X6Bayer10RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, - Bayer8BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Bayer16BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - BayerS16BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, - X2Bayer14BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, - X4Bayer12BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, - X6Bayer10BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, - Bayer8GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Bayer16GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - BayerS16GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, - X2Bayer14GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, - X4Bayer12GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, - X6Bayer10GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, - Bayer8GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, - Bayer16GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, - BayerS16GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, - X2Bayer14GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, - X4Bayer12GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, - X6Bayer10GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, - XYZ = ColorSpace.Unknown14 | ColorSwizzle.XYZ1 | ColorComponent.X20Y20Z20 | ColorDataType.Float, + NonColor8 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + NonColor16 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + NonColor24 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X24 | ColorDataType.Integer, + NonColor32 = ColorSpace.NonColor | ColorSwizzle.X000 | ColorComponent.X32 | ColorDataType.Integer, + X4C4 = ColorSpace.NonColor | ColorSwizzle.Y000 | ColorComponent.Y4X4 | ColorDataType.Integer, + A4L4 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.Y4X4 | ColorDataType.Integer, + A8L8 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.Y8X8 | ColorDataType.Integer, + Float_A16L16 = ColorSpace.LinearRGBA | ColorSwizzle.YYYX | ColorComponent.X16Y16 | ColorDataType.Float, + A1B5G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + A4B4G4R4 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, + A5B5G5R1 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + A2B10G10R10 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_A16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + A1R5G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + A4R4G4B4 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, + A5R1G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X5Y1Z5W5 | ColorDataType.Integer, + A2R10G10B10 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8R8G8B8 = ColorSpace.LinearRGBA | ColorSwizzle.YZWX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A1 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X1 | ColorDataType.Integer, + A2 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X2 | ColorDataType.Integer, + A4 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X4 | ColorDataType.Integer, + A8 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X8 | ColorDataType.Integer, + A16 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X16 | ColorDataType.Integer, + A32 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X32 | ColorDataType.Integer, + Float_A16 = ColorSpace.LinearRGBA | ColorSwizzle._000X | ColorComponent.X16 | ColorDataType.Float, + L4A4 = ColorSpace.LinearRGBA | ColorSwizzle.XXXY | ColorComponent.Y4X4 | ColorDataType.Integer, + L8A8 = ColorSpace.LinearRGBA | ColorSwizzle.XXXY | ColorComponent.Y8X8 | ColorDataType.Integer, + B4G4R4A4 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, + B5G5R1A5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X5Y5Z1W5 | ColorDataType.Integer, + B5G5R5A1 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + B8G8R8A8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + B10G10R10A2 = ColorSpace.LinearRGBA | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R1G5B5A5 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + R4G4B4A4 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X4Y4Z4W4 | ColorDataType.Integer, + R5G5B5A1 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + R8G8B8A8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + R10G10B10A2 = ColorSpace.LinearRGBA | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + L1 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X1 | ColorDataType.Integer, + L2 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X2 | ColorDataType.Integer, + L4 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X4 | ColorDataType.Integer, + L8 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X8 | ColorDataType.Integer, + L16 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X16 | ColorDataType.Integer, + L32 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X32 | ColorDataType.Integer, + Float_L16 = ColorSpace.LinearRGBA | ColorSwizzle.XXX1 | ColorComponent.X16 | ColorDataType.Float, + B5G6R5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X5Y6Z5 | ColorDataType.Integer, + B6G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X6Y5Z5 | ColorDataType.Integer, + B5G5R5X1 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + B8_G8_R8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, + B8G8R8X8 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + Float_B10G11R11 = ColorSpace.LinearRGBA | ColorSwizzle.ZYX1 | ColorComponent.X11Y11Z10 | ColorDataType.Float, + X1B5G5R5 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + X8B8G8R8 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_X16B16G16R16 = ColorSpace.LinearRGBA | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + R3G3B2 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X3Y3Z2 | ColorDataType.Integer, + R5G5B6 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.Z5Y5X6 | ColorDataType.Integer, + R5G6B5 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X5Y6Z5 | ColorDataType.Integer, + R5G5B5X1 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X5Y5Z5W1 | ColorDataType.Integer, + R8_G8_B8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, + R8G8B8X8 = ColorSpace.LinearRGBA | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X1R5G5B5 = ColorSpace.LinearRGBA | ColorSwizzle.YZW1 | ColorComponent.X1Y5Z5W5 | ColorDataType.Integer, + X8R8G8B8 = ColorSpace.LinearRGBA | ColorSwizzle.YZW1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + RG8 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.Y8X8 | ColorDataType.Integer, + R16G16 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.X16Y16 | ColorDataType.Integer, + Float_R16G16 = ColorSpace.LinearRGBA | ColorSwizzle.XY01 | ColorComponent.X16Y16 | ColorDataType.Float, + R8 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X8 | ColorDataType.Integer, + R16 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X16 | ColorDataType.Integer, + Float_R16 = ColorSpace.LinearRGBA | ColorSwizzle.X001 | ColorComponent.X16 | ColorDataType.Float, + A2B10G10R10_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_sRGB = ColorSpace.SRGB | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2R10G10B10_sRGB = ColorSpace.SRGB | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_sRGB = ColorSpace.SRGB | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_sRGB = ColorSpace.SRGB | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_sRGB = ColorSpace.SRGB | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_sRGB = ColorSpace.SRGB | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2B10G10R10_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_709 = ColorSpace.RGB709 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2R10G10B10_709 = ColorSpace.RGB709 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_709 = ColorSpace.RGB709 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_709 = ColorSpace.RGB709 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_709 = ColorSpace.RGB709 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_709 = ColorSpace.RGB709 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2B10G10R10_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2R10G10B10_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_709_Linear = ColorSpace.LinearRGB709 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_A16B16G16R16_scRGB_Linear = ColorSpace.LinearScRGB | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + A2B10G10R10_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2R10G10B10_2020 = ColorSpace.RGB2020 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_2020 = ColorSpace.RGB2020 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_2020 = ColorSpace.RGB2020 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_2020 = ColorSpace.RGB2020 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + A2B10G10R10_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + A8B8G8R8_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_A16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + A2R10G10B10_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.YZWX | ColorComponent.X2Y10Z10W10 | ColorDataType.Integer, + B10G10R10A2_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.ZYXW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + R10G10B10A2_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.XYZW | ColorComponent.X10Y10Z10W2 | ColorDataType.Integer, + X8B8G8R8_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZY1 | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + X16B16G16R16_2020_Linear = ColorSpace.LinearRGB2020 | ColorSwizzle.WZY1 | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Float_A16B16G16R16_2020_PQ = ColorSpace.RGB2020_PQ | ColorSwizzle.WZYX | ColorComponent.X16Y16Z16W16 | ColorDataType.Float, + A4I4 = ColorSpace.ColorIndex | ColorSwizzle.X00X | ColorComponent.Y4X4 | ColorDataType.Integer, + A8I8 = ColorSpace.ColorIndex | ColorSwizzle.X00X | ColorComponent.Y8X8 | ColorDataType.Integer, + I4A4 = ColorSpace.ColorIndex | ColorSwizzle.X00Y | ColorComponent.Y4X4 | ColorDataType.Integer, + I8A8 = ColorSpace.ColorIndex | ColorSwizzle.X00Y | ColorComponent.Y8X8 | ColorDataType.Integer, + I1 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X1 | ColorDataType.Integer, + I2 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X2 | ColorDataType.Integer, + I4 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X4 | ColorDataType.Integer, + I8 = ColorSpace.ColorIndex | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + A8Y8U8V8 = ColorSpace.YCbCr601 | ColorSwizzle.YZWX | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + A16Y16U16V16 = ColorSpace.YCbCr601 | ColorSwizzle.YZWX | ColorComponent.X16Y16Z16W16 | ColorDataType.Integer, + Y8U8V8A8 = ColorSpace.YCbCr601 | ColorSwizzle.XYZW | ColorComponent.X8Y8Z8W8 | ColorDataType.Integer, + V8_U8 = ColorSpace.YCbCr601 | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8 = ColorSpace.YCbCr601 | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V10U10 = ColorSpace.YCbCr601 | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, + V12U12 = ColorSpace.YCbCr601 | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, + V8 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + V10 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, + V12 = ColorSpace.YCbCr601 | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, + U8_V8 = ColorSpace.YCbCr601 | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8 = ColorSpace.YCbCr601 | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U10V10 = ColorSpace.YCbCr601 | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, + U12V12 = ColorSpace.YCbCr601 | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, + U8 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + U10 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, + U12 = ColorSpace.YCbCr601 | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, + Y8 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Y10 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, + Y12 = ColorSpace.YCbCr601 | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, + YVYU = ColorSpace.YCbCr601 | ColorSwizzle.XZY1 | ColorComponent.X8Y8X8Z8 | ColorDataType.Integer, + VYUY = ColorSpace.YCbCr601 | ColorSwizzle.XZY1 | ColorComponent.Y8X8Z8X8 | ColorDataType.Integer, + UYVY = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.Y8X8Z8X8 | ColorDataType.Integer, + YUYV = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.X8Y8X8Z8 | ColorDataType.Integer, + Y8_U8_V8 = ColorSpace.YCbCr601 | ColorSwizzle.XYZ1 | ColorComponent.X8Y8Z8 | ColorDataType.Integer, + V8_U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + U8_V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + Y8_RR = ColorSpace.YCbCr601_RR | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + V8_U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + U8_V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + Y8_ER = ColorSpace.YCbCr601_ER | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + V8_U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V10U10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, + V12U12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, + V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + V10_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, + V12_709 = ColorSpace.YCbCr709 | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, + U8_V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U10V10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, + U12V12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, + U8_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + U10_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, + U12_709 = ColorSpace.YCbCr709 | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, + Y8_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Y10_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, + Y12_709 = ColorSpace.YCbCr709 | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, + V8_U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0YX0 | ColorComponent.X8Y8 | ColorDataType.Integer, + V8U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0YX0 | ColorComponent.Y8X8 | ColorDataType.Integer, + V10U10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, + V12U12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, + V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X8 | ColorDataType.Integer, + V10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, + V12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, + U8_V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XY0 | ColorComponent.X8Y8 | ColorDataType.Integer, + U8V8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XY0 | ColorComponent.Y8X8 | ColorDataType.Integer, + U10V10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, + U12V12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, + U8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X8 | ColorDataType.Integer, + U10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, + U12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, + Y8_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Y10_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, + Y12_709_ER = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, + V10U10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y10X10 | ColorDataType.Integer, + V12U12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0ZY0 | ColorComponent.Y12X12 | ColorDataType.Integer, + V10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X10 | ColorDataType.Integer, + V12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._00X0 | ColorComponent.X12 | ColorDataType.Integer, + U10V10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y10X10 | ColorDataType.Integer, + U12V12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0XZ0 | ColorComponent.Y12X12 | ColorDataType.Integer, + U10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X10 | ColorDataType.Integer, + U12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle._0X00 | ColorComponent.X12 | ColorDataType.Integer, + Y10_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X10 | ColorDataType.Integer, + Y12_2020 = ColorSpace.YCbCr709_ER | ColorSwizzle.X000 | ColorComponent.X12 | ColorDataType.Integer, + Bayer8RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Bayer16RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + BayerS16RGGB = ColorSpace.BayerRGGB | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, + X2Bayer14RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, + X4Bayer12RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, + X6Bayer10RGGB = ColorSpace.BayerRGGB | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, + Bayer8BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Bayer16BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + BayerS16BGGR = ColorSpace.BayerBGGR | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, + X2Bayer14BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, + X4Bayer12BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, + X6Bayer10BGGR = ColorSpace.BayerBGGR | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, + Bayer8GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Bayer16GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + BayerS16GRBG = ColorSpace.BayerGRBG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, + X2Bayer14GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, + X4Bayer12GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, + X6Bayer10GRBG = ColorSpace.BayerGRBG | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, + Bayer8GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X8 | ColorDataType.Integer, + Bayer16GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Integer, + BayerS16GBRG = ColorSpace.BayerGBRG | ColorSwizzle.X000 | ColorComponent.X16 | ColorDataType.Stencil, + X2Bayer14GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y2X14 | ColorDataType.Integer, + X4Bayer12GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y4X12 | ColorDataType.Integer, + X6Bayer10GBRG = ColorSpace.BayerGBRG | ColorSwizzle.Y000 | ColorComponent.Y6X10 | ColorDataType.Integer, + XYZ = ColorSpace.XYZ | ColorSwizzle.XYZ1 | ColorComponent.X20Y20Z20 | ColorDataType.Float, } } From 464ec7ced8bd8dc9ea8e4021cf602e6caedfffcf Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Mon, 25 Mar 2019 00:23:27 +0100 Subject: [PATCH 28/36] Add Cmeq_V, Cmge_V, Cmgt_V, Cmle_V & Cmlt_V (Z & ~Z) Sse opt.. (#646) * Follow-up (Neg_V). * Follow-up (Not_V & Orn_V). * Add Cmeq/ge/gt/le/lt_V (Z & ~Z) Sse opt.. * Add EmitLd/Stvectmp2/3. * Remove Dup (EmitVectorPairwiseSseOrSse2OpF). * Remove Dup (EmitFcmpOrFcmpe). * Add S/Uabd/l_V Sse opt.. Remove Dup (Srhadd_V). * Nit. --- .../Instructions/InstEmitSimdArithmetic.cs | 279 ++++++++++++++++-- ChocolArm64/Instructions/InstEmitSimdCmp.cs | 165 +++++++++-- .../Instructions/InstEmitSimdHelper.cs | 2 +- .../Instructions/InstEmitSimdLogical.cs | 12 +- 4 files changed, 403 insertions(+), 55 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs index 5ceea77491..d2d87beffe 100644 --- a/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs +++ b/ChocolArm64/Instructions/InstEmitSimdArithmetic.cs @@ -1863,13 +1863,7 @@ namespace ChocolArm64.Instructions Type[] typesSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; - string[] namesSzv = new string[] { nameof(VectorHelper.VectorSByteZero), - nameof(VectorHelper.VectorInt16Zero), - nameof(VectorHelper.VectorInt32Zero), - nameof(VectorHelper.VectorInt64Zero) }; - - VectorHelper.EmitCall(context, namesSzv[op.Size]); - + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesSub)); @@ -1921,20 +1915,125 @@ namespace ChocolArm64.Instructions public static void Sabd_V(ILEmitterCtx context) { - EmitVectorBinaryOpSx(context, () => + if (Optimizations.UseSse2) { - context.Emit(OpCodes.Sub); - EmitAbs(context); - }); + OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; + + Type[] typesCmpSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; + Type[] typesAndOr = new Type[] { typeof(Vector128), typeof(Vector128) }; + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSub)); + + context.EmitStvectmp(); // Cmp mask + context.EmitLdvectmp(); // Cmp mask + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndOr)); + + context.EmitLdvectmp(); // Cmp mask + + context.EmitLdvec(op.Rm); + context.EmitLdvec(op.Rn); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndOr)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else + { + EmitVectorBinaryOpSx(context, () => + { + context.Emit(OpCodes.Sub); + EmitAbs(context); + }); + } } public static void Sabdl_V(ILEmitterCtx context) { - EmitVectorWidenRnRmBinaryOpSx(context, () => + OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; + + if (Optimizations.UseSse41 && op.Size < 2) { - context.Emit(OpCodes.Sub); - EmitAbs(context); - }); + Type[] typesCmpSub = new Type[] { VectorIntTypesPerSizeLog2[op.Size + 1], + VectorIntTypesPerSizeLog2[op.Size + 1] }; + Type[] typesSrl = new Type[] { VectorIntTypesPerSizeLog2[op.Size], typeof(byte) }; + Type[] typesAndOr = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesCvt = new Type[] { VectorIntTypesPerSizeLog2[op.Size] }; + + string nameCvt = op.Size == 0 + ? nameof(Sse41.ConvertToVector128Int16) + : nameof(Sse41.ConvertToVector128Int32); + + context.EmitLdvec(op.Rn); + + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } + + context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); + + context.EmitLdvec(op.Rm); + + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } + + context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); + + context.EmitStvectmp2(); // Long Rm + context.EmitStvectmp(); // Long Rn + + context.EmitLdvectmp(); // Long Rn + context.EmitLdvectmp2(); // Long Rm + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), typesCmpSub)); + + context.EmitStvectmp3(); // Cmp mask + context.EmitLdvectmp3(); // Cmp mask + + context.EmitLdvectmp(); // Long Rn + context.EmitLdvectmp2(); // Long Rm + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndOr)); + + context.EmitLdvectmp3(); // Cmp mask + + context.EmitLdvectmp2(); // Long Rm + context.EmitLdvectmp(); // Long Rn + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndOr)); + + context.EmitStvec(op.Rd); + } + else + { + EmitVectorWidenRnRmBinaryOpSx(context, () => + { + context.Emit(OpCodes.Sub); + EmitAbs(context); + }); + } } public static void Sadalp_V(ILEmitterCtx context) @@ -2430,8 +2529,8 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(op.Size == 0 ? sbyte.MinValue : short.MinValue); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - context.Emit(OpCodes.Dup); context.EmitStvectmp(); + context.EmitLdvectmp(); context.EmitLdvec(op.Rn); context.EmitLdvectmp(); @@ -2604,20 +2703,152 @@ namespace ChocolArm64.Instructions public static void Uabd_V(ILEmitterCtx context) { - EmitVectorBinaryOpZx(context, () => + if (Optimizations.UseSse41) { - context.Emit(OpCodes.Sub); - EmitAbs(context); - }); + OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; + + Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; + Type[] typesCmpSub = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; + Type[] typesAndOr = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(long) }; + + Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); + + context.EmitLdvec(op.Rm); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeSse.GetMethod(nameof(Sse2.Max), typesMax)); + + context.EmitLdvec(op.Rm); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmpSub)); + + context.EmitLdc_I8(-1L); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); + + context.EmitStvectmp(); // Cmp mask + context.EmitLdvectmp(); // Cmp mask + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rm); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndOr)); + + context.EmitLdvectmp(); // Cmp mask + + context.EmitLdvec(op.Rm); + context.EmitLdvec(op.Rn); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndOr)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else + { + EmitVectorBinaryOpZx(context, () => + { + context.Emit(OpCodes.Sub); + EmitAbs(context); + }); + } } public static void Uabdl_V(ILEmitterCtx context) { - EmitVectorWidenRnRmBinaryOpZx(context, () => + OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; + + if (Optimizations.UseSse41 && op.Size < 2) { - context.Emit(OpCodes.Sub); - EmitAbs(context); - }); + Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size + 1], + VectorUIntTypesPerSizeLog2[op.Size + 1] }; + Type[] typesCmpSub = new Type[] { VectorIntTypesPerSizeLog2 [op.Size + 1], + VectorIntTypesPerSizeLog2 [op.Size + 1] }; + Type[] typesSrl = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], typeof(byte) }; + Type[] typesAndOr = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesCvt = new Type[] { VectorUIntTypesPerSizeLog2[op.Size] }; + Type[] typesSav = new Type[] { typeof(long) }; + + string nameCvt = op.Size == 0 + ? nameof(Sse41.ConvertToVector128Int16) + : nameof(Sse41.ConvertToVector128Int32); + + context.EmitLdvec(op.Rn); + + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } + + context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); + + context.EmitLdvec(op.Rm); + + if (op.RegisterSize == RegisterSize.Simd128) + { + context.Emit(OpCodes.Ldc_I4_8); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), typesSrl)); + } + + context.EmitCall(typeof(Sse41).GetMethod(nameCvt, typesCvt)); + + context.EmitStvectmp2(); // Long Rm + context.EmitStvectmp(); // Long Rn + + context.EmitLdvectmp2(); // Long Rm + context.EmitLdvectmp(); // Long Rn + + context.EmitCall(typeof(Sse41).GetMethod(nameof(Sse41.Max), typesMax)); + + context.EmitLdvectmp2(); // Long Rm + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmpSub)); + + context.EmitLdc_I8(-1L); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); + + context.EmitStvectmp3(); // Cmp mask + context.EmitLdvectmp3(); // Cmp mask + + context.EmitLdvectmp(); // Long Rn + context.EmitLdvectmp2(); // Long Rm + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndOr)); + + context.EmitLdvectmp3(); // Cmp mask + + context.EmitLdvectmp2(); // Long Rm + context.EmitLdvectmp(); // Long Rn + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), typesCmpSub)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAndOr)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), typesAndOr)); + + context.EmitStvec(op.Rd); + } + else + { + EmitVectorWidenRnRmBinaryOpZx(context, () => + { + context.Emit(OpCodes.Sub); + EmitAbs(context); + }); + } } public static void Uadalp_V(ILEmitterCtx context) diff --git a/ChocolArm64/Instructions/InstEmitSimdCmp.cs b/ChocolArm64/Instructions/InstEmitSimdCmp.cs index 62cf772091..e6b33f797b 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCmp.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCmp.cs @@ -20,19 +20,32 @@ namespace ChocolArm64.Instructions public static void Cmeq_V(ILEmitterCtx context) { - if (context.CurrOp is OpCodeSimdReg64 op) + if (Optimizations.UseSse41) { - if (op.Size < 3 && Optimizations.UseSse2) + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; + + Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse41); + + context.EmitLdvec(op.Rn); + + if (op is OpCodeSimdReg64 binOp) { - EmitSse2Op(context, nameof(Sse2.CompareEqual)); - } - else if (op.Size == 3 && Optimizations.UseSse41) - { - EmitSse41Op(context, nameof(Sse41.CompareEqual)); + context.EmitLdvec(binOp.Rm); } else { - EmitCmpOp(context, OpCodes.Beq_S, scalar: false); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + } + + context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareEqual), typesCmp)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); } } else @@ -48,7 +61,45 @@ namespace ChocolArm64.Instructions public static void Cmge_V(ILEmitterCtx context) { - EmitCmpOp(context, OpCodes.Bge_S, scalar: false); + if (Optimizations.UseSse42) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(long) }; + + Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); + + if (op is OpCodeSimdReg64 binOp) + { + context.EmitLdvec(binOp.Rm); + } + else + { + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + } + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); + + context.EmitLdc_I8(-1L); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else + { + EmitCmpOp(context, OpCodes.Bge_S, scalar: false); + } } public static void Cmgt_S(ILEmitterCtx context) @@ -58,19 +109,32 @@ namespace ChocolArm64.Instructions public static void Cmgt_V(ILEmitterCtx context) { - if (context.CurrOp is OpCodeSimdReg64 op) + if (Optimizations.UseSse42) { - if (op.Size < 3 && Optimizations.UseSse2) + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; + + Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); + + context.EmitLdvec(op.Rn); + + if (op is OpCodeSimdReg64 binOp) { - EmitSse2Op(context, nameof(Sse2.CompareGreaterThan)); - } - else if (op.Size == 3 && Optimizations.UseSse42) - { - EmitSse42Op(context, nameof(Sse42.CompareGreaterThan)); + context.EmitLdvec(binOp.Rm); } else { - EmitCmpOp(context, OpCodes.Bgt_S, scalar: false); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + } + + context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); } } else @@ -92,8 +156,8 @@ namespace ChocolArm64.Instructions { Type[] typesMax = new Type[] { VectorUIntTypesPerSizeLog2[op.Size], VectorUIntTypesPerSizeLog2[op.Size] }; Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2 [op.Size], VectorIntTypesPerSizeLog2 [op.Size] }; - Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesSav = new Type[] { typeof(byte) }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(long) }; Type typeSse = op.Size == 0 ? typeof(Sse2) : typeof(Sse41); @@ -106,7 +170,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqual), typesCmp)); - context.EmitLdc_I4(byte.MaxValue); + context.EmitLdc_I8(-1L); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); @@ -169,7 +233,37 @@ namespace ChocolArm64.Instructions public static void Cmle_V(ILEmitterCtx context) { - EmitCmpOp(context, OpCodes.Ble_S, scalar: false); + if (Optimizations.UseSse42) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(long) }; + + Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); + + context.EmitLdvec(op.Rn); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); + + context.EmitLdc_I8(-1L); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else + { + EmitCmpOp(context, OpCodes.Ble_S, scalar: false); + } } public static void Cmlt_S(ILEmitterCtx context) @@ -179,7 +273,30 @@ namespace ChocolArm64.Instructions public static void Cmlt_V(ILEmitterCtx context) { - EmitCmpOp(context, OpCodes.Blt_S, scalar: false); + if (Optimizations.UseSse42) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + Type[] typesCmp = new Type[] { VectorIntTypesPerSizeLog2[op.Size], VectorIntTypesPerSizeLog2[op.Size] }; + + Type typeSse = op.Size != 3 ? typeof(Sse2) : typeof(Sse42); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeSse.GetMethod(nameof(Sse2.CompareGreaterThan), typesCmp)); + + context.EmitStvec(op.Rd); + + if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else + { + EmitCmpOp(context, OpCodes.Blt_S, scalar: false); + } } public static void Cmtst_S(ILEmitterCtx context) @@ -390,8 +507,8 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rm); } - context.Emit(OpCodes.Dup); context.EmitStvectmp(); + context.EmitLdvectmp(); context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), typesCmp)); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); @@ -453,8 +570,8 @@ namespace ChocolArm64.Instructions context.EmitLdvec(op.Rm); } - context.Emit(OpCodes.Dup); context.EmitStvectmp(); + context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrderedScalar), typesCmp)); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); diff --git a/ChocolArm64/Instructions/InstEmitSimdHelper.cs b/ChocolArm64/Instructions/InstEmitSimdHelper.cs index 10b86a3e17..56ef1fdca4 100644 --- a/ChocolArm64/Instructions/InstEmitSimdHelper.cs +++ b/ChocolArm64/Instructions/InstEmitSimdHelper.cs @@ -872,8 +872,8 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.UnpackLow), types)); - context.Emit(OpCodes.Dup); context.EmitStvectmp(); + context.EmitLdvectmp(); VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); diff --git a/ChocolArm64/Instructions/InstEmitSimdLogical.cs b/ChocolArm64/Instructions/InstEmitSimdLogical.cs index bf80bada3e..a5a9227410 100644 --- a/ChocolArm64/Instructions/InstEmitSimdLogical.cs +++ b/ChocolArm64/Instructions/InstEmitSimdLogical.cs @@ -193,12 +193,12 @@ namespace ChocolArm64.Instructions { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - Type[] typesSav = new Type[] { typeof(byte) }; - Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(long) }; + Type[] typesAnt = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); - context.EmitLdc_I4(byte.MaxValue); + context.EmitLdc_I8(-1L); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAnt)); @@ -222,13 +222,13 @@ namespace ChocolArm64.Instructions { OpCodeSimdReg64 op = (OpCodeSimdReg64)context.CurrOp; - Type[] typesSav = new Type[] { typeof(byte) }; - Type[] typesAntOr = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(long) }; + Type[] typesAntOr = new Type[] { typeof(Vector128), typeof(Vector128) }; context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rm); - context.EmitLdc_I4(byte.MaxValue); + context.EmitLdc_I8(-1L); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), typesAntOr)); From febc2ad6f492972243f0d8918337f08e7bd395ee Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Wed, 3 Apr 2019 14:21:22 +0200 Subject: [PATCH 29/36] Sse optimized all the fp to integer conversion instructions (signed) with Tests (signed & unsigned). (#655) * Update CpuTestSimdCvt.cs * Update CpuTestSimd.cs * Update CpuTestSimdShImm.cs * Update InstEmitSimdCvt.cs * Update InstEmitSimdMove.cs * Update InstEmitSimdCmp.cs * Update VectorHelper.cs * Update InstEmitSimdHelper.cs * Update OpCodeTable.cs * Update InstEmitSimdCvt.cs * Update InstEmitSimdHelper.cs * Update InstEmitSimdMove.cs --- ChocolArm64/Instructions/InstEmitSimdCmp.cs | 6 +- ChocolArm64/Instructions/InstEmitSimdCvt.cs | 400 +++++++++++++++++- .../Instructions/InstEmitSimdHelper.cs | 4 +- ChocolArm64/Instructions/InstEmitSimdMove.cs | 6 +- ChocolArm64/Instructions/VectorHelper.cs | 87 +--- ChocolArm64/OpCodeTable.cs | 6 +- Ryujinx.Tests/Cpu/CpuTestSimd.cs | 160 ++++++- Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs | 276 +++++++++--- Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs | 166 ++++++++ 9 files changed, 956 insertions(+), 155 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitSimdCmp.cs b/ChocolArm64/Instructions/InstEmitSimdCmp.cs index e6b33f797b..d54edb7eda 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCmp.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCmp.cs @@ -563,7 +563,7 @@ namespace ChocolArm64.Instructions if (cmpWithZero) { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); } else { @@ -574,7 +574,7 @@ namespace ChocolArm64.Instructions context.EmitLdvectmp(); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrderedScalar), typesCmp)); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareEqualOrderedScalar), typesCmp)); @@ -839,7 +839,7 @@ namespace ChocolArm64.Instructions } else { - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); } if (isLeOrLt) diff --git a/ChocolArm64/Instructions/InstEmitSimdCvt.cs b/ChocolArm64/Instructions/InstEmitSimdCvt.cs index c5c61bcca5..2e2da6a357 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCvt.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCvt.cs @@ -35,7 +35,7 @@ namespace ChocolArm64.Instructions //Single -> Double. Type[] typesCvt = new Type[] { typeof(Vector128), typeof(Vector128) }; - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorDoubleZero)); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitLdvec(op.Rn); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), typesCvt)); @@ -125,7 +125,14 @@ namespace ChocolArm64.Instructions public static void Fcvtms_Gp(ILEmitterCtx context) { - EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor))); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsMinusInfinity, isFixed: false); + } + else + { + EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor))); + } } public static void Fcvtmu_Gp(ILEmitterCtx context) @@ -207,12 +214,26 @@ namespace ChocolArm64.Instructions public static void Fcvtns_S(ILEmitterCtx context) { - EmitFcvtn(context, signed: true, scalar: true); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, isFixed: false, scalar: true); + } + else + { + EmitFcvtn(context, signed: true, scalar: true); + } } public static void Fcvtns_V(ILEmitterCtx context) { - EmitFcvtn(context, signed: true, scalar: false); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, isFixed: false, scalar: false); + } + else + { + EmitFcvtn(context, signed: true, scalar: false); + } } public static void Fcvtnu_S(ILEmitterCtx context) @@ -227,7 +248,14 @@ namespace ChocolArm64.Instructions public static void Fcvtps_Gp(ILEmitterCtx context) { - EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling))); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsPlusInfinity, isFixed: false); + } + else + { + EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling))); + } } public static void Fcvtpu_Gp(ILEmitterCtx context) @@ -237,22 +265,62 @@ namespace ChocolArm64.Instructions public static void Fcvtzs_Gp(ILEmitterCtx context) { - EmitFcvt_s_Gp(context, () => { }); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsZero, isFixed: false); + } + else + { + EmitFcvt_s_Gp(context, () => { }); + } } public static void Fcvtzs_Gp_Fixed(ILEmitterCtx context) { - EmitFcvtzs_Gp_Fixed(context); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsZero, isFixed: true); + } + else + { + EmitFcvtzs_Gp_Fixed(context); + } } public static void Fcvtzs_S(ILEmitterCtx context) { - EmitFcvtz(context, signed: true, scalar: true); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: false, scalar: true); + } + else + { + EmitFcvtz(context, signed: true, scalar: true); + } } public static void Fcvtzs_V(ILEmitterCtx context) { - EmitFcvtz(context, signed: true, scalar: false); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: false, scalar: false); + } + else + { + EmitFcvtz(context, signed: true, scalar: false); + } + } + + public static void Fcvtzs_V_Fixed(ILEmitterCtx context) + { + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: true, scalar: false); + } + else + { + EmitFcvtz(context, signed: true, scalar: false); + } } public static void Fcvtzu_Gp(ILEmitterCtx context) @@ -275,6 +343,11 @@ namespace ChocolArm64.Instructions EmitFcvtz(context, signed: false, scalar: false); } + public static void Fcvtzu_V_Fixed(ILEmitterCtx context) + { + EmitFcvtz(context, signed: false, scalar: false); + } + public static void Scvtf_Gp(ILEmitterCtx context) { OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; @@ -730,5 +803,314 @@ namespace ChocolArm64.Instructions context.Emit(OpCodes.Mul); } } + + private static void EmitSse41Fcvt_Signed_Gp(ILEmitterCtx context, RoundMode roundMode, bool isFixed) + { + OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; + + if (op.Size == 0) + { + Type[] typesCmpMul = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesAnd = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesRndCvt = new Type[] { typeof(Vector128) }; + Type[] typesCvt = new Type[] { typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(int) }; + + //string nameCvt; + int fpMaxVal; + + if (op.RegisterSize == RegisterSize.Int32) + { + //nameCvt = nameof(Sse.ConvertToInt32); + fpMaxVal = 0x4F000000; // 2.14748365E9f (2147483648) + } + else + { + //nameCvt = nameof(Sse.ConvertToInt64); + fpMaxVal = 0x5F000000; // 9.223372E18f (9223372036854775808) + } + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), typesCmpMul)); + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAnd)); + + if (isFixed) + { + // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, op.FBits) + int fpScaled = 0x40000000 + (op.FBits - 1) * 0x800000; + + context.EmitLdc_I4(fpScaled); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesCmpMul)); + } + + context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); + + context.EmitStvectmp(); + context.EmitLdvectmp(); + + // TODO: Use Sse.ConvertToInt64 once it is fixed (in .NET Core 3.0), + // remove the following if/else and uncomment the code. + + //context.EmitCall(typeof(Sse).GetMethod(nameCvt, typesRndCvt)); + + if (op.RegisterSize == RegisterSize.Int32) + { + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.ConvertToInt32), typesRndCvt)); + } + else + { + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Double), typesRndCvt)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), new Type[] { typeof(Vector128) })); + } + + context.EmitLdvectmp(); + + context.EmitLdc_I4(fpMaxVal); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), typesCmpMul)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt32), typesCvt)); + + if (op.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Xor); + context.Emit(OpCodes.Conv_U8); + } + else + { + context.Emit(OpCodes.Conv_I8); + context.Emit(OpCodes.Xor); + } + + context.EmitStintzr(op.Rd); + } + else /* if (op.Size == 1) */ + { + Type[] typesCmpMul = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesAnd = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesRndCvt = new Type[] { typeof(Vector128) }; + Type[] typesCvt = new Type[] { typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(long) }; + + string nameCvt; + long fpMaxVal; + + if (op.RegisterSize == RegisterSize.Int32) + { + nameCvt = nameof(Sse2.ConvertToInt32); + fpMaxVal = 0x41E0000000000000L; // 2147483648.0000000d (2147483648) + } + else + { + nameCvt = nameof(Sse2.ConvertToInt64); + fpMaxVal = 0x43E0000000000000L; // 9.2233720368547760E18d (9223372036854775808) + } + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), typesCmpMul)); + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAnd)); + + if (isFixed) + { + // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, op.FBits) + long fpScaled = 0x4000000000000000L + (op.FBits - 1) * 0x10000000000000L; + + context.EmitLdc_I8(fpScaled); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesCmpMul)); + } + + context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); + + context.EmitStvectmp(); + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameCvt, typesRndCvt)); + + context.EmitLdvectmp(); + + context.EmitLdc_I8(fpMaxVal); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), typesCmpMul)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt32), typesCvt)); + + if (op.RegisterSize == RegisterSize.Int32) + { + context.Emit(OpCodes.Xor); + context.Emit(OpCodes.Conv_U8); + } + else + { + context.Emit(OpCodes.Conv_I8); + context.Emit(OpCodes.Xor); + } + + context.EmitStintzr(op.Rd); + } + } + + private static void EmitSse41Fcvt_Signed(ILEmitterCtx context, RoundMode roundMode, bool isFixed, bool scalar) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + // sizeF == ((OpCodeSimdShImm64)op).Size - 2 + int sizeF = op.Size & 1; + + if (sizeF == 0) + { + Type[] typesCmpMul = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesAndXor = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesRndCvt = new Type[] { typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(int) }; + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), typesCmpMul)); + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXor)); + + if (isFixed) + { + int fBits = GetImmShr((OpCodeSimdShImm64)op); + + // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) + int fpScaled = 0x40000000 + (fBits - 1) * 0x800000; + + context.EmitLdc_I4(fpScaled); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesCmpMul)); + } + + context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); + + context.EmitStvectmp(); + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt)); + + context.EmitLdvectmp(); + + context.EmitLdc_I4(0x4F000000); // 2.14748365E9f (2147483648) + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), typesCmpMul)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXor)); + + context.EmitStvec(op.Rd); + + if (scalar) + { + EmitVectorZero32_128(context, op.Rd); + } + else if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else /* if (sizeF == 1) */ + { + Type[] typesCmpMulUpk = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesAndXor = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesRndCvt = new Type[] { typeof(Vector128) }; + Type[] typesSv = new Type[] { typeof(long), typeof(long) }; + Type[] typesSav = new Type[] { typeof(long) }; + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), typesCmpMulUpk)); + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXor)); + + if (isFixed) + { + int fBits = GetImmShr((OpCodeSimdShImm64)op); + + // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) + long fpScaled = 0x4000000000000000L + (fBits - 1) * 0x10000000000000L; + + context.EmitLdc_I8(fpScaled); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesCmpMulUpk)); + } + + context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); + + context.EmitStvectmp(); + context.EmitLdvectmp(); + + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), typesCmpMulUpk)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); + + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv)); + + context.EmitLdvectmp(); + + context.EmitLdc_I8(0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), typesCmpMulUpk)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXor)); + + context.EmitStvec(op.Rd); + + if (scalar) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + } + + private static string GetSse41NameRnd(RoundMode roundMode) + { + switch (roundMode) + { + case RoundMode.ToNearest: + return nameof(Sse41.RoundToNearestInteger); // even + + case RoundMode.TowardsMinusInfinity: + return nameof(Sse41.RoundToNegativeInfinity); + + case RoundMode.TowardsPlusInfinity: + return nameof(Sse41.RoundToPositiveInfinity); + + case RoundMode.TowardsZero: + return nameof(Sse41.RoundToZero); + + default: throw new ArgumentException(nameof(roundMode)); + } + } } } diff --git a/ChocolArm64/Instructions/InstEmitSimdHelper.cs b/ChocolArm64/Instructions/InstEmitSimdHelper.cs index 56ef1fdca4..6799a3a388 100644 --- a/ChocolArm64/Instructions/InstEmitSimdHelper.cs +++ b/ChocolArm64/Instructions/InstEmitSimdHelper.cs @@ -1367,8 +1367,8 @@ namespace ChocolArm64.Instructions { if (Optimizations.UseSse) { - //TODO: Use Sse2.MoveScalar once it is fixed, - //as of the time of writing it just crashes the JIT (SDK 2.1.504). + // TODO: Use Sse2.MoveScalar once it is fixed (in .NET Core 3.0), + // as of the time of writing it just crashes the JIT. /*Type[] typesMov = new Type[] { typeof(Vector128) }; diff --git a/ChocolArm64/Instructions/InstEmitSimdMove.cs b/ChocolArm64/Instructions/InstEmitSimdMove.cs index cdd351718c..131ddec610 100644 --- a/ChocolArm64/Instructions/InstEmitSimdMove.cs +++ b/ChocolArm64/Instructions/InstEmitSimdMove.cs @@ -358,7 +358,7 @@ namespace ChocolArm64.Instructions if (Optimizations.UseSsse3) { Type[] typesCmpSflSub = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesOr = new Type[] { typeof(Vector128 ), typeof(Vector128 ) }; + Type[] typesOr = new Type[] { typeof(Vector128), typeof(Vector128) }; Type[] typesSav = new Type[] { typeof(long) }; context.EmitLdvec(op.Rn); @@ -710,7 +710,7 @@ namespace ChocolArm64.Instructions context.EmitCall(typeof(Ssse3).GetMethod(nameof(Ssse3.Shuffle), GetTypesSflUpk(0))); } - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInt64Zero)); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(3))); @@ -763,7 +763,7 @@ namespace ChocolArm64.Instructions else { context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackLow), GetTypesSflUpk(op.Size))); - VectorHelper.EmitCall(context, nameof(VectorHelper.VectorInt64Zero)); + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); context.EmitCall(typeof(Sse2).GetMethod(nameUpk, GetTypesSflUpk(3))); } diff --git a/ChocolArm64/Instructions/VectorHelper.cs b/ChocolArm64/Instructions/VectorHelper.cs index edb3428d85..d1dfaced41 100644 --- a/ChocolArm64/Instructions/VectorHelper.cs +++ b/ChocolArm64/Instructions/VectorHelper.cs @@ -26,8 +26,8 @@ namespace ChocolArm64.Instructions { if (float.IsNaN(value)) return 0; - return value > int.MaxValue ? int.MaxValue : - value < int.MinValue ? int.MinValue : (int)value; + return value >= int.MaxValue ? int.MaxValue : + value <= int.MinValue ? int.MinValue : (int)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -35,8 +35,8 @@ namespace ChocolArm64.Instructions { if (float.IsNaN(value)) return 0; - return value > long.MaxValue ? long.MaxValue : - value < long.MinValue ? long.MinValue : (long)value; + return value >= long.MaxValue ? long.MaxValue : + value <= long.MinValue ? long.MinValue : (long)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -44,8 +44,8 @@ namespace ChocolArm64.Instructions { if (float.IsNaN(value)) return 0; - return value > uint.MaxValue ? uint.MaxValue : - value < uint.MinValue ? uint.MinValue : (uint)value; + return value >= uint.MaxValue ? uint.MaxValue : + value <= uint.MinValue ? uint.MinValue : (uint)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -53,8 +53,8 @@ namespace ChocolArm64.Instructions { if (float.IsNaN(value)) return 0; - return value > ulong.MaxValue ? ulong.MaxValue : - value < ulong.MinValue ? ulong.MinValue : (ulong)value; + return value >= ulong.MaxValue ? ulong.MaxValue : + value <= ulong.MinValue ? ulong.MinValue : (ulong)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -62,8 +62,8 @@ namespace ChocolArm64.Instructions { if (double.IsNaN(value)) return 0; - return value > int.MaxValue ? int.MaxValue : - value < int.MinValue ? int.MinValue : (int)value; + return value >= int.MaxValue ? int.MaxValue : + value <= int.MinValue ? int.MinValue : (int)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -71,8 +71,8 @@ namespace ChocolArm64.Instructions { if (double.IsNaN(value)) return 0; - return value > long.MaxValue ? long.MaxValue : - value < long.MinValue ? long.MinValue : (long)value; + return value >= long.MaxValue ? long.MaxValue : + value <= long.MinValue ? long.MinValue : (long)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -80,8 +80,8 @@ namespace ChocolArm64.Instructions { if (double.IsNaN(value)) return 0; - return value > uint.MaxValue ? uint.MaxValue : - value < uint.MinValue ? uint.MinValue : (uint)value; + return value >= uint.MaxValue ? uint.MaxValue : + value <= uint.MinValue ? uint.MinValue : (uint)value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -89,8 +89,8 @@ namespace ChocolArm64.Instructions { if (double.IsNaN(value)) return 0; - return value > ulong.MaxValue ? ulong.MaxValue : - value < ulong.MinValue ? ulong.MinValue : (ulong)value; + return value >= ulong.MaxValue ? ulong.MaxValue : + value <= ulong.MinValue ? ulong.MinValue : (ulong)value; } public static double Round(double value, CpuThreadState state) @@ -500,50 +500,6 @@ namespace ChocolArm64.Instructions return Sse41.Insert(vector, value, 0b1110); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorSByteZero() - { - if (Sse2.IsSupported) - { - return Sse2.SetZeroVector128(); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorInt16Zero() - { - if (Sse2.IsSupported) - { - return Sse2.SetZeroVector128(); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorInt32Zero() - { - if (Sse2.IsSupported) - { - return Sse2.SetZeroVector128(); - } - - throw new PlatformNotSupportedException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorInt64Zero() - { - if (Sse2.IsSupported) - { - return Sse2.SetZeroVector128(); - } - - throw new PlatformNotSupportedException(); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 VectorSingleZero() { @@ -554,16 +510,5 @@ namespace ChocolArm64.Instructions throw new PlatformNotSupportedException(); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 VectorDoubleZero() - { - if (Sse2.IsSupported) - { - return Sse2.SetZeroVector128(); - } - - throw new PlatformNotSupportedException(); - } } } diff --git a/ChocolArm64/OpCodeTable.cs b/ChocolArm64/OpCodeTable.cs index 9fdda87b42..50bc6a1d6d 100644 --- a/ChocolArm64/OpCodeTable.cs +++ b/ChocolArm64/OpCodeTable.cs @@ -313,12 +313,14 @@ namespace ChocolArm64 SetA64(">00111100x011000>xxxxxxxxxxxxxxx", InstEmit.Fcvtzs_Gp_Fixed, typeof(OpCodeSimdCvt64)); SetA64("010111101x100001101110xxxxxxxxxx", InstEmit.Fcvtzs_S, typeof(OpCodeSimd64)); SetA64("0>0011101<100001101110xxxxxxxxxx", InstEmit.Fcvtzs_V, typeof(OpCodeSimd64)); - SetA64("0x0011110>>xxxxx111111xxxxxxxxxx", InstEmit.Fcvtzs_V, typeof(OpCodeSimdShImm64)); + SetA64("0x001111001xxxxx111111xxxxxxxxxx", InstEmit.Fcvtzs_V_Fixed, typeof(OpCodeSimdShImm64)); + SetA64("0100111101xxxxxx111111xxxxxxxxxx", InstEmit.Fcvtzs_V_Fixed, typeof(OpCodeSimdShImm64)); SetA64("x00111100x111001000000xxxxxxxxxx", InstEmit.Fcvtzu_Gp, typeof(OpCodeSimdCvt64)); SetA64(">00111100x011001>xxxxxxxxxxxxxxx", InstEmit.Fcvtzu_Gp_Fixed, typeof(OpCodeSimdCvt64)); SetA64("011111101x100001101110xxxxxxxxxx", InstEmit.Fcvtzu_S, typeof(OpCodeSimd64)); SetA64("0>1011101<100001101110xxxxxxxxxx", InstEmit.Fcvtzu_V, typeof(OpCodeSimd64)); - SetA64("0x1011110>>xxxxx111111xxxxxxxxxx", InstEmit.Fcvtzu_V, typeof(OpCodeSimdShImm64)); + SetA64("0x101111001xxxxx111111xxxxxxxxxx", InstEmit.Fcvtzu_V_Fixed, typeof(OpCodeSimdShImm64)); + SetA64("0110111101xxxxxx111111xxxxxxxxxx", InstEmit.Fcvtzu_V_Fixed, typeof(OpCodeSimdShImm64)); SetA64("000111100x1xxxxx000110xxxxxxxxxx", InstEmit.Fdiv_S, typeof(OpCodeSimdReg64)); SetA64("0>1011100<1xxxxx111111xxxxxxxxxx", InstEmit.Fdiv_V, typeof(OpCodeSimdReg64)); SetA64("000111110x0xxxxx0xxxxxxxxxxxxxxx", InstEmit.Fmadd_S, typeof(OpCodeSimdReg64)); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd.cs b/Ryujinx.Tests/Cpu/CpuTestSimd.cs index 565b6613e0..e409d8dd7a 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimd.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimd.cs @@ -172,6 +172,56 @@ namespace Ryujinx.Tests.Cpu } } + private static IEnumerable _1S_F_Cvt_() + { + // int + yield return 0x00000000CF000001; // -2.1474839E9f (-2147483904) + yield return 0x00000000CF000000; // -2.14748365E9f (-2147483648) + yield return 0x00000000CEFFFFFF; // -2.14748352E9f (-2147483520) + yield return 0x000000004F000001; // 2.1474839E9f (2147483904) + yield return 0x000000004F000000; // 2.14748365E9f (2147483648) + yield return 0x000000004EFFFFFF; // 2.14748352E9f (2147483520) + + yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue) + yield return 0x0000000080800000ul; // -Min Normal + yield return 0x00000000807FFFFFul; // -Max Subnormal + yield return 0x0000000080000001ul; // -Min Subnormal (-float.Epsilon) + yield return 0x000000007F7FFFFFul; // +Max Normal (float.MaxValue) + yield return 0x0000000000800000ul; // +Min Normal + yield return 0x00000000007FFFFFul; // +Max Subnormal + yield return 0x0000000000000001ul; // +Min Subnormal (float.Epsilon) + + if (!NoZeros) + { + yield return 0x0000000080000000ul; // -Zero + yield return 0x0000000000000000ul; // +Zero + } + + if (!NoInfs) + { + yield return 0x00000000FF800000ul; // -Infinity + yield return 0x000000007F800000ul; // +Infinity + } + + if (!NoNaNs) + { + yield return 0x00000000FFC00000ul; // -QNaN (all zeros payload) (float.NaN) + yield return 0x00000000FFBFFFFFul; // -SNaN (all ones payload) + yield return 0x000000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN) + yield return 0x000000007FBFFFFFul; // +SNaN (all ones payload) + } + + for (int cnt = 1; cnt <= RndCnt; cnt++) + { + ulong grbg = TestContext.CurrentContext.Random.NextUInt(); + ulong rnd1 = GenNormalS(); + ulong rnd2 = GenSubnormalS(); + + yield return (grbg << 32) | rnd1; + yield return (grbg << 32) | rnd2; + } + } + private static IEnumerable _2S_F_() { yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue) @@ -213,6 +263,55 @@ namespace Ryujinx.Tests.Cpu } } + private static IEnumerable _2S_F_Cvt_() + { + // int + yield return 0xCF000001CF000001; // -2.1474839E9f (-2147483904) + yield return 0xCF000000CF000000; // -2.14748365E9f (-2147483648) + yield return 0xCEFFFFFFCEFFFFFF; // -2.14748352E9f (-2147483520) + yield return 0x4F0000014F000001; // 2.1474839E9f (2147483904) + yield return 0x4F0000004F000000; // 2.14748365E9f (2147483648) + yield return 0x4EFFFFFF4EFFFFFF; // 2.14748352E9f (2147483520) + + yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue) + yield return 0x8080000080800000ul; // -Min Normal + yield return 0x807FFFFF807FFFFFul; // -Max Subnormal + yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon) + yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue) + yield return 0x0080000000800000ul; // +Min Normal + yield return 0x007FFFFF007FFFFFul; // +Max Subnormal + yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon) + + if (!NoZeros) + { + yield return 0x8000000080000000ul; // -Zero + yield return 0x0000000000000000ul; // +Zero + } + + if (!NoInfs) + { + yield return 0xFF800000FF800000ul; // -Infinity + yield return 0x7F8000007F800000ul; // +Infinity + } + + if (!NoNaNs) + { + yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN) + yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload) + yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN) + yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload) + } + + for (int cnt = 1; cnt <= RndCnt; cnt++) + { + ulong rnd1 = GenNormalS(); + ulong rnd2 = GenSubnormalS(); + + yield return (rnd1 << 32) | rnd1; + yield return (rnd2 << 32) | rnd2; + } + } + private static IEnumerable _1D_F_() { yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) @@ -253,6 +352,55 @@ namespace Ryujinx.Tests.Cpu yield return rnd2; } } + + private static IEnumerable _1D_F_Cvt_() + { + // long + yield return 0xC3E0000000000001ul; // -9.2233720368547780E18d (-9223372036854778000) + yield return 0xC3E0000000000000ul; // -9.2233720368547760E18d (-9223372036854776000) + yield return 0xC3DFFFFFFFFFFFFFul; // -9.2233720368547750E18d (-9223372036854775000) + yield return 0x43E0000000000001ul; // 9.2233720368547780E18d (9223372036854778000) + yield return 0x43E0000000000000ul; // 9.2233720368547760E18d (9223372036854776000) + yield return 0x43DFFFFFFFFFFFFFul; // 9.2233720368547750E18d (9223372036854775000) + + yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) + yield return 0x8010000000000000ul; // -Min Normal + yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal + yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon) + yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue) + yield return 0x0010000000000000ul; // +Min Normal + yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal + yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon) + + if (!NoZeros) + { + yield return 0x8000000000000000ul; // -Zero + yield return 0x0000000000000000ul; // +Zero + } + + if (!NoInfs) + { + yield return 0xFFF0000000000000ul; // -Infinity + yield return 0x7FF0000000000000ul; // +Infinity + } + + if (!NoNaNs) + { + yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN) + yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload) + yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN) + yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload) + } + + for (int cnt = 1; cnt <= RndCnt; cnt++) + { + ulong rnd1 = GenNormalD(); + ulong rnd2 = GenSubnormalD(); + + yield return rnd1; + yield return rnd2; + } + } #endregion #region "ValueSource (Opcodes)" @@ -1319,7 +1467,7 @@ namespace Ryujinx.Tests.Cpu [Test, Pairwise] [Explicit] public void F_Cvt_NZ_SU_S_S([ValueSource("_F_Cvt_NZ_SU_S_S_")] uint opcodes, - [ValueSource("_1S_F_")] ulong a) + [ValueSource("_1S_F_Cvt_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); Vector128 v0 = MakeVectorE0E1(z, z); @@ -1332,7 +1480,7 @@ namespace Ryujinx.Tests.Cpu [Test, Pairwise] [Explicit] public void F_Cvt_NZ_SU_S_D([ValueSource("_F_Cvt_NZ_SU_S_D_")] uint opcodes, - [ValueSource("_1D_F_")] ulong a) + [ValueSource("_1D_F_Cvt_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); Vector128 v0 = MakeVectorE1(z); @@ -1347,8 +1495,8 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_NZ_SU_V_2S_4S([ValueSource("_F_Cvt_NZ_SU_V_2S_4S_")] uint opcodes, [Values(0u)] uint rd, [Values(1u, 0u)] uint rn, - [ValueSource("_2S_F_")] ulong z, - [ValueSource("_2S_F_")] ulong a, + [ValueSource("_2S_F_Cvt_")] ulong z, + [ValueSource("_2S_F_Cvt_")] ulong a, [Values(0b0u, 0b1u)] uint q) // <2S, 4S> { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); @@ -1366,8 +1514,8 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_NZ_SU_V_2D([ValueSource("_F_Cvt_NZ_SU_V_2D_")] uint opcodes, [Values(0u)] uint rd, [Values(1u, 0u)] uint rn, - [ValueSource("_1D_F_")] ulong z, - [ValueSource("_1D_F_")] ulong a) + [ValueSource("_1D_F_Cvt_")] ulong z, + [ValueSource("_1D_F_Cvt_")] ulong a) { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs index ecf90b0aa7..775044a020 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs @@ -13,8 +13,24 @@ namespace Ryujinx.Tests.Cpu #if SimdCvt #region "ValueSource (Types)" - private static IEnumerable _1S_F_() + private static IEnumerable _1S_F_Cvt_() { + // int + yield return 0x00000000CF000001; // -2.1474839E9f (-2147483904) + yield return 0x00000000CF000000; // -2.14748365E9f (-2147483648) + yield return 0x00000000CEFFFFFF; // -2.14748352E9f (-2147483520) + yield return 0x000000004F000001; // 2.1474839E9f (2147483904) + yield return 0x000000004F000000; // 2.14748365E9f (2147483648) + yield return 0x000000004EFFFFFF; // 2.14748352E9f (2147483520) + + // long + yield return 0x00000000DF000001ul; // -9.223373E18f (-9223373136366403584) + yield return 0x00000000DF000000ul; // -9.223372E18f (-9223372036854775808) + yield return 0x00000000DEFFFFFFul; // -9.2233715E18f (-9223371487098961920) + yield return 0x000000005F000001ul; // 9.223373E18f (9223373136366403584) + yield return 0x000000005F000000ul; // 9.223372E18f (9223372036854775808) + yield return 0x000000005EFFFFFFul; // 9.2233715E18f (9223371487098961920) + yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue) yield return 0x0000000080800000ul; // -Min Normal yield return 0x00000000807FFFFFul; // -Max Subnormal @@ -55,8 +71,24 @@ namespace Ryujinx.Tests.Cpu } } - private static IEnumerable _1D_F_() + private static IEnumerable _1D_F_Cvt_() { + // int + yield return 0xC1E0000000200000ul; // -2147483649.0000000d (-2147483649) + yield return 0xC1E0000000000000ul; // -2147483648.0000000d (-2147483648) + yield return 0xC1DFFFFFFFC00000ul; // -2147483647.0000000d (-2147483647) + yield return 0x41E0000000200000ul; // 2147483649.0000000d (2147483649) + yield return 0x41E0000000000000ul; // 2147483648.0000000d (2147483648) + yield return 0x41DFFFFFFFC00000ul; // 2147483647.0000000d (2147483647) + + // long + yield return 0xC3E0000000000001ul; // -9.2233720368547780E18d (-9223372036854778000) + yield return 0xC3E0000000000000ul; // -9.2233720368547760E18d (-9223372036854776000) + yield return 0xC3DFFFFFFFFFFFFFul; // -9.2233720368547750E18d (-9223372036854775000) + yield return 0x43E0000000000001ul; // 9.2233720368547780E18d (9223372036854778000) + yield return 0x43E0000000000000ul; // 9.2233720368547760E18d (9223372036854776000) + yield return 0x43DFFFFFFFFFFFFFul; // 9.2233720368547750E18d (9223372036854775000) + yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) yield return 0x8010000000000000ul; // -Min Normal yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal @@ -110,7 +142,67 @@ namespace Ryujinx.Tests.Cpu #endregion #region "ValueSource (Opcodes)" - private static uint[] _F_Cvt_Z_SU_S_SW_() + private static uint[] _F_Cvt_AMPZ_SU_Gp_SW_() + { + return new uint[] + { + 0x1E240000u, // FCVTAS W0, S0 + 0x1E250000u, // FCVTAU W0, S0 + 0x1E300000u, // FCVTMS W0, S0 + 0x1E310000u, // FCVTMU W0, S0 + 0x1E280000u, // FCVTPS W0, S0 + 0x1E290000u, // FCVTPU W0, S0 + 0x1E380000u, // FCVTZS W0, S0 + 0x1E390000u // FCVTZU W0, S0 + }; + } + + private static uint[] _F_Cvt_AMPZ_SU_Gp_SX_() + { + return new uint[] + { + 0x9E240000u, // FCVTAS X0, S0 + 0x9E250000u, // FCVTAU X0, S0 + 0x9E300000u, // FCVTMS X0, S0 + 0x9E310000u, // FCVTMU X0, S0 + 0x9E280000u, // FCVTPS X0, S0 + 0x9E290000u, // FCVTPU X0, S0 + 0x9E380000u, // FCVTZS X0, S0 + 0x9E390000u // FCVTZU X0, S0 + }; + } + + private static uint[] _F_Cvt_AMPZ_SU_Gp_DW_() + { + return new uint[] + { + 0x1E640000u, // FCVTAS W0, D0 + 0x1E650000u, // FCVTAU W0, D0 + 0x1E700000u, // FCVTMS W0, D0 + 0x1E710000u, // FCVTMU W0, D0 + 0x1E680000u, // FCVTPS W0, D0 + 0x1E690000u, // FCVTPU W0, D0 + 0x1E780000u, // FCVTZS W0, D0 + 0x1E790000u // FCVTZU W0, D0 + }; + } + + private static uint[] _F_Cvt_AMPZ_SU_Gp_DX_() + { + return new uint[] + { + 0x9E640000u, // FCVTAS X0, D0 + 0x9E650000u, // FCVTAU X0, D0 + 0x9E700000u, // FCVTMS X0, D0 + 0x9E710000u, // FCVTMU X0, D0 + 0x9E680000u, // FCVTPS X0, D0 + 0x9E690000u, // FCVTPU X0, D0 + 0x9E780000u, // FCVTZS X0, D0 + 0x9E790000u // FCVTZU X0, D0 + }; + } + + private static uint[] _F_Cvt_Z_SU_Gp_Fixed_SW_() { return new uint[] { @@ -119,7 +211,7 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _F_Cvt_Z_SU_S_SX_() + private static uint[] _F_Cvt_Z_SU_Gp_Fixed_SX_() { return new uint[] { @@ -128,7 +220,7 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _F_Cvt_Z_SU_S_DW_() + private static uint[] _F_Cvt_Z_SU_Gp_Fixed_DW_() { return new uint[] { @@ -137,7 +229,7 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _F_Cvt_Z_SU_S_DX_() + private static uint[] _F_Cvt_Z_SU_Gp_Fixed_DX_() { return new uint[] { @@ -146,7 +238,7 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _SU_Cvt_F_S_WS_() + private static uint[] _SU_Cvt_F_Gp_Fixed_WS_() { return new uint[] { @@ -155,7 +247,7 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _SU_Cvt_F_S_WD_() + private static uint[] _SU_Cvt_F_Gp_Fixed_WD_() { return new uint[] { @@ -164,7 +256,7 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _SU_Cvt_F_S_XS_() + private static uint[] _SU_Cvt_F_Gp_Fixed_XS_() { return new uint[] { @@ -173,7 +265,7 @@ namespace Ryujinx.Tests.Cpu }; } - private static uint[] _SU_Cvt_F_S_XD_() + private static uint[] _SU_Cvt_F_Gp_Fixed_XD_() { return new uint[] { @@ -184,20 +276,86 @@ namespace Ryujinx.Tests.Cpu #endregion private const int RndCnt = 2; - private const int RndCntFbits = 2; + private const int RndCntFBits = 2; private static readonly bool NoZeros = false; private static readonly bool NoInfs = false; private static readonly bool NoNaNs = false; [Test, Pairwise] [Explicit] - public void F_Cvt_Z_SU_S_SW([ValueSource("_F_Cvt_Z_SU_S_SW_")] uint opcodes, - [Values(0u, 31u)] uint rd, - [Values(1u)] uint rn, - [ValueSource("_1S_F_")] ulong a, - [Values(1u, 32u)] [Random(2u, 31u, RndCntFbits)] uint fbits) + public void F_Cvt_AMPZ_SU_Gp_SW([ValueSource("_F_Cvt_AMPZ_SU_Gp_SW_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1S_F_Cvt_")] ulong a) { - uint scale = (64u - fbits) & 0x3Fu; + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + + ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; + uint w31 = TestContext.CurrentContext.Random.NextUInt(); + Vector128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void F_Cvt_AMPZ_SU_Gp_SX([ValueSource("_F_Cvt_AMPZ_SU_Gp_SX_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1S_F_Cvt_")] ulong a) + { + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + + ulong x31 = TestContext.CurrentContext.Random.NextULong(); + Vector128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, x31: x31, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void F_Cvt_AMPZ_SU_Gp_DW([ValueSource("_F_Cvt_AMPZ_SU_Gp_DW_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1D_F_Cvt_")] ulong a) + { + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + + ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; + uint w31 = TestContext.CurrentContext.Random.NextUInt(); + Vector128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void F_Cvt_AMPZ_SU_Gp_DX([ValueSource("_F_Cvt_AMPZ_SU_Gp_DX_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1D_F_Cvt_")] ulong a) + { + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + + ulong x31 = TestContext.CurrentContext.Random.NextULong(); + Vector128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, x31: x31, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void F_Cvt_Z_SU_Gp_Fixed_SW([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_SW_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1S_F_Cvt_")] ulong a, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits) + { + uint scale = (64u - fBits) & 0x3Fu; opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (scale << 10); @@ -212,13 +370,13 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void F_Cvt_Z_SU_S_SX([ValueSource("_F_Cvt_Z_SU_S_SX_")] uint opcodes, - [Values(0u, 31u)] uint rd, - [Values(1u)] uint rn, - [ValueSource("_1S_F_")] ulong a, - [Values(1u, 64u)] [Random(2u, 63u, RndCntFbits)] uint fbits) + public void F_Cvt_Z_SU_Gp_Fixed_SX([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_SX_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1S_F_Cvt_")] ulong a, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) { - uint scale = (64u - fbits) & 0x3Fu; + uint scale = (64u - fBits) & 0x3Fu; opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (scale << 10); @@ -232,13 +390,13 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void F_Cvt_Z_SU_S_DW([ValueSource("_F_Cvt_Z_SU_S_DW_")] uint opcodes, - [Values(0u, 31u)] uint rd, - [Values(1u)] uint rn, - [ValueSource("_1D_F_")] ulong a, - [Values(1u, 32u)] [Random(2u, 31u, RndCntFbits)] uint fbits) + public void F_Cvt_Z_SU_Gp_Fixed_DW([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_DW_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1D_F_Cvt_")] ulong a, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits) { - uint scale = (64u - fbits) & 0x3Fu; + uint scale = (64u - fBits) & 0x3Fu; opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (scale << 10); @@ -253,13 +411,13 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void F_Cvt_Z_SU_S_DX([ValueSource("_F_Cvt_Z_SU_S_DX_")] uint opcodes, - [Values(0u, 31u)] uint rd, - [Values(1u)] uint rn, - [ValueSource("_1D_F_")] ulong a, - [Values(1u, 64u)] [Random(2u, 63u, RndCntFbits)] uint fbits) + public void F_Cvt_Z_SU_Gp_Fixed_DX([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_DX_")] uint opcodes, + [Values(0u, 31u)] uint rd, + [Values(1u)] uint rn, + [ValueSource("_1D_F_Cvt_")] ulong a, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) { - uint scale = (64u - fbits) & 0x3Fu; + uint scale = (64u - fBits) & 0x3Fu; opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (scale << 10); @@ -273,13 +431,13 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void SU_Cvt_F_S_WS([ValueSource("_SU_Cvt_F_S_WS_")] uint opcodes, - [Values(0u)] uint rd, - [Values(1u, 31u)] uint rn, - [ValueSource("_W_")] [Random(RndCnt)] uint wn, - [Values(1u, 32u)] [Random(2u, 31u, RndCntFbits)] uint fbits) + public void SU_Cvt_F_Gp_Fixed_WS([ValueSource("_SU_Cvt_F_Gp_Fixed_WS_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_W_")] [Random(RndCnt)] uint wn, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits) { - uint scale = (64u - fbits) & 0x3Fu; + uint scale = (64u - fBits) & 0x3Fu; opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (scale << 10); @@ -294,13 +452,13 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void SU_Cvt_F_S_WD([ValueSource("_SU_Cvt_F_S_WD_")] uint opcodes, - [Values(0u)] uint rd, - [Values(1u, 31u)] uint rn, - [ValueSource("_W_")] [Random(RndCnt)] uint wn, - [Values(1u, 32u)] [Random(2u, 31u, RndCntFbits)] uint fbits) + public void SU_Cvt_F_Gp_Fixed_WD([ValueSource("_SU_Cvt_F_Gp_Fixed_WD_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_W_")] [Random(RndCnt)] uint wn, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits) { - uint scale = (64u - fbits) & 0x3Fu; + uint scale = (64u - fBits) & 0x3Fu; opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (scale << 10); @@ -315,13 +473,13 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void SU_Cvt_F_S_XS([ValueSource("_SU_Cvt_F_S_XS_")] uint opcodes, - [Values(0u)] uint rd, - [Values(1u, 31u)] uint rn, - [ValueSource("_X_")] [Random(RndCnt)] ulong xn, - [Values(1u, 64u)] [Random(2u, 63u, RndCntFbits)] uint fbits) + public void SU_Cvt_F_Gp_Fixed_XS([ValueSource("_SU_Cvt_F_Gp_Fixed_XS_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_X_")] [Random(RndCnt)] ulong xn, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) { - uint scale = (64u - fbits) & 0x3Fu; + uint scale = (64u - fBits) & 0x3Fu; opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (scale << 10); @@ -336,13 +494,13 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] [Explicit] - public void SU_Cvt_F_S_XD([ValueSource("_SU_Cvt_F_S_XD_")] uint opcodes, - [Values(0u)] uint rd, - [Values(1u, 31u)] uint rn, - [ValueSource("_X_")] [Random(RndCnt)] ulong xn, - [Values(1u, 64u)] [Random(2u, 63u, RndCntFbits)] uint fbits) + public void SU_Cvt_F_Gp_Fixed_XD([ValueSource("_SU_Cvt_F_Gp_Fixed_XD_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_X_")] [Random(RndCnt)] ulong xn, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) { - uint scale = (64u - fbits) & 0x3Fu; + uint scale = (64u - fBits) & 0x3Fu; opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (scale << 10); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs index 9a295d5ed1..c1a1ed42a5 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs @@ -2,6 +2,7 @@ using NUnit.Framework; +using System.Collections.Generic; using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu @@ -47,9 +48,125 @@ namespace Ryujinx.Tests.Cpu return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful, 0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul }; } + + private static IEnumerable _2S_F_Cvt_() + { + // int + yield return 0xCF000001CF000001; // -2.1474839E9f (-2147483904) + yield return 0xCF000000CF000000; // -2.14748365E9f (-2147483648) + yield return 0xCEFFFFFFCEFFFFFF; // -2.14748352E9f (-2147483520) + yield return 0x4F0000014F000001; // 2.1474839E9f (2147483904) + yield return 0x4F0000004F000000; // 2.14748365E9f (2147483648) + yield return 0x4EFFFFFF4EFFFFFF; // 2.14748352E9f (2147483520) + + yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue) + yield return 0x8080000080800000ul; // -Min Normal + yield return 0x807FFFFF807FFFFFul; // -Max Subnormal + yield return 0x8000000180000001ul; // -Min Subnormal (-float.Epsilon) + yield return 0x7F7FFFFF7F7FFFFFul; // +Max Normal (float.MaxValue) + yield return 0x0080000000800000ul; // +Min Normal + yield return 0x007FFFFF007FFFFFul; // +Max Subnormal + yield return 0x0000000100000001ul; // +Min Subnormal (float.Epsilon) + + if (!NoZeros) + { + yield return 0x8000000080000000ul; // -Zero + yield return 0x0000000000000000ul; // +Zero + } + + if (!NoInfs) + { + yield return 0xFF800000FF800000ul; // -Infinity + yield return 0x7F8000007F800000ul; // +Infinity + } + + if (!NoNaNs) + { + yield return 0xFFC00000FFC00000ul; // -QNaN (all zeros payload) (float.NaN) + yield return 0xFFBFFFFFFFBFFFFFul; // -SNaN (all ones payload) + yield return 0x7FC000007FC00000ul; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN) + yield return 0x7FBFFFFF7FBFFFFFul; // +SNaN (all ones payload) + } + + for (int cnt = 1; cnt <= RndCnt; cnt++) + { + ulong rnd1 = GenNormalS(); + ulong rnd2 = GenSubnormalS(); + + yield return (rnd1 << 32) | rnd1; + yield return (rnd2 << 32) | rnd2; + } + } + + private static IEnumerable _1D_F_Cvt_() + { + // long + yield return 0xC3E0000000000001ul; // -9.2233720368547780E18d (-9223372036854778000) + yield return 0xC3E0000000000000ul; // -9.2233720368547760E18d (-9223372036854776000) + yield return 0xC3DFFFFFFFFFFFFFul; // -9.2233720368547750E18d (-9223372036854775000) + yield return 0x43E0000000000001ul; // 9.2233720368547780E18d (9223372036854778000) + yield return 0x43E0000000000000ul; // 9.2233720368547760E18d (9223372036854776000) + yield return 0x43DFFFFFFFFFFFFFul; // 9.2233720368547750E18d (9223372036854775000) + + yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) + yield return 0x8010000000000000ul; // -Min Normal + yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal + yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon) + yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue) + yield return 0x0010000000000000ul; // +Min Normal + yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal + yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon) + + if (!NoZeros) + { + yield return 0x8000000000000000ul; // -Zero + yield return 0x0000000000000000ul; // +Zero + } + + if (!NoInfs) + { + yield return 0xFFF0000000000000ul; // -Infinity + yield return 0x7FF0000000000000ul; // +Infinity + } + + if (!NoNaNs) + { + yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN) + yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload) + yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN) + yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload) + } + + for (int cnt = 1; cnt <= RndCnt; cnt++) + { + ulong rnd1 = GenNormalD(); + ulong rnd2 = GenSubnormalD(); + + yield return rnd1; + yield return rnd2; + } + } #endregion #region "ValueSource (Opcodes)" + private static uint[] _F_Cvt_Z_SU_V_Fixed_2S_4S_() + { + return new uint[] + { + 0x0F20FC00u, // FCVTZS V0.2S, V0.2S, #32 + 0x2F20FC00u // FCVTZU V0.2S, V0.2S, #32 + }; + } + + private static uint[] _F_Cvt_Z_SU_V_Fixed_2D_() + { + return new uint[] + { + 0x4F40FC00u, // FCVTZS V0.2D, V0.2D, #64 + 0x6F40FC00u // FCVTZU V0.2D, V0.2D, #64 + }; + } + private static uint[] _SU_Shll_V_8B8H_16B8H_() { return new uint[] @@ -259,8 +376,57 @@ namespace Ryujinx.Tests.Cpu #endregion private const int RndCnt = 2; + private const int RndCntFBits = 2; private const int RndCntShift = 2; + private static readonly bool NoZeros = false; + private static readonly bool NoInfs = false; + private static readonly bool NoNaNs = false; + + [Test, Pairwise] [Explicit] + public void F_Cvt_Z_SU_V_Fixed_2S_4S([ValueSource("_F_Cvt_Z_SU_V_Fixed_2S_4S_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource("_2S_F_Cvt_")] ulong z, + [ValueSource("_2S_F_Cvt_")] ulong a, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits, + [Values(0b0u, 0b1u)] uint q) // <2S, 4S> + { + uint immHb = (64 - fBits) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + opcodes |= ((q & 1) << 30); + + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(a, a * q); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void F_Cvt_Z_SU_V_Fixed_2D([ValueSource("_F_Cvt_Z_SU_V_Fixed_2D_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource("_1D_F_Cvt_")] ulong z, + [ValueSource("_1D_F_Cvt_")] ulong a, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) + { + uint immHb = (128 - fBits) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(a, a); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + [Test, Pairwise, Description("SHL , , #")] public void Shl_S_D([Values(0u)] uint rd, [Values(1u, 0u)] uint rn, From af65ed3930294f687c6100280b650b36f888427d Mon Sep 17 00:00:00 2001 From: jduncanator <1518948+jduncanator@users.noreply.github.com> Date: Thu, 11 Apr 2019 23:19:49 +1000 Subject: [PATCH 30/36] Add missing TextureCubeMapArray texture type entry (#657) * Add missing TextureCubeMapArray texture type entry * Duplicate comment from other Create path --- Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs index 191f6e3deb..b6bf36c58e 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglTexture.cs @@ -95,6 +95,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL type, IntPtr.Zero); break; + // Cube map arrays are just 2D texture arrays with 6 entries + // per cube map so we can handle them in the same way + case TextureTarget.TextureCubeMapArray: case TextureTarget.Texture2DArray: GL.TexImage3D( target, From 233fc95e1e656f3932f57005d24b76fb750e7704 Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Fri, 12 Apr 2019 18:14:16 +0200 Subject: [PATCH 31/36] Sse optimized the Vector & Scalar fp-to-integer conversion instructions (unsigned); improved the related Tests. (#656) * Update InstEmitSimdCvt.cs * Update CpuTestSimdCvt.cs * Update CpuTestSimd.cs * Update CpuTestSimdShImm.cs * Update InstEmitSimdCvt.cs --- ChocolArm64/Instructions/InstEmitSimdCvt.cs | 523 +++++++++++--------- Ryujinx.Tests/Cpu/CpuTestSimd.cs | 95 +++- Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs | 90 +++- Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs | 59 ++- 4 files changed, 475 insertions(+), 292 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitSimdCvt.cs b/ChocolArm64/Instructions/InstEmitSimdCvt.cs index 2e2da6a357..ab2fb6a833 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCvt.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCvt.cs @@ -125,14 +125,7 @@ namespace ChocolArm64.Instructions public static void Fcvtms_Gp(ILEmitterCtx context) { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsMinusInfinity, isFixed: false); - } - else - { - EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor))); - } + EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor))); } public static void Fcvtmu_Gp(ILEmitterCtx context) @@ -216,7 +209,7 @@ namespace ChocolArm64.Instructions { if (Optimizations.UseSse41) { - EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, isFixed: false, scalar: true); + EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, scalar: true); } else { @@ -228,7 +221,7 @@ namespace ChocolArm64.Instructions { if (Optimizations.UseSse41) { - EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, isFixed: false, scalar: false); + EmitSse41Fcvt_Signed(context, RoundMode.ToNearest, scalar: false); } else { @@ -238,24 +231,31 @@ namespace ChocolArm64.Instructions public static void Fcvtnu_S(ILEmitterCtx context) { - EmitFcvtn(context, signed: false, scalar: true); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Unsigned(context, RoundMode.ToNearest, scalar: true); + } + else + { + EmitFcvtn(context, signed: false, scalar: true); + } } public static void Fcvtnu_V(ILEmitterCtx context) { - EmitFcvtn(context, signed: false, scalar: false); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Unsigned(context, RoundMode.ToNearest, scalar: false); + } + else + { + EmitFcvtn(context, signed: false, scalar: false); + } } public static void Fcvtps_Gp(ILEmitterCtx context) { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsPlusInfinity, isFixed: false); - } - else - { - EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling))); - } + EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling))); } public static void Fcvtpu_Gp(ILEmitterCtx context) @@ -265,33 +265,19 @@ namespace ChocolArm64.Instructions public static void Fcvtzs_Gp(ILEmitterCtx context) { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsZero, isFixed: false); - } - else - { - EmitFcvt_s_Gp(context, () => { }); - } + EmitFcvt_s_Gp(context, () => { }); } public static void Fcvtzs_Gp_Fixed(ILEmitterCtx context) { - if (Optimizations.UseSse41) - { - EmitSse41Fcvt_Signed_Gp(context, RoundMode.TowardsZero, isFixed: true); - } - else - { - EmitFcvtzs_Gp_Fixed(context); - } + EmitFcvtzs_Gp_Fixed(context); } public static void Fcvtzs_S(ILEmitterCtx context) { if (Optimizations.UseSse41) { - EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: false, scalar: true); + EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, scalar: true); } else { @@ -303,7 +289,7 @@ namespace ChocolArm64.Instructions { if (Optimizations.UseSse41) { - EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: false, scalar: false); + EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, scalar: false); } else { @@ -315,7 +301,7 @@ namespace ChocolArm64.Instructions { if (Optimizations.UseSse41) { - EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, isFixed: true, scalar: false); + EmitSse41Fcvt_Signed(context, RoundMode.TowardsZero, scalar: false); } else { @@ -335,17 +321,38 @@ namespace ChocolArm64.Instructions public static void Fcvtzu_S(ILEmitterCtx context) { - EmitFcvtz(context, signed: false, scalar: true); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Unsigned(context, RoundMode.TowardsZero, scalar: true); + } + else + { + EmitFcvtz(context, signed: false, scalar: true); + } } public static void Fcvtzu_V(ILEmitterCtx context) { - EmitFcvtz(context, signed: false, scalar: false); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Unsigned(context, RoundMode.TowardsZero, scalar: false); + } + else + { + EmitFcvtz(context, signed: false, scalar: false); + } } public static void Fcvtzu_V_Fixed(ILEmitterCtx context) { - EmitFcvtz(context, signed: false, scalar: false); + if (Optimizations.UseSse41) + { + EmitSse41Fcvt_Unsigned(context, RoundMode.TowardsZero, scalar: false); + } + else + { + EmitFcvtz(context, signed: false, scalar: false); + } } public static void Scvtf_Gp(ILEmitterCtx context) @@ -804,168 +811,7 @@ namespace ChocolArm64.Instructions } } - private static void EmitSse41Fcvt_Signed_Gp(ILEmitterCtx context, RoundMode roundMode, bool isFixed) - { - OpCodeSimdCvt64 op = (OpCodeSimdCvt64)context.CurrOp; - - if (op.Size == 0) - { - Type[] typesCmpMul = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesAnd = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesRndCvt = new Type[] { typeof(Vector128) }; - Type[] typesCvt = new Type[] { typeof(Vector128) }; - Type[] typesSav = new Type[] { typeof(int) }; - - //string nameCvt; - int fpMaxVal; - - if (op.RegisterSize == RegisterSize.Int32) - { - //nameCvt = nameof(Sse.ConvertToInt32); - fpMaxVal = 0x4F000000; // 2.14748365E9f (2147483648) - } - else - { - //nameCvt = nameof(Sse.ConvertToInt64); - fpMaxVal = 0x5F000000; // 9.223372E18f (9223372036854775808) - } - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), typesCmpMul)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAnd)); - - if (isFixed) - { - // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, op.FBits) - int fpScaled = 0x40000000 + (op.FBits - 1) * 0x800000; - - context.EmitLdc_I4(fpScaled); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesCmpMul)); - } - - context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - // TODO: Use Sse.ConvertToInt64 once it is fixed (in .NET Core 3.0), - // remove the following if/else and uncomment the code. - - //context.EmitCall(typeof(Sse).GetMethod(nameCvt, typesRndCvt)); - - if (op.RegisterSize == RegisterSize.Int32) - { - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.ConvertToInt32), typesRndCvt)); - } - else - { - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Double), typesRndCvt)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), new Type[] { typeof(Vector128) })); - } - - context.EmitLdvectmp(); - - context.EmitLdc_I4(fpMaxVal); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), typesCmpMul)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt32), typesCvt)); - - if (op.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Xor); - context.Emit(OpCodes.Conv_U8); - } - else - { - context.Emit(OpCodes.Conv_I8); - context.Emit(OpCodes.Xor); - } - - context.EmitStintzr(op.Rd); - } - else /* if (op.Size == 1) */ - { - Type[] typesCmpMul = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesAnd = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesRndCvt = new Type[] { typeof(Vector128) }; - Type[] typesCvt = new Type[] { typeof(Vector128) }; - Type[] typesSav = new Type[] { typeof(long) }; - - string nameCvt; - long fpMaxVal; - - if (op.RegisterSize == RegisterSize.Int32) - { - nameCvt = nameof(Sse2.ConvertToInt32); - fpMaxVal = 0x41E0000000000000L; // 2147483648.0000000d (2147483648) - } - else - { - nameCvt = nameof(Sse2.ConvertToInt64); - fpMaxVal = 0x43E0000000000000L; // 9.2233720368547760E18d (9223372036854775808) - } - - context.EmitLdvec(op.Rn); - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), typesCmpMul)); - - context.EmitLdvec(op.Rn); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAnd)); - - if (isFixed) - { - // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, op.FBits) - long fpScaled = 0x4000000000000000L + (op.FBits - 1) * 0x10000000000000L; - - context.EmitLdc_I8(fpScaled); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesCmpMul)); - } - - context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); - - context.EmitStvectmp(); - context.EmitLdvectmp(); - - context.EmitCall(typeof(Sse2).GetMethod(nameCvt, typesRndCvt)); - - context.EmitLdvectmp(); - - context.EmitLdc_I8(fpMaxVal); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), typesCmpMul)); - - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt32), typesCvt)); - - if (op.RegisterSize == RegisterSize.Int32) - { - context.Emit(OpCodes.Xor); - context.Emit(OpCodes.Conv_U8); - } - else - { - context.Emit(OpCodes.Conv_I8); - context.Emit(OpCodes.Xor); - } - - context.EmitStintzr(op.Rd); - } - } - - private static void EmitSse41Fcvt_Signed(ILEmitterCtx context, RoundMode roundMode, bool isFixed, bool scalar) + private static void EmitSse41Fcvt_Signed(ILEmitterCtx context, RoundMode roundMode, bool scalar) { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; @@ -974,23 +820,22 @@ namespace ChocolArm64.Instructions if (sizeF == 0) { - Type[] typesCmpMul = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesAndXor = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; Type[] typesRndCvt = new Type[] { typeof(Vector128) }; Type[] typesSav = new Type[] { typeof(int) }; context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), typesCmpMul)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), types)); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXor)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); - if (isFixed) + if (op is OpCodeSimdShImm64 fixedOp) { - int fBits = GetImmShr((OpCodeSimdShImm64)op); + int fBits = GetImmShr(fixedOp); // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) int fpScaled = 0x40000000 + (fBits - 1) * 0x800000; @@ -998,7 +843,7 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(fpScaled); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesCmpMul)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), types)); } context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); @@ -1013,9 +858,9 @@ namespace ChocolArm64.Instructions context.EmitLdc_I4(0x4F000000); // 2.14748365E9f (2147483648) context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), typesCmpMul)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), types)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXor)); + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Xor), types)); context.EmitStvec(op.Rd); @@ -1030,24 +875,23 @@ namespace ChocolArm64.Instructions } else /* if (sizeF == 1) */ { - Type[] typesCmpMulUpk = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesAndXor = new Type[] { typeof(Vector128), typeof(Vector128) }; - Type[] typesRndCvt = new Type[] { typeof(Vector128) }; - Type[] typesSv = new Type[] { typeof(long), typeof(long) }; - Type[] typesSav = new Type[] { typeof(long) }; + Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesRndCvt = new Type[] { typeof(Vector128) }; + Type[] typesSv = new Type[] { typeof(long), typeof(long) }; + Type[] typesSav = new Type[] { typeof(long) }; context.EmitLdvec(op.Rn); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), typesCmpMulUpk)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), types)); context.EmitLdvec(op.Rn); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), typesAndXor)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); - if (isFixed) + if (op is OpCodeSimdShImm64 fixedOp) { - int fBits = GetImmShr((OpCodeSimdShImm64)op); + int fBits = GetImmShr(fixedOp); // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) long fpScaled = 0x4000000000000000L + (fBits - 1) * 0x10000000000000L; @@ -1055,19 +899,26 @@ namespace ChocolArm64.Instructions context.EmitLdc_I8(fpScaled); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), typesCmpMulUpk)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), types)); } context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); context.EmitStvectmp(); - context.EmitLdvectmp(); - context.EmitLdvectmp(); + if (!scalar) + { + context.EmitLdvectmp(); + context.EmitLdvectmp(); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), typesCmpMulUpk)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); + } + else + { + context.EmitLdc_I8(0L); + } context.EmitLdvectmp(); @@ -1080,9 +931,223 @@ namespace ChocolArm64.Instructions context.EmitLdc_I8(0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), typesCmpMulUpk)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), types)); - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), typesAndXor)); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types)); + + context.EmitStvec(op.Rd); + + if (scalar) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + } + + private static void EmitSse41Fcvt_Unsigned(ILEmitterCtx context, RoundMode roundMode, bool scalar) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + // sizeF == ((OpCodeSimdShImm64)op).Size - 2 + int sizeF = op.Size & 1; + + if (sizeF == 0) + { + Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesAdd = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesRndCvt = new Type[] { typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(int) }; + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), types)); + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); + + if (op is OpCodeSimdShImm64 fixedOp) + { + int fBits = GetImmShr(fixedOp); + + // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) + int fpScaled = 0x40000000 + (fBits - 1) * 0x800000; + + context.EmitLdc_I4(fpScaled); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), types)); + } + + context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); + + context.Emit(OpCodes.Dup); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), types)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); + + context.EmitStvectmp(); + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt)); + + context.EmitLdvectmp(); + + context.EmitLdc_I4(0x4F000000); // 2.14748365E9f (2147483648) + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitStvectmp2(); + context.EmitLdvectmp2(); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Subtract), types)); + + context.Emit(OpCodes.Dup); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), types)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.And), types)); + + context.EmitStvectmp(); + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Int32), typesRndCvt)); + + context.EmitLdvectmp(); + context.EmitLdvectmp2(); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), types)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Xor), types)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); + + context.EmitStvec(op.Rd); + + if (scalar) + { + EmitVectorZero32_128(context, op.Rd); + } + else if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + else /* if (sizeF == 1) */ + { + Type[] types = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesAdd = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesRndCvt = new Type[] { typeof(Vector128) }; + Type[] typesSv = new Type[] { typeof(long), typeof(long) }; + Type[] typesSav = new Type[] { typeof(long) }; + + context.EmitLdvec(op.Rn); + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareOrdered), types)); + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); + + if (op is OpCodeSimdShImm64 fixedOp) + { + int fBits = GetImmShr(fixedOp); + + // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) + long fpScaled = 0x4000000000000000L + (fBits - 1) * 0x10000000000000L; + + context.EmitLdc_I8(fpScaled); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Multiply), types)); + } + + context.EmitCall(typeof(Sse41).GetMethod(GetSse41NameRnd(roundMode), typesRndCvt)); + + context.Emit(OpCodes.Dup); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), types)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); + + context.EmitStvectmp(); + + if (!scalar) + { + context.EmitLdvectmp(); + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); + } + else + { + context.EmitLdc_I8(0L); + } + + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv)); + + context.EmitLdvectmp(); + + context.EmitLdc_I8(0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808) + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitStvectmp2(); + context.EmitLdvectmp2(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Subtract), types)); + + context.Emit(OpCodes.Dup); + + VectorHelper.EmitCall(context, nameof(VectorHelper.VectorSingleZero)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThan), types)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types)); + + context.EmitStvectmp(); + + if (!scalar) + { + context.EmitLdvectmp(); + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.UnpackHigh), types)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); + } + else + { + context.EmitLdc_I8(0L); + } + + context.EmitLdvectmp(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToInt64), typesRndCvt)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetVector128), typesSv)); + + context.EmitLdvectmp(); + context.EmitLdvectmp2(); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.CompareGreaterThanOrEqual), types)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), typesAdd)); context.EmitStvec(op.Rd); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd.cs b/Ryujinx.Tests/Cpu/CpuTestSimd.cs index e409d8dd7a..fd395da8ef 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimd.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimd.cs @@ -2,6 +2,7 @@ using NUnit.Framework; +using System; using System.Collections.Generic; using System.Runtime.Intrinsics; @@ -172,15 +173,20 @@ namespace Ryujinx.Tests.Cpu } } - private static IEnumerable _1S_F_Cvt_() + private static IEnumerable _1S_F_W_() { // int - yield return 0x00000000CF000001; // -2.1474839E9f (-2147483904) - yield return 0x00000000CF000000; // -2.14748365E9f (-2147483648) - yield return 0x00000000CEFFFFFF; // -2.14748352E9f (-2147483520) - yield return 0x000000004F000001; // 2.1474839E9f (2147483904) - yield return 0x000000004F000000; // 2.14748365E9f (2147483648) - yield return 0x000000004EFFFFFF; // 2.14748352E9f (2147483520) + yield return 0x00000000CF000001ul; // -2.1474839E9f (-2147483904) + yield return 0x00000000CF000000ul; // -2.14748365E9f (-2147483648) + yield return 0x00000000CEFFFFFFul; // -2.14748352E9f (-2147483520) + yield return 0x000000004F000001ul; // 2.1474839E9f (2147483904) + yield return 0x000000004F000000ul; // 2.14748365E9f (2147483648) + yield return 0x000000004EFFFFFFul; // 2.14748352E9f (2147483520) + + // uint + yield return 0x000000004F800001ul; // 4.2949678E9f (4294967808) + yield return 0x000000004F800000ul; // 4.2949673E9f (4294967296) + yield return 0x000000004F7FFFFFul; // 4.29496704E9f (4294967040) yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue) yield return 0x0000000080800000ul; // -Min Normal @@ -214,11 +220,20 @@ namespace Ryujinx.Tests.Cpu for (int cnt = 1; cnt <= RndCnt; cnt++) { ulong grbg = TestContext.CurrentContext.Random.NextUInt(); - ulong rnd1 = GenNormalS(); - ulong rnd2 = GenSubnormalS(); + + ulong rnd1 = (uint)BitConverter.SingleToInt32Bits( + (float)((int)TestContext.CurrentContext.Random.NextUInt())); + ulong rnd2 = (uint)BitConverter.SingleToInt32Bits( + (float)((uint)TestContext.CurrentContext.Random.NextUInt())); + + ulong rnd3 = GenNormalS(); + ulong rnd4 = GenSubnormalS(); yield return (grbg << 32) | rnd1; yield return (grbg << 32) | rnd2; + + yield return (grbg << 32) | rnd3; + yield return (grbg << 32) | rnd4; } } @@ -263,15 +278,20 @@ namespace Ryujinx.Tests.Cpu } } - private static IEnumerable _2S_F_Cvt_() + private static IEnumerable _2S_F_W_() { // int - yield return 0xCF000001CF000001; // -2.1474839E9f (-2147483904) - yield return 0xCF000000CF000000; // -2.14748365E9f (-2147483648) - yield return 0xCEFFFFFFCEFFFFFF; // -2.14748352E9f (-2147483520) - yield return 0x4F0000014F000001; // 2.1474839E9f (2147483904) - yield return 0x4F0000004F000000; // 2.14748365E9f (2147483648) - yield return 0x4EFFFFFF4EFFFFFF; // 2.14748352E9f (2147483520) + yield return 0xCF000001CF000001ul; // -2.1474839E9f (-2147483904) + yield return 0xCF000000CF000000ul; // -2.14748365E9f (-2147483648) + yield return 0xCEFFFFFFCEFFFFFFul; // -2.14748352E9f (-2147483520) + yield return 0x4F0000014F000001ul; // 2.1474839E9f (2147483904) + yield return 0x4F0000004F000000ul; // 2.14748365E9f (2147483648) + yield return 0x4EFFFFFF4EFFFFFFul; // 2.14748352E9f (2147483520) + + // uint + yield return 0x4F8000014F800001ul; // 4.2949678E9f (4294967808) + yield return 0x4F8000004F800000ul; // 4.2949673E9f (4294967296) + yield return 0x4F7FFFFF4F7FFFFFul; // 4.29496704E9f (4294967040) yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue) yield return 0x8080000080800000ul; // -Min Normal @@ -304,11 +324,19 @@ namespace Ryujinx.Tests.Cpu for (int cnt = 1; cnt <= RndCnt; cnt++) { - ulong rnd1 = GenNormalS(); - ulong rnd2 = GenSubnormalS(); + ulong rnd1 = (uint)BitConverter.SingleToInt32Bits( + (float)((int)TestContext.CurrentContext.Random.NextUInt())); + ulong rnd2 = (uint)BitConverter.SingleToInt32Bits( + (float)((uint)TestContext.CurrentContext.Random.NextUInt())); + + ulong rnd3 = GenNormalS(); + ulong rnd4 = GenSubnormalS(); yield return (rnd1 << 32) | rnd1; yield return (rnd2 << 32) | rnd2; + + yield return (rnd3 << 32) | rnd3; + yield return (rnd4 << 32) | rnd4; } } @@ -353,7 +381,7 @@ namespace Ryujinx.Tests.Cpu } } - private static IEnumerable _1D_F_Cvt_() + private static IEnumerable _1D_F_X_() { // long yield return 0xC3E0000000000001ul; // -9.2233720368547780E18d (-9223372036854778000) @@ -363,6 +391,11 @@ namespace Ryujinx.Tests.Cpu yield return 0x43E0000000000000ul; // 9.2233720368547760E18d (9223372036854776000) yield return 0x43DFFFFFFFFFFFFFul; // 9.2233720368547750E18d (9223372036854775000) + // ulong + yield return 0x43F0000000000001ul; // 1.8446744073709556e19d (18446744073709556000) + yield return 0x43F0000000000000ul; // 1.8446744073709552E19d (18446744073709552000) + yield return 0x43EFFFFFFFFFFFFFul; // 1.8446744073709550e19d (18446744073709550000) + yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) yield return 0x8010000000000000ul; // -Min Normal yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal @@ -394,11 +427,19 @@ namespace Ryujinx.Tests.Cpu for (int cnt = 1; cnt <= RndCnt; cnt++) { - ulong rnd1 = GenNormalD(); - ulong rnd2 = GenSubnormalD(); + ulong rnd1 = (ulong)BitConverter.DoubleToInt64Bits( + (double)((long)TestContext.CurrentContext.Random.NextULong())); + ulong rnd2 = (ulong)BitConverter.DoubleToInt64Bits( + (double)((ulong)TestContext.CurrentContext.Random.NextULong())); + + ulong rnd3 = GenNormalD(); + ulong rnd4 = GenSubnormalD(); yield return rnd1; yield return rnd2; + + yield return rnd3; + yield return rnd4; } } #endregion @@ -1467,7 +1508,7 @@ namespace Ryujinx.Tests.Cpu [Test, Pairwise] [Explicit] public void F_Cvt_NZ_SU_S_S([ValueSource("_F_Cvt_NZ_SU_S_S_")] uint opcodes, - [ValueSource("_1S_F_Cvt_")] ulong a) + [ValueSource("_1S_F_W_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); Vector128 v0 = MakeVectorE0E1(z, z); @@ -1480,7 +1521,7 @@ namespace Ryujinx.Tests.Cpu [Test, Pairwise] [Explicit] public void F_Cvt_NZ_SU_S_D([ValueSource("_F_Cvt_NZ_SU_S_D_")] uint opcodes, - [ValueSource("_1D_F_Cvt_")] ulong a) + [ValueSource("_1D_F_X_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); Vector128 v0 = MakeVectorE1(z); @@ -1495,8 +1536,8 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_NZ_SU_V_2S_4S([ValueSource("_F_Cvt_NZ_SU_V_2S_4S_")] uint opcodes, [Values(0u)] uint rd, [Values(1u, 0u)] uint rn, - [ValueSource("_2S_F_Cvt_")] ulong z, - [ValueSource("_2S_F_Cvt_")] ulong a, + [ValueSource("_2S_F_W_")] ulong z, + [ValueSource("_2S_F_W_")] ulong a, [Values(0b0u, 0b1u)] uint q) // <2S, 4S> { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); @@ -1514,8 +1555,8 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_NZ_SU_V_2D([ValueSource("_F_Cvt_NZ_SU_V_2D_")] uint opcodes, [Values(0u)] uint rd, [Values(1u, 0u)] uint rn, - [ValueSource("_1D_F_Cvt_")] ulong z, - [ValueSource("_1D_F_Cvt_")] ulong a) + [ValueSource("_1D_F_X_")] ulong z, + [ValueSource("_1D_F_X_")] ulong a) { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs index 775044a020..60935488ef 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs @@ -2,6 +2,7 @@ using NUnit.Framework; +using System; using System.Collections.Generic; using System.Runtime.Intrinsics; @@ -13,15 +14,15 @@ namespace Ryujinx.Tests.Cpu #if SimdCvt #region "ValueSource (Types)" - private static IEnumerable _1S_F_Cvt_() + private static IEnumerable _1S_F_WX_() { // int - yield return 0x00000000CF000001; // -2.1474839E9f (-2147483904) - yield return 0x00000000CF000000; // -2.14748365E9f (-2147483648) - yield return 0x00000000CEFFFFFF; // -2.14748352E9f (-2147483520) - yield return 0x000000004F000001; // 2.1474839E9f (2147483904) - yield return 0x000000004F000000; // 2.14748365E9f (2147483648) - yield return 0x000000004EFFFFFF; // 2.14748352E9f (2147483520) + yield return 0x00000000CF000001ul; // -2.1474839E9f (-2147483904) + yield return 0x00000000CF000000ul; // -2.14748365E9f (-2147483648) + yield return 0x00000000CEFFFFFFul; // -2.14748352E9f (-2147483520) + yield return 0x000000004F000001ul; // 2.1474839E9f (2147483904) + yield return 0x000000004F000000ul; // 2.14748365E9f (2147483648) + yield return 0x000000004EFFFFFFul; // 2.14748352E9f (2147483520) // long yield return 0x00000000DF000001ul; // -9.223373E18f (-9223373136366403584) @@ -31,6 +32,16 @@ namespace Ryujinx.Tests.Cpu yield return 0x000000005F000000ul; // 9.223372E18f (9223372036854775808) yield return 0x000000005EFFFFFFul; // 9.2233715E18f (9223371487098961920) + // uint + yield return 0x000000004F800001ul; // 4.2949678E9f (4294967808) + yield return 0x000000004F800000ul; // 4.2949673E9f (4294967296) + yield return 0x000000004F7FFFFFul; // 4.29496704E9f (4294967040) + + // ulong + yield return 0x000000005F800001ul; // 1.8446746E19f (18446746272732807168) + yield return 0x000000005F800000ul; // 1.8446744E19f (18446744073709551616) + yield return 0x000000005F7FFFFFul; // 1.8446743E19f (18446742974197923840) + yield return 0x00000000FF7FFFFFul; // -Max Normal (float.MinValue) yield return 0x0000000080800000ul; // -Min Normal yield return 0x00000000807FFFFFul; // -Max Subnormal @@ -63,15 +74,30 @@ namespace Ryujinx.Tests.Cpu for (int cnt = 1; cnt <= RndCnt; cnt++) { ulong grbg = TestContext.CurrentContext.Random.NextUInt(); - ulong rnd1 = GenNormalS(); - ulong rnd2 = GenSubnormalS(); + + ulong rnd1 = (uint)BitConverter.SingleToInt32Bits( + (float)((int)TestContext.CurrentContext.Random.NextUInt())); + ulong rnd2 = (uint)BitConverter.SingleToInt32Bits( + (float)((long)TestContext.CurrentContext.Random.NextULong())); + ulong rnd3 = (uint)BitConverter.SingleToInt32Bits( + (float)((uint)TestContext.CurrentContext.Random.NextUInt())); + ulong rnd4 = (uint)BitConverter.SingleToInt32Bits( + (float)((ulong)TestContext.CurrentContext.Random.NextULong())); + + ulong rnd5 = GenNormalS(); + ulong rnd6 = GenSubnormalS(); yield return (grbg << 32) | rnd1; yield return (grbg << 32) | rnd2; + yield return (grbg << 32) | rnd3; + yield return (grbg << 32) | rnd4; + + yield return (grbg << 32) | rnd5; + yield return (grbg << 32) | rnd6; } } - private static IEnumerable _1D_F_Cvt_() + private static IEnumerable _1D_F_WX_() { // int yield return 0xC1E0000000200000ul; // -2147483649.0000000d (-2147483649) @@ -89,6 +115,16 @@ namespace Ryujinx.Tests.Cpu yield return 0x43E0000000000000ul; // 9.2233720368547760E18d (9223372036854776000) yield return 0x43DFFFFFFFFFFFFFul; // 9.2233720368547750E18d (9223372036854775000) + // uint + yield return 0x41F0000000100000ul; // 4294967297.0000000d (4294967297) + yield return 0x41F0000000000000ul; // 4294967296.0000000d (4294967296) + yield return 0x41EFFFFFFFE00000ul; // 4294967295.0000000d (4294967295) + + // ulong + yield return 0x43F0000000000001ul; // 1.8446744073709556e19d (18446744073709556000) + yield return 0x43F0000000000000ul; // 1.8446744073709552E19d (18446744073709552000) + yield return 0x43EFFFFFFFFFFFFFul; // 1.8446744073709550e19d (18446744073709550000) + yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) yield return 0x8010000000000000ul; // -Min Normal yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal @@ -120,11 +156,25 @@ namespace Ryujinx.Tests.Cpu for (int cnt = 1; cnt <= RndCnt; cnt++) { - ulong rnd1 = GenNormalD(); - ulong rnd2 = GenSubnormalD(); + ulong rnd1 = (ulong)BitConverter.DoubleToInt64Bits( + (double)((int)TestContext.CurrentContext.Random.NextUInt())); + ulong rnd2 = (ulong)BitConverter.DoubleToInt64Bits( + (double)((long)TestContext.CurrentContext.Random.NextULong())); + ulong rnd3 = (ulong)BitConverter.DoubleToInt64Bits( + (double)((uint)TestContext.CurrentContext.Random.NextUInt())); + ulong rnd4 = (ulong)BitConverter.DoubleToInt64Bits( + (double)((ulong)TestContext.CurrentContext.Random.NextULong())); + + ulong rnd5 = GenNormalD(); + ulong rnd6 = GenSubnormalD(); yield return rnd1; yield return rnd2; + yield return rnd3; + yield return rnd4; + + yield return rnd5; + yield return rnd6; } } @@ -286,7 +336,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_AMPZ_SU_Gp_SW([ValueSource("_F_Cvt_AMPZ_SU_Gp_SW_")] uint opcodes, [Values(0u, 31u)] uint rd, [Values(1u)] uint rn, - [ValueSource("_1S_F_Cvt_")] ulong a) + [ValueSource("_1S_F_WX_")] ulong a) { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); @@ -303,7 +353,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_AMPZ_SU_Gp_SX([ValueSource("_F_Cvt_AMPZ_SU_Gp_SX_")] uint opcodes, [Values(0u, 31u)] uint rd, [Values(1u)] uint rn, - [ValueSource("_1S_F_Cvt_")] ulong a) + [ValueSource("_1S_F_WX_")] ulong a) { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); @@ -319,7 +369,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_AMPZ_SU_Gp_DW([ValueSource("_F_Cvt_AMPZ_SU_Gp_DW_")] uint opcodes, [Values(0u, 31u)] uint rd, [Values(1u)] uint rn, - [ValueSource("_1D_F_Cvt_")] ulong a) + [ValueSource("_1D_F_WX_")] ulong a) { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); @@ -336,7 +386,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_AMPZ_SU_Gp_DX([ValueSource("_F_Cvt_AMPZ_SU_Gp_DX_")] uint opcodes, [Values(0u, 31u)] uint rd, [Values(1u)] uint rn, - [ValueSource("_1D_F_Cvt_")] ulong a) + [ValueSource("_1D_F_WX_")] ulong a) { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); @@ -352,7 +402,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_Z_SU_Gp_Fixed_SW([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_SW_")] uint opcodes, [Values(0u, 31u)] uint rd, [Values(1u)] uint rn, - [ValueSource("_1S_F_Cvt_")] ulong a, + [ValueSource("_1S_F_WX_")] ulong a, [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits) { uint scale = (64u - fBits) & 0x3Fu; @@ -373,7 +423,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_Z_SU_Gp_Fixed_SX([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_SX_")] uint opcodes, [Values(0u, 31u)] uint rd, [Values(1u)] uint rn, - [ValueSource("_1S_F_Cvt_")] ulong a, + [ValueSource("_1S_F_WX_")] ulong a, [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) { uint scale = (64u - fBits) & 0x3Fu; @@ -393,7 +443,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_Z_SU_Gp_Fixed_DW([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_DW_")] uint opcodes, [Values(0u, 31u)] uint rd, [Values(1u)] uint rn, - [ValueSource("_1D_F_Cvt_")] ulong a, + [ValueSource("_1D_F_WX_")] ulong a, [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits) { uint scale = (64u - fBits) & 0x3Fu; @@ -414,7 +464,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_Z_SU_Gp_Fixed_DX([ValueSource("_F_Cvt_Z_SU_Gp_Fixed_DX_")] uint opcodes, [Values(0u, 31u)] uint rd, [Values(1u)] uint rn, - [ValueSource("_1D_F_Cvt_")] ulong a, + [ValueSource("_1D_F_WX_")] ulong a, [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) { uint scale = (64u - fBits) & 0x3Fu; diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs index c1a1ed42a5..cabaac0220 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs @@ -2,6 +2,7 @@ using NUnit.Framework; +using System; using System.Collections.Generic; using System.Runtime.Intrinsics; @@ -49,15 +50,20 @@ namespace Ryujinx.Tests.Cpu 0x8080808080808080ul, 0xFFFFFFFFFFFFFFFFul }; } - private static IEnumerable _2S_F_Cvt_() + private static IEnumerable _2S_F_W_() { // int - yield return 0xCF000001CF000001; // -2.1474839E9f (-2147483904) - yield return 0xCF000000CF000000; // -2.14748365E9f (-2147483648) - yield return 0xCEFFFFFFCEFFFFFF; // -2.14748352E9f (-2147483520) - yield return 0x4F0000014F000001; // 2.1474839E9f (2147483904) - yield return 0x4F0000004F000000; // 2.14748365E9f (2147483648) - yield return 0x4EFFFFFF4EFFFFFF; // 2.14748352E9f (2147483520) + yield return 0xCF000001CF000001ul; // -2.1474839E9f (-2147483904) + yield return 0xCF000000CF000000ul; // -2.14748365E9f (-2147483648) + yield return 0xCEFFFFFFCEFFFFFFul; // -2.14748352E9f (-2147483520) + yield return 0x4F0000014F000001ul; // 2.1474839E9f (2147483904) + yield return 0x4F0000004F000000ul; // 2.14748365E9f (2147483648) + yield return 0x4EFFFFFF4EFFFFFFul; // 2.14748352E9f (2147483520) + + // uint + yield return 0x4F8000014F800001ul; // 4.2949678E9f (4294967808) + yield return 0x4F8000004F800000ul; // 4.2949673E9f (4294967296) + yield return 0x4F7FFFFF4F7FFFFFul; // 4.29496704E9f (4294967040) yield return 0xFF7FFFFFFF7FFFFFul; // -Max Normal (float.MinValue) yield return 0x8080000080800000ul; // -Min Normal @@ -90,15 +96,23 @@ namespace Ryujinx.Tests.Cpu for (int cnt = 1; cnt <= RndCnt; cnt++) { - ulong rnd1 = GenNormalS(); - ulong rnd2 = GenSubnormalS(); + ulong rnd1 = (uint)BitConverter.SingleToInt32Bits( + (float)((int)TestContext.CurrentContext.Random.NextUInt())); + ulong rnd2 = (uint)BitConverter.SingleToInt32Bits( + (float)((uint)TestContext.CurrentContext.Random.NextUInt())); + + ulong rnd3 = GenNormalS(); + ulong rnd4 = GenSubnormalS(); yield return (rnd1 << 32) | rnd1; yield return (rnd2 << 32) | rnd2; + + yield return (rnd3 << 32) | rnd3; + yield return (rnd4 << 32) | rnd4; } } - private static IEnumerable _1D_F_Cvt_() + private static IEnumerable _1D_F_X_() { // long yield return 0xC3E0000000000001ul; // -9.2233720368547780E18d (-9223372036854778000) @@ -108,6 +122,11 @@ namespace Ryujinx.Tests.Cpu yield return 0x43E0000000000000ul; // 9.2233720368547760E18d (9223372036854776000) yield return 0x43DFFFFFFFFFFFFFul; // 9.2233720368547750E18d (9223372036854775000) + // ulong + yield return 0x43F0000000000001ul; // 1.8446744073709556e19d (18446744073709556000) + yield return 0x43F0000000000000ul; // 1.8446744073709552E19d (18446744073709552000) + yield return 0x43EFFFFFFFFFFFFFul; // 1.8446744073709550e19d (18446744073709550000) + yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue) yield return 0x8010000000000000ul; // -Min Normal yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal @@ -139,11 +158,19 @@ namespace Ryujinx.Tests.Cpu for (int cnt = 1; cnt <= RndCnt; cnt++) { - ulong rnd1 = GenNormalD(); - ulong rnd2 = GenSubnormalD(); + ulong rnd1 = (ulong)BitConverter.DoubleToInt64Bits( + (double)((long)TestContext.CurrentContext.Random.NextULong())); + ulong rnd2 = (ulong)BitConverter.DoubleToInt64Bits( + (double)((ulong)TestContext.CurrentContext.Random.NextULong())); + + ulong rnd3 = GenNormalD(); + ulong rnd4 = GenSubnormalD(); yield return rnd1; yield return rnd2; + + yield return rnd3; + yield return rnd4; } } #endregion @@ -387,8 +414,8 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_Z_SU_V_Fixed_2S_4S([ValueSource("_F_Cvt_Z_SU_V_Fixed_2S_4S_")] uint opcodes, [Values(0u)] uint rd, [Values(1u, 0u)] uint rn, - [ValueSource("_2S_F_Cvt_")] ulong z, - [ValueSource("_2S_F_Cvt_")] ulong a, + [ValueSource("_2S_F_W_")] ulong z, + [ValueSource("_2S_F_W_")] ulong a, [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits, [Values(0b0u, 0b1u)] uint q) // <2S, 4S> { @@ -410,8 +437,8 @@ namespace Ryujinx.Tests.Cpu public void F_Cvt_Z_SU_V_Fixed_2D([ValueSource("_F_Cvt_Z_SU_V_Fixed_2D_")] uint opcodes, [Values(0u)] uint rd, [Values(1u, 0u)] uint rn, - [ValueSource("_1D_F_Cvt_")] ulong z, - [ValueSource("_1D_F_Cvt_")] ulong a, + [ValueSource("_1D_F_X_")] ulong z, + [ValueSource("_1D_F_X_")] ulong a, [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) { uint immHb = (128 - fBits) & 0x7F; From b2e88b04a85b41cc60af3485d88c90429e84a218 Mon Sep 17 00:00:00 2001 From: BaronKiko Date: Tue, 16 Apr 2019 00:22:55 +0100 Subject: [PATCH 32/36] Config option to ignore missing services (#658) * Implemented config option to ignore missing services * Removed unused using statement * Resolved comments from review --- Ryujinx.HLE/HOS/Services/DummyService.cs | 20 ++++++++++++++++++++ Ryujinx.HLE/HOS/Services/IpcService.cs | 22 +++++++++++++++++++--- Ryujinx.HLE/HOS/Services/ServiceFactory.cs | 12 ++++++++++++ Ryujinx/Config.jsonc | 3 +++ Ryujinx/Configuration.cs | 8 ++++++++ Ryujinx/_schema.json | 11 +++++++++++ 6 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 Ryujinx.HLE/HOS/Services/DummyService.cs diff --git a/Ryujinx.HLE/HOS/Services/DummyService.cs b/Ryujinx.HLE/HOS/Services/DummyService.cs new file mode 100644 index 0000000000..28087bdf8b --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/DummyService.cs @@ -0,0 +1,20 @@ +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Services +{ + class DummyService : IpcService + { + private Dictionary _commands; + + public override IReadOnlyDictionary Commands => _commands; + + public string ServiceName { get; set; } + + public DummyService(string serviceName) + { + _commands = new Dictionary(); + ServiceName = serviceName; + } + } +} diff --git a/Ryujinx.HLE/HOS/Services/IpcService.cs b/Ryujinx.HLE/HOS/Services/IpcService.cs index 71683ce3c5..2a4a93192b 100644 --- a/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -89,13 +89,29 @@ namespace Ryujinx.HLE.HOS.Services long sfciMagic = context.RequestData.ReadInt64(); int commandId = (int)context.RequestData.ReadInt64(); - if (service.Commands.TryGetValue(commandId, out ServiceProcessRequest processRequest)) + bool serviceExists = service.Commands.TryGetValue(commandId, out ServiceProcessRequest processRequest); + + if (ServiceConfiguration.IgnoreMissingServices || serviceExists) { + long result = 0; + context.ResponseData.BaseStream.Seek(_isDomain ? 0x20 : 0x10, SeekOrigin.Begin); - Logger.PrintDebug(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Method.Name}"); + if (serviceExists) + { + Logger.PrintDebug(LogClass.KernelIpc, $"{service.GetType().Name}: {processRequest.Method.Name}"); - long result = processRequest(context); + result = processRequest(context); + } + else + { + string serviceName; + DummyService dummyService = service as DummyService; + + serviceName = (dummyService == null) ? service.GetType().FullName : dummyService.ServiceName; + + Logger.PrintWarning(LogClass.KernelIpc, $"Missing service {serviceName}: {commandId} ignored"); + } if (_isDomain) { diff --git a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs index 83a217a5d3..113bbe51c8 100644 --- a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs +++ b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Services.Acc; using Ryujinx.HLE.HOS.Services.Am; using Ryujinx.HLE.HOS.Services.Apm; @@ -30,6 +31,11 @@ using System; namespace Ryujinx.HLE.HOS.Services { + public static class ServiceConfiguration + { + public static bool IgnoreMissingServices { get; set; } + } + static class ServiceFactory { public static IpcService MakeService(Horizon system, string name) @@ -209,6 +215,12 @@ namespace Ryujinx.HLE.HOS.Services return new IApplicationRootService(); } + if (ServiceConfiguration.IgnoreMissingServices) + { + Logger.PrintWarning(LogClass.Service, $"Missing service {name} ignored"); + return new DummyService(name); + } + throw new NotImplementedException(name); } } diff --git a/Ryujinx/Config.jsonc b/Ryujinx/Config.jsonc index 6e808b56fd..151756f43c 100644 --- a/Ryujinx/Config.jsonc +++ b/Ryujinx/Config.jsonc @@ -44,6 +44,9 @@ // Enable or disable aggressive CPU optimizations "enable_aggressive_cpu_opts": true, + // Enable or disable ignoring missing services, this may cause instability + "ignore_missing_services": false, + // The primary controller's type // Supported Values: Handheld, ProController, NpadPair, NpadLeft, NpadRight "controller_type": "Handheld", diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs index c4a1b4369f..560a6dab59 100644 --- a/Ryujinx/Configuration.cs +++ b/Ryujinx/Configuration.cs @@ -4,6 +4,7 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.HLE; using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.HOS.Services; using Ryujinx.HLE.Input; using Ryujinx.UI.Input; using System; @@ -91,6 +92,11 @@ namespace Ryujinx /// public bool EnableAggressiveCpuOpts { get; private set; } + /// + /// Enable or disable ignoring missing services + /// + public bool IgnoreMissingServices { get; private set; } + /// /// The primary controller's type /// @@ -207,6 +213,8 @@ namespace Ryujinx Optimizations.AssumeStrictAbiCompliance = true; } + ServiceConfiguration.IgnoreMissingServices = Instance.IgnoreMissingServices; + if(Instance.GamepadControls.Enabled) { if (GamePad.GetName(Instance.GamepadControls.Index) == "Unmapped Controller") diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json index 7e7e466594..11eff12b08 100644 --- a/Ryujinx/_schema.json +++ b/Ryujinx/_schema.json @@ -411,6 +411,17 @@ false ] }, + "ignore_missing_services": { + "$id": "#/properties/ignore_missing_services", + "type": "boolean", + "title": "Ignore Missing Services", + "description": "Enable or disable ignoring missing services, this may cause instability", + "default": false, + "examples": [ + true, + false + ] + }, "controller_type": { "$id": "#/properties/controller_type", "type": "string", From 6b23a2c125b9c48b5ebea92716004ef68698bb0f Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 17 Apr 2019 20:57:08 -0300 Subject: [PATCH 33/36] New shader translator implementation (#654) * Start implementing a new shader translator * Fix shift instructions and a typo * Small refactoring on StructuredProgram, move RemovePhis method to a separate class * Initial geometry shader support * Implement TLD4 * Fix -- There's no negation on FMUL32I * Add constant folding and algebraic simplification optimizations, nits * Some leftovers from constant folding * Avoid cast for constant assignments * Add a branch elimination pass, and misc small fixes * Remove redundant branches, add expression propagation and other improvements on the code * Small leftovers -- add missing break and continue, remove unused properties, other improvements * Add null check to handle empty block cases on block visitor * Add HADD2 and HMUL2 half float shader instructions * Optimize pack/unpack sequences, some fixes related to half float instructions * Add TXQ, TLD, TLDS and TLD4S shader texture instructions, and some support for bindless textures, some refactoring on codegen * Fix copy paste mistake that caused RZ to be ignored on the AST instruction * Add workaround for conditional exit, and fix half float instruction with constant buffer * Add missing 0.0 source for TLDS.LZ variants * Simplify the switch for TLDS.LZ * Texture instructions related fixes * Implement the HFMA instruction, and some misc. fixes * Enable constant folding on UnpackHalf2x16 instructions * Refactor HFMA to use OpCode* for opcode decoding rather than on the helper methods * Remove the old shader translator * Remove ShaderDeclInfo and other unused things * Add dual vertex shader support * Add ShaderConfig, used to pass shader type and maximum cbuffer size * Move and rename some instruction enums * Move texture instructions into a separate file * Move operand GetExpression and locals management to OperandManager * Optimize opcode decoding using a simple list and binary search * Add missing condition for do-while on goto elimination * Misc. fixes on texture instructions * Simplify TLDS switch * Address PR feedback, and a nit --- Ryujinx.Graphics/Gal/IGalShader.cs | 5 +- Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs | 5 +- Ryujinx.Graphics/Gal/OpenGL/OglShader.cs | 51 +- .../Gal/OpenGL/OglShaderProgram.cs | 13 +- Ryujinx.Graphics/Gal/Shader/GlslDecl.cs | 420 ----- Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 1679 ----------------- Ryujinx.Graphics/Gal/Shader/GlslProgram.cs | 22 - .../Gal/Shader/ShaderDecodeAlu.cs | 1299 ------------- .../Gal/Shader/ShaderDecodeFlow.cs | 57 - .../Gal/Shader/ShaderDecodeFunc.cs | 4 - .../Gal/Shader/ShaderDecodeHelper.cs | 78 - .../Gal/Shader/ShaderDecodeMem.cs | 878 --------- .../Gal/Shader/ShaderDecodeMove.cs | 431 ----- .../Gal/Shader/ShaderDecodeOpCode.cs | 313 --- .../Gal/Shader/ShaderDecodeSpecial.cs | 25 - Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs | 218 --- Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs | 146 -- Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs | 10 - Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs | 14 - Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs | 46 - Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs | 12 - Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs | 17 - Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs | 94 - Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs | 4 - .../Gal/Shader/ShaderIrMetaIpa.cs | 12 - .../Gal/Shader/ShaderIrMetaTex.cs | 24 - .../Gal/Shader/ShaderIrMetaTexq.cs | 15 - Ryujinx.Graphics/Gal/Shader/ShaderIrNode.cs | 4 - Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs | 25 - .../Gal/Shader/ShaderIrOperAbuf.cs | 15 - .../Gal/Shader/ShaderIrOperCbuf.cs | 17 - .../Gal/Shader/ShaderIrOperGpr.cs | 36 - .../Gal/Shader/ShaderIrOperImm.cs | 12 - .../Gal/Shader/ShaderIrOperImmf.cs | 12 - .../Gal/Shader/ShaderIrOperPred.cs | 17 - .../Gal/Shader/ShaderOpCodeTable.cs | 190 -- Ryujinx.Graphics/Gal/Shader/ShaderOper.cs | 11 - .../Gal/Shader/ShaderRegisterSize.cs | 9 - Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs | 13 - Ryujinx.Graphics/Gal/ShaderDeclInfo.cs | 45 - Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs | 25 +- Ryujinx.Graphics/Shader/CBufferDescriptor.cs | 15 + .../Shader/CodeGen/Glsl/CodeGenContext.cs | 90 + .../Shader/CodeGen/Glsl/Declarations.cs | 206 ++ .../Shader/CodeGen/Glsl/DefaultNames.cs | 17 + .../Shader/CodeGen/Glsl/GlslGenerator.cs | 133 ++ .../Shader/CodeGen/Glsl/GlslProgram.cs | 20 + .../CodeGen/Glsl/Instructions/InstGen.cs | 110 ++ .../Glsl/Instructions/InstGenHelper.cs | 170 ++ .../Glsl/Instructions/InstGenMemory.cs | 244 +++ .../Glsl/Instructions/InstGenPacking.cs | 45 + .../CodeGen/Glsl/Instructions/InstInfo.cs | 18 + .../CodeGen/Glsl/Instructions/InstType.cs | 27 + .../Shader/CodeGen/Glsl/NumberFormatter.cs | 104 + .../Shader/CodeGen/Glsl/OperandManager.cs | 239 +++ .../Shader/CodeGen/Glsl/TypeConversion.cs | 85 + .../Shader/Decoders/BitfieldExtensions.cs | 25 + Ryujinx.Graphics/Shader/Decoders/Block.cs | 117 ++ Ryujinx.Graphics/Shader/Decoders/Condition.cs | 45 + .../Shader/Decoders/ConditionalOperation.cs | 10 + Ryujinx.Graphics/Shader/Decoders/Decoder.cs | 406 ++++ .../Shader/Decoders/DecoderHelper.cs | 58 + .../Shader/Decoders/FPHalfSwizzle.cs | 10 + Ryujinx.Graphics/Shader/Decoders/FPType.cs | 9 + Ryujinx.Graphics/Shader/Decoders/FmulScale.cs | 13 + Ryujinx.Graphics/Shader/Decoders/IOpCode.cs | 16 + .../Shader/Decoders/IOpCodeAlu.cs | 12 + .../Shader/Decoders/IOpCodeCbuf.cs | 8 + .../Shader/Decoders/IOpCodeFArith.cs | 12 + .../Shader/Decoders/IOpCodeHfma.cs | 13 + .../Shader/Decoders/IOpCodeImm.cs | 7 + .../Shader/Decoders/IOpCodeImmF.cs | 7 + .../Shader/Decoders/IOpCodeLop.cs | 10 + Ryujinx.Graphics/Shader/Decoders/IOpCodeRa.cs | 7 + Ryujinx.Graphics/Shader/Decoders/IOpCodeRc.cs | 7 + Ryujinx.Graphics/Shader/Decoders/IOpCodeRd.cs | 7 + .../Shader/Decoders/IOpCodeReg.cs | 7 + .../Shader/Decoders/IOpCodeRegCbuf.cs | 8 + .../Shader/Decoders/IntegerCondition.cs | 18 + .../Shader/Decoders/IntegerHalfPart.cs | 9 + .../Shader/Decoders/IntegerShift.cs | 9 + .../Shader/Decoders/IntegerSize.cs | 12 + .../Shader/Decoders/IntegerType.cs | 14 + .../Shader/Decoders/LogicalOperation.cs | 10 + .../Shader/Decoders/MufuOperation.cs | 15 + Ryujinx.Graphics/Shader/Decoders/OpCode.cs | 30 + Ryujinx.Graphics/Shader/Decoders/OpCodeAlu.cs | 34 + .../Shader/Decoders/OpCodeAluCbuf.cs | 16 + .../Shader/Decoders/OpCodeAluImm.cs | 14 + .../Shader/Decoders/OpCodeAluImm2x10.cs | 14 + .../Shader/Decoders/OpCodeAluImm32.cs | 18 + .../Shader/Decoders/OpCodeAluReg.cs | 14 + .../Shader/Decoders/OpCodeAluRegCbuf.cs | 18 + .../Shader/Decoders/OpCodeAttribute.cs | 16 + .../Shader/Decoders/OpCodeBranch.cs | 19 + .../Shader/Decoders/OpCodeExit.cs | 14 + .../Shader/Decoders/OpCodeFArith.cs | 24 + .../Shader/Decoders/OpCodeFArithCbuf.cs | 16 + .../Shader/Decoders/OpCodeFArithImm.cs | 14 + .../Shader/Decoders/OpCodeFArithImm32.cs | 30 + .../Shader/Decoders/OpCodeFArithReg.cs | 14 + .../Shader/Decoders/OpCodeFArithRegCbuf.cs | 16 + .../Shader/Decoders/OpCodeFsetImm.cs | 14 + .../Shader/Decoders/OpCodeHfma.cs | 22 + .../Shader/Decoders/OpCodeHfmaCbuf.cs | 30 + .../Shader/Decoders/OpCodeHfmaImm2x10.cs | 26 + .../Shader/Decoders/OpCodeHfmaImm32.cs | 25 + .../Shader/Decoders/OpCodeHfmaReg.cs | 29 + .../Shader/Decoders/OpCodeHfmaRegCbuf.cs | 30 + Ryujinx.Graphics/Shader/Decoders/OpCodeIpa.cs | 14 + Ryujinx.Graphics/Shader/Decoders/OpCodeLdc.cs | 26 + Ryujinx.Graphics/Shader/Decoders/OpCodeLop.cs | 28 + .../Shader/Decoders/OpCodeLopCbuf.cs | 16 + .../Shader/Decoders/OpCodeLopImm.cs | 14 + .../Shader/Decoders/OpCodeLopImm32.cs | 22 + .../Shader/Decoders/OpCodeLopReg.cs | 14 + .../Shader/Decoders/OpCodePsetp.cs | 20 + Ryujinx.Graphics/Shader/Decoders/OpCodeSet.cs | 26 + .../Shader/Decoders/OpCodeSetCbuf.cs | 16 + .../Shader/Decoders/OpCodeSetImm.cs | 14 + .../Shader/Decoders/OpCodeSetReg.cs | 14 + Ryujinx.Graphics/Shader/Decoders/OpCodeSsy.cs | 20 + .../Shader/Decoders/OpCodeSync.cs | 15 + .../Shader/Decoders/OpCodeTable.cs | 216 +++ Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs | 14 + .../Shader/Decoders/OpCodeTexs.cs | 11 + .../Shader/Decoders/OpCodeTexture.cs | 42 + .../Shader/Decoders/OpCodeTextureScalar.cs | 61 + Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs | 20 + .../Shader/Decoders/OpCodeTld4.cs | 20 + .../Shader/Decoders/OpCodeTld4s.cs | 20 + .../Shader/Decoders/OpCodeTlds.cs | 11 + Ryujinx.Graphics/Shader/Decoders/Register.cs | 36 + .../Shader/Decoders/RegisterConsts.cs | 13 + .../Shader/Decoders/RegisterType.cs | 9 + .../Shader/Decoders/RoundingMode.cs | 10 + .../Shader/Decoders/TexelLoadScalarType.cs | 15 + .../Shader/Decoders/TextureDimensions.cs | 10 + .../Shader/Decoders/TextureGatherOffset.cs | 9 + .../Shader/Decoders/TextureLodMode.cs | 12 + .../Shader/Decoders/TextureProperty.cs | 13 + .../Shader/Decoders/TextureScalarType.cs | 20 + Ryujinx.Graphics/Shader/Decoders/XmadCMode.cs | 11 + .../Shader/Instructions/InstEmitAlu.cs | 684 +++++++ .../Shader/Instructions/InstEmitAluHelper.cs | 88 + .../Shader/Instructions/InstEmitConversion.cs | 213 +++ .../Shader/Instructions/InstEmitFArith.cs | 369 ++++ .../Shader/Instructions/InstEmitFlow.cs | 107 ++ .../Shader/Instructions/InstEmitHelper.cs | 267 +++ .../Shader/Instructions/InstEmitMemory.cs | 138 ++ .../Shader/Instructions/InstEmitMove.cs | 32 + .../Shader/Instructions/InstEmitTexture.cs | 776 ++++++++ .../Shader/Instructions/InstEmitter.cs | 6 + .../Shader/Instructions/Lop3Expression.cs | 149 ++ .../IntermediateRepresentation/BasicBlock.cs | 61 + .../IntermediateRepresentation/INode.cs | 13 + .../IntermediateRepresentation/Instruction.cs | 87 + .../IntermediateRepresentation/IrConsts.cs | 8 + .../IntermediateRepresentation/Operand.cs | 79 + .../OperandHelper.cs | 62 + .../IntermediateRepresentation/OperandType.cs | 15 + .../IntermediateRepresentation/Operation.cs | 101 + .../IntermediateRepresentation/PhiNode.cs | 94 + .../TextureFlags.cs | 17 + .../TextureOperation.cs | 24 + .../IntermediateRepresentation/TextureType.cs | 35 + Ryujinx.Graphics/Shader/ShaderConfig.cs | 23 + Ryujinx.Graphics/Shader/ShaderHeader.cs | 166 ++ Ryujinx.Graphics/Shader/ShaderProgram.cs | 15 + Ryujinx.Graphics/Shader/ShaderProgramInfo.cs | 17 + .../Shader/StructuredIr/AstAssignment.cs | 35 + .../Shader/StructuredIr/AstBlock.cs | 116 ++ .../Shader/StructuredIr/AstBlockType.cs | 12 + .../Shader/StructuredIr/AstBlockVisitor.cs | 68 + .../Shader/StructuredIr/AstHelper.cs | 73 + .../Shader/StructuredIr/AstNode.cs | 11 + .../Shader/StructuredIr/AstOperand.cs | 49 + .../Shader/StructuredIr/AstOperation.cs | 49 + .../Shader/StructuredIr/AstOptimizer.cs | 149 ++ .../StructuredIr/AstTextureOperation.cs | 25 + .../Shader/StructuredIr/GotoElimination.cs | 459 +++++ .../Shader/StructuredIr/GotoStatement.cs | 23 + .../Shader/StructuredIr/IAstNode.cs | 11 + .../Shader/StructuredIr/InstructionInfo.cs | 142 ++ .../Shader/StructuredIr/OperandInfo.cs | 34 + .../Shader/StructuredIr/PhiFunctions.cs | 74 + .../Shader/StructuredIr/StructuredProgram.cs | 254 +++ .../StructuredIr/StructuredProgramContext.cs | 292 +++ .../StructuredIr/StructuredProgramInfo.cs | 32 + .../Shader/StructuredIr/VariableType.cs | 13 + Ryujinx.Graphics/Shader/TextureDescriptor.cs | 36 + .../Shader/Translation/AttributeConsts.cs | 30 + .../Shader/Translation/ControlFlowGraph.cs | 108 ++ .../Shader/Translation/Dominance.cs | 127 ++ .../Shader/Translation/EmitterContext.cs | 105 ++ .../Shader/Translation/EmitterContextInsts.cs | 420 +++++ .../Optimizations/BranchElimination.cs | 64 + .../Optimizations/ConstantFolding.cs | 323 ++++ .../Optimizations/HalfConversion.cs | 47 + .../Translation/Optimizations/Optimizer.cs | 172 ++ .../Optimizations/Simplification.cs | 147 ++ Ryujinx.Graphics/Shader/Translation/Ssa.cs | 330 ++++ .../Shader/Translation/Translator.cs | 219 +++ .../Texture/TextureInstructionSuffix.cs | 19 - Ryujinx.ShaderTools/Memory.cs | 2 +- Ryujinx.ShaderTools/Program.cs | 31 +- Ryujinx/Program.cs | 2 +- 207 files changed, 11514 insertions(+), 6311 deletions(-) delete mode 100644 Ryujinx.Graphics/Gal/Shader/GlslDecl.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/GlslProgram.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrNode.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderOper.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderRegisterSize.cs delete mode 100644 Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs delete mode 100644 Ryujinx.Graphics/Gal/ShaderDeclInfo.cs create mode 100644 Ryujinx.Graphics/Shader/CBufferDescriptor.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/CodeGenContext.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/Declarations.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/DefaultNames.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslGenerator.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslProgram.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGen.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstInfo.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstType.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs create mode 100644 Ryujinx.Graphics/Shader/CodeGen/Glsl/TypeConversion.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/BitfieldExtensions.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/Block.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/Condition.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/ConditionalOperation.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/Decoder.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/DecoderHelper.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/FPHalfSwizzle.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/FPType.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/FmulScale.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCode.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeAlu.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeFArith.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeHfma.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeImm.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeImmF.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeLop.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeRa.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeRc.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeRd.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeReg.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IOpCodeRegCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IntegerCondition.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IntegerHalfPart.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IntegerShift.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IntegerSize.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/IntegerType.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/LogicalOperation.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/MufuOperation.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCode.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeAlu.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeAluCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm2x10.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm32.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeAluReg.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeAluRegCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeAttribute.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeBranch.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeExit.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeFArith.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeFArithCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm32.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeFArithReg.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeFArithRegCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeFsetImm.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeHfma.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaImm2x10.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaImm32.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaReg.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaRegCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeIpa.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeLdc.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeLop.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeLopCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeLopImm.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeLopImm32.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeLopReg.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodePsetp.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeSet.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeSetCbuf.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeSetImm.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeSetReg.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeSsy.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeSync.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTable.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTexs.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTexture.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTextureScalar.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTld4.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTld4s.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/OpCodeTlds.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/Register.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/RegisterConsts.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/RegisterType.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/RoundingMode.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/TexelLoadScalarType.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/TextureDimensions.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/TextureGatherOffset.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/TextureLodMode.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/TextureProperty.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/TextureScalarType.cs create mode 100644 Ryujinx.Graphics/Shader/Decoders/XmadCMode.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitAlu.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitAluHelper.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitConversion.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitFArith.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitFlow.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitHelper.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitMemory.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitMove.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/InstEmitter.cs create mode 100644 Ryujinx.Graphics/Shader/Instructions/Lop3Expression.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/BasicBlock.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/INode.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/Instruction.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/IrConsts.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/Operand.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/OperandHelper.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/OperandType.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/Operation.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/PhiNode.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureFlags.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureOperation.cs create mode 100644 Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureType.cs create mode 100644 Ryujinx.Graphics/Shader/ShaderConfig.cs create mode 100644 Ryujinx.Graphics/Shader/ShaderHeader.cs create mode 100644 Ryujinx.Graphics/Shader/ShaderProgram.cs create mode 100644 Ryujinx.Graphics/Shader/ShaderProgramInfo.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstAssignment.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstBlock.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstBlockType.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstBlockVisitor.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstHelper.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstNode.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstOperand.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstOperation.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstOptimizer.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/AstTextureOperation.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/GotoElimination.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/GotoStatement.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/IAstNode.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/InstructionInfo.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/OperandInfo.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/PhiFunctions.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/StructuredProgram.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/StructuredProgramContext.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/StructuredProgramInfo.cs create mode 100644 Ryujinx.Graphics/Shader/StructuredIr/VariableType.cs create mode 100644 Ryujinx.Graphics/Shader/TextureDescriptor.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/AttributeConsts.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/ControlFlowGraph.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/Dominance.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/EmitterContext.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/EmitterContextInsts.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/Optimizations/BranchElimination.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/Optimizations/ConstantFolding.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/Optimizations/HalfConversion.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/Optimizations/Optimizer.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/Optimizations/Simplification.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/Ssa.cs create mode 100644 Ryujinx.Graphics/Shader/Translation/Translator.cs delete mode 100644 Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs diff --git a/Ryujinx.Graphics/Gal/IGalShader.cs b/Ryujinx.Graphics/Gal/IGalShader.cs index 99cd4d7624..6a9abe75bc 100644 --- a/Ryujinx.Graphics/Gal/IGalShader.cs +++ b/Ryujinx.Graphics/Gal/IGalShader.cs @@ -1,3 +1,4 @@ +using Ryujinx.Graphics.Shader; using System.Collections.Generic; namespace Ryujinx.Graphics.Gal @@ -8,8 +9,8 @@ namespace Ryujinx.Graphics.Gal void Create(IGalMemory memory, long vpAPos, long key, GalShaderType type); - IEnumerable GetConstBufferUsage(long key); - IEnumerable GetTextureUsage(long key); + IEnumerable GetConstBufferUsage(long key); + IEnumerable GetTextureUsage(long key); void Bind(long key); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs index 3c8ada3ea6..64768e285b 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs @@ -1,4 +1,5 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Shader; using System; using System.Collections.Generic; @@ -529,9 +530,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL { if (stage != null) { - foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage) + foreach (CBufferDescriptor desc in stage.ConstBufferUsage) { - long key = New.ConstBufferKeys[(int)stage.Type][declInfo.Cbuf]; + long key = New.ConstBufferKeys[(int)stage.Type][desc.Slot]; if (key != 0 && _buffer.TryGetUbo(key, out int uboHandle)) { diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs index 8faa90537e..8f4072c53e 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglShader.cs @@ -1,5 +1,6 @@ using OpenTK.Graphics.OpenGL; -using Ryujinx.Graphics.Gal.Shader; +using Ryujinx.Graphics.Shader; +using Ryujinx.Graphics.Shader.Translation; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -51,54 +52,54 @@ namespace Ryujinx.Graphics.Gal.OpenGL bool isDualVp, GalShaderType type) { - GlslProgram program; + ShaderConfig config = new ShaderConfig(type, OglLimit.MaxUboSize); - GlslDecompiler decompiler = new GlslDecompiler(OglLimit.MaxUboSize, OglExtension.NvidiaDriver); - - int shaderDumpIndex = ShaderDumper.DumpIndex; + ShaderProgram program; if (isDualVp) { ShaderDumper.Dump(memory, position, type, "a"); ShaderDumper.Dump(memory, positionB, type, "b"); - program = decompiler.Decompile(memory, position, positionB, type); + program = Translator.Translate(memory, (ulong)position, (ulong)positionB, config); } else { ShaderDumper.Dump(memory, position, type); - program = decompiler.Decompile(memory, position, type); + program = Translator.Translate(memory, (ulong)position, config); } string code = program.Code; if (ShaderDumper.IsDumpEnabled()) { + int shaderDumpIndex = ShaderDumper.DumpIndex; + code = "//Shader " + shaderDumpIndex + Environment.NewLine + code; } - return new OglShaderStage(type, code, program.Uniforms, program.Textures); + return new OglShaderStage(type, code, program.Info.CBuffers, program.Info.Textures); } - public IEnumerable GetConstBufferUsage(long key) + public IEnumerable GetConstBufferUsage(long key) { if (_stages.TryGetValue(key, out OglShaderStage stage)) { return stage.ConstBufferUsage; } - return Enumerable.Empty(); + return Enumerable.Empty(); } - public IEnumerable GetTextureUsage(long key) + public IEnumerable GetTextureUsage(long key) { if (_stages.TryGetValue(key, out OglShaderStage stage)) { return stage.TextureUsage; } - return Enumerable.Empty(); + return Enumerable.Empty(); } public unsafe void SetExtraData(float flipX, float flipY, int instance) @@ -130,16 +131,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL private void Bind(OglShaderStage stage) { - if (stage.Type == GalShaderType.Geometry) - { - //Enhanced layouts are required for Geometry shaders - //skip this stage if current driver has no ARB_enhanced_layouts - if (!OglExtension.EnhancedLayouts) - { - return; - } - } - switch (stage.Type) { case GalShaderType.Vertex: Current.Vertex = stage; break; @@ -221,7 +212,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL private void BindUniformBlocks(int programHandle) { - int extraBlockindex = GL.GetUniformBlockIndex(programHandle, GlslDecl.ExtraUniformBlockName); + int extraBlockindex = GL.GetUniformBlockIndex(programHandle, "Extra"); GL.UniformBlockBinding(programHandle, extraBlockindex, 0); @@ -231,14 +222,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL { if (stage != null) { - foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage) + foreach (CBufferDescriptor desc in stage.ConstBufferUsage) { - int blockIndex = GL.GetUniformBlockIndex(programHandle, declInfo.Name); + int blockIndex = GL.GetUniformBlockIndex(programHandle, desc.Name); if (blockIndex < 0) { - //It is expected that its found, if it's not then driver might be in a malfunction - throw new InvalidOperationException(); + //This may be fine, the compiler may optimize away unused uniform buffers, + //and in this case the above call would return -1 as the buffer has been + //optimized away. + continue; } GL.UniformBlockBinding(programHandle, blockIndex, freeBinding); @@ -263,9 +256,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL { if (stage != null) { - foreach (ShaderDeclInfo decl in stage.TextureUsage) + foreach (TextureDescriptor desc in stage.TextureUsage) { - int location = GL.GetUniformLocation(programHandle, decl.Name); + int location = GL.GetUniformLocation(programHandle, desc.Name); GL.Uniform1(location, index); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs b/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs index 9e68a8e6dc..86126bca4d 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs @@ -1,4 +1,5 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Graphics.Shader; using System; using System.Collections.Generic; @@ -23,14 +24,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL public string Code { get; private set; } - public IEnumerable ConstBufferUsage { get; private set; } - public IEnumerable TextureUsage { get; private set; } + public IEnumerable ConstBufferUsage { get; private set; } + public IEnumerable TextureUsage { get; private set; } public OglShaderStage( - GalShaderType type, - string code, - IEnumerable constBufferUsage, - IEnumerable textureUsage) + GalShaderType type, + string code, + IEnumerable constBufferUsage, + IEnumerable textureUsage) { Type = type; Code = code; diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs deleted file mode 100644 index 734267625c..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs +++ /dev/null @@ -1,420 +0,0 @@ -using Ryujinx.Graphics.Texture; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gal.Shader -{ - class GlslDecl - { - public const int LayerAttr = 0x064; - public const int PointSizeAttr = 0x06c; - public const int PointCoordAttrX = 0x2e0; - public const int PointCoordAttrY = 0x2e4; - public const int TessCoordAttrX = 0x2f0; - public const int TessCoordAttrY = 0x2f4; - public const int TessCoordAttrZ = 0x2f8; - public const int InstanceIdAttr = 0x2f8; - public const int VertexIdAttr = 0x2fc; - public const int FaceAttr = 0x3fc; - - public const int GlPositionVec4Index = 7; - - public const int PositionOutAttrLocation = 15; - - private const int AttrStartIndex = 8; - private const int TexStartIndex = 8; - - public const string PositionOutAttrName = "position"; - - private const string TextureName = "tex"; - private const string UniformName = "c"; - - private const string AttrName = "attr"; - private const string InAttrName = "in_" + AttrName; - private const string OutAttrName = "out_" + AttrName; - - private const string GprName = "gpr"; - private const string PredName = "pred"; - - public const string FragmentOutputName = "FragColor"; - - public const string ExtraUniformBlockName = "Extra"; - public const string FlipUniformName = "flip"; - public const string InstanceUniformName = "instance"; - - public const string BasicBlockName = "bb"; - public const string BasicBlockAName = BasicBlockName + "_a"; - public const string BasicBlockBName = BasicBlockName + "_b"; - - public const int SsyStackSize = 16; - public const string SsyStackName = "ssy_stack"; - public const string SsyCursorName = "ssy_cursor"; - - private string[] _stagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" }; - - private string _stagePrefix; - - private Dictionary m_CbTextures; - - private Dictionary m_Textures; - private Dictionary m_Uniforms; - - private Dictionary m_Attributes; - private Dictionary m_InAttributes; - private Dictionary m_OutAttributes; - - private Dictionary m_Gprs; - private Dictionary m_GprsHalf; - private Dictionary m_Preds; - - public IReadOnlyDictionary CbTextures => m_CbTextures; - - public IReadOnlyDictionary Textures => m_Textures; - public IReadOnlyDictionary Uniforms => m_Uniforms; - - public IReadOnlyDictionary Attributes => m_Attributes; - public IReadOnlyDictionary InAttributes => m_InAttributes; - public IReadOnlyDictionary OutAttributes => m_OutAttributes; - - public IReadOnlyDictionary Gprs => m_Gprs; - public IReadOnlyDictionary GprsHalf => m_GprsHalf; - public IReadOnlyDictionary Preds => m_Preds; - - public GalShaderType ShaderType { get; private set; } - - private GlslDecl(GalShaderType shaderType) - { - ShaderType = shaderType; - - m_CbTextures = new Dictionary(); - - m_Textures = new Dictionary(); - m_Uniforms = new Dictionary(); - - m_Attributes = new Dictionary(); - m_InAttributes = new Dictionary(); - m_OutAttributes = new Dictionary(); - - m_Gprs = new Dictionary(); - m_GprsHalf = new Dictionary(); - m_Preds = new Dictionary(); - } - - public GlslDecl(ShaderIrBlock[] blocks, GalShaderType shaderType, ShaderHeader header) : this(shaderType) - { - _stagePrefix = _stagePrefixes[(int)shaderType] + "_"; - - if (shaderType == GalShaderType.Fragment) - { - int index = 0; - - for (int attachment = 0; attachment < 8; attachment++) - { - for (int component = 0; component < 4; component++) - { - if (header.OmapTargets[attachment].ComponentEnabled(component)) - { - m_Gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index)); - - index++; - } - } - } - - if (header.OmapDepth) - { - index = header.DepthRegister; - - m_Gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index)); - } - } - - foreach (ShaderIrBlock block in blocks) - { - ShaderIrNode[] nodes = block.GetNodes(); - - foreach (ShaderIrNode node in nodes) - { - Traverse(nodes, null, node); - } - } - } - - public static GlslDecl Merge(GlslDecl vpA, GlslDecl vpB) - { - GlslDecl combined = new GlslDecl(GalShaderType.Vertex); - - Merge(combined.m_Textures, vpA.m_Textures, vpB.m_Textures); - Merge(combined.m_Uniforms, vpA.m_Uniforms, vpB.m_Uniforms); - - Merge(combined.m_Attributes, vpA.m_Attributes, vpB.m_Attributes); - Merge(combined.m_OutAttributes, vpA.m_OutAttributes, vpB.m_OutAttributes); - - Merge(combined.m_Gprs, vpA.m_Gprs, vpB.m_Gprs); - Merge(combined.m_GprsHalf, vpA.m_GprsHalf, vpB.m_GprsHalf); - Merge(combined.m_Preds, vpA.m_Preds, vpB.m_Preds); - - //Merge input attributes. - foreach (KeyValuePair kv in vpA.m_InAttributes) - { - combined.m_InAttributes.TryAdd(kv.Key, kv.Value); - } - - foreach (KeyValuePair kv in vpB.m_InAttributes) - { - //If Vertex Program A already writes to this attribute, - //then we don't need to add it as an input attribute since - //Vertex Program A will already have written to it anyway, - //and there's no guarantee that there is an input attribute - //for this slot. - if (!vpA.m_OutAttributes.ContainsKey(kv.Key)) - { - combined.m_InAttributes.TryAdd(kv.Key, kv.Value); - } - } - - return combined; - } - - public static string GetGprName(int index) - { - return GprName + index; - } - - private static void Merge( - Dictionary c, - Dictionary a, - Dictionary b) - { - foreach (KeyValuePair kv in a) - { - c.TryAdd(kv.Key, kv.Value); - } - - foreach (KeyValuePair kv in b) - { - c.TryAdd(kv.Key, kv.Value); - } - } - - private void Traverse(ShaderIrNode[] nodes, ShaderIrNode parent, ShaderIrNode node) - { - switch (node) - { - case ShaderIrAsg asg: - { - Traverse(nodes, asg, asg.Dst); - Traverse(nodes, asg, asg.Src); - - break; - } - - case ShaderIrCond cond: - { - Traverse(nodes, cond, cond.Pred); - Traverse(nodes, cond, cond.Child); - - break; - } - - case ShaderIrOp op: - { - Traverse(nodes, op, op.OperandA); - Traverse(nodes, op, op.OperandB); - Traverse(nodes, op, op.OperandC); - - if (op.Inst == ShaderIrInst.Texq || - op.Inst == ShaderIrInst.Texs || - op.Inst == ShaderIrInst.Tld4 || - op.Inst == ShaderIrInst.Txlf) - { - int handle = ((ShaderIrOperImm)op.OperandC).Value; - - int index = handle - TexStartIndex; - - string name = _stagePrefix + TextureName + index; - - GalTextureTarget textureTarget; - - TextureInstructionSuffix textureInstructionSuffix; - - // TODO: Non 2D texture type for TEXQ? - if (op.Inst == ShaderIrInst.Texq) - { - textureTarget = GalTextureTarget.TwoD; - textureInstructionSuffix = TextureInstructionSuffix.None; - } - else - { - ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData); - - textureTarget = meta.TextureTarget; - textureInstructionSuffix = meta.TextureInstructionSuffix; - } - - m_Textures.TryAdd(handle, new ShaderDeclInfo(name, handle, false, 0, 1, textureTarget, textureInstructionSuffix)); - } - else if (op.Inst == ShaderIrInst.Texb) - { - ShaderIrNode handleSrc = null; - - int index = Array.IndexOf(nodes, parent) - 1; - - for (; index >= 0; index--) - { - ShaderIrNode curr = nodes[index]; - - if (curr is ShaderIrAsg asg && asg.Dst is ShaderIrOperGpr gpr) - { - if (gpr.Index == ((ShaderIrOperGpr)op.OperandC).Index) - { - handleSrc = asg.Src; - - break; - } - } - } - - if (handleSrc != null && handleSrc is ShaderIrOperCbuf cbuf) - { - ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData); - string name = _stagePrefix + TextureName + "_cb" + cbuf.Index + "_" + cbuf.Pos; - - m_CbTextures.Add(op, new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index, 1, meta.TextureTarget, meta.TextureInstructionSuffix)); - } - else - { - throw new NotImplementedException("Shader TEX.B instruction is not fully supported!"); - } - } - break; - } - - case ShaderIrOperCbuf cbuf: - { - if (!m_Uniforms.ContainsKey(cbuf.Index)) - { - string name = _stagePrefix + UniformName + cbuf.Index; - - ShaderDeclInfo declInfo = new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index); - - m_Uniforms.Add(cbuf.Index, declInfo); - } - break; - } - - case ShaderIrOperAbuf abuf: - { - //This is a built-in variable. - if (abuf.Offs == LayerAttr || - abuf.Offs == PointSizeAttr || - abuf.Offs == PointCoordAttrX || - abuf.Offs == PointCoordAttrY || - abuf.Offs == VertexIdAttr || - abuf.Offs == InstanceIdAttr || - abuf.Offs == FaceAttr) - { - break; - } - - int index = abuf.Offs >> 4; - int elem = (abuf.Offs >> 2) & 3; - - int glslIndex = index - AttrStartIndex; - - if (glslIndex < 0) - { - return; - } - - ShaderDeclInfo declInfo; - - if (parent is ShaderIrAsg asg && asg.Dst == node) - { - if (!m_OutAttributes.TryGetValue(index, out declInfo)) - { - declInfo = new ShaderDeclInfo(OutAttrName + glslIndex, glslIndex); - - m_OutAttributes.Add(index, declInfo); - } - } - else - { - if (!m_InAttributes.TryGetValue(index, out declInfo)) - { - declInfo = new ShaderDeclInfo(InAttrName + glslIndex, glslIndex); - - m_InAttributes.Add(index, declInfo); - } - } - - declInfo.Enlarge(elem + 1); - - if (!m_Attributes.ContainsKey(index)) - { - declInfo = new ShaderDeclInfo(AttrName + glslIndex, glslIndex, false, 0, 4); - - m_Attributes.Add(index, declInfo); - } - - Traverse(nodes, abuf, abuf.Vertex); - - break; - } - - case ShaderIrOperGpr gpr: - { - if (!gpr.IsConst) - { - string name = GetGprName(gpr.Index); - - if (gpr.RegisterSize == ShaderRegisterSize.Single) - { - m_Gprs.TryAdd(gpr.Index, new ShaderDeclInfo(name, gpr.Index)); - } - else if (gpr.RegisterSize == ShaderRegisterSize.Half) - { - name += "_h" + gpr.HalfPart; - - m_GprsHalf.TryAdd((gpr.Index << 1) | gpr.HalfPart, new ShaderDeclInfo(name, gpr.Index)); - } - else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */ - { - throw new NotImplementedException("Double types are not supported."); - } - } - break; - } - - case ShaderIrOperPred pred: - { - if (!pred.IsConst && !HasName(m_Preds, pred.Index)) - { - string name = PredName + pred.Index; - - m_Preds.TryAdd(pred.Index, new ShaderDeclInfo(name, pred.Index)); - } - break; - } - } - } - - private bool HasName(Dictionary decls, int index) - { - //This is used to check if the dictionary already contains - //a entry for a vector at a given index position. - //Used to enable turning gprs into vectors. - int vecIndex = index & ~3; - - if (decls.TryGetValue(vecIndex, out ShaderDeclInfo declInfo)) - { - if (declInfo.Size > 1 && index < vecIndex + declInfo.Size) - { - return true; - } - } - - return decls.ContainsKey(index); - } - } -} diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs deleted file mode 100644 index 228a901851..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ /dev/null @@ -1,1679 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using Ryujinx.Graphics.Texture; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; - -namespace Ryujinx.Graphics.Gal.Shader -{ - public class GlslDecompiler - { - private delegate string GetInstExpr(ShaderIrOp op); - - private Dictionary _instsExpr; - - private enum OperType - { - Bool, - F32, - I32 - } - - private const string IdentationStr = " "; - - private const int MaxVertexInput = 3; - - private GlslDecl _decl; - - private ShaderHeader _header, _headerB; - - private ShaderIrBlock[] _blocks, _blocksB; - - private StringBuilder _sb; - - public int MaxUboSize { get; } - - private bool _isNvidiaDriver; - - public GlslDecompiler(int maxUboSize, bool isNvidiaDriver) - { - _instsExpr = new Dictionary() - { - { ShaderIrInst.Abs, GetAbsExpr }, - { ShaderIrInst.Add, GetAddExpr }, - { ShaderIrInst.And, GetAndExpr }, - { ShaderIrInst.Asr, GetAsrExpr }, - { ShaderIrInst.Band, GetBandExpr }, - { ShaderIrInst.Bnot, GetBnotExpr }, - { ShaderIrInst.Bor, GetBorExpr }, - { ShaderIrInst.Bxor, GetBxorExpr }, - { ShaderIrInst.Ceil, GetCeilExpr }, - { ShaderIrInst.Ceq, GetCeqExpr }, - { ShaderIrInst.Cge, GetCgeExpr }, - { ShaderIrInst.Cgt, GetCgtExpr }, - { ShaderIrInst.Clamps, GetClampsExpr }, - { ShaderIrInst.Clampu, GetClampuExpr }, - { ShaderIrInst.Cle, GetCleExpr }, - { ShaderIrInst.Clt, GetCltExpr }, - { ShaderIrInst.Cne, GetCneExpr }, - { ShaderIrInst.Cut, GetCutExpr }, - { ShaderIrInst.Exit, GetExitExpr }, - { ShaderIrInst.Fabs, GetAbsExpr }, - { ShaderIrInst.Fadd, GetAddExpr }, - { ShaderIrInst.Fceq, GetCeqExpr }, - { ShaderIrInst.Fcequ, GetCequExpr }, - { ShaderIrInst.Fcge, GetCgeExpr }, - { ShaderIrInst.Fcgeu, GetCgeuExpr }, - { ShaderIrInst.Fcgt, GetCgtExpr }, - { ShaderIrInst.Fcgtu, GetCgtuExpr }, - { ShaderIrInst.Fclamp, GetFclampExpr }, - { ShaderIrInst.Fcle, GetCleExpr }, - { ShaderIrInst.Fcleu, GetCleuExpr }, - { ShaderIrInst.Fclt, GetCltExpr }, - { ShaderIrInst.Fcltu, GetCltuExpr }, - { ShaderIrInst.Fcnan, GetCnanExpr }, - { ShaderIrInst.Fcne, GetCneExpr }, - { ShaderIrInst.Fcneu, GetCneuExpr }, - { ShaderIrInst.Fcnum, GetCnumExpr }, - { ShaderIrInst.Fcos, GetFcosExpr }, - { ShaderIrInst.Fex2, GetFex2Expr }, - { ShaderIrInst.Ffma, GetFfmaExpr }, - { ShaderIrInst.Flg2, GetFlg2Expr }, - { ShaderIrInst.Floor, GetFloorExpr }, - { ShaderIrInst.Fmax, GetMaxExpr }, - { ShaderIrInst.Fmin, GetMinExpr }, - { ShaderIrInst.Fmul, GetMulExpr }, - { ShaderIrInst.Fneg, GetNegExpr }, - { ShaderIrInst.Frcp, GetFrcpExpr }, - { ShaderIrInst.Frsq, GetFrsqExpr }, - { ShaderIrInst.Fsin, GetFsinExpr }, - { ShaderIrInst.Fsqrt, GetFsqrtExpr }, - { ShaderIrInst.Ftos, GetFtosExpr }, - { ShaderIrInst.Ftou, GetFtouExpr }, - { ShaderIrInst.Ipa, GetIpaExpr }, - { ShaderIrInst.Kil, GetKilExpr }, - { ShaderIrInst.Lsl, GetLslExpr }, - { ShaderIrInst.Lsr, GetLsrExpr }, - { ShaderIrInst.Max, GetMaxExpr }, - { ShaderIrInst.Min, GetMinExpr }, - { ShaderIrInst.Mul, GetMulExpr }, - { ShaderIrInst.Neg, GetNegExpr }, - { ShaderIrInst.Not, GetNotExpr }, - { ShaderIrInst.Or, GetOrExpr }, - { ShaderIrInst.Stof, GetStofExpr }, - { ShaderIrInst.Sub, GetSubExpr }, - { ShaderIrInst.Texb, GetTexbExpr }, - { ShaderIrInst.Texq, GetTexqExpr }, - { ShaderIrInst.Texs, GetTexsExpr }, - { ShaderIrInst.Tld4, GetTld4Expr }, - { ShaderIrInst.Trunc, GetTruncExpr }, - { ShaderIrInst.Txlf, GetTxlfExpr }, - { ShaderIrInst.Utof, GetUtofExpr }, - { ShaderIrInst.Xor, GetXorExpr } - }; - - MaxUboSize = maxUboSize / 16; - _isNvidiaDriver = isNvidiaDriver; - } - - public GlslProgram Decompile( - IGalMemory memory, - long vpAPosition, - long vpBPosition, - GalShaderType shaderType) - { - _header = new ShaderHeader(memory, vpAPosition); - _headerB = new ShaderHeader(memory, vpBPosition); - - _blocks = ShaderDecoder.Decode(memory, vpAPosition); - _blocksB = ShaderDecoder.Decode(memory, vpBPosition); - - GlslDecl declVpA = new GlslDecl(_blocks, shaderType, _header); - GlslDecl declVpB = new GlslDecl(_blocksB, shaderType, _headerB); - - _decl = GlslDecl.Merge(declVpA, declVpB); - - return Decompile(); - } - - public GlslProgram Decompile(IGalMemory memory, long position, GalShaderType shaderType) - { - _header = new ShaderHeader(memory, position); - _headerB = null; - - _blocks = ShaderDecoder.Decode(memory, position); - _blocksB = null; - - _decl = new GlslDecl(_blocks, shaderType, _header); - - return Decompile(); - } - - private GlslProgram Decompile() - { - _sb = new StringBuilder(); - - _sb.AppendLine("#version 410 core"); - - PrintDeclHeader(); - PrintDeclTextures(); - PrintDeclUniforms(); - PrintDeclAttributes(); - PrintDeclInAttributes(); - PrintDeclOutAttributes(); - PrintDeclGprs(); - PrintDeclPreds(); - PrintDeclSsy(); - - if (_blocksB != null) - { - PrintBlockScope(_blocks, GlslDecl.BasicBlockAName); - - _sb.AppendLine(); - - PrintBlockScope(_blocksB, GlslDecl.BasicBlockBName); - } - else - { - PrintBlockScope(_blocks, GlslDecl.BasicBlockName); - } - - _sb.AppendLine(); - - PrintMain(); - - string glslCode = _sb.ToString(); - - List textureInfo = new List(); - - textureInfo.AddRange(_decl.Textures.Values); - textureInfo.AddRange(IterateCbTextures()); - - return new GlslProgram(glslCode, textureInfo, _decl.Uniforms.Values); - } - - private void PrintDeclHeader() - { - if (_decl.ShaderType == GalShaderType.Geometry) - { - int maxVertices = _header.MaxOutputVertexCount; - - string outputTopology; - - switch (_header.OutputTopology) - { - case ShaderHeader.PointList: outputTopology = "points"; break; - case ShaderHeader.LineStrip: outputTopology = "line_strip"; break; - case ShaderHeader.TriangleStrip: outputTopology = "triangle_strip"; break; - - default: throw new InvalidOperationException(); - } - - _sb.AppendLine("#extension GL_ARB_enhanced_layouts : require"); - - _sb.AppendLine(); - - _sb.AppendLine("// Stubbed. Maxwell geometry shaders don't inform input geometry type"); - - _sb.AppendLine("layout(triangles) in;" + Environment.NewLine); - - _sb.AppendLine($"layout({outputTopology}, max_vertices = {maxVertices}) out;"); - - _sb.AppendLine(); - } - } - - private string GetSamplerType(TextureTarget textureTarget, bool hasShadow) - { - string result; - - switch (textureTarget) - { - case TextureTarget.Texture1D: - result = "sampler1D"; - break; - case TextureTarget.Texture2D: - result = "sampler2D"; - break; - case TextureTarget.Texture3D: - result = "sampler3D"; - break; - case TextureTarget.TextureCubeMap: - result = "samplerCube"; - break; - case TextureTarget.TextureRectangle: - result = "sampler2DRect"; - break; - case TextureTarget.Texture1DArray: - result = "sampler1DArray"; - break; - case TextureTarget.Texture2DArray: - result = "sampler2DArray"; - break; - case TextureTarget.TextureCubeMapArray: - result = "samplerCubeArray"; - break; - case TextureTarget.TextureBuffer: - result = "samplerBuffer"; - break; - case TextureTarget.Texture2DMultisample: - result = "sampler2DMS"; - break; - case TextureTarget.Texture2DMultisampleArray: - result = "sampler2DMSArray"; - break; - default: - throw new NotSupportedException(); - } - - if (hasShadow) - result += "Shadow"; - - return result; - } - - private void PrintDeclTextures() - { - foreach (ShaderDeclInfo declInfo in IterateCbTextures()) - { - TextureTarget target = ImageUtils.GetTextureTarget(declInfo.TextureTarget); - _sb.AppendLine($"// {declInfo.TextureSuffix}"); - _sb.AppendLine("uniform " + GetSamplerType(target, (declInfo.TextureSuffix & TextureInstructionSuffix.Dc) != 0) + " " + declInfo.Name + ";"); - } - - foreach (ShaderDeclInfo declInfo in _decl.Textures.Values.OrderBy(DeclKeySelector)) - { - TextureTarget target = ImageUtils.GetTextureTarget(declInfo.TextureTarget); - _sb.AppendLine($"// {declInfo.TextureSuffix}"); - _sb.AppendLine("uniform " + GetSamplerType(target, (declInfo.TextureSuffix & TextureInstructionSuffix.Dc) != 0) + " " + declInfo.Name + ";"); - } - } - - private IEnumerable IterateCbTextures() - { - HashSet names = new HashSet(); - - foreach (ShaderDeclInfo declInfo in _decl.CbTextures.Values.OrderBy(DeclKeySelector)) - { - if (names.Add(declInfo.Name)) - { - yield return declInfo; - } - } - } - - private void PrintDeclUniforms() - { - if (_decl.ShaderType == GalShaderType.Vertex) - { - //Memory layout here is [flip_x, flip_y, instance, unused] - //It's using 4 bytes, not 8 - - _sb.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + " {"); - - _sb.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";"); - - _sb.AppendLine(IdentationStr + "int " + GlslDecl.InstanceUniformName + ";"); - - _sb.AppendLine("};"); - _sb.AppendLine(); - } - - foreach (ShaderDeclInfo declInfo in _decl.Uniforms.Values.OrderBy(DeclKeySelector)) - { - _sb.AppendLine($"layout (std140) uniform {declInfo.Name} {{"); - - _sb.AppendLine($"{IdentationStr}vec4 {declInfo.Name}_data[{MaxUboSize}];"); - - _sb.AppendLine("};"); - } - - if (_decl.Uniforms.Count > 0) - { - _sb.AppendLine(); - } - } - - private void PrintDeclAttributes() - { - string geometryArray = (_decl.ShaderType == GalShaderType.Geometry) ? "[" + MaxVertexInput + "]" : ""; - - PrintDecls(_decl.Attributes, suffix: geometryArray); - } - - private void PrintDeclInAttributes() - { - if (_decl.ShaderType == GalShaderType.Fragment) - { - _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") in vec4 " + GlslDecl.PositionOutAttrName + ";"); - } - - if (_decl.ShaderType == GalShaderType.Geometry) - { - if (_decl.InAttributes.Count > 0) - { - _sb.AppendLine("in Vertex {"); - - foreach (ShaderDeclInfo declInfo in _decl.InAttributes.Values.OrderBy(DeclKeySelector)) - { - if (declInfo.Index >= 0) - { - _sb.AppendLine(IdentationStr + "layout (location = " + declInfo.Index + ") vec4 " + declInfo.Name + "; "); - } - } - - _sb.AppendLine("} block_in[];" + Environment.NewLine); - } - } - else - { - PrintDeclAttributes(_decl.InAttributes.Values, "in"); - } - } - - private void PrintDeclOutAttributes() - { - if (_decl.ShaderType == GalShaderType.Fragment) - { - int count = 0; - - for (int attachment = 0; attachment < 8; attachment++) - { - if (_header.OmapTargets[attachment].Enabled) - { - _sb.AppendLine("layout (location = " + attachment + ") out vec4 " + GlslDecl.FragmentOutputName + attachment + ";"); - - count++; - } - } - - if (count > 0) - { - _sb.AppendLine(); - } - } - else - { - _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";"); - _sb.AppendLine(); - } - - PrintDeclAttributes(_decl.OutAttributes.Values, "out"); - } - - private void PrintDeclAttributes(IEnumerable decls, string inOut) - { - int count = 0; - - foreach (ShaderDeclInfo declInfo in decls.OrderBy(DeclKeySelector)) - { - if (declInfo.Index >= 0) - { - _sb.AppendLine("layout (location = " + declInfo.Index + ") " + inOut + " vec4 " + declInfo.Name + ";"); - - count++; - } - } - - if (count > 0) - { - _sb.AppendLine(); - } - } - - private void PrintDeclGprs() - { - PrintDecls(_decl.Gprs); - PrintDecls(_decl.GprsHalf); - } - - private void PrintDeclPreds() - { - PrintDecls(_decl.Preds, "bool"); - } - - private void PrintDeclSsy() - { - _sb.AppendLine("uint " + GlslDecl.SsyCursorName + " = 0;"); - - _sb.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine); - } - - private void PrintDecls(IReadOnlyDictionary dict, string customType = null, string suffix = "") - { - foreach (ShaderDeclInfo declInfo in dict.Values.OrderBy(DeclKeySelector)) - { - string name; - - if (customType != null) - { - name = customType + " " + declInfo.Name + suffix + ";"; - } - else if (declInfo.Name.Contains(GlslDecl.FragmentOutputName)) - { - name = "layout (location = " + declInfo.Index / 4 + ") out vec4 " + declInfo.Name + suffix + ";"; - } - else - { - name = GetDecl(declInfo) + suffix + ";"; - } - - _sb.AppendLine(name); - } - - if (dict.Count > 0) - { - _sb.AppendLine(); - } - } - - private int DeclKeySelector(ShaderDeclInfo declInfo) - { - return declInfo.Cbuf << 24 | declInfo.Index; - } - - private string GetDecl(ShaderDeclInfo declInfo) - { - if (declInfo.Size == 4) - { - return "vec4 " + declInfo.Name; - } - else - { - return "float " + declInfo.Name; - } - } - - private void PrintMain() - { - _sb.AppendLine("void main() {"); - - foreach (KeyValuePair kv in _decl.InAttributes) - { - if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr)) - { - continue; - } - - ShaderDeclInfo declInfo = kv.Value; - - if (_decl.ShaderType == GalShaderType.Geometry) - { - for (int vertex = 0; vertex < MaxVertexInput; vertex++) - { - string dst = attr.Name + "[" + vertex + "]"; - - string src = "block_in[" + vertex + "]." + declInfo.Name; - - _sb.AppendLine(IdentationStr + dst + " = " + src + ";"); - } - } - else - { - _sb.AppendLine(IdentationStr + attr.Name + " = " + declInfo.Name + ";"); - } - } - - _sb.AppendLine(IdentationStr + "uint pc;"); - - if (_blocksB != null) - { - PrintProgram(_blocks, GlslDecl.BasicBlockAName); - PrintProgram(_blocksB, GlslDecl.BasicBlockBName); - } - else - { - PrintProgram(_blocks, GlslDecl.BasicBlockName); - } - - if (_decl.ShaderType != GalShaderType.Geometry) - { - PrintAttrToOutput(); - } - - if (_decl.ShaderType == GalShaderType.Fragment) - { - if (_header.OmapDepth) - { - _sb.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(_header.DepthRegister) + ";"); - } - - int gprIndex = 0; - - for (int attachment = 0; attachment < 8; attachment++) - { - string output = GlslDecl.FragmentOutputName + attachment; - - OmapTarget target = _header.OmapTargets[attachment]; - - for (int component = 0; component < 4; component++) - { - if (target.ComponentEnabled(component)) - { - _sb.AppendLine(IdentationStr + output + "[" + component + "] = " + GlslDecl.GetGprName(gprIndex) + ";"); - - gprIndex++; - } - } - } - } - - _sb.AppendLine("}"); - } - - private void PrintProgram(ShaderIrBlock[] blocks, string name) - { - const string ident1 = IdentationStr; - const string ident2 = ident1 + IdentationStr; - const string ident3 = ident2 + IdentationStr; - const string ident4 = ident3 + IdentationStr; - - _sb.AppendLine(ident1 + "pc = " + GetBlockPosition(blocks[0]) + ";"); - _sb.AppendLine(ident1 + "do {"); - _sb.AppendLine(ident2 + "switch (pc) {"); - - foreach (ShaderIrBlock block in blocks) - { - string functionName = block.Position.ToString("x8"); - - _sb.AppendLine(ident3 + "case 0x" + functionName + ": pc = " + name + "_" + functionName + "(); break;"); - } - - _sb.AppendLine(ident3 + "default:"); - _sb.AppendLine(ident4 + "pc = 0;"); - _sb.AppendLine(ident4 + "break;"); - - _sb.AppendLine(ident2 + "}"); - _sb.AppendLine(ident1 + "} while (pc != 0);"); - } - - private void PrintAttrToOutput(string identation = IdentationStr) - { - foreach (KeyValuePair kv in _decl.OutAttributes) - { - if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr)) - { - continue; - } - - ShaderDeclInfo declInfo = kv.Value; - - string name = attr.Name; - - if (_decl.ShaderType == GalShaderType.Geometry) - { - name += "[0]"; - } - - _sb.AppendLine(identation + declInfo.Name + " = " + name + ";"); - } - - if (_decl.ShaderType == GalShaderType.Vertex) - { - _sb.AppendLine(identation + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";"); - } - - if (_decl.ShaderType != GalShaderType.Fragment) - { - _sb.AppendLine(identation + GlslDecl.PositionOutAttrName + " = gl_Position;"); - _sb.AppendLine(identation + GlslDecl.PositionOutAttrName + ".w = 1;"); - } - } - - private void PrintBlockScope(ShaderIrBlock[] blocks, string name) - { - foreach (ShaderIrBlock block in blocks) - { - _sb.AppendLine("uint " + name + "_" + block.Position.ToString("x8") + "() {"); - - PrintNodes(block, block.GetNodes()); - - _sb.AppendLine("}" + Environment.NewLine); - } - } - - private void PrintNodes(ShaderIrBlock block, ShaderIrNode[] nodes) - { - foreach (ShaderIrNode node in nodes) - { - PrintNode(block, node, IdentationStr); - } - - if (nodes.Length == 0) - { - _sb.AppendLine(IdentationStr + "return 0u;"); - - return; - } - - ShaderIrNode last = nodes[nodes.Length - 1]; - - bool unconditionalFlowChange = false; - - if (last is ShaderIrOp op) - { - switch (op.Inst) - { - case ShaderIrInst.Bra: - case ShaderIrInst.Exit: - case ShaderIrInst.Sync: - unconditionalFlowChange = true; - break; - } - } - - if (!unconditionalFlowChange) - { - if (block.Next != null) - { - _sb.AppendLine(IdentationStr + "return " + GetBlockPosition(block.Next) + ";"); - } - else - { - _sb.AppendLine(IdentationStr + "return 0u;"); - } - } - } - - private void PrintNode(ShaderIrBlock block, ShaderIrNode node, string identation) - { - if (node is ShaderIrCond cond) - { - string ifExpr = GetSrcExpr(cond.Pred, true); - - if (cond.Not) - { - ifExpr = "!(" + ifExpr + ")"; - } - - _sb.AppendLine(identation + "if (" + ifExpr + ") {"); - - PrintNode(block, cond.Child, identation + IdentationStr); - - _sb.AppendLine(identation + "}"); - } - else if (node is ShaderIrAsg asg) - { - if (IsValidOutOper(asg.Dst)) - { - string expr = GetSrcExpr(asg.Src, true); - - expr = GetExprWithCast(asg.Dst, asg.Src, expr); - - _sb.AppendLine(identation + GetDstOperName(asg.Dst) + " = " + expr + ";"); - } - } - else if (node is ShaderIrOp op) - { - switch (op.Inst) - { - case ShaderIrInst.Bra: - { - _sb.AppendLine(identation + "return " + GetBlockPosition(block.Branch) + ";"); - - break; - } - - case ShaderIrInst.Emit: - { - PrintAttrToOutput(identation); - - _sb.AppendLine(identation + "EmitVertex();"); - - break; - } - - case ShaderIrInst.Ssy: - { - string stackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; - - int targetPosition = (op.OperandA as ShaderIrOperImm).Value; - - string target = "0x" + targetPosition.ToString("x8") + "u"; - - _sb.AppendLine(identation + stackIndex + " = " + target + ";"); - - _sb.AppendLine(identation + GlslDecl.SsyCursorName + "++;"); - - break; - } - - case ShaderIrInst.Sync: - { - _sb.AppendLine(identation + GlslDecl.SsyCursorName + "--;"); - - string target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]"; - - _sb.AppendLine(identation + "return " + target + ";"); - - break; - } - - default: - _sb.AppendLine(identation + GetSrcExpr(op, true) + ";"); - - break; - } - } - else if (node is ShaderIrCmnt cmnt) - { - _sb.AppendLine(identation + "// " + cmnt.Comment); - } - else - { - throw new InvalidOperationException(); - } - } - - private bool IsValidOutOper(ShaderIrNode node) - { - if (node is ShaderIrOperGpr gpr && gpr.IsConst) - { - return false; - } - else if (node is ShaderIrOperPred pred && pred.IsConst) - { - return false; - } - - return true; - } - - private string GetDstOperName(ShaderIrNode node) - { - if (node is ShaderIrOperAbuf abuf) - { - return GetOutAbufName(abuf); - } - else if (node is ShaderIrOperGpr gpr) - { - return GetName(gpr); - } - else if (node is ShaderIrOperPred pred) - { - return GetName(pred); - } - - throw new ArgumentException(nameof(node)); - } - - private string GetSrcExpr(ShaderIrNode node, bool entry = false) - { - switch (node) - { - case ShaderIrOperAbuf abuf: return GetName (abuf); - case ShaderIrOperCbuf cbuf: return GetName (cbuf); - case ShaderIrOperGpr gpr: return GetName (gpr); - case ShaderIrOperImm imm: return GetValue(imm); - case ShaderIrOperImmf immf: return GetValue(immf); - case ShaderIrOperPred pred: return GetName (pred); - - case ShaderIrOp op: - string expr; - - if (_instsExpr.TryGetValue(op.Inst, out GetInstExpr getExpr)) - { - expr = getExpr(op); - } - else - { - throw new NotImplementedException(op.Inst.ToString()); - } - - if (!entry && NeedsParentheses(op)) - { - expr = "(" + expr + ")"; - } - - return expr; - - default: throw new ArgumentException(nameof(node)); - } - } - - private static bool NeedsParentheses(ShaderIrOp op) - { - switch (op.Inst) - { - case ShaderIrInst.Ipa: - case ShaderIrInst.Texq: - case ShaderIrInst.Texs: - case ShaderIrInst.Tld4: - case ShaderIrInst.Txlf: - return false; - } - - return true; - } - - private string GetName(ShaderIrOperCbuf cbuf) - { - if (!_decl.Uniforms.TryGetValue(cbuf.Index, out ShaderDeclInfo declInfo)) - { - throw new InvalidOperationException(); - } - - if (cbuf.Offs != null) - { - string offset = "floatBitsToInt(" + GetSrcExpr(cbuf.Offs) + ")"; - - string index = "(" + cbuf.Pos * 4 + " + " + offset + ")"; - - return $"{declInfo.Name}_data[{index} / 16][({index} / 4) % 4]"; - } - else - { - return $"{declInfo.Name}_data[{cbuf.Pos / 4}][{cbuf.Pos % 4}]"; - } - } - - private string GetOutAbufName(ShaderIrOperAbuf abuf) - { - if (_decl.ShaderType == GalShaderType.Geometry) - { - switch (abuf.Offs) - { - case GlslDecl.LayerAttr: return "gl_Layer"; - } - } - - return GetAttrTempName(abuf); - } - - private string GetName(ShaderIrOperAbuf abuf) - { - //Handle special scalar read-only attributes here. - if (_decl.ShaderType == GalShaderType.Vertex) - { - switch (abuf.Offs) - { - case GlslDecl.VertexIdAttr: return "gl_VertexID"; - case GlslDecl.InstanceIdAttr: return GlslDecl.InstanceUniformName; - } - } - else if (_decl.ShaderType == GalShaderType.TessEvaluation) - { - switch (abuf.Offs) - { - case GlslDecl.TessCoordAttrX: return "gl_TessCoord.x"; - case GlslDecl.TessCoordAttrY: return "gl_TessCoord.y"; - case GlslDecl.TessCoordAttrZ: return "gl_TessCoord.z"; - } - } - else if (_decl.ShaderType == GalShaderType.Fragment) - { - switch (abuf.Offs) - { - case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x"; - case GlslDecl.PointCoordAttrY: return "gl_PointCoord.y"; - case GlslDecl.FaceAttr: return "(gl_FrontFacing ? -1 : 0)"; - } - } - - return GetAttrTempName(abuf); - } - - private string GetAttrTempName(ShaderIrOperAbuf abuf) - { - int index = abuf.Offs >> 4; - int elem = (abuf.Offs >> 2) & 3; - - string swizzle = "." + GetAttrSwizzle(elem); - - if (!_decl.Attributes.TryGetValue(index, out ShaderDeclInfo declInfo)) - { - //Handle special vec4 attributes here - //(for example, index 7 is always gl_Position). - if (index == GlslDecl.GlPositionVec4Index) - { - string name = - _decl.ShaderType != GalShaderType.Vertex && - _decl.ShaderType != GalShaderType.Geometry ? GlslDecl.PositionOutAttrName : "gl_Position"; - - return name + swizzle; - } - else if (abuf.Offs == GlslDecl.PointSizeAttr) - { - return "gl_PointSize"; - } - } - - if (declInfo.Index >= 32) - { - throw new InvalidOperationException($"Shader attribute offset {abuf.Offs} is invalid."); - } - - if (_decl.ShaderType == GalShaderType.Geometry) - { - string vertex = "floatBitsToInt(" + GetSrcExpr(abuf.Vertex) + ")"; - - return declInfo.Name + "[" + vertex + "]" + swizzle; - } - else - { - return declInfo.Name + swizzle; - } - } - - private string GetName(ShaderIrOperGpr gpr) - { - if (gpr.IsConst) - { - return "0"; - } - - if (gpr.RegisterSize == ShaderRegisterSize.Single) - { - return GetNameWithSwizzle(_decl.Gprs, gpr.Index); - } - else if (gpr.RegisterSize == ShaderRegisterSize.Half) - { - return GetNameWithSwizzle(_decl.GprsHalf, (gpr.Index << 1) | gpr.HalfPart); - } - else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */ - { - throw new NotImplementedException("Double types are not supported."); - } - } - - private string GetValue(ShaderIrOperImm imm) - { - //Only use hex is the value is too big and would likely be hard to read as int. - if (imm.Value > 0xfff || - imm.Value < -0xfff) - { - return "0x" + imm.Value.ToString("x8", CultureInfo.InvariantCulture); - } - else - { - return GetIntConst(imm.Value); - } - } - - private string GetValue(ShaderIrOperImmf immf) - { - return GetFloatConst(immf.Value); - } - - private string GetName(ShaderIrOperPred pred) - { - return pred.IsConst ? "true" : GetNameWithSwizzle(_decl.Preds, pred.Index); - } - - private string GetNameWithSwizzle(IReadOnlyDictionary dict, int index) - { - int vecIndex = index & ~3; - - if (dict.TryGetValue(vecIndex, out ShaderDeclInfo declInfo)) - { - if (declInfo.Size > 1 && index < vecIndex + declInfo.Size) - { - return declInfo.Name + "." + GetAttrSwizzle(index & 3); - } - } - - if (!dict.TryGetValue(index, out declInfo)) - { - throw new InvalidOperationException(); - } - - return declInfo.Name; - } - - private string GetAttrSwizzle(int elem) - { - return "xyzw".Substring(elem, 1); - } - - private string GetAbsExpr(ShaderIrOp op) => GetUnaryCall(op, "abs"); - - private string GetAddExpr(ShaderIrOp op) => GetBinaryExpr(op, "+"); - - private string GetAndExpr(ShaderIrOp op) => GetBinaryExpr(op, "&"); - - private string GetAsrExpr(ShaderIrOp op) => GetBinaryExpr(op, ">>"); - - private string GetBandExpr(ShaderIrOp op) => GetBinaryExpr(op, "&&"); - - private string GetBnotExpr(ShaderIrOp op) => GetUnaryExpr(op, "!"); - - private string GetBorExpr(ShaderIrOp op) => GetBinaryExpr(op, "||"); - - private string GetBxorExpr(ShaderIrOp op) => GetBinaryExpr(op, "^^"); - - private string GetCeilExpr(ShaderIrOp op) => GetUnaryCall(op, "ceil"); - - private string GetClampsExpr(ShaderIrOp op) - { - return "clamp(" + GetOperExpr(op, op.OperandA) + ", " + - GetOperExpr(op, op.OperandB) + ", " + - GetOperExpr(op, op.OperandC) + ")"; - } - - private string GetClampuExpr(ShaderIrOp op) - { - return "int(clamp(uint(" + GetOperExpr(op, op.OperandA) + "), " + - "uint(" + GetOperExpr(op, op.OperandB) + "), " + - "uint(" + GetOperExpr(op, op.OperandC) + ")))"; - } - - private string GetCeqExpr(ShaderIrOp op) => GetBinaryExpr(op, "=="); - - private string GetCequExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "=="); - - private string GetCgeExpr(ShaderIrOp op) => GetBinaryExpr(op, ">="); - - private string GetCgeuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, ">="); - - private string GetCgtExpr(ShaderIrOp op) => GetBinaryExpr(op, ">"); - - private string GetCgtuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, ">"); - - private string GetCleExpr(ShaderIrOp op) => GetBinaryExpr(op, "<="); - - private string GetCleuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "<="); - - private string GetCltExpr(ShaderIrOp op) => GetBinaryExpr(op, "<"); - - private string GetCltuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "<"); - - private string GetCnanExpr(ShaderIrOp op) => GetUnaryCall(op, "isnan"); - - private string GetCneExpr(ShaderIrOp op) => GetBinaryExpr(op, "!="); - - private string GetCutExpr(ShaderIrOp op) => "EndPrimitive()"; - - private string GetCneuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "!="); - - private string GetCnumExpr(ShaderIrOp op) => GetUnaryCall(op, "!isnan"); - - private string GetExitExpr(ShaderIrOp op) => "return 0u"; - - private string GetFcosExpr(ShaderIrOp op) => GetUnaryCall(op, "cos"); - - private string GetFex2Expr(ShaderIrOp op) => GetUnaryCall(op, "exp2"); - - private string GetFfmaExpr(ShaderIrOp op) => GetTernaryExpr(op, "*", "+"); - - private string GetFclampExpr(ShaderIrOp op) => GetTernaryCall(op, "clamp"); - - private string GetFlg2Expr(ShaderIrOp op) => GetUnaryCall(op, "log2"); - - private string GetFloorExpr(ShaderIrOp op) => GetUnaryCall(op, "floor"); - - private string GetFrcpExpr(ShaderIrOp op) => GetUnaryExpr(op, "1 / "); - - private string GetFrsqExpr(ShaderIrOp op) => GetUnaryCall(op, "inversesqrt"); - - private string GetFsinExpr(ShaderIrOp op) => GetUnaryCall(op, "sin"); - - private string GetFsqrtExpr(ShaderIrOp op) => GetUnaryCall(op, "sqrt"); - - private string GetFtosExpr(ShaderIrOp op) - { - return "int(" + GetOperExpr(op, op.OperandA) + ")"; - } - - private string GetFtouExpr(ShaderIrOp op) - { - return "int(uint(" + GetOperExpr(op, op.OperandA) + "))"; - } - - private string GetIpaExpr(ShaderIrOp op) - { - ShaderIrMetaIpa meta = (ShaderIrMetaIpa)op.MetaData; - - ShaderIrOperAbuf abuf = (ShaderIrOperAbuf)op.OperandA; - - if (meta.Mode == ShaderIpaMode.Pass) - { - int index = abuf.Offs >> 4; - int elem = (abuf.Offs >> 2) & 3; - - if (_decl.ShaderType == GalShaderType.Fragment && index == GlslDecl.GlPositionVec4Index) - { - switch (elem) - { - case 0: return "gl_FragCoord.x"; - case 1: return "gl_FragCoord.y"; - case 2: return "gl_FragCoord.z"; - case 3: return "1"; - } - } - } - - return GetSrcExpr(op.OperandA); - } - - private string GetKilExpr(ShaderIrOp op) => "discard"; - - private string GetLslExpr(ShaderIrOp op) => GetBinaryExpr(op, "<<"); - private string GetLsrExpr(ShaderIrOp op) - { - return "int(uint(" + GetOperExpr(op, op.OperandA) + ") >> " + - GetOperExpr(op, op.OperandB) + ")"; - } - - private string GetMaxExpr(ShaderIrOp op) => GetBinaryCall(op, "max"); - private string GetMinExpr(ShaderIrOp op) => GetBinaryCall(op, "min"); - - private string GetMulExpr(ShaderIrOp op) => GetBinaryExpr(op, "*"); - - private string GetNegExpr(ShaderIrOp op) => GetUnaryExpr(op, "-"); - - private string GetNotExpr(ShaderIrOp op) => GetUnaryExpr(op, "~"); - - private string GetOrExpr(ShaderIrOp op) => GetBinaryExpr(op, "|"); - - private string GetStofExpr(ShaderIrOp op) - { - return "float(" + GetOperExpr(op, op.OperandA) + ")"; - } - - private string GetSubExpr(ShaderIrOp op) => GetBinaryExpr(op, "-"); - - private string GetTexbExpr(ShaderIrOp op) - { - ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - - if (!_decl.CbTextures.TryGetValue(op, out ShaderDeclInfo declInfo)) - { - throw new InvalidOperationException(); - } - - string coords = GetTexSamplerCoords(op); - - string ch = "rgba".Substring(meta.Elem, 1); - - return GetTextureOperation(op, declInfo.Name, coords, ch); - } - - private string GetTexqExpr(ShaderIrOp op) - { - ShaderIrMetaTexq meta = (ShaderIrMetaTexq)op.MetaData; - - string ch = "xyzw".Substring(meta.Elem, 1); - - if (meta.Info == ShaderTexqInfo.Dimension) - { - string sampler = GetTexSamplerName(op); - - string lod = GetOperExpr(op, op.OperandA); //??? - - return "textureSize(" + sampler + ", " + lod + ")." + ch; - } - else - { - throw new NotImplementedException(meta.Info.ToString()); - } - } - - private string GetTexsExpr(ShaderIrOp op) - { - ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - - string sampler = GetTexSamplerName(op); - - string coords = GetTexSamplerCoords(op); - - string ch = "rgba".Substring(meta.Elem, 1); - - return GetTextureOperation(op, sampler, coords, ch); - } - - private string GetTld4Expr(ShaderIrOp op) - { - ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - - string sampler = GetTexSamplerName(op); - - string coords = GetTexSamplerCoords(op); - - string ch = "rgba".Substring(meta.Elem, 1); - - return GetTextureGatherOperation(op, sampler, coords, ch); - } - - // TODO: support AOFFI on non nvidia drivers - private string GetTxlfExpr(ShaderIrOp op) - { - // TODO: Support all suffixes - ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - - TextureInstructionSuffix suffix = meta.TextureInstructionSuffix; - - string sampler = GetTexSamplerName(op); - - string coords = GetITexSamplerCoords(op); - - string ch = "rgba".Substring(meta.Elem, 1); - - string lod = "0"; - - if (meta.LevelOfDetail != null) - { - lod = GetOperExpr(op, meta.LevelOfDetail); - } - - if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) - { - string offset = GetTextureOffset(meta, GetOperExpr(op, meta.Offset)); - return "texelFetchOffset(" + sampler + ", " + coords + ", " + lod + ", " + offset + ")." + ch; - } - - return "texelFetch(" + sampler + ", " + coords + ", " + lod + ")." + ch; - } - - private string GetTruncExpr(ShaderIrOp op) => GetUnaryCall(op, "trunc"); - - private string GetUtofExpr(ShaderIrOp op) - { - return "float(uint(" + GetOperExpr(op, op.OperandA) + "))"; - } - - private string GetXorExpr(ShaderIrOp op) => GetBinaryExpr(op, "^"); - - private string GetUnaryCall(ShaderIrOp op, string funcName) - { - return funcName + "(" + GetOperExpr(op, op.OperandA) + ")"; - } - - private string GetBinaryCall(ShaderIrOp op, string funcName) - { - return funcName + "(" + GetOperExpr(op, op.OperandA) + ", " + - GetOperExpr(op, op.OperandB) + ")"; - } - - private string GetTernaryCall(ShaderIrOp op, string funcName) - { - return funcName + "(" + GetOperExpr(op, op.OperandA) + ", " + - GetOperExpr(op, op.OperandB) + ", " + - GetOperExpr(op, op.OperandC) + ")"; - } - - private string GetUnaryExpr(ShaderIrOp op, string opr) - { - return opr + GetOperExpr(op, op.OperandA); - } - - private string GetBinaryExpr(ShaderIrOp op, string opr) - { - return GetOperExpr(op, op.OperandA) + " " + opr + " " + - GetOperExpr(op, op.OperandB); - } - - private string GetBinaryExprWithNaN(ShaderIrOp op, string opr) - { - string a = GetOperExpr(op, op.OperandA); - string b = GetOperExpr(op, op.OperandB); - - string nanCheck = - " || isnan(" + a + ")" + - " || isnan(" + b + ")"; - - return a + " " + opr + " " + b + nanCheck; - } - - private string GetTernaryExpr(ShaderIrOp op, string opr1, string opr2) - { - return GetOperExpr(op, op.OperandA) + " " + opr1 + " " + - GetOperExpr(op, op.OperandB) + " " + opr2 + " " + - GetOperExpr(op, op.OperandC); - } - - private string GetTexSamplerName(ShaderIrOp op) - { - ShaderIrOperImm node = (ShaderIrOperImm)op.OperandC; - - int handle = ((ShaderIrOperImm)op.OperandC).Value; - - if (!_decl.Textures.TryGetValue(handle, out ShaderDeclInfo declInfo)) - { - throw new InvalidOperationException(); - } - - return declInfo.Name; - } - - private string GetTexSamplerCoords(ShaderIrOp op) - { - ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - - bool hasDepth = (meta.TextureInstructionSuffix & TextureInstructionSuffix.Dc) != 0; - - int coords = ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget); - - bool isArray = ImageUtils.IsArray(meta.TextureTarget); - - - string GetLastArgument(ShaderIrNode node) - { - string result = GetOperExpr(op, node); - - // array index is actually an integer so we need to pass it correctly - if (isArray) - { - result = "float(floatBitsToInt(" + result + "))"; - } - - return result; - } - - string lastArgument; - string depthArgument = ""; - - int vecSize = coords; - if (hasDepth && op.Inst != ShaderIrInst.Tld4) - { - vecSize++; - depthArgument = $", {GetOperExpr(op, meta.DepthCompare)}"; - } - - switch (coords) - { - case 1: - if (hasDepth) - { - return $"vec3({GetOperExpr(op, meta.Coordinates[0])}, 0.0{depthArgument})"; - } - - return GetOperExpr(op, meta.Coordinates[0]); - case 2: - lastArgument = GetLastArgument(meta.Coordinates[1]); - - return $"vec{vecSize}({GetOperExpr(op, meta.Coordinates[0])}, {lastArgument}{depthArgument})"; - case 3: - lastArgument = GetLastArgument(meta.Coordinates[2]); - - return $"vec{vecSize}({GetOperExpr(op, meta.Coordinates[0])}, {GetOperExpr(op, meta.Coordinates[1])}, {lastArgument}{depthArgument})"; - case 4: - lastArgument = GetLastArgument(meta.Coordinates[3]); - - return $"vec4({GetOperExpr(op, meta.Coordinates[0])}, {GetOperExpr(op, meta.Coordinates[1])}, {GetOperExpr(op, meta.Coordinates[2])}, {lastArgument}){depthArgument}"; - default: - throw new InvalidOperationException(); - } - - } - - private string GetTextureOffset(ShaderIrMetaTex meta, string oper, int shift = 4, int mask = 0xF) - { - string GetOffset(string operation, int index) - { - return $"({operation} >> {index * shift}) & 0x{mask:x}"; - } - - int coords = ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget); - - if (ImageUtils.IsArray(meta.TextureTarget)) - coords -= 1; - - switch (coords) - { - case 1: - return GetOffset(oper, 0); - case 2: - return "ivec2(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ")"; - case 3: - return "ivec3(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ", " + GetOffset(oper, 2) + ")"; - case 4: - return "ivec4(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ", " + GetOffset(oper, 2) + ", " + GetOffset(oper, 3) + ")"; - default: - throw new InvalidOperationException(); - } - } - - // TODO: support AOFFI on non nvidia drivers - private string GetTextureGatherOperation(ShaderIrOp op, string sampler, string coords, string ch) - { - ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - - TextureInstructionSuffix suffix = meta.TextureInstructionSuffix; - - string chString = "." + ch; - - string comp = meta.Component.ToString(); - - if ((suffix & TextureInstructionSuffix.Dc) != 0) - { - comp = GetOperExpr(op, meta.DepthCompare); - } - - if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) - { - string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))", 8, 0x3F); - - if ((suffix & TextureInstructionSuffix.Dc) != 0) - { - return "textureGatherOffset(" + sampler + ", " + coords + ", " + comp + ", " + offset + ")" + chString; - } - - return "textureGatherOffset(" + sampler + ", " + coords + ", " + offset + ", " + comp + ")" + chString; - } - // TODO: Support PTP - else if ((suffix & TextureInstructionSuffix.Ptp) != 0) - { - throw new NotImplementedException(); - } - - return "textureGather(" + sampler + ", " + coords + ", " + comp + ")" + chString; - } - - // TODO: support AOFFI on non nvidia drivers - private string GetTextureOperation(ShaderIrOp op, string sampler, string coords, string ch) - { - ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - - TextureInstructionSuffix suffix = meta.TextureInstructionSuffix; - - string chString = "." + ch; - - if ((suffix & TextureInstructionSuffix.Dc) != 0) - { - chString = ""; - } - - // TODO: Support LBA and LLA - if ((suffix & TextureInstructionSuffix.Lz) != 0) - { - if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) - { - string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))"); - - return "textureLodOffset(" + sampler + ", " + coords + ", 0.0, " + offset + ")" + chString; - } - - return "textureLod(" + sampler + ", " + coords + ", 0.0)" + chString; - } - else if ((suffix & TextureInstructionSuffix.Lb) != 0) - { - if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) - { - string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))"); - - return "textureOffset(" + sampler + ", " + coords + ", " + offset + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString; - } - - return "texture(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString; - } - else if ((suffix & TextureInstructionSuffix.Ll) != 0) - { - if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) - { - string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))"); - - return "textureLodOffset(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ", " + offset + ")" + chString; - } - - return "textureLod(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString; - } - else if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver) - { - string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))"); - - return "textureOffset(" + sampler + ", " + coords + ", " + offset + ")" + chString; - } - else - { - return "texture(" + sampler + ", " + coords + ")" + chString; - } - throw new NotImplementedException($"Texture Suffix {meta.TextureInstructionSuffix} is not implemented"); - - } - - private string GetITexSamplerCoords(ShaderIrOp op) - { - ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData; - - switch (ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget)) - { - case 1: - return GetOperExpr(op, meta.Coordinates[0]); - case 2: - return "ivec2(" + GetOperExpr(op, meta.Coordinates[0]) + ", " + GetOperExpr(op, meta.Coordinates[1]) + ")"; - case 3: - return "ivec3(" + GetOperExpr(op, meta.Coordinates[0]) + ", " + GetOperExpr(op, meta.Coordinates[1]) + ", " + GetOperExpr(op, meta.Coordinates[2]) + ")"; - default: - throw new InvalidOperationException(); - } - } - - private string GetOperExpr(ShaderIrOp op, ShaderIrNode oper) - { - return GetExprWithCast(op, oper, GetSrcExpr(oper)); - } - - private static string GetExprWithCast(ShaderIrNode dst, ShaderIrNode src, string expr) - { - //Note: The "DstType" (of the cast) is the type that the operation - //uses on the source operands, while the "SrcType" is the destination - //type of the operand result (if it is a operation) or just the type - //of the variable for registers/uniforms/attributes. - OperType dstType = GetSrcNodeType(dst); - OperType srcType = GetDstNodeType(src); - - if (dstType != srcType) - { - //Check for invalid casts - //(like bool to int/float and others). - if (srcType != OperType.F32 && - srcType != OperType.I32) - { - throw new InvalidOperationException(); - } - - switch (src) - { - case ShaderIrOperGpr gpr: - { - //When the Gpr is ZR, just return the 0 value directly, - //since the float encoding for 0 is 0. - if (gpr.IsConst) - { - return "0"; - } - break; - } - } - - switch (dstType) - { - case OperType.F32: expr = "intBitsToFloat(" + expr + ")"; break; - case OperType.I32: expr = "floatBitsToInt(" + expr + ")"; break; - } - } - - return expr; - } - - private static string GetIntConst(int value) - { - string expr = value.ToString(CultureInfo.InvariantCulture); - - return value < 0 ? "(" + expr + ")" : expr; - } - - private static string GetFloatConst(float value) - { - string expr = value.ToString(CultureInfo.InvariantCulture); - - return value < 0 ? "(" + expr + ")" : expr; - } - - private static OperType GetDstNodeType(ShaderIrNode node) - { - //Special case instructions with the result type different - //from the input types (like integer <-> float conversion) here. - if (node is ShaderIrOp op) - { - switch (op.Inst) - { - case ShaderIrInst.Stof: - case ShaderIrInst.Txlf: - case ShaderIrInst.Utof: - return OperType.F32; - - case ShaderIrInst.Ftos: - case ShaderIrInst.Ftou: - return OperType.I32; - } - } - - return GetSrcNodeType(node); - } - - private static OperType GetSrcNodeType(ShaderIrNode node) - { - switch (node) - { - case ShaderIrOperAbuf abuf: - return abuf.Offs == GlslDecl.LayerAttr || - abuf.Offs == GlslDecl.InstanceIdAttr || - abuf.Offs == GlslDecl.VertexIdAttr || - abuf.Offs == GlslDecl.FaceAttr - ? OperType.I32 - : OperType.F32; - - case ShaderIrOperCbuf cbuf: return OperType.F32; - case ShaderIrOperGpr gpr: return OperType.F32; - case ShaderIrOperImm imm: return OperType.I32; - case ShaderIrOperImmf immf: return OperType.F32; - case ShaderIrOperPred pred: return OperType.Bool; - - case ShaderIrOp op: - if (op.Inst > ShaderIrInst.B_Start && - op.Inst < ShaderIrInst.B_End) - { - return OperType.Bool; - } - else if (op.Inst > ShaderIrInst.F_Start && - op.Inst < ShaderIrInst.F_End) - { - return OperType.F32; - } - else if (op.Inst > ShaderIrInst.I_Start && - op.Inst < ShaderIrInst.I_End) - { - return OperType.I32; - } - break; - } - - throw new ArgumentException(nameof(node)); - } - - private static string GetBlockPosition(ShaderIrBlock block) - { - if (block != null) - { - return "0x" + block.Position.ToString("x8") + "u"; - } - else - { - return "0u"; - } - } - } -} diff --git a/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs b/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs deleted file mode 100644 index be8555d572..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/GlslProgram.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gal.Shader -{ - public struct GlslProgram - { - public string Code { get; private set; } - - public IEnumerable Textures { get; private set; } - public IEnumerable Uniforms { get; private set; } - - public GlslProgram( - string code, - IEnumerable textures, - IEnumerable uniforms) - { - Code = code; - Textures = textures; - Uniforms = uniforms; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs deleted file mode 100644 index f935be74ff..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ /dev/null @@ -1,1299 +0,0 @@ -using System; - -using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; - -namespace Ryujinx.Graphics.Gal.Shader -{ - static partial class ShaderDecode - { - private enum HalfOutputType - { - PackedFp16, - Fp32, - MergeH0, - MergeH1 - } - - public static void Bfe_C(ShaderIrBlock block, long opCode, int position) - { - EmitBfe(block, opCode, ShaderOper.Cr); - } - - public static void Bfe_I(ShaderIrBlock block, long opCode, int position) - { - EmitBfe(block, opCode, ShaderOper.Imm); - } - - public static void Bfe_R(ShaderIrBlock block, long opCode, int position) - { - EmitBfe(block, opCode, ShaderOper.Rr); - } - - public static void Fadd_C(ShaderIrBlock block, long opCode, int position) - { - EmitFadd(block, opCode, ShaderOper.Cr); - } - - public static void Fadd_I(ShaderIrBlock block, long opCode, int position) - { - EmitFadd(block, opCode, ShaderOper.Immf); - } - - public static void Fadd_I32(ShaderIrBlock block, long opCode, int position) - { - ShaderIrNode operA = opCode.Gpr8(); - ShaderIrNode operB = opCode.Immf32_20(); - - bool negB = opCode.Read(53); - bool absA = opCode.Read(54); - bool negA = opCode.Read(56); - bool absB = opCode.Read(57); - - operA = GetAluFabsFneg(operA, absA, negA); - operB = GetAluFabsFneg(operB, absB, negB); - - ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Fadd, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - public static void Fadd_R(ShaderIrBlock block, long opCode, int position) - { - EmitFadd(block, opCode, ShaderOper.Rr); - } - - public static void Ffma_CR(ShaderIrBlock block, long opCode, int position) - { - EmitFfma(block, opCode, ShaderOper.Cr); - } - - public static void Ffma_I(ShaderIrBlock block, long opCode, int position) - { - EmitFfma(block, opCode, ShaderOper.Immf); - } - - public static void Ffma_RC(ShaderIrBlock block, long opCode, int position) - { - EmitFfma(block, opCode, ShaderOper.Rc); - } - - public static void Ffma_RR(ShaderIrBlock block, long opCode, int position) - { - EmitFfma(block, opCode, ShaderOper.Rr); - } - - public static void Fmnmx_C(ShaderIrBlock block, long opCode, int position) - { - EmitFmnmx(block, opCode, ShaderOper.Cr); - } - - public static void Fmnmx_I(ShaderIrBlock block, long opCode, int position) - { - EmitFmnmx(block, opCode, ShaderOper.Immf); - } - - public static void Fmnmx_R(ShaderIrBlock block, long opCode, int position) - { - EmitFmnmx(block, opCode, ShaderOper.Rr); - } - - public static void Fmul_I32(ShaderIrBlock block, long opCode, int position) - { - ShaderIrNode operA = opCode.Gpr8(); - ShaderIrNode operB = opCode.Immf32_20(); - - ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Fmul, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - public static void Fmul_C(ShaderIrBlock block, long opCode, int position) - { - EmitFmul(block, opCode, ShaderOper.Cr); - } - - public static void Fmul_I(ShaderIrBlock block, long opCode, int position) - { - EmitFmul(block, opCode, ShaderOper.Immf); - } - - public static void Fmul_R(ShaderIrBlock block, long opCode, int position) - { - EmitFmul(block, opCode, ShaderOper.Rr); - } - - public static void Fset_C(ShaderIrBlock block, long opCode, int position) - { - EmitFset(block, opCode, ShaderOper.Cr); - } - - public static void Fset_I(ShaderIrBlock block, long opCode, int position) - { - EmitFset(block, opCode, ShaderOper.Immf); - } - - public static void Fset_R(ShaderIrBlock block, long opCode, int position) - { - EmitFset(block, opCode, ShaderOper.Rr); - } - - public static void Fsetp_C(ShaderIrBlock block, long opCode, int position) - { - EmitFsetp(block, opCode, ShaderOper.Cr); - } - - public static void Fsetp_I(ShaderIrBlock block, long opCode, int position) - { - EmitFsetp(block, opCode, ShaderOper.Immf); - } - - public static void Fsetp_R(ShaderIrBlock block, long opCode, int position) - { - EmitFsetp(block, opCode, ShaderOper.Rr); - } - - public static void Hadd2_R(ShaderIrBlock block, long opCode, int position) - { - EmitBinaryHalfOp(block, opCode, ShaderIrInst.Fadd); - } - - public static void Hmul2_R(ShaderIrBlock block, long opCode, int position) - { - EmitBinaryHalfOp(block, opCode, ShaderIrInst.Fmul); - } - - public static void Iadd_C(ShaderIrBlock block, long opCode, int position) - { - EmitIadd(block, opCode, ShaderOper.Cr); - } - - public static void Iadd_I(ShaderIrBlock block, long opCode, int position) - { - EmitIadd(block, opCode, ShaderOper.Imm); - } - - public static void Iadd_I32(ShaderIrBlock block, long opCode, int position) - { - ShaderIrNode operA = opCode.Gpr8(); - ShaderIrNode operB = opCode.Imm32_20(); - - bool negA = opCode.Read(56); - - operA = GetAluIneg(operA, negA); - - ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Add, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - public static void Iadd_R(ShaderIrBlock block, long opCode, int position) - { - EmitIadd(block, opCode, ShaderOper.Rr); - } - - public static void Iadd3_C(ShaderIrBlock block, long opCode, int position) - { - EmitIadd3(block, opCode, ShaderOper.Cr); - } - - public static void Iadd3_I(ShaderIrBlock block, long opCode, int position) - { - EmitIadd3(block, opCode, ShaderOper.Imm); - } - - public static void Iadd3_R(ShaderIrBlock block, long opCode, int position) - { - EmitIadd3(block, opCode, ShaderOper.Rr); - } - - public static void Imnmx_C(ShaderIrBlock block, long opCode, int position) - { - EmitImnmx(block, opCode, ShaderOper.Cr); - } - - public static void Imnmx_I(ShaderIrBlock block, long opCode, int position) - { - EmitImnmx(block, opCode, ShaderOper.Imm); - } - - public static void Imnmx_R(ShaderIrBlock block, long opCode, int position) - { - EmitImnmx(block, opCode, ShaderOper.Rr); - } - - public static void Ipa(ShaderIrBlock block, long opCode, int position) - { - ShaderIrNode operA = opCode.Abuf28(); - ShaderIrNode operB = opCode.Gpr20(); - - ShaderIpaMode mode = (ShaderIpaMode)(opCode.Read(54, 3)); - - ShaderIrMetaIpa meta = new ShaderIrMetaIpa(mode); - - ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Ipa, operA, operB, null, meta); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - public static void Iscadd_C(ShaderIrBlock block, long opCode, int position) - { - EmitIscadd(block, opCode, ShaderOper.Cr); - } - - public static void Iscadd_I(ShaderIrBlock block, long opCode, int position) - { - EmitIscadd(block, opCode, ShaderOper.Imm); - } - - public static void Iscadd_R(ShaderIrBlock block, long opCode, int position) - { - EmitIscadd(block, opCode, ShaderOper.Rr); - } - - public static void Iset_C(ShaderIrBlock block, long opCode, int position) - { - EmitIset(block, opCode, ShaderOper.Cr); - } - - public static void Iset_I(ShaderIrBlock block, long opCode, int position) - { - EmitIset(block, opCode, ShaderOper.Imm); - } - - public static void Iset_R(ShaderIrBlock block, long opCode, int position) - { - EmitIset(block, opCode, ShaderOper.Rr); - } - - public static void Isetp_C(ShaderIrBlock block, long opCode, int position) - { - EmitIsetp(block, opCode, ShaderOper.Cr); - } - - public static void Isetp_I(ShaderIrBlock block, long opCode, int position) - { - EmitIsetp(block, opCode, ShaderOper.Imm); - } - - public static void Isetp_R(ShaderIrBlock block, long opCode, int position) - { - EmitIsetp(block, opCode, ShaderOper.Rr); - } - - public static void Lop_I32(ShaderIrBlock block, long opCode, int position) - { - int subOp = opCode.Read(53, 3); - - bool invA = opCode.Read(55); - bool invB = opCode.Read(56); - - ShaderIrInst inst = 0; - - switch (subOp) - { - case 0: inst = ShaderIrInst.And; break; - case 1: inst = ShaderIrInst.Or; break; - case 2: inst = ShaderIrInst.Xor; break; - } - - ShaderIrNode operB = GetAluNot(opCode.Imm32_20(), invB); - - //SubOp == 3 is pass, used by the not instruction - //which just moves the inverted register value. - if (subOp < 3) - { - ShaderIrNode operA = GetAluNot(opCode.Gpr8(), invA); - - ShaderIrOp op = new ShaderIrOp(inst, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - else - { - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operB))); - } - } - - public static void Lop_C(ShaderIrBlock block, long opCode, int position) - { - EmitLop(block, opCode, ShaderOper.Cr); - } - - public static void Lop_I(ShaderIrBlock block, long opCode, int position) - { - EmitLop(block, opCode, ShaderOper.Imm); - } - - public static void Lop_R(ShaderIrBlock block, long opCode, int position) - { - EmitLop(block, opCode, ShaderOper.Rr); - } - - public static void Mufu(ShaderIrBlock block, long opCode, int position) - { - int subOp = opCode.Read(20, 0xf); - - bool absA = opCode.Read(46); - bool negA = opCode.Read(48); - - ShaderIrInst inst = 0; - - switch (subOp) - { - case 0: inst = ShaderIrInst.Fcos; break; - case 1: inst = ShaderIrInst.Fsin; break; - case 2: inst = ShaderIrInst.Fex2; break; - case 3: inst = ShaderIrInst.Flg2; break; - case 4: inst = ShaderIrInst.Frcp; break; - case 5: inst = ShaderIrInst.Frsq; break; - case 8: inst = ShaderIrInst.Fsqrt; break; - - default: throw new NotImplementedException(subOp.ToString()); - } - - ShaderIrNode operA = opCode.Gpr8(); - - ShaderIrOp op = new ShaderIrOp(inst, GetAluFabsFneg(operA, absA, negA)); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - public static void Psetp(ShaderIrBlock block, long opCode, int position) - { - bool negA = opCode.Read(15); - bool negB = opCode.Read(32); - bool negP = opCode.Read(42); - - ShaderIrInst lopInst = opCode.BLop24(); - - ShaderIrNode operA = opCode.Pred12(); - ShaderIrNode operB = opCode.Pred29(); - - if (negA) - { - operA = new ShaderIrOp(ShaderIrInst.Bnot, operA); - } - - if (negB) - { - operB = new ShaderIrOp(ShaderIrInst.Bnot, operB); - } - - ShaderIrOp op = new ShaderIrOp(lopInst, operA, operB); - - ShaderIrOperPred p0Node = opCode.Pred3(); - ShaderIrOperPred p1Node = opCode.Pred0(); - ShaderIrOperPred p2Node = opCode.Pred39(); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op))); - - lopInst = opCode.BLop45(); - - if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst) - { - return; - } - - ShaderIrNode p2NNode = p2Node; - - if (negP) - { - p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode); - } - - op = new ShaderIrOp(ShaderIrInst.Bnot, p0Node); - - op = new ShaderIrOp(lopInst, op, p2NNode); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(p1Node, op))); - - op = new ShaderIrOp(lopInst, p0Node, p2NNode); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op))); - } - - public static void Rro_C(ShaderIrBlock block, long opCode, int position) - { - EmitRro(block, opCode, ShaderOper.Cr); - } - - public static void Rro_I(ShaderIrBlock block, long opCode, int position) - { - EmitRro(block, opCode, ShaderOper.Immf); - } - - public static void Rro_R(ShaderIrBlock block, long opCode, int position) - { - EmitRro(block, opCode, ShaderOper.Rr); - } - - public static void Shl_C(ShaderIrBlock block, long opCode, int position) - { - EmitAluBinary(block, opCode, ShaderOper.Cr, ShaderIrInst.Lsl); - } - - public static void Shl_I(ShaderIrBlock block, long opCode, int position) - { - EmitAluBinary(block, opCode, ShaderOper.Imm, ShaderIrInst.Lsl); - } - - public static void Shl_R(ShaderIrBlock block, long opCode, int position) - { - EmitAluBinary(block, opCode, ShaderOper.Rr, ShaderIrInst.Lsl); - } - - public static void Shr_C(ShaderIrBlock block, long opCode, int position) - { - EmitAluBinary(block, opCode, ShaderOper.Cr, GetShrInst(opCode)); - } - - public static void Shr_I(ShaderIrBlock block, long opCode, int position) - { - EmitAluBinary(block, opCode, ShaderOper.Imm, GetShrInst(opCode)); - } - - public static void Shr_R(ShaderIrBlock block, long opCode, int position) - { - EmitAluBinary(block, opCode, ShaderOper.Rr, GetShrInst(opCode)); - } - - private static ShaderIrInst GetShrInst(long opCode) - { - bool signed = opCode.Read(48); - - return signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr; - } - - public static void Vmad(ShaderIrBlock block, long opCode, int position) - { - ShaderIrNode operA = opCode.Gpr8(); - - ShaderIrNode operB; - - if (opCode.Read(50)) - { - operB = opCode.Gpr20(); - } - else - { - operB = opCode.Imm19_20(); - } - - ShaderIrOperGpr operC = opCode.Gpr39(); - - ShaderIrNode tmp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB); - - ShaderIrNode final = new ShaderIrOp(ShaderIrInst.Add, tmp, operC); - - int shr = opCode.Read(51, 3); - - if (shr != 0) - { - int shift = (shr == 2) ? 15 : 7; - - final = new ShaderIrOp(ShaderIrInst.Lsr, final, new ShaderIrOperImm(shift)); - } - - block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c")); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), final))); - } - - public static void Xmad_CR(ShaderIrBlock block, long opCode, int position) - { - EmitXmad(block, opCode, ShaderOper.Cr); - } - - public static void Xmad_I(ShaderIrBlock block, long opCode, int position) - { - EmitXmad(block, opCode, ShaderOper.Imm); - } - - public static void Xmad_RC(ShaderIrBlock block, long opCode, int position) - { - EmitXmad(block, opCode, ShaderOper.Rc); - } - - public static void Xmad_RR(ShaderIrBlock block, long opCode, int position) - { - EmitXmad(block, opCode, ShaderOper.Rr); - } - - private static void EmitAluBinary( - ShaderIrBlock block, - long opCode, - ShaderOper oper, - ShaderIrInst inst) - { - ShaderIrNode operA = opCode.Gpr8(), operB; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - ShaderIrNode op = new ShaderIrOp(inst, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - private static void EmitBfe(ShaderIrBlock block, long opCode, ShaderOper oper) - { - //TODO: Handle the case where position + length - //is greater than the word size, in this case the sign bit - //needs to be replicated to fill the remaining space. - bool negB = opCode.Read(48); - bool negA = opCode.Read(49); - - ShaderIrNode operA = opCode.Gpr8(), operB; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - ShaderIrNode op; - - bool signed = opCode.Read(48); //? - - if (operB is ShaderIrOperImm posLen) - { - int position = (posLen.Value >> 0) & 0xff; - int length = (posLen.Value >> 8) & 0xff; - - int lSh = 32 - (position + length); - - ShaderIrInst rightShift = signed - ? ShaderIrInst.Asr - : ShaderIrInst.Lsr; - - op = new ShaderIrOp(ShaderIrInst.Lsl, operA, new ShaderIrOperImm(lSh)); - op = new ShaderIrOp(rightShift, op, new ShaderIrOperImm(lSh + position)); - } - else - { - ShaderIrOperImm shift = new ShaderIrOperImm(8); - ShaderIrOperImm mask = new ShaderIrOperImm(0xff); - - ShaderIrNode opPos, opLen; - - opPos = new ShaderIrOp(ShaderIrInst.And, operB, mask); - opLen = new ShaderIrOp(ShaderIrInst.Lsr, operB, shift); - opLen = new ShaderIrOp(ShaderIrInst.And, opLen, mask); - - op = new ShaderIrOp(ShaderIrInst.Lsr, operA, opPos); - - op = ExtendTo32(op, signed, opLen); - } - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - private static void EmitFadd(ShaderIrBlock block, long opCode, ShaderOper oper) - { - bool negB = opCode.Read(45); - bool absA = opCode.Read(46); - bool negA = opCode.Read(48); - bool absB = opCode.Read(49); - bool sat = opCode.Read(50); - - ShaderIrNode operA = opCode.Gpr8(), operB; - - operA = GetAluFabsFneg(operA, absA, negA); - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Immf: operB = opCode.Immf19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operB = GetAluFabsFneg(operB, absB, negB); - - ShaderIrNode op = new ShaderIrOp(ShaderIrInst.Fadd, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat)))); - } - - private static void EmitFmul(ShaderIrBlock block, long opCode, ShaderOper oper) - { - bool negB = opCode.Read(48); - bool sat = opCode.Read(50); - - ShaderIrNode operA = opCode.Gpr8(), operB; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Immf: operB = opCode.Immf19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operB = GetAluFneg(operB, negB); - - ShaderIrNode op = new ShaderIrOp(ShaderIrInst.Fmul, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat)))); - } - - private static void EmitFfma(ShaderIrBlock block, long opCode, ShaderOper oper) - { - bool negB = opCode.Read(48); - bool negC = opCode.Read(49); - bool sat = opCode.Read(50); - - ShaderIrNode operA = opCode.Gpr8(), operB, operC; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Immf: operB = opCode.Immf19_20(); break; - case ShaderOper.Rc: operB = opCode.Gpr39(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operB = GetAluFneg(operB, negB); - - if (oper == ShaderOper.Rc) - { - operC = GetAluFneg(opCode.Cbuf34(), negC); - } - else - { - operC = GetAluFneg(opCode.Gpr39(), negC); - } - - ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Ffma, operA, operB, operC); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat)))); - } - - private static void EmitIadd(ShaderIrBlock block, long opCode, ShaderOper oper) - { - ShaderIrNode operA = opCode.Gpr8(); - ShaderIrNode operB; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - bool negA = opCode.Read(49); - bool negB = opCode.Read(48); - - operA = GetAluIneg(operA, negA); - operB = GetAluIneg(operB, negB); - - ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Add, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - private static void EmitIadd3(ShaderIrBlock block, long opCode, ShaderOper oper) - { - int mode = opCode.Read(37, 3); - - bool neg1 = opCode.Read(51); - bool neg2 = opCode.Read(50); - bool neg3 = opCode.Read(49); - - int height1 = opCode.Read(35, 3); - int height2 = opCode.Read(33, 3); - int height3 = opCode.Read(31, 3); - - ShaderIrNode operB; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - ShaderIrNode ApplyHeight(ShaderIrNode src, int height) - { - if (oper != ShaderOper.Rr) - { - return src; - } - - switch (height) - { - case 0: return src; - case 1: return new ShaderIrOp(ShaderIrInst.And, src, new ShaderIrOperImm(0xffff)); - case 2: return new ShaderIrOp(ShaderIrInst.Lsr, src, new ShaderIrOperImm(16)); - - default: throw new InvalidOperationException(); - } - } - - ShaderIrNode src1 = GetAluIneg(ApplyHeight(opCode.Gpr8(), height1), neg1); - ShaderIrNode src2 = GetAluIneg(ApplyHeight(operB, height2), neg2); - ShaderIrNode src3 = GetAluIneg(ApplyHeight(opCode.Gpr39(), height3), neg3); - - ShaderIrOp sum = new ShaderIrOp(ShaderIrInst.Add, src1, src2); - - if (oper == ShaderOper.Rr) - { - switch (mode) - { - case 1: sum = new ShaderIrOp(ShaderIrInst.Lsr, sum, new ShaderIrOperImm(16)); break; - case 2: sum = new ShaderIrOp(ShaderIrInst.Lsl, sum, new ShaderIrOperImm(16)); break; - } - } - - //Note: Here there should be a "+ 1" when carry flag is set - //but since carry is mostly ignored by other instructions, it's excluded for now - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), new ShaderIrOp(ShaderIrInst.Add, sum, src3)))); - } - - private static void EmitIscadd(ShaderIrBlock block, long opCode, ShaderOper oper) - { - bool negB = opCode.Read(48); - bool negA = opCode.Read(49); - - ShaderIrNode operA = opCode.Gpr8(), operB; - - ShaderIrOperImm scale = opCode.Imm5_39(); - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operA = GetAluIneg(operA, negA); - operB = GetAluIneg(operB, negB); - - ShaderIrOp scaleOp = new ShaderIrOp(ShaderIrInst.Lsl, operA, scale); - ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, operB, scaleOp); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp))); - } - - private static void EmitFmnmx(ShaderIrBlock block, long opCode, ShaderOper oper) - { - EmitMnmx(block, opCode, true, oper); - } - - private static void EmitImnmx(ShaderIrBlock block, long opCode, ShaderOper oper) - { - EmitMnmx(block, opCode, false, oper); - } - - private static void EmitMnmx(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper) - { - bool negB = opCode.Read(45); - bool absA = opCode.Read(46); - bool negA = opCode.Read(48); - bool absB = opCode.Read(49); - - ShaderIrNode operA = opCode.Gpr8(), operB; - - if (isFloat) - { - operA = GetAluFabsFneg(operA, absA, negA); - } - else - { - operA = GetAluIabsIneg(operA, absA, negA); - } - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Immf: operB = opCode.Immf19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - if (isFloat) - { - operB = GetAluFabsFneg(operB, absB, negB); - } - else - { - operB = GetAluIabsIneg(operB, absB, negB); - } - - ShaderIrOperPred pred = opCode.Pred39(); - - ShaderIrOp op; - - ShaderIrInst maxInst = isFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max; - ShaderIrInst minInst = isFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min; - - if (pred.IsConst) - { - bool isMax = opCode.Read(42); - - op = new ShaderIrOp(isMax - ? maxInst - : minInst, operA, operB); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - else - { - ShaderIrNode predN = opCode.Pred39N(); - - ShaderIrOp opMax = new ShaderIrOp(maxInst, operA, operB); - ShaderIrOp opMin = new ShaderIrOp(minInst, operA, operB); - - ShaderIrAsg asgMax = new ShaderIrAsg(opCode.Gpr0(), opMax); - ShaderIrAsg asgMin = new ShaderIrAsg(opCode.Gpr0(), opMin); - - block.AddNode(opCode.PredNode(new ShaderIrCond(predN, asgMax, not: true))); - block.AddNode(opCode.PredNode(new ShaderIrCond(predN, asgMin, not: false))); - } - } - - private static void EmitRro(ShaderIrBlock block, long opCode, ShaderOper oper) - { - //Note: this is a range reduction instruction and is supposed to - //be used with Mufu, here it just moves the value and ignores the operation. - bool negA = opCode.Read(45); - bool absA = opCode.Read(49); - - ShaderIrNode operA; - - switch (oper) - { - case ShaderOper.Cr: operA = opCode.Cbuf34(); break; - case ShaderOper.Immf: operA = opCode.Immf19_20(); break; - case ShaderOper.Rr: operA = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operA = GetAluFabsFneg(operA, absA, negA); - - block.AddNode(new ShaderIrCmnt("Stubbed.")); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA))); - } - - private static void EmitFset(ShaderIrBlock block, long opCode, ShaderOper oper) - { - EmitSet(block, opCode, true, oper); - } - - private static void EmitIset(ShaderIrBlock block, long opCode, ShaderOper oper) - { - EmitSet(block, opCode, false, oper); - } - - private static void EmitSet(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper) - { - bool negA = opCode.Read(43); - bool absB = opCode.Read(44); - bool negB = opCode.Read(53); - bool absA = opCode.Read(54); - - bool boolFloat = opCode.Read(isFloat ? 52 : 44); - - ShaderIrNode operA = opCode.Gpr8(), operB; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Immf: operB = opCode.Immf19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - ShaderIrInst cmpInst; - - if (isFloat) - { - operA = GetAluFabsFneg(operA, absA, negA); - operB = GetAluFabsFneg(operB, absB, negB); - - cmpInst = opCode.CmpF(); - } - else - { - cmpInst = opCode.Cmp(); - } - - ShaderIrOp op = new ShaderIrOp(cmpInst, operA, operB); - - ShaderIrInst lopInst = opCode.BLop45(); - - ShaderIrOperPred pNode = opCode.Pred39(); - - ShaderIrNode imm0, imm1; - - if (boolFloat) - { - imm0 = new ShaderIrOperImmf(0); - imm1 = new ShaderIrOperImmf(1); - } - else - { - imm0 = new ShaderIrOperImm(0); - imm1 = new ShaderIrOperImm(-1); - } - - ShaderIrNode asg0 = new ShaderIrAsg(opCode.Gpr0(), imm0); - ShaderIrNode asg1 = new ShaderIrAsg(opCode.Gpr0(), imm1); - - if (lopInst != ShaderIrInst.Band || !pNode.IsConst) - { - ShaderIrOp op2 = new ShaderIrOp(lopInst, op, pNode); - - asg0 = new ShaderIrCond(op2, asg0, not: true); - asg1 = new ShaderIrCond(op2, asg1, not: false); - } - else - { - asg0 = new ShaderIrCond(op, asg0, not: true); - asg1 = new ShaderIrCond(op, asg1, not: false); - } - - block.AddNode(opCode.PredNode(asg0)); - block.AddNode(opCode.PredNode(asg1)); - } - - private static void EmitFsetp(ShaderIrBlock block, long opCode, ShaderOper oper) - { - EmitSetp(block, opCode, true, oper); - } - - private static void EmitIsetp(ShaderIrBlock block, long opCode, ShaderOper oper) - { - EmitSetp(block, opCode, false, oper); - } - - private static void EmitSetp(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper) - { - bool absA = opCode.Read(7); - bool negP = opCode.Read(42); - bool negA = opCode.Read(43); - bool absB = opCode.Read(44); - - ShaderIrNode operA = opCode.Gpr8(), operB; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Immf: operB = opCode.Immf19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - ShaderIrInst cmpInst; - - if (isFloat) - { - operA = GetAluFabsFneg(operA, absA, negA); - operB = GetAluFabs (operB, absB); - - cmpInst = opCode.CmpF(); - } - else - { - cmpInst = opCode.Cmp(); - } - - ShaderIrOp op = new ShaderIrOp(cmpInst, operA, operB); - - ShaderIrOperPred p0Node = opCode.Pred3(); - ShaderIrOperPred p1Node = opCode.Pred0(); - ShaderIrOperPred p2Node = opCode.Pred39(); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op))); - - ShaderIrInst lopInst = opCode.BLop45(); - - if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst) - { - return; - } - - ShaderIrNode p2NNode = p2Node; - - if (negP) - { - p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode); - } - - op = new ShaderIrOp(ShaderIrInst.Bnot, p0Node); - - op = new ShaderIrOp(lopInst, op, p2NNode); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(p1Node, op))); - - op = new ShaderIrOp(lopInst, p0Node, p2NNode); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op))); - } - - private static void EmitBinaryHalfOp(ShaderIrBlock block, long opCode, ShaderIrInst inst) - { - bool absB = opCode.Read(30); - bool negB = opCode.Read(31); - bool sat = opCode.Read(32); - bool absA = opCode.Read(44); - - ShaderIrOperGpr[] vecA = opCode.GprHalfVec8(); - ShaderIrOperGpr[] vecB = opCode.GprHalfVec20(); - - HalfOutputType outputType = (HalfOutputType)opCode.Read(49, 3); - - int elems = outputType == HalfOutputType.PackedFp16 ? 2 : 1; - int first = outputType == HalfOutputType.MergeH1 ? 1 : 0; - - for (int index = first; index < elems; index++) - { - ShaderIrNode operA = GetAluFabs (vecA[index], absA); - ShaderIrNode operB = GetAluFabsFneg(vecB[index], absB, negB); - - ShaderIrNode op = new ShaderIrOp(inst, operA, operB); - - ShaderIrOperGpr dst = GetHalfDst(opCode, outputType, index); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, GetAluFsat(op, sat)))); - } - } - - private static ShaderIrOperGpr GetHalfDst(long opCode, HalfOutputType outputType, int index) - { - switch (outputType) - { - case HalfOutputType.PackedFp16: return opCode.GprHalf0(index); - case HalfOutputType.Fp32: return opCode.Gpr0(); - case HalfOutputType.MergeH0: return opCode.GprHalf0(0); - case HalfOutputType.MergeH1: return opCode.GprHalf0(1); - } - - throw new ArgumentException(nameof(outputType)); - } - - private static void EmitLop(ShaderIrBlock block, long opCode, ShaderOper oper) - { - int subOp = opCode.Read(41, 3); - - bool invA = opCode.Read(39); - bool invB = opCode.Read(40); - - ShaderIrInst inst = 0; - - switch (subOp) - { - case 0: inst = ShaderIrInst.And; break; - case 1: inst = ShaderIrInst.Or; break; - case 2: inst = ShaderIrInst.Xor; break; - } - - ShaderIrNode operA = GetAluNot(opCode.Gpr8(), invA); - ShaderIrNode operB; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.Imm19_20(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operB = GetAluNot(operB, invB); - - ShaderIrNode op; - - if (subOp < 3) - { - op = new ShaderIrOp(inst, operA, operB); - } - else - { - op = operB; - } - - ShaderIrNode compare = new ShaderIrOp(ShaderIrInst.Cne, op, new ShaderIrOperImm(0)); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Pred48(), compare))); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - private enum XmadMode - { - Cfull = 0, - Clo = 1, - Chi = 2, - Csfu = 3, - Cbcc = 4 - } - - private static void EmitXmad(ShaderIrBlock block, long opCode, ShaderOper oper) - { - bool signedA = opCode.Read(48); - bool signedB = opCode.Read(49); - bool highB = opCode.Read(52); - bool highA = opCode.Read(53); - - int mode = opCode.Read(50, 7); - - ShaderIrNode operA = opCode.Gpr8(), operB, operC; - - switch (oper) - { - case ShaderOper.Cr: operB = opCode.Cbuf34(); break; - case ShaderOper.Imm: operB = opCode.ImmU16_20(); break; - case ShaderOper.Rc: operB = opCode.Gpr39(); break; - case ShaderOper.Rr: operB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - ShaderIrNode operB2 = operB; - - if (oper == ShaderOper.Imm) - { - int imm = ((ShaderIrOperImm)operB2).Value; - - if (!highB) - { - imm <<= 16; - } - - if (signedB) - { - imm >>= 16; - } - else - { - imm = (int)((uint)imm >> 16); - } - - operB2 = new ShaderIrOperImm(imm); - } - - ShaderIrOperImm imm16 = new ShaderIrOperImm(16); - - //If we are working with the lower 16-bits of the A/B operands, - //we need to shift the lower 16-bits to the top 16-bits. Later, - //they will be right shifted. For U16 types, this will be a logical - //right shift, and for S16 types, a arithmetic right shift. - if (!highA) - { - operA = new ShaderIrOp(ShaderIrInst.Lsl, operA, imm16); - } - - if (!highB && oper != ShaderOper.Imm) - { - operB2 = new ShaderIrOp(ShaderIrInst.Lsl, operB2, imm16); - } - - ShaderIrInst shiftA = signedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr; - ShaderIrInst shiftB = signedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr; - - operA = new ShaderIrOp(shiftA, operA, imm16); - - if (oper != ShaderOper.Imm) - { - operB2 = new ShaderIrOp(shiftB, operB2, imm16); - } - - bool productShiftLeft = false; - bool merge = false; - - if (oper == ShaderOper.Rc) - { - operC = opCode.Cbuf34(); - } - else - { - operC = opCode.Gpr39(); - - productShiftLeft = opCode.Read(36); - merge = opCode.Read(37); - } - - ShaderIrOp mulOp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB2); - - if (productShiftLeft) - { - mulOp = new ShaderIrOp(ShaderIrInst.Lsl, mulOp, imm16); - } - - switch ((XmadMode)mode) - { - case XmadMode.Clo: operC = ExtendTo32(operC, signed: false, size: 16); break; - - case XmadMode.Chi: operC = new ShaderIrOp(ShaderIrInst.Lsr, operC, imm16); break; - - case XmadMode.Cbcc: - { - ShaderIrOp operBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16); - - operC = new ShaderIrOp(ShaderIrInst.Add, operC, operBLsh16); - - break; - } - - case XmadMode.Csfu: - { - ShaderIrOperImm imm31 = new ShaderIrOperImm(31); - - ShaderIrOp signAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, operA, imm31); - ShaderIrOp signAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, operB2, imm31); - - signAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustA, imm16); - signAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustB, imm16); - - ShaderIrOp signAdjust = new ShaderIrOp(ShaderIrInst.Add, signAdjustA, signAdjustB); - - operC = new ShaderIrOp(ShaderIrInst.Sub, operC, signAdjust); - - break; - } - } - - ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, mulOp, operC); - - if (merge) - { - ShaderIrOperImm imm16Mask = new ShaderIrOperImm(0xffff); - - addOp = new ShaderIrOp(ShaderIrInst.And, addOp, imm16Mask); - operB = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16); - addOp = new ShaderIrOp(ShaderIrInst.Or, addOp, operB); - } - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp))); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs deleted file mode 100644 index fc9926934d..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; - -namespace Ryujinx.Graphics.Gal.Shader -{ - static partial class ShaderDecode - { - public static void Bra(ShaderIrBlock block, long opCode, int position) - { - if ((opCode & 0x20) != 0) - { - //This reads the target offset from the constant buffer. - //Almost impossible to support with GLSL. - throw new NotImplementedException(); - } - - ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch()); - - block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, imm))); - } - - public static void Exit(ShaderIrBlock block, long opCode, int position) - { - int cCode = (int)opCode & 0x1f; - - //TODO: Figure out what the other condition codes mean... - if (cCode == 0xf) - { - block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit))); - } - } - - public static void Kil(ShaderIrBlock block, long opCode, int position) - { - block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil))); - } - - public static void Ssy(ShaderIrBlock block, long opCode, int position) - { - if ((opCode & 0x20) != 0) - { - //This reads the target offset from the constant buffer. - //Almost impossible to support with GLSL. - throw new NotImplementedException(); - } - - ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch()); - - block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, imm)); - } - - public static void Sync(ShaderIrBlock block, long opCode, int position) - { - //TODO: Implement Sync condition codes - block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync))); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs deleted file mode 100644 index cc385aa4ea..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - delegate void ShaderDecodeFunc(ShaderIrBlock block, long opCode, int position); -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs deleted file mode 100644 index 9a84e6129c..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - static class ShaderDecodeHelper - { - private static readonly ShaderIrOperImmf ImmfZero = new ShaderIrOperImmf(0); - private static readonly ShaderIrOperImmf ImmfOne = new ShaderIrOperImmf(1); - - public static ShaderIrNode GetAluFabsFneg(ShaderIrNode node, bool abs, bool neg) - { - return GetAluFneg(GetAluFabs(node, abs), neg); - } - - public static ShaderIrNode GetAluFabs(ShaderIrNode node, bool abs) - { - return abs ? new ShaderIrOp(ShaderIrInst.Fabs, node) : node; - } - - public static ShaderIrNode GetAluFneg(ShaderIrNode node, bool neg) - { - return neg ? new ShaderIrOp(ShaderIrInst.Fneg, node) : node; - } - - public static ShaderIrNode GetAluFsat(ShaderIrNode node, bool sat) - { - return sat ? new ShaderIrOp(ShaderIrInst.Fclamp, node, ImmfZero, ImmfOne) : node; - } - - public static ShaderIrNode GetAluIabsIneg(ShaderIrNode node, bool abs, bool neg) - { - return GetAluIneg(GetAluIabs(node, abs), neg); - } - - public static ShaderIrNode GetAluIabs(ShaderIrNode node, bool abs) - { - return abs ? new ShaderIrOp(ShaderIrInst.Abs, node) : node; - } - - public static ShaderIrNode GetAluIneg(ShaderIrNode node, bool neg) - { - return neg ? new ShaderIrOp(ShaderIrInst.Neg, node) : node; - } - - public static ShaderIrNode GetAluNot(ShaderIrNode node, bool not) - { - return not ? new ShaderIrOp(ShaderIrInst.Not, node) : node; - } - - public static ShaderIrNode ExtendTo32(ShaderIrNode node, bool signed, int size) - { - int shift = 32 - size; - - ShaderIrInst rightShift = signed - ? ShaderIrInst.Asr - : ShaderIrInst.Lsr; - - node = new ShaderIrOp(ShaderIrInst.Lsl, node, new ShaderIrOperImm(shift)); - node = new ShaderIrOp(rightShift, node, new ShaderIrOperImm(shift)); - - return node; - } - - public static ShaderIrNode ExtendTo32(ShaderIrNode node, bool signed, ShaderIrNode size) - { - ShaderIrOperImm wordSize = new ShaderIrOperImm(32); - - ShaderIrOp shift = new ShaderIrOp(ShaderIrInst.Sub, wordSize, size); - - ShaderIrInst rightShift = signed - ? ShaderIrInst.Asr - : ShaderIrInst.Lsr; - - node = new ShaderIrOp(ShaderIrInst.Lsl, node, shift); - node = new ShaderIrOp(rightShift, node, shift); - - return node; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs deleted file mode 100644 index 7ce126b0c4..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs +++ /dev/null @@ -1,878 +0,0 @@ -using Ryujinx.Graphics.Texture; -using System; - -using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; - -namespace Ryujinx.Graphics.Gal.Shader -{ - static partial class ShaderDecode - { - // ReSharper disable InconsistentNaming - private const int ____ = 0x0; - private const int R___ = 0x1; - private const int _G__ = 0x2; - private const int RG__ = 0x3; - private const int __B_ = 0x4; - private const int RGB_ = 0x7; - private const int ___A = 0x8; - private const int R__A = 0x9; - private const int _G_A = 0xa; - private const int RG_A = 0xb; - private const int __BA = 0xc; - private const int R_BA = 0xd; - private const int _GBA = 0xe; - private const int RGBA = 0xf; - // ReSharper restore InconsistentNaming - - private static int[,] _maskLut = new int[,] - { - { ____, ____, ____, ____, ____, ____, ____, ____ }, - { R___, _G__, __B_, ___A, RG__, R__A, _G_A, __BA }, - { R___, _G__, __B_, ___A, RG__, ____, ____, ____ }, - { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ } - }; - - private static GalTextureTarget TexToTextureTarget(int texType, bool isArray) - { - switch (texType) - { - case 0: - return isArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD; - case 2: - return isArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD; - case 4: - if (isArray) - throw new InvalidOperationException("ARRAY bit set on a TEX with 3D texture!"); - return GalTextureTarget.ThreeD; - case 6: - return isArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap; - default: - throw new InvalidOperationException(); - } - } - - private static GalTextureTarget TexsToTextureTarget(int texType) - { - switch (texType) - { - case 0: - return GalTextureTarget.OneD; - case 2: - case 4: - case 6: - case 8: - case 0xa: - case 0xc: - return GalTextureTarget.TwoD; - case 0xe: - case 0x10: - case 0x12: - return GalTextureTarget.TwoDArray; - case 0x14: - case 0x16: - return GalTextureTarget.ThreeD; - case 0x18: - case 0x1a: - return GalTextureTarget.CubeMap; - default: - throw new InvalidOperationException(); - } - } - - public static GalTextureTarget TldsToTextureTarget(int texType) - { - switch (texType) - { - case 0: - case 2: - return GalTextureTarget.OneD; - case 4: - case 8: - case 0xa: - case 0xc: - case 0x18: - return GalTextureTarget.TwoD; - case 0x10: - return GalTextureTarget.TwoDArray; - case 0xe: - return GalTextureTarget.ThreeD; - default: - throw new InvalidOperationException(); - } - } - - public static void Ld_A(ShaderIrBlock block, long opCode, int position) - { - ShaderIrNode[] opers = opCode.Abuf20(); - - //Used by GS - ShaderIrOperGpr vertex = opCode.Gpr39(); - - int index = 0; - - foreach (ShaderIrNode operA in opers) - { - ShaderIrOperGpr operD = opCode.Gpr0(); - - operD.Index += index++; - - block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, operA))); - } - } - - public static void Ld_C(ShaderIrBlock block, long opCode, int position) - { - int cbufPos = opCode.Read(22, 0x3fff); - int cbufIndex = opCode.Read(36, 0x1f); - int type = opCode.Read(48, 7); - - if (type > 5) - { - throw new InvalidOperationException(); - } - - ShaderIrOperGpr temp = ShaderIrOperGpr.MakeTemporary(); - - block.AddNode(new ShaderIrAsg(temp, opCode.Gpr8())); - - int count = type == 5 ? 2 : 1; - - for (int index = 0; index < count; index++) - { - ShaderIrOperCbuf operA = new ShaderIrOperCbuf(cbufIndex, cbufPos, temp); - - ShaderIrOperGpr operD = opCode.Gpr0(); - - operA.Pos += index; - operD.Index += index; - - if (!operD.IsValidRegister) - { - break; - } - - ShaderIrNode node = operA; - - if (type < 4) - { - //This is a 8 or 16 bits type. - bool signed = (type & 1) != 0; - - int size = 8 << (type >> 1); - - node = ExtendTo32(node, signed, size); - } - - block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, node))); - } - } - - public static void St_A(ShaderIrBlock block, long opCode, int position) - { - ShaderIrNode[] opers = opCode.Abuf20(); - - int index = 0; - - foreach (ShaderIrNode operA in opers) - { - ShaderIrOperGpr operD = opCode.Gpr0(); - - operD.Index += index++; - - block.AddNode(opCode.PredNode(new ShaderIrAsg(operA, operD))); - } - } - - public static void Texq(ShaderIrBlock block, long opCode, int position) - { - ShaderIrNode operD = opCode.Gpr0(); - ShaderIrNode operA = opCode.Gpr8(); - - ShaderTexqInfo info = (ShaderTexqInfo)(opCode.Read(22, 0x1f)); - - ShaderIrMetaTexq meta0 = new ShaderIrMetaTexq(info, 0); - ShaderIrMetaTexq meta1 = new ShaderIrMetaTexq(info, 1); - - ShaderIrNode operC = opCode.Imm13_36(); - - ShaderIrOp op0 = new ShaderIrOp(ShaderIrInst.Texq, operA, null, operC, meta0); - ShaderIrOp op1 = new ShaderIrOp(ShaderIrInst.Texq, operA, null, operC, meta1); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, op0))); - block.AddNode(opCode.PredNode(new ShaderIrAsg(operA, op1))); //Is this right? - } - - public static void Tex(ShaderIrBlock block, long opCode, int position) - { - TextureInstructionSuffix suffix; - - int rawSuffix = opCode.Read(0x34, 0x38); - - switch (rawSuffix) - { - case 0: - suffix = TextureInstructionSuffix.None; - break; - case 0x8: - suffix = TextureInstructionSuffix.Lz; - break; - case 0x10: - suffix = TextureInstructionSuffix.Lb; - break; - case 0x18: - suffix = TextureInstructionSuffix.Ll; - break; - case 0x30: - suffix = TextureInstructionSuffix.Lba; - break; - case 0x38: - suffix = TextureInstructionSuffix.Lla; - break; - default: - throw new InvalidOperationException($"Invalid Suffix for TEX instruction {rawSuffix}"); - } - - bool isOffset = opCode.Read(0x36); - - if (isOffset) - suffix |= TextureInstructionSuffix.AOffI; - - EmitTex(block, opCode, suffix, gprHandle: false); - } - - public static void Tex_B(ShaderIrBlock block, long opCode, int position) - { - TextureInstructionSuffix suffix; - - int rawSuffix = opCode.Read(0x24, 0xe); - - switch (rawSuffix) - { - case 0: - suffix = TextureInstructionSuffix.None; - break; - case 0x2: - suffix = TextureInstructionSuffix.Lz; - break; - case 0x4: - suffix = TextureInstructionSuffix.Lb; - break; - case 0x6: - suffix = TextureInstructionSuffix.Ll; - break; - case 0xc: - suffix = TextureInstructionSuffix.Lba; - break; - case 0xe: - suffix = TextureInstructionSuffix.Lla; - break; - default: - throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {rawSuffix}"); - } - - bool isOffset = opCode.Read(0x23); - - if (isOffset) - suffix |= TextureInstructionSuffix.AOffI; - - EmitTex(block, opCode, suffix, gprHandle: true); - } - - private static void EmitTex(ShaderIrBlock block, long opCode, TextureInstructionSuffix textureInstructionSuffix, bool gprHandle) - { - bool isArray = opCode.HasArray(); - - GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray); - - bool hasDepthCompare = opCode.Read(0x32); - - if (hasDepthCompare) - { - textureInstructionSuffix |= TextureInstructionSuffix.Dc; - } - - ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; - - int indexExtraCoord = 0; - - if (isArray) - { - indexExtraCoord++; - - coords[coords.Length - 1] = opCode.Gpr8(); - } - - - for (int index = 0; index < coords.Length - indexExtraCoord; index++) - { - ShaderIrOperGpr coordReg = opCode.Gpr8(); - - coordReg.Index += index; - - coordReg.Index += indexExtraCoord; - - if (!coordReg.IsValidRegister) - { - coordReg.Index = ShaderIrOperGpr.ZrIndex; - } - - coords[index] = coordReg; - } - - int chMask = opCode.Read(31, 0xf); - - ShaderIrOperGpr levelOfDetail = null; - ShaderIrOperGpr offset = null; - ShaderIrOperGpr depthCompare = null; - - // TODO: determine first argument when TEX.B is used - int operBIndex = gprHandle ? 1 : 0; - - if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0 || - (textureInstructionSuffix & TextureInstructionSuffix.Lb) != 0 || - (textureInstructionSuffix & TextureInstructionSuffix.Lba) != 0 || - (textureInstructionSuffix & TextureInstructionSuffix.Lla) != 0) - { - levelOfDetail = opCode.Gpr20(); - levelOfDetail.Index += operBIndex; - - operBIndex++; - } - - if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) - { - offset = opCode.Gpr20(); - offset.Index += operBIndex; - - operBIndex++; - } - - if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) - { - depthCompare = opCode.Gpr20(); - depthCompare.Index += operBIndex; - - operBIndex++; - } - - // ??? - ShaderIrNode operC = gprHandle - ? (ShaderIrNode)opCode.Gpr20() - : (ShaderIrNode)opCode.Imm13_36(); - - ShaderIrInst inst = gprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs; - - coords = CoordsRegistersToTempRegisters(block, coords); - - int regInc = 0; - - for (int ch = 0; ch < 4; ch++) - { - if (!IsChannelUsed(chMask, ch)) - { - continue; - } - - ShaderIrOperGpr dst = opCode.Gpr0(); - - dst.Index += regInc++; - - if (!dst.IsValidRegister || dst.IsConst) - { - continue; - } - - ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) - { - LevelOfDetail = levelOfDetail, - Offset = offset, - DepthCompare = depthCompare - }; - - ShaderIrOp op = new ShaderIrOp(inst, coords[0], coords.Length > 1 ? coords[1] : null, operC, meta); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); - } - } - - public static void Texs(ShaderIrBlock block, long opCode, int position) - { - TextureInstructionSuffix suffix; - - int rawSuffix = opCode.Read(0x34, 0x1e); - - switch (rawSuffix) - { - case 0: - case 0x4: - case 0x10: - case 0x16: - suffix = TextureInstructionSuffix.Lz; - break; - case 0x6: - case 0x1a: - suffix = TextureInstructionSuffix.Ll; - break; - case 0x8: - suffix = TextureInstructionSuffix.Dc; - break; - case 0x2: - case 0xe: - case 0x14: - case 0x18: - suffix = TextureInstructionSuffix.None; - break; - case 0xa: - suffix = TextureInstructionSuffix.Ll | TextureInstructionSuffix.Dc; - break; - case 0xc: - case 0x12: - suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.Dc; - break; - default: - throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {rawSuffix}"); - } - - GalTextureTarget textureTarget = TexsToTextureTarget(opCode.Read(52, 0x1e)); - - EmitTexs(block, opCode, ShaderIrInst.Texs, textureTarget, suffix); - } - - public static void Tlds(ShaderIrBlock block, long opCode, int position) - { - TextureInstructionSuffix suffix; - - int rawSuffix = opCode.Read(0x34, 0x1e); - - switch (rawSuffix) - { - case 0: - case 0x4: - case 0x8: - suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.AOffI; - break; - case 0xc: - suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.Mz; - break; - case 0xe: - case 0x10: - suffix = TextureInstructionSuffix.Lz; - break; - case 0x2: - case 0xa: - suffix = TextureInstructionSuffix.Ll; - break; - case 0x18: - suffix = TextureInstructionSuffix.Ll | TextureInstructionSuffix.AOffI; - break; - default: - throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {rawSuffix}"); - } - - GalTextureTarget textureTarget = TldsToTextureTarget(opCode.Read(52, 0x1e)); - - EmitTexs(block, opCode, ShaderIrInst.Txlf, textureTarget, suffix); - } - - public static void Tld4(ShaderIrBlock block, long opCode, int position) - { - TextureInstructionSuffix suffix; - - int rawSuffix = opCode.Read(0x34, 0xc); - - switch (rawSuffix) - { - case 0: - suffix = TextureInstructionSuffix.None; - break; - case 0x4: - suffix = TextureInstructionSuffix.AOffI; - break; - case 0x8: - suffix = TextureInstructionSuffix.Ptp; - break; - default: - throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {rawSuffix}"); - } - - bool isShadow = opCode.Read(0x32); - - bool isArray = opCode.HasArray(); - int chMask = opCode.Read(31, 0xf); - - GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray); - - if (isShadow) - { - suffix |= TextureInstructionSuffix.Dc; - } - - EmitTld4(block, opCode, textureTarget, suffix, chMask, opCode.Read(0x38, 0x3), false); - } - - public static void Tld4S(ShaderIrBlock block, long opCode, int position) - { - TextureInstructionSuffix suffix = TextureInstructionSuffix.None; - - bool isOffset = opCode.Read(0x33); - bool isShadow = opCode.Read(0x32); - - if (isOffset) - { - suffix |= TextureInstructionSuffix.AOffI; - } - - if (isShadow) - { - suffix |= TextureInstructionSuffix.Dc; - } - - // TLD4S seems to only support 2D textures with RGBA mask? - EmitTld4(block, opCode, GalTextureTarget.TwoD, suffix, RGBA, opCode.Read(0x34, 0x3), true); - } - - private static void EmitTexs(ShaderIrBlock block, - long opCode, - ShaderIrInst inst, - GalTextureTarget textureTarget, - TextureInstructionSuffix textureInstructionSuffix) - { - if (inst == ShaderIrInst.Txlf && textureTarget == GalTextureTarget.CubeArray) - { - throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!"); - } - - bool isArray = ImageUtils.IsArray(textureTarget); - - ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)]; - - ShaderIrOperGpr operA = opCode.Gpr8(); - ShaderIrOperGpr operB = opCode.Gpr20(); - - ShaderIrOperGpr suffixExtra = opCode.Gpr20(); - suffixExtra.Index += 1; - - int coordStartIndex = 0; - - if (isArray) - { - coordStartIndex++; - coords[coords.Length - 1] = opCode.Gpr8(); - } - - switch (coords.Length - coordStartIndex) - { - case 1: - coords[0] = opCode.Gpr8(); - - break; - case 2: - coords[0] = opCode.Gpr8(); - coords[0].Index += coordStartIndex; - - break; - case 3: - coords[0] = opCode.Gpr8(); - coords[0].Index += coordStartIndex; - - coords[1] = opCode.Gpr8(); - coords[1].Index += 1 + coordStartIndex; - - break; - default: - throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TEXS"); - } - - int operBIndex = 0; - - ShaderIrOperGpr levelOfDetail = null; - ShaderIrOperGpr offset = null; - ShaderIrOperGpr depthCompare = null; - - // OperB is always the last value - // Not applicable to 1d textures - if (coords.Length - coordStartIndex != 1) - { - coords[coords.Length - coordStartIndex - 1] = operB; - operBIndex++; - } - - // Encoding of TEXS/TLDS is a bit special and change for 2d textures - // NOTE: OperA seems to hold at best two args. - // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB. - if (textureInstructionSuffix != TextureInstructionSuffix.None && textureInstructionSuffix != TextureInstructionSuffix.Lz && textureTarget == GalTextureTarget.TwoD) - { - coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); - coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; - operBIndex--; - } - - // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?) - if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0) - { - levelOfDetail = opCode.Gpr20(); - levelOfDetail.Index += operBIndex; - operBIndex++; - } - - if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) - { - offset = opCode.Gpr20(); - offset.Index += operBIndex; - operBIndex++; - } - - if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) - { - depthCompare = opCode.Gpr20(); - depthCompare.Index += operBIndex; - operBIndex++; - } - - int lutIndex; - - lutIndex = !opCode.Gpr0().IsConst ? 1 : 0; - lutIndex |= !opCode.Gpr28().IsConst ? 2 : 0; - - if (lutIndex == 0) - { - //Both destination registers are RZ, do nothing. - return; - } - - bool fp16 = !opCode.Read(59); - - int dstIncrement = 0; - - ShaderIrOperGpr GetDst() - { - ShaderIrOperGpr dst; - - if (fp16) - { - //FP16 mode, two components are packed on the two - //halfs of a 32-bits register, as two half-float values. - int halfPart = dstIncrement & 1; - - switch (lutIndex) - { - case 1: dst = opCode.GprHalf0(halfPart); break; - case 2: dst = opCode.GprHalf28(halfPart); break; - case 3: dst = (dstIncrement >> 1) != 0 - ? opCode.GprHalf28(halfPart) - : opCode.GprHalf0(halfPart); break; - - default: throw new InvalidOperationException(); - } - } - else - { - //32-bits mode, each component uses one register. - //Two components uses two consecutive registers. - switch (lutIndex) - { - case 1: dst = opCode.Gpr0(); break; - case 2: dst = opCode.Gpr28(); break; - case 3: dst = (dstIncrement >> 1) != 0 - ? opCode.Gpr28() - : opCode.Gpr0(); break; - - default: throw new InvalidOperationException(); - } - - dst.Index += dstIncrement & 1; - } - - dstIncrement++; - - return dst; - } - - int chMask = _maskLut[lutIndex, opCode.Read(50, 7)]; - - if (chMask == 0) - { - //All channels are disabled, do nothing. - return; - } - - ShaderIrNode operC = opCode.Imm13_36(); - coords = CoordsRegistersToTempRegisters(block, coords); - - for (int ch = 0; ch < 4; ch++) - { - if (!IsChannelUsed(chMask, ch)) - { - continue; - } - - ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords) - { - LevelOfDetail = levelOfDetail, - Offset = offset, - DepthCompare = depthCompare - }; - ShaderIrOp op = new ShaderIrOp(inst, operA, operB, operC, meta); - - ShaderIrOperGpr dst = GetDst(); - - if (dst.IsValidRegister && !dst.IsConst) - { - block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); - } - } - } - - private static void EmitTld4(ShaderIrBlock block, long opCode, GalTextureTarget textureType, TextureInstructionSuffix textureInstructionSuffix, int chMask, int component, bool scalar) - { - ShaderIrOperGpr operA = opCode.Gpr8(); - ShaderIrOperGpr operB = opCode.Gpr20(); - ShaderIrOperImm operC = opCode.Imm13_36(); - - ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureType)]; - - ShaderIrOperGpr offset = null; - ShaderIrOperGpr depthCompare = null; - - bool isArray = ImageUtils.IsArray(textureType); - - int operBIndex = 0; - - if (scalar) - { - int coordStartIndex = 0; - - if (isArray) - { - coordStartIndex++; - coords[coords.Length - 1] = operB; - } - - switch (coords.Length - coordStartIndex) - { - case 1: - coords[0] = opCode.Gpr8(); - - break; - case 2: - coords[0] = opCode.Gpr8(); - coords[0].Index += coordStartIndex; - - break; - case 3: - coords[0] = opCode.Gpr8(); - coords[0].Index += coordStartIndex; - - coords[1] = opCode.Gpr8(); - coords[1].Index += 1 + coordStartIndex; - - break; - default: - throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TLD4S"); - } - - if (coords.Length - coordStartIndex != 1) - { - coords[coords.Length - coordStartIndex - 1] = operB; - operBIndex++; - } - - if (textureInstructionSuffix != TextureInstructionSuffix.None && textureType == GalTextureTarget.TwoD) - { - coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8(); - coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1; - operBIndex--; - } - } - else - { - int indexExtraCoord = 0; - - if (isArray) - { - indexExtraCoord++; - - coords[coords.Length - 1] = opCode.Gpr8(); - } - - for (int index = 0; index < coords.Length - indexExtraCoord; index++) - { - coords[index] = opCode.Gpr8(); - - coords[index].Index += index; - - coords[index].Index += indexExtraCoord; - - if (coords[index].Index > ShaderIrOperGpr.ZrIndex) - { - coords[index].Index = ShaderIrOperGpr.ZrIndex; - } - } - } - - if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0) - { - offset = opCode.Gpr20(); - offset.Index += operBIndex; - operBIndex++; - } - - if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0) - { - depthCompare = opCode.Gpr20(); - depthCompare.Index += operBIndex; - operBIndex++; - } - - coords = CoordsRegistersToTempRegisters(block, coords); - - int regInc = 0; - - for (int ch = 0; ch < 4; ch++) - { - if (!IsChannelUsed(chMask, ch)) - { - continue; - } - - ShaderIrOperGpr dst = opCode.Gpr0(); - - dst.Index += regInc++; - - if (!dst.IsValidRegister || dst.IsConst) - { - continue; - } - - ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureType, textureInstructionSuffix, coords) - { - Component = component, - Offset = offset, - DepthCompare = depthCompare - }; - - ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Tld4, operA, operB, operC, meta); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op))); - } - } - - private static bool IsChannelUsed(int chMask, int ch) - { - return (chMask & (1 << ch)) != 0; - } - - private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock block, params ShaderIrOperGpr[] registers) - { - ShaderIrOperGpr[] res = new ShaderIrOperGpr[registers.Length]; - - for (int index = 0; index < res.Length; index++) - { - res[index] = ShaderIrOperGpr.MakeTemporary(index); - block.AddNode(new ShaderIrAsg(res[index], registers[index])); - } - - return res; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs deleted file mode 100644 index 0a2b4232bb..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs +++ /dev/null @@ -1,431 +0,0 @@ -using System; - -using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper; - -namespace Ryujinx.Graphics.Gal.Shader -{ - static partial class ShaderDecode - { - private enum IntType - { - U8 = 0, - U16 = 1, - U32 = 2, - U64 = 3, - S8 = 4, - S16 = 5, - S32 = 6, - S64 = 7 - } - - private enum FloatType - { - F16 = 1, - F32 = 2, - F64 = 3 - } - - public static void F2f_C(ShaderIrBlock block, long opCode, int position) - { - EmitF2F(block, opCode, ShaderOper.Cr); - } - - public static void F2f_I(ShaderIrBlock block, long opCode, int position) - { - EmitF2F(block, opCode, ShaderOper.Immf); - } - - public static void F2f_R(ShaderIrBlock block, long opCode, int position) - { - EmitF2F(block, opCode, ShaderOper.Rr); - } - - public static void F2i_C(ShaderIrBlock block, long opCode, int position) - { - EmitF2I(block, opCode, ShaderOper.Cr); - } - - public static void F2i_I(ShaderIrBlock block, long opCode, int position) - { - EmitF2I(block, opCode, ShaderOper.Immf); - } - - public static void F2i_R(ShaderIrBlock block, long opCode, int position) - { - EmitF2I(block, opCode, ShaderOper.Rr); - } - - public static void I2f_C(ShaderIrBlock block, long opCode, int position) - { - EmitI2F(block, opCode, ShaderOper.Cr); - } - - public static void I2f_I(ShaderIrBlock block, long opCode, int position) - { - EmitI2F(block, opCode, ShaderOper.Imm); - } - - public static void I2f_R(ShaderIrBlock block, long opCode, int position) - { - EmitI2F(block, opCode, ShaderOper.Rr); - } - - public static void I2i_C(ShaderIrBlock block, long opCode, int position) - { - EmitI2I(block, opCode, ShaderOper.Cr); - } - - public static void I2i_I(ShaderIrBlock block, long opCode, int position) - { - EmitI2I(block, opCode, ShaderOper.Imm); - } - - public static void I2i_R(ShaderIrBlock block, long opCode, int position) - { - EmitI2I(block, opCode, ShaderOper.Rr); - } - - public static void Isberd(ShaderIrBlock block, long opCode, int position) - { - //This instruction seems to be used to translate from an address to a vertex index in a GS - //Stub it as such - - block.AddNode(new ShaderIrCmnt("Stubbed.")); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), opCode.Gpr8()))); - } - - public static void Mov_C(ShaderIrBlock block, long opCode, int position) - { - ShaderIrOperCbuf cbuf = opCode.Cbuf34(); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), cbuf))); - } - - public static void Mov_I(ShaderIrBlock block, long opCode, int position) - { - ShaderIrOperImm imm = opCode.Imm19_20(); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm))); - } - - public static void Mov_I32(ShaderIrBlock block, long opCode, int position) - { - ShaderIrOperImm imm = opCode.Imm32_20(); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm))); - } - - public static void Mov_R(ShaderIrBlock block, long opCode, int position) - { - ShaderIrOperGpr gpr = opCode.Gpr20(); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), gpr))); - } - - public static void Sel_C(ShaderIrBlock block, long opCode, int position) - { - EmitSel(block, opCode, ShaderOper.Cr); - } - - public static void Sel_I(ShaderIrBlock block, long opCode, int position) - { - EmitSel(block, opCode, ShaderOper.Imm); - } - - public static void Sel_R(ShaderIrBlock block, long opCode, int position) - { - EmitSel(block, opCode, ShaderOper.Rr); - } - - public static void Mov_S(ShaderIrBlock block, long opCode, int position) - { - block.AddNode(new ShaderIrCmnt("Stubbed.")); - - //Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS - ShaderIrNode source = new ShaderIrOperImm(0); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), source))); - } - - private static void EmitF2F(ShaderIrBlock block, long opCode, ShaderOper oper) - { - bool negA = opCode.Read(45); - bool absA = opCode.Read(49); - - ShaderIrNode operA; - - switch (oper) - { - case ShaderOper.Cr: operA = opCode.Cbuf34(); break; - case ShaderOper.Immf: operA = opCode.Immf19_20(); break; - case ShaderOper.Rr: operA = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operA = GetAluFabsFneg(operA, absA, negA); - - ShaderIrInst roundInst = GetRoundInst(opCode); - - if (roundInst != ShaderIrInst.Invalid) - { - operA = new ShaderIrOp(roundInst, operA); - } - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA))); - } - - private static void EmitF2I(ShaderIrBlock block, long opCode, ShaderOper oper) - { - IntType type = GetIntType(opCode); - - if (type == IntType.U64 || - type == IntType.S64) - { - //TODO: 64-bits support. - //Note: GLSL doesn't support 64-bits integers. - throw new NotImplementedException(); - } - - bool negA = opCode.Read(45); - bool absA = opCode.Read(49); - - ShaderIrNode operA; - - switch (oper) - { - case ShaderOper.Cr: operA = opCode.Cbuf34(); break; - case ShaderOper.Immf: operA = opCode.Immf19_20(); break; - case ShaderOper.Rr: operA = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operA = GetAluFabsFneg(operA, absA, negA); - - ShaderIrInst roundInst = GetRoundInst(opCode); - - if (roundInst != ShaderIrInst.Invalid) - { - operA = new ShaderIrOp(roundInst, operA); - } - - bool signed = type >= IntType.S8; - - int size = 8 << ((int)type & 3); - - if (size < 32) - { - uint mask = uint.MaxValue >> (32 - size); - - float cMin = 0; - float cMax = mask; - - if (signed) - { - uint halfMask = mask >> 1; - - cMin -= halfMask + 1; - cMax = halfMask; - } - - ShaderIrOperImmf min = new ShaderIrOperImmf(cMin); - ShaderIrOperImmf max = new ShaderIrOperImmf(cMax); - - operA = new ShaderIrOp(ShaderIrInst.Fclamp, operA, min, max); - } - - ShaderIrInst inst = signed - ? ShaderIrInst.Ftos - : ShaderIrInst.Ftou; - - ShaderIrNode op = new ShaderIrOp(inst, operA); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - private static void EmitI2F(ShaderIrBlock block, long opCode, ShaderOper oper) - { - IntType type = GetIntType(opCode); - - if (type == IntType.U64 || - type == IntType.S64) - { - //TODO: 64-bits support. - //Note: GLSL doesn't support 64-bits integers. - throw new NotImplementedException(); - } - - int sel = opCode.Read(41, 3); - - bool negA = opCode.Read(45); - bool absA = opCode.Read(49); - - ShaderIrNode operA; - - switch (oper) - { - case ShaderOper.Cr: operA = opCode.Cbuf34(); break; - case ShaderOper.Imm: operA = opCode.Imm19_20(); break; - case ShaderOper.Rr: operA = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operA = GetAluIabsIneg(operA, absA, negA); - - bool signed = type >= IntType.S8; - - int shift = sel * 8; - - int size = 8 << ((int)type & 3); - - if (shift != 0) - { - operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift)); - } - - if (size < 32) - { - operA = ExtendTo32(operA, signed, size); - } - - ShaderIrInst inst = signed - ? ShaderIrInst.Stof - : ShaderIrInst.Utof; - - ShaderIrNode op = new ShaderIrOp(inst, operA); - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op))); - } - - private static void EmitI2I(ShaderIrBlock block, long opCode, ShaderOper oper) - { - IntType type = GetIntType(opCode); - - if (type == IntType.U64 || - type == IntType.S64) - { - //TODO: 64-bits support. - //Note: GLSL doesn't support 64-bits integers. - throw new NotImplementedException(); - } - - int sel = opCode.Read(41, 3); - - bool negA = opCode.Read(45); - bool absA = opCode.Read(49); - bool satA = opCode.Read(50); - - ShaderIrNode operA; - - switch (oper) - { - case ShaderOper.Cr: operA = opCode.Cbuf34(); break; - case ShaderOper.Immf: operA = opCode.Immf19_20(); break; - case ShaderOper.Rr: operA = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - operA = GetAluIabsIneg(operA, absA, negA); - - bool signed = type >= IntType.S8; - - int shift = sel * 8; - - int size = 8 << ((int)type & 3); - - if (shift != 0) - { - operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift)); - } - - if (size < 32) - { - uint mask = uint.MaxValue >> (32 - size); - - if (satA) - { - uint cMin = 0; - uint cMax = mask; - - if (signed) - { - uint halfMask = mask >> 1; - - cMin -= halfMask + 1; - cMax = halfMask; - } - - ShaderIrOperImm min = new ShaderIrOperImm((int)cMin); - ShaderIrOperImm max = new ShaderIrOperImm((int)cMax); - - operA = new ShaderIrOp(signed - ? ShaderIrInst.Clamps - : ShaderIrInst.Clampu, operA, min, max); - } - else - { - operA = ExtendTo32(operA, signed, size); - } - } - - block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA))); - } - - private static void EmitSel(ShaderIrBlock block, long opCode, ShaderOper oper) - { - ShaderIrOperGpr dst = opCode.Gpr0(); - ShaderIrNode pred = opCode.Pred39N(); - - ShaderIrNode resultA = opCode.Gpr8(); - ShaderIrNode resultB; - - switch (oper) - { - case ShaderOper.Cr: resultB = opCode.Cbuf34(); break; - case ShaderOper.Imm: resultB = opCode.Imm19_20(); break; - case ShaderOper.Rr: resultB = opCode.Gpr20(); break; - - default: throw new ArgumentException(nameof(oper)); - } - - block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultA), false))); - - block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultB), true))); - } - - private static IntType GetIntType(long opCode) - { - bool signed = opCode.Read(13); - - IntType type = (IntType)(opCode.Read(10, 3)); - - if (signed) - { - type += (int)IntType.S8; - } - - return type; - } - - private static FloatType GetFloatType(long opCode) - { - return (FloatType)(opCode.Read(8, 3)); - } - - private static ShaderIrInst GetRoundInst(long opCode) - { - switch (opCode.Read(39, 3)) - { - case 1: return ShaderIrInst.Floor; - case 2: return ShaderIrInst.Ceil; - case 3: return ShaderIrInst.Trunc; - } - - return ShaderIrInst.Invalid; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs deleted file mode 100644 index 4b1e404692..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs +++ /dev/null @@ -1,313 +0,0 @@ -using System; - -namespace Ryujinx.Graphics.Gal.Shader -{ - static partial class ShaderDecode - { - private static int Read(this long opCode, int position, int mask) - { - return (int)(opCode >> position) & mask; - } - - private static bool Read(this long opCode, int position) - { - return ((opCode >> position) & 1) != 0; - } - - private static int Branch(this long opCode) - { - return ((int)(opCode >> 20) << 8) >> 8; - } - - private static bool HasArray(this long opCode) - { - return opCode.Read(0x1c); - } - - private static ShaderIrOperAbuf[] Abuf20(this long opCode) - { - int abuf = opCode.Read(20, 0x3ff); - int size = opCode.Read(47, 3); - - ShaderIrOperGpr vertex = opCode.Gpr39(); - - ShaderIrOperAbuf[] opers = new ShaderIrOperAbuf[size + 1]; - - for (int index = 0; index <= size; index++) - { - opers[index] = new ShaderIrOperAbuf(abuf + index * 4, vertex); - } - - return opers; - } - - private static ShaderIrOperAbuf Abuf28(this long opCode) - { - int abuf = opCode.Read(28, 0x3ff); - - return new ShaderIrOperAbuf(abuf, opCode.Gpr39()); - } - - private static ShaderIrOperCbuf Cbuf34(this long opCode) - { - return new ShaderIrOperCbuf( - opCode.Read(34, 0x1f), - opCode.Read(20, 0x3fff)); - } - - private static ShaderIrOperGpr Gpr8(this long opCode) - { - return new ShaderIrOperGpr(opCode.Read(8, 0xff)); - } - - private static ShaderIrOperGpr Gpr20(this long opCode) - { - return new ShaderIrOperGpr(opCode.Read(20, 0xff)); - } - - private static ShaderIrOperGpr Gpr39(this long opCode) - { - return new ShaderIrOperGpr(opCode.Read(39, 0xff)); - } - - private static ShaderIrOperGpr Gpr0(this long opCode) - { - return new ShaderIrOperGpr(opCode.Read(0, 0xff)); - } - - private static ShaderIrOperGpr Gpr28(this long opCode) - { - return new ShaderIrOperGpr(opCode.Read(28, 0xff)); - } - - private static ShaderIrOperGpr[] GprHalfVec8(this long opCode) - { - return GetGprHalfVec2(opCode.Read(8, 0xff), opCode.Read(47, 3)); - } - - private static ShaderIrOperGpr[] GprHalfVec20(this long opCode) - { - return GetGprHalfVec2(opCode.Read(20, 0xff), opCode.Read(28, 3)); - } - - private static ShaderIrOperGpr[] GetGprHalfVec2(int gpr, int mask) - { - if (mask == 1) - { - //This value is used for FP32, the whole 32-bits register - //is used as each element on the vector. - return new ShaderIrOperGpr[] - { - new ShaderIrOperGpr(gpr), - new ShaderIrOperGpr(gpr) - }; - } - - ShaderIrOperGpr low = new ShaderIrOperGpr(gpr, 0); - ShaderIrOperGpr high = new ShaderIrOperGpr(gpr, 1); - - return new ShaderIrOperGpr[] - { - (mask & 1) != 0 ? high : low, - (mask & 2) != 0 ? high : low - }; - } - - private static ShaderIrOperGpr GprHalf0(this long opCode, int halfPart) - { - return new ShaderIrOperGpr(opCode.Read(0, 0xff), halfPart); - } - - private static ShaderIrOperGpr GprHalf28(this long opCode, int halfPart) - { - return new ShaderIrOperGpr(opCode.Read(28, 0xff), halfPart); - } - - private static ShaderIrOperImm Imm5_39(this long opCode) - { - return new ShaderIrOperImm(opCode.Read(39, 0x1f)); - } - - private static ShaderIrOperImm Imm13_36(this long opCode) - { - return new ShaderIrOperImm(opCode.Read(36, 0x1fff)); - } - - private static ShaderIrOperImm Imm32_20(this long opCode) - { - return new ShaderIrOperImm((int)(opCode >> 20)); - } - - private static ShaderIrOperImmf Immf32_20(this long opCode) - { - return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(opCode >> 20))); - } - - private static ShaderIrOperImm ImmU16_20(this long opCode) - { - return new ShaderIrOperImm(opCode.Read(20, 0xffff)); - } - - private static ShaderIrOperImm Imm19_20(this long opCode) - { - int value = opCode.Read(20, 0x7ffff); - - bool neg = opCode.Read(56); - - if (neg) - { - value = -value; - } - - return new ShaderIrOperImm(value); - } - - private static ShaderIrOperImmf Immf19_20(this long opCode) - { - uint imm = (uint)(opCode >> 20) & 0x7ffff; - - bool neg = opCode.Read(56); - - imm <<= 12; - - if (neg) - { - imm |= 0x80000000; - } - - float value = BitConverter.Int32BitsToSingle((int)imm); - - return new ShaderIrOperImmf(value); - } - - private static ShaderIrOperPred Pred0(this long opCode) - { - return new ShaderIrOperPred(opCode.Read(0, 7)); - } - - private static ShaderIrOperPred Pred3(this long opCode) - { - return new ShaderIrOperPred(opCode.Read(3, 7)); - } - - private static ShaderIrOperPred Pred12(this long opCode) - { - return new ShaderIrOperPred(opCode.Read(12, 7)); - } - - private static ShaderIrOperPred Pred29(this long opCode) - { - return new ShaderIrOperPred(opCode.Read(29, 7)); - } - - private static ShaderIrNode Pred39N(this long opCode) - { - ShaderIrNode node = opCode.Pred39(); - - if (opCode.Read(42)) - { - node = new ShaderIrOp(ShaderIrInst.Bnot, node); - } - - return node; - } - - private static ShaderIrOperPred Pred39(this long opCode) - { - return new ShaderIrOperPred(opCode.Read(39, 7)); - } - - private static ShaderIrOperPred Pred48(this long opCode) - { - return new ShaderIrOperPred(opCode.Read(48, 7)); - } - - private static ShaderIrInst Cmp(this long opCode) - { - switch (opCode.Read(49, 7)) - { - case 1: return ShaderIrInst.Clt; - case 2: return ShaderIrInst.Ceq; - case 3: return ShaderIrInst.Cle; - case 4: return ShaderIrInst.Cgt; - case 5: return ShaderIrInst.Cne; - case 6: return ShaderIrInst.Cge; - } - - throw new ArgumentException(nameof(opCode)); - } - - private static ShaderIrInst CmpF(this long opCode) - { - switch (opCode.Read(48, 0xf)) - { - case 0x1: return ShaderIrInst.Fclt; - case 0x2: return ShaderIrInst.Fceq; - case 0x3: return ShaderIrInst.Fcle; - case 0x4: return ShaderIrInst.Fcgt; - case 0x5: return ShaderIrInst.Fcne; - case 0x6: return ShaderIrInst.Fcge; - case 0x7: return ShaderIrInst.Fcnum; - case 0x8: return ShaderIrInst.Fcnan; - case 0x9: return ShaderIrInst.Fcltu; - case 0xa: return ShaderIrInst.Fcequ; - case 0xb: return ShaderIrInst.Fcleu; - case 0xc: return ShaderIrInst.Fcgtu; - case 0xd: return ShaderIrInst.Fcneu; - case 0xe: return ShaderIrInst.Fcgeu; - } - - throw new ArgumentException(nameof(opCode)); - } - - private static ShaderIrInst BLop45(this long opCode) - { - switch (opCode.Read(45, 3)) - { - case 0: return ShaderIrInst.Band; - case 1: return ShaderIrInst.Bor; - case 2: return ShaderIrInst.Bxor; - } - - throw new ArgumentException(nameof(opCode)); - } - - private static ShaderIrInst BLop24(this long opCode) - { - switch (opCode.Read(24, 3)) - { - case 0: return ShaderIrInst.Band; - case 1: return ShaderIrInst.Bor; - case 2: return ShaderIrInst.Bxor; - } - - throw new ArgumentException(nameof(opCode)); - } - - private static ShaderIrNode PredNode(this long opCode, ShaderIrNode node) - { - ShaderIrOperPred pred = opCode.PredNode(); - - if (pred.Index != ShaderIrOperPred.UnusedIndex) - { - bool inv = opCode.Read(19); - - node = new ShaderIrCond(pred, node, inv); - } - - return node; - } - - private static ShaderIrOperPred PredNode(this long opCode) - { - int pred = opCode.Read(16, 0xf); - - if (pred != 0xf) - { - pred &= 7; - } - - return new ShaderIrOperPred(pred); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs deleted file mode 100644 index 9098ca5e55..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - static partial class ShaderDecode - { - public static void Out_R(ShaderIrBlock block, long opCode, int position) - { - //TODO: Those registers have to be used for something - ShaderIrOperGpr gpr0 = opCode.Gpr0(); - ShaderIrOperGpr gpr8 = opCode.Gpr8(); - ShaderIrOperGpr gpr20 = opCode.Gpr20(); - - int type = opCode.Read(39, 3); - - if ((type & 1) != 0) - { - block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Emit))); - } - - if ((type & 2) != 0) - { - block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Cut))); - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs deleted file mode 100644 index 4b23f8d0fa..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs +++ /dev/null @@ -1,218 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gal.Shader -{ - static class ShaderDecoder - { - private const long HeaderSize = 0x50; - - private const bool AddDbgComments = true; - - public static ShaderIrBlock[] Decode(IGalMemory memory, long start) - { - Dictionary visited = new Dictionary(); - Dictionary visitedEnd = new Dictionary(); - - Queue blocks = new Queue(); - - long beginning = start + HeaderSize; - - ShaderIrBlock Enqueue(int position, ShaderIrBlock source = null) - { - if (!visited.TryGetValue(position, out ShaderIrBlock output)) - { - output = new ShaderIrBlock(position); - - blocks.Enqueue(output); - - visited.Add(position, output); - } - - if (source != null) - { - output.Sources.Add(source); - } - - return output; - } - - ShaderIrBlock entry = Enqueue(0); - - while (blocks.Count > 0) - { - ShaderIrBlock current = blocks.Dequeue(); - - FillBlock(memory, current, beginning); - - //Set child blocks. "Branch" is the block the branch instruction - //points to (when taken), "Next" is the block at the next address, - //executed when the branch is not taken. For Unconditional Branches - //or end of shader, Next is null. - if (current.Nodes.Count > 0) - { - ShaderIrNode lastNode = current.GetLastNode(); - - ShaderIrOp innerOp = GetInnermostOp(lastNode); - - if (innerOp?.Inst == ShaderIrInst.Bra) - { - int target = ((ShaderIrOperImm)innerOp.OperandA).Value; - - current.Branch = Enqueue(target, current); - } - - foreach (ShaderIrNode node in current.Nodes) - { - innerOp = GetInnermostOp(node); - - if (innerOp is ShaderIrOp currOp && currOp.Inst == ShaderIrInst.Ssy) - { - int target = ((ShaderIrOperImm)currOp.OperandA).Value; - - Enqueue(target, current); - } - } - - if (NodeHasNext(lastNode)) - { - current.Next = Enqueue(current.EndPosition); - } - } - - //If we have on the graph two blocks with the same end position, - //then we need to split the bigger block and have two small blocks, - //the end position of the bigger "Current" block should then be == to - //the position of the "Smaller" block. - while (visitedEnd.TryGetValue(current.EndPosition, out ShaderIrBlock smaller)) - { - if (current.Position > smaller.Position) - { - ShaderIrBlock temp = smaller; - - smaller = current; - current = temp; - } - - current.EndPosition = smaller.Position; - current.Next = smaller; - current.Branch = null; - - current.Nodes.RemoveRange( - current.Nodes.Count - smaller.Nodes.Count, - smaller.Nodes.Count); - - visitedEnd[smaller.EndPosition] = smaller; - } - - visitedEnd.Add(current.EndPosition, current); - } - - //Make and sort Graph blocks array by position. - ShaderIrBlock[] graph = new ShaderIrBlock[visited.Count]; - - while (visited.Count > 0) - { - uint firstPos = uint.MaxValue; - - foreach (ShaderIrBlock block in visited.Values) - { - if (firstPos > (uint)block.Position) - firstPos = (uint)block.Position; - } - - ShaderIrBlock current = visited[(int)firstPos]; - - do - { - graph[graph.Length - visited.Count] = current; - - visited.Remove(current.Position); - - current = current.Next; - } - while (current != null); - } - - return graph; - } - - private static void FillBlock(IGalMemory memory, ShaderIrBlock block, long beginning) - { - int position = block.Position; - - do - { - //Ignore scheduling instructions, which are written every 32 bytes. - if ((position & 0x1f) == 0) - { - position += 8; - - continue; - } - - uint word0 = (uint)memory.ReadInt32(position + beginning + 0); - uint word1 = (uint)memory.ReadInt32(position + beginning + 4); - - position += 8; - - long opCode = word0 | (long)word1 << 32; - - ShaderDecodeFunc decode = ShaderOpCodeTable.GetDecoder(opCode); - - if (AddDbgComments) - { - string dbgOpCode = $"0x{(position - 8):x16}: 0x{opCode:x16} "; - - dbgOpCode += (decode?.Method.Name ?? "???"); - - if (decode == ShaderDecode.Bra || decode == ShaderDecode.Ssy) - { - int offset = ((int)(opCode >> 20) << 8) >> 8; - - long target = position + offset; - - dbgOpCode += " (0x" + target.ToString("x16") + ")"; - } - - block.AddNode(new ShaderIrCmnt(dbgOpCode)); - } - - if (decode == null) - { - continue; - } - - decode(block, opCode, position); - } - while (!IsFlowChange(block.GetLastNode())); - - block.EndPosition = position; - } - - private static bool IsFlowChange(ShaderIrNode node) - { - return !NodeHasNext(GetInnermostOp(node)); - } - - private static ShaderIrOp GetInnermostOp(ShaderIrNode node) - { - if (node is ShaderIrCond cond) - { - node = cond.Child; - } - - return node is ShaderIrOp op ? op : null; - } - - private static bool NodeHasNext(ShaderIrNode node) - { - if (!(node is ShaderIrOp op)) - { - return true; - } - - return op.Inst != ShaderIrInst.Exit && - op.Inst != ShaderIrInst.Bra; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs deleted file mode 100644 index 2f9326e121..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; - -namespace Ryujinx.Graphics.Gal.Shader -{ - struct OmapTarget - { - public bool Red; - public bool Green; - public bool Blue; - public bool Alpha; - - public bool Enabled => Red || Green || Blue || Alpha; - - public bool ComponentEnabled(int component) - { - switch (component) - { - case 0: return Red; - case 1: return Green; - case 2: return Blue; - case 3: return Alpha; - } - - throw new ArgumentException(nameof(component)); - } - } - - class ShaderHeader - { - public const int PointList = 1; - public const int LineStrip = 6; - public const int TriangleStrip = 7; - - public int SphType { get; private set; } - public int Version { get; private set; } - public int ShaderType { get; private set; } - public bool MrtEnable { get; private set; } - public bool KillsPixels { get; private set; } - public bool DoesGlobalStore { get; private set; } - public int SassVersion { get; private set; } - public bool DoesLoadOrStore { get; private set; } - public bool DoesFp64 { get; private set; } - public int StreamOutMask { get; private set; } - - public int ShaderLocalMemoryLowSize { get; private set; } - public int PerPatchAttributeCount { get; private set; } - - public int ShaderLocalMemoryHighSize { get; private set; } - public int ThreadsPerInputPrimitive { get; private set; } - - public int ShaderLocalMemoryCrsSize { get; private set; } - public int OutputTopology { get; private set; } - - public int MaxOutputVertexCount { get; private set; } - public int StoreReqStart { get; private set; } - public int StoreReqEnd { get; private set; } - - public OmapTarget[] OmapTargets { get; private set; } - public bool OmapSampleMask { get; private set; } - public bool OmapDepth { get; private set; } - - public ShaderHeader(IGalMemory memory, long position) - { - uint commonWord0 = (uint)memory.ReadInt32(position + 0); - uint commonWord1 = (uint)memory.ReadInt32(position + 4); - uint commonWord2 = (uint)memory.ReadInt32(position + 8); - uint commonWord3 = (uint)memory.ReadInt32(position + 12); - uint commonWord4 = (uint)memory.ReadInt32(position + 16); - - SphType = ReadBits(commonWord0, 0, 5); - Version = ReadBits(commonWord0, 5, 5); - ShaderType = ReadBits(commonWord0, 10, 4); - MrtEnable = ReadBits(commonWord0, 14, 1) != 0; - KillsPixels = ReadBits(commonWord0, 15, 1) != 0; - DoesGlobalStore = ReadBits(commonWord0, 16, 1) != 0; - SassVersion = ReadBits(commonWord0, 17, 4); - DoesLoadOrStore = ReadBits(commonWord0, 26, 1) != 0; - DoesFp64 = ReadBits(commonWord0, 27, 1) != 0; - StreamOutMask = ReadBits(commonWord0, 28, 4); - - ShaderLocalMemoryLowSize = ReadBits(commonWord1, 0, 24); - PerPatchAttributeCount = ReadBits(commonWord1, 24, 8); - - ShaderLocalMemoryHighSize = ReadBits(commonWord2, 0, 24); - ThreadsPerInputPrimitive = ReadBits(commonWord2, 24, 8); - - ShaderLocalMemoryCrsSize = ReadBits(commonWord3, 0, 24); - OutputTopology = ReadBits(commonWord3, 24, 4); - - MaxOutputVertexCount = ReadBits(commonWord4, 0, 12); - StoreReqStart = ReadBits(commonWord4, 12, 8); - StoreReqEnd = ReadBits(commonWord4, 24, 8); - - //Type 2 (fragment?) reading - uint type2OmapTarget = (uint)memory.ReadInt32(position + 72); - uint type2Omap = (uint)memory.ReadInt32(position + 76); - - OmapTargets = new OmapTarget[8]; - - for (int i = 0; i < OmapTargets.Length; i++) - { - int offset = i * 4; - - OmapTargets[i] = new OmapTarget - { - Red = ReadBits(type2OmapTarget, offset + 0, 1) != 0, - Green = ReadBits(type2OmapTarget, offset + 1, 1) != 0, - Blue = ReadBits(type2OmapTarget, offset + 2, 1) != 0, - Alpha = ReadBits(type2OmapTarget, offset + 3, 1) != 0 - }; - } - - OmapSampleMask = ReadBits(type2Omap, 0, 1) != 0; - OmapDepth = ReadBits(type2Omap, 1, 1) != 0; - } - - public int DepthRegister - { - get - { - int count = 0; - - for (int index = 0; index < OmapTargets.Length; index++) - { - for (int component = 0; component < 4; component++) - { - if (OmapTargets[index].ComponentEnabled(component)) - { - count++; - } - } - } - - // Depth register is always two registers after the last color output - return count + 1; - } - } - - private static int ReadBits(uint word, int offset, int bitWidth) - { - uint mask = (1u << bitWidth) - 1u; - - return (int)((word >> offset) & mask); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs deleted file mode 100644 index b3713fa483..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - enum ShaderIpaMode - { - Pass = 0, - None = 1, - Constant = 2, - Sc = 3 - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs deleted file mode 100644 index 53871a1451..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrAsg : ShaderIrNode - { - public ShaderIrNode Dst { get; set; } - public ShaderIrNode Src { get; set; } - - public ShaderIrAsg(ShaderIrNode dst, ShaderIrNode src) - { - Dst = dst; - Src = src; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs deleted file mode 100644 index 49257d2834..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections.Generic; - -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrBlock - { - public int Position { get; set; } - public int EndPosition { get; set; } - - public ShaderIrBlock Next { get; set; } - public ShaderIrBlock Branch { get; set; } - - public List Sources { get; private set; } - - public List Nodes { get; private set; } - - public ShaderIrBlock(int position) - { - Position = position; - - Sources = new List(); - - Nodes = new List(); - } - - public void AddNode(ShaderIrNode node) - { - Nodes.Add(node); - } - - public ShaderIrNode[] GetNodes() - { - return Nodes.ToArray(); - } - - public ShaderIrNode GetLastNode() - { - if (Nodes.Count > 0) - { - return Nodes[Nodes.Count - 1]; - } - - return null; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs deleted file mode 100644 index 5da04e5ee2..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrCmnt : ShaderIrNode - { - public string Comment { get; private set; } - - public ShaderIrCmnt(string comment) - { - Comment = comment; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs deleted file mode 100644 index 34acf90d7e..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrCond : ShaderIrNode - { - public ShaderIrNode Pred { get; set; } - public ShaderIrNode Child { get; set; } - - public bool Not { get; private set; } - - public ShaderIrCond(ShaderIrNode pred, ShaderIrNode child, bool not) - { - Pred = pred; - Child = child; - Not = not; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs deleted file mode 100644 index 68ff214e4e..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs +++ /dev/null @@ -1,94 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - enum ShaderIrInst - { - Invalid, - - B_Start, - Band, - Bnot, - Bor, - Bxor, - B_End, - - F_Start, - Ceil, - - Fabs, - Fadd, - Fceq, - Fcequ, - Fcge, - Fcgeu, - Fcgt, - Fcgtu, - Fclamp, - Fcle, - Fcleu, - Fclt, - Fcltu, - Fcnan, - Fcne, - Fcneu, - Fcnum, - Fcos, - Fex2, - Ffma, - Flg2, - Floor, - Fmax, - Fmin, - Fmul, - Fneg, - Frcp, - Frsq, - Fsin, - Fsqrt, - Ftos, - Ftou, - Ipa, - Texb, - Texs, - Tld4, - Trunc, - F_End, - - I_Start, - Abs, - Add, - And, - Asr, - Ceq, - Cge, - Cgt, - Clamps, - Clampu, - Cle, - Clt, - Cne, - Lsl, - Lsr, - Max, - Min, - Mul, - Neg, - Not, - Or, - Stof, - Sub, - Texq, - Txlf, - Utof, - Xor, - I_End, - - Bra, - Exit, - Kil, - Ssy, - Sync, - - Emit, - Cut - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs deleted file mode 100644 index afb7503be8..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrMeta { } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs deleted file mode 100644 index 07db646757..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrMetaIpa : ShaderIrMeta - { - public ShaderIpaMode Mode { get; private set; } - - public ShaderIrMetaIpa(ShaderIpaMode mode) - { - Mode = mode; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs deleted file mode 100644 index e0265138c8..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Ryujinx.Graphics.Texture; - -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrMetaTex : ShaderIrMeta - { - public int Elem { get; private set; } - public GalTextureTarget TextureTarget { get; private set; } - public ShaderIrNode[] Coordinates { get; private set; } - public TextureInstructionSuffix TextureInstructionSuffix { get; private set; } - public ShaderIrOperGpr LevelOfDetail; - public ShaderIrOperGpr Offset; - public ShaderIrOperGpr DepthCompare; - public int Component; // for TLD4(S) - - public ShaderIrMetaTex(int elem, GalTextureTarget textureTarget, TextureInstructionSuffix textureInstructionSuffix, params ShaderIrNode[] coordinates) - { - Elem = elem; - TextureTarget = textureTarget; - TextureInstructionSuffix = textureInstructionSuffix; - Coordinates = coordinates; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs deleted file mode 100644 index c925ea4e1a..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrMetaTexq : ShaderIrMeta - { - public ShaderTexqInfo Info { get; private set; } - - public int Elem { get; private set; } - - public ShaderIrMetaTexq(ShaderTexqInfo info, int elem) - { - Info = info; - Elem = elem; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrNode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrNode.cs deleted file mode 100644 index 2648164a11..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrNode.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrNode { } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs deleted file mode 100644 index c91c392653..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrOp : ShaderIrNode - { - public ShaderIrInst Inst { get; private set; } - public ShaderIrNode OperandA { get; set; } - public ShaderIrNode OperandB { get; set; } - public ShaderIrNode OperandC { get; set; } - public ShaderIrMeta MetaData { get; set; } - - public ShaderIrOp( - ShaderIrInst inst, - ShaderIrNode operandA = null, - ShaderIrNode operandB = null, - ShaderIrNode operandC = null, - ShaderIrMeta metaData = null) - { - Inst = inst; - OperandA = operandA; - OperandB = operandB; - OperandC = operandC; - MetaData = metaData; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs deleted file mode 100644 index 1f339e8051..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrOperAbuf : ShaderIrNode - { - public int Offs { get; private set; } - - public ShaderIrNode Vertex { get; private set; } - - public ShaderIrOperAbuf(int offs, ShaderIrNode vertex) - { - Offs = offs; - Vertex = vertex; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs deleted file mode 100644 index 9f419bbbec..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrOperCbuf : ShaderIrNode - { - public int Index { get; private set; } - public int Pos { get; set; } - - public ShaderIrNode Offs { get; private set; } - - public ShaderIrOperCbuf(int index, int pos, ShaderIrNode offs = null) - { - Index = index; - Pos = pos; - Offs = offs; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs deleted file mode 100644 index 0d102d8978..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrOperGpr : ShaderIrNode - { - public const int ZrIndex = 0xff; - - public bool IsConst => Index == ZrIndex; - - public bool IsValidRegister => (uint)Index <= ZrIndex; - - public int Index { get; set; } - public int HalfPart { get; set; } - - public ShaderRegisterSize RegisterSize { get; private set; } - - public ShaderIrOperGpr(int index) - { - Index = index; - - RegisterSize = ShaderRegisterSize.Single; - } - - public ShaderIrOperGpr(int index, int halfPart) - { - Index = index; - HalfPart = halfPart; - - RegisterSize = ShaderRegisterSize.Half; - } - - public static ShaderIrOperGpr MakeTemporary(int index = 0) - { - return new ShaderIrOperGpr(0x100 + index); - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs deleted file mode 100644 index 6b23b36574..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrOperImm : ShaderIrNode - { - public int Value { get; private set; } - - public ShaderIrOperImm(int value) - { - Value = value; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs deleted file mode 100644 index 5b08c5b1c9..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrOperImmf : ShaderIrNode - { - public float Value { get; private set; } - - public ShaderIrOperImmf(float value) - { - Value = value; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs deleted file mode 100644 index 6c16a145d9..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - class ShaderIrOperPred : ShaderIrNode - { - public const int UnusedIndex = 0x7; - public const int NeverExecute = 0xf; - - public bool IsConst => Index >= UnusedIndex; - - public int Index { get; set; } - - public ShaderIrOperPred(int index) - { - Index = index; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs deleted file mode 100644 index 1edf91a015..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ /dev/null @@ -1,190 +0,0 @@ -using System; - -namespace Ryujinx.Graphics.Gal.Shader -{ - static class ShaderOpCodeTable - { - private const int EncodingBits = 14; - - private class ShaderDecodeEntry - { - public ShaderDecodeFunc Func; - - public int XBits; - - public ShaderDecodeEntry(ShaderDecodeFunc func, int xBits) - { - Func = func; - XBits = xBits; - } - } - - private static ShaderDecodeEntry[] _opCodes; - - static ShaderOpCodeTable() - { - _opCodes = new ShaderDecodeEntry[1 << EncodingBits]; - -#region Instructions - Set("0100110000000x", ShaderDecode.Bfe_C); - Set("0011100x00000x", ShaderDecode.Bfe_I); - Set("0101110000000x", ShaderDecode.Bfe_R); - Set("111000100100xx", ShaderDecode.Bra); - Set("111000110000xx", ShaderDecode.Exit); - Set("0100110010101x", ShaderDecode.F2f_C); - Set("0011100x10101x", ShaderDecode.F2f_I); - Set("0101110010101x", ShaderDecode.F2f_R); - Set("0100110010110x", ShaderDecode.F2i_C); - Set("0011100x10110x", ShaderDecode.F2i_I); - Set("0101110010110x", ShaderDecode.F2i_R); - Set("0100110001011x", ShaderDecode.Fadd_C); - Set("0011100x01011x", ShaderDecode.Fadd_I); - Set("000010xxxxxxxx", ShaderDecode.Fadd_I32); - Set("0101110001011x", ShaderDecode.Fadd_R); - Set("010010011xxxxx", ShaderDecode.Ffma_CR); - Set("0011001x1xxxxx", ShaderDecode.Ffma_I); - Set("010100011xxxxx", ShaderDecode.Ffma_RC); - Set("010110011xxxxx", ShaderDecode.Ffma_RR); - Set("0100110001101x", ShaderDecode.Fmul_C); - Set("0011100x01101x", ShaderDecode.Fmul_I); - Set("00011110xxxxxx", ShaderDecode.Fmul_I32); - Set("0101110001101x", ShaderDecode.Fmul_R); - Set("0100110001100x", ShaderDecode.Fmnmx_C); - Set("0011100x01100x", ShaderDecode.Fmnmx_I); - Set("0101110001100x", ShaderDecode.Fmnmx_R); - Set("0100100xxxxxxx", ShaderDecode.Fset_C); - Set("0011000xxxxxxx", ShaderDecode.Fset_I); - Set("01011000xxxxxx", ShaderDecode.Fset_R); - Set("010010111011xx", ShaderDecode.Fsetp_C); - Set("0011011x1011xx", ShaderDecode.Fsetp_I); - Set("010110111011xx", ShaderDecode.Fsetp_R); - Set("0101110100010x", ShaderDecode.Hadd2_R); - Set("0101110100001x", ShaderDecode.Hmul2_R); - Set("0100110010111x", ShaderDecode.I2f_C); - Set("0011100x10111x", ShaderDecode.I2f_I); - Set("0101110010111x", ShaderDecode.I2f_R); - Set("0100110011100x", ShaderDecode.I2i_C); - Set("0011100x11100x", ShaderDecode.I2i_I); - Set("0101110011100x", ShaderDecode.I2i_R); - Set("0100110000010x", ShaderDecode.Iadd_C); - Set("0011100000010x", ShaderDecode.Iadd_I); - Set("0001110x0xxxxx", ShaderDecode.Iadd_I32); - Set("0101110000010x", ShaderDecode.Iadd_R); - Set("010011001100xx", ShaderDecode.Iadd3_C); - Set("001110001100xx", ShaderDecode.Iadd3_I); - Set("010111001100xx", ShaderDecode.Iadd3_R); - Set("0100110000100x", ShaderDecode.Imnmx_C); - Set("0011100x00100x", ShaderDecode.Imnmx_I); - Set("0101110000100x", ShaderDecode.Imnmx_R); - Set("1110111111010x", ShaderDecode.Isberd); - Set("11100000xxxxxx", ShaderDecode.Ipa); - Set("0100110000011x", ShaderDecode.Iscadd_C); - Set("0011100x00011x", ShaderDecode.Iscadd_I); - Set("0101110000011x", ShaderDecode.Iscadd_R); - Set("010010110101xx", ShaderDecode.Iset_C); - Set("001101100101xx", ShaderDecode.Iset_I); - Set("010110110101xx", ShaderDecode.Iset_R); - Set("010010110110xx", ShaderDecode.Isetp_C); - Set("0011011x0110xx", ShaderDecode.Isetp_I); - Set("010110110110xx", ShaderDecode.Isetp_R); - Set("111000110011xx", ShaderDecode.Kil); - Set("1110111111011x", ShaderDecode.Ld_A); - Set("1110111110010x", ShaderDecode.Ld_C); - Set("0100110001000x", ShaderDecode.Lop_C); - Set("0011100001000x", ShaderDecode.Lop_I); - Set("000001xxxxxxxx", ShaderDecode.Lop_I32); - Set("0101110001000x", ShaderDecode.Lop_R); - Set("0100110010011x", ShaderDecode.Mov_C); - Set("0011100x10011x", ShaderDecode.Mov_I); - Set("000000010000xx", ShaderDecode.Mov_I32); - Set("0101110010011x", ShaderDecode.Mov_R); - Set("1111000011001x", ShaderDecode.Mov_S); - Set("0101000010000x", ShaderDecode.Mufu); - Set("1111101111100x", ShaderDecode.Out_R); - Set("0101000010010x", ShaderDecode.Psetp); - Set("0100110010010x", ShaderDecode.Rro_C); - Set("0011100x10010x", ShaderDecode.Rro_I); - Set("0101110010010x", ShaderDecode.Rro_R); - Set("0100110010100x", ShaderDecode.Sel_C); - Set("0011100010100x", ShaderDecode.Sel_I); - Set("0101110010100x", ShaderDecode.Sel_R); - Set("0100110001001x", ShaderDecode.Shl_C); - Set("0011100x01001x", ShaderDecode.Shl_I); - Set("0101110001001x", ShaderDecode.Shl_R); - Set("0100110000101x", ShaderDecode.Shr_C); - Set("0011100x00101x", ShaderDecode.Shr_I); - Set("0101110000101x", ShaderDecode.Shr_R); - Set("111000101001xx", ShaderDecode.Ssy); - Set("1110111111110x", ShaderDecode.St_A); - Set("1111000011111x", ShaderDecode.Sync); - Set("110000xxxx111x", ShaderDecode.Tex); - Set("1101111010111x", ShaderDecode.Tex_B); - Set("1101111101001x", ShaderDecode.Texq); - Set("1101x00xxxxxxx", ShaderDecode.Texs); - Set("1101101xxxxxxx", ShaderDecode.Tlds); - Set("110010xxxx111x", ShaderDecode.Tld4); - Set("1101111100xxxx", ShaderDecode.Tld4S); - Set("01011111xxxxxx", ShaderDecode.Vmad); - Set("0100111xxxxxxx", ShaderDecode.Xmad_CR); - Set("0011011x00xxxx", ShaderDecode.Xmad_I); - Set("010100010xxxxx", ShaderDecode.Xmad_RC); - Set("0101101100xxxx", ShaderDecode.Xmad_RR); -#endregion - } - - private static void Set(string encoding, ShaderDecodeFunc func) - { - if (encoding.Length != EncodingBits) - { - throw new ArgumentException(nameof(encoding)); - } - - int bit = encoding.Length - 1; - int value = 0; - int xMask = 0; - int xBits = 0; - - int[] xPos = new int[encoding.Length]; - - for (int index = 0; index < encoding.Length; index++, bit--) - { - char chr = encoding[index]; - - if (chr == '1') - { - value |= 1 << bit; - } - else if (chr == 'x') - { - xMask |= 1 << bit; - - xPos[xBits++] = bit; - } - } - - xMask = ~xMask; - - ShaderDecodeEntry entry = new ShaderDecodeEntry(func, xBits); - - for (int index = 0; index < (1 << xBits); index++) - { - value &= xMask; - - for (int x = 0; x < xBits; x++) - { - value |= ((index >> x) & 1) << xPos[x]; - } - - if (_opCodes[value] == null || _opCodes[value].XBits > xBits) - { - _opCodes[value] = entry; - } - } - } - - public static ShaderDecodeFunc GetDecoder(long opCode) - { - return _opCodes[(ulong)opCode >> (64 - EncodingBits)]?.Func; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs deleted file mode 100644 index 22a2ab85cd..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - enum ShaderOper - { - Cr, - Imm, - Immf, - Rc, - Rr - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderRegisterSize.cs b/Ryujinx.Graphics/Gal/Shader/ShaderRegisterSize.cs deleted file mode 100644 index eb37359bf4..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderRegisterSize.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - enum ShaderRegisterSize - { - Half, - Single, - Double - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs b/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs deleted file mode 100644 index 9158662ccd..0000000000 --- a/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Ryujinx.Graphics.Gal.Shader -{ - enum ShaderTexqInfo - { - Dimension = 1, - TextureType = 2, - SamplePos = 5, - Filter = 16, - Lod = 18, - Wrap = 20, - BorderColor = 22 - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs b/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs deleted file mode 100644 index f1f4650c8f..0000000000 --- a/Ryujinx.Graphics/Gal/ShaderDeclInfo.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Ryujinx.Graphics.Texture; - -namespace Ryujinx.Graphics.Gal -{ - public class ShaderDeclInfo - { - public string Name { get; private set; } - - public int Index { get; private set; } - public bool IsCb { get; private set; } - public int Cbuf { get; private set; } - public int Size { get; private set; } - - public GalTextureTarget TextureTarget { get; private set; } - - public TextureInstructionSuffix TextureSuffix { get; private set; } - - public ShaderDeclInfo( - string name, - int index, - bool isCb = false, - int cbuf = 0, - int size = 1, - GalTextureTarget textureTarget = GalTextureTarget.TwoD, - TextureInstructionSuffix textureSuffix = TextureInstructionSuffix.None) - { - Name = name; - Index = index; - IsCb = isCb; - Cbuf = cbuf; - Size = size; - - TextureTarget = textureTarget; - TextureSuffix = textureSuffix; - } - - internal void Enlarge(int newSize) - { - if (Size < newSize) - { - Size = newSize; - } - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs index 605cbda816..bbed642b82 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs @@ -1,6 +1,7 @@ using Ryujinx.Common; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; +using Ryujinx.Graphics.Shader; using Ryujinx.Graphics.Texture; using System; using System.Collections.Generic; @@ -464,7 +465,7 @@ namespace Ryujinx.Graphics.Graphics3d left = _viewportX1 - (left - _viewportX0); right = _viewportX1 - (right - _viewportX0); } - + // Ensure X is in the right order if (left > right) { @@ -626,20 +627,22 @@ namespace Ryujinx.Graphics.Graphics3d for (int index = 0; index < keys.Length; index++) { - foreach (ShaderDeclInfo declInfo in _gpu.Renderer.Shader.GetTextureUsage(keys[index])) + foreach (TextureDescriptor desc in _gpu.Renderer.Shader.GetTextureUsage(keys[index])) { - long position; + int textureHandle; - if (declInfo.IsCb) + if (desc.IsBindless) { - position = _constBuffers[index][declInfo.Cbuf].Position; + long position = _constBuffers[index][desc.CbufSlot].Position; + + textureHandle = vmm.ReadInt32(position + desc.CbufOffset * 4); } else { - position = _constBuffers[index][textureCbIndex].Position; - } + long position = _constBuffers[index][textureCbIndex].Position; - int textureHandle = vmm.ReadInt32(position + declInfo.Index * 4); + textureHandle = vmm.ReadInt32(position + desc.HandleIndex * 4); + } unboundTextures.Add(UploadTexture(vmm, textureHandle)); } @@ -712,9 +715,9 @@ namespace Ryujinx.Graphics.Graphics3d { for (int stage = 0; stage < keys.Length; stage++) { - foreach (ShaderDeclInfo declInfo in _gpu.Renderer.Shader.GetConstBufferUsage(keys[stage])) + foreach (CBufferDescriptor desc in _gpu.Renderer.Shader.GetConstBufferUsage(keys[stage])) { - ConstBuffer cb = _constBuffers[stage][declInfo.Cbuf]; + ConstBuffer cb = _constBuffers[stage][desc.Slot]; if (!cb.Enabled) { @@ -735,7 +738,7 @@ namespace Ryujinx.Graphics.Graphics3d } } - state.ConstBufferKeys[stage][declInfo.Cbuf] = key; + state.ConstBufferKeys[stage][desc.Slot] = key; } } } diff --git a/Ryujinx.Graphics/Shader/CBufferDescriptor.cs b/Ryujinx.Graphics/Shader/CBufferDescriptor.cs new file mode 100644 index 0000000000..f99665e162 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CBufferDescriptor.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Graphics.Shader +{ + public struct CBufferDescriptor + { + public string Name { get; } + + public int Slot { get; } + + public CBufferDescriptor(string name, int slot) + { + Name = name; + Slot = slot; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/CodeGenContext.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/CodeGenContext.cs new file mode 100644 index 0000000000..ce5d7b949e --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/CodeGenContext.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using System.Text; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + class CodeGenContext + { + private const string Tab = " "; + + public ShaderConfig Config { get; } + + public List CBufferDescriptors { get; } + public List TextureDescriptors { get; } + + public OperandManager OperandManager { get; } + + private StringBuilder _sb; + + private int _level; + + private string _identation; + + public CodeGenContext(ShaderConfig config) + { + Config = config; + + CBufferDescriptors = new List(); + TextureDescriptors = new List(); + + OperandManager = new OperandManager(); + + _sb = new StringBuilder(); + } + + public void AppendLine() + { + _sb.AppendLine(); + } + + public void AppendLine(string str) + { + _sb.AppendLine(_identation + str); + } + + public string GetCode() + { + return _sb.ToString(); + } + + public void EnterScope() + { + AppendLine("{"); + + _level++; + + UpdateIdentation(); + } + + public void LeaveScope(string suffix = "") + { + if (_level == 0) + { + return; + } + + _level--; + + UpdateIdentation(); + + AppendLine("}" + suffix); + } + + private void UpdateIdentation() + { + _identation = GetIdentation(_level); + } + + private static string GetIdentation(int level) + { + string identation = string.Empty; + + for (int index = 0; index < level; index++) + { + identation += Tab; + } + + return identation; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Declarations.cs new file mode 100644 index 0000000000..5412d87281 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Declarations.cs @@ -0,0 +1,206 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + static class Declarations + { + public static void Declare(CodeGenContext context, StructuredProgramInfo info) + { + context.AppendLine("#version 420 core"); + + context.AppendLine(); + + context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;"); + + context.AppendLine(); + + if (context.Config.Type == GalShaderType.Geometry) + { + context.AppendLine("layout (points) in;"); + context.AppendLine("layout (triangle_strip, max_vertices = 4) out;"); + + context.AppendLine(); + } + + context.AppendLine("layout (std140) uniform Extra"); + + context.EnterScope(); + + context.AppendLine("vec2 flip;"); + context.AppendLine("int instance;"); + + context.LeaveScope(";"); + + context.AppendLine(); + + if (info.CBuffers.Count != 0) + { + DeclareUniforms(context, info); + + context.AppendLine(); + } + + if (info.Samplers.Count != 0) + { + DeclareSamplers(context, info); + + context.AppendLine(); + } + + if (info.IAttributes.Count != 0) + { + DeclareInputAttributes(context, info); + + context.AppendLine(); + } + + if (info.OAttributes.Count != 0) + { + DeclareOutputAttributes(context, info); + + context.AppendLine(); + } + } + + public static void DeclareLocals(CodeGenContext context, StructuredProgramInfo info) + { + foreach (AstOperand decl in info.Locals) + { + string name = context.OperandManager.DeclareLocal(decl); + + context.AppendLine(GetVarTypeName(decl.VarType) + " " + name + ";"); + } + } + + private static string GetVarTypeName(VariableType type) + { + switch (type) + { + case VariableType.Bool: return "bool"; + case VariableType.F32: return "float"; + case VariableType.S32: return "int"; + case VariableType.U32: return "uint"; + } + + throw new ArgumentException($"Invalid variable type \"{type}\"."); + } + + private static void DeclareUniforms(CodeGenContext context, StructuredProgramInfo info) + { + foreach (int cbufSlot in info.CBuffers.OrderBy(x => x)) + { + string ubName = OperandManager.GetShaderStagePrefix(context.Config.Type); + + ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot; + + context.CBufferDescriptors.Add(new CBufferDescriptor(ubName, cbufSlot)); + + context.AppendLine("layout (std140) uniform " + ubName); + + context.EnterScope(); + + string ubSize = "[" + NumberFormatter.FormatInt(context.Config.MaxCBufferSize / 16) + "]"; + + context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Type, cbufSlot) + ubSize + ";"); + + context.LeaveScope(";"); + } + } + + private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info) + { + Dictionary samplers = new Dictionary(); + + foreach (AstTextureOperation texOp in info.Samplers.OrderBy(x => x.Handle)) + { + string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp); + + if (!samplers.TryAdd(samplerName, texOp)) + { + continue; + } + + string samplerTypeName = GetSamplerTypeName(texOp.Type); + + context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";"); + } + + foreach (KeyValuePair kv in samplers) + { + string samplerName = kv.Key; + + AstTextureOperation texOp = kv.Value; + + TextureDescriptor desc; + + if ((texOp.Flags & TextureFlags.Bindless) != 0) + { + AstOperand operand = texOp.GetSource(0) as AstOperand; + + desc = new TextureDescriptor(samplerName, operand.CbufSlot, operand.CbufOffset); + } + else + { + desc = new TextureDescriptor(samplerName, texOp.Handle); + } + + context.TextureDescriptors.Add(desc); + } + } + + private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info) + { + string suffix = context.Config.Type == GalShaderType.Geometry ? "[]" : string.Empty; + + foreach (int attr in info.IAttributes.OrderBy(x => x)) + { + context.AppendLine($"layout (location = {attr}) in vec4 {DefaultNames.IAttributePrefix}{attr}{suffix};"); + } + } + + private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info) + { + foreach (int attr in info.OAttributes.OrderBy(x => x)) + { + context.AppendLine($"layout (location = {attr}) out vec4 {DefaultNames.OAttributePrefix}{attr};"); + } + } + + private static string GetSamplerTypeName(TextureType type) + { + string typeName; + + switch (type & TextureType.Mask) + { + case TextureType.Texture1D: typeName = "sampler1D"; break; + case TextureType.Texture2D: typeName = "sampler2D"; break; + case TextureType.Texture3D: typeName = "sampler3D"; break; + case TextureType.TextureCube: typeName = "samplerCube"; break; + + default: throw new ArgumentException($"Invalid sampler type \"{type}\"."); + } + + if ((type & TextureType.Multisample) != 0) + { + typeName += "MS"; + } + + if ((type & TextureType.Array) != 0) + { + typeName += "Array"; + } + + if ((type & TextureType.Shadow) != 0) + { + typeName += "Shadow"; + } + + return typeName; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/DefaultNames.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/DefaultNames.cs new file mode 100644 index 0000000000..1d3939fb79 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/DefaultNames.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + static class DefaultNames + { + public const string LocalNamePrefix = "temp"; + + public const string SamplerNamePrefix = "tex"; + + public const string IAttributePrefix = "in_attr"; + public const string OAttributePrefix = "out_attr"; + + public const string UniformNamePrefix = "c"; + public const string UniformNameSuffix = "data"; + + public const string UndefinedName = "undef"; + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslGenerator.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslGenerator.cs new file mode 100644 index 0000000000..4edbda8b9e --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslGenerator.cs @@ -0,0 +1,133 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; +using System; + +using static Ryujinx.Graphics.Shader.CodeGen.Glsl.TypeConversion; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + static class GlslGenerator + { + public static GlslProgram Generate(StructuredProgramInfo info, ShaderConfig config) + { + CodeGenContext context = new CodeGenContext(config); + + Declarations.Declare(context, info); + + PrintMainBlock(context, info); + + return new GlslProgram( + context.CBufferDescriptors.ToArray(), + context.TextureDescriptors.ToArray(), + context.GetCode()); + } + + private static void PrintMainBlock(CodeGenContext context, StructuredProgramInfo info) + { + context.AppendLine("void main()"); + + context.EnterScope(); + + Declarations.DeclareLocals(context, info); + + PrintBlock(context, info.MainBlock); + + context.LeaveScope(); + } + + private static void PrintBlock(CodeGenContext context, AstBlock block) + { + AstBlockVisitor visitor = new AstBlockVisitor(block); + + visitor.BlockEntered += (sender, e) => + { + switch (e.Block.Type) + { + case AstBlockType.DoWhile: + context.AppendLine("do"); + break; + + case AstBlockType.Else: + context.AppendLine("else"); + break; + + case AstBlockType.ElseIf: + context.AppendLine($"else if ({GetCondExpr(context, e.Block.Condition)})"); + break; + + case AstBlockType.If: + context.AppendLine($"if ({GetCondExpr(context, e.Block.Condition)})"); + break; + + default: throw new InvalidOperationException($"Found unexpected block type \"{e.Block.Type}\"."); + } + + context.EnterScope(); + }; + + visitor.BlockLeft += (sender, e) => + { + context.LeaveScope(); + + if (e.Block.Type == AstBlockType.DoWhile) + { + context.AppendLine($"while ({GetCondExpr(context, e.Block.Condition)});"); + } + }; + + foreach (IAstNode node in visitor.Visit()) + { + if (node is AstOperation operation) + { + if (operation.Inst == Instruction.Return) + { + PrepareForReturn(context); + } + + context.AppendLine(InstGen.GetExpression(context, operation) + ";"); + } + else if (node is AstAssignment assignment) + { + VariableType srcType = OperandManager.GetNodeDestType(assignment.Source); + VariableType dstType = OperandManager.GetNodeDestType(assignment.Destination); + + string dest; + + if (assignment.Destination is AstOperand operand && operand.Type == OperandType.Attribute) + { + dest = OperandManager.GetOutAttributeName(operand, context.Config.Type); + } + else + { + dest = InstGen.GetExpression(context, assignment.Destination); + } + + string src = ReinterpretCast(context, assignment.Source, srcType, dstType); + + context.AppendLine(dest + " = " + src + ";"); + } + else + { + throw new InvalidOperationException($"Found unexpected node type \"{node?.GetType().Name ?? "null"}\"."); + } + } + } + + private static string GetCondExpr(CodeGenContext context, IAstNode cond) + { + VariableType srcType = OperandManager.GetNodeDestType(cond); + + return ReinterpretCast(context, cond, srcType, VariableType.Bool); + } + + private static void PrepareForReturn(CodeGenContext context) + { + if (context.Config.Type == GalShaderType.Vertex) + { + context.AppendLine("gl_Position.xy *= flip;"); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslProgram.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslProgram.cs new file mode 100644 index 0000000000..e616aa1f81 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslProgram.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + class GlslProgram + { + public CBufferDescriptor[] CBufferDescriptors { get; } + public TextureDescriptor[] TextureDescriptors { get; } + + public string Code { get; } + + public GlslProgram( + CBufferDescriptor[] cBufferDescs, + TextureDescriptor[] textureDescs, + string code) + { + CBufferDescriptors = cBufferDescs; + TextureDescriptors = textureDescs; + Code = code; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGen.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGen.cs new file mode 100644 index 0000000000..b0b2ec1a99 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGen.cs @@ -0,0 +1,110 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; +using System; + +using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper; +using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions +{ + static class InstGen + { + public static string GetExpression(CodeGenContext context, IAstNode node) + { + if (node is AstOperation operation) + { + return GetExpression(context, operation); + } + else if (node is AstOperand operand) + { + return context.OperandManager.GetExpression(operand, context.Config.Type); + } + + throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\"."); + } + + private static string GetExpression(CodeGenContext context, AstOperation operation) + { + Instruction inst = operation.Inst; + + InstInfo info = GetInstructionInfo(inst); + + if ((info.Type & InstType.Call) != 0) + { + int arity = (int)(info.Type & InstType.ArityMask); + + string args = string.Empty; + + for (int argIndex = 0; argIndex < arity; argIndex++) + { + if (argIndex != 0) + { + args += ", "; + } + + VariableType dstType = GetSrcVarType(inst, argIndex); + + args += GetSoureExpr(context, operation.GetSource(argIndex), dstType); + } + + return info.OpName + "(" + args + ")"; + } + else if ((info.Type & InstType.Op) != 0) + { + string op = info.OpName; + + int arity = (int)(info.Type & InstType.ArityMask); + + string[] expr = new string[arity]; + + for (int index = 0; index < arity; index++) + { + IAstNode src = operation.GetSource(index); + + string srcExpr = GetSoureExpr(context, src, GetSrcVarType(inst, index)); + + bool isLhs = arity == 2 && index == 0; + + expr[index] = Enclose(srcExpr, src, inst, info, isLhs); + } + + switch (arity) + { + case 0: + return op; + + case 1: + return op + expr[0]; + + case 2: + return $"{expr[0]} {op} {expr[1]}"; + + case 3: + return $"{expr[0]} {op[0]} {expr[1]} {op[1]} {expr[2]}"; + } + } + else if ((info.Type & InstType.Special) != 0) + { + switch (inst) + { + case Instruction.LoadConstant: + return InstGenMemory.LoadConstant(context, operation); + + case Instruction.PackHalf2x16: + return InstGenPacking.PackHalf2x16(context, operation); + + case Instruction.TextureSample: + return InstGenMemory.TextureSample(context, operation); + + case Instruction.TextureSize: + return InstGenMemory.TextureSize(context, operation); + + case Instruction.UnpackHalf2x16: + return InstGenPacking.UnpackHalf2x16(context, operation); + } + } + + throw new InvalidOperationException($"Unexpected instruction type \"{info.Type}\"."); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs new file mode 100644 index 0000000000..0b86007293 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs @@ -0,0 +1,170 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; + +using static Ryujinx.Graphics.Shader.CodeGen.Glsl.TypeConversion; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions +{ + static class InstGenHelper + { + private static InstInfo[] _infoTbl; + + static InstGenHelper() + { + _infoTbl = new InstInfo[(int)Instruction.Count]; + + Add(Instruction.Absolute, InstType.CallUnary, "abs"); + Add(Instruction.Add, InstType.OpBinaryCom, "+", 2); + Add(Instruction.BitfieldExtractS32, InstType.CallTernary, "bitfieldExtract"); + Add(Instruction.BitfieldExtractU32, InstType.CallTernary, "bitfieldExtract"); + Add(Instruction.BitfieldInsert, InstType.CallQuaternary, "bitfieldInsert"); + Add(Instruction.BitfieldReverse, InstType.CallUnary, "bitfieldReverse"); + Add(Instruction.BitwiseAnd, InstType.OpBinaryCom, "&", 6); + Add(Instruction.BitwiseExclusiveOr, InstType.OpBinaryCom, "^", 7); + Add(Instruction.BitwiseNot, InstType.OpUnary, "~", 0); + Add(Instruction.BitwiseOr, InstType.OpBinaryCom, "|", 8); + Add(Instruction.Ceiling, InstType.CallUnary, "ceil"); + Add(Instruction.Clamp, InstType.CallTernary, "clamp"); + Add(Instruction.ClampU32, InstType.CallTernary, "clamp"); + Add(Instruction.CompareEqual, InstType.OpBinaryCom, "==", 5); + Add(Instruction.CompareGreater, InstType.OpBinary, ">", 4); + Add(Instruction.CompareGreaterOrEqual, InstType.OpBinary, ">=", 4); + Add(Instruction.CompareGreaterOrEqualU32, InstType.OpBinary, ">=", 4); + Add(Instruction.CompareGreaterU32, InstType.OpBinary, ">", 4); + Add(Instruction.CompareLess, InstType.OpBinary, "<", 4); + Add(Instruction.CompareLessOrEqual, InstType.OpBinary, "<=", 4); + Add(Instruction.CompareLessOrEqualU32, InstType.OpBinary, "<=", 4); + Add(Instruction.CompareLessU32, InstType.OpBinary, "<", 4); + Add(Instruction.CompareNotEqual, InstType.OpBinaryCom, "!=", 5); + Add(Instruction.ConditionalSelect, InstType.OpTernary, "?:", 12); + Add(Instruction.ConvertFPToS32, InstType.CallUnary, "int"); + Add(Instruction.ConvertS32ToFP, InstType.CallUnary, "float"); + Add(Instruction.ConvertU32ToFP, InstType.CallUnary, "float"); + Add(Instruction.Cosine, InstType.CallUnary, "cos"); + Add(Instruction.Discard, InstType.OpNullary, "discard"); + Add(Instruction.Divide, InstType.OpBinary, "/", 1); + Add(Instruction.EmitVertex, InstType.CallNullary, "EmitVertex"); + Add(Instruction.EndPrimitive, InstType.CallNullary, "EndPrimitive"); + Add(Instruction.ExponentB2, InstType.CallUnary, "exp2"); + Add(Instruction.Floor, InstType.CallUnary, "floor"); + Add(Instruction.FusedMultiplyAdd, InstType.CallTernary, "fma"); + Add(Instruction.IsNan, InstType.CallUnary, "isnan"); + Add(Instruction.LoadConstant, InstType.Special); + Add(Instruction.LogarithmB2, InstType.CallUnary, "log2"); + Add(Instruction.LogicalAnd, InstType.OpBinaryCom, "&&", 9); + Add(Instruction.LogicalExclusiveOr, InstType.OpBinaryCom, "^^", 10); + Add(Instruction.LogicalNot, InstType.OpUnary, "!", 0); + Add(Instruction.LogicalOr, InstType.OpBinaryCom, "||", 11); + Add(Instruction.LoopBreak, InstType.OpNullary, "break"); + Add(Instruction.LoopContinue, InstType.OpNullary, "continue"); + Add(Instruction.PackHalf2x16, InstType.Special); + Add(Instruction.ShiftLeft, InstType.OpBinary, "<<", 3); + Add(Instruction.ShiftRightS32, InstType.OpBinary, ">>", 3); + Add(Instruction.ShiftRightU32, InstType.OpBinary, ">>", 3); + Add(Instruction.Maximum, InstType.CallBinary, "max"); + Add(Instruction.MaximumU32, InstType.CallBinary, "max"); + Add(Instruction.Minimum, InstType.CallBinary, "min"); + Add(Instruction.MinimumU32, InstType.CallBinary, "min"); + Add(Instruction.Multiply, InstType.OpBinaryCom, "*", 1); + Add(Instruction.Negate, InstType.OpUnary, "-", 0); + Add(Instruction.ReciprocalSquareRoot, InstType.CallUnary, "inversesqrt"); + Add(Instruction.Return, InstType.OpNullary, "return"); + Add(Instruction.Sine, InstType.CallUnary, "sin"); + Add(Instruction.SquareRoot, InstType.CallUnary, "sqrt"); + Add(Instruction.Subtract, InstType.OpBinary, "-", 2); + Add(Instruction.TextureSample, InstType.Special); + Add(Instruction.TextureSize, InstType.Special); + Add(Instruction.Truncate, InstType.CallUnary, "trunc"); + Add(Instruction.UnpackHalf2x16, InstType.Special); + } + + private static void Add(Instruction inst, InstType flags, string opName = null, int precedence = 0) + { + _infoTbl[(int)inst] = new InstInfo(flags, opName, precedence); + } + + public static InstInfo GetInstructionInfo(Instruction inst) + { + return _infoTbl[(int)(inst & Instruction.Mask)]; + } + + public static string GetSoureExpr(CodeGenContext context, IAstNode node, VariableType dstType) + { + return ReinterpretCast(context, node, OperandManager.GetNodeDestType(node), dstType); + } + + public static string Enclose(string expr, IAstNode node, Instruction pInst, bool isLhs) + { + InstInfo pInfo = GetInstructionInfo(pInst); + + return Enclose(expr, node, pInst, pInfo, isLhs); + } + + public static string Enclose(string expr, IAstNode node, Instruction pInst, InstInfo pInfo, bool isLhs = false) + { + if (NeedsParenthesis(node, pInst, pInfo, isLhs)) + { + expr = "(" + expr + ")"; + } + + return expr; + } + + public static bool NeedsParenthesis(IAstNode node, Instruction pInst, InstInfo pInfo, bool isLhs) + { + //If the node isn't a operation, then it can only be a operand, + //and those never needs to be surrounded in parenthesis. + if (!(node is AstOperation operation)) + { + //This is sort of a special case, if this is a negative constant, + //and it is consumed by a unary operation, we need to put on the parenthesis, + //as in GLSL a sequence like --2 or ~-1 is not valid. + if (IsNegativeConst(node) && pInfo.Type == InstType.OpUnary) + { + return true; + } + + return false; + } + + if ((pInfo.Type & (InstType.Call | InstType.Special)) != 0) + { + return false; + } + + InstInfo info = _infoTbl[(int)(operation.Inst & Instruction.Mask)]; + + if ((info.Type & (InstType.Call | InstType.Special)) != 0) + { + return false; + } + + if (info.Precedence < pInfo.Precedence) + { + return false; + } + + if (info.Precedence == pInfo.Precedence && isLhs) + { + return false; + } + + if (pInst == operation.Inst && info.Type == InstType.OpBinaryCom) + { + return false; + } + + return true; + } + + private static bool IsNegativeConst(IAstNode node) + { + if (!(node is AstOperand operand)) + { + return false; + } + + return operand.Type == OperandType.Constant && operand.Value < 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs new file mode 100644 index 0000000000..79f80057ff --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs @@ -0,0 +1,244 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; + +using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper; +using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions +{ + static class InstGenMemory + { + public static string LoadConstant(CodeGenContext context, AstOperation operation) + { + IAstNode src1 = operation.GetSource(1); + + string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1)); + + offsetExpr = Enclose(offsetExpr, src1, Instruction.ShiftRightS32, isLhs: true); + + return OperandManager.GetConstantBufferName(operation.GetSource(0), offsetExpr, context.Config.Type); + } + + public static string TextureSample(CodeGenContext context, AstOperation operation) + { + AstTextureOperation texOp = (AstTextureOperation)operation; + + bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + bool isGather = (texOp.Flags & TextureFlags.Gather) != 0; + bool intCoords = (texOp.Flags & TextureFlags.IntCoords) != 0; + bool hasLodBias = (texOp.Flags & TextureFlags.LodBias) != 0; + bool hasLodLevel = (texOp.Flags & TextureFlags.LodLevel) != 0; + bool hasOffset = (texOp.Flags & TextureFlags.Offset) != 0; + bool hasOffsets = (texOp.Flags & TextureFlags.Offsets) != 0; + bool isArray = (texOp.Type & TextureType.Array) != 0; + bool isMultisample = (texOp.Type & TextureType.Multisample) != 0; + bool isShadow = (texOp.Type & TextureType.Shadow) != 0; + + string texCall = intCoords ? "texelFetch" : "texture"; + + if (isGather) + { + texCall += "Gather"; + } + else if (hasLodLevel && !intCoords) + { + texCall += "Lod"; + } + + if (hasOffset) + { + texCall += "Offset"; + } + else if (hasOffsets) + { + texCall += "Offsets"; + } + + string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp); + + texCall += "(" + samplerName; + + int coordsCount = texOp.Type.GetCoordsCount(); + + int pCount = coordsCount; + + int arrayIndexElem = -1; + + if (isArray) + { + arrayIndexElem = pCount++; + } + + //The sampler 1D shadow overload expects a + //dummy value on the middle of the vector, who knows why... + bool hasDummy1DShadowElem = texOp.Type == (TextureType.Texture1D | TextureType.Shadow); + + if (hasDummy1DShadowElem) + { + pCount++; + } + + if (isShadow && !isGather) + { + pCount++; + } + + //On textureGather*, the comparison value is + //always specified as an extra argument. + bool hasExtraCompareArg = isShadow && isGather; + + if (pCount == 5) + { + pCount = 4; + + hasExtraCompareArg = true; + } + + int srcIndex = isBindless ? 1 : 0; + + string Src(VariableType type) + { + return GetSoureExpr(context, texOp.GetSource(srcIndex++), type); + } + + void Append(string str) + { + texCall += ", " + str; + } + + VariableType coordType = intCoords ? VariableType.S32 : VariableType.F32; + + string AssemblePVector(int count) + { + if (count > 1) + { + string[] elems = new string[count]; + + for (int index = 0; index < count; index++) + { + if (arrayIndexElem == index) + { + elems[index] = Src(VariableType.S32); + + if (!intCoords) + { + elems[index] = "float(" + elems[index] + ")"; + } + } + else if (index == 1 && hasDummy1DShadowElem) + { + elems[index] = NumberFormatter.FormatFloat(0); + } + else + { + elems[index] = Src(coordType); + } + } + + string prefix = intCoords ? "i" : string.Empty; + + return prefix + "vec" + count + "(" + string.Join(", ", elems) + ")"; + } + else + { + return Src(coordType); + } + } + + Append(AssemblePVector(pCount)); + + if (hasExtraCompareArg) + { + Append(Src(VariableType.F32)); + } + + if (isMultisample) + { + Append(Src(VariableType.S32)); + } + else if (hasLodLevel) + { + Append(Src(coordType)); + } + + string AssembleOffsetVector(int count) + { + if (count > 1) + { + string[] elems = new string[count]; + + for (int index = 0; index < count; index++) + { + elems[index] = Src(VariableType.S32); + } + + return "ivec" + count + "(" + string.Join(", ", elems) + ")"; + } + else + { + return Src(VariableType.S32); + } + } + + if (hasOffset) + { + Append(AssembleOffsetVector(coordsCount)); + } + else if (hasOffsets) + { + texCall += $", ivec{coordsCount}[4]("; + + texCall += AssembleOffsetVector(coordsCount) + ", "; + texCall += AssembleOffsetVector(coordsCount) + ", "; + texCall += AssembleOffsetVector(coordsCount) + ", "; + texCall += AssembleOffsetVector(coordsCount) + ")"; + } + + if (hasLodBias) + { + Append(Src(VariableType.F32)); + } + + //textureGather* optional extra component index, + //not needed for shadow samplers. + if (isGather && !isShadow) + { + Append(Src(VariableType.S32)); + } + + texCall += ")" + (isGather || !isShadow ? GetMask(texOp.ComponentMask) : ""); + + return texCall; + } + + public static string TextureSize(CodeGenContext context, AstOperation operation) + { + AstTextureOperation texOp = (AstTextureOperation)operation; + + bool isBindless = (texOp.Flags & TextureFlags.Bindless) != 0; + + string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp); + + IAstNode src0 = operation.GetSource(isBindless ? 1 : 0); + + string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0)); + + return $"textureSize({samplerName}, {src0Expr}){GetMask(texOp.ComponentMask)}"; + } + + private static string GetMask(int compMask) + { + string mask = "."; + + for (int index = 0; index < 4; index++) + { + if ((compMask & (1 << index)) != 0) + { + mask += "rgba".Substring(index, 1); + } + } + + return mask; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs new file mode 100644 index 0000000000..4a40032c57 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs @@ -0,0 +1,45 @@ +using Ryujinx.Graphics.Shader.StructuredIr; + +using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper; +using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions +{ + static class InstGenPacking + { + public static string PackHalf2x16(CodeGenContext context, AstOperation operation) + { + IAstNode src0 = operation.GetSource(0); + IAstNode src1 = operation.GetSource(1); + + string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0)); + string src1Expr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1)); + + return $"packHalf2x16(vec2({src0Expr}, {src1Expr}))"; + } + + public static string UnpackHalf2x16(CodeGenContext context, AstOperation operation) + { + IAstNode src = operation.GetSource(0); + + string srcExpr = GetSoureExpr(context, src, GetSrcVarType(operation.Inst, 0)); + + return $"unpackHalf2x16({srcExpr}){GetMask(operation.ComponentMask)}"; + } + + private static string GetMask(int compMask) + { + string mask = "."; + + for (int index = 0; index < 2; index++) + { + if ((compMask & (1 << index)) != 0) + { + mask += "xy".Substring(index, 1); + } + } + + return mask; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstInfo.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstInfo.cs new file mode 100644 index 0000000000..fc9aef7ec3 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstInfo.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions +{ + struct InstInfo + { + public InstType Type { get; } + + public string OpName { get; } + + public int Precedence { get; } + + public InstInfo(InstType type, string opName, int precedence) + { + Type = type; + OpName = opName; + Precedence = precedence; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstType.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstType.cs new file mode 100644 index 0000000000..7d38a9d269 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstType.cs @@ -0,0 +1,27 @@ +using System; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions +{ + [Flags] + enum InstType + { + OpNullary = Op | 0, + OpUnary = Op | 1, + OpBinary = Op | 2, + OpTernary = Op | 3, + OpBinaryCom = OpBinary | Comutative, + + CallNullary = Call | 0, + CallUnary = Call | 1, + CallBinary = Call | 2, + CallTernary = Call | 3, + CallQuaternary = Call | 4, + + Comutative = 1 << 8, + Op = 1 << 9, + Call = 1 << 10, + Special = 1 << 11, + + ArityMask = 0xff + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs new file mode 100644 index 0000000000..2ec44277c3 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs @@ -0,0 +1,104 @@ +using Ryujinx.Graphics.Shader.StructuredIr; +using System; +using System.Globalization; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + static class NumberFormatter + { + private const int MaxDecimal = 256; + + public static bool TryFormat(int value, VariableType dstType, out string formatted) + { + if (dstType == VariableType.F32) + { + return TryFormatFloat(BitConverter.Int32BitsToSingle(value), out formatted); + } + else if (dstType == VariableType.S32) + { + formatted = FormatInt(value); + } + else if (dstType == VariableType.U32) + { + formatted = FormatUint((uint)value); + } + else if (dstType == VariableType.Bool) + { + formatted = value != 0 ? "true" : "false"; + } + else + { + throw new ArgumentException($"Invalid variable type \"{dstType}\"."); + } + + return true; + } + + public static string FormatFloat(float value) + { + if (!TryFormatFloat(value, out string formatted)) + { + throw new ArgumentException("Failed to convert float value to string."); + } + + return formatted; + } + + public static bool TryFormatFloat(float value, out string formatted) + { + if (float.IsNaN(value) || float.IsInfinity(value)) + { + formatted = null; + + return false; + } + + formatted = value.ToString("G9", CultureInfo.InvariantCulture); + + if (!(formatted.Contains('.') || + formatted.Contains('e') || + formatted.Contains('E'))) + { + formatted += ".0"; + } + + return true; + } + + public static string FormatInt(int value, VariableType dstType) + { + if (dstType == VariableType.S32) + { + return FormatInt(value); + } + else if (dstType == VariableType.U32) + { + return FormatUint((uint)value); + } + else + { + throw new ArgumentException($"Invalid variable type \"{dstType}\"."); + } + } + + public static string FormatInt(int value) + { + if (value <= MaxDecimal && value >= -MaxDecimal) + { + return value.ToString(CultureInfo.InvariantCulture); + } + + return "0x" + value.ToString("X", CultureInfo.InvariantCulture); + } + + public static string FormatUint(uint value) + { + if (value <= MaxDecimal && value >= 0) + { + return value.ToString(CultureInfo.InvariantCulture) + "u"; + } + + return "0x" + value.ToString("X", CultureInfo.InvariantCulture) + "u"; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs new file mode 100644 index 0000000000..debba42843 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs @@ -0,0 +1,239 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; +using System; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + class OperandManager + { + private static string[] _stagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" }; + + private struct BuiltInAttribute + { + public string Name { get; } + + public VariableType Type { get; } + + public BuiltInAttribute(string name, VariableType type) + { + Name = name; + Type = type; + } + } + + private static Dictionary _builtInAttributes = + new Dictionary() + { + { AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", VariableType.S32) }, + { AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", VariableType.F32) }, + { AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", VariableType.F32) }, + { AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", VariableType.F32) }, + { AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", VariableType.F32) }, + { AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", VariableType.F32) }, + { AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", VariableType.F32) }, + { AttributeConsts.PointCoordY, new BuiltInAttribute("gl_PointCoord.y", VariableType.F32) }, + { AttributeConsts.TessCoordX, new BuiltInAttribute("gl_TessCoord.x", VariableType.F32) }, + { AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) }, + { AttributeConsts.InstanceId, new BuiltInAttribute("instance", VariableType.S32) }, + { AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) }, + { AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) }, + { AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) } + }; + + private Dictionary _locals; + + public OperandManager() + { + _locals = new Dictionary(); + } + + public string DeclareLocal(AstOperand operand) + { + string name = $"{DefaultNames.LocalNamePrefix}_{_locals.Count}"; + + _locals.Add(operand, name); + + return name; + } + + public string GetExpression(AstOperand operand, GalShaderType shaderType) + { + switch (operand.Type) + { + case OperandType.Attribute: + return GetAttributeName(operand, shaderType); + + case OperandType.Constant: + return NumberFormatter.FormatInt(operand.Value); + + case OperandType.ConstantBuffer: + return GetConstantBufferName(operand, shaderType); + + case OperandType.LocalVariable: + return _locals[operand]; + + case OperandType.Undefined: + return DefaultNames.UndefinedName; + } + + throw new ArgumentException($"Invalid operand type \"{operand.Type}\"."); + } + + public static string GetConstantBufferName(AstOperand cbuf, GalShaderType shaderType) + { + string ubName = GetUbName(shaderType, cbuf.CbufSlot); + + ubName += "[" + (cbuf.CbufOffset >> 2) + "]"; + + return ubName + "." + GetSwizzleMask(cbuf.CbufOffset & 3); + } + + public static string GetConstantBufferName(IAstNode slot, string offsetExpr, GalShaderType shaderType) + { + //Non-constant slots are not supported. + //It is expected that upstream stages are never going to generate non-constant + //slot access. + AstOperand operand = (AstOperand)slot; + + string ubName = GetUbName(shaderType, operand.Value); + + string index0 = "[" + offsetExpr + " >> 4]"; + string index1 = "[" + offsetExpr + " >> 2 & 3]"; + + return ubName + index0 + index1; + } + + public static string GetOutAttributeName(AstOperand attr, GalShaderType shaderType) + { + return GetAttributeName(attr, shaderType, isOutAttr: true); + } + + private static string GetAttributeName(AstOperand attr, GalShaderType shaderType, bool isOutAttr = false) + { + int value = attr.Value; + + string swzMask = GetSwizzleMask((value >> 2) & 3); + + if (value >= AttributeConsts.UserAttributeBase && + value < AttributeConsts.UserAttributeEnd) + { + value -= AttributeConsts.UserAttributeBase; + + string prefix = isOutAttr + ? DefaultNames.OAttributePrefix + : DefaultNames.IAttributePrefix; + + string name = $"{prefix}{(value >> 4)}"; + + if (shaderType == GalShaderType.Geometry && !isOutAttr) + { + name += "[0]"; + } + + name += "." + swzMask; + + return name; + } + else + { + if (value >= AttributeConsts.FragmentOutputColorBase && + value < AttributeConsts.FragmentOutputColorEnd) + { + value -= AttributeConsts.FragmentOutputColorBase; + + return $"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}"; + } + else if (_builtInAttributes.TryGetValue(value & ~3, out BuiltInAttribute builtInAttr)) + { + //TODO: There must be a better way to handle this... + if (shaderType == GalShaderType.Fragment) + { + switch (value & ~3) + { + case AttributeConsts.PositionX: return "gl_FragCoord.x"; + case AttributeConsts.PositionY: return "gl_FragCoord.y"; + case AttributeConsts.PositionZ: return "gl_FragCoord.z"; + case AttributeConsts.PositionW: return "1.0"; + } + } + + string name = builtInAttr.Name; + + if (shaderType == GalShaderType.Geometry && !isOutAttr) + { + name = "gl_in[0]." + name; + } + + return name; + } + } + + return DefaultNames.UndefinedName; + } + + public static string GetUbName(GalShaderType shaderType, int slot) + { + string ubName = OperandManager.GetShaderStagePrefix(shaderType); + + ubName += "_" + DefaultNames.UniformNamePrefix + slot; + + return ubName + "_" + DefaultNames.UniformNameSuffix; + } + + public static string GetSamplerName(GalShaderType shaderType, AstTextureOperation texOp) + { + string suffix; + + if ((texOp.Flags & TextureFlags.Bindless) != 0) + { + AstOperand operand = texOp.GetSource(0) as AstOperand; + + suffix = "_cb" + operand.CbufSlot + "_" + operand.CbufOffset; + } + else + { + suffix = (texOp.Handle - 8).ToString(); + } + + return GetShaderStagePrefix(shaderType) + "_" + DefaultNames.SamplerNamePrefix + suffix; + } + + public static string GetShaderStagePrefix(GalShaderType shaderType) + { + return _stagePrefixes[(int)shaderType]; + } + + private static string GetSwizzleMask(int value) + { + return "xyzw".Substring(value, 1); + } + + public static VariableType GetNodeDestType(IAstNode node) + { + if (node is AstOperation operation) + { + return GetDestVarType(operation.Inst); + } + else if (node is AstOperand operand) + { + if (operand.Type == OperandType.Attribute) + { + if (_builtInAttributes.TryGetValue(operand.Value & ~3, out BuiltInAttribute builtInAttr)) + { + return builtInAttr.Type; + } + } + + return OperandInfo.GetVarType(operand); + } + else + { + throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\"."); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/CodeGen/Glsl/TypeConversion.cs b/Ryujinx.Graphics/Shader/CodeGen/Glsl/TypeConversion.cs new file mode 100644 index 0000000000..7adc5ad339 --- /dev/null +++ b/Ryujinx.Graphics/Shader/CodeGen/Glsl/TypeConversion.cs @@ -0,0 +1,85 @@ +using Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; +using System; + +namespace Ryujinx.Graphics.Shader.CodeGen.Glsl +{ + static class TypeConversion + { + public static string ReinterpretCast( + CodeGenContext context, + IAstNode node, + VariableType srcType, + VariableType dstType) + { + if (node is AstOperand operand && operand.Type == OperandType.Constant) + { + if (NumberFormatter.TryFormat(operand.Value, dstType, out string formatted)) + { + return formatted; + } + } + + string expr = InstGen.GetExpression(context, node); + + return ReinterpretCast(expr, node, srcType, dstType); + } + + private static string ReinterpretCast(string expr, IAstNode node, VariableType srcType, VariableType dstType) + { + if (srcType == dstType) + { + return expr; + } + + if (srcType == VariableType.F32) + { + switch (dstType) + { + case VariableType.S32: return $"floatBitsToInt({expr})"; + case VariableType.U32: return $"floatBitsToUint({expr})"; + } + } + else if (dstType == VariableType.F32) + { + switch (srcType) + { + case VariableType.Bool: return $"intBitsToFloat({ReinterpretBoolToInt(expr, node, VariableType.S32)})"; + case VariableType.S32: return $"intBitsToFloat({expr})"; + case VariableType.U32: return $"uintBitsToFloat({expr})"; + } + } + else if (srcType == VariableType.Bool) + { + return ReinterpretBoolToInt(expr, node, dstType); + } + else if (dstType == VariableType.Bool) + { + expr = InstGenHelper.Enclose(expr, node, Instruction.CompareNotEqual, isLhs: true); + + return $"({expr} != 0)"; + } + else if (dstType == VariableType.S32) + { + return $"int({expr})"; + } + else if (dstType == VariableType.U32) + { + return $"uint({expr})"; + } + + throw new ArgumentException($"Invalid reinterpret cast from \"{srcType}\" to \"{dstType}\"."); + } + + private static string ReinterpretBoolToInt(string expr, IAstNode node, VariableType dstType) + { + string trueExpr = NumberFormatter.FormatInt(IrConsts.True, dstType); + string falseExpr = NumberFormatter.FormatInt(IrConsts.False, dstType); + + expr = InstGenHelper.Enclose(expr, node, Instruction.ConditionalSelect, isLhs: false); + + return $"({expr} ? {trueExpr} : {falseExpr})"; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/BitfieldExtensions.cs b/Ryujinx.Graphics/Shader/Decoders/BitfieldExtensions.cs new file mode 100644 index 0000000000..3bb9bc1f4c --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/BitfieldExtensions.cs @@ -0,0 +1,25 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + static class BitfieldExtensions + { + public static bool Extract(this int value, int lsb) + { + return ((int)(value >> lsb) & 1) != 0; + } + + public static int Extract(this int value, int lsb, int length) + { + return (int)(value >> lsb) & (int)(uint.MaxValue >> (32 - length)); + } + + public static bool Extract(this long value, int lsb) + { + return ((int)(value >> lsb) & 1) != 0; + } + + public static int Extract(this long value, int lsb, int length) + { + return (int)(value >> lsb) & (int)(uint.MaxValue >> (32 - length)); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/Block.cs b/Ryujinx.Graphics/Shader/Decoders/Block.cs new file mode 100644 index 0000000000..b5e610d713 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/Block.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class Block + { + public ulong Address { get; set; } + public ulong EndAddress { get; set; } + + public Block Next { get; set; } + public Block Branch { get; set; } + + public List OpCodes { get; } + public List SsyOpCodes { get; } + + public Block(ulong address) + { + Address = address; + + OpCodes = new List(); + SsyOpCodes = new List(); + } + + public void Split(Block rightBlock) + { + int splitIndex = BinarySearch(OpCodes, rightBlock.Address); + + if (OpCodes[splitIndex].Address < rightBlock.Address) + { + splitIndex++; + } + + int splitCount = OpCodes.Count - splitIndex; + + if (splitCount <= 0) + { + throw new ArgumentException("Can't split at right block address."); + } + + rightBlock.EndAddress = EndAddress; + + rightBlock.Next = Next; + rightBlock.Branch = Branch; + + rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount)); + + rightBlock.UpdateSsyOpCodes(); + + EndAddress = rightBlock.Address; + + Next = rightBlock; + Branch = null; + + OpCodes.RemoveRange(splitIndex, splitCount); + + UpdateSsyOpCodes(); + } + + private static int BinarySearch(List opCodes, ulong address) + { + int left = 0; + int middle = 0; + int right = opCodes.Count - 1; + + while (left <= right) + { + int size = right - left; + + middle = left + (size >> 1); + + OpCode opCode = opCodes[middle]; + + if (address == opCode.Address) + { + break; + } + + if (address < opCode.Address) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + return middle; + } + + public OpCode GetLastOp() + { + if (OpCodes.Count != 0) + { + return OpCodes[OpCodes.Count - 1]; + } + + return null; + } + + public void UpdateSsyOpCodes() + { + SsyOpCodes.Clear(); + + for (int index = 0; index < OpCodes.Count; index++) + { + if (!(OpCodes[index] is OpCodeSsy op)) + { + continue; + } + + SsyOpCodes.Add(op); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/Condition.cs b/Ryujinx.Graphics/Shader/Decoders/Condition.cs new file mode 100644 index 0000000000..10400f94ac --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/Condition.cs @@ -0,0 +1,45 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum Condition + { + Less = 1 << 0, + Equal = 1 << 1, + Greater = 1 << 2, + Nan = 1 << 3, + Unsigned = 1 << 4, + + Never = 0, + + LessOrEqual = Less | Equal, + NotEqual = Less | Greater, + GreaterOrEqual = Greater | Equal, + Number = Greater | Equal | Less, + + LessUnordered = Less | Nan, + EqualUnordered = Equal | Nan, + LessOrEqualUnordered = LessOrEqual | Nan, + GreaterUnordered = Greater | Nan, + NotEqualUnordered = NotEqual | Nan, + GreaterOrEqualUnordered = GreaterOrEqual | Nan, + + Always = 0xf, + + Off = Unsigned | Never, + Lower = Unsigned | Less, + Sff = Unsigned | Equal, + LowerOrSame = Unsigned | LessOrEqual, + Higher = Unsigned | Greater, + Sft = Unsigned | NotEqual, + HigherOrSame = Unsigned | GreaterOrEqual, + Oft = Unsigned | Always, + + CsmTa = 0x18, + CsmTr = 0x19, + CsmMx = 0x1a, + FcsmTa = 0x1b, + FcsmTr = 0x1c, + FcsmMx = 0x1d, + Rle = 0x1e, + Rgt = 0x1f + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/ConditionalOperation.cs b/Ryujinx.Graphics/Shader/Decoders/ConditionalOperation.cs new file mode 100644 index 0000000000..4fc31e842b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/ConditionalOperation.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum ConditionalOperation + { + False = 0, + True = 1, + Zero = 2, + NotZero = 3 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/Decoder.cs b/Ryujinx.Graphics/Shader/Decoders/Decoder.cs new file mode 100644 index 0000000000..86df3b203d --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/Decoder.cs @@ -0,0 +1,406 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Shader.Instructions; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + static class Decoder + { + private const long HeaderSize = 0x50; + + private delegate object OpActivator(InstEmitter emitter, ulong address, long opCode); + + private static ConcurrentDictionary _opActivators; + + static Decoder() + { + _opActivators = new ConcurrentDictionary(); + } + + public static Block[] Decode(IGalMemory memory, ulong address) + { + List blocks = new List(); + + Queue workQueue = new Queue(); + + Dictionary visited = new Dictionary(); + + Block GetBlock(ulong blkAddress) + { + if (!visited.TryGetValue(blkAddress, out Block block)) + { + block = new Block(blkAddress); + + workQueue.Enqueue(block); + + visited.Add(blkAddress, block); + } + + return block; + } + + ulong startAddress = address + HeaderSize; + + GetBlock(startAddress); + + while (workQueue.TryDequeue(out Block currBlock)) + { + //Check if the current block is inside another block. + if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex)) + { + Block nBlock = blocks[nBlkIndex]; + + if (nBlock.Address == currBlock.Address) + { + throw new InvalidOperationException("Found duplicate block address on the list."); + } + + nBlock.Split(currBlock); + + blocks.Insert(nBlkIndex + 1, currBlock); + + continue; + } + + //If we have a block after the current one, set the limit address. + ulong limitAddress = ulong.MaxValue; + + if (nBlkIndex != blocks.Count) + { + Block nBlock = blocks[nBlkIndex]; + + int nextIndex = nBlkIndex + 1; + + if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count) + { + limitAddress = blocks[nextIndex].Address; + } + else if (nBlock.Address > currBlock.Address) + { + limitAddress = blocks[nBlkIndex].Address; + } + } + + FillBlock(memory, currBlock, limitAddress, startAddress); + + if (currBlock.OpCodes.Count != 0) + { + foreach (OpCodeSsy ssyOp in currBlock.SsyOpCodes) + { + GetBlock(ssyOp.GetAbsoluteAddress()); + } + + //Set child blocks. "Branch" is the block the branch instruction + //points to (when taken), "Next" is the block at the next address, + //executed when the branch is not taken. For Unconditional Branches + //or end of program, Next is null. + OpCode lastOp = currBlock.GetLastOp(); + + if (lastOp is OpCodeBranch op) + { + currBlock.Branch = GetBlock(op.GetAbsoluteAddress()); + } + + if (!IsUnconditionalBranch(lastOp)) + { + currBlock.Next = GetBlock(currBlock.EndAddress); + } + } + + //Insert the new block on the list (sorted by address). + if (blocks.Count != 0) + { + Block nBlock = blocks[nBlkIndex]; + + blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock); + } + else + { + blocks.Add(currBlock); + } + } + + foreach (Block ssyBlock in blocks.Where(x => x.SsyOpCodes.Count != 0)) + { + for (int ssyIndex = 0; ssyIndex < ssyBlock.SsyOpCodes.Count; ssyIndex++) + { + PropagateSsy(visited, ssyBlock, ssyIndex); + } + } + + return blocks.ToArray(); + } + + private static bool BinarySearch(List blocks, ulong address, out int index) + { + index = 0; + + int left = 0; + int right = blocks.Count - 1; + + while (left <= right) + { + int size = right - left; + + int middle = left + (size >> 1); + + Block block = blocks[middle]; + + index = middle; + + if (address >= block.Address && address < block.EndAddress) + { + return true; + } + + if (address < block.Address) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + return false; + } + + private static void FillBlock( + IGalMemory memory, + Block block, + ulong limitAddress, + ulong startAddress) + { + ulong address = block.Address; + + do + { + if (address >= limitAddress) + { + break; + } + + //Ignore scheduling instructions, which are written every 32 bytes. + if (((address - startAddress) & 0x1f) == 0) + { + address += 8; + + continue; + } + + uint word0 = (uint)memory.ReadInt32((long)(address + 0)); + uint word1 = (uint)memory.ReadInt32((long)(address + 4)); + + ulong opAddress = address; + + address += 8; + + long opCode = word0 | (long)word1 << 32; + + (InstEmitter emitter, Type opCodeType) = OpCodeTable.GetEmitter(opCode); + + if (emitter == null) + { + //TODO: Warning, illegal encoding. + continue; + } + + OpCode op = MakeOpCode(opCodeType, emitter, opAddress, opCode); + + block.OpCodes.Add(op); + } + while (!IsBranch(block.GetLastOp())); + + block.EndAddress = address; + + block.UpdateSsyOpCodes(); + } + + private static bool IsUnconditionalBranch(OpCode opCode) + { + return IsUnconditional(opCode) && IsBranch(opCode); + } + + private static bool IsUnconditional(OpCode opCode) + { + if (opCode is OpCodeExit op && op.Condition != Condition.Always) + { + return false; + } + + return opCode.Predicate.Index == RegisterConsts.PredicateTrueIndex && !opCode.InvertPredicate; + } + + private static bool IsBranch(OpCode opCode) + { + return (opCode is OpCodeBranch && opCode.Emitter != InstEmit.Ssy) || + opCode is OpCodeSync || + opCode is OpCodeExit; + } + + private static OpCode MakeOpCode(Type type, InstEmitter emitter, ulong address, long opCode) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + OpActivator createInstance = _opActivators.GetOrAdd(type, CacheOpActivator); + + return (OpCode)createInstance(emitter, address, opCode); + } + + private static OpActivator CacheOpActivator(Type type) + { + Type[] argTypes = new Type[] { typeof(InstEmitter), typeof(ulong), typeof(long) }; + + DynamicMethod mthd = new DynamicMethod($"Make{type.Name}", type, argTypes); + + ILGenerator generator = mthd.GetILGenerator(); + + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldarg_1); + generator.Emit(OpCodes.Ldarg_2); + generator.Emit(OpCodes.Newobj, type.GetConstructor(argTypes)); + generator.Emit(OpCodes.Ret); + + return (OpActivator)mthd.CreateDelegate(typeof(OpActivator)); + } + + private struct PathBlockState + { + public Block Block { get; } + + private enum RestoreType + { + None, + PopSsy, + PushSync + } + + private RestoreType _restoreType; + + private ulong _restoreValue; + + public bool ReturningFromVisit => _restoreType != RestoreType.None; + + public PathBlockState(Block block) + { + Block = block; + _restoreType = RestoreType.None; + _restoreValue = 0; + } + + public PathBlockState(int oldSsyStackSize) + { + Block = null; + _restoreType = RestoreType.PopSsy; + _restoreValue = (ulong)oldSsyStackSize; + } + + public PathBlockState(ulong syncAddress) + { + Block = null; + _restoreType = RestoreType.PushSync; + _restoreValue = syncAddress; + } + + public void RestoreStackState(Stack ssyStack) + { + if (_restoreType == RestoreType.PushSync) + { + ssyStack.Push(_restoreValue); + } + else if (_restoreType == RestoreType.PopSsy) + { + while (ssyStack.Count > (uint)_restoreValue) + { + ssyStack.Pop(); + } + } + } + } + + private static void PropagateSsy(Dictionary blocks, Block ssyBlock, int ssyIndex) + { + OpCodeSsy ssyOp = ssyBlock.SsyOpCodes[ssyIndex]; + + Stack workQueue = new Stack(); + + HashSet visited = new HashSet(); + + Stack ssyStack = new Stack(); + + void Push(PathBlockState pbs) + { + if (pbs.Block == null || visited.Add(pbs.Block)) + { + workQueue.Push(pbs); + } + } + + Push(new PathBlockState(ssyBlock)); + + while (workQueue.TryPop(out PathBlockState pbs)) + { + if (pbs.ReturningFromVisit) + { + pbs.RestoreStackState(ssyStack); + + continue; + } + + Block current = pbs.Block; + + int ssyOpCodesCount = current.SsyOpCodes.Count; + + if (ssyOpCodesCount != 0) + { + Push(new PathBlockState(ssyStack.Count)); + + for (int index = ssyIndex; index < ssyOpCodesCount; index++) + { + ssyStack.Push(current.SsyOpCodes[index].GetAbsoluteAddress()); + } + } + + ssyIndex = 0; + + if (current.Next != null) + { + Push(new PathBlockState(current.Next)); + } + + if (current.Branch != null) + { + Push(new PathBlockState(current.Branch)); + } + else if (current.GetLastOp() is OpCodeSync op) + { + ulong syncAddress = ssyStack.Pop(); + + if (ssyStack.Count == 0) + { + ssyStack.Push(syncAddress); + + op.Targets.Add(ssyOp, op.Targets.Count); + + ssyOp.Syncs.TryAdd(op, Local()); + } + else + { + Push(new PathBlockState(syncAddress)); + Push(new PathBlockState(blocks[syncAddress])); + } + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/DecoderHelper.cs b/Ryujinx.Graphics/Shader/Decoders/DecoderHelper.cs new file mode 100644 index 0000000000..fd0a45e82b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/DecoderHelper.cs @@ -0,0 +1,58 @@ +using System; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + static class DecoderHelper + { + public static int DecodeS20Immediate(long opCode) + { + int imm = opCode.Extract(20, 19); + + bool negate = opCode.Extract(56); + + if (negate) + { + imm = -imm; + } + + return imm; + } + + public static int Decode2xF10Immediate(long opCode) + { + int immH0 = opCode.Extract(20, 9); + int immH1 = opCode.Extract(30, 9); + + bool negateH0 = opCode.Extract(29); + bool negateH1 = opCode.Extract(56); + + if (negateH0) + { + immH0 |= 1 << 9; + } + + if (negateH1) + { + immH1 |= 1 << 9; + } + + return immH1 << 22 | immH0 << 6; + } + + public static float DecodeF20Immediate(long opCode) + { + int imm = opCode.Extract(20, 19); + + bool negate = opCode.Extract(56); + + imm <<= 12; + + if (negate) + { + imm |= 1 << 31; + } + + return BitConverter.Int32BitsToSingle(imm); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/FPHalfSwizzle.cs b/Ryujinx.Graphics/Shader/Decoders/FPHalfSwizzle.cs new file mode 100644 index 0000000000..3ddf17cfcc --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/FPHalfSwizzle.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum FPHalfSwizzle + { + FP16 = 0, + FP32 = 1, + DupH0 = 2, + DupH1 = 3 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/FPType.cs b/Ryujinx.Graphics/Shader/Decoders/FPType.cs new file mode 100644 index 0000000000..e602ad45fa --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/FPType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum FPType + { + FP16 = 1, + FP32 = 2, + FP64 = 3 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/FmulScale.cs b/Ryujinx.Graphics/Shader/Decoders/FmulScale.cs new file mode 100644 index 0000000000..c35c6e489e --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/FmulScale.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum FmulScale + { + None = 0, + Divide2 = 1, + Divide4 = 2, + Divide8 = 3, + Multiply8 = 4, + Multiply4 = 5, + Multiply2 = 6 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCode.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCode.cs new file mode 100644 index 0000000000..dd6ad79a2e --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCode.cs @@ -0,0 +1,16 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCode + { + InstEmitter Emitter { get; } + + ulong Address { get; } + long RawOpCode { get; } + + Register Predicate { get; } + + bool InvertPredicate { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeAlu.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeAlu.cs new file mode 100644 index 0000000000..d840d49d1b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeAlu.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeAlu : IOpCodeRd, IOpCodeRa + { + Register Predicate39 { get; } + + bool InvertP { get; } + bool Extended { get; } + bool SetCondCode { get; } + bool Saturate { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeCbuf.cs new file mode 100644 index 0000000000..42a174514c --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeCbuf.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeCbuf : IOpCode + { + int Offset { get; } + int Slot { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeFArith.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeFArith.cs new file mode 100644 index 0000000000..d68ccf593b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeFArith.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeFArith : IOpCodeAlu + { + RoundingMode RoundingMode { get; } + + FmulScale Scale { get; } + + bool FlushToZero { get; } + bool AbsoluteA { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeHfma.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeHfma.cs new file mode 100644 index 0000000000..4638f66086 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeHfma.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeHfma : IOpCode + { + bool NegateB { get; } + bool NegateC { get; } + bool Saturate { get; } + + FPHalfSwizzle SwizzleA { get; } + FPHalfSwizzle SwizzleB { get; } + FPHalfSwizzle SwizzleC { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeImm.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeImm.cs new file mode 100644 index 0000000000..9cfcd69b05 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeImm.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeImm : IOpCode + { + int Immediate { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeImmF.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeImmF.cs new file mode 100644 index 0000000000..629eff7973 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeImmF.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeImmF : IOpCode + { + float Immediate { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeLop.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeLop.cs new file mode 100644 index 0000000000..62c87bf435 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeLop.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeLop : IOpCodeAlu + { + LogicalOperation LogicalOp { get; } + + bool InvertA { get; } + bool InvertB { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeRa.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeRa.cs new file mode 100644 index 0000000000..e5902110e5 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeRa.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeRa : IOpCode + { + Register Ra { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeRc.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeRc.cs new file mode 100644 index 0000000000..bb806b95c9 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeRc.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeRc : IOpCode + { + Register Rc { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeRd.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeRd.cs new file mode 100644 index 0000000000..099c4061ab --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeRd.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeRd : IOpCode + { + Register Rd { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeReg.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeReg.cs new file mode 100644 index 0000000000..3ed157e821 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeReg.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeReg : IOpCode + { + Register Rb { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IOpCodeRegCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/IOpCodeRegCbuf.cs new file mode 100644 index 0000000000..429f01bb7f --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IOpCodeRegCbuf.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + interface IOpCodeRegCbuf : IOpCodeRc + { + int Offset { get; } + int Slot { get; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IntegerCondition.cs b/Ryujinx.Graphics/Shader/Decoders/IntegerCondition.cs new file mode 100644 index 0000000000..a1937c2f52 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IntegerCondition.cs @@ -0,0 +1,18 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum IntegerCondition + { + Less = 1 << 0, + Equal = 1 << 1, + Greater = 1 << 2, + + Never = 0, + + LessOrEqual = Less | Equal, + NotEqual = Less | Greater, + GreaterOrEqual = Greater | Equal, + Number = Greater | Equal | Less, + + Always = 7 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IntegerHalfPart.cs b/Ryujinx.Graphics/Shader/Decoders/IntegerHalfPart.cs new file mode 100644 index 0000000000..b779f44d4b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IntegerHalfPart.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum IntegerHalfPart + { + B32 = 0, + H0 = 1, + H1 = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IntegerShift.cs b/Ryujinx.Graphics/Shader/Decoders/IntegerShift.cs new file mode 100644 index 0000000000..ce4d9f3bb6 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IntegerShift.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum IntegerShift + { + NoShift = 0, + ShiftRight = 1, + ShiftLeft = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IntegerSize.cs b/Ryujinx.Graphics/Shader/Decoders/IntegerSize.cs new file mode 100644 index 0000000000..70fdfc3dc9 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IntegerSize.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum IntegerSize + { + U8 = 0, + S8 = 1, + U16 = 2, + S16 = 3, + B32 = 4, + B64 = 5 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/IntegerType.cs b/Ryujinx.Graphics/Shader/Decoders/IntegerType.cs new file mode 100644 index 0000000000..46734dbe4a --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/IntegerType.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum IntegerType + { + U8 = 0, + U16 = 1, + U32 = 2, + U64 = 3, + S8 = 4, + S16 = 5, + S32 = 6, + S64 = 7 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/LogicalOperation.cs b/Ryujinx.Graphics/Shader/Decoders/LogicalOperation.cs new file mode 100644 index 0000000000..5221442510 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/LogicalOperation.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum LogicalOperation + { + And = 0, + Or = 1, + ExclusiveOr = 2, + Passthrough = 3 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/MufuOperation.cs b/Ryujinx.Graphics/Shader/Decoders/MufuOperation.cs new file mode 100644 index 0000000000..88bd1f5cea --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/MufuOperation.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum MufuOperation + { + Cosine = 0, + Sine = 1, + ExponentB2 = 2, + LogarithmB2 = 3, + Reciprocal = 4, + ReciprocalSquareRoot = 5, + Reciprocal64H = 6, + ReciprocalSquareRoot64H = 7, + SquareRoot = 8 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCode.cs b/Ryujinx.Graphics/Shader/Decoders/OpCode.cs new file mode 100644 index 0000000000..b0f2ffdc32 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCode.cs @@ -0,0 +1,30 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCode + { + public InstEmitter Emitter { get; } + + public ulong Address { get; } + public long RawOpCode { get; } + + public Register Predicate { get; protected set; } + + public bool InvertPredicate { get; protected set; } + + //When inverted, the always true predicate == always false. + public bool NeverExecute => Predicate.Index == RegisterConsts.PredicateTrueIndex && InvertPredicate; + + public OpCode(InstEmitter emitter, ulong address, long opCode) + { + Emitter = emitter; + Address = address; + RawOpCode = opCode; + + Predicate = new Register(opCode.Extract(16, 3), RegisterType.Predicate); + + InvertPredicate = opCode.Extract(19); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeAlu.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeAlu.cs new file mode 100644 index 0000000000..15fbb9af79 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeAlu.cs @@ -0,0 +1,34 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeAlu : OpCode, IOpCodeAlu, IOpCodeRc + { + public Register Rd { get; } + public Register Ra { get; } + public Register Rc { get; } + public Register Predicate39 { get; } + + public int ByteSelection { get; } + + public bool InvertP { get; } + public bool Extended { get; protected set; } + public bool SetCondCode { get; protected set; } + public bool Saturate { get; protected set; } + + public OpCodeAlu(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr); + Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr); + Rc = new Register(opCode.Extract(39, 8), RegisterType.Gpr); + Predicate39 = new Register(opCode.Extract(39, 3), RegisterType.Predicate); + + ByteSelection = opCode.Extract(41, 2); + + InvertP = opCode.Extract(42); + Extended = opCode.Extract(43); + SetCondCode = opCode.Extract(47); + Saturate = opCode.Extract(50); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeAluCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluCbuf.cs new file mode 100644 index 0000000000..9c12798947 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluCbuf.cs @@ -0,0 +1,16 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeAluCbuf : OpCodeAlu, IOpCodeCbuf + { + public int Offset { get; } + public int Slot { get; } + + public OpCodeAluCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = opCode.Extract(20, 14); + Slot = opCode.Extract(34, 5); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm.cs new file mode 100644 index 0000000000..a407fc6bf8 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeAluImm : OpCodeAlu, IOpCodeImm + { + public int Immediate { get; } + + public OpCodeAluImm(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = DecoderHelper.DecodeS20Immediate(opCode); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm2x10.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm2x10.cs new file mode 100644 index 0000000000..9aeb32bd4d --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm2x10.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeAluImm2x10 : OpCodeAlu, IOpCodeImm + { + public int Immediate { get; } + + public OpCodeAluImm2x10(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = DecoderHelper.Decode2xF10Immediate(opCode); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm32.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm32.cs new file mode 100644 index 0000000000..5941e0b9a2 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm32.cs @@ -0,0 +1,18 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeAluImm32 : OpCodeAlu, IOpCodeImm + { + public int Immediate { get; } + + public OpCodeAluImm32(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = opCode.Extract(20, 32); + + SetCondCode = opCode.Extract(52); + Extended = opCode.Extract(53); + Saturate = opCode.Extract(54); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeAluReg.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluReg.cs new file mode 100644 index 0000000000..13b96a3ae8 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluReg.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeAluReg : OpCodeAlu, IOpCodeReg + { + public Register Rb { get; protected set; } + + public OpCodeAluReg(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeAluRegCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluRegCbuf.cs new file mode 100644 index 0000000000..6cf6bd2e22 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeAluRegCbuf.cs @@ -0,0 +1,18 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeAluRegCbuf : OpCodeAluReg, IOpCodeRegCbuf + { + public int Offset { get; } + public int Slot { get; } + + public OpCodeAluRegCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = opCode.Extract(20, 14); + Slot = opCode.Extract(34, 5); + + Rb = new Register(opCode.Extract(39, 8), RegisterType.Gpr); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeAttribute.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeAttribute.cs new file mode 100644 index 0000000000..fd8e63fcfb --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeAttribute.cs @@ -0,0 +1,16 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeAttribute : OpCodeAluReg + { + public int AttributeOffset { get; } + public int Count { get; } + + public OpCodeAttribute(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + AttributeOffset = opCode.Extract(20, 10); + Count = opCode.Extract(47, 2) + 1; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeBranch.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeBranch.cs new file mode 100644 index 0000000000..25941b3967 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeBranch.cs @@ -0,0 +1,19 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeBranch : OpCode + { + public int Offset { get; } + + public OpCodeBranch(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = ((int)(opCode >> 20) << 8) >> 8; + } + + public ulong GetAbsoluteAddress() + { + return (ulong)((long)Address + (long)Offset + 8); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeExit.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeExit.cs new file mode 100644 index 0000000000..d50903eb4f --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeExit.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeExit : OpCode + { + public Condition Condition { get; } + + public OpCodeExit(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Condition = (Condition)opCode.Extract(0, 5); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeFArith.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArith.cs new file mode 100644 index 0000000000..c88f7f0ee3 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArith.cs @@ -0,0 +1,24 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeFArith : OpCodeAlu, IOpCodeFArith + { + public RoundingMode RoundingMode { get; } + + public FmulScale Scale { get; } + + public bool FlushToZero { get; } + public bool AbsoluteA { get; } + + public OpCodeFArith(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + RoundingMode = (RoundingMode)opCode.Extract(39, 2); + + Scale = (FmulScale)opCode.Extract(41, 3); + + FlushToZero = opCode.Extract(44); + AbsoluteA = opCode.Extract(46); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithCbuf.cs new file mode 100644 index 0000000000..5486bb0b07 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithCbuf.cs @@ -0,0 +1,16 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeFArithCbuf : OpCodeFArith, IOpCodeCbuf + { + public int Offset { get; } + public int Slot { get; } + + public OpCodeFArithCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = opCode.Extract(20, 14); + Slot = opCode.Extract(34, 5); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm.cs new file mode 100644 index 0000000000..1bb6f42552 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeFArithImm : OpCodeFArith, IOpCodeImmF + { + public float Immediate { get; } + + public OpCodeFArithImm(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = DecoderHelper.DecodeF20Immediate(opCode); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm32.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm32.cs new file mode 100644 index 0000000000..ec9da6f302 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm32.cs @@ -0,0 +1,30 @@ +using Ryujinx.Graphics.Shader.Instructions; +using System; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeFArithImm32 : OpCodeAlu, IOpCodeFArith, IOpCodeImmF + { + public RoundingMode RoundingMode => RoundingMode.ToNearest; + + public FmulScale Scale => FmulScale.None; + + public bool FlushToZero { get; } + public bool AbsoluteA { get; } + + public float Immediate { get; } + + public OpCodeFArithImm32(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + int imm = opCode.Extract(20, 32); + + Immediate = BitConverter.Int32BitsToSingle(imm); + + SetCondCode = opCode.Extract(52); + AbsoluteA = opCode.Extract(54); + FlushToZero = opCode.Extract(55); + + Saturate = false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithReg.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithReg.cs new file mode 100644 index 0000000000..55cf448597 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithReg.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeFArithReg : OpCodeFArith, IOpCodeReg + { + public Register Rb { get; protected set; } + + public OpCodeFArithReg(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithRegCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithRegCbuf.cs new file mode 100644 index 0000000000..315c2c8b15 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeFArithRegCbuf.cs @@ -0,0 +1,16 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeFArithRegCbuf : OpCodeFArith, IOpCodeRegCbuf + { + public int Offset { get; } + public int Slot { get; } + + public OpCodeFArithRegCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = opCode.Extract(20, 14); + Slot = opCode.Extract(34, 5); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeFsetImm.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeFsetImm.cs new file mode 100644 index 0000000000..cb5f155e82 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeFsetImm.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeFsetImm : OpCodeSet, IOpCodeImmF + { + public float Immediate { get; } + + public OpCodeFsetImm(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = DecoderHelper.DecodeF20Immediate(opCode); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeHfma.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfma.cs new file mode 100644 index 0000000000..32f3cd7ab8 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfma.cs @@ -0,0 +1,22 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeHfma : OpCode, IOpCodeRd, IOpCodeRa, IOpCodeRc + { + public Register Rd { get; } + public Register Ra { get; } + public Register Rc { get; protected set; } + + public FPHalfSwizzle SwizzleA { get; } + + public OpCodeHfma(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr); + Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr); + Rc = new Register(opCode.Extract(39, 8), RegisterType.Gpr); + + SwizzleA = (FPHalfSwizzle)opCode.Extract(47, 2); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaCbuf.cs new file mode 100644 index 0000000000..33768c7d01 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaCbuf.cs @@ -0,0 +1,30 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeHfmaCbuf : OpCodeHfma, IOpCodeHfma, IOpCodeCbuf + { + public int Offset { get; } + public int Slot { get; } + + public bool NegateB { get; } + public bool NegateC { get; } + public bool Saturate { get; } + + public FPHalfSwizzle SwizzleB => FPHalfSwizzle.FP32; + public FPHalfSwizzle SwizzleC { get; } + + public OpCodeHfmaCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = opCode.Extract(20, 14); + Slot = opCode.Extract(34, 5); + + NegateC = opCode.Extract(51); + Saturate = opCode.Extract(52); + + SwizzleC = (FPHalfSwizzle)opCode.Extract(53, 2); + + NegateB = opCode.Extract(56); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaImm2x10.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaImm2x10.cs new file mode 100644 index 0000000000..80a5a14089 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaImm2x10.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeHfmaImm2x10 : OpCodeHfma, IOpCodeHfma, IOpCodeImm + { + public int Immediate { get; } + + public bool NegateB => false; + public bool NegateC { get; } + public bool Saturate { get; } + + public FPHalfSwizzle SwizzleB => FPHalfSwizzle.FP16; + public FPHalfSwizzle SwizzleC { get; } + + public OpCodeHfmaImm2x10(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = DecoderHelper.Decode2xF10Immediate(opCode); + + NegateC = opCode.Extract(51); + Saturate = opCode.Extract(52); + + SwizzleC = (FPHalfSwizzle)opCode.Extract(53, 2); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaImm32.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaImm32.cs new file mode 100644 index 0000000000..05eb9ffe0a --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaImm32.cs @@ -0,0 +1,25 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeHfmaImm32 : OpCodeHfma, IOpCodeHfma, IOpCodeImm + { + public int Immediate { get; } + + public bool NegateB => false; + public bool NegateC { get; } + public bool Saturate => false; + + public FPHalfSwizzle SwizzleB => FPHalfSwizzle.FP16; + public FPHalfSwizzle SwizzleC => FPHalfSwizzle.FP16; + + public OpCodeHfmaImm32(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = opCode.Extract(20, 32); + + NegateC = opCode.Extract(52); + + Rc = Rd; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaReg.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaReg.cs new file mode 100644 index 0000000000..714c89dead --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaReg.cs @@ -0,0 +1,29 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeHfmaReg : OpCodeHfma, IOpCodeHfma, IOpCodeReg + { + public Register Rb { get; } + + public bool NegateB { get; } + public bool NegateC { get; } + public bool Saturate { get; } + + public FPHalfSwizzle SwizzleB { get; } + public FPHalfSwizzle SwizzleC { get; } + + public OpCodeHfmaReg(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr); + + SwizzleB = (FPHalfSwizzle)opCode.Extract(28, 2); + + NegateC = opCode.Extract(30); + NegateB = opCode.Extract(31); + Saturate = opCode.Extract(32); + + SwizzleC = (FPHalfSwizzle)opCode.Extract(35, 2); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaRegCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaRegCbuf.cs new file mode 100644 index 0000000000..c0001908ce --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeHfmaRegCbuf.cs @@ -0,0 +1,30 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeHfmaRegCbuf : OpCodeHfma, IOpCodeHfma, IOpCodeRegCbuf + { + public int Offset { get; } + public int Slot { get; } + + public bool NegateB { get; } + public bool NegateC { get; } + public bool Saturate { get; } + + public FPHalfSwizzle SwizzleB { get; } + public FPHalfSwizzle SwizzleC => FPHalfSwizzle.FP32; + + public OpCodeHfmaRegCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = opCode.Extract(20, 14); + Slot = opCode.Extract(34, 5); + + NegateC = opCode.Extract(51); + Saturate = opCode.Extract(52); + + SwizzleB = (FPHalfSwizzle)opCode.Extract(53, 2); + + NegateB = opCode.Extract(56); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeIpa.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeIpa.cs new file mode 100644 index 0000000000..e21095a325 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeIpa.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeIpa : OpCodeAluReg + { + public int AttributeOffset { get; } + + public OpCodeIpa(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + AttributeOffset = opCode.Extract(28, 10); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeLdc.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeLdc.cs new file mode 100644 index 0000000000..cc9f065828 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeLdc.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeLdc : OpCode, IOpCodeRd, IOpCodeRa, IOpCodeCbuf + { + public Register Rd { get; } + public Register Ra { get; } + + public int Offset { get; } + public int Slot { get; } + + public IntegerSize Size { get; } + + public OpCodeLdc(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr); + Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr); + + Offset = opCode.Extract(22, 14); + Slot = opCode.Extract(36, 5); + + Size = (IntegerSize)opCode.Extract(48, 3); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeLop.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeLop.cs new file mode 100644 index 0000000000..c5f903451b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeLop.cs @@ -0,0 +1,28 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeLop : OpCodeAlu, IOpCodeLop + { + public bool InvertA { get; protected set; } + public bool InvertB { get; protected set; } + + public LogicalOperation LogicalOp { get; } + + public ConditionalOperation CondOp { get; } + + public Register Predicate48 { get; } + + public OpCodeLop(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + InvertA = opCode.Extract(39); + InvertB = opCode.Extract(40); + + LogicalOp = (LogicalOperation)opCode.Extract(41, 2); + + CondOp = (ConditionalOperation)opCode.Extract(44, 2); + + Predicate48 = new Register(opCode.Extract(48, 3), RegisterType.Predicate); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeLopCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeLopCbuf.cs new file mode 100644 index 0000000000..f174733c42 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeLopCbuf.cs @@ -0,0 +1,16 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeLopCbuf : OpCodeLop, IOpCodeCbuf + { + public int Offset { get; } + public int Slot { get; } + + public OpCodeLopCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = opCode.Extract(20, 14); + Slot = opCode.Extract(34, 5); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeLopImm.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeLopImm.cs new file mode 100644 index 0000000000..a2f091a2c4 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeLopImm.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeLopImm : OpCodeLop, IOpCodeImm + { + public int Immediate { get; } + + public OpCodeLopImm(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = DecoderHelper.DecodeS20Immediate(opCode); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeLopImm32.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeLopImm32.cs new file mode 100644 index 0000000000..cb48f3a615 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeLopImm32.cs @@ -0,0 +1,22 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeLopImm32 : OpCodeAluImm32, IOpCodeLop, IOpCodeImm + { + public LogicalOperation LogicalOp { get; } + + public bool InvertA { get; } + public bool InvertB { get; } + + public OpCodeLopImm32(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + LogicalOp = (LogicalOperation)opCode.Extract(53, 2); + + InvertA = opCode.Extract(55); + InvertB = opCode.Extract(56); + + Extended = opCode.Extract(57); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeLopReg.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeLopReg.cs new file mode 100644 index 0000000000..5f43db72b5 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeLopReg.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeLopReg : OpCodeLop, IOpCodeReg + { + public Register Rb { get; } + + public OpCodeLopReg(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodePsetp.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodePsetp.cs new file mode 100644 index 0000000000..729e3207e8 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodePsetp.cs @@ -0,0 +1,20 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodePsetp : OpCodeSet + { + public Register Predicate12 { get; } + public Register Predicate29 { get; } + + public LogicalOperation LogicalOpAB { get; } + + public OpCodePsetp(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Predicate12 = new Register(opCode.Extract(12, 3), RegisterType.Predicate); + Predicate29 = new Register(opCode.Extract(29, 3), RegisterType.Predicate); + + LogicalOpAB = (LogicalOperation)opCode.Extract(24, 2); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeSet.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeSet.cs new file mode 100644 index 0000000000..cd6773a13c --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeSet.cs @@ -0,0 +1,26 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeSet : OpCodeAlu + { + public Register Predicate0 { get; } + public Register Predicate3 { get; } + + public bool NegateP { get; } + + public LogicalOperation LogicalOp { get; } + + public bool FlushToZero { get; } + + public OpCodeSet(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Predicate0 = new Register(opCode.Extract(0, 3), RegisterType.Predicate); + Predicate3 = new Register(opCode.Extract(3, 3), RegisterType.Predicate); + + LogicalOp = (LogicalOperation)opCode.Extract(45, 2); + + FlushToZero = opCode.Extract(47); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeSetCbuf.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeSetCbuf.cs new file mode 100644 index 0000000000..4f3dbd7412 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeSetCbuf.cs @@ -0,0 +1,16 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeSetCbuf : OpCodeSet, IOpCodeCbuf + { + public int Offset { get; } + public int Slot { get; } + + public OpCodeSetCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Offset = opCode.Extract(20, 14); + Slot = opCode.Extract(34, 5); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeSetImm.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeSetImm.cs new file mode 100644 index 0000000000..bc63b9f476 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeSetImm.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeSetImm : OpCodeSet, IOpCodeImm + { + public int Immediate { get; } + + public OpCodeSetImm(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Immediate = DecoderHelper.DecodeS20Immediate(opCode); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeSetReg.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeSetReg.cs new file mode 100644 index 0000000000..bbdee19622 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeSetReg.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeSetReg : OpCodeSet, IOpCodeReg + { + public Register Rb { get; protected set; } + + public OpCodeSetReg(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeSsy.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeSsy.cs new file mode 100644 index 0000000000..499c070689 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeSsy.cs @@ -0,0 +1,20 @@ +using Ryujinx.Graphics.Shader.Instructions; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeSsy : OpCodeBranch + { + public Dictionary Syncs { get; } + + public OpCodeSsy(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Syncs = new Dictionary(); + + Predicate = new Register(RegisterConsts.PredicateTrueIndex, RegisterType.Predicate); + + InvertPredicate = false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeSync.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeSync.cs new file mode 100644 index 0000000000..081d08a0de --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeSync.cs @@ -0,0 +1,15 @@ +using Ryujinx.Graphics.Shader.Instructions; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeSync : OpCode + { + public Dictionary Targets { get; } + + public OpCodeSync(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Targets = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTable.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTable.cs new file mode 100644 index 0000000000..d588ce8ee8 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTable.cs @@ -0,0 +1,216 @@ +using Ryujinx.Graphics.Shader.Instructions; +using System; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + static class OpCodeTable + { + private const int EncodingBits = 14; + + private class TableEntry + { + public InstEmitter Emitter { get; } + + public Type OpCodeType { get; } + + public int XBits { get; } + + public TableEntry(InstEmitter emitter, Type opCodeType, int xBits) + { + Emitter = emitter; + OpCodeType = opCodeType; + XBits = xBits; + } + } + + private static TableEntry[] _opCodes; + + static OpCodeTable() + { + _opCodes = new TableEntry[1 << EncodingBits]; + +#region Instructions + Set("1110111111011x", InstEmit.Ald, typeof(OpCodeAttribute)); + Set("1110111111110x", InstEmit.Ast, typeof(OpCodeAttribute)); + Set("0100110000000x", InstEmit.Bfe, typeof(OpCodeAluCbuf)); + Set("0011100x00000x", InstEmit.Bfe, typeof(OpCodeAluImm)); + Set("0101110000000x", InstEmit.Bfe, typeof(OpCodeAluReg)); + Set("111000100100xx", InstEmit.Bra, typeof(OpCodeBranch)); + Set("111000110000xx", InstEmit.Exit, typeof(OpCodeExit)); + Set("0100110010101x", InstEmit.F2F, typeof(OpCodeFArithCbuf)); + Set("0011100x10101x", InstEmit.F2F, typeof(OpCodeFArithImm)); + Set("0101110010101x", InstEmit.F2F, typeof(OpCodeFArithReg)); + Set("0100110010110x", InstEmit.F2I, typeof(OpCodeFArithCbuf)); + Set("0011100x10110x", InstEmit.F2I, typeof(OpCodeFArithImm)); + Set("0101110010110x", InstEmit.F2I, typeof(OpCodeFArithReg)); + Set("0100110001011x", InstEmit.Fadd, typeof(OpCodeFArithCbuf)); + Set("0011100x01011x", InstEmit.Fadd, typeof(OpCodeFArithImm)); + Set("000010xxxxxxxx", InstEmit.Fadd, typeof(OpCodeFArithImm32)); + Set("0101110001011x", InstEmit.Fadd, typeof(OpCodeFArithReg)); + Set("010010011xxxxx", InstEmit.Ffma, typeof(OpCodeFArithCbuf)); + Set("0011001x1xxxxx", InstEmit.Ffma, typeof(OpCodeFArithImm)); + Set("010100011xxxxx", InstEmit.Ffma, typeof(OpCodeFArithRegCbuf)); + Set("010110011xxxxx", InstEmit.Ffma, typeof(OpCodeFArithReg)); + Set("0100110001100x", InstEmit.Fmnmx, typeof(OpCodeFArithCbuf)); + Set("0011100x01100x", InstEmit.Fmnmx, typeof(OpCodeFArithImm)); + Set("0101110001100x", InstEmit.Fmnmx, typeof(OpCodeFArithReg)); + Set("0100110001101x", InstEmit.Fmul, typeof(OpCodeFArithCbuf)); + Set("0011100x01101x", InstEmit.Fmul, typeof(OpCodeFArithImm)); + Set("00011110xxxxxx", InstEmit.Fmul, typeof(OpCodeFArithImm32)); + Set("0101110001101x", InstEmit.Fmul, typeof(OpCodeFArithReg)); + Set("0100100xxxxxxx", InstEmit.Fset, typeof(OpCodeSetCbuf)); + Set("0011000xxxxxxx", InstEmit.Fset, typeof(OpCodeFsetImm)); + Set("01011000xxxxxx", InstEmit.Fset, typeof(OpCodeSetReg)); + Set("010010111011xx", InstEmit.Fsetp, typeof(OpCodeSetCbuf)); + Set("0011011x1011xx", InstEmit.Fsetp, typeof(OpCodeFsetImm)); + Set("010110111011xx", InstEmit.Fsetp, typeof(OpCodeSetReg)); + Set("0111101x1xxxxx", InstEmit.Hadd2, typeof(OpCodeAluCbuf)); + Set("0111101x0xxxxx", InstEmit.Hadd2, typeof(OpCodeAluImm2x10)); + Set("0010110xxxxxxx", InstEmit.Hadd2, typeof(OpCodeAluImm32)); + Set("0101110100010x", InstEmit.Hadd2, typeof(OpCodeAluReg)); + Set("01110xxx1xxxxx", InstEmit.Hfma2, typeof(OpCodeHfmaCbuf)); + Set("01110xxx0xxxxx", InstEmit.Hfma2, typeof(OpCodeHfmaImm2x10)); + Set("0010100xxxxxxx", InstEmit.Hfma2, typeof(OpCodeHfmaImm32)); + Set("0101110100000x", InstEmit.Hfma2, typeof(OpCodeHfmaReg)); + Set("01100xxx1xxxxx", InstEmit.Hfma2, typeof(OpCodeHfmaRegCbuf)); + Set("0111100x1xxxxx", InstEmit.Hmul2, typeof(OpCodeAluCbuf)); + Set("0111100x0xxxxx", InstEmit.Hmul2, typeof(OpCodeAluImm2x10)); + Set("0010101xxxxxxx", InstEmit.Hmul2, typeof(OpCodeAluImm32)); + Set("0101110100001x", InstEmit.Hmul2, typeof(OpCodeAluReg)); + Set("0100110010111x", InstEmit.I2F, typeof(OpCodeAluCbuf)); + Set("0011100x10111x", InstEmit.I2F, typeof(OpCodeAluImm)); + Set("0101110010111x", InstEmit.I2F, typeof(OpCodeAluReg)); + Set("0100110011100x", InstEmit.I2I, typeof(OpCodeAluCbuf)); + Set("0011100x11100x", InstEmit.I2I, typeof(OpCodeAluImm)); + Set("0101110011100x", InstEmit.I2I, typeof(OpCodeAluReg)); + Set("0100110000010x", InstEmit.Iadd, typeof(OpCodeAluCbuf)); + Set("0011100000010x", InstEmit.Iadd, typeof(OpCodeAluImm)); + Set("0001110x0xxxxx", InstEmit.Iadd, typeof(OpCodeAluImm32)); + Set("0101110000010x", InstEmit.Iadd, typeof(OpCodeAluReg)); + Set("010011001100xx", InstEmit.Iadd3, typeof(OpCodeAluCbuf)); + Set("001110001100xx", InstEmit.Iadd3, typeof(OpCodeAluImm)); + Set("010111001100xx", InstEmit.Iadd3, typeof(OpCodeAluReg)); + Set("0100110000100x", InstEmit.Imnmx, typeof(OpCodeAluCbuf)); + Set("0011100x00100x", InstEmit.Imnmx, typeof(OpCodeAluImm)); + Set("0101110000100x", InstEmit.Imnmx, typeof(OpCodeAluReg)); + Set("11100000xxxxxx", InstEmit.Ipa, typeof(OpCodeIpa)); + Set("0100110000011x", InstEmit.Iscadd, typeof(OpCodeAluCbuf)); + Set("0011100x00011x", InstEmit.Iscadd, typeof(OpCodeAluImm)); + Set("000101xxxxxxxx", InstEmit.Iscadd, typeof(OpCodeAluImm32)); + Set("0101110000011x", InstEmit.Iscadd, typeof(OpCodeAluReg)); + Set("010010110101xx", InstEmit.Iset, typeof(OpCodeSetCbuf)); + Set("001101100101xx", InstEmit.Iset, typeof(OpCodeSetImm)); + Set("010110110101xx", InstEmit.Iset, typeof(OpCodeSetReg)); + Set("010010110110xx", InstEmit.Isetp, typeof(OpCodeSetCbuf)); + Set("0011011x0110xx", InstEmit.Isetp, typeof(OpCodeSetImm)); + Set("010110110110xx", InstEmit.Isetp, typeof(OpCodeSetReg)); + Set("111000110011xx", InstEmit.Kil, typeof(OpCodeExit)); + Set("1110111110010x", InstEmit.Ldc, typeof(OpCodeLdc)); + Set("0100110001000x", InstEmit.Lop, typeof(OpCodeLopCbuf)); + Set("0011100001000x", InstEmit.Lop, typeof(OpCodeLopImm)); + Set("000001xxxxxxxx", InstEmit.Lop, typeof(OpCodeLopImm32)); + Set("0101110001000x", InstEmit.Lop, typeof(OpCodeLopReg)); + Set("0010000xxxxxxx", InstEmit.Lop3, typeof(OpCodeLopCbuf)); + Set("001111xxxxxxxx", InstEmit.Lop3, typeof(OpCodeLopImm)); + Set("0101101111100x", InstEmit.Lop3, typeof(OpCodeLopReg)); + Set("0100110010011x", InstEmit.Mov, typeof(OpCodeAluCbuf)); + Set("0011100x10011x", InstEmit.Mov, typeof(OpCodeAluImm)); + Set("000000010000xx", InstEmit.Mov, typeof(OpCodeAluImm32)); + Set("0101110010011x", InstEmit.Mov, typeof(OpCodeAluReg)); + Set("0101000010000x", InstEmit.Mufu, typeof(OpCodeFArith)); + Set("1111101111100x", InstEmit.Out, typeof(OpCode)); + Set("0101000010010x", InstEmit.Psetp, typeof(OpCodePsetp)); + Set("0100110010010x", InstEmit.Rro, typeof(OpCodeFArithCbuf)); + Set("0011100x10010x", InstEmit.Rro, typeof(OpCodeFArithImm)); + Set("0101110010010x", InstEmit.Rro, typeof(OpCodeFArithReg)); + Set("0100110010100x", InstEmit.Sel, typeof(OpCodeAluCbuf)); + Set("0011100010100x", InstEmit.Sel, typeof(OpCodeAluImm)); + Set("0101110010100x", InstEmit.Sel, typeof(OpCodeAluReg)); + Set("0100110001001x", InstEmit.Shl, typeof(OpCodeAluCbuf)); + Set("0011100x01001x", InstEmit.Shl, typeof(OpCodeAluImm)); + Set("0101110001001x", InstEmit.Shl, typeof(OpCodeAluReg)); + Set("0100110000101x", InstEmit.Shr, typeof(OpCodeAluCbuf)); + Set("0011100x00101x", InstEmit.Shr, typeof(OpCodeAluImm)); + Set("0101110000101x", InstEmit.Shr, typeof(OpCodeAluReg)); + Set("111000101001xx", InstEmit.Ssy, typeof(OpCodeSsy)); + Set("1111000011111x", InstEmit.Sync, typeof(OpCodeSync)); + Set("110000xxxx111x", InstEmit.Tex, typeof(OpCodeTex)); + Set("1101111010111x", InstEmit.Tex_B, typeof(OpCodeTex)); + Set("1101x00xxxxxxx", InstEmit.Texs, typeof(OpCodeTexs)); + Set("1101x01xxxxxxx", InstEmit.Texs, typeof(OpCodeTlds)); + Set("1101x11100xxxx", InstEmit.Texs, typeof(OpCodeTld4s)); + Set("11011100xx111x", InstEmit.Tld, typeof(OpCodeTld)); + Set("11011101xx111x", InstEmit.Tld_B, typeof(OpCodeTld)); + Set("110010xxxx111x", InstEmit.Tld4, typeof(OpCodeTld4)); + Set("1101111101001x", InstEmit.Txq, typeof(OpCodeTex)); + Set("1101111101010x", InstEmit.Txq_B, typeof(OpCodeTex)); + Set("0100111xxxxxxx", InstEmit.Xmad, typeof(OpCodeAluCbuf)); + Set("0011011x00xxxx", InstEmit.Xmad, typeof(OpCodeAluImm)); + Set("010100010xxxxx", InstEmit.Xmad, typeof(OpCodeAluRegCbuf)); + Set("0101101100xxxx", InstEmit.Xmad, typeof(OpCodeAluReg)); +#endregion + } + + private static void Set(string encoding, InstEmitter emitter, Type opCodeType) + { + if (encoding.Length != EncodingBits) + { + throw new ArgumentException(nameof(encoding)); + } + + int bit = encoding.Length - 1; + int value = 0; + int xMask = 0; + int xBits = 0; + + int[] xPos = new int[encoding.Length]; + + for (int index = 0; index < encoding.Length; index++, bit--) + { + char chr = encoding[index]; + + if (chr == '1') + { + value |= 1 << bit; + } + else if (chr == 'x') + { + xMask |= 1 << bit; + + xPos[xBits++] = bit; + } + } + + xMask = ~xMask; + + TableEntry entry = new TableEntry(emitter, opCodeType, xBits); + + for (int index = 0; index < (1 << xBits); index++) + { + value &= xMask; + + for (int X = 0; X < xBits; X++) + { + value |= ((index >> X) & 1) << xPos[X]; + } + + if (_opCodes[value] == null || _opCodes[value].XBits > xBits) + { + _opCodes[value] = entry; + } + } + } + + public static (InstEmitter emitter, Type opCodeType) GetEmitter(long OpCode) + { + TableEntry entry = _opCodes[(ulong)OpCode >> (64 - EncodingBits)]; + + if (entry != null) + { + return (entry.Emitter, entry.OpCodeType); + } + + return (null, null); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs new file mode 100644 index 0000000000..da8756b91c --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTex.cs @@ -0,0 +1,14 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeTex : OpCodeTexture + { + public OpCodeTex(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + HasDepthCompare = opCode.Extract(50); + + HasOffset = opCode.Extract(54); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTexs.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTexs.cs new file mode 100644 index 0000000000..0822c4c074 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTexs.cs @@ -0,0 +1,11 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeTexs : OpCodeTextureScalar + { + public TextureScalarType Type => (TextureScalarType)RawType; + + public OpCodeTexs(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) { } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTexture.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTexture.cs new file mode 100644 index 0000000000..7a7e8f46e7 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTexture.cs @@ -0,0 +1,42 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeTexture : OpCode + { + public Register Rd { get; } + public Register Ra { get; } + public Register Rb { get; } + + public bool IsArray { get; } + + public TextureDimensions Dimensions { get; } + + public int ComponentMask { get; } + + public int Immediate { get; } + + public TextureLodMode LodMode { get; protected set; } + + public bool HasOffset { get; protected set; } + public bool HasDepthCompare { get; protected set; } + public bool IsMultisample { get; protected set; } + + public OpCodeTexture(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rd = new Register(opCode.Extract(0, 8), RegisterType.Gpr); + Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr); + Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr); + + IsArray = opCode.Extract(28); + + Dimensions = (TextureDimensions)opCode.Extract(29, 2); + + ComponentMask = opCode.Extract(31, 4); + + Immediate = opCode.Extract(36, 13); + + LodMode = (TextureLodMode)opCode.Extract(55, 3); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTextureScalar.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTextureScalar.cs new file mode 100644 index 0000000000..4389f45319 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTextureScalar.cs @@ -0,0 +1,61 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeTextureScalar : OpCode + { +#region "Component mask LUT" + private const int ____ = 0x0; + private const int R___ = 0x1; + private const int _G__ = 0x2; + private const int RG__ = 0x3; + private const int __B_ = 0x4; + private const int RGB_ = 0x7; + private const int ___A = 0x8; + private const int R__A = 0x9; + private const int _G_A = 0xa; + private const int RG_A = 0xb; + private const int __BA = 0xc; + private const int R_BA = 0xd; + private const int _GBA = 0xe; + private const int RGBA = 0xf; + + private static int[,] _maskLut = new int[,] + { + { R___, _G__, __B_, ___A, RG__, R__A, _G_A, __BA }, + { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ } + }; +#endregion + + public Register Rd0 { get; } + public Register Ra { get; } + public Register Rb { get; } + public Register Rd1 { get; } + + public int Immediate { get; } + + public int ComponentMask { get; } + + protected int RawType; + + public bool IsFp16 { get; } + + public OpCodeTextureScalar(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + Rd0 = new Register(opCode.Extract(0, 8), RegisterType.Gpr); + Ra = new Register(opCode.Extract(8, 8), RegisterType.Gpr); + Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr); + Rd1 = new Register(opCode.Extract(28, 8), RegisterType.Gpr); + + Immediate = opCode.Extract(36, 13); + + int compSel = opCode.Extract(50, 3); + + RawType = opCode.Extract(53, 4); + + IsFp16 = !opCode.Extract(59); + + ComponentMask = _maskLut[Rd1.IsRZ ? 0 : 1, compSel]; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs new file mode 100644 index 0000000000..61bd900b2d --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld.cs @@ -0,0 +1,20 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeTld : OpCodeTexture + { + public OpCodeTld(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + HasOffset = opCode.Extract(35); + + IsMultisample = opCode.Extract(50); + + bool isLL = opCode.Extract(55); + + LodMode = isLL + ? TextureLodMode.LodLevel + : TextureLodMode.LodZero; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4.cs new file mode 100644 index 0000000000..485edf936b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4.cs @@ -0,0 +1,20 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeTld4 : OpCodeTexture + { + public TextureGatherOffset Offset { get; } + + public int GatherCompIndex { get; } + + public OpCodeTld4(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + HasDepthCompare = opCode.Extract(50); + + Offset = (TextureGatherOffset)opCode.Extract(54, 2); + + GatherCompIndex = opCode.Extract(56, 2); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4s.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4s.cs new file mode 100644 index 0000000000..0d7b84606a --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTld4s.cs @@ -0,0 +1,20 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeTld4s : OpCodeTextureScalar + { + public bool HasDepthCompare { get; } + public bool HasOffset { get; } + + public int GatherCompIndex { get; } + + public OpCodeTld4s(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) + { + HasDepthCompare = opCode.Extract(50); + HasOffset = opCode.Extract(51); + + GatherCompIndex = opCode.Extract(52, 2); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/OpCodeTlds.cs b/Ryujinx.Graphics/Shader/Decoders/OpCodeTlds.cs new file mode 100644 index 0000000000..e117721e9e --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/OpCodeTlds.cs @@ -0,0 +1,11 @@ +using Ryujinx.Graphics.Shader.Instructions; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + class OpCodeTlds : OpCodeTextureScalar + { + public TexelLoadScalarType Type => (TexelLoadScalarType)RawType; + + public OpCodeTlds(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode) { } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/Register.cs b/Ryujinx.Graphics/Shader/Decoders/Register.cs new file mode 100644 index 0000000000..30840d8c03 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/Register.cs @@ -0,0 +1,36 @@ +using System; + +namespace Ryujinx.Graphics.Shader.Decoders +{ + struct Register : IEquatable + { + public int Index { get; } + + public RegisterType Type { get; } + + public bool IsRZ => Type == RegisterType.Gpr && Index == RegisterConsts.RegisterZeroIndex; + public bool IsPT => Type == RegisterType.Predicate && Index == RegisterConsts.PredicateTrueIndex; + + public Register(int index, RegisterType type) + { + Index = index; + Type = type; + } + + public override int GetHashCode() + { + return (ushort)Index | ((ushort)Type << 16); + } + + public override bool Equals(object obj) + { + return obj is Register reg && Equals(reg); + } + + public bool Equals(Register other) + { + return other.Index == Index && + other.Type == Type; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/RegisterConsts.cs b/Ryujinx.Graphics/Shader/Decoders/RegisterConsts.cs new file mode 100644 index 0000000000..d381f9543e --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/RegisterConsts.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + static class RegisterConsts + { + public const int GprsCount = 255; + public const int PredsCount = 7; + public const int FlagsCount = 4; + public const int TotalCount = GprsCount + PredsCount + FlagsCount; + + public const int RegisterZeroIndex = GprsCount; + public const int PredicateTrueIndex = PredsCount; + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/RegisterType.cs b/Ryujinx.Graphics/Shader/Decoders/RegisterType.cs new file mode 100644 index 0000000000..648f816a24 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/RegisterType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum RegisterType + { + Flag, + Gpr, + Predicate, + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/RoundingMode.cs b/Ryujinx.Graphics/Shader/Decoders/RoundingMode.cs new file mode 100644 index 0000000000..13bb08dc82 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/RoundingMode.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum RoundingMode + { + ToNearest = 0, + TowardsNegativeInfinity = 1, + TowardsPositiveInfinity = 2, + TowardsZero = 3 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/TexelLoadScalarType.cs b/Ryujinx.Graphics/Shader/Decoders/TexelLoadScalarType.cs new file mode 100644 index 0000000000..cef5778a55 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/TexelLoadScalarType.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum TexelLoadScalarType + { + Texture1DLodZero = 0x0, + Texture1DLodLevel = 0x1, + Texture2DLodZero = 0x2, + Texture2DLodZeroOffset = 0x4, + Texture2DLodLevel = 0x5, + Texture2DLodZeroMultisample = 0x6, + Texture3DLodZero = 0x7, + Texture2DArrayLodZero = 0x8, + Texture2DLodLevelOffset = 0xc + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/TextureDimensions.cs b/Ryujinx.Graphics/Shader/Decoders/TextureDimensions.cs new file mode 100644 index 0000000000..dbdf1927fb --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/TextureDimensions.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum TextureDimensions + { + Texture1D = 0, + Texture2D = 1, + Texture3D = 2, + TextureCube = 3 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/TextureGatherOffset.cs b/Ryujinx.Graphics/Shader/Decoders/TextureGatherOffset.cs new file mode 100644 index 0000000000..4e9ade26a4 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/TextureGatherOffset.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum TextureGatherOffset + { + None = 0, + Offset = 1, + Offsets = 2 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/TextureLodMode.cs b/Ryujinx.Graphics/Shader/Decoders/TextureLodMode.cs new file mode 100644 index 0000000000..0cc6f71432 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/TextureLodMode.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum TextureLodMode + { + None = 0, + LodZero = 1, + LodBias = 2, + LodLevel = 3, + LodBiasA = 4, //? + LodLevelA = 5 //? + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/TextureProperty.cs b/Ryujinx.Graphics/Shader/Decoders/TextureProperty.cs new file mode 100644 index 0000000000..ea35b1d1cb --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/TextureProperty.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum TextureProperty + { + Dimensions = 0x1, + Type = 0x2, + SamplePos = 0x5, + Filter = 0xa, + Lod = 0xc, + Wrap = 0xe, + BorderColor = 0x10 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/TextureScalarType.cs b/Ryujinx.Graphics/Shader/Decoders/TextureScalarType.cs new file mode 100644 index 0000000000..0055174b4e --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/TextureScalarType.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum TextureScalarType + { + Texture1DLodZero = 0x0, + Texture2D = 0x1, + Texture2DLodZero = 0x2, + Texture2DLodLevel = 0x3, + Texture2DDepthCompare = 0x4, + Texture2DLodLevelDepthCompare = 0x5, + Texture2DLodZeroDepthCompare = 0x6, + Texture2DArray = 0x7, + Texture2DArrayLodZero = 0x8, + Texture2DArrayLodZeroDepthCompare = 0x9, + Texture3D = 0xa, + Texture3DLodZero = 0xb, + TextureCube = 0xc, + TextureCubeLodLevel = 0xd + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Decoders/XmadCMode.cs b/Ryujinx.Graphics/Shader/Decoders/XmadCMode.cs new file mode 100644 index 0000000000..949a2ef70a --- /dev/null +++ b/Ryujinx.Graphics/Shader/Decoders/XmadCMode.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Graphics.Shader.Decoders +{ + enum XmadCMode + { + Cfull = 0, + Clo = 1, + Chi = 2, + Csfu = 3, + Cbcc = 4 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitAlu.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitAlu.cs new file mode 100644 index 0000000000..f7815e2330 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitAlu.cs @@ -0,0 +1,684 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; +using System; + +using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; +using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper; +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void Bfe(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + bool isReverse = op.RawOpCode.Extract(40); + bool isSigned = op.RawOpCode.Extract(48); + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + + if (isReverse) + { + srcA = context.BitfieldReverse(srcA); + } + + Operand position = context.BitwiseAnd(srcB, Const(0xff)); + + Operand size = context.BitfieldExtractU32(srcB, Const(8), Const(8)); + + Operand res = isSigned + ? context.BitfieldExtractS32(srcA, position, size) + : context.BitfieldExtractU32(srcA, position, size); + + context.Copy(GetDest(context), res); + + //TODO: CC, X, corner cases + } + + public static void Iadd(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + bool negateA = false, negateB = false; + + if (!(op is OpCodeAluImm32)) + { + negateB = op.RawOpCode.Extract(48); + negateA = op.RawOpCode.Extract(49); + } + + Operand srcA = context.INegate(GetSrcA(context), negateA); + Operand srcB = context.INegate(GetSrcB(context), negateB); + + Operand res = context.IAdd(srcA, srcB); + + bool isSubtraction = negateA || negateB; + + if (op.Extended) + { + //Add carry, or subtract borrow. + res = context.IAdd(res, isSubtraction + ? context.BitwiseNot(GetCF(context)) + : context.BitwiseAnd(GetCF(context), Const(1))); + } + + SetIaddFlags(context, res, srcA, srcB, op.SetCondCode, op.Extended, isSubtraction); + + context.Copy(GetDest(context), res); + } + + public static void Iadd3(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + IntegerHalfPart partC = (IntegerHalfPart)op.RawOpCode.Extract(31, 2); + IntegerHalfPart partB = (IntegerHalfPart)op.RawOpCode.Extract(33, 2); + IntegerHalfPart partA = (IntegerHalfPart)op.RawOpCode.Extract(35, 2); + + IntegerShift mode = (IntegerShift)op.RawOpCode.Extract(37, 2); + + bool negateC = op.RawOpCode.Extract(49); + bool negateB = op.RawOpCode.Extract(50); + bool negateA = op.RawOpCode.Extract(51); + + Operand Extend(Operand src, IntegerHalfPart part) + { + if (!(op is OpCodeAluReg) || part == IntegerHalfPart.B32) + { + return src; + } + + if (part == IntegerHalfPart.H0) + { + return context.BitwiseAnd(src, Const(0xffff)); + } + else if (part == IntegerHalfPart.H1) + { + return context.ShiftRightU32(src, Const(16)); + } + else + { + //TODO: Warning. + } + + return src; + } + + Operand srcA = context.INegate(Extend(GetSrcA(context), partA), negateA); + Operand srcB = context.INegate(Extend(GetSrcB(context), partB), negateB); + Operand srcC = context.INegate(Extend(GetSrcC(context), partC), negateC); + + Operand res = context.IAdd(srcA, srcB); + + if (op is OpCodeAluReg && mode != IntegerShift.NoShift) + { + if (mode == IntegerShift.ShiftLeft) + { + res = context.ShiftLeft(res, Const(16)); + } + else if (mode == IntegerShift.ShiftRight) + { + res = context.ShiftRightU32(res, Const(16)); + } + else + { + //TODO: Warning. + } + } + + res = context.IAdd(res, srcC); + + context.Copy(GetDest(context), res); + + //TODO: CC, X, corner cases + } + + public static void Imnmx(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + bool isSignedInt = op.RawOpCode.Extract(48); + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + + Operand resMin = isSignedInt + ? context.IMinimumS32(srcA, srcB) + : context.IMinimumU32(srcA, srcB); + + Operand resMax = isSignedInt + ? context.IMaximumS32(srcA, srcB) + : context.IMaximumU32(srcA, srcB); + + Operand pred = GetPredicate39(context); + + Operand dest = GetDest(context); + + context.Copy(dest, context.ConditionalSelect(pred, resMin, resMax)); + + SetZnFlags(context, dest, op.SetCondCode); + + //TODO: X flags. + } + + public static void Iscadd(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + bool negateA = false, negateB = false; + + if (!(op is OpCodeAluImm32)) + { + negateB = op.RawOpCode.Extract(48); + negateA = op.RawOpCode.Extract(49); + } + + int shift = op is OpCodeAluImm32 + ? op.RawOpCode.Extract(53, 5) + : op.RawOpCode.Extract(39, 5); + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + + srcA = context.ShiftLeft(srcA, Const(shift)); + + srcA = context.INegate(srcA, negateA); + srcB = context.INegate(srcB, negateB); + + Operand res = context.IAdd(srcA, srcB); + + context.Copy(GetDest(context), res); + + //TODO: CC, X + } + + public static void Iset(EmitterContext context) + { + OpCodeSet op = (OpCodeSet)context.CurrOp; + + bool boolFloat = op.RawOpCode.Extract(44); + bool isSigned = op.RawOpCode.Extract(48); + + IntegerCondition cmpOp = (IntegerCondition)op.RawOpCode.Extract(49, 3); + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + + Operand res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned); + + Operand pred = GetPredicate39(context); + + res = GetPredLogicalOp(context, op.LogicalOp, res, pred); + + Operand dest = GetDest(context); + + if (boolFloat) + { + context.Copy(dest, context.ConditionalSelect(res, ConstF(1), Const(0))); + } + else + { + context.Copy(dest, res); + } + + //TODO: CC, X + } + + public static void Isetp(EmitterContext context) + { + OpCodeSet op = (OpCodeSet)context.CurrOp; + + bool isSigned = op.RawOpCode.Extract(48); + + IntegerCondition cmpOp = (IntegerCondition)op.RawOpCode.Extract(49, 3); + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + + Operand p0Res = GetIntComparison(context, cmpOp, srcA, srcB, isSigned); + + Operand p1Res = context.BitwiseNot(p0Res); + + Operand pred = GetPredicate39(context); + + p0Res = GetPredLogicalOp(context, op.LogicalOp, p0Res, pred); + p1Res = GetPredLogicalOp(context, op.LogicalOp, p1Res, pred); + + context.Copy(Register(op.Predicate3), p0Res); + context.Copy(Register(op.Predicate0), p1Res); + } + + public static void Lop(EmitterContext context) + { + IOpCodeLop op = (IOpCodeLop)context.CurrOp; + + Operand srcA = context.BitwiseNot(GetSrcA(context), op.InvertA); + Operand srcB = context.BitwiseNot(GetSrcB(context), op.InvertB); + + Operand res = srcB; + + switch (op.LogicalOp) + { + case LogicalOperation.And: res = context.BitwiseAnd (srcA, srcB); break; + case LogicalOperation.Or: res = context.BitwiseOr (srcA, srcB); break; + case LogicalOperation.ExclusiveOr: res = context.BitwiseExclusiveOr(srcA, srcB); break; + } + + EmitLopPredWrite(context, op, res); + + Operand dest = GetDest(context); + + context.Copy(dest, res); + + SetZnFlags(context, dest, op.SetCondCode, op.Extended); + } + + public static void Lop3(EmitterContext context) + { + IOpCodeLop op = (IOpCodeLop)context.CurrOp; + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + Operand srcC = GetSrcC(context); + + bool regVariant = op is OpCodeLopReg; + + int truthTable = regVariant + ? op.RawOpCode.Extract(28, 8) + : op.RawOpCode.Extract(48, 8); + + Operand res = Lop3Expression.GetFromTruthTable(context, srcA, srcB, srcC, truthTable); + + if (regVariant) + { + EmitLopPredWrite(context, op, res); + } + + Operand dest = GetDest(context); + + context.Copy(dest, res); + + SetZnFlags(context, dest, op.SetCondCode, op.Extended); + } + + public static void Psetp(EmitterContext context) + { + OpCodePsetp op = (OpCodePsetp)context.CurrOp; + + bool invertA = op.RawOpCode.Extract(15); + bool invertB = op.RawOpCode.Extract(32); + + Operand srcA = context.BitwiseNot(Register(op.Predicate12), invertA); + Operand srcB = context.BitwiseNot(Register(op.Predicate29), invertB); + + Operand p0Res = GetPredLogicalOp(context, op.LogicalOpAB, srcA, srcB); + + Operand p1Res = context.BitwiseNot(p0Res); + + Operand pred = GetPredicate39(context); + + p0Res = GetPredLogicalOp(context, op.LogicalOp, p0Res, pred); + p1Res = GetPredLogicalOp(context, op.LogicalOp, p1Res, pred); + + context.Copy(Register(op.Predicate3), p0Res); + context.Copy(Register(op.Predicate0), p1Res); + } + + public static void Rro(EmitterContext context) + { + //This is the range reduction operator, + //we translate it as a simple move, as it + //should be always followed by a matching + //MUFU instruction. + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + bool negateB = op.RawOpCode.Extract(45); + bool absoluteB = op.RawOpCode.Extract(49); + + Operand srcB = GetSrcB(context); + + srcB = context.FPAbsNeg(srcB, absoluteB, negateB); + + context.Copy(GetDest(context), srcB); + } + + public static void Shl(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + bool isMasked = op.RawOpCode.Extract(39); + + Operand srcB = GetSrcB(context); + + if (isMasked) + { + srcB = context.BitwiseAnd(srcB, Const(0x1f)); + } + + Operand res = context.ShiftLeft(GetSrcA(context), srcB); + + if (!isMasked) + { + //Clamped shift value. + Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32)); + + res = context.ConditionalSelect(isLessThan32, res, Const(0)); + } + + //TODO: X, CC + + context.Copy(GetDest(context), res); + } + + public static void Shr(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + bool isMasked = op.RawOpCode.Extract(39); + bool isReverse = op.RawOpCode.Extract(40); + bool isSigned = op.RawOpCode.Extract(48); + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + + if (isReverse) + { + srcA = context.BitfieldReverse(srcA); + } + + if (isMasked) + { + srcB = context.BitwiseAnd(srcB, Const(0x1f)); + } + + Operand res = isSigned + ? context.ShiftRightS32(srcA, srcB) + : context.ShiftRightU32(srcA, srcB); + + if (!isMasked) + { + //Clamped shift value. + Operand resShiftBy32; + + if (isSigned) + { + resShiftBy32 = context.ShiftRightS32(srcA, Const(31)); + } + else + { + resShiftBy32 = Const(0); + } + + Operand isLessThan32 = context.ICompareLessUnsigned(srcB, Const(32)); + + res = context.ConditionalSelect(isLessThan32, res, resShiftBy32); + } + + //TODO: X, CC + + context.Copy(GetDest(context), res); + } + + public static void Xmad(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + bool signedA = context.CurrOp.RawOpCode.Extract(48); + bool signedB = context.CurrOp.RawOpCode.Extract(49); + bool highA = context.CurrOp.RawOpCode.Extract(53); + bool highB = false; + + XmadCMode mode; + + if (op is OpCodeAluReg) + { + highB = context.CurrOp.RawOpCode.Extract(35); + + mode = (XmadCMode)context.CurrOp.RawOpCode.Extract(50, 3); + } + else + { + mode = (XmadCMode)context.CurrOp.RawOpCode.Extract(50, 2); + + if (!(op is OpCodeAluImm)) + { + highB = context.CurrOp.RawOpCode.Extract(52); + } + } + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + Operand srcC = GetSrcC(context); + + //XMAD immediates are 16-bits unsigned integers. + if (srcB.Type == OperandType.Constant) + { + srcB = Const(srcB.Value & 0xffff); + } + + Operand Extend16To32(Operand src, bool high, bool signed) + { + if (signed && high) + { + return context.ShiftRightS32(src, Const(16)); + } + else if (signed) + { + return context.BitfieldExtractS32(src, Const(0), Const(16)); + } + else if (high) + { + return context.ShiftRightU32(src, Const(16)); + } + else + { + return context.BitwiseAnd(src, Const(0xffff)); + } + } + + srcA = Extend16To32(srcA, highA, signedA); + srcB = Extend16To32(srcB, highB, signedB); + + bool productShiftLeft = false; + bool merge = false; + + if (!(op is OpCodeAluRegCbuf)) + { + productShiftLeft = context.CurrOp.RawOpCode.Extract(36); + merge = context.CurrOp.RawOpCode.Extract(37); + } + + bool extended; + + if ((op is OpCodeAluReg) || (op is OpCodeAluImm)) + { + extended = context.CurrOp.RawOpCode.Extract(38); + } + else + { + extended = context.CurrOp.RawOpCode.Extract(54); + } + + Operand res = context.IMultiply(srcA, srcB); + + if (productShiftLeft) + { + res = context.ShiftLeft(res, Const(16)); + } + + switch (mode) + { + case XmadCMode.Cfull: break; + + case XmadCMode.Clo: srcC = Extend16To32(srcC, high: false, signed: false); break; + case XmadCMode.Chi: srcC = Extend16To32(srcC, high: true, signed: false); break; + + case XmadCMode.Cbcc: + { + srcC = context.IAdd(srcC, context.ShiftLeft(GetSrcB(context), Const(16))); + + break; + } + + case XmadCMode.Csfu: + { + Operand signAdjustA = context.ShiftLeft(context.ShiftRightU32(srcA, Const(31)), Const(16)); + Operand signAdjustB = context.ShiftLeft(context.ShiftRightU32(srcB, Const(31)), Const(16)); + + srcC = context.ISubtract(srcC, context.IAdd(signAdjustA, signAdjustB)); + + break; + } + + default: /* TODO: Warning */ break; + } + + Operand product = res; + + if (extended) + { + //Add with carry. + res = context.IAdd(res, context.BitwiseAnd(GetCF(context), Const(1))); + } + else + { + //Add (no carry in). + res = context.IAdd(res, srcC); + } + + SetIaddFlags(context, res, product, srcC, op.SetCondCode, extended); + + if (merge) + { + res = context.BitwiseAnd(res, Const(0xffff)); + res = context.BitwiseOr(res, context.ShiftLeft(GetSrcB(context), Const(16))); + } + + context.Copy(GetDest(context), res); + } + + private static Operand GetIntComparison( + EmitterContext context, + IntegerCondition cond, + Operand srcA, + Operand srcB, + bool isSigned) + { + Operand res; + + if (cond == IntegerCondition.Always) + { + res = Const(IrConsts.True); + } + else if (cond == IntegerCondition.Never) + { + res = Const(IrConsts.False); + } + else + { + Instruction inst; + + switch (cond) + { + case IntegerCondition.Less: inst = Instruction.CompareLessU32; break; + case IntegerCondition.Equal: inst = Instruction.CompareEqual; break; + case IntegerCondition.LessOrEqual: inst = Instruction.CompareLessOrEqualU32; break; + case IntegerCondition.Greater: inst = Instruction.CompareGreaterU32; break; + case IntegerCondition.NotEqual: inst = Instruction.CompareNotEqual; break; + case IntegerCondition.GreaterOrEqual: inst = Instruction.CompareGreaterOrEqualU32; break; + + default: throw new InvalidOperationException($"Unexpected condition \"{cond}\"."); + } + + if (isSigned) + { + switch (cond) + { + case IntegerCondition.Less: inst = Instruction.CompareLess; break; + case IntegerCondition.LessOrEqual: inst = Instruction.CompareLessOrEqual; break; + case IntegerCondition.Greater: inst = Instruction.CompareGreater; break; + case IntegerCondition.GreaterOrEqual: inst = Instruction.CompareGreaterOrEqual; break; + } + } + + res = context.Add(inst, Local(), srcA, srcB); + } + + return res; + } + + private static void EmitLopPredWrite(EmitterContext context, IOpCodeLop op, Operand result) + { + if (op is OpCodeLop opLop && !opLop.Predicate48.IsPT) + { + Operand pRes; + + if (opLop.CondOp == ConditionalOperation.False) + { + pRes = Const(IrConsts.False); + } + else if (opLop.CondOp == ConditionalOperation.True) + { + pRes = Const(IrConsts.True); + } + else if (opLop.CondOp == ConditionalOperation.Zero) + { + pRes = context.ICompareEqual(result, Const(0)); + } + else /* if (opLop.CondOp == ConditionalOperation.NotZero) */ + { + pRes = context.ICompareNotEqual(result, Const(0)); + } + + context.Copy(Register(opLop.Predicate48), pRes); + } + } + + private static void SetIaddFlags( + EmitterContext context, + Operand res, + Operand srcA, + Operand srcB, + bool setCC, + bool extended, + bool isSubtraction = false) + { + if (!setCC) + { + return; + } + + if (!extended || isSubtraction) + { + //C = d < a + context.Copy(GetCF(context), context.ICompareLessUnsigned(res, srcA)); + } + else + { + //C = (d == a && CIn) || d < a + Operand tempC0 = context.ICompareEqual (res, srcA); + Operand tempC1 = context.ICompareLessUnsigned(res, srcA); + + tempC0 = context.BitwiseAnd(tempC0, GetCF(context)); + + context.Copy(GetCF(context), context.BitwiseOr(tempC0, tempC1)); + } + + //V = (d ^ a) & ~(a ^ b) < 0 + Operand tempV0 = context.BitwiseExclusiveOr(res, srcA); + Operand tempV1 = context.BitwiseExclusiveOr(srcA, srcB); + + tempV1 = context.BitwiseNot(tempV1); + + Operand tempV = context.BitwiseAnd(tempV0, tempV1); + + context.Copy(GetVF(context), context.ICompareLess(tempV, Const(0))); + + SetZnFlags(context, res, setCC: true, extended: extended); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitAluHelper.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitAluHelper.cs new file mode 100644 index 0000000000..b5bde1a1c1 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitAluHelper.cs @@ -0,0 +1,88 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; +using System; + +using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static class InstEmitAluHelper + { + public static int GetIntMin(IntegerType type) + { + switch (type) + { + case IntegerType.U8: return byte.MinValue; + case IntegerType.S8: return sbyte.MinValue; + case IntegerType.U16: return ushort.MinValue; + case IntegerType.S16: return short.MinValue; + case IntegerType.U32: return (int)uint.MinValue; + case IntegerType.S32: return int.MinValue; + } + + throw new ArgumentException($"The type \"{type}\" is not a supported int type."); + } + + public static int GetIntMax(IntegerType type) + { + switch (type) + { + case IntegerType.U8: return byte.MaxValue; + case IntegerType.S8: return sbyte.MaxValue; + case IntegerType.U16: return ushort.MaxValue; + case IntegerType.S16: return short.MaxValue; + case IntegerType.U32: return unchecked((int)uint.MaxValue); + case IntegerType.S32: return int.MaxValue; + } + + throw new ArgumentException($"The type \"{type}\" is not a supported int type."); + } + + public static Operand GetPredLogicalOp( + EmitterContext context, + LogicalOperation logicalOp, + Operand input, + Operand pred) + { + switch (logicalOp) + { + case LogicalOperation.And: return context.BitwiseAnd (input, pred); + case LogicalOperation.Or: return context.BitwiseOr (input, pred); + case LogicalOperation.ExclusiveOr: return context.BitwiseExclusiveOr(input, pred); + } + + return input; + } + + public static void SetZnFlags(EmitterContext context, Operand dest, bool setCC, bool extended = false) + { + if (!setCC) + { + return; + } + + if (extended) + { + //When the operation is extended, it means we are doing + //the operation on a long word with any number of bits, + //so we need to AND the zero flag from result with the + //previous result when extended is specified, to ensure + //we have ZF set only if all words are zero, and not just + //the last one. + Operand oldZF = GetZF(context); + + Operand res = context.BitwiseAnd(context.ICompareEqual(dest, Const(0)), oldZF); + + context.Copy(GetZF(context), res); + } + else + { + context.Copy(GetZF(context), context.ICompareEqual(dest, Const(0))); + } + + context.Copy(GetNF(context), context.ICompareLess(dest, Const(0))); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitConversion.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitConversion.cs new file mode 100644 index 0000000000..f5e9af0365 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitConversion.cs @@ -0,0 +1,213 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; + +using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; +using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper; +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void F2F(EmitterContext context) + { + OpCodeFArith op = (OpCodeFArith)context.CurrOp; + + FPType srcType = (FPType)op.RawOpCode.Extract(8, 2); + FPType dstType = (FPType)op.RawOpCode.Extract(10, 2); + + bool pass = op.RawOpCode.Extract(40); + bool negateB = op.RawOpCode.Extract(45); + bool absoluteB = op.RawOpCode.Extract(49); + + pass &= op.RoundingMode == RoundingMode.TowardsNegativeInfinity; + + Operand srcB = context.FPAbsNeg(GetSrcB(context, srcType), absoluteB, negateB); + + if (!pass) + { + switch (op.RoundingMode) + { + case RoundingMode.TowardsNegativeInfinity: + srcB = context.FPFloor(srcB); + break; + + case RoundingMode.TowardsPositiveInfinity: + srcB = context.FPCeiling(srcB); + break; + + case RoundingMode.TowardsZero: + srcB = context.FPTruncate(srcB); + break; + } + } + + srcB = context.FPSaturate(srcB, op.Saturate); + + WriteFP(context, dstType, srcB); + + //TODO: CC. + } + + public static void F2I(EmitterContext context) + { + OpCodeFArith op = (OpCodeFArith)context.CurrOp; + + IntegerType intType = (IntegerType)op.RawOpCode.Extract(8, 2); + + bool isSmallInt = intType <= IntegerType.U16; + + FPType floatType = (FPType)op.RawOpCode.Extract(10, 2); + + bool isSignedInt = op.RawOpCode.Extract(12); + bool negateB = op.RawOpCode.Extract(45); + bool absoluteB = op.RawOpCode.Extract(49); + + if (isSignedInt) + { + intType |= IntegerType.S8; + } + + Operand srcB = context.FPAbsNeg(GetSrcB(context, floatType), absoluteB, negateB); + + switch (op.RoundingMode) + { + case RoundingMode.TowardsNegativeInfinity: + srcB = context.FPFloor(srcB); + break; + + case RoundingMode.TowardsPositiveInfinity: + srcB = context.FPCeiling(srcB); + break; + + case RoundingMode.TowardsZero: + srcB = context.FPTruncate(srcB); + break; + } + + srcB = context.FPConvertToS32(srcB); + + //TODO: S/U64, conversion overflow handling. + if (intType != IntegerType.S32) + { + int min = GetIntMin(intType); + int max = GetIntMax(intType); + + srcB = isSignedInt + ? context.IClampS32(srcB, Const(min), Const(max)) + : context.IClampU32(srcB, Const(min), Const(max)); + } + + Operand dest = GetDest(context); + + context.Copy(dest, srcB); + + //TODO: CC. + } + + public static void I2F(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + FPType dstType = (FPType)op.RawOpCode.Extract(8, 2); + + IntegerType srcType = (IntegerType)op.RawOpCode.Extract(10, 2); + + bool isSmallInt = srcType <= IntegerType.U16; + + bool isSignedInt = op.RawOpCode.Extract(13); + bool negateB = op.RawOpCode.Extract(45); + bool absoluteB = op.RawOpCode.Extract(49); + + Operand srcB = context.IAbsNeg(GetSrcB(context), absoluteB, negateB); + + if (isSmallInt) + { + int size = srcType == IntegerType.U16 ? 16 : 8; + + srcB = isSignedInt + ? context.BitfieldExtractS32(srcB, Const(op.ByteSelection * 8), Const(size)) + : context.BitfieldExtractU32(srcB, Const(op.ByteSelection * 8), Const(size)); + } + + srcB = isSignedInt + ? context.IConvertS32ToFP(srcB) + : context.IConvertU32ToFP(srcB); + + WriteFP(context, dstType, srcB); + + //TODO: CC. + } + + public static void I2I(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + IntegerType dstType = (IntegerType)op.RawOpCode.Extract(8, 2); + IntegerType srcType = (IntegerType)op.RawOpCode.Extract(10, 2); + + if (srcType == IntegerType.U64 || dstType == IntegerType.U64) + { + //TODO: Warning. This instruction doesn't support 64-bits integers + } + + bool srcIsSmallInt = srcType <= IntegerType.U16; + + bool dstIsSignedInt = op.RawOpCode.Extract(12); + bool srcIsSignedInt = op.RawOpCode.Extract(13); + bool negateB = op.RawOpCode.Extract(45); + bool absoluteB = op.RawOpCode.Extract(49); + + Operand srcB = GetSrcB(context); + + if (srcIsSmallInt) + { + int size = srcType == IntegerType.U16 ? 16 : 8; + + srcB = srcIsSignedInt + ? context.BitfieldExtractS32(srcB, Const(op.ByteSelection * 8), Const(size)) + : context.BitfieldExtractU32(srcB, Const(op.ByteSelection * 8), Const(size)); + } + + srcB = context.IAbsNeg(srcB, absoluteB, negateB); + + if (op.Saturate) + { + if (dstIsSignedInt) + { + dstType |= IntegerType.S8; + } + + int min = GetIntMin(dstType); + int max = GetIntMax(dstType); + + srcB = dstIsSignedInt + ? context.IClampS32(srcB, Const(min), Const(max)) + : context.IClampU32(srcB, Const(min), Const(max)); + } + + context.Copy(GetDest(context), srcB); + + //TODO: CC. + } + + private static void WriteFP(EmitterContext context, FPType type, Operand srcB) + { + Operand dest = GetDest(context); + + if (type == FPType.FP32) + { + context.Copy(dest, srcB); + } + else if (type == FPType.FP16) + { + context.Copy(dest, context.PackHalf2x16(srcB, ConstF(0))); + } + else + { + //TODO. + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitFArith.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitFArith.cs new file mode 100644 index 0000000000..72492470ca --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitFArith.cs @@ -0,0 +1,369 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; +using System; + +using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper; +using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void Fadd(EmitterContext context) + { + IOpCodeFArith op = (IOpCodeFArith)context.CurrOp; + + bool absoluteA = op.AbsoluteA, absoluteB, negateA, negateB; + + if (op is OpCodeFArithImm32) + { + negateB = op.RawOpCode.Extract(53); + negateA = op.RawOpCode.Extract(56); + absoluteB = op.RawOpCode.Extract(57); + } + else + { + negateB = op.RawOpCode.Extract(45); + negateA = op.RawOpCode.Extract(48); + absoluteB = op.RawOpCode.Extract(49); + } + + Operand srcA = context.FPAbsNeg(GetSrcA(context), absoluteA, negateA); + Operand srcB = context.FPAbsNeg(GetSrcB(context), absoluteB, negateB); + + Operand dest = GetDest(context); + + context.Copy(dest, context.FPSaturate(context.FPAdd(srcA, srcB), op.Saturate)); + + SetFPZnFlags(context, dest, op.SetCondCode); + } + + public static void Ffma(EmitterContext context) + { + IOpCodeFArith op = (IOpCodeFArith)context.CurrOp; + + bool negateB = op.RawOpCode.Extract(48); + bool negateC = op.RawOpCode.Extract(49); + + Operand srcA = GetSrcA(context); + + Operand srcB = context.FPNegate(GetSrcB(context), negateB); + Operand srcC = context.FPNegate(GetSrcC(context), negateC); + + Operand dest = GetDest(context); + + context.Copy(dest, context.FPSaturate(context.FPFusedMultiplyAdd(srcA, srcB, srcC), op.Saturate)); + + SetFPZnFlags(context, dest, op.SetCondCode); + } + + public static void Fmnmx(EmitterContext context) + { + IOpCodeFArith op = (IOpCodeFArith)context.CurrOp; + + bool absoluteA = op.AbsoluteA; + bool negateB = op.RawOpCode.Extract(45); + bool negateA = op.RawOpCode.Extract(48); + bool absoluteB = op.RawOpCode.Extract(49); + + Operand srcA = context.FPAbsNeg(GetSrcA(context), absoluteA, negateA); + Operand srcB = context.FPAbsNeg(GetSrcB(context), absoluteB, negateB); + + Operand resMin = context.FPMinimum(srcA, srcB); + Operand resMax = context.FPMaximum(srcA, srcB); + + Operand pred = GetPredicate39(context); + + Operand dest = GetDest(context); + + context.Copy(dest, context.ConditionalSelect(pred, resMin, resMax)); + + SetFPZnFlags(context, dest, op.SetCondCode); + } + + public static void Fmul(EmitterContext context) + { + IOpCodeFArith op = (IOpCodeFArith)context.CurrOp; + + bool negateB = !(op is OpCodeFArithImm32) && op.RawOpCode.Extract(48); + + Operand srcA = GetSrcA(context); + + Operand srcB = context.FPNegate(GetSrcB(context), negateB); + + switch (op.Scale) + { + case FmulScale.None: break; + + case FmulScale.Divide2: srcA = context.FPDivide (srcA, ConstF(2)); break; + case FmulScale.Divide4: srcA = context.FPDivide (srcA, ConstF(4)); break; + case FmulScale.Divide8: srcA = context.FPDivide (srcA, ConstF(8)); break; + case FmulScale.Multiply2: srcA = context.FPMultiply(srcA, ConstF(2)); break; + case FmulScale.Multiply4: srcA = context.FPMultiply(srcA, ConstF(4)); break; + case FmulScale.Multiply8: srcA = context.FPMultiply(srcA, ConstF(8)); break; + + default: break; //TODO: Warning. + } + + Operand dest = GetDest(context); + + context.Copy(dest, context.FPSaturate(context.FPMultiply(srcA, srcB), op.Saturate)); + + SetFPZnFlags(context, dest, op.SetCondCode); + } + + public static void Fset(EmitterContext context) + { + OpCodeSet op = (OpCodeSet)context.CurrOp; + + Condition cmpOp = (Condition)op.RawOpCode.Extract(48, 4); + + bool negateA = op.RawOpCode.Extract(43); + bool absoluteB = op.RawOpCode.Extract(44); + bool boolFloat = op.RawOpCode.Extract(52); + bool negateB = op.RawOpCode.Extract(53); + bool absoluteA = op.RawOpCode.Extract(54); + + Operand srcA = context.FPAbsNeg(GetSrcA(context), absoluteA, negateA); + Operand srcB = context.FPAbsNeg(GetSrcB(context), absoluteB, negateB); + + Operand res = GetFPComparison(context, cmpOp, srcA, srcB); + + Operand pred = GetPredicate39(context); + + res = GetPredLogicalOp(context, op.LogicalOp, res, pred); + + Operand dest = GetDest(context); + + if (boolFloat) + { + context.Copy(dest, context.ConditionalSelect(res, ConstF(1), Const(0))); + } + else + { + context.Copy(dest, res); + } + + //TODO: CC, X + } + + public static void Fsetp(EmitterContext context) + { + OpCodeSet op = (OpCodeSet)context.CurrOp; + + Condition cmpOp = (Condition)op.RawOpCode.Extract(48, 4); + + bool absoluteA = op.RawOpCode.Extract(7); + bool negateA = op.RawOpCode.Extract(43); + bool absoluteB = op.RawOpCode.Extract(44); + + Operand srcA = context.FPAbsNeg (GetSrcA(context), absoluteA, negateA); + Operand srcB = context.FPAbsolute(GetSrcB(context), absoluteB); + + Operand p0Res = GetFPComparison(context, cmpOp, srcA, srcB); + + Operand p1Res = context.BitwiseNot(p0Res); + + Operand pred = GetPredicate39(context); + + p0Res = GetPredLogicalOp(context, op.LogicalOp, p0Res, pred); + p1Res = GetPredLogicalOp(context, op.LogicalOp, p1Res, pred); + + context.Copy(Register(op.Predicate3), p0Res); + context.Copy(Register(op.Predicate0), p1Res); + } + + public static void Hadd2(EmitterContext context) + { + Hadd2Hmul2Impl(context, isAdd: true); + } + + public static void Hfma2(EmitterContext context) + { + IOpCodeHfma op = (IOpCodeHfma)context.CurrOp; + + Operand[] srcA = GetHfmaSrcA(context); + Operand[] srcB = GetHfmaSrcB(context); + Operand[] srcC = GetHfmaSrcC(context); + + Operand[] res = new Operand[2]; + + for (int index = 0; index < res.Length; index++) + { + res[index] = context.FPFusedMultiplyAdd(srcA[index], srcB[index], srcC[index]); + + res[index] = context.FPSaturate(res[index], op.Saturate); + } + + context.Copy(GetDest(context), GetHalfPacked(context, res)); + } + + public static void Hmul2(EmitterContext context) + { + Hadd2Hmul2Impl(context, isAdd: false); + } + + private static void Hadd2Hmul2Impl(EmitterContext context, bool isAdd) + { + OpCode op = context.CurrOp; + + bool saturate = op.RawOpCode.Extract(op is OpCodeAluImm32 ? 52 : 32); + + Operand[] srcA = GetHalfSrcA(context); + Operand[] srcB = GetHalfSrcB(context); + + Operand[] res = new Operand[2]; + + for (int index = 0; index < res.Length; index++) + { + if (isAdd) + { + res[index] = context.FPAdd(srcA[index], srcB[index]); + } + else + { + res[index] = context.FPMultiply(srcA[index], srcB[index]); + } + + res[index] = context.FPSaturate(res[index], saturate); + } + + context.Copy(GetDest(context), GetHalfPacked(context, res)); + } + + public static void Mufu(EmitterContext context) + { + IOpCodeFArith op = (IOpCodeFArith)context.CurrOp; + + bool negateB = op.RawOpCode.Extract(48); + + Operand res = context.FPAbsNeg(GetSrcA(context), op.AbsoluteA, negateB); + + MufuOperation subOp = (MufuOperation)context.CurrOp.RawOpCode.Extract(20, 4); + + switch (subOp) + { + case MufuOperation.Cosine: + res = context.FPCosine(res); + break; + + case MufuOperation.Sine: + res = context.FPSine(res); + break; + + case MufuOperation.ExponentB2: + res = context.FPExponentB2(res); + break; + + case MufuOperation.LogarithmB2: + res = context.FPLogarithmB2(res); + break; + + case MufuOperation.Reciprocal: + res = context.FPReciprocal(res); + break; + + case MufuOperation.ReciprocalSquareRoot: + res = context.FPReciprocalSquareRoot(res); + break; + + case MufuOperation.SquareRoot: + res = context.FPSquareRoot(res); + break; + + default: /* TODO */ break; + } + + context.Copy(GetDest(context), context.FPSaturate(res, op.Saturate)); + } + + private static Operand GetFPComparison( + EmitterContext context, + Condition cond, + Operand srcA, + Operand srcB) + { + Operand res; + + if (cond == Condition.Always) + { + res = Const(IrConsts.True); + } + else if (cond == Condition.Never) + { + res = Const(IrConsts.False); + } + else if (cond == Condition.Nan || cond == Condition.Number) + { + res = context.BitwiseOr(context.IsNan(srcA), context.IsNan(srcB)); + + if (cond == Condition.Number) + { + res = context.BitwiseNot(res); + } + } + else + { + Instruction inst; + + switch (cond & ~Condition.Nan) + { + case Condition.Less: inst = Instruction.CompareLess; break; + case Condition.Equal: inst = Instruction.CompareEqual; break; + case Condition.LessOrEqual: inst = Instruction.CompareLessOrEqual; break; + case Condition.Greater: inst = Instruction.CompareGreater; break; + case Condition.NotEqual: inst = Instruction.CompareNotEqual; break; + case Condition.GreaterOrEqual: inst = Instruction.CompareGreaterOrEqual; break; + + default: throw new InvalidOperationException($"Unexpected condition \"{cond}\"."); + } + + res = context.Add(inst | Instruction.FP, Local(), srcA, srcB); + + if ((cond & Condition.Nan) != 0) + { + res = context.BitwiseOr(res, context.IsNan(srcA)); + res = context.BitwiseOr(res, context.IsNan(srcB)); + } + } + + return res; + } + + private static void SetFPZnFlags(EmitterContext context, Operand dest, bool setCC) + { + if (setCC) + { + context.Copy(GetZF(context), context.FPCompareEqual(dest, ConstF(0))); + context.Copy(GetNF(context), context.FPCompareLess (dest, ConstF(0))); + } + } + + private static Operand[] GetHfmaSrcA(EmitterContext context) + { + IOpCodeHfma op = (IOpCodeHfma)context.CurrOp; + + return GetHalfSources(context, GetSrcA(context), op.SwizzleA); + } + + private static Operand[] GetHfmaSrcB(EmitterContext context) + { + IOpCodeHfma op = (IOpCodeHfma)context.CurrOp; + + Operand[] operands = GetHalfSources(context, GetSrcB(context), op.SwizzleB); + + return FPAbsNeg(context, operands, false, op.NegateB); + } + + private static Operand[] GetHfmaSrcC(EmitterContext context) + { + IOpCodeHfma op = (IOpCodeHfma)context.CurrOp; + + Operand[] operands = GetHalfSources(context, GetSrcC(context), op.SwizzleC); + + return FPAbsNeg(context, operands, false, op.NegateC); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitFlow.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitFlow.cs new file mode 100644 index 0000000000..c4523f75cf --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitFlow.cs @@ -0,0 +1,107 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; +using System.Collections.Generic; +using System.Linq; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void Bra(EmitterContext context) + { + EmitBranch(context, context.CurrBlock.Branch.Address); + } + + public static void Exit(EmitterContext context) + { + OpCodeExit op = (OpCodeExit)context.CurrOp; + + //TODO: Figure out how this is supposed to work in the + //presence of other condition codes. + if (op.Condition == Condition.Always) + { + context.Return(); + } + } + + public static void Kil(EmitterContext context) + { + context.Discard(); + } + + public static void Ssy(EmitterContext context) + { + OpCodeSsy op = (OpCodeSsy)context.CurrOp; + + foreach (KeyValuePair kv in op.Syncs) + { + OpCodeSync opSync = kv.Key; + + Operand local = kv.Value; + + int ssyIndex = opSync.Targets[op]; + + context.Copy(local, Const(ssyIndex)); + } + } + + public static void Sync(EmitterContext context) + { + OpCodeSync op = (OpCodeSync)context.CurrOp; + + if (op.Targets.Count == 1) + { + //If we have only one target, then the SSY is basically + //a branch, we can produce better codegen for this case. + OpCodeSsy opSsy = op.Targets.Keys.First(); + + EmitBranch(context, opSsy.GetAbsoluteAddress()); + } + else + { + foreach (KeyValuePair kv in op.Targets) + { + OpCodeSsy opSsy = kv.Key; + + Operand label = context.GetLabel(opSsy.GetAbsoluteAddress()); + + Operand local = opSsy.Syncs[op]; + + int ssyIndex = kv.Value; + + context.BranchIfTrue(label, context.ICompareEqual(local, Const(ssyIndex))); + } + } + } + + private static void EmitBranch(EmitterContext context, ulong address) + { + //If we're branching to the next instruction, then the branch + //is useless and we can ignore it. + if (address == context.CurrOp.Address + 8) + { + return; + } + + Operand label = context.GetLabel(address); + + Operand pred = Register(context.CurrOp.Predicate); + + if (context.CurrOp.Predicate.IsPT) + { + context.Branch(label); + } + else if (context.CurrOp.InvertPredicate) + { + context.BranchIfFalse(label, pred); + } + else + { + context.BranchIfTrue(label, pred); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitHelper.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitHelper.cs new file mode 100644 index 0000000000..e31528d02b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitHelper.cs @@ -0,0 +1,267 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; +using System; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static class InstEmitHelper + { + public static Operand GetZF(EmitterContext context) + { + return Register(0, RegisterType.Flag); + } + + public static Operand GetNF(EmitterContext context) + { + return Register(1, RegisterType.Flag); + } + + public static Operand GetCF(EmitterContext context) + { + return Register(2, RegisterType.Flag); + } + + public static Operand GetVF(EmitterContext context) + { + return Register(3, RegisterType.Flag); + } + + public static Operand GetDest(EmitterContext context) + { + return Register(((IOpCodeRd)context.CurrOp).Rd); + } + + public static Operand GetSrcA(EmitterContext context) + { + return Register(((IOpCodeRa)context.CurrOp).Ra); + } + + public static Operand GetSrcB(EmitterContext context, FPType floatType) + { + if (floatType == FPType.FP32) + { + return GetSrcB(context); + } + else if (floatType == FPType.FP16) + { + int h = context.CurrOp.RawOpCode.Extract(41, 1); + + return GetHalfSources(context, GetSrcB(context), FPHalfSwizzle.FP16)[h]; + } + else if (floatType == FPType.FP64) + { + //TODO. + } + + throw new ArgumentException($"Invalid floating point type \"{floatType}\"."); + } + + public static Operand GetSrcB(EmitterContext context) + { + switch (context.CurrOp) + { + case IOpCodeCbuf op: + return Cbuf(op.Slot, op.Offset); + + case IOpCodeImm op: + return Const(op.Immediate); + + case IOpCodeImmF op: + return ConstF(op.Immediate); + + case IOpCodeReg op: + return Register(op.Rb); + + case IOpCodeRegCbuf op: + return Register(op.Rc); + } + + throw new InvalidOperationException($"Unexpected opcode type \"{context.CurrOp.GetType().Name}\"."); + } + + public static Operand GetSrcC(EmitterContext context) + { + switch (context.CurrOp) + { + case IOpCodeRegCbuf op: + return Cbuf(op.Slot, op.Offset); + + case IOpCodeRc op: + return Register(op.Rc); + } + + throw new InvalidOperationException($"Unexpected opcode type \"{context.CurrOp.GetType().Name}\"."); + } + + public static Operand[] GetHalfSrcA(EmitterContext context) + { + OpCode op = context.CurrOp; + + bool absoluteA = false, negateA = false; + + if (op is IOpCodeCbuf || op is IOpCodeImm) + { + negateA = op.RawOpCode.Extract(43); + absoluteA = op.RawOpCode.Extract(44); + } + else if (op is IOpCodeReg) + { + absoluteA = op.RawOpCode.Extract(44); + } + else if (op is OpCodeAluImm32 && op.Emitter == InstEmit.Hadd2) + { + negateA = op.RawOpCode.Extract(56); + } + + FPHalfSwizzle swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(47, 2); + + Operand[] operands = GetHalfSources(context, GetSrcA(context), swizzle); + + return FPAbsNeg(context, operands, absoluteA, negateA); + } + + public static Operand[] GetHalfSrcB(EmitterContext context) + { + OpCode op = context.CurrOp; + + FPHalfSwizzle swizzle = FPHalfSwizzle.FP16; + + bool absoluteB = false, negateB = false; + + if (op is IOpCodeReg) + { + swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(28, 2); + + absoluteB = op.RawOpCode.Extract(30); + negateB = op.RawOpCode.Extract(31); + } + else if (op is IOpCodeCbuf) + { + swizzle = FPHalfSwizzle.FP32; + + absoluteB = op.RawOpCode.Extract(54); + } + + Operand[] operands = GetHalfSources(context, GetSrcB(context), swizzle); + + return FPAbsNeg(context, operands, absoluteB, negateB); + } + + public static Operand[] FPAbsNeg(EmitterContext context, Operand[] operands, bool abs, bool neg) + { + for (int index = 0; index < operands.Length; index++) + { + operands[index] = context.FPAbsNeg(operands[index], abs, neg); + } + + return operands; + } + + public static Operand[] GetHalfSources(EmitterContext context, Operand src, FPHalfSwizzle swizzle) + { + switch (swizzle) + { + case FPHalfSwizzle.FP16: + return new Operand[] + { + context.UnpackHalf2x16Low (src), + context.UnpackHalf2x16High(src) + }; + + case FPHalfSwizzle.FP32: return new Operand[] { src, src }; + + case FPHalfSwizzle.DupH0: + return new Operand[] + { + context.UnpackHalf2x16Low(src), + context.UnpackHalf2x16Low(src) + }; + + case FPHalfSwizzle.DupH1: + return new Operand[] + { + context.UnpackHalf2x16High(src), + context.UnpackHalf2x16High(src) + }; + } + + throw new ArgumentException($"Invalid swizzle \"{swizzle}\"."); + } + + public static Operand GetHalfPacked(EmitterContext context, Operand[] results) + { + OpCode op = context.CurrOp; + + FPHalfSwizzle swizzle = FPHalfSwizzle.FP16; + + if (!(op is OpCodeAluImm32)) + { + swizzle = (FPHalfSwizzle)context.CurrOp.RawOpCode.Extract(49, 2); + } + + switch (swizzle) + { + case FPHalfSwizzle.FP16: return context.PackHalf2x16(results[0], results[1]); + + case FPHalfSwizzle.FP32: return results[0]; + + case FPHalfSwizzle.DupH0: + { + Operand h1 = GetHalfDest(context, isHigh: true); + + return context.PackHalf2x16(results[0], h1); + } + + case FPHalfSwizzle.DupH1: + { + Operand h0 = GetHalfDest(context, isHigh: false); + + return context.PackHalf2x16(h0, results[1]); + } + } + + throw new ArgumentException($"Invalid swizzle \"{swizzle}\"."); + } + + public static Operand GetHalfDest(EmitterContext context, bool isHigh) + { + if (isHigh) + { + return context.UnpackHalf2x16High(GetDest(context)); + } + else + { + return context.UnpackHalf2x16Low(GetDest(context)); + } + } + + public static Operand GetPredicate39(EmitterContext context) + { + IOpCodeAlu op = (IOpCodeAlu)context.CurrOp; + + Operand local = Register(op.Predicate39); + + if (op.InvertP) + { + local = context.BitwiseNot(local); + } + + return local; + } + + public static Operand SignExtendTo32(EmitterContext context, Operand src, int srcBits) + { + return context.BitfieldExtractS32(src, Const(0), Const(srcBits)); + } + + public static Operand ZeroExtendTo32(EmitterContext context, Operand src, int srcBits) + { + int mask = (int)(0xffffffffu >> (32 - srcBits)); + + return context.BitwiseAnd(src, Const(mask)); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitMemory.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitMemory.cs new file mode 100644 index 0000000000..d81e97a13f --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitMemory.cs @@ -0,0 +1,138 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; + +using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void Ald(EmitterContext context) + { + OpCodeAttribute op = (OpCodeAttribute)context.CurrOp; + + Operand[] elems = new Operand[op.Count]; + + for (int index = 0; index < op.Count; index++) + { + Operand src = Attribute(op.AttributeOffset + index * 4); + + context.Copy(elems[index] = Local(), src); + } + + for (int index = 0; index < op.Count; index++) + { + Register rd = new Register(op.Rd.Index + index, RegisterType.Gpr); + + if (rd.IsRZ) + { + break; + } + + context.Copy(Register(rd), elems[index]); + } + } + + public static void Ast(EmitterContext context) + { + OpCodeAttribute op = (OpCodeAttribute)context.CurrOp; + + for (int index = 0; index < op.Count; index++) + { + if (op.Rd.Index + index > RegisterConsts.RegisterZeroIndex) + { + break; + } + + Register rd = new Register(op.Rd.Index + index, RegisterType.Gpr); + + Operand dest = Attribute(op.AttributeOffset + index * 4); + + context.Copy(dest, Register(rd)); + } + } + + public static void Ipa(EmitterContext context) + { + OpCodeIpa op = (OpCodeIpa)context.CurrOp; + + Operand srcA = new Operand(OperandType.Attribute, op.AttributeOffset); + + Operand srcB = GetSrcB(context); + + context.Copy(GetDest(context), srcA); + } + + public static void Ldc(EmitterContext context) + { + OpCodeLdc op = (OpCodeLdc)context.CurrOp; + + if (op.Size > IntegerSize.B64) + { + //TODO: Warning. + } + + bool isSmallInt = op.Size < IntegerSize.B32; + + int count = op.Size == IntegerSize.B64 ? 2 : 1; + + Operand baseOffset = context.Copy(GetSrcA(context)); + + for (int index = 0; index < count; index++) + { + Register rd = new Register(op.Rd.Index + index, RegisterType.Gpr); + + if (rd.IsRZ) + { + break; + } + + Operand offset = context.IAdd(baseOffset, Const((op.Offset + index) * 4)); + + Operand value = context.LoadConstant(Const(op.Slot), offset); + + if (isSmallInt) + { + Operand shift = context.BitwiseAnd(baseOffset, Const(3)); + + value = context.ShiftRightU32(value, shift); + + switch (op.Size) + { + case IntegerSize.U8: value = ZeroExtendTo32(context, value, 8); break; + case IntegerSize.U16: value = ZeroExtendTo32(context, value, 16); break; + case IntegerSize.S8: value = SignExtendTo32(context, value, 8); break; + case IntegerSize.S16: value = SignExtendTo32(context, value, 16); break; + } + } + + context.Copy(Register(rd), value); + } + } + + public static void Out(EmitterContext context) + { + OpCode op = context.CurrOp; + + bool emit = op.RawOpCode.Extract(39); + bool cut = op.RawOpCode.Extract(40); + + if (!(emit || cut)) + { + //TODO: Warning. + } + + if (emit) + { + context.EmitVertex(); + } + + if (cut) + { + context.EndPrimitive(); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitMove.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitMove.cs new file mode 100644 index 0000000000..b74dbfd721 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitMove.cs @@ -0,0 +1,32 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; + +using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void Mov(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + context.Copy(GetDest(context), GetSrcB(context)); + } + + public static void Sel(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + Operand pred = GetPredicate39(context); + + Operand srcA = GetSrcA(context); + Operand srcB = GetSrcB(context); + + Operand res = context.ConditionalSelect(pred, srcA, srcB); + + context.Copy(GetDest(context), res); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs new file mode 100644 index 0000000000..1b19d901cf --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs @@ -0,0 +1,776 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; +using System; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static partial class InstEmit + { + public static void Tex(EmitterContext context) + { + Tex(context, TextureFlags.None); + } + + public static void Tex_B(EmitterContext context) + { + Tex(context, TextureFlags.Bindless); + } + + public static void Tld(EmitterContext context) + { + Tex(context, TextureFlags.IntCoords); + } + + public static void Tld_B(EmitterContext context) + { + Tex(context, TextureFlags.IntCoords | TextureFlags.Bindless); + } + + public static void Texs(EmitterContext context) + { + OpCodeTextureScalar op = (OpCodeTextureScalar)context.CurrOp; + + if (op.Rd0.IsRZ && op.Rd1.IsRZ) + { + return; + } + + List sourcesList = new List(); + + int raIndex = op.Ra.Index; + int rbIndex = op.Rb.Index; + + Operand Ra() + { + if (raIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(raIndex++, RegisterType.Gpr)); + } + + Operand Rb() + { + if (rbIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(rbIndex++, RegisterType.Gpr)); + } + + void AddTextureOffset(int coordsCount, int stride, int size) + { + Operand packedOffs = Rb(); + + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * stride), Const(size))); + } + } + + TextureType type; + TextureFlags flags; + + if (op is OpCodeTexs texsOp) + { + type = GetTextureType (texsOp.Type); + flags = GetTextureFlags(texsOp.Type); + + if ((type & TextureType.Array) != 0) + { + Operand arrayIndex = Ra(); + + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + + sourcesList.Add(arrayIndex); + + if ((type & TextureType.Shadow) != 0) + { + sourcesList.Add(Rb()); + } + + if ((flags & TextureFlags.LodLevel) != 0) + { + sourcesList.Add(ConstF(0)); + } + } + else + { + switch (texsOp.Type) + { + case TextureScalarType.Texture1DLodZero: + sourcesList.Add(Ra()); + break; + + case TextureScalarType.Texture2D: + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + break; + + case TextureScalarType.Texture2DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(ConstF(0)); + break; + + case TextureScalarType.Texture2DLodLevel: + case TextureScalarType.Texture2DDepthCompare: + case TextureScalarType.Texture3D: + case TextureScalarType.TextureCube: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + break; + + case TextureScalarType.Texture2DLodZeroDepthCompare: + case TextureScalarType.Texture3DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(ConstF(0)); + break; + + case TextureScalarType.Texture2DLodLevelDepthCompare: + case TextureScalarType.TextureCubeLodLevel: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(Rb()); + break; + } + } + } + else if (op is OpCodeTlds tldsOp) + { + type = GetTextureType (tldsOp.Type); + flags = GetTextureFlags(tldsOp.Type) | TextureFlags.IntCoords; + + switch (tldsOp.Type) + { + case TexelLoadScalarType.Texture1DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture1DLodLevel: + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + break; + + case TexelLoadScalarType.Texture2DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture2DLodZeroOffset: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture2DLodZeroMultisample: + case TexelLoadScalarType.Texture2DLodLevel: + case TexelLoadScalarType.Texture2DLodLevelOffset: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + break; + + case TexelLoadScalarType.Texture3DLodZero: + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + sourcesList.Add(Const(0)); + break; + + case TexelLoadScalarType.Texture2DArrayLodZero: + sourcesList.Add(Rb()); + sourcesList.Add(Rb()); + sourcesList.Add(Ra()); + sourcesList.Add(Const(0)); + break; + } + + if ((flags & TextureFlags.Offset) != 0) + { + AddTextureOffset(type.GetCoordsCount(), 4, 4); + } + } + else if (op is OpCodeTld4s tld4sOp) + { + if (!(tld4sOp.HasDepthCompare || tld4sOp.HasOffset)) + { + sourcesList.Add(Ra()); + sourcesList.Add(Rb()); + } + else + { + sourcesList.Add(Ra()); + sourcesList.Add(Ra()); + } + + type = TextureType.Texture2D; + flags = TextureFlags.Gather; + + if (tld4sOp.HasDepthCompare) + { + sourcesList.Add(Rb()); + + type |= TextureType.Shadow; + } + + if (tld4sOp.HasOffset) + { + AddTextureOffset(type.GetCoordsCount(), 8, 6); + + flags |= TextureFlags.Offset; + } + + sourcesList.Add(Const(tld4sOp.GatherCompIndex)); + } + else + { + throw new InvalidOperationException($"Invalid opcode type \"{op.GetType().Name}\"."); + } + + Operand[] sources = sourcesList.ToArray(); + + Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) }; + Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) }; + + int destIncrement = 0; + + Operand GetDest() + { + int high = destIncrement >> 1; + int low = destIncrement & 1; + + destIncrement++; + + if (op.IsFp16) + { + return high != 0 + ? (rd1[low] = Local()) + : (rd0[low] = Local()); + } + else + { + int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index; + + if (rdIndex < RegisterConsts.RegisterZeroIndex) + { + rdIndex += low; + } + + return Register(rdIndex, RegisterType.Gpr); + } + } + + int handle = op.Immediate; + + for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + Operand dest = GetDest(); + + TextureOperation operation = new TextureOperation( + Instruction.TextureSample, + type, + flags, + handle, + compIndex, + dest, + sources); + + context.Add(operation); + } + } + + if (op.IsFp16) + { + context.Copy(Register(op.Rd0), context.PackHalf2x16(rd0[0], rd0[1])); + context.Copy(Register(op.Rd1), context.PackHalf2x16(rd1[0], rd1[1])); + } + } + + public static void Tld4(EmitterContext context) + { + OpCodeTld4 op = (OpCodeTld4)context.CurrOp; + + if (op.Rd.IsRZ) + { + return; + } + + int raIndex = op.Ra.Index; + int rbIndex = op.Rb.Index; + + Operand Ra() + { + if (raIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(raIndex++, RegisterType.Gpr)); + } + + Operand Rb() + { + if (rbIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(rbIndex++, RegisterType.Gpr)); + } + + Operand arrayIndex = op.IsArray ? Ra() : null; + + List sourcesList = new List(); + + TextureType type = GetTextureType(op.Dimensions); + + TextureFlags flags = TextureFlags.Gather; + + int coordsCount = type.GetCoordsCount(); + + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(Ra()); + } + + if (op.IsArray) + { + sourcesList.Add(arrayIndex); + + type |= TextureType.Array; + } + + Operand[] packedOffs = new Operand[2]; + + packedOffs[0] = op.Offset != TextureGatherOffset.None ? Rb() : null; + packedOffs[1] = op.Offset == TextureGatherOffset.Offsets ? Rb() : null; + + if (op.HasDepthCompare) + { + sourcesList.Add(Rb()); + + type |= TextureType.Shadow; + } + + if (op.Offset != TextureGatherOffset.None) + { + int offsetTexelsCount = op.Offset == TextureGatherOffset.Offsets ? 4 : 1; + + for (int index = 0; index < coordsCount * offsetTexelsCount; index++) + { + Operand packed = packedOffs[(index >> 2) & 1]; + + sourcesList.Add(context.BitfieldExtractS32(packed, Const((index & 3) * 8), Const(6))); + } + + flags |= op.Offset == TextureGatherOffset.Offsets + ? TextureFlags.Offsets + : TextureFlags.Offset; + } + + sourcesList.Add(Const(op.GatherCompIndex)); + + Operand[] sources = sourcesList.ToArray(); + + int rdIndex = op.Rd.Index; + + Operand GetDest() + { + if (rdIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return Register(rdIndex++, RegisterType.Gpr); + } + + int handle = op.Immediate; + + for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + Operand dest = GetDest(); + + TextureOperation operation = new TextureOperation( + Instruction.TextureSample, + type, + flags, + handle, + compIndex, + dest, + sources); + + context.Add(operation); + } + } + } + + public static void Txq(EmitterContext context) + { + Txq(context, bindless: false); + } + + public static void Txq_B(EmitterContext context) + { + Txq(context, bindless: true); + } + + private static void Txq(EmitterContext context, bool bindless) + { + OpCodeTex op = (OpCodeTex)context.CurrOp; + + if (op.Rd.IsRZ) + { + return; + } + + TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6); + + //TODO: Validate and use property. + Instruction inst = Instruction.TextureSize; + + TextureType type = TextureType.Texture2D; + + TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None; + + int raIndex = op.Ra.Index; + + Operand Ra() + { + if (raIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(raIndex++, RegisterType.Gpr)); + } + + List sourcesList = new List(); + + if (bindless) + { + sourcesList.Add(Ra()); + } + + sourcesList.Add(Ra()); + + Operand[] sources = sourcesList.ToArray(); + + int rdIndex = op.Rd.Index; + + Operand GetDest() + { + if (rdIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return Register(rdIndex++, RegisterType.Gpr); + } + + int handle = !bindless ? op.Immediate : 0; + + for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + Operand dest = GetDest(); + + TextureOperation operation = new TextureOperation( + inst, + type, + flags, + handle, + compIndex, + dest, + sources); + + context.Add(operation); + } + } + } + + private static void Tex(EmitterContext context, TextureFlags flags) + { + OpCodeTexture op = (OpCodeTexture)context.CurrOp; + + bool isBindless = (flags & TextureFlags.Bindless) != 0; + bool intCoords = (flags & TextureFlags.IntCoords) != 0; + + if (op.Rd.IsRZ) + { + return; + } + + int raIndex = op.Ra.Index; + int rbIndex = op.Rb.Index; + + Operand Ra() + { + if (raIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(raIndex++, RegisterType.Gpr)); + } + + Operand Rb() + { + if (rbIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return context.Copy(Register(rbIndex++, RegisterType.Gpr)); + } + + Operand arrayIndex = op.IsArray ? Ra() : null; + + List sourcesList = new List(); + + if (isBindless) + { + sourcesList.Add(Rb()); + } + + TextureType type = GetTextureType(op.Dimensions); + + int coordsCount = type.GetCoordsCount(); + + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(Ra()); + } + + if (op.IsArray) + { + sourcesList.Add(arrayIndex); + + type |= TextureType.Array; + } + + bool hasLod = op.LodMode > TextureLodMode.LodZero; + + Operand lodValue = hasLod ? Rb() : ConstF(0); + + Operand packedOffs = op.HasOffset ? Rb() : null; + + if (op.HasDepthCompare) + { + sourcesList.Add(Rb()); + + type |= TextureType.Shadow; + } + + if ((op.LodMode == TextureLodMode.LodZero || + op.LodMode == TextureLodMode.LodLevel || + op.LodMode == TextureLodMode.LodLevelA) && !op.IsMultisample) + { + sourcesList.Add(lodValue); + + flags |= TextureFlags.LodLevel; + } + + if (op.HasOffset) + { + for (int index = 0; index < coordsCount; index++) + { + sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4))); + } + + flags |= TextureFlags.Offset; + } + + if (op.LodMode == TextureLodMode.LodBias || + op.LodMode == TextureLodMode.LodBiasA) + { + sourcesList.Add(lodValue); + + flags |= TextureFlags.LodBias; + } + + if (op.IsMultisample) + { + sourcesList.Add(Rb()); + + type |= TextureType.Multisample; + } + + Operand[] sources = sourcesList.ToArray(); + + int rdIndex = op.Rd.Index; + + Operand GetDest() + { + if (rdIndex > RegisterConsts.RegisterZeroIndex) + { + return Const(0); + } + + return Register(rdIndex++, RegisterType.Gpr); + } + + int handle = !isBindless ? op.Immediate : 0; + + for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++) + { + if ((compMask & 1) != 0) + { + Operand dest = GetDest(); + + TextureOperation operation = new TextureOperation( + Instruction.TextureSample, + type, + flags, + handle, + compIndex, + dest, + sources); + + context.Add(operation); + } + } + } + + private static TextureType GetTextureType(TextureDimensions dimensions) + { + switch (dimensions) + { + case TextureDimensions.Texture1D: return TextureType.Texture1D; + case TextureDimensions.Texture2D: return TextureType.Texture2D; + case TextureDimensions.Texture3D: return TextureType.Texture3D; + case TextureDimensions.TextureCube: return TextureType.TextureCube; + } + + throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\"."); + } + + private static TextureType GetTextureType(TextureScalarType type) + { + switch (type) + { + case TextureScalarType.Texture1DLodZero: + return TextureType.Texture1D; + + case TextureScalarType.Texture2D: + case TextureScalarType.Texture2DLodZero: + case TextureScalarType.Texture2DLodLevel: + return TextureType.Texture2D; + + case TextureScalarType.Texture2DDepthCompare: + case TextureScalarType.Texture2DLodLevelDepthCompare: + case TextureScalarType.Texture2DLodZeroDepthCompare: + return TextureType.Texture2D | TextureType.Shadow; + + case TextureScalarType.Texture2DArray: + case TextureScalarType.Texture2DArrayLodZero: + return TextureType.Texture2D | TextureType.Array; + + case TextureScalarType.Texture2DArrayLodZeroDepthCompare: + return TextureType.Texture2D | TextureType.Array | TextureType.Shadow; + + case TextureScalarType.Texture3D: + case TextureScalarType.Texture3DLodZero: + return TextureType.Texture3D; + + case TextureScalarType.TextureCube: + case TextureScalarType.TextureCubeLodLevel: + return TextureType.TextureCube; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + + private static TextureType GetTextureType(TexelLoadScalarType type) + { + switch (type) + { + case TexelLoadScalarType.Texture1DLodZero: + case TexelLoadScalarType.Texture1DLodLevel: + return TextureType.Texture1D; + + case TexelLoadScalarType.Texture2DLodZero: + case TexelLoadScalarType.Texture2DLodZeroOffset: + case TexelLoadScalarType.Texture2DLodLevel: + case TexelLoadScalarType.Texture2DLodLevelOffset: + return TextureType.Texture2D; + + case TexelLoadScalarType.Texture2DLodZeroMultisample: + return TextureType.Texture2D | TextureType.Multisample; + + case TexelLoadScalarType.Texture3DLodZero: + return TextureType.Texture3D; + + case TexelLoadScalarType.Texture2DArrayLodZero: + return TextureType.Texture2D | TextureType.Array; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + + private static TextureFlags GetTextureFlags(TextureScalarType type) + { + switch (type) + { + case TextureScalarType.Texture1DLodZero: + case TextureScalarType.Texture2DLodZero: + case TextureScalarType.Texture2DLodLevel: + case TextureScalarType.Texture2DLodLevelDepthCompare: + case TextureScalarType.Texture2DLodZeroDepthCompare: + case TextureScalarType.Texture2DArrayLodZero: + case TextureScalarType.Texture2DArrayLodZeroDepthCompare: + case TextureScalarType.Texture3DLodZero: + case TextureScalarType.TextureCubeLodLevel: + return TextureFlags.LodLevel; + + case TextureScalarType.Texture2D: + case TextureScalarType.Texture2DDepthCompare: + case TextureScalarType.Texture2DArray: + case TextureScalarType.Texture3D: + case TextureScalarType.TextureCube: + return TextureFlags.None; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + + private static TextureFlags GetTextureFlags(TexelLoadScalarType type) + { + switch (type) + { + case TexelLoadScalarType.Texture1DLodZero: + case TexelLoadScalarType.Texture1DLodLevel: + case TexelLoadScalarType.Texture2DLodZero: + case TexelLoadScalarType.Texture2DLodLevel: + case TexelLoadScalarType.Texture2DLodZeroMultisample: + case TexelLoadScalarType.Texture3DLodZero: + case TexelLoadScalarType.Texture2DArrayLodZero: + return TextureFlags.LodLevel; + + case TexelLoadScalarType.Texture2DLodZeroOffset: + case TexelLoadScalarType.Texture2DLodLevelOffset: + return TextureFlags.LodLevel | TextureFlags.Offset; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/InstEmitter.cs b/Ryujinx.Graphics/Shader/Instructions/InstEmitter.cs new file mode 100644 index 0000000000..91c740b684 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/InstEmitter.cs @@ -0,0 +1,6 @@ +using Ryujinx.Graphics.Shader.Translation; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + delegate void InstEmitter(EmitterContext context); +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Instructions/Lop3Expression.cs b/Ryujinx.Graphics/Shader/Instructions/Lop3Expression.cs new file mode 100644 index 0000000000..e55ed660a3 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Instructions/Lop3Expression.cs @@ -0,0 +1,149 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.Translation; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Instructions +{ + static class Lop3Expression + { + public static Operand GetFromTruthTable( + EmitterContext context, + Operand srcA, + Operand srcB, + Operand srcC, + int imm) + { + Operand expr = null; + + //Handle some simple cases, or cases where + //the KMap would yield poor results (like XORs). + if (imm == 0x96 || imm == 0x69) + { + //XOR (0x96) and XNOR (0x69). + if (imm == 0x69) + { + srcA = context.BitwiseNot(srcA); + } + + expr = context.BitwiseExclusiveOr(srcA, srcB); + expr = context.BitwiseExclusiveOr(expr, srcC); + + return expr; + } + else if (imm == 0) + { + //Always false. + return Const(IrConsts.False); + } + else if (imm == 0xff) + { + //Always true. + return Const(IrConsts.True); + } + + int map; + + //Encode into gray code. + map = ((imm >> 0) & 1) << 0; + map |= ((imm >> 1) & 1) << 4; + map |= ((imm >> 2) & 1) << 1; + map |= ((imm >> 3) & 1) << 5; + map |= ((imm >> 4) & 1) << 3; + map |= ((imm >> 5) & 1) << 7; + map |= ((imm >> 6) & 1) << 2; + map |= ((imm >> 7) & 1) << 6; + + //Solve KMap, get sum of products. + int visited = 0; + + for (int index = 0; index < 8 && visited != 0xff; index++) + { + if ((map & (1 << index)) == 0) + { + continue; + } + + int mask = 0; + + for (int mSize = 4; mSize != 0; mSize >>= 1) + { + mask = RotateLeft4((1 << mSize) - 1, index & 3) << (index & 4); + + if ((map & mask) == mask) + { + break; + } + } + + //The mask should wrap, if we are on the high row, shift to low etc. + int mask2 = (index & 4) != 0 ? mask >> 4 : mask << 4; + + if ((map & mask2) == mask2) + { + mask |= mask2; + } + + if ((mask & visited) == mask) + { + continue; + } + + bool notA = (mask & 0x33) != 0; + bool notB = (mask & 0x99) != 0; + bool notC = (mask & 0x0f) != 0; + + bool aChanges = (mask & 0xcc) != 0 && notA; + bool bChanges = (mask & 0x66) != 0 && notB; + bool cChanges = (mask & 0xf0) != 0 && notC; + + Operand localExpr = null; + + void And(Operand source) + { + if (localExpr != null) + { + localExpr = context.BitwiseAnd(localExpr, source); + } + else + { + localExpr = source; + } + } + + if (!aChanges) + { + And(context.BitwiseNot(srcA, notA)); + } + + if (!bChanges) + { + And(context.BitwiseNot(srcB, notB)); + } + + if (!cChanges) + { + And(context.BitwiseNot(srcC, notC)); + } + + if (expr != null) + { + expr = context.BitwiseOr(expr, localExpr); + } + else + { + expr = localExpr; + } + + visited |= mask; + } + + return expr; + } + + private static int RotateLeft4(int value, int shift) + { + return ((value << shift) | (value >> (4 - shift))) & 0xf; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/BasicBlock.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/BasicBlock.cs new file mode 100644 index 0000000000..949753377e --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/BasicBlock.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class BasicBlock + { + public int Index { get; set; } + + public LinkedList Operations { get; } + + private BasicBlock _next; + private BasicBlock _branch; + + public BasicBlock Next + { + get => _next; + set => _next = AddSuccessor(_next, value); + } + + public BasicBlock Branch + { + get => _branch; + set => _branch = AddSuccessor(_branch, value); + } + + public bool HasBranch => _branch != null; + + public List Predecessors { get; } + + public HashSet DominanceFrontiers { get; } + + public BasicBlock ImmediateDominator { get; set; } + + public BasicBlock() + { + Operations = new LinkedList(); + + Predecessors = new List(); + + DominanceFrontiers = new HashSet(); + } + + public BasicBlock(int index) : this() + { + Index = index; + } + + private BasicBlock AddSuccessor(BasicBlock oldBlock, BasicBlock newBlock) + { + oldBlock?.Predecessors.Remove(this); + newBlock?.Predecessors.Add(this); + + return newBlock; + } + + public INode GetLastOp() + { + return Operations.Last?.Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/INode.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/INode.cs new file mode 100644 index 0000000000..48dda24b1e --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/INode.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + interface INode + { + Operand Dest { get; set; } + + int SourcesCount { get; } + + Operand GetSource(int index); + + void SetSource(int index, Operand operand); + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/Instruction.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/Instruction.cs new file mode 100644 index 0000000000..ac0ebc2b08 --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/Instruction.cs @@ -0,0 +1,87 @@ +using System; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + [Flags] + enum Instruction + { + Absolute = 1, + Add, + BitfieldExtractS32, + BitfieldExtractU32, + BitfieldInsert, + BitfieldReverse, + BitwiseAnd, + BitwiseExclusiveOr, + BitwiseNot, + BitwiseOr, + Branch, + BranchIfFalse, + BranchIfTrue, + Ceiling, + Clamp, + ClampU32, + CompareEqual, + CompareGreater, + CompareGreaterOrEqual, + CompareGreaterOrEqualU32, + CompareGreaterU32, + CompareLess, + CompareLessOrEqual, + CompareLessOrEqualU32, + CompareLessU32, + CompareNotEqual, + ConditionalSelect, + ConvertFPToS32, + ConvertS32ToFP, + ConvertU32ToFP, + Copy, + Cosine, + Discard, + Divide, + EmitVertex, + EndPrimitive, + ExponentB2, + Floor, + FusedMultiplyAdd, + IsNan, + LoadConstant, + LoadGlobal, + LoadLocal, + LogarithmB2, + LogicalAnd, + LogicalExclusiveOr, + LogicalNot, + LogicalOr, + LoopBreak, + LoopContinue, + MarkLabel, + Maximum, + MaximumU32, + Minimum, + MinimumU32, + Multiply, + Negate, + PackDouble2x32, + PackHalf2x16, + ReciprocalSquareRoot, + Return, + ShiftLeft, + ShiftRightS32, + ShiftRightU32, + Sine, + SquareRoot, + StoreGlobal, + StoreLocal, + Subtract, + TextureSample, + TextureSize, + Truncate, + UnpackDouble2x32, + UnpackHalf2x16, + + Count, + FP = 1 << 16, + Mask = 0xffff + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/IrConsts.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/IrConsts.cs new file mode 100644 index 0000000000..c264e47d1a --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/IrConsts.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + static class IrConsts + { + public const int False = 0; + public const int True = -1; + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/Operand.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/Operand.cs new file mode 100644 index 0000000000..1df88a3d9b --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/Operand.cs @@ -0,0 +1,79 @@ +using Ryujinx.Graphics.Shader.Decoders; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class Operand + { + private const int CbufSlotBits = 5; + private const int CbufSlotLsb = 32 - CbufSlotBits; + private const int CbufSlotMask = (1 << CbufSlotBits) - 1; + + public OperandType Type { get; } + + public int Value { get; } + + public INode AsgOp { get; set; } + + public HashSet UseOps { get; } + + private Operand() + { + UseOps = new HashSet(); + } + + public Operand(OperandType type) : this() + { + Type = type; + } + + public Operand(OperandType type, int value) : this() + { + Type = type; + Value = value; + } + + public Operand(Register reg) : this() + { + Type = OperandType.Register; + Value = PackRegInfo(reg.Index, reg.Type); + } + + public Operand(int slot, int offset) : this() + { + Type = OperandType.ConstantBuffer; + Value = PackCbufInfo(slot, offset); + } + + private static int PackCbufInfo(int slot, int offset) + { + return (slot << CbufSlotLsb) | offset; + } + + private static int PackRegInfo(int index, RegisterType type) + { + return ((int)type << 24) | index; + } + + public int GetCbufSlot() + { + return (Value >> CbufSlotLsb) & CbufSlotMask; + } + + public int GetCbufOffset() + { + return Value & ~(CbufSlotMask << CbufSlotLsb); + } + + public Register GetRegister() + { + return new Register(Value & 0xffffff, (RegisterType)(Value >> 24)); + } + + public float AsFloat() + { + return BitConverter.Int32BitsToSingle(Value); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/OperandHelper.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/OperandHelper.cs new file mode 100644 index 0000000000..6765f8a44f --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/OperandHelper.cs @@ -0,0 +1,62 @@ +using Ryujinx.Graphics.Shader.Decoders; +using System; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + static class OperandHelper + { + public static Operand Attribute(int value) + { + return new Operand(OperandType.Attribute, value); + } + + public static Operand Cbuf(int slot, int offset) + { + return new Operand(slot, offset); + } + + public static Operand Const(int value) + { + return new Operand(OperandType.Constant, value); + } + + public static Operand ConstF(float value) + { + return new Operand(OperandType.Constant, BitConverter.SingleToInt32Bits(value)); + } + + public static Operand Label() + { + return new Operand(OperandType.Label); + } + + public static Operand Local() + { + return new Operand(OperandType.LocalVariable); + } + + public static Operand Register(int index, RegisterType type) + { + return Register(new Register(index, type)); + } + + public static Operand Register(Register reg) + { + if (reg.IsRZ) + { + return Const(0); + } + else if (reg.IsPT) + { + return Const(IrConsts.True); + } + + return new Operand(reg); + } + + public static Operand Undef() + { + return new Operand(OperandType.Undefined); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/OperandType.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/OperandType.cs new file mode 100644 index 0000000000..e0e2a6675a --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/OperandType.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + enum OperandType + { + Attribute, + Constant, + ConstantBuffer, + GlobalMemory, + Label, + LocalMemory, + LocalVariable, + Register, + Undefined + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/Operation.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/Operation.cs new file mode 100644 index 0000000000..f657995370 --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/Operation.cs @@ -0,0 +1,101 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class Operation : INode + { + public Instruction Inst { get; private set; } + + private Operand _dest; + + public Operand Dest + { + get => _dest; + set => _dest = AssignDest(value); + } + + private Operand[] _sources; + + public int SourcesCount => _sources.Length; + + public int ComponentIndex { get; } + + public Operation(Instruction inst, Operand dest, params Operand[] sources) + { + Inst = inst; + Dest = dest; + + //The array may be modified externally, so we store a copy. + _sources = (Operand[])sources.Clone(); + + for (int index = 0; index < _sources.Length; index++) + { + Operand source = _sources[index]; + + if (source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + } + } + + public Operation( + Instruction inst, + int compIndex, + Operand dest, + params Operand[] sources) : this(inst, dest, sources) + { + ComponentIndex = compIndex; + } + + private Operand AssignDest(Operand dest) + { + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + + return dest; + } + + public Operand GetSource(int index) + { + return _sources[index]; + } + + public void SetSource(int index, Operand source) + { + Operand oldSrc = _sources[index]; + + if (oldSrc != null && oldSrc.Type == OperandType.LocalVariable) + { + oldSrc.UseOps.Remove(this); + } + + if (source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + + _sources[index] = source; + } + + public void TurnIntoCopy(Operand source) + { + Inst = Instruction.Copy; + + foreach (Operand oldSrc in _sources) + { + if (oldSrc.Type == OperandType.LocalVariable) + { + oldSrc.UseOps.Remove(this); + } + } + + if (source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + + _sources = new Operand[] { source }; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/PhiNode.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/PhiNode.cs new file mode 100644 index 0000000000..13ff41bd14 --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/PhiNode.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class PhiNode : INode + { + private Operand _dest; + + public Operand Dest + { + get => _dest; + set => _dest = AssignDest(value); + } + + private HashSet _blocks; + + private class PhiSource + { + public BasicBlock Block { get; } + public Operand Operand { get; set; } + + public PhiSource(BasicBlock block, Operand operand) + { + Block = block; + Operand = operand; + } + } + + private List _sources; + + public int SourcesCount => _sources.Count; + + public PhiNode(Operand dest) + { + _blocks = new HashSet(); + + _sources = new List(); + + dest.AsgOp = this; + + Dest = dest; + } + + private Operand AssignDest(Operand dest) + { + if (dest != null && dest.Type == OperandType.LocalVariable) + { + dest.AsgOp = this; + } + + return dest; + } + + public void AddSource(BasicBlock block, Operand operand) + { + if (_blocks.Add(block)) + { + if (operand.Type == OperandType.LocalVariable) + { + operand.UseOps.Add(this); + } + + _sources.Add(new PhiSource(block, operand)); + } + } + + public Operand GetSource(int index) + { + return _sources[index].Operand; + } + + public BasicBlock GetBlock(int index) + { + return _sources[index].Block; + } + + public void SetSource(int index, Operand source) + { + Operand oldSrc = _sources[index].Operand; + + if (oldSrc != null && oldSrc.Type == OperandType.LocalVariable) + { + oldSrc.UseOps.Remove(this); + } + + if (source.Type == OperandType.LocalVariable) + { + source.UseOps.Add(this); + } + + _sources[index].Operand = source; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureFlags.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureFlags.cs new file mode 100644 index 0000000000..5f0a84276c --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureFlags.cs @@ -0,0 +1,17 @@ +using System; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + [Flags] + enum TextureFlags + { + None = 0, + Bindless = 1 << 0, + Gather = 1 << 1, + IntCoords = 1 << 2, + LodBias = 1 << 3, + LodLevel = 1 << 4, + Offset = 1 << 5, + Offsets = 1 << 6 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureOperation.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureOperation.cs new file mode 100644 index 0000000000..f5f2cc5c60 --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureOperation.cs @@ -0,0 +1,24 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + class TextureOperation : Operation + { + public TextureType Type { get; } + public TextureFlags Flags { get; } + + public int Handle { get; } + + public TextureOperation( + Instruction inst, + TextureType type, + TextureFlags flags, + int handle, + int compIndex, + Operand dest, + params Operand[] sources) : base(inst, compIndex, dest, sources) + { + Type = type; + Flags = flags; + Handle = handle; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureType.cs b/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureType.cs new file mode 100644 index 0000000000..bf20700776 --- /dev/null +++ b/Ryujinx.Graphics/Shader/IntermediateRepresentation/TextureType.cs @@ -0,0 +1,35 @@ +using System; + +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + [Flags] + enum TextureType + { + Texture1D, + Texture2D, + Texture3D, + TextureCube, + + Mask = 0xff, + + Array = 1 << 8, + Multisample = 1 << 9, + Shadow = 1 << 10 + } + + static class TextureTypeExtensions + { + public static int GetCoordsCount(this TextureType type) + { + switch (type & TextureType.Mask) + { + case TextureType.Texture1D: return 1; + case TextureType.Texture2D: return 2; + case TextureType.Texture3D: return 3; + case TextureType.TextureCube: return 3; + } + + throw new ArgumentException($"Invalid texture type \"{type}\"."); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/ShaderConfig.cs b/Ryujinx.Graphics/Shader/ShaderConfig.cs new file mode 100644 index 0000000000..c2a94814e9 --- /dev/null +++ b/Ryujinx.Graphics/Shader/ShaderConfig.cs @@ -0,0 +1,23 @@ +using Ryujinx.Graphics.Gal; +using System; + +namespace Ryujinx.Graphics.Shader +{ + public struct ShaderConfig + { + public GalShaderType Type { get; } + + public int MaxCBufferSize; + + public ShaderConfig(GalShaderType type, int maxCBufferSize) + { + if (maxCBufferSize <= 0) + { + throw new ArgumentOutOfRangeException(nameof(maxCBufferSize)); + } + + Type = type; + MaxCBufferSize = maxCBufferSize; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/ShaderHeader.cs b/Ryujinx.Graphics/Shader/ShaderHeader.cs new file mode 100644 index 0000000000..53abdc56ed --- /dev/null +++ b/Ryujinx.Graphics/Shader/ShaderHeader.cs @@ -0,0 +1,166 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Shader.Decoders; +using System; + +namespace Ryujinx.Graphics.Shader +{ + struct OutputMapTarget + { + public bool Red { get; } + public bool Green { get; } + public bool Blue { get; } + public bool Alpha { get; } + + public bool Enabled => Red || Green || Blue || Alpha; + + public OutputMapTarget(bool red, bool green, bool blue, bool alpha) + { + Red = red; + Green = green; + Blue = blue; + Alpha = alpha; + } + + public bool ComponentEnabled(int component) + { + switch (component) + { + case 0: return Red; + case 1: return Green; + case 2: return Blue; + case 3: return Alpha; + } + + throw new ArgumentOutOfRangeException(nameof(component)); + } + } + + class ShaderHeader + { + public int SphType { get; } + + public int Version { get; } + + public int ShaderType { get; } + + public bool MrtEnable { get; } + + public bool KillsPixels { get; } + + public bool DoesGlobalStore { get; } + + public int SassVersion { get; } + + public bool DoesLoadOrStore { get; } + + public bool DoesFp64 { get; } + + public int StreamOutMask{ get; } + + public int ShaderLocalMemoryLowSize { get; } + + public int PerPatchAttributeCount { get; } + + public int ShaderLocalMemoryHighSize { get; } + + public int ThreadsPerInputPrimitive { get; } + + public int ShaderLocalMemoryCrsSize { get; } + + public int OutputTopology { get; } + + public int MaxOutputVertexCount { get; } + + public int StoreReqStart { get; } + public int StoreReqEnd { get; } + + public OutputMapTarget[] OmapTargets { get; } + public bool OmapSampleMask { get; } + public bool OmapDepth { get; } + + public ShaderHeader(IGalMemory memory, ulong address) + { + int commonWord0 = memory.ReadInt32((long)address + 0); + int commonWord1 = memory.ReadInt32((long)address + 4); + int commonWord2 = memory.ReadInt32((long)address + 8); + int commonWord3 = memory.ReadInt32((long)address + 12); + int commonWord4 = memory.ReadInt32((long)address + 16); + + SphType = commonWord0.Extract(0, 5); + + Version = commonWord0.Extract(5, 5); + + ShaderType = commonWord0.Extract(10, 4); + + MrtEnable = commonWord0.Extract(14); + + KillsPixels = commonWord0.Extract(15); + + DoesGlobalStore = commonWord0.Extract(16); + + SassVersion = commonWord0.Extract(17, 4); + + DoesLoadOrStore = commonWord0.Extract(26); + + DoesFp64 = commonWord0.Extract(27); + + StreamOutMask = commonWord0.Extract(28, 4); + + ShaderLocalMemoryLowSize = commonWord1.Extract(0, 24); + + PerPatchAttributeCount = commonWord1.Extract(24, 8); + + ShaderLocalMemoryHighSize = commonWord2.Extract(0, 24); + + ThreadsPerInputPrimitive = commonWord2.Extract(24, 8); + + ShaderLocalMemoryCrsSize = commonWord3.Extract(0, 24); + + OutputTopology = commonWord3.Extract(24, 4); + + MaxOutputVertexCount = commonWord4.Extract(0, 12); + + StoreReqStart = commonWord4.Extract(12, 8); + StoreReqEnd = commonWord4.Extract(24, 8); + + int type2OmapTarget = memory.ReadInt32((long)address + 72); + int type2Omap = memory.ReadInt32((long)address + 76); + + OmapTargets = new OutputMapTarget[8]; + + for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4) + { + OmapTargets[offset >> 2] = new OutputMapTarget( + type2OmapTarget.Extract(offset + 0), + type2OmapTarget.Extract(offset + 1), + type2OmapTarget.Extract(offset + 2), + type2OmapTarget.Extract(offset + 3)); + } + + OmapSampleMask = type2Omap.Extract(0); + OmapDepth = type2Omap.Extract(1); + } + + public int DepthRegister + { + get + { + int count = 0; + + for (int index = 0; index < OmapTargets.Length; index++) + { + for (int component = 0; component < 4; component++) + { + if (OmapTargets[index].ComponentEnabled(component)) + { + count++; + } + } + } + + //Depth register is always two registers after the last color output. + return count + 1; + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/ShaderProgram.cs b/Ryujinx.Graphics/Shader/ShaderProgram.cs new file mode 100644 index 0000000000..9257fd262d --- /dev/null +++ b/Ryujinx.Graphics/Shader/ShaderProgram.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Graphics.Shader +{ + public class ShaderProgram + { + public ShaderProgramInfo Info { get; } + + public string Code { get; } + + internal ShaderProgram(ShaderProgramInfo info, string code) + { + Info = info; + Code = code; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/ShaderProgramInfo.cs b/Ryujinx.Graphics/Shader/ShaderProgramInfo.cs new file mode 100644 index 0000000000..c529a3536f --- /dev/null +++ b/Ryujinx.Graphics/Shader/ShaderProgramInfo.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.ObjectModel; + +namespace Ryujinx.Graphics.Shader +{ + public class ShaderProgramInfo + { + public ReadOnlyCollection CBuffers { get; } + public ReadOnlyCollection Textures { get; } + + internal ShaderProgramInfo(CBufferDescriptor[] cBuffers, TextureDescriptor[] textures) + { + CBuffers = Array.AsReadOnly(cBuffers); + Textures = Array.AsReadOnly(textures); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstAssignment.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstAssignment.cs new file mode 100644 index 0000000000..bb3fe7af4b --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstAssignment.cs @@ -0,0 +1,35 @@ +using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class AstAssignment : AstNode + { + public IAstNode Destination { get; } + + private IAstNode _source; + + public IAstNode Source + { + get + { + return _source; + } + set + { + RemoveUse(_source, this); + + AddUse(value, this); + + _source = value; + } + } + + public AstAssignment(IAstNode destination, IAstNode source) + { + Destination = destination; + Source = source; + + AddDef(destination, this); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstBlock.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstBlock.cs new file mode 100644 index 0000000000..fdef87de56 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstBlock.cs @@ -0,0 +1,116 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System; +using System.Collections; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class AstBlock : AstNode, IEnumerable + { + public AstBlockType Type { get; private set; } + + private IAstNode _condition; + + public IAstNode Condition + { + get + { + return _condition; + } + set + { + RemoveUse(_condition, this); + + AddUse(value, this); + + _condition = value; + } + } + + private LinkedList _nodes; + + public IAstNode First => _nodes.First?.Value; + + public int Count => _nodes.Count; + + public AstBlock(AstBlockType type, IAstNode condition = null) + { + Type = type; + Condition = condition; + + _nodes = new LinkedList(); + } + + public void Add(IAstNode node) + { + Add(node, _nodes.AddLast(node)); + } + + public void AddFirst(IAstNode node) + { + Add(node, _nodes.AddFirst(node)); + } + + public void AddBefore(IAstNode next, IAstNode node) + { + Add(node, _nodes.AddBefore(next.LLNode, node)); + } + + public void AddAfter(IAstNode prev, IAstNode node) + { + Add(node, _nodes.AddAfter(prev.LLNode, node)); + } + + private void Add(IAstNode node, LinkedListNode newNode) + { + if (node.Parent != null) + { + throw new ArgumentException("Node already belongs to a block."); + } + + node.Parent = this; + node.LLNode = newNode; + } + + public void Remove(IAstNode node) + { + _nodes.Remove(node.LLNode); + + node.Parent = null; + node.LLNode = null; + } + + public void AndCondition(IAstNode cond) + { + Condition = new AstOperation(Instruction.LogicalAnd, Condition, cond); + } + + public void OrCondition(IAstNode cond) + { + Condition = new AstOperation(Instruction.LogicalOr, Condition, cond); + } + public void TurnIntoIf(IAstNode cond) + { + Condition = cond; + + Type = AstBlockType.If; + } + + public void TurnIntoElseIf() + { + Type = AstBlockType.ElseIf; + } + + public IEnumerator GetEnumerator() + { + return _nodes.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstBlockType.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstBlockType.cs new file mode 100644 index 0000000000..c12efda909 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstBlockType.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + enum AstBlockType + { + DoWhile, + If, + Else, + ElseIf, + Main, + While + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstBlockVisitor.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstBlockVisitor.cs new file mode 100644 index 0000000000..9397fdb913 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstBlockVisitor.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class AstBlockVisitor + { + public AstBlock Block { get; private set; } + + public class BlockVisitationEventArgs : EventArgs + { + public AstBlock Block { get; } + + public BlockVisitationEventArgs(AstBlock block) + { + Block = block; + } + } + + public event EventHandler BlockEntered; + public event EventHandler BlockLeft; + + public AstBlockVisitor(AstBlock mainBlock) + { + Block = mainBlock; + } + + public IEnumerable Visit() + { + IAstNode node = Block.First; + + while (node != null) + { + //We reached a child block, visit the nodes inside. + while (node is AstBlock childBlock) + { + Block = childBlock; + + node = childBlock.First; + + BlockEntered?.Invoke(this, new BlockVisitationEventArgs(Block)); + } + + //Node may be null, if the block is empty. + if (node != null) + { + IAstNode next = Next(node); + + yield return node; + + node = next; + } + + //We reached the end of the list, go up on tree to the parent blocks. + while (node == null && Block.Type != AstBlockType.Main) + { + BlockLeft?.Invoke(this, new BlockVisitationEventArgs(Block)); + + node = Next(Block); + + Block = Block.Parent; + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstHelper.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstHelper.cs new file mode 100644 index 0000000000..9d3148e1bb --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstHelper.cs @@ -0,0 +1,73 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + static class AstHelper + { + public static void AddUse(IAstNode node, IAstNode parent) + { + if (node is AstOperand operand && operand.Type == OperandType.LocalVariable) + { + operand.Uses.Add(parent); + } + } + + public static void AddDef(IAstNode node, IAstNode parent) + { + if (node is AstOperand operand && operand.Type == OperandType.LocalVariable) + { + operand.Defs.Add(parent); + } + } + + public static void RemoveUse(IAstNode node, IAstNode parent) + { + if (node is AstOperand operand && operand.Type == OperandType.LocalVariable) + { + operand.Uses.Remove(parent); + } + } + + public static void RemoveDef(IAstNode node, IAstNode parent) + { + if (node is AstOperand operand && operand.Type == OperandType.LocalVariable) + { + operand.Defs.Remove(parent); + } + } + + public static AstAssignment Assign(IAstNode destination, IAstNode source) + { + return new AstAssignment(destination, source); + } + + public static AstOperand Const(int value) + { + return new AstOperand(OperandType.Constant, value); + } + + public static AstOperand Local(VariableType type) + { + AstOperand local = new AstOperand(OperandType.LocalVariable); + + local.VarType = type; + + return local; + } + + public static IAstNode InverseCond(IAstNode cond) + { + return new AstOperation(Instruction.LogicalNot, cond); + } + + public static IAstNode Next(IAstNode node) + { + return node.LLNode.Next?.Value; + } + + public static IAstNode Previous(IAstNode node) + { + return node.LLNode.Previous?.Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstNode.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstNode.cs new file mode 100644 index 0000000000..c667aac988 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstNode.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class AstNode : IAstNode + { + public AstBlock Parent { get; set; } + + public LinkedListNode LLNode { get; set; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstOperand.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstOperand.cs new file mode 100644 index 0000000000..97ff3ca97c --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstOperand.cs @@ -0,0 +1,49 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class AstOperand : AstNode + { + public HashSet Defs { get; } + public HashSet Uses { get; } + + public OperandType Type { get; } + + public VariableType VarType { get; set; } + + public int Value { get; } + + public int CbufSlot { get; } + public int CbufOffset { get; } + + private AstOperand() + { + Defs = new HashSet(); + Uses = new HashSet(); + + VarType = VariableType.S32; + } + + public AstOperand(Operand operand) : this() + { + Type = operand.Type; + + if (Type == OperandType.ConstantBuffer) + { + CbufSlot = operand.GetCbufSlot(); + CbufOffset = operand.GetCbufOffset(); + } + else + { + Value = operand.Value; + } + } + + public AstOperand(OperandType type, int value = 0) : this() + { + Type = type; + Value = value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstOperation.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstOperation.cs new file mode 100644 index 0000000000..1607ffecde --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstOperation.cs @@ -0,0 +1,49 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; + +using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class AstOperation : AstNode + { + public Instruction Inst { get; } + + public int ComponentMask { get; } + + private IAstNode[] _sources; + + public int SourcesCount => _sources.Length; + + public AstOperation(Instruction inst, params IAstNode[] sources) + { + Inst = inst; + _sources = sources; + + foreach (IAstNode source in sources) + { + AddUse(source, this); + } + + ComponentMask = 1; + } + + public AstOperation(Instruction inst, int compMask, params IAstNode[] sources) : this(inst, sources) + { + ComponentMask = compMask; + } + + public IAstNode GetSource(int index) + { + return _sources[index]; + } + + public void SetSource(int index, IAstNode source) + { + RemoveUse(_sources[index], this); + + AddUse(source, this); + + _sources[index] = source; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstOptimizer.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstOptimizer.cs new file mode 100644 index 0000000000..0f5392b7d6 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstOptimizer.cs @@ -0,0 +1,149 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; +using System.Linq; + +using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + static class AstOptimizer + { + public static void Optimize(StructuredProgramInfo info) + { + AstBlock mainBlock = info.MainBlock; + + AstBlockVisitor visitor = new AstBlockVisitor(mainBlock); + + foreach (IAstNode node in visitor.Visit()) + { + if (node is AstAssignment assignment && assignment.Destination is AstOperand propVar) + { + bool isWorthPropagating = propVar.Uses.Count == 1 || IsWorthPropagating(assignment.Source); + + if (propVar.Defs.Count == 1 && isWorthPropagating) + { + PropagateExpression(propVar, assignment.Source); + } + + if (propVar.Type == OperandType.LocalVariable && propVar.Uses.Count == 0) + { + visitor.Block.Remove(assignment); + + info.Locals.Remove(propVar); + } + } + } + + RemoveEmptyBlocks(mainBlock); + } + + private static bool IsWorthPropagating(IAstNode source) + { + if (!(source is AstOperation srcOp)) + { + return false; + } + + if (!InstructionInfo.IsUnary(srcOp.Inst)) + { + return false; + } + + return srcOp.GetSource(0) is AstOperand || srcOp.Inst == Instruction.Copy; + } + + private static void PropagateExpression(AstOperand propVar, IAstNode source) + { + IAstNode[] uses = propVar.Uses.ToArray(); + + foreach (IAstNode useNode in uses) + { + if (useNode is AstBlock useBlock) + { + useBlock.Condition = source; + } + else if (useNode is AstOperation useOperation) + { + for (int srcIndex = 0; srcIndex < useOperation.SourcesCount; srcIndex++) + { + if (useOperation.GetSource(srcIndex) == propVar) + { + useOperation.SetSource(srcIndex, source); + } + } + } + else if (useNode is AstAssignment useAssignment) + { + useAssignment.Source = source; + } + } + } + + private static void RemoveEmptyBlocks(AstBlock mainBlock) + { + Queue pending = new Queue(); + + pending.Enqueue(mainBlock); + + while (pending.TryDequeue(out AstBlock block)) + { + foreach (IAstNode node in block) + { + if (node is AstBlock childBlock) + { + pending.Enqueue(childBlock); + } + } + + AstBlock parent = block.Parent; + + if (parent == null) + { + continue; + } + + AstBlock nextBlock = Next(block) as AstBlock; + + bool hasElse = nextBlock != null && nextBlock.Type == AstBlockType.Else; + + bool isIf = block.Type == AstBlockType.If; + + if (block.Count == 0) + { + if (isIf) + { + if (hasElse) + { + nextBlock.TurnIntoIf(InverseCond(block.Condition)); + } + + parent.Remove(block); + } + else if (block.Type == AstBlockType.Else) + { + parent.Remove(block); + } + } + else if (isIf && parent.Type == AstBlockType.Else && parent.Count == (hasElse ? 2 : 1)) + { + AstBlock parentOfParent = parent.Parent; + + parent.Remove(block); + + parentOfParent.AddAfter(parent, block); + + if (hasElse) + { + parent.Remove(nextBlock); + + parentOfParent.AddAfter(block, nextBlock); + } + + parentOfParent.Remove(parent); + + block.TurnIntoElseIf(); + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/AstTextureOperation.cs b/Ryujinx.Graphics/Shader/StructuredIr/AstTextureOperation.cs new file mode 100644 index 0000000000..e40f7b70eb --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/AstTextureOperation.cs @@ -0,0 +1,25 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class AstTextureOperation : AstOperation + { + public TextureType Type { get; } + public TextureFlags Flags { get; } + + public int Handle { get; } + + public AstTextureOperation( + Instruction inst, + TextureType type, + TextureFlags flags, + int handle, + int compMask, + params IAstNode[] sources) : base(inst, compMask, sources) + { + Type = type; + Flags = flags; + Handle = handle; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/GotoElimination.cs b/Ryujinx.Graphics/Shader/StructuredIr/GotoElimination.cs new file mode 100644 index 0000000000..dffc3142f1 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/GotoElimination.cs @@ -0,0 +1,459 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + static class GotoElimination + { + //This is a modified version of the algorithm presented on the paper + //"Taming Control Flow: A Structured Approach to Eliminating Goto Statements". + public static void Eliminate(GotoStatement[] gotos) + { + for (int index = gotos.Length - 1; index >= 0; index--) + { + GotoStatement stmt = gotos[index]; + + AstBlock gBlock = ParentBlock(stmt.Goto); + AstBlock lBlock = ParentBlock(stmt.Label); + + int gLevel = Level(gBlock); + int lLevel = Level(lBlock); + + if (IndirectlyRelated(gBlock, lBlock, gLevel, lLevel)) + { + AstBlock drBlock = gBlock; + + int drLevel = gLevel; + + do + { + drBlock = drBlock.Parent; + + drLevel--; + } + while (!DirectlyRelated(drBlock, lBlock, drLevel, lLevel)); + + MoveOutward(stmt, gLevel, drLevel); + + gBlock = drBlock; + gLevel = drLevel; + + if (Previous(stmt.Goto) is AstBlock elseBlock && elseBlock.Type == AstBlockType.Else) + { + //It's possible that the label was enclosed inside an else block, + //in this case we need to update the block and level. + //We also need to set the IsLoop for the case when the label is + //now before the goto, due to the newly introduced else block. + lBlock = ParentBlock(stmt.Label); + + lLevel = Level(lBlock); + + if (!IndirectlyRelated(elseBlock, lBlock, gLevel + 1, lLevel)) + { + stmt.IsLoop = true; + } + } + } + + if (DirectlyRelated(gBlock, lBlock, gLevel, lLevel)) + { + if (gLevel > lLevel) + { + MoveOutward(stmt, gLevel, lLevel); + } + else + { + if (stmt.IsLoop) + { + Lift(stmt); + } + + MoveInward(stmt); + } + } + + gBlock = ParentBlock(stmt.Goto); + + if (stmt.IsLoop) + { + EncloseDoWhile(stmt, gBlock, stmt.Label); + } + else + { + Enclose(gBlock, AstBlockType.If, stmt.Condition, Next(stmt.Goto), stmt.Label); + } + + gBlock.Remove(stmt.Goto); + } + } + + private static bool IndirectlyRelated(AstBlock lBlock, AstBlock rBlock, int lLevel, int rlevel) + { + return !(lBlock == rBlock || DirectlyRelated(lBlock, rBlock, lLevel, rlevel)); + } + + private static bool DirectlyRelated(AstBlock lBlock, AstBlock rBlock, int lLevel, int rLevel) + { + //If the levels are equal, they can be either siblings or indirectly related. + if (lLevel == rLevel) + { + return false; + } + + IAstNode block; + IAstNode other; + + int blockLvl, otherLvl; + + if (lLevel > rLevel) + { + block = lBlock; + blockLvl = lLevel; + other = rBlock; + otherLvl = rLevel; + } + else /* if (rLevel > lLevel) */ + { + block = rBlock; + blockLvl = rLevel; + other = lBlock; + otherLvl = lLevel; + } + + while (blockLvl >= otherLvl) + { + if (block == other) + { + return true; + } + + block = block.Parent; + + blockLvl--; + } + + return false; + } + + private static void Lift(GotoStatement stmt) + { + AstBlock block = ParentBlock(stmt.Goto); + + AstBlock[] path = BackwardsPath(block, ParentBlock(stmt.Label)); + + AstBlock loopFirstStmt = path[path.Length - 1]; + + if (loopFirstStmt.Type == AstBlockType.Else) + { + loopFirstStmt = Previous(loopFirstStmt) as AstBlock; + + if (loopFirstStmt == null || loopFirstStmt.Type != AstBlockType.If) + { + throw new InvalidOperationException("Found an else without a matching if."); + } + } + + AstBlock newBlock = EncloseDoWhile(stmt, block, loopFirstStmt); + + block.Remove(stmt.Goto); + + newBlock.AddFirst(stmt.Goto); + + stmt.IsLoop = false; + } + + private static void MoveOutward(GotoStatement stmt, int gLevel, int lLevel) + { + AstBlock origin = ParentBlock(stmt.Goto); + + AstBlock block = origin; + + //Check if a loop is enclosing the goto, and the block that is + //directly related to the label is above the loop block. + //In that case, we need to introduce a break to get out of the loop. + AstBlock loopBlock = origin; + + int loopLevel = gLevel; + + while (loopLevel > lLevel) + { + AstBlock child = loopBlock; + + loopBlock = loopBlock.Parent; + + loopLevel--; + + if (child.Type == AstBlockType.DoWhile) + { + EncloseSingleInst(stmt, Instruction.LoopBreak); + + block.Remove(stmt.Goto); + + loopBlock.AddAfter(child, stmt.Goto); + + block = loopBlock; + gLevel = loopLevel; + } + } + + //Insert ifs to skip the parts that shouldn't be executed due to the goto. + bool tryInsertElse = stmt.IsUnconditional && origin.Type == AstBlockType.If; + + while (gLevel > lLevel) + { + Enclose(block, AstBlockType.If, stmt.Condition, Next(stmt.Goto)); + + block.Remove(stmt.Goto); + + AstBlock child = block; + + //We can't move the goto in the middle of a if and a else block, in + //this case we need to move it after the else. + //IsLoop may need to be updated if the label is inside the else, as + //introducing a loop is the only way to ensure the else will be executed. + if (Next(child) is AstBlock elseBlock && elseBlock.Type == AstBlockType.Else) + { + child = elseBlock; + } + + block = block.Parent; + + block.AddAfter(child, stmt.Goto); + + gLevel--; + + if (tryInsertElse && child == origin) + { + AstBlock lBlock = ParentBlock(stmt.Label); + + IAstNode last = block == lBlock && !stmt.IsLoop ? stmt.Label : null; + + AstBlock newBlock = Enclose(block, AstBlockType.Else, null, Next(stmt.Goto), last); + + if (newBlock != null) + { + block.Remove(stmt.Goto); + + block.AddAfter(newBlock, stmt.Goto); + } + } + } + } + + private static void MoveInward(GotoStatement stmt) + { + AstBlock block = ParentBlock(stmt.Goto); + + AstBlock[] path = BackwardsPath(block, ParentBlock(stmt.Label)); + + for (int index = path.Length - 1; index >= 0; index--) + { + AstBlock child = path[index]; + AstBlock last = child; + + if (child.Type == AstBlockType.If) + { + //Modify the if condition to allow it to be entered by the goto. + if (!ContainsCondComb(child.Condition, Instruction.LogicalOr, stmt.Condition)) + { + child.OrCondition(stmt.Condition); + } + } + else if (child.Type == AstBlockType.Else) + { + //Modify the matching if condition to force the else to be entered by the goto. + if (!(Previous(child) is AstBlock ifBlock) || ifBlock.Type != AstBlockType.If) + { + throw new InvalidOperationException("Found an else without a matching if."); + } + + IAstNode cond = InverseCond(stmt.Condition); + + if (!ContainsCondComb(ifBlock.Condition, Instruction.LogicalAnd, cond)) + { + ifBlock.AndCondition(cond); + } + + last = ifBlock; + } + + Enclose(block, AstBlockType.If, stmt.Condition, Next(stmt.Goto), last); + + block.Remove(stmt.Goto); + + child.AddFirst(stmt.Goto); + + block = child; + } + } + + private static bool ContainsCondComb(IAstNode node, Instruction inst, IAstNode newCond) + { + while (node is AstOperation operation && operation.SourcesCount == 2) + { + if (operation.Inst == inst && IsSameCond(operation.GetSource(1), newCond)) + { + return true; + } + + node = operation.GetSource(0); + } + + return false; + } + + private static AstBlock EncloseDoWhile(GotoStatement stmt, AstBlock block, IAstNode first) + { + if (block.Type == AstBlockType.DoWhile && first == block.First) + { + //We only need to insert the continue if we're not at the end of the loop, + //or if our condition is different from the loop condition. + if (Next(stmt.Goto) != null || block.Condition != stmt.Condition) + { + EncloseSingleInst(stmt, Instruction.LoopContinue); + } + + //Modify the do-while condition to allow it to continue. + if (!ContainsCondComb(block.Condition, Instruction.LogicalOr, stmt.Condition)) + { + block.OrCondition(stmt.Condition); + } + + return block; + } + + return Enclose(block, AstBlockType.DoWhile, stmt.Condition, first, stmt.Goto); + } + + private static void EncloseSingleInst(GotoStatement stmt, Instruction inst) + { + AstBlock block = ParentBlock(stmt.Goto); + + AstBlock newBlock = new AstBlock(AstBlockType.If, stmt.Condition); + + block.AddAfter(stmt.Goto, newBlock); + + newBlock.AddFirst(new AstOperation(inst)); + } + + private static AstBlock Enclose( + AstBlock block, + AstBlockType type, + IAstNode cond, + IAstNode first, + IAstNode last = null) + { + if (first == last) + { + return null; + } + + if (type == AstBlockType.If) + { + cond = InverseCond(cond); + } + + //Do a quick check, if we are enclosing a single block, + //and the block type/condition matches the one we're going + //to create, then we don't need a new block, we can just + //return the old one. + bool hasSingleNode = Next(first) == last; + + if (hasSingleNode && BlockMatches(first, type, cond)) + { + return first as AstBlock; + } + + AstBlock newBlock = new AstBlock(type, cond); + + block.AddBefore(first, newBlock); + + while (first != last) + { + IAstNode next = Next(first); + + block.Remove(first); + + newBlock.Add(first); + + first = next; + } + + return newBlock; + } + + private static bool BlockMatches(IAstNode node, AstBlockType type, IAstNode cond) + { + if (!(node is AstBlock block)) + { + return false; + } + + return block.Type == type && IsSameCond(block.Condition, cond); + } + + private static bool IsSameCond(IAstNode lCond, IAstNode rCond) + { + if (lCond is AstOperation lCondOp && lCondOp.Inst == Instruction.LogicalNot) + { + if (!(rCond is AstOperation rCondOp) || rCondOp.Inst != lCondOp.Inst) + { + return false; + } + + lCond = lCondOp.GetSource(0); + rCond = rCondOp.GetSource(0); + } + + return lCond == rCond; + } + + private static AstBlock ParentBlock(IAstNode node) + { + if (node is AstBlock block) + { + return block.Parent; + } + + while (!(node is AstBlock)) + { + node = node.Parent; + } + + return node as AstBlock; + } + + private static AstBlock[] BackwardsPath(AstBlock top, AstBlock bottom) + { + AstBlock block = bottom; + + List path = new List(); + + while (block != top) + { + path.Add(block); + + block = block.Parent; + } + + return path.ToArray(); + } + + private static int Level(IAstNode node) + { + int level = 0; + + while (node != null) + { + level++; + + node = node.Parent; + } + + return level; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/GotoStatement.cs b/Ryujinx.Graphics/Shader/StructuredIr/GotoStatement.cs new file mode 100644 index 0000000000..25216e55fb --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/GotoStatement.cs @@ -0,0 +1,23 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class GotoStatement + { + public AstOperation Goto { get; } + public AstAssignment Label { get; } + + public IAstNode Condition => Label.Destination; + + public bool IsLoop { get; set; } + + public bool IsUnconditional => Goto.Inst == Instruction.Branch; + + public GotoStatement(AstOperation branch, AstAssignment label, bool isLoop) + { + Goto = branch; + Label = label; + IsLoop = isLoop; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/IAstNode.cs b/Ryujinx.Graphics/Shader/StructuredIr/IAstNode.cs new file mode 100644 index 0000000000..5ececbb5e4 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/IAstNode.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + interface IAstNode + { + AstBlock Parent { get; set; } + + LinkedListNode LLNode { get; set; } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/InstructionInfo.cs b/Ryujinx.Graphics/Shader/StructuredIr/InstructionInfo.cs new file mode 100644 index 0000000000..46a61553b8 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/InstructionInfo.cs @@ -0,0 +1,142 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + static class InstructionInfo + { + private struct InstInfo + { + public VariableType DestType { get; } + + public VariableType[] SrcTypes { get; } + + public InstInfo(VariableType destType, params VariableType[] srcTypes) + { + DestType = destType; + SrcTypes = srcTypes; + } + } + + private static InstInfo[] _infoTbl; + + static InstructionInfo() + { + _infoTbl = new InstInfo[(int)Instruction.Count]; + + Add(Instruction.Absolute, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.Add, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.BitfieldExtractS32, VariableType.S32, VariableType.S32, VariableType.S32, VariableType.S32); + Add(Instruction.BitfieldExtractU32, VariableType.U32, VariableType.U32, VariableType.S32, VariableType.S32); + Add(Instruction.BitfieldInsert, VariableType.Int, VariableType.Int, VariableType.Int, VariableType.S32, VariableType.S32); + Add(Instruction.BitfieldReverse, VariableType.Int, VariableType.Int); + Add(Instruction.BitwiseAnd, VariableType.Int, VariableType.Int, VariableType.Int); + Add(Instruction.BitwiseExclusiveOr, VariableType.Int, VariableType.Int, VariableType.Int); + Add(Instruction.BitwiseNot, VariableType.Int, VariableType.Int); + Add(Instruction.BitwiseOr, VariableType.Int, VariableType.Int, VariableType.Int); + Add(Instruction.BranchIfTrue, VariableType.None, VariableType.Bool); + Add(Instruction.BranchIfFalse, VariableType.None, VariableType.Bool); + Add(Instruction.Ceiling, VariableType.F32, VariableType.F32, VariableType.F32); + Add(Instruction.Clamp, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.ClampU32, VariableType.U32, VariableType.U32, VariableType.U32, VariableType.U32); + Add(Instruction.CompareEqual, VariableType.Bool, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.CompareGreater, VariableType.Bool, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.CompareGreaterOrEqual, VariableType.Bool, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.CompareGreaterOrEqualU32, VariableType.Bool, VariableType.U32, VariableType.U32); + Add(Instruction.CompareGreaterU32, VariableType.Bool, VariableType.U32, VariableType.U32); + Add(Instruction.CompareLess, VariableType.Bool, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.CompareLessOrEqual, VariableType.Bool, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.CompareLessOrEqualU32, VariableType.Bool, VariableType.U32, VariableType.U32); + Add(Instruction.CompareLessU32, VariableType.Bool, VariableType.U32, VariableType.U32); + Add(Instruction.CompareNotEqual, VariableType.Bool, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.ConditionalSelect, VariableType.Scalar, VariableType.Bool, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.ConvertFPToS32, VariableType.S32, VariableType.F32); + Add(Instruction.ConvertS32ToFP, VariableType.F32, VariableType.S32); + Add(Instruction.ConvertU32ToFP, VariableType.F32, VariableType.U32); + Add(Instruction.Cosine, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.Divide, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.ExponentB2, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.Floor, VariableType.F32, VariableType.F32); + Add(Instruction.FusedMultiplyAdd, VariableType.F32, VariableType.F32, VariableType.F32, VariableType.F32); + Add(Instruction.IsNan, VariableType.Bool, VariableType.F32); + Add(Instruction.LoadConstant, VariableType.F32, VariableType.S32, VariableType.S32); + Add(Instruction.LogarithmB2, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.LogicalAnd, VariableType.Bool, VariableType.Bool, VariableType.Bool); + Add(Instruction.LogicalExclusiveOr, VariableType.Bool, VariableType.Bool, VariableType.Bool); + Add(Instruction.LogicalNot, VariableType.Bool, VariableType.Bool); + Add(Instruction.LogicalOr, VariableType.Bool, VariableType.Bool, VariableType.Bool); + Add(Instruction.ShiftLeft, VariableType.Int, VariableType.Int, VariableType.Int); + Add(Instruction.ShiftRightS32, VariableType.S32, VariableType.S32, VariableType.Int); + Add(Instruction.ShiftRightU32, VariableType.U32, VariableType.U32, VariableType.Int); + Add(Instruction.Maximum, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.MaximumU32, VariableType.U32, VariableType.U32, VariableType.U32); + Add(Instruction.Minimum, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.MinimumU32, VariableType.U32, VariableType.U32, VariableType.U32); + Add(Instruction.Multiply, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.Negate, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.PackHalf2x16, VariableType.U32, VariableType.F32, VariableType.F32); + Add(Instruction.ReciprocalSquareRoot, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.Sine, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.SquareRoot, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.Subtract, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar); + Add(Instruction.TextureSample, VariableType.F32); + Add(Instruction.TextureSize, VariableType.S32, VariableType.S32, VariableType.S32); + Add(Instruction.Truncate, VariableType.F32, VariableType.F32); + Add(Instruction.UnpackHalf2x16, VariableType.F32, VariableType.U32); + } + + private static void Add(Instruction inst, VariableType destType, params VariableType[] srcTypes) + { + _infoTbl[(int)inst] = new InstInfo(destType, srcTypes); + } + + public static VariableType GetDestVarType(Instruction inst) + { + return GetFinalVarType(_infoTbl[(int)(inst & Instruction.Mask)].DestType, inst); + } + + public static VariableType GetSrcVarType(Instruction inst, int index) + { + if (inst == Instruction.TextureSample) + { + return VariableType.F32; + } + + return GetFinalVarType(_infoTbl[(int)(inst & Instruction.Mask)].SrcTypes[index], inst); + } + + private static VariableType GetFinalVarType(VariableType type, Instruction inst) + { + if (type == VariableType.Scalar) + { + return (inst & Instruction.FP) != 0 + ? VariableType.F32 + : VariableType.S32; + } + else if (type == VariableType.Int) + { + return VariableType.S32; + } + else if (type == VariableType.None) + { + throw new ArgumentException($"Invalid operand for instruction \"{inst}\"."); + } + + return type; + } + + public static bool IsUnary(Instruction inst) + { + if (inst == Instruction.Copy) + { + return true; + } + else if (inst == Instruction.TextureSample) + { + return false; + } + + return _infoTbl[(int)(inst & Instruction.Mask)].SrcTypes.Length == 1; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/OperandInfo.cs b/Ryujinx.Graphics/Shader/StructuredIr/OperandInfo.cs new file mode 100644 index 0000000000..a3a8d13839 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/OperandInfo.cs @@ -0,0 +1,34 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + static class OperandInfo + { + public static VariableType GetVarType(AstOperand operand) + { + if (operand.Type == OperandType.LocalVariable) + { + return operand.VarType; + } + else + { + return GetVarType(operand.Type); + } + } + + public static VariableType GetVarType(OperandType type) + { + switch (type) + { + case OperandType.Attribute: return VariableType.F32; + case OperandType.Constant: return VariableType.S32; + case OperandType.ConstantBuffer: return VariableType.F32; + case OperandType.GlobalMemory: return VariableType.F32; + case OperandType.Undefined: return VariableType.S32; + } + + throw new ArgumentException($"Invalid operand type \"{type}\"."); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/PhiFunctions.cs b/Ryujinx.Graphics/Shader/StructuredIr/PhiFunctions.cs new file mode 100644 index 0000000000..53391b6268 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/PhiFunctions.cs @@ -0,0 +1,74 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + static class PhiFunctions + { + public static void Remove(BasicBlock[] blocks) + { + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + BasicBlock block = blocks[blkIndex]; + + LinkedListNode node = block.Operations.First; + + while (node != null) + { + LinkedListNode nextNode = node.Next; + + if (!(node.Value is PhiNode phi)) + { + node = nextNode; + + continue; + } + + for (int index = 0; index < phi.SourcesCount; index++) + { + Operand src = phi.GetSource(index); + + BasicBlock srcBlock = phi.GetBlock(index); + + Operation copyOp = new Operation(Instruction.Copy, phi.Dest, src); + + AddBeforeBranch(srcBlock, copyOp); + } + + block.Operations.Remove(node); + + node = nextNode; + } + } + } + + private static void AddBeforeBranch(BasicBlock block, INode node) + { + INode lastOp = block.GetLastOp(); + + if (lastOp is Operation operation && IsControlFlowInst(operation.Inst)) + { + block.Operations.AddBefore(block.Operations.Last, node); + } + else + { + block.Operations.AddLast(node); + } + } + + private static bool IsControlFlowInst(Instruction inst) + { + switch (inst) + { + case Instruction.Branch: + case Instruction.BranchIfFalse: + case Instruction.BranchIfTrue: + case Instruction.Discard: + case Instruction.Return: + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgram.cs b/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgram.cs new file mode 100644 index 0000000000..f65631be7c --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgram.cs @@ -0,0 +1,254 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + static class StructuredProgram + { + public static StructuredProgramInfo MakeStructuredProgram(BasicBlock[] blocks) + { + PhiFunctions.Remove(blocks); + + StructuredProgramContext context = new StructuredProgramContext(blocks.Length); + + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + BasicBlock block = blocks[blkIndex]; + + context.EnterBlock(block); + + foreach (INode node in block.Operations) + { + Operation operation = (Operation)node; + + if (IsBranchInst(operation.Inst)) + { + context.LeaveBlock(block, operation); + } + else + { + AddOperation(context, operation); + } + } + } + + GotoElimination.Eliminate(context.GetGotos()); + + AstOptimizer.Optimize(context.Info); + + return context.Info; + } + + private static void AddOperation(StructuredProgramContext context, Operation operation) + { + Instruction inst = operation.Inst; + + IAstNode[] sources = new IAstNode[operation.SourcesCount]; + + for (int index = 0; index < sources.Length; index++) + { + sources[index] = context.GetOperandUse(operation.GetSource(index)); + } + + if (operation.Dest != null) + { + AstOperand dest = context.GetOperandDef(operation.Dest); + + if (inst == Instruction.LoadConstant) + { + Operand ldcSource = operation.GetSource(0); + + if (ldcSource.Type != OperandType.Constant) + { + throw new InvalidOperationException("Found LDC with non-constant constant buffer slot."); + } + + context.Info.CBuffers.Add(ldcSource.Value); + } + + AstAssignment assignment; + + //If all the sources are bool, it's better to use short-circuiting + //logical operations, rather than forcing a cast to int and doing + //a bitwise operation with the value, as it is likely to be used as + //a bool in the end. + if (IsBitwiseInst(inst) && AreAllSourceTypesEqual(sources, VariableType.Bool)) + { + inst = GetLogicalFromBitwiseInst(inst); + } + + bool isCondSel = inst == Instruction.ConditionalSelect; + bool isCopy = inst == Instruction.Copy; + + if (isCondSel || isCopy) + { + VariableType type = GetVarTypeFromUses(operation.Dest); + + if (isCondSel && type == VariableType.F32) + { + inst |= Instruction.FP; + } + + dest.VarType = type; + } + else + { + dest.VarType = InstructionInfo.GetDestVarType(inst); + } + + int componentMask = 1 << operation.ComponentIndex; + + IAstNode source; + + if (operation is TextureOperation texOp) + { + AstTextureOperation astTexOp = new AstTextureOperation( + inst, + texOp.Type, + texOp.Flags, + texOp.Handle, + componentMask, + sources); + + context.Info.Samplers.Add(astTexOp); + + source = astTexOp; + } + else if (!isCopy) + { + source = new AstOperation(inst, componentMask, sources); + } + else + { + source = sources[0]; + } + + assignment = new AstAssignment(dest, source); + + context.AddNode(assignment); + } + else + { + context.AddNode(new AstOperation(inst, sources)); + } + } + + private static VariableType GetVarTypeFromUses(Operand dest) + { + HashSet visited = new HashSet(); + + Queue pending = new Queue(); + + bool Enqueue(Operand operand) + { + if (visited.Add(operand)) + { + pending.Enqueue(operand); + + return true; + } + + return false; + } + + Enqueue(dest); + + while (pending.TryDequeue(out Operand operand)) + { + foreach (INode useNode in operand.UseOps) + { + if (!(useNode is Operation operation)) + { + continue; + } + + if (operation.Inst == Instruction.Copy) + { + if (operation.Dest.Type == OperandType.LocalVariable) + { + if (Enqueue(operation.Dest)) + { + break; + } + } + else + { + return OperandInfo.GetVarType(operation.Dest.Type); + } + } + else + { + for (int index = 0; index < operation.SourcesCount; index++) + { + if (operation.GetSource(index) == operand) + { + return InstructionInfo.GetSrcVarType(operation.Inst, index); + } + } + } + } + } + + return VariableType.S32; + } + + private static bool AreAllSourceTypesEqual(IAstNode[] sources, VariableType type) + { + foreach (IAstNode node in sources) + { + if (!(node is AstOperand operand)) + { + return false; + } + + if (operand.VarType != type) + { + return false; + } + } + + return true; + } + + private static bool IsBranchInst(Instruction inst) + { + switch (inst) + { + case Instruction.Branch: + case Instruction.BranchIfFalse: + case Instruction.BranchIfTrue: + return true; + } + + return false; + } + + private static bool IsBitwiseInst(Instruction inst) + { + switch (inst) + { + case Instruction.BitwiseAnd: + case Instruction.BitwiseExclusiveOr: + case Instruction.BitwiseNot: + case Instruction.BitwiseOr: + return true; + } + + return false; + } + + private static Instruction GetLogicalFromBitwiseInst(Instruction inst) + { + switch (inst) + { + case Instruction.BitwiseAnd: return Instruction.LogicalAnd; + case Instruction.BitwiseExclusiveOr: return Instruction.LogicalExclusiveOr; + case Instruction.BitwiseNot: return Instruction.LogicalNot; + case Instruction.BitwiseOr: return Instruction.LogicalOr; + } + + throw new ArgumentException($"Unexpected instruction \"{inst}\"."); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgramContext.cs b/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgramContext.cs new file mode 100644 index 0000000000..e1f0503a57 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgramContext.cs @@ -0,0 +1,292 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; +using System.Linq; + +using static Ryujinx.Graphics.Shader.StructuredIr.AstHelper; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class StructuredProgramContext + { + private HashSet _loopTails; + + private Stack<(AstBlock Block, int EndIndex)> _blockStack; + + private Dictionary _localsMap; + + private Dictionary _gotoTempAsgs; + + private List _gotos; + + private AstBlock _currBlock; + + private int _currEndIndex; + + public StructuredProgramInfo Info { get; } + + public StructuredProgramContext(int blocksCount) + { + _loopTails = new HashSet(); + + _blockStack = new Stack<(AstBlock, int)>(); + + _localsMap = new Dictionary(); + + _gotoTempAsgs = new Dictionary(); + + _gotos = new List(); + + _currBlock = new AstBlock(AstBlockType.Main); + + _currEndIndex = blocksCount; + + Info = new StructuredProgramInfo(_currBlock); + } + + public void EnterBlock(BasicBlock block) + { + while (_currEndIndex == block.Index) + { + (_currBlock, _currEndIndex) = _blockStack.Pop(); + } + + if (_gotoTempAsgs.TryGetValue(block.Index, out AstAssignment gotoTempAsg)) + { + AddGotoTempReset(block, gotoTempAsg); + } + + LookForDoWhileStatements(block); + } + + public void LeaveBlock(BasicBlock block, Operation branchOp) + { + LookForIfStatements(block, branchOp); + } + + private void LookForDoWhileStatements(BasicBlock block) + { + //Check if we have any predecessor whose index is greater than the + //current block, this indicates a loop. + bool done = false; + + foreach (BasicBlock predecessor in block.Predecessors.OrderByDescending(x => x.Index)) + { + if (predecessor.Index < block.Index) + { + break; + } + + if (predecessor.Index < _currEndIndex && !done) + { + Operation branchOp = (Operation)predecessor.GetLastOp(); + + NewBlock(AstBlockType.DoWhile, branchOp, predecessor.Index + 1); + + _loopTails.Add(predecessor); + + done = true; + } + else + { + AddGotoTempReset(block, GetGotoTempAsg(block.Index)); + + break; + } + } + } + + private void LookForIfStatements(BasicBlock block, Operation branchOp) + { + if (block.Branch == null) + { + return; + } + + bool isLoop = block.Branch.Index <= block.Index; + + if (block.Branch.Index <= _currEndIndex && !isLoop) + { + NewBlock(AstBlockType.If, branchOp, block.Branch.Index); + } + else if (!_loopTails.Contains(block)) + { + AstAssignment gotoTempAsg = GetGotoTempAsg(block.Branch.Index); + + IAstNode cond = GetBranchCond(AstBlockType.DoWhile, branchOp); + + AddNode(Assign(gotoTempAsg.Destination, cond)); + + AstOperation branch = new AstOperation(branchOp.Inst); + + AddNode(branch); + + GotoStatement gotoStmt = new GotoStatement(branch, gotoTempAsg, isLoop); + + _gotos.Add(gotoStmt); + } + } + + private AstAssignment GetGotoTempAsg(int index) + { + if (_gotoTempAsgs.TryGetValue(index, out AstAssignment gotoTempAsg)) + { + return gotoTempAsg; + } + + AstOperand gotoTemp = NewTemp(VariableType.Bool); + + gotoTempAsg = Assign(gotoTemp, Const(IrConsts.False)); + + _gotoTempAsgs.Add(index, gotoTempAsg); + + return gotoTempAsg; + } + + private void AddGotoTempReset(BasicBlock block, AstAssignment gotoTempAsg) + { + AddNode(gotoTempAsg); + + //For block 0, we don't need to add the extra "reset" at the beggining, + //because it is already the first node to be executed on the shader, + //so it is reset to false by the "local" assignment anyway. + if (block.Index != 0) + { + Info.MainBlock.AddFirst(Assign(gotoTempAsg.Destination, Const(IrConsts.False))); + } + } + + private void NewBlock(AstBlockType type, Operation branchOp, int endIndex) + { + NewBlock(type, GetBranchCond(type, branchOp), endIndex); + } + + private void NewBlock(AstBlockType type, IAstNode cond, int endIndex) + { + AstBlock childBlock = new AstBlock(type, cond); + + AddNode(childBlock); + + _blockStack.Push((_currBlock, _currEndIndex)); + + _currBlock = childBlock; + _currEndIndex = endIndex; + } + + private IAstNode GetBranchCond(AstBlockType type, Operation branchOp) + { + IAstNode cond; + + if (branchOp.Inst == Instruction.Branch) + { + cond = Const(type == AstBlockType.If ? IrConsts.False : IrConsts.True); + } + else + { + cond = GetOperandUse(branchOp.GetSource(0)); + + Instruction invInst = type == AstBlockType.If + ? Instruction.BranchIfTrue + : Instruction.BranchIfFalse; + + if (branchOp.Inst == invInst) + { + cond = new AstOperation(Instruction.LogicalNot, cond); + } + } + + return cond; + } + + public void AddNode(IAstNode node) + { + _currBlock.Add(node); + } + + public GotoStatement[] GetGotos() + { + return _gotos.ToArray(); + } + + private AstOperand NewTemp(VariableType type) + { + AstOperand newTemp = Local(type); + + Info.Locals.Add(newTemp); + + return newTemp; + } + + public AstOperand GetOperandDef(Operand operand) + { + if (TryGetUserAttributeIndex(operand, out int attrIndex)) + { + Info.OAttributes.Add(attrIndex); + } + + return GetOperand(operand); + } + + public AstOperand GetOperandUse(Operand operand) + { + if (TryGetUserAttributeIndex(operand, out int attrIndex)) + { + Info.IAttributes.Add(attrIndex); + } + else if (operand.Type == OperandType.ConstantBuffer) + { + Info.CBuffers.Add(operand.GetCbufSlot()); + } + + return GetOperand(operand); + } + + private AstOperand GetOperand(Operand operand) + { + if (operand == null) + { + return null; + } + + if (operand.Type != OperandType.LocalVariable) + { + return new AstOperand(operand); + } + + if (!_localsMap.TryGetValue(operand, out AstOperand astOperand)) + { + astOperand = new AstOperand(operand); + + _localsMap.Add(operand, astOperand); + + Info.Locals.Add(astOperand); + } + + return astOperand; + } + + private static bool TryGetUserAttributeIndex(Operand operand, out int attrIndex) + { + if (operand.Type == OperandType.Attribute) + { + if (operand.Value >= AttributeConsts.UserAttributeBase && + operand.Value < AttributeConsts.UserAttributeEnd) + { + attrIndex = (operand.Value - AttributeConsts.UserAttributeBase) >> 4; + + return true; + } + else if (operand.Value >= AttributeConsts.FragmentOutputColorBase && + operand.Value < AttributeConsts.FragmentOutputColorEnd) + { + attrIndex = (operand.Value - AttributeConsts.FragmentOutputColorBase) >> 4; + + return true; + } + } + + attrIndex = 0; + + return false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgramInfo.cs b/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgramInfo.cs new file mode 100644 index 0000000000..d368ef0058 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/StructuredProgramInfo.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + class StructuredProgramInfo + { + public AstBlock MainBlock { get; } + + public HashSet Locals { get; } + + public HashSet CBuffers { get; } + + public HashSet IAttributes { get; } + public HashSet OAttributes { get; } + + public HashSet Samplers { get; } + + public StructuredProgramInfo(AstBlock mainBlock) + { + MainBlock = mainBlock; + + Locals = new HashSet(); + + CBuffers = new HashSet(); + + IAttributes = new HashSet(); + OAttributes = new HashSet(); + + Samplers = new HashSet(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/StructuredIr/VariableType.cs b/Ryujinx.Graphics/Shader/StructuredIr/VariableType.cs new file mode 100644 index 0000000000..4c7f384978 --- /dev/null +++ b/Ryujinx.Graphics/Shader/StructuredIr/VariableType.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Graphics.Shader.StructuredIr +{ + enum VariableType + { + None, + Bool, + Scalar, + Int, + F32, + S32, + U32 + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/TextureDescriptor.cs b/Ryujinx.Graphics/Shader/TextureDescriptor.cs new file mode 100644 index 0000000000..96f0f5b16d --- /dev/null +++ b/Ryujinx.Graphics/Shader/TextureDescriptor.cs @@ -0,0 +1,36 @@ +namespace Ryujinx.Graphics.Shader +{ + public struct TextureDescriptor + { + public string Name { get; } + + public int HandleIndex { get; } + + public bool IsBindless { get; } + + public int CbufSlot { get; } + public int CbufOffset { get; } + + public TextureDescriptor(string name, int hIndex) + { + Name = name; + HandleIndex = hIndex; + + IsBindless = false; + + CbufSlot = 0; + CbufOffset = 0; + } + + public TextureDescriptor(string name, int cbufSlot, int cbufOffset) + { + Name = name; + HandleIndex = 0; + + IsBindless = true; + + CbufSlot = cbufSlot; + CbufOffset = cbufOffset; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/AttributeConsts.cs b/Ryujinx.Graphics/Shader/Translation/AttributeConsts.cs new file mode 100644 index 0000000000..ae3e361c72 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/AttributeConsts.cs @@ -0,0 +1,30 @@ +namespace Ryujinx.Graphics.Shader.IntermediateRepresentation +{ + static class AttributeConsts + { + public const int Layer = 0x064; + public const int PointSize = 0x06c; + public const int PositionX = 0x070; + public const int PositionY = 0x074; + public const int PositionZ = 0x078; + public const int PositionW = 0x07c; + public const int PointCoordX = 0x2e0; + public const int PointCoordY = 0x2e4; + public const int TessCoordX = 0x2f0; + public const int TessCoordY = 0x2f4; + public const int InstanceId = 0x2f8; + public const int VertexId = 0x2fc; + public const int FrontFacing = 0x3fc; + + public const int UserAttributesCount = 32; + public const int UserAttributeBase = 0x80; + public const int UserAttributeEnd = UserAttributeBase + UserAttributesCount * 16; + + + //Note: Those attributes are used internally by the translator + //only, they don't exist on Maxwell. + public const int FragmentOutputDepth = 0x1000000; + public const int FragmentOutputColorBase = 0x1000010; + public const int FragmentOutputColorEnd = FragmentOutputColorBase + 8 * 16; + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/ControlFlowGraph.cs b/Ryujinx.Graphics/Shader/Translation/ControlFlowGraph.cs new file mode 100644 index 0000000000..e2ca74a4de --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/ControlFlowGraph.cs @@ -0,0 +1,108 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.Translation +{ + static class ControlFlowGraph + { + public static BasicBlock[] MakeCfg(Operation[] operations) + { + Dictionary labels = new Dictionary(); + + List blocks = new List(); + + BasicBlock currentBlock = null; + + void NextBlock(BasicBlock nextBlock) + { + if (currentBlock != null && !EndsWithUnconditionalInst(currentBlock.GetLastOp())) + { + currentBlock.Next = nextBlock; + } + + currentBlock = nextBlock; + } + + void NewNextBlock() + { + BasicBlock block = new BasicBlock(blocks.Count); + + blocks.Add(block); + + NextBlock(block); + } + + bool needsNewBlock = true; + + for (int index = 0; index < operations.Length; index++) + { + Operation operation = operations[index]; + + if (operation.Inst == Instruction.MarkLabel) + { + Operand label = operation.Dest; + + if (labels.TryGetValue(label, out BasicBlock nextBlock)) + { + nextBlock.Index = blocks.Count; + + blocks.Add(nextBlock); + + NextBlock(nextBlock); + } + else + { + NewNextBlock(); + + labels.Add(label, currentBlock); + } + } + else + { + if (needsNewBlock) + { + NewNextBlock(); + } + + currentBlock.Operations.AddLast(operation); + } + + needsNewBlock = operation.Inst == Instruction.Branch || + operation.Inst == Instruction.BranchIfTrue || + operation.Inst == Instruction.BranchIfFalse; + + if (needsNewBlock) + { + Operand label = operation.Dest; + + if (!labels.TryGetValue(label, out BasicBlock branchBlock)) + { + branchBlock = new BasicBlock(); + + labels.Add(label, branchBlock); + } + + currentBlock.Branch = branchBlock; + } + } + + return blocks.ToArray(); + } + + private static bool EndsWithUnconditionalInst(INode node) + { + if (node is Operation operation) + { + switch (operation.Inst) + { + case Instruction.Branch: + case Instruction.Discard: + case Instruction.Return: + return true; + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/Dominance.cs b/Ryujinx.Graphics/Shader/Translation/Dominance.cs new file mode 100644 index 0000000000..b4b80e3ef2 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/Dominance.cs @@ -0,0 +1,127 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Shader.Translation +{ + static class Dominance + { + //Those methods are an implementation of the algorithms on "A Simple, Fast Dominance Algorithm". + //https://www.cs.rice.edu/~keith/EMBED/dom.pdf + public static void FindDominators(BasicBlock entry, int blocksCount) + { + HashSet visited = new HashSet(); + + Stack blockStack = new Stack(); + + List postOrderBlocks = new List(blocksCount); + + int[] postOrderMap = new int[blocksCount]; + + visited.Add(entry); + + blockStack.Push(entry); + + while (blockStack.TryPop(out BasicBlock block)) + { + if (block.Next != null && visited.Add(block.Next)) + { + blockStack.Push(block); + blockStack.Push(block.Next); + } + else if (block.Branch != null && visited.Add(block.Branch)) + { + blockStack.Push(block); + blockStack.Push(block.Branch); + } + else + { + postOrderMap[block.Index] = postOrderBlocks.Count; + + postOrderBlocks.Add(block); + } + } + + BasicBlock Intersect(BasicBlock block1, BasicBlock block2) + { + while (block1 != block2) + { + while (postOrderMap[block1.Index] < postOrderMap[block2.Index]) + { + block1 = block1.ImmediateDominator; + } + + while (postOrderMap[block2.Index] < postOrderMap[block1.Index]) + { + block2 = block2.ImmediateDominator; + } + } + + return block1; + } + + entry.ImmediateDominator = entry; + + bool modified; + + do + { + modified = false; + + for (int blkIndex = postOrderBlocks.Count - 2; blkIndex >= 0; blkIndex--) + { + BasicBlock block = postOrderBlocks[blkIndex]; + + BasicBlock newIDom = null; + + foreach (BasicBlock predecessor in block.Predecessors) + { + if (predecessor.ImmediateDominator != null) + { + if (newIDom != null) + { + newIDom = Intersect(predecessor, newIDom); + } + else + { + newIDom = predecessor; + } + } + } + + if (block.ImmediateDominator != newIDom) + { + block.ImmediateDominator = newIDom; + + modified = true; + } + } + } + while (modified); + } + + public static void FindDominanceFrontiers(BasicBlock[] blocks) + { + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + BasicBlock block = blocks[blkIndex]; + + if (block.Predecessors.Count < 2) + { + continue; + } + + for (int pBlkIndex = 0; pBlkIndex < block.Predecessors.Count; pBlkIndex++) + { + BasicBlock current = block.Predecessors[pBlkIndex]; + + while (current != block.ImmediateDominator) + { + current.DominanceFrontiers.Add(block); + + current = current.ImmediateDominator; + } + } + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics/Shader/Translation/EmitterContext.cs new file mode 100644 index 0000000000..6c2bf6e478 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/EmitterContext.cs @@ -0,0 +1,105 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Translation +{ + class EmitterContext + { + public Block CurrBlock { get; set; } + public OpCode CurrOp { get; set; } + + private GalShaderType _shaderType; + + private ShaderHeader _header; + + private List _operations; + + private Dictionary _labels; + + public EmitterContext(GalShaderType shaderType, ShaderHeader header) + { + _shaderType = shaderType; + _header = header; + + _operations = new List(); + + _labels = new Dictionary(); + } + + public Operand Add(Instruction inst, Operand dest = null, params Operand[] sources) + { + Operation operation = new Operation(inst, dest, sources); + + Add(operation); + + return dest; + } + + public void Add(Operation operation) + { + _operations.Add(operation); + } + + public void MarkLabel(Operand label) + { + Add(Instruction.MarkLabel, label); + } + + public Operand GetLabel(ulong address) + { + if (!_labels.TryGetValue(address, out Operand label)) + { + label = Label(); + + _labels.Add(address, label); + } + + return label; + } + + public void PrepareForReturn() + { + if (_shaderType == GalShaderType.Fragment) + { + if (_header.OmapDepth) + { + Operand dest = Attribute(AttributeConsts.FragmentOutputDepth); + + Operand src = Register(_header.DepthRegister, RegisterType.Gpr); + + this.Copy(dest, src); + } + + int regIndex = 0; + + for (int attachment = 0; attachment < 8; attachment++) + { + OutputMapTarget target = _header.OmapTargets[attachment]; + + for (int component = 0; component < 4; component++) + { + if (target.ComponentEnabled(component)) + { + Operand dest = Attribute(AttributeConsts.FragmentOutputColorBase + regIndex * 4); + + Operand src = Register(regIndex, RegisterType.Gpr); + + this.Copy(dest, src); + + regIndex++; + } + } + } + } + } + + public Operation[] GetOperations() + { + return _operations.ToArray(); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/EmitterContextInsts.cs b/Ryujinx.Graphics/Shader/Translation/EmitterContextInsts.cs new file mode 100644 index 0000000000..604aa67d34 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/EmitterContextInsts.cs @@ -0,0 +1,420 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Translation +{ + static class EmitterContextInsts + { + public static Operand BitfieldExtractS32(this EmitterContext context, Operand a, Operand b, Operand c) + { + return context.Add(Instruction.BitfieldExtractS32, Local(), a, b, c); + } + + public static Operand BitfieldExtractU32(this EmitterContext context, Operand a, Operand b, Operand c) + { + return context.Add(Instruction.BitfieldExtractU32, Local(), a, b, c); + } + + public static Operand BitfieldInsert(this EmitterContext context, Operand a, Operand b, Operand c, Operand d) + { + return context.Add(Instruction.BitfieldInsert, Local(), a, b, c, d); + } + + public static Operand BitfieldReverse(this EmitterContext context, Operand a) + { + return context.Add(Instruction.BitfieldReverse, Local(), a); + } + + public static Operand BitwiseAnd(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.BitwiseAnd, Local(), a, b); + } + + public static Operand BitwiseExclusiveOr(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.BitwiseExclusiveOr, Local(), a, b); + } + + public static Operand BitwiseNot(this EmitterContext context, Operand a, bool invert) + { + if (invert) + { + a = context.BitwiseNot(a); + } + + return a; + } + + public static Operand BitwiseNot(this EmitterContext context, Operand a) + { + return context.Add(Instruction.BitwiseNot, Local(), a); + } + + public static Operand BitwiseOr(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.BitwiseOr, Local(), a, b); + } + + public static Operand Branch(this EmitterContext context, Operand d) + { + return context.Add(Instruction.Branch, d); + } + + public static Operand BranchIfFalse(this EmitterContext context, Operand d, Operand a) + { + return context.Add(Instruction.BranchIfFalse, d, a); + } + + public static Operand BranchIfTrue(this EmitterContext context, Operand d, Operand a) + { + return context.Add(Instruction.BranchIfTrue, d, a); + } + + public static Operand ConditionalSelect(this EmitterContext context, Operand a, Operand b, Operand c) + { + return context.Add(Instruction.ConditionalSelect, Local(), a, b, c); + } + + public static Operand Copy(this EmitterContext context, Operand a) + { + return context.Add(Instruction.Copy, Local(), a); + } + + public static void Copy(this EmitterContext context, Operand d, Operand a) + { + if (d.Type == OperandType.Constant) + { + return; + } + + context.Add(Instruction.Copy, d, a); + } + + public static Operand Discard(this EmitterContext context) + { + return context.Add(Instruction.Discard); + } + + public static Operand EmitVertex(this EmitterContext context) + { + return context.Add(Instruction.EmitVertex); + } + + public static Operand EndPrimitive(this EmitterContext context) + { + return context.Add(Instruction.EndPrimitive); + } + + public static Operand FPAbsNeg(this EmitterContext context, Operand a, bool abs, bool neg) + { + return context.FPNegate(context.FPAbsolute(a, abs), neg); + } + + public static Operand FPAbsolute(this EmitterContext context, Operand a, bool abs) + { + if (abs) + { + a = context.FPAbsolute(a); + } + + return a; + } + + public static Operand FPAbsolute(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.Absolute, Local(), a); + } + + public static Operand FPAdd(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.FP | Instruction.Add, Local(), a, b); + } + + public static Operand FPCeiling(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.Ceiling, Local(), a); + } + + public static Operand FPCompareEqual(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.FP | Instruction.CompareEqual, Local(), a, b); + } + + public static Operand FPCompareLess(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.FP | Instruction.CompareLess, Local(), a, b); + } + + public static Operand FPConvertToS32(this EmitterContext context, Operand a) + { + return context.Add(Instruction.ConvertFPToS32, Local(), a); + } + + public static Operand FPCosine(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.Cosine, Local(), a); + } + + public static Operand FPDivide(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.FP | Instruction.Divide, Local(), a, b); + } + + public static Operand FPExponentB2(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.ExponentB2, Local(), a); + } + + public static Operand FPFloor(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.Floor, Local(), a); + } + + public static Operand FPLogarithmB2(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.LogarithmB2, Local(), a); + } + + public static Operand FPMaximum(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.FP | Instruction.Maximum, Local(), a, b); + } + + public static Operand FPMinimum(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.FP | Instruction.Minimum, Local(), a, b); + } + + public static Operand FPMultiply(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.FP | Instruction.Multiply, Local(), a, b); + } + + public static Operand FPFusedMultiplyAdd(this EmitterContext context, Operand a, Operand b, Operand c) + { + return context.Add(Instruction.FusedMultiplyAdd, Local(), a, b, c); + } + + public static Operand FPNegate(this EmitterContext context, Operand a, bool neg) + { + if (neg) + { + a = context.FPNegate(a); + } + + return a; + } + + public static Operand FPNegate(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.Negate, Local(), a); + } + + public static Operand FPReciprocal(this EmitterContext context, Operand a) + { + return context.FPDivide(ConstF(1), a); + } + + public static Operand FPReciprocalSquareRoot(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.ReciprocalSquareRoot, Local(), a); + } + + public static Operand FPSaturate(this EmitterContext context, Operand a, bool sat) + { + if (sat) + { + a = context.FPSaturate(a); + } + + return a; + } + + public static Operand FPSaturate(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.Clamp, Local(), a, ConstF(0), ConstF(1)); + } + + public static Operand FPSine(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.Sine, Local(), a); + } + + public static Operand FPSquareRoot(this EmitterContext context, Operand a) + { + return context.Add(Instruction.FP | Instruction.SquareRoot, Local(), a); + } + + public static Operand FPTruncate(this EmitterContext context, Operand a) + { + return context.Add(Instruction.Truncate, Local(), a); + } + + public static Operand IAbsNeg(this EmitterContext context, Operand a, bool abs, bool neg) + { + return context.INegate(context.IAbsolute(a, abs), neg); + } + + public static Operand IAbsolute(this EmitterContext context, Operand a, bool abs) + { + if (abs) + { + a = context.IAbsolute(a); + } + + return a; + } + + public static Operand IAbsolute(this EmitterContext context, Operand a) + { + return context.Add(Instruction.Absolute, Local(), a); + } + + public static Operand IAdd(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.Add, Local(), a, b); + } + + public static Operand IClampS32(this EmitterContext context, Operand a, Operand b, Operand c) + { + return context.Add(Instruction.Clamp, Local(), a, b, c); + } + + public static Operand IClampU32(this EmitterContext context, Operand a, Operand b, Operand c) + { + return context.Add(Instruction.ClampU32, Local(), a, b, c); + } + + public static Operand ICompareEqual(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.CompareEqual, Local(), a, b); + } + + public static Operand ICompareLess(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.CompareLess, Local(), a, b); + } + + public static Operand ICompareLessUnsigned(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.CompareLessU32, Local(), a, b); + } + + public static Operand ICompareNotEqual(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.CompareNotEqual, Local(), a, b); + } + + public static Operand IConvertS32ToFP(this EmitterContext context, Operand a) + { + return context.Add(Instruction.ConvertS32ToFP, Local(), a); + } + + public static Operand IConvertU32ToFP(this EmitterContext context, Operand a) + { + return context.Add(Instruction.ConvertU32ToFP, Local(), a); + } + + public static Operand IMaximumS32(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.Maximum, Local(), a, b); + } + + public static Operand IMaximumU32(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.MaximumU32, Local(), a, b); + } + + public static Operand IMinimumS32(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.Minimum, Local(), a, b); + } + + public static Operand IMinimumU32(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.MinimumU32, Local(), a, b); + } + + public static Operand IMultiply(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.Multiply, Local(), a, b); + } + + public static Operand INegate(this EmitterContext context, Operand a, bool neg) + { + if (neg) + { + a = context.INegate(a); + } + + return a; + } + + public static Operand INegate(this EmitterContext context, Operand a) + { + return context.Add(Instruction.Negate, Local(), a); + } + + public static Operand ISubtract(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.Subtract, Local(), a, b); + } + + public static Operand IsNan(this EmitterContext context, Operand a) + { + return context.Add(Instruction.IsNan, Local(), a); + } + + public static Operand LoadConstant(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.LoadConstant, Local(), a, b); + } + + public static Operand PackHalf2x16(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.PackHalf2x16, Local(), a, b); + } + + public static Operand Return(this EmitterContext context) + { + context.PrepareForReturn(); + + return context.Add(Instruction.Return); + } + + public static Operand ShiftLeft(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.ShiftLeft, Local(), a, b); + } + + public static Operand ShiftRightS32(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.ShiftRightS32, Local(), a, b); + } + + public static Operand ShiftRightU32(this EmitterContext context, Operand a, Operand b) + { + return context.Add(Instruction.ShiftRightU32, Local(), a, b); + } + + public static Operand UnpackHalf2x16High(this EmitterContext context, Operand a) + { + return UnpackHalf2x16(context, a, 1); + } + + public static Operand UnpackHalf2x16Low(this EmitterContext context, Operand a) + { + return UnpackHalf2x16(context, a, 0); + } + + private static Operand UnpackHalf2x16(this EmitterContext context, Operand a, int index) + { + Operand dest = Local(); + + context.Add(new Operation(Instruction.UnpackHalf2x16, index, dest, a)); + + return dest; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/Optimizations/BranchElimination.cs b/Ryujinx.Graphics/Shader/Translation/Optimizations/BranchElimination.cs new file mode 100644 index 0000000000..2b0f19052b --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/Optimizations/BranchElimination.cs @@ -0,0 +1,64 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System; + +namespace Ryujinx.Graphics.Shader.Translation.Optimizations +{ + static class BranchElimination + { + public static bool Eliminate(BasicBlock block) + { + if (block.HasBranch && IsRedundantBranch((Operation)block.GetLastOp(), Next(block))) + { + block.Branch = null; + + return true; + } + + return false; + } + + private static bool IsRedundantBranch(Operation current, BasicBlock nextBlock) + { + //Here we check that: + //- The current block ends with a branch. + //- The next block only contains a branch. + //- The branch on the next block is unconditional. + //- Both branches are jumping to the same location. + //In this case, the branch on the current block can be removed, + //as the next block is going to jump to the same place anyway. + if (nextBlock == null) + { + return false; + } + + if (!(nextBlock.Operations.First?.Value is Operation next)) + { + return false; + } + + if (next.Inst != Instruction.Branch) + { + return false; + } + + return current.Dest == next.Dest; + } + + private static BasicBlock Next(BasicBlock block) + { + block = block.Next; + + while (block != null && block.Operations.Count == 0) + { + if (block.HasBranch) + { + throw new InvalidOperationException("Found a bogus empty block that \"ends with a branch\"."); + } + + block = block.Next; + } + + return block; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/Optimizations/ConstantFolding.cs b/Ryujinx.Graphics/Shader/Translation/Optimizations/ConstantFolding.cs new file mode 100644 index 0000000000..a2e05ef120 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/Optimizations/ConstantFolding.cs @@ -0,0 +1,323 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Translation.Optimizations +{ + static class ConstantFolding + { + public static void Fold(Operation operation) + { + if (!AreAllSourcesConstant(operation)) + { + return; + } + + switch (operation.Inst) + { + case Instruction.Add: + EvaluateBinary(operation, (x, y) => x + y); + break; + + case Instruction.BitwiseAnd: + EvaluateBinary(operation, (x, y) => x & y); + break; + + case Instruction.BitwiseExclusiveOr: + EvaluateBinary(operation, (x, y) => x ^ y); + break; + + case Instruction.BitwiseNot: + EvaluateUnary(operation, (x) => ~x); + break; + + case Instruction.BitwiseOr: + EvaluateBinary(operation, (x, y) => x | y); + break; + + case Instruction.BitfieldExtractS32: + BitfieldExtractS32(operation); + break; + + case Instruction.BitfieldExtractU32: + BitfieldExtractU32(operation); + break; + + case Instruction.Clamp: + EvaluateTernary(operation, (x, y, z) => Math.Clamp(x, y, z)); + break; + + case Instruction.ClampU32: + EvaluateTernary(operation, (x, y, z) => (int)Math.Clamp((uint)x, (uint)y, (uint)z)); + break; + + case Instruction.CompareEqual: + EvaluateBinary(operation, (x, y) => x == y); + break; + + case Instruction.CompareGreater: + EvaluateBinary(operation, (x, y) => x > y); + break; + + case Instruction.CompareGreaterOrEqual: + EvaluateBinary(operation, (x, y) => x >= y); + break; + + case Instruction.CompareGreaterOrEqualU32: + EvaluateBinary(operation, (x, y) => (uint)x >= (uint)y); + break; + + case Instruction.CompareGreaterU32: + EvaluateBinary(operation, (x, y) => (uint)x > (uint)y); + break; + + case Instruction.CompareLess: + EvaluateBinary(operation, (x, y) => x < y); + break; + + case Instruction.CompareLessOrEqual: + EvaluateBinary(operation, (x, y) => x <= y); + break; + + case Instruction.CompareLessOrEqualU32: + EvaluateBinary(operation, (x, y) => (uint)x <= (uint)y); + break; + + case Instruction.CompareLessU32: + EvaluateBinary(operation, (x, y) => (uint)x < (uint)y); + break; + + case Instruction.CompareNotEqual: + EvaluateBinary(operation, (x, y) => x != y); + break; + + case Instruction.Divide: + EvaluateBinary(operation, (x, y) => y != 0 ? x / y : 0); + break; + + case Instruction.FP | Instruction.Add: + EvaluateFPBinary(operation, (x, y) => x + y); + break; + + case Instruction.FP | Instruction.Clamp: + EvaluateFPTernary(operation, (x, y, z) => Math.Clamp(x, y, z)); + break; + + case Instruction.FP | Instruction.CompareEqual: + EvaluateFPBinary(operation, (x, y) => x == y); + break; + + case Instruction.FP | Instruction.CompareGreater: + EvaluateFPBinary(operation, (x, y) => x > y); + break; + + case Instruction.FP | Instruction.CompareGreaterOrEqual: + EvaluateFPBinary(operation, (x, y) => x >= y); + break; + + case Instruction.FP | Instruction.CompareLess: + EvaluateFPBinary(operation, (x, y) => x < y); + break; + + case Instruction.FP | Instruction.CompareLessOrEqual: + EvaluateFPBinary(operation, (x, y) => x <= y); + break; + + case Instruction.FP | Instruction.CompareNotEqual: + EvaluateFPBinary(operation, (x, y) => x != y); + break; + + case Instruction.FP | Instruction.Divide: + EvaluateFPBinary(operation, (x, y) => x / y); + break; + + case Instruction.FP | Instruction.Multiply: + EvaluateFPBinary(operation, (x, y) => x * y); + break; + + case Instruction.FP | Instruction.Negate: + EvaluateFPUnary(operation, (x) => -x); + break; + + case Instruction.FP | Instruction.Subtract: + EvaluateFPBinary(operation, (x, y) => x - y); + break; + + case Instruction.IsNan: + EvaluateFPUnary(operation, (x) => float.IsNaN(x)); + break; + + case Instruction.Maximum: + EvaluateBinary(operation, (x, y) => Math.Max(x, y)); + break; + + case Instruction.MaximumU32: + EvaluateBinary(operation, (x, y) => (int)Math.Max((uint)x, (uint)y)); + break; + + case Instruction.Minimum: + EvaluateBinary(operation, (x, y) => Math.Min(x, y)); + break; + + case Instruction.MinimumU32: + EvaluateBinary(operation, (x, y) => (int)Math.Min((uint)x, (uint)y)); + break; + + case Instruction.Multiply: + EvaluateBinary(operation, (x, y) => x * y); + break; + + case Instruction.Negate: + EvaluateUnary(operation, (x) => -x); + break; + + case Instruction.ShiftLeft: + EvaluateBinary(operation, (x, y) => x << y); + break; + + case Instruction.ShiftRightS32: + EvaluateBinary(operation, (x, y) => x >> y); + break; + + case Instruction.ShiftRightU32: + EvaluateBinary(operation, (x, y) => (int)((uint)x >> y)); + break; + + case Instruction.Subtract: + EvaluateBinary(operation, (x, y) => x - y); + break; + + case Instruction.UnpackHalf2x16: + UnpackHalf2x16(operation); + break; + } + } + + private static bool AreAllSourcesConstant(Operation operation) + { + for (int index = 0; index < operation.SourcesCount; index++) + { + if (operation.GetSource(index).Type != OperandType.Constant) + { + return false; + } + } + + return true; + } + + private static void BitfieldExtractS32(Operation operation) + { + int value = GetBitfieldExtractValue(operation); + + int shift = 32 - operation.GetSource(2).Value; + + value = (value << shift) >> shift; + + operation.TurnIntoCopy(Const(value)); + } + + private static void BitfieldExtractU32(Operation operation) + { + operation.TurnIntoCopy(Const(GetBitfieldExtractValue(operation))); + } + + private static int GetBitfieldExtractValue(Operation operation) + { + int value = operation.GetSource(0).Value; + int lsb = operation.GetSource(1).Value; + int length = operation.GetSource(2).Value; + + return value.Extract(lsb, length); + } + + private static void UnpackHalf2x16(Operation operation) + { + int value = operation.GetSource(0).Value; + + value = (value >> operation.ComponentIndex * 16) & 0xffff; + + operation.TurnIntoCopy(ConstF(HalfConversion.HalfToSingle(value))); + } + + private static void FPNegate(Operation operation) + { + float value = operation.GetSource(0).AsFloat(); + + operation.TurnIntoCopy(ConstF(-value)); + } + + private static void EvaluateUnary(Operation operation, Func op) + { + int x = operation.GetSource(0).Value; + + operation.TurnIntoCopy(Const(op(x))); + } + + private static void EvaluateFPUnary(Operation operation, Func op) + { + float x = operation.GetSource(0).AsFloat(); + + operation.TurnIntoCopy(ConstF(op(x))); + } + + private static void EvaluateFPUnary(Operation operation, Func op) + { + float x = operation.GetSource(0).AsFloat(); + + operation.TurnIntoCopy(Const(op(x) ? IrConsts.True : IrConsts.False)); + } + + private static void EvaluateBinary(Operation operation, Func op) + { + int x = operation.GetSource(0).Value; + int y = operation.GetSource(1).Value; + + operation.TurnIntoCopy(Const(op(x, y))); + } + + private static void EvaluateBinary(Operation operation, Func op) + { + int x = operation.GetSource(0).Value; + int y = operation.GetSource(1).Value; + + operation.TurnIntoCopy(Const(op(x, y) ? IrConsts.True : IrConsts.False)); + } + + private static void EvaluateFPBinary(Operation operation, Func op) + { + float x = operation.GetSource(0).AsFloat(); + float y = operation.GetSource(1).AsFloat(); + + operation.TurnIntoCopy(ConstF(op(x, y))); + } + + private static void EvaluateFPBinary(Operation operation, Func op) + { + float x = operation.GetSource(0).AsFloat(); + float y = operation.GetSource(1).AsFloat(); + + operation.TurnIntoCopy(Const(op(x, y) ? IrConsts.True : IrConsts.False)); + } + + private static void EvaluateTernary(Operation operation, Func op) + { + int x = operation.GetSource(0).Value; + int y = operation.GetSource(1).Value; + int z = operation.GetSource(2).Value; + + operation.TurnIntoCopy(Const(op(x, y, z))); + } + + private static void EvaluateFPTernary(Operation operation, Func op) + { + float x = operation.GetSource(0).AsFloat(); + float y = operation.GetSource(1).AsFloat(); + float z = operation.GetSource(2).AsFloat(); + + operation.TurnIntoCopy(ConstF(op(x, y, z))); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/Optimizations/HalfConversion.cs b/Ryujinx.Graphics/Shader/Translation/Optimizations/HalfConversion.cs new file mode 100644 index 0000000000..9ef35abc92 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/Optimizations/HalfConversion.cs @@ -0,0 +1,47 @@ +using System; + +namespace Ryujinx.Graphics.Shader.Translation.Optimizations +{ + static class HalfConversion + { + public static float HalfToSingle(int value) + { + int mantissa = (value >> 0) & 0x3ff; + int exponent = (value >> 10) & 0x1f; + int sign = (value >> 15) & 0x1; + + if (exponent == 0x1f) + { + //NaN or Infinity. + mantissa <<= 13; + exponent = 0xff; + } + else if (exponent != 0 || mantissa != 0 ) + { + if (exponent == 0) + { + //Denormal. + int e = -1; + int m = mantissa; + + do + { + e++; + m <<= 1; + } + while ((m & 0x400) == 0); + + mantissa = m & 0x3ff; + exponent = e; + } + + mantissa <<= 13; + exponent = 127 - 15 + exponent; + } + + int output = (sign << 31) | (exponent << 23) | mantissa; + + return BitConverter.Int32BitsToSingle(output); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/Optimizations/Optimizer.cs b/Ryujinx.Graphics/Shader/Translation/Optimizations/Optimizer.cs new file mode 100644 index 0000000000..88118e3a75 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/Optimizations/Optimizer.cs @@ -0,0 +1,172 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.Graphics.Shader.Translation.Optimizations +{ + static class Optimizer + { + public static void Optimize(BasicBlock[] blocks) + { + bool modified; + + do + { + modified = false; + + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + BasicBlock block = blocks[blkIndex]; + + LinkedListNode node = block.Operations.First; + + while (node != null) + { + LinkedListNode nextNode = node.Next; + + bool isUnused = IsUnused(node.Value); + + if (!(node.Value is Operation operation) || isUnused) + { + if (isUnused) + { + RemoveNode(block, node); + + modified = true; + } + + node = nextNode; + + continue; + } + + ConstantFolding.Fold(operation); + + Simplification.Simplify(operation); + + if (DestIsLocalVar(operation)) + { + if (operation.Inst == Instruction.Copy) + { + PropagateCopy(operation); + + RemoveNode(block, node); + + modified = true; + } + else if (operation.Inst == Instruction.PackHalf2x16 && PropagatePack(operation)) + { + if (operation.Dest.UseOps.Count == 0) + { + RemoveNode(block, node); + } + + modified = true; + } + } + + node = nextNode; + } + + if (BranchElimination.Eliminate(block)) + { + RemoveNode(block, block.Operations.Last); + + modified = true; + } + } + } + while (modified); + } + + private static void PropagateCopy(Operation copyOp) + { + //Propagate copy source operand to all uses of + //the destination operand. + Operand dest = copyOp.Dest; + Operand src = copyOp.GetSource(0); + + INode[] uses = dest.UseOps.ToArray(); + + foreach (INode useNode in uses) + { + for (int index = 0; index < useNode.SourcesCount; index++) + { + if (useNode.GetSource(index) == dest) + { + useNode.SetSource(index, src); + } + } + } + } + + private static bool PropagatePack(Operation packOp) + { + //Propagate pack source operands to uses by unpack + //instruction. The source depends on the unpack instruction. + bool modified = false; + + Operand dest = packOp.Dest; + Operand src0 = packOp.GetSource(0); + Operand src1 = packOp.GetSource(1); + + INode[] uses = dest.UseOps.ToArray(); + + foreach (INode useNode in uses) + { + if (!(useNode is Operation operation) || operation.Inst != Instruction.UnpackHalf2x16) + { + continue; + } + + if (operation.GetSource(0) == dest) + { + operation.TurnIntoCopy(operation.ComponentIndex == 1 ? src1 : src0); + + modified = true; + } + } + + return modified; + } + + private static void RemoveNode(BasicBlock block, LinkedListNode llNode) + { + //Remove a node from the nodes list, and also remove itself + //from all the use lists on the operands that this node uses. + block.Operations.Remove(llNode); + + Queue nodes = new Queue(); + + nodes.Enqueue(llNode.Value); + + while (nodes.TryDequeue(out INode node)) + { + for (int index = 0; index < node.SourcesCount; index++) + { + Operand src = node.GetSource(index); + + if (src.Type != OperandType.LocalVariable) + { + continue; + } + + if (src.UseOps.Remove(node) && src.UseOps.Count == 0) + { + nodes.Enqueue(src.AsgOp); + } + } + } + } + + private static bool IsUnused(INode node) + { + return DestIsLocalVar(node) && node.Dest.UseOps.Count == 0; + } + + private static bool DestIsLocalVar(INode node) + { + return node.Dest != null && node.Dest.Type == OperandType.LocalVariable; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/Optimizations/Simplification.cs b/Ryujinx.Graphics/Shader/Translation/Optimizations/Simplification.cs new file mode 100644 index 0000000000..56b1543f12 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/Optimizations/Simplification.cs @@ -0,0 +1,147 @@ +using Ryujinx.Graphics.Shader.IntermediateRepresentation; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Translation.Optimizations +{ + static class Simplification + { + private const int AllOnes = ~0; + + public static void Simplify(Operation operation) + { + switch (operation.Inst) + { + case Instruction.Add: + case Instruction.BitwiseExclusiveOr: + TryEliminateBinaryOpComutative(operation, 0); + break; + + case Instruction.BitwiseAnd: + TryEliminateBitwiseAnd(operation); + break; + + case Instruction.BitwiseOr: + TryEliminateBitwiseOr(operation); + break; + + case Instruction.ConditionalSelect: + TryEliminateConditionalSelect(operation); + break; + + case Instruction.Divide: + TryEliminateBinaryOpY(operation, 1); + break; + + case Instruction.Multiply: + TryEliminateBinaryOpComutative(operation, 1); + break; + + case Instruction.ShiftLeft: + case Instruction.ShiftRightS32: + case Instruction.ShiftRightU32: + case Instruction.Subtract: + TryEliminateBinaryOpY(operation, 0); + break; + } + } + + private static void TryEliminateBitwiseAnd(Operation operation) + { + //Try to recognize and optimize those 3 patterns (in order): + //x & 0xFFFFFFFF == x, 0xFFFFFFFF & y == y, + //x & 0x00000000 == 0x00000000, 0x00000000 & y == 0x00000000 + Operand x = operation.GetSource(0); + Operand y = operation.GetSource(1); + + if (IsConstEqual(x, AllOnes)) + { + operation.TurnIntoCopy(y); + } + else if (IsConstEqual(y, AllOnes)) + { + operation.TurnIntoCopy(x); + } + else if (IsConstEqual(x, 0) || IsConstEqual(y, 0)) + { + operation.TurnIntoCopy(Const(0)); + } + } + + private static void TryEliminateBitwiseOr(Operation operation) + { + //Try to recognize and optimize those 3 patterns (in order): + //x | 0x00000000 == x, 0x00000000 | y == y, + //x | 0xFFFFFFFF == 0xFFFFFFFF, 0xFFFFFFFF | y == 0xFFFFFFFF + Operand x = operation.GetSource(0); + Operand y = operation.GetSource(1); + + if (IsConstEqual(x, 0)) + { + operation.TurnIntoCopy(y); + } + else if (IsConstEqual(y, 0)) + { + operation.TurnIntoCopy(x); + } + else if (IsConstEqual(x, AllOnes) || IsConstEqual(y, AllOnes)) + { + operation.TurnIntoCopy(Const(AllOnes)); + } + } + + private static void TryEliminateBinaryOpY(Operation operation, int comparand) + { + Operand x = operation.GetSource(0); + Operand y = operation.GetSource(1); + + if (IsConstEqual(y, comparand)) + { + operation.TurnIntoCopy(x); + } + } + + private static void TryEliminateBinaryOpComutative(Operation operation, int comparand) + { + Operand x = operation.GetSource(0); + Operand y = operation.GetSource(1); + + if (IsConstEqual(x, comparand)) + { + operation.TurnIntoCopy(y); + } + else if (IsConstEqual(y, comparand)) + { + operation.TurnIntoCopy(x); + } + } + + private static void TryEliminateConditionalSelect(Operation operation) + { + Operand cond = operation.GetSource(0); + + if (cond.Type != OperandType.Constant) + { + return; + } + + //The condition is constant, we can turn it into a copy, and select + //the source based on the condition value. + int srcIndex = cond.Value != 0 ? 1 : 2; + + Operand source = operation.GetSource(srcIndex); + + operation.TurnIntoCopy(source); + } + + private static bool IsConstEqual(Operand operand, int comparand) + { + if (operand.Type != OperandType.Constant) + { + return false; + } + + return operand.Value == comparand; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/Ssa.cs b/Ryujinx.Graphics/Shader/Translation/Ssa.cs new file mode 100644 index 0000000000..b612649ca3 --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/Ssa.cs @@ -0,0 +1,330 @@ +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Translation +{ + static class Ssa + { + private const int GprsAndPredsCount = RegisterConsts.GprsCount + RegisterConsts.PredsCount; + + private class DefMap + { + private Dictionary _map; + + private long[] _phiMasks; + + public DefMap() + { + _map = new Dictionary(); + + _phiMasks = new long[(RegisterConsts.TotalCount + 63) / 64]; + } + + public bool TryAddOperand(Register reg, Operand operand) + { + return _map.TryAdd(reg, operand); + } + + public bool TryGetOperand(Register reg, out Operand operand) + { + return _map.TryGetValue(reg, out operand); + } + + public bool AddPhi(Register reg) + { + int key = GetKeyFromRegister(reg); + + int index = key / 64; + int bit = key & 63; + + long mask = 1L << bit; + + if ((_phiMasks[index] & mask) != 0) + { + return false; + } + + _phiMasks[index] |= mask; + + return true; + } + + public bool HasPhi(Register reg) + { + int key = GetKeyFromRegister(reg); + + int index = key / 64; + int bit = key & 63; + + return (_phiMasks[index] & (1L << bit)) != 0; + } + } + + private struct Definition + { + public BasicBlock Block { get; } + public Operand Local { get; } + + public Definition(BasicBlock block, Operand local) + { + Block = block; + Local = local; + } + } + + public static void Rename(BasicBlock[] blocks) + { + DefMap[] globalDefs = new DefMap[blocks.Length]; + + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + globalDefs[blkIndex] = new DefMap(); + } + + Queue dfPhiBlocks = new Queue(); + + //First pass, get all defs and locals uses. + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; + + Operand RenameLocal(Operand operand) + { + if (operand != null && operand.Type == OperandType.Register) + { + Operand local = localDefs[GetKeyFromRegister(operand.GetRegister())]; + + operand = local ?? operand; + } + + return operand; + } + + BasicBlock block = blocks[blkIndex]; + + LinkedListNode node = block.Operations.First; + + while (node != null) + { + if (node.Value is Operation operation) + { + for (int index = 0; index < operation.SourcesCount; index++) + { + operation.SetSource(index, RenameLocal(operation.GetSource(index))); + } + + if (operation.Dest != null && operation.Dest.Type == OperandType.Register) + { + Operand local = Local(); + + localDefs[GetKeyFromRegister(operation.Dest.GetRegister())] = local; + + operation.Dest = local; + } + } + + node = node.Next; + } + + for (int index = 0; index < RegisterConsts.TotalCount; index++) + { + Operand local = localDefs[index]; + + if (local == null) + { + continue; + } + + Register reg = GetRegisterFromKey(index); + + globalDefs[block.Index].TryAddOperand(reg, local); + + dfPhiBlocks.Enqueue(block); + + while (dfPhiBlocks.TryDequeue(out BasicBlock dfPhiBlock)) + { + foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers) + { + if (globalDefs[domFrontier.Index].AddPhi(reg)) + { + dfPhiBlocks.Enqueue(domFrontier); + } + } + } + } + } + + //Second pass, rename variables with definitions on different blocks. + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; + + BasicBlock block = blocks[blkIndex]; + + Operand RenameGlobal(Operand operand) + { + if (operand != null && operand.Type == OperandType.Register) + { + int key = GetKeyFromRegister(operand.GetRegister()); + + Operand local = localDefs[key]; + + if (local != null) + { + return local; + } + + operand = FindDefinitionForCurr(globalDefs, block, operand.GetRegister()); + + localDefs[key] = operand; + } + + return operand; + } + + LinkedListNode node = block.Operations.First; + + while (node != null) + { + if (node.Value is Operation operation) + { + for (int index = 0; index < operation.SourcesCount; index++) + { + operation.SetSource(index, RenameGlobal(operation.GetSource(index))); + } + } + + node = node.Next; + } + } + } + + private static Operand FindDefinitionForCurr(DefMap[] globalDefs, BasicBlock current, Register reg) + { + if (globalDefs[current.Index].HasPhi(reg)) + { + return InsertPhi(globalDefs, current, reg); + } + + if (current != current.ImmediateDominator) + { + return FindDefinition(globalDefs, current.ImmediateDominator, reg).Local; + } + + return Undef(); + } + + private static Definition FindDefinition(DefMap[] globalDefs, BasicBlock current, Register reg) + { + foreach (BasicBlock block in SelfAndImmediateDominators(current)) + { + DefMap defMap = globalDefs[block.Index]; + + if (defMap.TryGetOperand(reg, out Operand lastDef)) + { + return new Definition(block, lastDef); + } + + if (defMap.HasPhi(reg)) + { + return new Definition(block, InsertPhi(globalDefs, block, reg)); + } + } + + return new Definition(current, Undef()); + } + + private static IEnumerable SelfAndImmediateDominators(BasicBlock block) + { + while (block != block.ImmediateDominator) + { + yield return block; + + block = block.ImmediateDominator; + } + + yield return block; + } + + private static Operand InsertPhi(DefMap[] globalDefs, BasicBlock block, Register reg) + { + //This block has a Phi that has not been materialized yet, but that + //would define a new version of the variable we're looking for. We need + //to materialize the Phi, add all the block/operand pairs into the Phi, and + //then use the definition from that Phi. + Operand local = Local(); + + PhiNode phi = new PhiNode(local); + + AddPhi(block, phi); + + globalDefs[block.Index].TryAddOperand(reg, local); + + foreach (BasicBlock predecessor in block.Predecessors) + { + Definition def = FindDefinition(globalDefs, predecessor, reg); + + phi.AddSource(def.Block, def.Local); + } + + return local; + } + + private static void AddPhi(BasicBlock block, PhiNode phi) + { + LinkedListNode node = block.Operations.First; + + if (node != null) + { + while (node.Next?.Value is PhiNode) + { + node = node.Next; + } + } + + if (node?.Value is PhiNode) + { + block.Operations.AddAfter(node, phi); + } + else + { + block.Operations.AddFirst(phi); + } + } + + private static int GetKeyFromRegister(Register reg) + { + if (reg.Type == RegisterType.Gpr) + { + return reg.Index; + } + else if (reg.Type == RegisterType.Predicate) + { + return RegisterConsts.GprsCount + reg.Index; + } + else /* if (reg.Type == RegisterType.Flag) */ + { + return GprsAndPredsCount + reg.Index; + } + } + + private static Register GetRegisterFromKey(int key) + { + if (key < RegisterConsts.GprsCount) + { + return new Register(key, RegisterType.Gpr); + } + else if (key < GprsAndPredsCount) + { + return new Register(key - RegisterConsts.GprsCount, RegisterType.Predicate); + } + else /* if (key < RegisterConsts.TotalCount) */ + { + return new Register(key - GprsAndPredsCount, RegisterType.Flag); + } + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Shader/Translation/Translator.cs b/Ryujinx.Graphics/Shader/Translation/Translator.cs new file mode 100644 index 0000000000..706f3cfa4e --- /dev/null +++ b/Ryujinx.Graphics/Shader/Translation/Translator.cs @@ -0,0 +1,219 @@ +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Shader.CodeGen.Glsl; +using Ryujinx.Graphics.Shader.Decoders; +using Ryujinx.Graphics.Shader.Instructions; +using Ryujinx.Graphics.Shader.IntermediateRepresentation; +using Ryujinx.Graphics.Shader.StructuredIr; +using Ryujinx.Graphics.Shader.Translation.Optimizations; +using System.Collections.Generic; + +using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper; + +namespace Ryujinx.Graphics.Shader.Translation +{ + public static class Translator + { + public static ShaderProgram Translate(IGalMemory memory, ulong address, ShaderConfig config) + { + return Translate(memory, address, 0, config); + } + + public static ShaderProgram Translate( + IGalMemory memory, + ulong address, + ulong addressB, + ShaderConfig config) + { + Operation[] shaderOps = DecodeShader(memory, address, config.Type); + + if (addressB != 0) + { + //Dual vertex shader. + Operation[] shaderOpsB = DecodeShader(memory, addressB, config.Type); + + shaderOps = Combine(shaderOps, shaderOpsB); + } + + BasicBlock[] irBlocks = ControlFlowGraph.MakeCfg(shaderOps); + + Dominance.FindDominators(irBlocks[0], irBlocks.Length); + + Dominance.FindDominanceFrontiers(irBlocks); + + Ssa.Rename(irBlocks); + + Optimizer.Optimize(irBlocks); + + StructuredProgramInfo sInfo = StructuredProgram.MakeStructuredProgram(irBlocks); + + GlslProgram program = GlslGenerator.Generate(sInfo, config); + + ShaderProgramInfo spInfo = new ShaderProgramInfo( + program.CBufferDescriptors, + program.TextureDescriptors); + + return new ShaderProgram(spInfo, program.Code); + } + + private static Operation[] DecodeShader(IGalMemory memory, ulong address, GalShaderType shaderType) + { + ShaderHeader header = new ShaderHeader(memory, address); + + Block[] cfg = Decoder.Decode(memory, address); + + EmitterContext context = new EmitterContext(shaderType, header); + + for (int blkIndex = 0; blkIndex < cfg.Length; blkIndex++) + { + Block block = cfg[blkIndex]; + + context.CurrBlock = block; + + context.MarkLabel(context.GetLabel(block.Address)); + + for (int opIndex = 0; opIndex < block.OpCodes.Count; opIndex++) + { + OpCode op = block.OpCodes[opIndex]; + + if (op.NeverExecute) + { + continue; + } + + Operand predSkipLbl = null; + + bool skipPredicateCheck = op.Emitter == InstEmit.Bra; + + if (op is OpCodeSync opSync) + { + //If the instruction is a SYNC instruction with only one + //possible target address, then the instruction is basically + //just a simple branch, we can generate code similar to branch + //instructions, with the condition check on the branch itself. + skipPredicateCheck |= opSync.Targets.Count < 2; + } + + if (!(op.Predicate.IsPT || skipPredicateCheck)) + { + Operand label; + + if (opIndex == block.OpCodes.Count - 1 && block.Next != null) + { + label = context.GetLabel(block.Next.Address); + } + else + { + label = Label(); + + predSkipLbl = label; + } + + Operand pred = Register(op.Predicate); + + if (op.InvertPredicate) + { + context.BranchIfTrue(label, pred); + } + else + { + context.BranchIfFalse(label, pred); + } + } + + context.CurrOp = op; + + op.Emitter(context); + + if (predSkipLbl != null) + { + context.MarkLabel(predSkipLbl); + } + } + } + + return context.GetOperations(); + } + + private static Operation[] Combine(Operation[] a, Operation[] b) + { + //Here we combine two shaders. + //For shader A: + //- All user attribute stores on shader A are turned into copies to a + //temporary variable. It's assumed that shader B will consume them. + //- All return instructions are turned into branch instructions, the + //branch target being the start of the shader B code. + //For shader B: + //- All user attribute loads on shader B are turned into copies from a + //temporary variable, as long that attribute is written by shader A. + List output = new List(a.Length + b.Length); + + Operand[] temps = new Operand[AttributeConsts.UserAttributesCount * 4]; + + Operand lblB = Label(); + + for (int index = 0; index < a.Length; index++) + { + Operation operation = a[index]; + + if (IsUserAttribute(operation.Dest)) + { + int tIndex = (operation.Dest.Value - AttributeConsts.UserAttributeBase) / 4; + + Operand temp = temps[tIndex]; + + if (temp == null) + { + temp = Local(); + + temps[tIndex] = temp; + } + + operation.Dest = temp; + } + + if (operation.Inst == Instruction.Return) + { + output.Add(new Operation(Instruction.Branch, lblB)); + } + else + { + output.Add(operation); + } + } + + output.Add(new Operation(Instruction.MarkLabel, lblB)); + + for (int index = 0; index < b.Length; index++) + { + Operation operation = b[index]; + + for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++) + { + Operand src = operation.GetSource(srcIndex); + + if (IsUserAttribute(src)) + { + Operand temp = temps[(src.Value - AttributeConsts.UserAttributeBase) / 4]; + + if (temp != null) + { + operation.SetSource(srcIndex, temp); + } + } + } + + output.Add(operation); + } + + return output.ToArray(); + } + + private static bool IsUserAttribute(Operand operand) + { + return operand != null && + operand.Type == OperandType.Attribute && + operand.Value >= AttributeConsts.UserAttributeBase && + operand.Value < AttributeConsts.UserAttributeEnd; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs b/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs deleted file mode 100644 index 65a8f356b2..0000000000 --- a/Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Ryujinx.Graphics.Texture -{ - [Flags] - public enum TextureInstructionSuffix - { - None = 0x00, // No Modifier - Lz = 0x02, // Load LOD Zero - Lb = 0x08, // Load Bias - Ll = 0x10, // Load LOD - Lba = 0x20, // Load Bias with OperA? Auto? - Lla = 0x40, // Load LOD with OperA? Auto? - Dc = 0x80, // Depth Compare - AOffI = 0x100, // Offset - Mz = 0x200, // Multisample Zero? - Ptp = 0x400 // ??? - } -} diff --git a/Ryujinx.ShaderTools/Memory.cs b/Ryujinx.ShaderTools/Memory.cs index f801ab39a9..c99224b5ed 100644 --- a/Ryujinx.ShaderTools/Memory.cs +++ b/Ryujinx.ShaderTools/Memory.cs @@ -23,4 +23,4 @@ namespace Ryujinx.ShaderTools return Reader.ReadInt32(); } } -} +} \ No newline at end of file diff --git a/Ryujinx.ShaderTools/Program.cs b/Ryujinx.ShaderTools/Program.cs index 77aba0abe6..e763e2c1c1 100644 --- a/Ryujinx.ShaderTools/Program.cs +++ b/Ryujinx.ShaderTools/Program.cs @@ -1,5 +1,6 @@ using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics.Gal.Shader; +using Ryujinx.Graphics.Shader; +using Ryujinx.Graphics.Shader.Translation; using System; using System.IO; @@ -7,32 +8,30 @@ namespace Ryujinx.ShaderTools { class Program { - private static readonly int MaxUboSize = 65536; - static void Main(string[] args) { if (args.Length == 2) { - GlslDecompiler Decompiler = new GlslDecompiler(MaxUboSize, true); - - GalShaderType ShaderType = GalShaderType.Vertex; + GalShaderType type = GalShaderType.Vertex; switch (args[0].ToLower()) { - case "v": ShaderType = GalShaderType.Vertex; break; - case "tc": ShaderType = GalShaderType.TessControl; break; - case "te": ShaderType = GalShaderType.TessEvaluation; break; - case "g": ShaderType = GalShaderType.Geometry; break; - case "f": ShaderType = GalShaderType.Fragment; break; + case "v": type = GalShaderType.Vertex; break; + case "tc": type = GalShaderType.TessControl; break; + case "te": type = GalShaderType.TessEvaluation; break; + case "g": type = GalShaderType.Geometry; break; + case "f": type = GalShaderType.Fragment; break; } - using (FileStream FS = new FileStream(args[1], FileMode.Open, FileAccess.Read)) + using (FileStream fs = new FileStream(args[1], FileMode.Open, FileAccess.Read)) { - Memory Mem = new Memory(FS); + Memory mem = new Memory(fs); - GlslProgram Program = Decompiler.Decompile(Mem, 0, ShaderType); + ShaderConfig config = new ShaderConfig(type, 65536); - Console.WriteLine(Program.Code); + string code = Translator.Translate(mem, 0, config).Code; + + Console.WriteLine(code); } } else @@ -41,4 +40,4 @@ namespace Ryujinx.ShaderTools } } } -} +} \ No newline at end of file diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index 1b26b39188..42a6a74159 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -75,7 +75,7 @@ namespace Ryujinx break; } } - else + else { Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file"); } From bea73895f543f444e5c307321659088a051ce47c Mon Sep 17 00:00:00 2001 From: jduncanator <1518948+jduncanator@users.noreply.github.com> Date: Sat, 20 Apr 2019 11:56:55 +1000 Subject: [PATCH 34/36] Implement IIrSensorServer GetNpadIrCameraHandle (#663) * Implement IIrSensorServer GetNpadIrCameraHandle Resolves #618 * Throw ArgumentOutOfRange instead of IOE * Revise for changes in later firmware Based on RE work from 6.1.0 * Nits --- .../HOS/Services/Irs/IIrSensorServer.cs | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/Ryujinx.HLE/HOS/Services/Irs/IIrSensorServer.cs b/Ryujinx.HLE/HOS/Services/Irs/IIrSensorServer.cs index e6521c041e..b63f99c846 100644 --- a/Ryujinx.HLE/HOS/Services/Irs/IIrSensorServer.cs +++ b/Ryujinx.HLE/HOS/Services/Irs/IIrSensorServer.cs @@ -1,5 +1,7 @@ using Ryujinx.Common.Logging; +using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Ipc; +using System; using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Services.Irs @@ -10,14 +12,13 @@ namespace Ryujinx.HLE.HOS.Services.Irs public override IReadOnlyDictionary Commands => _commands; - private bool _activated; - public IIrSensorServer() { _commands = new Dictionary { - { 302, ActivateIrsensor }, - { 303, DeactivateIrsensor } + { 302, ActivateIrsensor }, + { 303, DeactivateIrsensor }, + { 311, GetNpadIrCameraHandle } }; } @@ -40,5 +41,45 @@ namespace Ryujinx.HLE.HOS.Services.Irs return 0; } + + // GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle + public long GetNpadIrCameraHandle(ServiceCtx context) + { + uint npadId = context.RequestData.ReadUInt32(); + + if (npadId >= 8 && npadId != 16 && npadId != 32) + { + return ErrorCode.MakeError(ErrorModule.Hid, 0x2c5); + } + + if (((1 << (int)npadId) & 0x1000100FF) == 0) + { + return ErrorCode.MakeError(ErrorModule.Hid, 0x2c5); + } + + int npadTypeId = GetNpadTypeId(npadId); + + context.ResponseData.Write(npadTypeId); + + return 0; + } + + private int GetNpadTypeId(uint npadId) + { + switch(npadId) + { + case 0: return 0; + case 1: return 1; + case 2: return 2; + case 3: return 3; + case 4: return 4; + case 5: return 5; + case 6: return 6; + case 7: return 7; + case 32: return 8; + case 16: return 9; + default: throw new ArgumentOutOfRangeException(nameof(npadId)); + } + } } } \ No newline at end of file From 9e923b1473ca565df2012de10d319e336eab67f4 Mon Sep 17 00:00:00 2001 From: jduncanator <1518948+jduncanator@users.noreply.github.com> Date: Sat, 20 Apr 2019 12:23:13 +1000 Subject: [PATCH 35/36] Implement IIrSensorServer GetIrsensorSharedMemoryHandle (#664) * Implement IIrSensorServer GetIrsensorSharedMemoryHandle Resolves #620 * Set _irsSharedMem --- Ryujinx.HLE/HOS/Horizon.cs | 6 ++++ .../HOS/Services/Irs/IIrSensorServer.cs | 30 ++++++++++++++++--- Ryujinx.HLE/HOS/Services/ServiceFactory.cs | 2 +- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index b5ce555a16..e152846e42 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -30,6 +30,7 @@ namespace Ryujinx.HLE.HOS internal const int HidSize = 0x40000; internal const int FontSize = 0x1100000; + internal const int IirsSize = 0x8000; private const int MemoryBlockAllocatorSize = 0x2710; @@ -81,6 +82,7 @@ namespace Ryujinx.HLE.HOS internal KSharedMemory HidSharedMem { get; private set; } internal KSharedMemory FontSharedMem { get; private set; } + internal KSharedMemory IirsSharedMem { get; private set; } internal SharedFontManager Font { get; private set; } @@ -151,17 +153,21 @@ namespace Ryujinx.HLE.HOS ulong hidPa = region.Address; ulong fontPa = region.Address + HidSize; + ulong iirsPa = region.Address + HidSize + FontSize; HidBaseAddress = (long)(hidPa - DramMemoryMap.DramBase); KPageList hidPageList = new KPageList(); KPageList fontPageList = new KPageList(); + KPageList iirsPageList = new KPageList(); hidPageList .AddRange(hidPa, HidSize / KMemoryManager.PageSize); fontPageList.AddRange(fontPa, FontSize / KMemoryManager.PageSize); + iirsPageList.AddRange(iirsPa, IirsSize / KMemoryManager.PageSize); HidSharedMem = new KSharedMemory(this, hidPageList, 0, 0, MemoryPermission.Read); FontSharedMem = new KSharedMemory(this, fontPageList, 0, 0, MemoryPermission.Read); + IirsSharedMem = new KSharedMemory(this, iirsPageList, 0, 0, MemoryPermission.Read); AppletState = new AppletStateMgr(this); diff --git a/Ryujinx.HLE/HOS/Services/Irs/IIrSensorServer.cs b/Ryujinx.HLE/HOS/Services/Irs/IIrSensorServer.cs index b63f99c846..500d5f1079 100644 --- a/Ryujinx.HLE/HOS/Services/Irs/IIrSensorServer.cs +++ b/Ryujinx.HLE/HOS/Services/Irs/IIrSensorServer.cs @@ -1,6 +1,8 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.Exceptions; using Ryujinx.HLE.HOS.Ipc; +using Ryujinx.HLE.HOS.Kernel.Common; +using Ryujinx.HLE.HOS.Kernel.Memory; using System; using System.Collections.Generic; @@ -12,14 +14,19 @@ namespace Ryujinx.HLE.HOS.Services.Irs public override IReadOnlyDictionary Commands => _commands; - public IIrSensorServer() + private KSharedMemory _irsSharedMem; + + public IIrSensorServer(KSharedMemory irsSharedMem) { _commands = new Dictionary { - { 302, ActivateIrsensor }, - { 303, DeactivateIrsensor }, - { 311, GetNpadIrCameraHandle } + { 302, ActivateIrsensor }, + { 303, DeactivateIrsensor }, + { 304, GetIrsensorSharedMemoryHandle }, + { 311, GetNpadIrCameraHandle } }; + + _irsSharedMem = irsSharedMem; } // ActivateIrsensor(nn::applet::AppletResourceUserId, pid) @@ -42,6 +49,21 @@ namespace Ryujinx.HLE.HOS.Services.Irs return 0; } + // GetIrsensorSharedMemoryHandle(nn::applet::AppletResourceUserId, pid) -> handle + public long GetIrsensorSharedMemoryHandle(ServiceCtx context) + { + var handleTable = context.Process.HandleTable; + + if (handleTable.GenerateHandle(_irsSharedMem, out int handle) != KernelResult.Success) + { + throw new InvalidOperationException("Out of handles!"); + } + + context.Response.HandleDesc = IpcHandleDesc.MakeCopy(handle); + + return 0; + } + // GetNpadIrCameraHandle(u32) -> nn::irsensor::IrCameraHandle public long GetNpadIrCameraHandle(ServiceCtx context) { diff --git a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs index 113bbe51c8..3bde7b8779 100644 --- a/Ryujinx.HLE/HOS/Services/ServiceFactory.cs +++ b/Ryujinx.HLE/HOS/Services/ServiceFactory.cs @@ -112,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Services return new IHidServer(system); case "irs": - return new IIrSensorServer(); + return new IIrSensorServer(system.IirsSharedMem); case "ldr:ro": return new IRoInterface(); From 74da8785a5f3a79914182d384e966fb5d27fa708 Mon Sep 17 00:00:00 2001 From: LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> Date: Sun, 21 Apr 2019 04:07:35 +0200 Subject: [PATCH 36/36] Sse optimized the 32-bit Vector & Scalar integer-to-fp conversion instructions (signed & unsigned); added the related Gp & V_Fixed Tests (signed & unsigned). (#662) * Update CpuTestSimdCvt.cs * Update CpuTestSimd.cs * Update CpuTestSimdShImm.cs * Update InstEmitSimdCvt.cs * Update OpCodeTable.cs * Update InstEmitSimdCvt.cs --- ChocolArm64/Instructions/InstEmitSimdCvt.cs | 191 +++++++++++++++++--- ChocolArm64/OpCodeTable.cs | 4 + Ryujinx.Tests/Cpu/CpuTestSimd.cs | 4 +- Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs | 106 ++++++++++- Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs | 62 +++++++ 5 files changed, 342 insertions(+), 25 deletions(-) diff --git a/ChocolArm64/Instructions/InstEmitSimdCvt.cs b/ChocolArm64/Instructions/InstEmitSimdCvt.cs index ab2fb6a833..c5f16f86cb 100644 --- a/ChocolArm64/Instructions/InstEmitSimdCvt.cs +++ b/ChocolArm64/Instructions/InstEmitSimdCvt.cs @@ -363,7 +363,7 @@ namespace ChocolArm64.Instructions if (context.CurrOp.RegisterSize == RegisterSize.Int32) { - context.Emit(OpCodes.Conv_U4); + context.Emit(OpCodes.Conv_I4); } EmitFloatCast(context, op.Size); @@ -393,11 +393,20 @@ namespace ChocolArm64.Instructions { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - EmitVectorExtractSx(context, op.Rn, 0, op.Size + 2); + int sizeF = op.Size & 1; - EmitFloatCast(context, op.Size); + if (Optimizations.UseSse2 && sizeF == 0) + { + EmitSse2cvtF_Signed(context, scalar: true); + } + else + { + EmitVectorExtractSx(context, op.Rn, 0, sizeF + 2); - EmitScalarSetF(context, op.Rd, op.Size); + EmitFloatCast(context, sizeF); + + EmitScalarSetF(context, op.Rd, sizeF); + } } public static void Scvtf_V(ILEmitterCtx context) @@ -408,18 +417,24 @@ namespace ChocolArm64.Instructions if (Optimizations.UseSse2 && sizeF == 0) { - Type[] typesCvt = new Type[] { typeof(Vector128) }; + EmitSse2cvtF_Signed(context, scalar: false); + } + else + { + EmitVectorCvtf(context, signed: true); + } + } - context.EmitLdvec(op.Rn); + public static void Scvtf_V_Fixed(ILEmitterCtx context) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); + // sizeF == ((OpCodeSimdShImm64)op).Size - 2 + int sizeF = op.Size & 1; - context.EmitStvec(op.Rd); - - if (op.RegisterSize == RegisterSize.Simd64) - { - EmitVectorZeroUpper(context, op.Rd); - } + if (Optimizations.UseSse2 && sizeF == 0) + { + EmitSse2cvtF_Signed(context, scalar: false); } else { @@ -469,18 +484,55 @@ namespace ChocolArm64.Instructions { OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; - EmitVectorExtractZx(context, op.Rn, 0, op.Size + 2); + int sizeF = op.Size & 1; - context.Emit(OpCodes.Conv_R_Un); + if (Optimizations.UseSse2 && sizeF == 0) + { + EmitSse2cvtF_Unsigned(context, scalar: true); + } + else + { + EmitVectorExtractZx(context, op.Rn, 0, sizeF + 2); - EmitFloatCast(context, op.Size); + context.Emit(OpCodes.Conv_R_Un); - EmitScalarSetF(context, op.Rd, op.Size); + EmitFloatCast(context, sizeF); + + EmitScalarSetF(context, op.Rd, sizeF); + } } public static void Ucvtf_V(ILEmitterCtx context) { - EmitVectorCvtf(context, signed: false); + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + int sizeF = op.Size & 1; + + if (Optimizations.UseSse2 && sizeF == 0) + { + EmitSse2cvtF_Unsigned(context, scalar: false); + } + else + { + EmitVectorCvtf(context, signed: false); + } + } + + public static void Ucvtf_V_Fixed(ILEmitterCtx context) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + // sizeF == ((OpCodeSimdShImm64)op).Size - 2 + int sizeF = op.Size & 1; + + if (Optimizations.UseSse2 && sizeF == 0) + { + EmitSse2cvtF_Unsigned(context, scalar: false); + } + else + { + EmitVectorCvtf(context, signed: false); + } } private static void EmitFcvtn(ILEmitterCtx context, bool signed, bool scalar) @@ -838,7 +890,7 @@ namespace ChocolArm64.Instructions int fBits = GetImmShr(fixedOp); // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) - int fpScaled = 0x40000000 + (fBits - 1) * 0x800000; + int fpScaled = 0x3F800000 + fBits * 0x800000; context.EmitLdc_I4(fpScaled); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); @@ -894,7 +946,7 @@ namespace ChocolArm64.Instructions int fBits = GetImmShr(fixedOp); // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) - long fpScaled = 0x4000000000000000L + (fBits - 1) * 0x10000000000000L; + long fpScaled = 0x3FF0000000000000L + fBits * 0x10000000000000L; context.EmitLdc_I8(fpScaled); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); @@ -972,7 +1024,7 @@ namespace ChocolArm64.Instructions int fBits = GetImmShr(fixedOp); // BitConverter.Int32BitsToSingle(fpScaled) == MathF.Pow(2f, fBits) - int fpScaled = 0x40000000 + (fBits - 1) * 0x800000; + int fpScaled = 0x3F800000 + fBits * 0x800000; context.EmitLdc_I4(fpScaled); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); @@ -1060,7 +1112,7 @@ namespace ChocolArm64.Instructions int fBits = GetImmShr(fixedOp); // BitConverter.Int64BitsToDouble(fpScaled) == Math.Pow(2d, fBits) - long fpScaled = 0x4000000000000000L + (fBits - 1) * 0x10000000000000L; + long fpScaled = 0x3FF0000000000000L + fBits * 0x10000000000000L; context.EmitLdc_I8(fpScaled); context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); @@ -1158,6 +1210,101 @@ namespace ChocolArm64.Instructions } } + private static void EmitSse2cvtF_Signed(ILEmitterCtx context, bool scalar) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + Type[] typesMul = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesCvt = new Type[] { typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(int) }; + + context.EmitLdvec(op.Rn); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); + + if (op is OpCodeSimdShImm64 fixedOp) + { + int fBits = GetImmShr(fixedOp); + + // BitConverter.Int32BitsToSingle(fpScaled) == 1f / MathF.Pow(2f, fBits) + int fpScaled = 0x3F800000 - fBits * 0x800000; + + context.EmitLdc_I4(fpScaled); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMul)); + } + + context.EmitStvec(op.Rd); + + if (scalar) + { + EmitVectorZero32_128(context, op.Rd); + } + else if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + + private static void EmitSse2cvtF_Unsigned(ILEmitterCtx context, bool scalar) + { + OpCodeSimd64 op = (OpCodeSimd64)context.CurrOp; + + Type[] typesMulAdd = new Type[] { typeof(Vector128), typeof(Vector128) }; + Type[] typesSrlSll = new Type[] { typeof(Vector128), typeof(byte) }; + Type[] typesCvt = new Type[] { typeof(Vector128) }; + Type[] typesSav = new Type[] { typeof(int) }; + + context.EmitLdvec(op.Rn); + + context.EmitLdc_I4(16); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrlSll)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); + + context.EmitLdc_I4(0x47800000); // 65536.0f (1 << 16) + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulAdd)); + + context.EmitLdvec(op.Rn); + + context.EmitLdc_I4(16); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), typesSrlSll)); + + context.EmitLdc_I4(16); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), typesSrlSll)); + + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertToVector128Single), typesCvt)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Add), typesMulAdd)); + + if (op is OpCodeSimdShImm64 fixedOp) + { + int fBits = GetImmShr(fixedOp); + + // BitConverter.Int32BitsToSingle(fpScaled) == 1f / MathF.Pow(2f, fBits) + int fpScaled = 0x3F800000 - fBits * 0x800000; + + context.EmitLdc_I4(fpScaled); + context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), typesSav)); + + context.EmitCall(typeof(Sse).GetMethod(nameof(Sse.Multiply), typesMulAdd)); + } + + context.EmitStvec(op.Rd); + + if (scalar) + { + EmitVectorZero32_128(context, op.Rd); + } + else if (op.RegisterSize == RegisterSize.Simd64) + { + EmitVectorZeroUpper(context, op.Rd); + } + } + private static string GetSse41NameRnd(RoundMode roundMode) { switch (roundMode) diff --git a/ChocolArm64/OpCodeTable.cs b/ChocolArm64/OpCodeTable.cs index 50bc6a1d6d..fb8b19cd19 100644 --- a/ChocolArm64/OpCodeTable.cs +++ b/ChocolArm64/OpCodeTable.cs @@ -439,6 +439,8 @@ namespace ChocolArm64 SetA64(">00111100x000010>xxxxxxxxxxxxxxx", InstEmit.Scvtf_Gp_Fixed, typeof(OpCodeSimdCvt64)); SetA64("010111100x100001110110xxxxxxxxxx", InstEmit.Scvtf_S, typeof(OpCodeSimd64)); SetA64("0>0011100<100001110110xxxxxxxxxx", InstEmit.Scvtf_V, typeof(OpCodeSimd64)); + SetA64("0x001111001xxxxx111001xxxxxxxxxx", InstEmit.Scvtf_V_Fixed, typeof(OpCodeSimdShImm64)); + SetA64("0100111101xxxxxx111001xxxxxxxxxx", InstEmit.Scvtf_V_Fixed, typeof(OpCodeSimdShImm64)); SetA64("01011110000xxxxx000000xxxxxxxxxx", InstEmit.Sha1c_V, typeof(OpCodeSimdReg64)); SetA64("0101111000101000000010xxxxxxxxxx", InstEmit.Sha1h_V, typeof(OpCodeSimd64)); SetA64("01011110000xxxxx001000xxxxxxxxxx", InstEmit.Sha1m_V, typeof(OpCodeSimdReg64)); @@ -548,6 +550,8 @@ namespace ChocolArm64 SetA64(">00111100x000011>xxxxxxxxxxxxxxx", InstEmit.Ucvtf_Gp_Fixed, typeof(OpCodeSimdCvt64)); SetA64("011111100x100001110110xxxxxxxxxx", InstEmit.Ucvtf_S, typeof(OpCodeSimd64)); SetA64("0>1011100<100001110110xxxxxxxxxx", InstEmit.Ucvtf_V, typeof(OpCodeSimd64)); + SetA64("0x101111001xxxxx111001xxxxxxxxxx", InstEmit.Ucvtf_V_Fixed, typeof(OpCodeSimdShImm64)); + SetA64("0110111101xxxxxx111001xxxxxxxxxx", InstEmit.Ucvtf_V_Fixed, typeof(OpCodeSimdShImm64)); SetA64("0x101110<<1xxxxx000001xxxxxxxxxx", InstEmit.Uhadd_V, typeof(OpCodeSimdReg64)); SetA64("0x101110<<1xxxxx001001xxxxxxxxxx", InstEmit.Uhsub_V, typeof(OpCodeSimdReg64)); SetA64("0x101110<<1xxxxx011001xxxxxxxxxx", InstEmit.Umax_V, typeof(OpCodeSimdReg64)); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd.cs b/Ryujinx.Tests/Cpu/CpuTestSimd.cs index fd395da8ef..df23f2eff8 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimd.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimd.cs @@ -2082,7 +2082,7 @@ namespace Ryujinx.Tests.Cpu SingleOpcode(opcodes, v0: v0, v1: v1); - CompareAgainstUnicorn(); + CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned } [Test, Pairwise] [Explicit] @@ -2118,7 +2118,7 @@ namespace Ryujinx.Tests.Cpu SingleOpcode(opcodes, v0: v0, v1: v1); - CompareAgainstUnicorn(); + CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned } [Test, Pairwise] diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs index 60935488ef..ff8e802708 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs @@ -288,6 +288,42 @@ namespace Ryujinx.Tests.Cpu }; } + private static uint[] _SU_Cvt_F_Gp_WS_() + { + return new uint[] + { + 0x1E220000u, // SCVTF S0, W0 + 0x1E230000u // UCVTF S0, W0 + }; + } + + private static uint[] _SU_Cvt_F_Gp_WD_() + { + return new uint[] + { + 0x1E620000u, // SCVTF D0, W0 + 0x1E630000u // UCVTF D0, W0 + }; + } + + private static uint[] _SU_Cvt_F_Gp_XS_() + { + return new uint[] + { + 0x9E220000u, // SCVTF S0, X0 + 0x9E230000u // UCVTF S0, X0 + }; + } + + private static uint[] _SU_Cvt_F_Gp_XD_() + { + return new uint[] + { + 0x9E620000u, // SCVTF D0, X0 + 0x9E630000u // UCVTF D0, X0 + }; + } + private static uint[] _SU_Cvt_F_Gp_Fixed_WS_() { return new uint[] @@ -480,6 +516,74 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_Gp_WS([ValueSource("_SU_Cvt_F_Gp_WS_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_W_")] [Random(RndCnt)] uint wn) + { + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + + uint w31 = TestContext.CurrentContext.Random.NextUInt(); + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE0E1(z, z); + + SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_Gp_WD([ValueSource("_SU_Cvt_F_Gp_WD_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_W_")] [Random(RndCnt)] uint wn) + { + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + + uint w31 = TestContext.CurrentContext.Random.NextUInt(); + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(z); + + SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_Gp_XS([ValueSource("_SU_Cvt_F_Gp_XS_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_X_")] [Random(RndCnt)] ulong xn) + { + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + + ulong x31 = TestContext.CurrentContext.Random.NextULong(); + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE0E1(z, z); + + SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_Gp_XD([ValueSource("_SU_Cvt_F_Gp_XD_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 31u)] uint rn, + [ValueSource("_X_")] [Random(RndCnt)] ulong xn) + { + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + + ulong x31 = TestContext.CurrentContext.Random.NextULong(); + ulong z = TestContext.CurrentContext.Random.NextULong(); + Vector128 v0 = MakeVectorE1(z); + + SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0); + + CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned + } + [Test, Pairwise] [Explicit] public void SU_Cvt_F_Gp_Fixed_WS([ValueSource("_SU_Cvt_F_Gp_Fixed_WS_")] uint opcodes, [Values(0u)] uint rd, @@ -561,7 +665,7 @@ namespace Ryujinx.Tests.Cpu SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0); - CompareAgainstUnicorn(); + CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned } #endif } diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs index cabaac0220..c08949a5ae 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs @@ -194,6 +194,24 @@ namespace Ryujinx.Tests.Cpu }; } + private static uint[] _SU_Cvt_F_V_Fixed_2S_4S_() + { + return new uint[] + { + 0x0F20E400u, // SCVTF V0.2S, V0.2S, #32 + 0x2F20E400u // UCVTF V0.2S, V0.2S, #32 + }; + } + + private static uint[] _SU_Cvt_F_V_Fixed_2D_() + { + return new uint[] + { + 0x4F40E400u, // SCVTF V0.2D, V0.2D, #64 + 0x6F40E400u // UCVTF V0.2D, V0.2D, #64 + }; + } + private static uint[] _SU_Shll_V_8B8H_16B8H_() { return new uint[] @@ -454,6 +472,50 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_V_Fixed_2S_4S([ValueSource("_SU_Cvt_F_V_Fixed_2S_4S_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource("_2S_")] [Random(RndCnt)] ulong z, + [ValueSource("_2S_")] [Random(RndCnt)] ulong a, + [Values(1u, 32u)] [Random(2u, 31u, RndCntFBits)] uint fBits, + [Values(0b0u, 0b1u)] uint q) // <2S, 4S> + { + uint immHb = (64 - fBits) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + opcodes |= ((q & 1) << 30); + + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(a, a * q); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] [Explicit] + public void SU_Cvt_F_V_Fixed_2D([ValueSource("_SU_Cvt_F_V_Fixed_2D_")] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource("_1D_")] [Random(RndCnt)] ulong z, + [ValueSource("_1D_")] [Random(RndCnt)] ulong a, + [Values(1u, 64u)] [Random(2u, 63u, RndCntFBits)] uint fBits) + { + uint immHb = (128 - fBits) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + + Vector128 v0 = MakeVectorE0E1(z, z); + Vector128 v1 = MakeVectorE0E1(a, a); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsD); // unsigned + } + [Test, Pairwise, Description("SHL , , #")] public void Shl_S_D([Values(0u)] uint rd, [Values(1u, 0u)] uint rn,