mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-25 20:28:48 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cdc8550ec | |||
| d6fccedab8 | |||
| fed7a6d062 | |||
| 50f78f3713 |
@@ -621,6 +621,8 @@ internal static class Gen5ShaderTranslator
|
||||
0x10 => "SSendmsg",
|
||||
0x16 => "STtraceData",
|
||||
0x20 => "SInstPrefetch",
|
||||
0x21 => "SClause",
|
||||
0x23 => "SWaitcntDepctr",
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
|
||||
@@ -1136,6 +1136,52 @@ internal static partial class Gen5SpirvTranslator
|
||||
left,
|
||||
right);
|
||||
break;
|
||||
case "SMulHiU32":
|
||||
{
|
||||
var wideLeft = _module.AddInstruction(
|
||||
SpirvOp.UConvert,
|
||||
_ulongType,
|
||||
left);
|
||||
var wideRight = _module.AddInstruction(
|
||||
SpirvOp.UConvert,
|
||||
_ulongType,
|
||||
right);
|
||||
var product = _module.AddInstruction(
|
||||
SpirvOp.IMul,
|
||||
_ulongType,
|
||||
wideLeft,
|
||||
wideRight);
|
||||
result = _module.AddInstruction(
|
||||
SpirvOp.UConvert,
|
||||
_uintType,
|
||||
ShiftRightLogical64(
|
||||
product,
|
||||
_module.Constant64(_ulongType, 32)));
|
||||
break;
|
||||
}
|
||||
case "SMulHiI32":
|
||||
{
|
||||
var wideLeft = _module.AddInstruction(
|
||||
SpirvOp.SConvert,
|
||||
_longType,
|
||||
Bitcast(_intType, left));
|
||||
var wideRight = _module.AddInstruction(
|
||||
SpirvOp.SConvert,
|
||||
_longType,
|
||||
Bitcast(_intType, right));
|
||||
var product = _module.AddInstruction(
|
||||
SpirvOp.IMul,
|
||||
_longType,
|
||||
wideLeft,
|
||||
wideRight);
|
||||
result = _module.AddInstruction(
|
||||
SpirvOp.UConvert,
|
||||
_uintType,
|
||||
ShiftRightLogical64(
|
||||
Bitcast(_ulongType, product),
|
||||
_module.Constant64(_ulongType, 32)));
|
||||
break;
|
||||
}
|
||||
case "SAndB32":
|
||||
result = BitwiseAnd(left, right);
|
||||
Store(_scc, IsNotZero(result));
|
||||
|
||||
@@ -349,7 +349,32 @@ public static class KernelPthreadCompatExports
|
||||
ExportName = "pthread_cond_timedwait",
|
||||
Target = Generation.Gen4 | Generation.Gen5,
|
||||
LibraryName = "libKernel")]
|
||||
public static int PosixPthreadCondTimedwait(CpuContext ctx) => PthreadCondTimedwait(ctx);
|
||||
public static int PosixPthreadCondTimedwait(CpuContext ctx)
|
||||
{
|
||||
// POSIX passes `const struct timespec *abstime` (absolute deadline), not relative microseconds (#113).
|
||||
var abstimeAddress = ctx[CpuRegister.Rdx];
|
||||
if (abstimeAddress == 0)
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!ctx.TryReadUInt64(abstimeAddress, out var deadlineSeconds) ||
|
||||
!ctx.TryReadUInt64(abstimeAddress + 8, out var deadlineNanoseconds))
|
||||
{
|
||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
|
||||
}
|
||||
|
||||
var nowMicroseconds = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() * 1000L;
|
||||
var deadlineMicroseconds =
|
||||
deadlineSeconds >= long.MaxValue / 1_000_000UL
|
||||
? long.MaxValue
|
||||
: (long)(deadlineSeconds * 1_000_000UL + Math.Min(deadlineNanoseconds, 999_999_999UL) / 1000UL);
|
||||
var remainingMicroseconds = deadlineMicroseconds - nowMicroseconds;
|
||||
var timeoutUsec = remainingMicroseconds <= 0
|
||||
? 1u
|
||||
: (uint)Math.Min(remainingMicroseconds, uint.MaxValue);
|
||||
return PthreadCondWaitCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi], timed: true, timeoutUsec: timeoutUsec);
|
||||
}
|
||||
|
||||
[SysAbiExport(
|
||||
Nid = "kDh-NfxgMtE",
|
||||
@@ -1185,10 +1210,19 @@ public static class KernelPthreadCompatExports
|
||||
|
||||
if (consumedPendingSignal)
|
||||
{
|
||||
// Leave SyncRoot before relocking the mutex to avoid lock-order inversion with cond-signal (#113).
|
||||
state.Waiters = Math.Max(0, state.Waiters - 1);
|
||||
TracePthreadCond("wait-wake-pending", condAddress, mutexAddress, state, timed, waitResult);
|
||||
var pendingLockResult = PthreadMutexRelockForCondWait(ctx, mutexAddress, releasedRecursion);
|
||||
return pendingLockResult != (int)OrbisGen2Result.ORBIS_GEN2_OK ? pendingLockResult : waitResult;
|
||||
Monitor.Exit(state.SyncRoot);
|
||||
try
|
||||
{
|
||||
var pendingLockResult = PthreadMutexRelockForCondWait(ctx, mutexAddress, releasedRecursion);
|
||||
return pendingLockResult != (int)OrbisGen2Result.ORBIS_GEN2_OK ? pendingLockResult : waitResult;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Enter(state.SyncRoot);
|
||||
}
|
||||
}
|
||||
|
||||
var scheduler = GuestThreadExecution.Scheduler;
|
||||
|
||||
@@ -45,6 +45,59 @@ public static class VideoOutExports
|
||||
private static readonly object _stateGate = new();
|
||||
private static readonly object _frameDumpGate = new();
|
||||
private static readonly Dictionary<int, VideoOutPortState> _ports = new();
|
||||
|
||||
// Hardware raises vblank autonomously; UE blocks its frame loop on it.
|
||||
private static Timer? _vblankPumpTimer;
|
||||
private static int _vblankPumpActive;
|
||||
private const int VblankPumpIntervalMs = 16;
|
||||
|
||||
private static void EnsureVblankPumpStarted()
|
||||
{
|
||||
if (_vblankPumpTimer is not null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_vblankPumpTimer = new Timer(
|
||||
static _ => PumpVblanks(),
|
||||
null,
|
||||
VblankPumpIntervalMs,
|
||||
VblankPumpIntervalMs);
|
||||
}
|
||||
|
||||
private static void PumpVblanks()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _vblankPumpActive, 1) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
VideoOutPortState[] ports;
|
||||
lock (_stateGate)
|
||||
{
|
||||
if (_ports.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Signalling reaches WakeBlockedThreads -> Pump(), which serialises on one global
|
||||
// flag. Waking an unwatched queue would hold it 60x/sec and starve guest threads.
|
||||
ports = _ports.Values.Where(static port => port.VblankEvents.Count != 0).ToArray();
|
||||
}
|
||||
|
||||
foreach (var port in ports)
|
||||
{
|
||||
SignalVblank(port);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Volatile.Write(ref _vblankPumpActive, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<(int Handle, int BufferIndex, ulong Address), ulong> _lastFrameFingerprints = new();
|
||||
private static int _nextHandle = 1;
|
||||
private static int _frameDumpCount;
|
||||
@@ -177,6 +230,7 @@ public static class VideoOutExports
|
||||
{
|
||||
Handle = handle,
|
||||
};
|
||||
EnsureVblankPumpStarted();
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user