Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
9d987f24a0
14 changed files with 358 additions and 20 deletions
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<long, string>();
|
||||
|
||||
Name = Exe.Name;
|
||||
FilePath = Exe.FilePath;
|
||||
|
||||
if (FilePath != null)
|
||||
{
|
||||
Name = Path.GetFileNameWithoutExtension(FilePath.Replace(Homebrew.TemporaryNroSuffix, ""));
|
||||
}
|
||||
|
||||
this.Memory = Memory;
|
||||
this.ImageBase = ImageBase;
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||
{
|
||||
public interface IExecutable
|
||||
{
|
||||
string Name { get; }
|
||||
string FilePath { get; }
|
||||
|
||||
byte[] Text { get; }
|
||||
byte[] RO { get; }
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace Ryujinx
|
|||
};
|
||||
|
||||
Screen.MainLoop();
|
||||
Ns.OnFinish(EventArgs.Empty);
|
||||
}
|
||||
|
||||
Environment.Exit(0);
|
||||
|
|
Loading…
Reference in a new issue