mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-01 07:29:43 +08:00
Fix guest shutdown when VideoOut window is closed (#184)
Propagate Silk window close to runtime teardown so audio and CPU workers stop instead of continuing after the presentation window is dismissed.
This commit is contained in:
@@ -213,6 +213,17 @@ public static class AudioOutExports
|
||||
: (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
public static void ShutdownAllPorts()
|
||||
{
|
||||
foreach (var handle in Ports.Keys)
|
||||
{
|
||||
if (Ports.TryRemove(handle, out var port))
|
||||
{
|
||||
port.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryGetFormat(
|
||||
int rawFormat,
|
||||
out int channels,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using SharpEmu.HLE;
|
||||
using SharpEmu.Libs.Audio;
|
||||
using SharpEmu.Libs.Kernel;
|
||||
using SharpEmu.Logging;
|
||||
using System.Buffers.Binary;
|
||||
@@ -52,6 +53,8 @@ public static class VideoOutExports
|
||||
private const int VblankWaitTimeoutMilliseconds = 100;
|
||||
private static Thread? _vblankPumpThread;
|
||||
private static int _vblankPumpStarted;
|
||||
private static volatile int _vblankPumpStopRequested;
|
||||
private static volatile int _presentationWindowCloseNotified;
|
||||
|
||||
private static readonly object _vblankEdgeGate = new();
|
||||
private static ulong _vblankEdgeSequence;
|
||||
@@ -80,7 +83,7 @@ public static class VideoOutExports
|
||||
var intervalTicks = Math.Max(1L, (long)(Stopwatch.Frequency / VblankHz));
|
||||
var nextEdge = Stopwatch.GetTimestamp() + intervalTicks;
|
||||
|
||||
while (true)
|
||||
while (_vblankPumpStopRequested == 0)
|
||||
{
|
||||
WaitUntilTimestamp(nextEdge);
|
||||
PumpVblanks();
|
||||
@@ -97,6 +100,59 @@ public static class VideoOutExports
|
||||
}
|
||||
}
|
||||
|
||||
public static void NotifyPresentationWindowClosed()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _presentationWindowCloseNotified, 1) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Error.WriteLine("[LOADER][INFO] VideoOut presentation window closed");
|
||||
RequestHostShutdown("videoout-window-closed");
|
||||
}
|
||||
|
||||
public static void NotifyHostInterrupt()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _presentationWindowCloseNotified, 1) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Console.Error.WriteLine("[LOADER][INFO] Host interrupt requested");
|
||||
RequestHostShutdown("host-interrupt");
|
||||
}
|
||||
|
||||
private static void RequestHostShutdown(string reason)
|
||||
{
|
||||
AudioOutExports.ShutdownAllPorts();
|
||||
StopVblankPump();
|
||||
HostSessionControl.RequestShutdown(reason);
|
||||
ScheduleProcessExitIfGuestDoesNotStop();
|
||||
}
|
||||
|
||||
private static void ScheduleProcessExitIfGuestDoesNotStop()
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(static _ =>
|
||||
{
|
||||
Thread.Sleep(2000);
|
||||
Environment.Exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
public static void StopVblankPump()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _vblankPumpStopRequested, 1) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var thread = _vblankPumpThread;
|
||||
if (thread is { IsAlive: true })
|
||||
{
|
||||
thread.Join(TimeSpan.FromSeconds(2));
|
||||
}
|
||||
}
|
||||
|
||||
private static void WaitUntilTimestamp(long deadlineTicks)
|
||||
{
|
||||
var spinThresholdTicks = Stopwatch.Frequency * 2L / 1000L;
|
||||
|
||||
@@ -1154,7 +1154,13 @@ internal static unsafe class VulkanVideoPresenter
|
||||
_window = Window.Create(options);
|
||||
_window.Load += Initialize;
|
||||
_window.Render += Render;
|
||||
_window.Closing += DisposeVulkan;
|
||||
_window.Closing += OnWindowClosing;
|
||||
}
|
||||
|
||||
private void OnWindowClosing()
|
||||
{
|
||||
VideoOutExports.NotifyPresentationWindowClosed();
|
||||
DisposeVulkan();
|
||||
}
|
||||
|
||||
public void Run() => _window.Run();
|
||||
|
||||
Reference in New Issue
Block a user