diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index 2e022fbd4..a44073513 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -144,6 +144,50 @@ namespace Ryujinx.Graphics.Gal.Shader EmitFsetp(Block, OpCode, ShaderOper.RR); } + public static void Iadd_C(ShaderIrBlock Block, long OpCode) + { + EmitIadd(Block, OpCode, ShaderOper.CR); + } + + public static void Iadd_I(ShaderIrBlock Block, long OpCode) + { + EmitIadd(Block, OpCode, ShaderOper.Imm); + } + + public static void Iadd_I32(ShaderIrBlock Block, long OpCode) + { + ShaderIrNode OperA = GetOperGpr8 (OpCode); + ShaderIrNode OperB = GetOperImm32_20(OpCode); + + bool NegA = ((OpCode >> 56) & 1) != 0; + + OperA = GetAluIneg(OperA, NegA); + + ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + + public static void Iadd_R(ShaderIrBlock Block, long OpCode) + { + EmitIadd(Block, OpCode, ShaderOper.RR); + } + + public static void Iadd3_C(ShaderIrBlock Block, long OpCode) + { + EmitIadd3(Block, OpCode, ShaderOper.CR); + } + + public static void Iadd3_I(ShaderIrBlock Block, long OpCode) + { + EmitIadd3(Block, OpCode, ShaderOper.Imm); + } + + public static void Iadd3_R(ShaderIrBlock Block, long OpCode) + { + EmitIadd3(Block, OpCode, ShaderOper.RR); + } + public static void Imnmx_C(ShaderIrBlock Block, long OpCode) { EmitImnmx(Block, OpCode, ShaderOper.CR); @@ -184,6 +228,21 @@ namespace Ryujinx.Graphics.Gal.Shader EmitIscadd(Block, OpCode, ShaderOper.RR); } + public static void Iset_C(ShaderIrBlock Block, long OpCode) + { + EmitIset(Block, OpCode, ShaderOper.CR); + } + + public static void Iset_I(ShaderIrBlock Block, long OpCode) + { + EmitIset(Block, OpCode, ShaderOper.Imm); + } + + public static void Iset_R(ShaderIrBlock Block, long OpCode) + { + EmitIset(Block, OpCode, ShaderOper.RR); + } + public static void Isetp_C(ShaderIrBlock Block, long OpCode) { EmitIsetp(Block, OpCode, ShaderOper.CR); @@ -215,13 +274,13 @@ namespace Ryujinx.Graphics.Gal.Shader case 2: Inst = ShaderIrInst.Xor; break; } - ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA); + ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), InvB); //SubOp == 3 is pass, used by the not instruction //which just moves the inverted register value. if (SubOp < 3) { - ShaderIrNode OperB = GetAluNot(GetOperImm32_20(OpCode), InvB); + ShaderIrNode OperA = GetAluNot(GetOperGpr8(OpCode), InvA); ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB); @@ -229,10 +288,25 @@ namespace Ryujinx.Graphics.Gal.Shader } else { - Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode)); + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperB), OpCode)); } } + public static void Lop_C(ShaderIrBlock Block, long OpCode) + { + EmitLop(Block, OpCode, ShaderOper.CR); + } + + public static void Lop_I(ShaderIrBlock Block, long OpCode) + { + EmitLop(Block, OpCode, ShaderOper.Imm); + } + + public static void Lop_R(ShaderIrBlock Block, long OpCode) + { + EmitLop(Block, OpCode, ShaderOper.RR); + } + public static void Mufu(ShaderIrBlock Block, long OpCode) { int SubOp = (int)(OpCode >> 20) & 0xf; @@ -533,6 +607,92 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } + private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + ShaderIrNode OperA = GetOperGpr8(OpCode); + ShaderIrNode OperB; + + switch (Oper) + { + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + bool NegA = ((OpCode >> 49) & 1) != 0; + bool NegB = ((OpCode >> 48) & 1) != 0; + + OperA = GetAluIneg(OperA, NegA); + OperB = GetAluIneg(OperB, NegB); + + ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Add, OperA, OperB); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + + private static void EmitIadd3(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + int Mode = (int)((OpCode >> 37) & 3); + + bool Neg1 = ((OpCode >> 51) & 1) != 0; + bool Neg2 = ((OpCode >> 50) & 1) != 0; + bool Neg3 = ((OpCode >> 49) & 1) != 0; + + int Height1 = (int)((OpCode >> 35) & 3); + int Height2 = (int)((OpCode >> 33) & 3); + int Height3 = (int)((OpCode >> 31) & 3); + + ShaderIrNode OperB; + + switch (Oper) + { + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); 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(GetOperGpr8(OpCode), Height1), Neg1); + ShaderIrNode Src2 = GetAluIneg(ApplyHeight(OperB, Height2), Neg2); + ShaderIrNode Src3 = GetAluIneg(ApplyHeight(GetOperGpr39(OpCode), 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(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), new ShaderIrOp(ShaderIrInst.Add, Sum, Src3)), OpCode)); + } + private static void EmitIscadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { bool NegB = ((OpCode >> 48) & 1) != 0; @@ -821,6 +981,54 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(P0Node, Op), OpCode)); } + private static void EmitLop(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + int SubOp = (int)(OpCode >> 41) & 3; + + bool InvA = ((OpCode >> 39) & 1) != 0; + bool InvB = ((OpCode >> 40) & 1) != 0; + + 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(GetOperGpr8(OpCode), InvA); + ShaderIrNode OperB; + + switch (Oper) + { + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); 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(GetPredNode(new ShaderIrAsg(GetOperPred48(OpCode), Compare), OpCode)); + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); + } + private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { //TODO: Confirm SignAB/C, it is just a guess. diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs index a8ad5ec2e..1f1b158ef 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs @@ -156,6 +156,11 @@ namespace Ryujinx.Graphics.Gal.Shader return new ShaderIrOperPred((int)(OpCode >> 39) & 7); } + public static ShaderIrOperPred GetOperPred48(long OpCode) + { + return new ShaderIrOperPred((int)((OpCode >> 48) & 7)); + } + public static ShaderIrInst GetCmp(long OpCode) { switch ((int)(OpCode >> 49) & 7) diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs index dfcea905a..4c9e59cf0 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs @@ -113,6 +113,21 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode)); } + public static void Sel_C(ShaderIrBlock Block, long OpCode) + { + EmitSel(Block, OpCode, ShaderOper.CR); + } + + public static void Sel_I(ShaderIrBlock Block, long OpCode) + { + EmitSel(Block, OpCode, ShaderOper.Imm); + } + + public static void Sel_R(ShaderIrBlock Block, long OpCode) + { + EmitSel(Block, OpCode, ShaderOper.RR); + } + private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { bool NegA = ((OpCode >> 45) & 1) != 0; @@ -340,6 +355,28 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode)); } + private static void EmitSel(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + ShaderIrOperGpr Dst = GetOperGpr0 (OpCode); + ShaderIrNode Pred = GetOperPred39N(OpCode); + + ShaderIrNode ResultA = GetOperGpr8(OpCode); + ShaderIrNode ResultB; + + switch (Oper) + { + case ShaderOper.CR: ResultB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: ResultB = GetOperImm19_20(OpCode); break; + case ShaderOper.RR: ResultB = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + Block.AddNode(GetPredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultA), false), OpCode)); + + Block.AddNode(GetPredNode(new ShaderIrCond(Pred, new ShaderIrAsg(Dst, ResultB), true), OpCode)); + } + private static IntType GetIntType(long OpCode) { bool Signed = ((OpCode >> 13) & 1) != 0; diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index b4f51e508..1ac117851 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -64,6 +64,13 @@ namespace Ryujinx.Graphics.Gal.Shader 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); @@ -71,13 +78,19 @@ namespace Ryujinx.Graphics.Gal.Shader 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); @@ -87,6 +100,9 @@ namespace Ryujinx.Graphics.Gal.Shader 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); diff --git a/Ryujinx.HLE/Loaders/Executable.cs b/Ryujinx.HLE/Loaders/Executable.cs index 618ee241a..84f5ff390 100644 --- a/Ryujinx.HLE/Loaders/Executable.cs +++ b/Ryujinx.HLE/Loaders/Executable.cs @@ -2,6 +2,7 @@ using ChocolArm64.Memory; using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.OsHle; using System.Collections.Generic; +using System.IO; namespace Ryujinx.HLE.Loaders { @@ -15,6 +16,8 @@ namespace Ryujinx.HLE.Loaders public string Name { get; private set; } + public string FilePath { get; private set; } + private AMemory Memory; public long ImageBase { get; private set; } @@ -26,7 +29,12 @@ namespace Ryujinx.HLE.Loaders m_SymbolTable = new Dictionary(); - Name = Exe.Name; + FilePath = Exe.FilePath; + + if (FilePath != null) + { + Name = Path.GetFileNameWithoutExtension(FilePath.Replace(Homebrew.TemporaryNroSuffix, "")); + } this.Memory = Memory; this.ImageBase = ImageBase; diff --git a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs index 1e8e569a5..44bad6149 100644 --- a/Ryujinx.HLE/Loaders/Executables/IExecutable.cs +++ b/Ryujinx.HLE/Loaders/Executables/IExecutable.cs @@ -2,7 +2,7 @@ namespace Ryujinx.HLE.Loaders.Executables { public interface IExecutable { - string Name { get; } + string FilePath { get; } byte[] Text { get; } byte[] RO { get; } diff --git a/Ryujinx.HLE/Loaders/Executables/Nro.cs b/Ryujinx.HLE/Loaders/Executables/Nro.cs index 9e2b7e907..0b5068d7b 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nro.cs +++ b/Ryujinx.HLE/Loaders/Executables/Nro.cs @@ -4,7 +4,7 @@ namespace Ryujinx.HLE.Loaders.Executables { class Nro : IExecutable { - public string Name { get; private set; } + public string FilePath { get; private set; } public byte[] Text { get; private set; } public byte[] RO { get; private set; } @@ -16,9 +16,9 @@ namespace Ryujinx.HLE.Loaders.Executables public int DataOffset { get; private set; } public int BssSize { get; private set; } - public Nro(Stream Input, string Name) + public Nro(Stream Input, string FilePath) { - this.Name = Name; + this.FilePath = FilePath; BinaryReader Reader = new BinaryReader(Input); diff --git a/Ryujinx.HLE/Loaders/Executables/Nso.cs b/Ryujinx.HLE/Loaders/Executables/Nso.cs index a5e1a361e..fef9c4b85 100644 --- a/Ryujinx.HLE/Loaders/Executables/Nso.cs +++ b/Ryujinx.HLE/Loaders/Executables/Nso.cs @@ -6,7 +6,7 @@ namespace Ryujinx.HLE.Loaders.Executables { class Nso : IExecutable { - public string Name { get; private set; } + public string FilePath { get; private set; } public byte[] Text { get; private set; } public byte[] RO { get; private set; } @@ -29,9 +29,9 @@ namespace Ryujinx.HLE.Loaders.Executables HasDataHash = 1 << 5 } - public Nso(Stream Input, string Name) + public Nso(Stream Input, string FilePath) { - this.Name = Name; + this.FilePath = FilePath; BinaryReader Reader = new BinaryReader(Input); diff --git a/Ryujinx.HLE/OsHle/Homebrew.cs b/Ryujinx.HLE/OsHle/Homebrew.cs index 4266c8db4..778e52fe5 100644 --- a/Ryujinx.HLE/OsHle/Homebrew.cs +++ b/Ryujinx.HLE/OsHle/Homebrew.cs @@ -1,11 +1,14 @@ using ChocolArm64.Memory; +using System.Text; namespace Ryujinx.HLE.OsHle { static class Homebrew { + public const string TemporaryNroSuffix = ".ryu_tmp.nro"; + //http://switchbrew.org/index.php?title=Homebrew_ABI - public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle) + public static void WriteHbAbiData(AMemory Memory, long Position, int MainThreadHandle, string SwitchPath) { Memory.Manager.Map(Position, AMemoryMgr.PageSize, (int)MemoryType.Normal, AMemoryPerm.RW); @@ -15,6 +18,11 @@ namespace Ryujinx.HLE.OsHle //NextLoadPath WriteConfigEntry(Memory, ref Position, 2, 0, Position + 0x200, Position + 0x400); + // Argv + long ArgvPosition = Position + 0xC00; + WriteConfigEntry(Memory, ref Position, 5, 0, 0, ArgvPosition); + Memory.WriteBytes(ArgvPosition, Encoding.ASCII.GetBytes(SwitchPath + "\0")); + //AppletType WriteConfigEntry(Memory, ref Position, 7); diff --git a/Ryujinx.HLE/OsHle/Horizon.cs b/Ryujinx.HLE/OsHle/Horizon.cs index a5bf0616c..9d8a937ff 100644 --- a/Ryujinx.HLE/OsHle/Horizon.cs +++ b/Ryujinx.HLE/OsHle/Horizon.cs @@ -87,19 +87,36 @@ namespace Ryujinx.HLE.OsHle MainProcess.Run(); } - public void LoadProgram(string FileName) + public void LoadProgram(string FilePath) { - bool IsNro = Path.GetExtension(FileName).ToLower() == ".nro"; + bool IsNro = Path.GetExtension(FilePath).ToLower() == ".nro"; - string Name = Path.GetFileNameWithoutExtension(FileName); + string Name = Path.GetFileNameWithoutExtension(FilePath); + string SwitchFilePath = Ns.VFs.SystemPathToSwitchPath(FilePath); + + if (IsNro && (SwitchFilePath == null || !SwitchFilePath.StartsWith("sdmc:/"))) + { + // TODO: avoid copying the file if we are already inside a sdmc directory + string SwitchPath = $"sdmc:/switch/{Name}{Homebrew.TemporaryNroSuffix}"; + string TempPath = Ns.VFs.SwitchPathToSystemPath(SwitchPath); + + string SwitchDir = Path.GetDirectoryName(TempPath); + if (!Directory.Exists(SwitchDir)) + { + Directory.CreateDirectory(SwitchDir); + } + File.Copy(FilePath, TempPath, true); + + FilePath = TempPath; + } Process MainProcess = MakeProcess(); - using (FileStream Input = new FileStream(FileName, FileMode.Open)) + using (FileStream Input = new FileStream(FilePath, FileMode.Open)) { MainProcess.LoadProgram(IsNro - ? (IExecutable)new Nro(Input, Name) - : (IExecutable)new Nso(Input, Name)); + ? (IExecutable)new Nro(Input, FilePath) + : (IExecutable)new Nso(Input, FilePath)); } MainProcess.SetEmptyArgs(); diff --git a/Ryujinx.HLE/OsHle/Process.cs b/Ryujinx.HLE/OsHle/Process.cs index 53e357ab9..be27dcc28 100644 --- a/Ryujinx.HLE/OsHle/Process.cs +++ b/Ryujinx.HLE/OsHle/Process.cs @@ -13,6 +13,7 @@ using Ryujinx.HLE.OsHle.Services.Nv; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Text; namespace Ryujinx.HLE.OsHle @@ -155,7 +156,9 @@ namespace Ryujinx.HLE.OsHle { HbAbiDataPosition = AMemoryHelper.PageRoundUp(Executables[0].ImageEnd); - Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle); + string SwitchPath = Ns.VFs.SystemPathToSwitchPath(Executables[0].FilePath); + + Homebrew.WriteHbAbiData(Memory, HbAbiDataPosition, Handle, SwitchPath); MainThread.Thread.ThreadState.X0 = (ulong)HbAbiDataPosition; MainThread.Thread.ThreadState.X1 = ulong.MaxValue; @@ -400,6 +403,11 @@ namespace Ryujinx.HLE.OsHle { if (Disposing && !Disposed) { + if (NeedsHbAbi && Executables[0].FilePath.EndsWith(Homebrew.TemporaryNroSuffix)) + { + File.Delete(Executables[0].FilePath); + } + //If there is still some thread running, disposing the objects is not //safe as the thread may try to access those resources. Instead, we set //the flag to have the Process disposed when all threads finishes. diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 1946b187b..74c0564a9 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -81,8 +81,9 @@ namespace Ryujinx.HLE Gpu.Fifo.DispatchCalls(); } - internal virtual void OnFinish(EventArgs e) + public virtual void OnFinish(EventArgs e) { + Os.Dispose(); Finish?.Invoke(this, e); } diff --git a/Ryujinx.HLE/VirtualFileSystem.cs b/Ryujinx.HLE/VirtualFileSystem.cs index 8b71caa97..38df81f87 100644 --- a/Ryujinx.HLE/VirtualFileSystem.cs +++ b/Ryujinx.HLE/VirtualFileSystem.cs @@ -45,6 +45,35 @@ namespace Ryujinx.HLE public string GetGameSavesPath() => MakeDirAndGetFullPath(NandPath); + public string SwitchPathToSystemPath(string SwitchPath) + { + string[] Parts = SwitchPath.Split(":"); + if (Parts.Length != 2) + { + return null; + } + return GetFullPath(MakeDirAndGetFullPath(Parts[0]), Parts[1]); + } + + public string SystemPathToSwitchPath(string SystemPath) + { + string BaseSystemPath = GetBasePath() + "/"; + if (SystemPath.StartsWith(BaseSystemPath)) + { + string RawPath = SystemPath.Replace(BaseSystemPath, ""); + int FirstSeparatorOffset = RawPath.IndexOf('/'); + if (FirstSeparatorOffset == -1) + { + return $"{RawPath}:/"; + } + + string BasePath = RawPath.Substring(0, FirstSeparatorOffset); + string FileName = RawPath.Substring(FirstSeparatorOffset + 1); + return $"{BasePath}:/{FileName}"; + } + return null; + } + private string MakeDirAndGetFullPath(string Dir) { string FullPath = Path.Combine(GetBasePath(), Dir); diff --git a/Ryujinx/Ui/Program.cs b/Ryujinx/Ui/Program.cs index 5cacc6228..879b9c20b 100644 --- a/Ryujinx/Ui/Program.cs +++ b/Ryujinx/Ui/Program.cs @@ -68,6 +68,7 @@ namespace Ryujinx }; Screen.MainLoop(); + Ns.OnFinish(EventArgs.Empty); } Environment.Exit(0);