Add SvcSetThreadActivity, tweak SignalProcessWideKey, add fmul32i shader instructions and other small fixes

This commit is contained in:
gdkchan 2018-04-19 16:18:30 -03:00
parent 33ae6e544b
commit 03002f6537
9 changed files with 139 additions and 24 deletions

View File

@ -54,6 +54,14 @@ namespace ChocolArm64
return true; return true;
} }
public void StopExecution() => ThreadState.Running = false; public void StopExecution()
{
ThreadState.Running = false;
}
public bool IsCurrentThread()
{
return Thread.CurrentThread == Work;
}
} }
} }

View File

@ -15,11 +15,15 @@ namespace Ryujinx.Core.OsHle.Handles
public AutoResetEvent WaitEvent { get; private set; } public AutoResetEvent WaitEvent { get; private set; }
public bool Active { get; set; }
public SchedulerThread(KThread Thread) public SchedulerThread(KThread Thread)
{ {
this.Thread = Thread; this.Thread = Thread;
WaitEvent = new AutoResetEvent(false); WaitEvent = new AutoResetEvent(false);
Active = true;
} }
public void Dispose() public void Dispose()
@ -97,10 +101,13 @@ namespace Ryujinx.Core.OsHle.Handles
} }
public bool Remove(SchedulerThread SchedThread) public bool Remove(SchedulerThread SchedThread)
{
lock (Threads)
{ {
return Threads.Remove(SchedThread); return Threads.Remove(SchedThread);
} }
} }
}
private ConcurrentDictionary<KThread, SchedulerThread> AllThreads; private ConcurrentDictionary<KThread, SchedulerThread> AllThreads;
@ -180,6 +187,55 @@ namespace Ryujinx.Core.OsHle.Handles
} }
} }
public void SetThreadActivity(KThread Thread, bool Active)
{
if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
{
throw new InvalidOperationException();
}
lock (SchedLock)
{
bool OldState = SchedThread.Active;
SchedThread.Active = Active;
if (!OldState && Active)
{
if (ActiveProcessors.Add(Thread.ProcessorId))
{
RunThread(SchedThread);
}
else
{
WaitingToRun[Thread.ProcessorId].Push(SchedThread);
PrintDbgThreadInfo(Thread, "entering wait state...");
}
}
else if (OldState && !Active)
{
if (Thread.Thread.IsCurrentThread())
{
Suspend(Thread.ProcessorId);
PrintDbgThreadInfo(Thread, "entering inactive wait state...");
}
else
{
WaitingToRun[Thread.ProcessorId].Remove(SchedThread);
}
}
}
if (!Active && Thread.Thread.IsCurrentThread())
{
SchedThread.WaitEvent.WaitOne();
PrintDbgThreadInfo(Thread, "resuming execution...");
}
}
public void Suspend(int ProcessorId) public void Suspend(int ProcessorId)
{ {
lock (SchedLock) lock (SchedLock)
@ -222,9 +278,7 @@ namespace Ryujinx.Core.OsHle.Handles
public void Resume(KThread Thread) public void Resume(KThread Thread)
{ {
SchedulerThread SchedThread; if (!AllThreads.TryGetValue(Thread, out SchedulerThread SchedThread))
if (!AllThreads.TryGetValue(Thread, out SchedThread))
{ {
throw new InvalidOperationException(); throw new InvalidOperationException();
} }
@ -236,6 +290,8 @@ namespace Ryujinx.Core.OsHle.Handles
{ {
KThread Thread = SchedThread.Thread; KThread Thread = SchedThread.Thread;
if (SchedThread.Active)
{
lock (SchedLock) lock (SchedLock)
{ {
if (ActiveProcessors.Add(Thread.ProcessorId)) if (ActiveProcessors.Add(Thread.ProcessorId))
@ -245,9 +301,14 @@ namespace Ryujinx.Core.OsHle.Handles
return; return;
} }
PrintDbgThreadInfo(Thread, "entering wait state...");
WaitingToRun[Thread.ProcessorId].Push(SchedThread); WaitingToRun[Thread.ProcessorId].Push(SchedThread);
PrintDbgThreadInfo(Thread, "entering wait state...");
}
}
else
{
PrintDbgThreadInfo(Thread, "entering inactive wait state...");
} }
SchedThread.WaitEvent.WaitOne(); SchedThread.WaitEvent.WaitOne();

View File

@ -57,7 +57,7 @@ namespace Ryujinx.Core.OsHle.Kernel
Count = Process.Memory.ReadInt32(CondVarAddress); Count = Process.Memory.ReadInt32(CondVarAddress);
if (Count > 0) if (Result && Count > 0)
{ {
Process.Memory.WriteInt32(CondVarAddress, Count - 1); Process.Memory.WriteInt32(CondVarAddress, Count - 1);
} }
@ -73,10 +73,10 @@ namespace Ryujinx.Core.OsHle.Kernel
{ {
if (Count < 0) if (Count < 0)
{ {
Process.Memory.WriteInt32(CondVarAddress, WaitingThreads.Count);
foreach ((_, AutoResetEvent WaitEvent) in WaitingThreads) foreach ((_, AutoResetEvent WaitEvent) in WaitingThreads)
{ {
IncrementCondVarValue();
WaitEvent.Set(); WaitEvent.Set();
} }
@ -84,8 +84,6 @@ namespace Ryujinx.Core.OsHle.Kernel
} }
else else
{ {
Process.Memory.WriteInt32(CondVarAddress, Count);
while (WaitingThreads.Count > 0 && Count-- > 0) while (WaitingThreads.Count > 0 && Count-- > 0)
{ {
int HighestPriority = WaitingThreads[0].Thread.Priority; int HighestPriority = WaitingThreads[0].Thread.Priority;
@ -101,6 +99,8 @@ namespace Ryujinx.Core.OsHle.Kernel
} }
} }
IncrementCondVarValue();
WaitingThreads[HighestPrioIndex].WaitEvent.Set(); WaitingThreads[HighestPrioIndex].WaitEvent.Set();
WaitingThreads.RemoveAt(HighestPrioIndex); WaitingThreads.RemoveAt(HighestPrioIndex);
@ -111,6 +111,17 @@ namespace Ryujinx.Core.OsHle.Kernel
Process.Scheduler.Yield(Thread); Process.Scheduler.Yield(Thread);
} }
private void IncrementCondVarValue()
{
AcquireCondVarValue();
int Count = Process.Memory.ReadInt32(CondVarAddress);
Process.Memory.WriteInt32(CondVarAddress, Count + 1);
ReleaseCondVarValue();
}
private void AcquireCondVarValue() private void AcquireCondVarValue()
{ {
if (!OwnsCondVarValue) if (!OwnsCondVarValue)

View File

@ -63,7 +63,8 @@ namespace Ryujinx.Core.OsHle.Kernel
{ 0x25, SvcGetThreadId }, { 0x25, SvcGetThreadId },
{ 0x26, SvcBreak }, { 0x26, SvcBreak },
{ 0x27, SvcOutputDebugString }, { 0x27, SvcOutputDebugString },
{ 0x29, SvcGetInfo } { 0x29, SvcGetInfo },
{ 0x32, SvcSetThreadActivity }
}; };
this.Ns = Ns; this.Ns = Ns;

View File

@ -147,7 +147,28 @@ namespace Ryujinx.Core.OsHle.Kernel
} }
else else
{ {
Logging.Warn(LogClass.KernelSvc, $"Tried to GetThreadId on invalid thread handle 0x{Handle:x8}!"); Logging.Warn(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
}
}
private void SvcSetThreadActivity(AThreadState ThreadState)
{
int Handle = (int)ThreadState.X0;
bool Active = (int)ThreadState.X1 != 0;
KThread CurrThread = Process.HandleTable.GetData<KThread>(Handle);
if (CurrThread != null)
{
Process.Scheduler.SetThreadActivity(CurrThread, Active);
ThreadState.X0 = 0;
}
else
{
Logging.Warn(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle); ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
} }

View File

@ -193,7 +193,7 @@ namespace Ryujinx.Graphics.Gal.Shader
} }
else if (DeclInfo.Name == GlslDecl.FragmentOutputName) else if (DeclInfo.Name == GlslDecl.FragmentOutputName)
{ {
Name = "layout (location = 0) out " + GetDecl(DeclInfo) + ";"; Name = "layout (location = 0) out " + GetDecl(DeclInfo) + ";" + Environment.NewLine;
} }
else else
{ {

View File

@ -41,6 +41,16 @@ namespace Ryujinx.Graphics.Gal.Shader
EmitAluFfma(Block, OpCode, ShaderOper.RR); EmitAluFfma(Block, OpCode, ShaderOper.RR);
} }
public static void Fmul32i(ShaderIrBlock Block, long OpCode)
{
ShaderIrNode OperA = GetOperGpr8 (OpCode);
ShaderIrNode OperB = GetOperImmf32_20(OpCode);
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
}
public static void Fmul_C(ShaderIrBlock Block, long OpCode) public static void Fmul_C(ShaderIrBlock Block, long OpCode)
{ {
EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fmul); EmitAluBinaryF(Block, OpCode, ShaderOper.CR, ShaderIrInst.Fmul);
@ -212,7 +222,6 @@ namespace Ryujinx.Graphics.Gal.Shader
bool Aa = ((OpCode >> 46) & 1) != 0; bool Aa = ((OpCode >> 46) & 1) != 0;
bool Na = ((OpCode >> 48) & 1) != 0; bool Na = ((OpCode >> 48) & 1) != 0;
bool Ab = ((OpCode >> 49) & 1) != 0; bool Ab = ((OpCode >> 49) & 1) != 0;
bool Ad = ((OpCode >> 50) & 1) != 0;
ShaderIrNode OperA = GetOperGpr8(OpCode), OperB; ShaderIrNode OperA = GetOperGpr8(OpCode), OperB;
@ -234,8 +243,6 @@ namespace Ryujinx.Graphics.Gal.Shader
ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB); ShaderIrNode Op = new ShaderIrOp(Inst, OperA, OperB);
Op = GetAluAbs(Op, Ad);
Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
} }

