mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-10 11:38:41 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cdc8550ec | |||
| d6fccedab8 | |||
| fed7a6d062 | |||
| 50f78f3713 |
@@ -621,6 +621,8 @@ internal static class Gen5ShaderTranslator
|
|||||||
0x10 => "SSendmsg",
|
0x10 => "SSendmsg",
|
||||||
0x16 => "STtraceData",
|
0x16 => "STtraceData",
|
||||||
0x20 => "SInstPrefetch",
|
0x20 => "SInstPrefetch",
|
||||||
|
0x21 => "SClause",
|
||||||
|
0x23 => "SWaitcntDepctr",
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1136,6 +1136,52 @@ internal static partial class Gen5SpirvTranslator
|
|||||||
left,
|
left,
|
||||||
right);
|
right);
|
||||||
break;
|
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":
|
case "SAndB32":
|
||||||
result = BitwiseAnd(left, right);
|
result = BitwiseAnd(left, right);
|
||||||
Store(_scc, IsNotZero(result));
|
Store(_scc, IsNotZero(result));
|
||||||
|
|||||||
@@ -349,7 +349,32 @@ public static class KernelPthreadCompatExports
|
|||||||
ExportName = "pthread_cond_timedwait",
|
ExportName = "pthread_cond_timedwait",
|
||||||
Target = Generation.Gen4 | Generation.Gen5,
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
LibraryName = "libKernel")]
|
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(
|
[SysAbiExport(
|
||||||
Nid = "kDh-NfxgMtE",
|
Nid = "kDh-NfxgMtE",
|
||||||
@@ -1185,10 +1210,19 @@ public static class KernelPthreadCompatExports
|
|||||||
|
|
||||||
if (consumedPendingSignal)
|
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);
|
state.Waiters = Math.Max(0, state.Waiters - 1);
|
||||||
TracePthreadCond("wait-wake-pending", condAddress, mutexAddress, state, timed, waitResult);
|
TracePthreadCond("wait-wake-pending", condAddress, mutexAddress, state, timed, waitResult);
|
||||||
var pendingLockResult = PthreadMutexRelockForCondWait(ctx, mutexAddress, releasedRecursion);
|
Monitor.Exit(state.SyncRoot);
|
||||||
return pendingLockResult != (int)OrbisGen2Result.ORBIS_GEN2_OK ? pendingLockResult : waitResult;
|
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;
|
var scheduler = GuestThreadExecution.Scheduler;
|
||||||
|
|||||||
@@ -45,6 +45,59 @@ public static class VideoOutExports
|
|||||||
private static readonly object _stateGate = new();
|
private static readonly object _stateGate = new();
|
||||||
private static readonly object _frameDumpGate = new();
|
private static readonly object _frameDumpGate = new();
|
||||||
private static readonly Dictionary<int, VideoOutPortState> _ports = 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 readonly Dictionary<(int Handle, int BufferIndex, ulong Address), ulong> _lastFrameFingerprints = new();
|
||||||
private static int _nextHandle = 1;
|
private static int _nextHandle = 1;
|
||||||
private static int _frameDumpCount;
|
private static int _frameDumpCount;
|
||||||
@@ -177,6 +230,7 @@ public static class VideoOutExports
|
|||||||
{
|
{
|
||||||
Handle = handle,
|
Handle = handle,
|
||||||
};
|
};
|
||||||
|
EnsureVblankPumpStarted();
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user