diff --git a/src/Game.cs b/src/Game.cs index 1a33a56..1b7286f 100644 --- a/src/Game.cs +++ b/src/Game.cs @@ -235,8 +235,6 @@ namespace MoonWorks Draw(alpha); accumulatedDrawTime -= FramerateCapTimeSpan; - - GraphicsDevice.FlushEmergencyDisposalQueue(); } } diff --git a/src/Graphics/GraphicsDevice.cs b/src/Graphics/GraphicsDevice.cs index 8255203..4fe5bca 100644 --- a/src/Graphics/GraphicsDevice.cs +++ b/src/Graphics/GraphicsDevice.cs @@ -355,21 +355,6 @@ namespace MoonWorks.Graphics } } - ConcurrentQueue emergencyDisposalQueue = new ConcurrentQueue(); - - internal void RegisterForEmergencyDisposal(GraphicsResourceDisposalHandle handle) - { - emergencyDisposalQueue.Enqueue(handle); - } - - internal void FlushEmergencyDisposalQueue() - { - while (emergencyDisposalQueue.TryDequeue(out var handle)) - { - handle.Dispose(this); - } - } - protected virtual void Dispose(bool disposing) { if (!IsDisposed) @@ -387,11 +372,9 @@ namespace MoonWorks.Graphics } resources.Clear(); } - - Refresh.Refresh_DestroyDevice(Handle); } - FlushEmergencyDisposalQueue(); + Refresh.Refresh_DestroyDevice(Handle); IsDisposed = true; } diff --git a/src/Graphics/GraphicsResource.cs b/src/Graphics/GraphicsResource.cs index e124e4b..7eeccf9 100644 --- a/src/Graphics/GraphicsResource.cs +++ b/src/Graphics/GraphicsResource.cs @@ -1,18 +1,20 @@ using System; using System.Runtime.InteropServices; +using System.Threading; namespace MoonWorks.Graphics { + // TODO: give this a Name property for debugging use public abstract class GraphicsResource : IDisposable { public GraphicsDevice Device { get; } - public IntPtr Handle { get; internal set; } + public IntPtr Handle { get => handle; internal set => handle = value; } + private nint handle; public bool IsDisposed { get; private set; } protected abstract Action QueueDestroyFunction { get; } private GCHandle SelfReference; - protected GraphicsResource(GraphicsDevice device) { Device = device; @@ -21,26 +23,21 @@ namespace MoonWorks.Graphics Device.AddResourceReference(SelfReference); } - private GraphicsResourceDisposalHandle CreateDisposalHandle() - { - return new GraphicsResourceDisposalHandle - { - QueueDestroyAction = QueueDestroyFunction, - ResourceHandle = Handle - }; - } - protected void Dispose(bool disposing) { if (!IsDisposed) { - if (Handle != IntPtr.Zero) + if (disposing) { - QueueDestroyFunction(Device.Handle, Handle); Device.RemoveResourceReference(SelfReference); SelfReference.Free(); + } - Handle = IntPtr.Zero; + // Atomically call destroy function in case this is called from the finalizer thread + var toDispose = Interlocked.Exchange(ref handle, IntPtr.Zero); + if (toDispose != IntPtr.Zero) + { + QueueDestroyFunction(Device.Handle, toDispose); } IsDisposed = true; @@ -50,20 +47,12 @@ namespace MoonWorks.Graphics ~GraphicsResource() { #if DEBUG - // If the graphics device associated with this resource was already disposed, we assume - // that your game is in the middle of shutting down. - if (!IsDisposed && Device != null && !Device.IsDisposed) - { - // If you see this log message, you leaked a graphics resource without disposing it! - // This means your game may eventually run out of native memory for mysterious reasons. - Logger.LogWarn($"A resource of type {GetType().Name} was not Disposed."); - } + // If you see this log message, you leaked a graphics resource without disposing it! + // We'll try to clean it up for you but you really should fix this. + Logger.LogWarn($"A resource of type {GetType().Name} was not Disposed."); #endif - // While we only log in debug builds, in both debug and release builds we want to free - // any native resources associated with this object at the earliest opportunity. - // This will at least prevent you from running out of memory rapidly. - Device.RegisterForEmergencyDisposal(CreateDisposalHandle()); + Dispose(false); } public void Dispose() diff --git a/src/Graphics/GraphicsResourceDisposalHandle.cs b/src/Graphics/GraphicsResourceDisposalHandle.cs deleted file mode 100644 index c6c2837..0000000 --- a/src/Graphics/GraphicsResourceDisposalHandle.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace MoonWorks.Graphics -{ - // This allows us to defer native disposal calls from the finalizer thread. - internal struct GraphicsResourceDisposalHandle - { - internal Action QueueDestroyAction; - internal IntPtr ResourceHandle; - - public void Dispose(GraphicsDevice device) - { - if (device == null) - { - throw new ArgumentNullException(nameof(device)); - } - - if (QueueDestroyAction == null) - { - return; - } - - QueueDestroyAction(device.Handle, ResourceHandle); - } - } -}