View File

@ -70,6 +70,11 @@ namespace Ryujinx.Graphics.Gal.Shader
return new ShaderIrOperImm((int)(OpCode >> 20)); return new ShaderIrOperImm((int)(OpCode >> 20));
} }
public static ShaderIrOperImmf GetOperImmf32_20(long OpCode)
{
return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(OpCode >> 20)));
}
public static ShaderIrOperImm GetOperImm19_20(long OpCode) public static ShaderIrOperImm GetOperImm19_20(long OpCode)
{ {
int Value = (int)(OpCode >> 20) & 0x7ffff; int Value = (int)(OpCode >> 20) & 0x7ffff;

View File

@ -27,6 +27,7 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("001100101xxxxx", ShaderDecode.Ffma_I); Set("001100101xxxxx", ShaderDecode.Ffma_I);
Set("010100011xxxxx", ShaderDecode.Ffma_RC); Set("010100011xxxxx", ShaderDecode.Ffma_RC);
Set("010110011xxxxx", ShaderDecode.Ffma_RR); Set("010110011xxxxx", ShaderDecode.Ffma_RR);
Set("00011110xxxxxx", ShaderDecode.Fmul32i);
Set("0100110001101x", ShaderDecode.Fmul_C); Set("0100110001101x", ShaderDecode.Fmul_C);
Set("0011100x01101x", ShaderDecode.Fmul_I); Set("0011100x01101x", ShaderDecode.Fmul_I);
Set("0101110001101x", ShaderDecode.Fmul_R); Set("0101110001101x", ShaderDecode.Fmul_R);