Check if the Device is rendering before waiting on it (#86)

Fixes an issue where there were missed references and an ``OperationCancelled`` exception when exiting an application.

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/86
This commit is contained in:
Max 2026-05-12 02:38:09 +00:00 committed by sh0inx
parent f8167eb625
commit 89ea41ef84
2 changed files with 41 additions and 38 deletions

View file

@ -176,9 +176,7 @@ namespace Ryujinx.Graphics.Vulkan
} }
} }
} }
// This can somehow become -1.
// Logger.Info?.PrintMsg(LogClass.Gpu, $"_referenceCount: {_referenceCount}");
Debug.Assert(_referenceCount >= 0); Debug.Assert(_referenceCount >= 0);
} }

View file

@ -622,15 +622,15 @@ namespace Ryujinx.Ava.Systems
// If the GPU has no work and is cancelled, we need to handle that as well. // If the GPU has no work and is cancelled, we need to handle that as well.
WaitHandle.WaitAny(new[] { _gpuDoneEvent, _gpuCancellationTokenSource.Token.WaitHandle }); WaitHandle.WaitAny(new[] { _gpuDoneEvent, _gpuCancellationTokenSource.Token.WaitHandle });
_gpuCancellationTokenSource.Dispose();
// Waiting for work to be finished before we dispose.
if (_renderingStarted) if (_renderingStarted)
{ {
// Waiting for work to be finished before we dispose.
Device.Gpu.WaitUntilGpuReady(); Device.Gpu.WaitUntilGpuReady();
} }
_gpuDoneEvent.Dispose(); _gpuDoneEvent.Dispose();
_gpuCancellationTokenSource.Dispose();
DisposeGpu(); DisposeGpu();
AppExit?.Invoke(this, EventArgs.Empty); AppExit?.Invoke(this, EventArgs.Empty);
@ -1095,51 +1095,56 @@ namespace Ryujinx.Ava.Systems
Device.Gpu.Renderer.RunLoop(() => Device.Gpu.Renderer.RunLoop(() =>
{ {
Device.Gpu.SetGpuThread(); try
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
_renderer.Window.ChangeVSyncMode(Device.VSyncMode);
while (_isActive)
{ {
_ticks += _chrono.ElapsedTicks; Device.Gpu.SetGpuThread();
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
_chrono.Restart(); _renderer.Window.ChangeVSyncMode(Device.VSyncMode);
if (Device.WaitFifo()) while (_isActive)
{ {
Device.Statistics.RecordFifoStart(); _ticks += _chrono.ElapsedTicks;
Device.ProcessFrame();
Device.Statistics.RecordFifoEnd();
}
while (Device.ConsumeFrameAvailable()) _chrono.Restart();
{
if (!_renderingStarted) if (Device.WaitFifo())
{ {
_renderingStarted = true; Device.Statistics.RecordFifoStart();
_viewModel.SwitchToRenderer(false); Device.ProcessFrame();
InitStatus(); Device.Statistics.RecordFifoEnd();
} }
Device.PresentFrame(() => (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.SwapBuffers()); while (Device.ConsumeFrameAvailable())
} {
if (!_renderingStarted)
{
_renderingStarted = true;
_viewModel.SwitchToRenderer(false);
InitStatus();
}
if (_ticks >= _ticksPerFrame) Device.PresentFrame(() =>
{ (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.SwapBuffers());
UpdateStatus(); }
if (_ticks >= _ticksPerFrame)
{
UpdateStatus();
}
} }
} }
finally
// Make sure all commands in the run loop are fully executed before leaving the loop.
if (Device.Gpu.Renderer is ThreadedRenderer threaded)
{ {
Logger.Info?.PrintMsg(LogClass.Gpu, "Flushing threaded commands..."); // Make sure all commands in the run loop are fully executed before leaving the loop.
threaded.FlushThreadedCommands(); if (Device.Gpu.Renderer is ThreadedRenderer threaded)
Logger.Info?.PrintMsg(LogClass.Gpu, "Flushed!"); {
Logger.Info?.PrintMsg(LogClass.Gpu, "Flushing threaded commands...");
threaded.FlushThreadedCommands();
Logger.Info?.PrintMsg(LogClass.Gpu, "Flushed!");
}
_gpuDoneEvent.Set();
} }
_gpuDoneEvent.Set();
}); });
(RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true); (RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);