forked from MoonsideGames/MoonWorks
Atomically call graphics resource destroy function
parent
528fb7ac7c
commit
450b08cbd8
|
@ -235,8 +235,6 @@ namespace MoonWorks
|
||||||
|
|
||||||
Draw(alpha);
|
Draw(alpha);
|
||||||
accumulatedDrawTime -= FramerateCapTimeSpan;
|
accumulatedDrawTime -= FramerateCapTimeSpan;
|
||||||
|
|
||||||
GraphicsDevice.FlushEmergencyDisposalQueue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -355,21 +355,6 @@ namespace MoonWorks.Graphics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConcurrentQueue<GraphicsResourceDisposalHandle> emergencyDisposalQueue = new ConcurrentQueue<GraphicsResourceDisposalHandle>();
|
|
||||||
|
|
||||||
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)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
|
@ -387,11 +372,9 @@ namespace MoonWorks.Graphics
|
||||||
}
|
}
|
||||||
resources.Clear();
|
resources.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Refresh.Refresh_DestroyDevice(Handle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FlushEmergencyDisposalQueue();
|
Refresh.Refresh_DestroyDevice(Handle);
|
||||||
|
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
namespace MoonWorks.Graphics
|
||||||
{
|
{
|
||||||
|
// TODO: give this a Name property for debugging use
|
||||||
public abstract class GraphicsResource : IDisposable
|
public abstract class GraphicsResource : IDisposable
|
||||||
{
|
{
|
||||||
public GraphicsDevice Device { get; }
|
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; }
|
public bool IsDisposed { get; private set; }
|
||||||
protected abstract Action<IntPtr, IntPtr> QueueDestroyFunction { get; }
|
protected abstract Action<IntPtr, IntPtr> QueueDestroyFunction { get; }
|
||||||
|
|
||||||
private GCHandle SelfReference;
|
private GCHandle SelfReference;
|
||||||
|
|
||||||
protected GraphicsResource(GraphicsDevice device)
|
protected GraphicsResource(GraphicsDevice device)
|
||||||
{
|
{
|
||||||
Device = device;
|
Device = device;
|
||||||
|
@ -21,26 +23,21 @@ namespace MoonWorks.Graphics
|
||||||
Device.AddResourceReference(SelfReference);
|
Device.AddResourceReference(SelfReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GraphicsResourceDisposalHandle CreateDisposalHandle()
|
|
||||||
{
|
|
||||||
return new GraphicsResourceDisposalHandle
|
|
||||||
{
|
|
||||||
QueueDestroyAction = QueueDestroyFunction,
|
|
||||||
ResourceHandle = Handle
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void Dispose(bool disposing)
|
protected void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
if (Handle != IntPtr.Zero)
|
if (disposing)
|
||||||
{
|
{
|
||||||
QueueDestroyFunction(Device.Handle, Handle);
|
|
||||||
Device.RemoveResourceReference(SelfReference);
|
Device.RemoveResourceReference(SelfReference);
|
||||||
SelfReference.Free();
|
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;
|
IsDisposed = true;
|
||||||
|
@ -50,20 +47,12 @@ namespace MoonWorks.Graphics
|
||||||
~GraphicsResource()
|
~GraphicsResource()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// If the graphics device associated with this resource was already disposed, we assume
|
// If you see this log message, you leaked a graphics resource without disposing it!
|
||||||
// that your game is in the middle of shutting down.
|
// We'll try to clean it up for you but you really should fix this.
|
||||||
if (!IsDisposed && Device != null && !Device.IsDisposed)
|
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!
|
|
||||||
// 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.");
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// While we only log in debug builds, in both debug and release builds we want to free
|
Dispose(false);
|
||||||
// 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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
@ -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<IntPtr, IntPtr> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue