resource management and logging improvements
parent
1d27a9e4a4
commit
e616b0fa62
|
@ -70,7 +70,7 @@ namespace MoonWorks
|
||||||
|
|
||||||
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO | SDL.SDL_INIT_TIMER | SDL.SDL_INIT_GAMECONTROLLER) < 0)
|
if (SDL.SDL_Init(SDL.SDL_INIT_VIDEO | SDL.SDL_INIT_TIMER | SDL.SDL_INIT_GAMECONTROLLER) < 0)
|
||||||
{
|
{
|
||||||
System.Console.WriteLine("Failed to initialize SDL!");
|
Logger.LogError("Failed to initialize SDL!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,6 +235,8 @@ namespace MoonWorks
|
||||||
|
|
||||||
Draw(alpha);
|
Draw(alpha);
|
||||||
accumulatedDrawTime -= FramerateCapTimeSpan;
|
accumulatedDrawTime -= FramerateCapTimeSpan;
|
||||||
|
|
||||||
|
GraphicsDevice.FlushEmergencyDisposalQueue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,14 +340,14 @@ namespace MoonWorks
|
||||||
var index = evt.cdevice.which;
|
var index = evt.cdevice.which;
|
||||||
if (SDL.SDL_IsGameController(index) == SDL.SDL_bool.SDL_TRUE)
|
if (SDL.SDL_IsGameController(index) == SDL.SDL_bool.SDL_TRUE)
|
||||||
{
|
{
|
||||||
System.Console.WriteLine($"New controller detected!");
|
Logger.LogInfo("New controller detected!");
|
||||||
Inputs.AddGamepad(index);
|
Inputs.AddGamepad(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleControllerRemoved(SDL.SDL_Event evt)
|
private void HandleControllerRemoved(SDL.SDL_Event evt)
|
||||||
{
|
{
|
||||||
System.Console.WriteLine($"Controller removal detected!");
|
Logger.LogInfo("Controller removal detected!");
|
||||||
Inputs.RemoveGamepad(evt.cdevice.which);
|
Inputs.RemoveGamepad(evt.cdevice.which);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace MoonWorks.Graphics
|
namespace MoonWorks.Graphics
|
||||||
{
|
{
|
||||||
internal class FencePool
|
internal class FencePool
|
||||||
{
|
{
|
||||||
private GraphicsDevice GraphicsDevice;
|
private GraphicsDevice GraphicsDevice;
|
||||||
private Queue<Fence> Fences = new Queue<Fence>();
|
private ConcurrentQueue<Fence> Fences = new ConcurrentQueue<Fence>();
|
||||||
|
|
||||||
public FencePool(GraphicsDevice graphicsDevice)
|
public FencePool(GraphicsDevice graphicsDevice)
|
||||||
{
|
{
|
||||||
|
@ -14,12 +14,14 @@ namespace MoonWorks.Graphics
|
||||||
|
|
||||||
public Fence Obtain()
|
public Fence Obtain()
|
||||||
{
|
{
|
||||||
if (Fences.Count == 0)
|
if (Fences.TryDequeue(out var fence))
|
||||||
|
{
|
||||||
|
return fence;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return new Fence(GraphicsDevice);
|
return new Fence(GraphicsDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Fences.Dequeue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Return(Fence fence)
|
public void Return(Fence fence)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using RefreshCS;
|
using RefreshCS;
|
||||||
|
@ -87,6 +88,12 @@ namespace MoonWorks.Graphics
|
||||||
/// <returns>True if successfully claimed.</returns>
|
/// <returns>True if successfully claimed.</returns>
|
||||||
public bool ClaimWindow(Window window, PresentMode presentMode)
|
public bool ClaimWindow(Window window, PresentMode presentMode)
|
||||||
{
|
{
|
||||||
|
if (window.Claimed)
|
||||||
|
{
|
||||||
|
Logger.LogError("Window already claimed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var success = Conversions.ByteToBool(
|
var success = Conversions.ByteToBool(
|
||||||
Refresh.Refresh_ClaimWindow(
|
Refresh.Refresh_ClaimWindow(
|
||||||
Handle,
|
Handle,
|
||||||
|
@ -101,7 +108,7 @@ namespace MoonWorks.Graphics
|
||||||
window.SwapchainFormat = GetSwapchainFormat(window);
|
window.SwapchainFormat = GetSwapchainFormat(window);
|
||||||
if (window.SwapchainTexture == null)
|
if (window.SwapchainTexture == null)
|
||||||
{
|
{
|
||||||
window.SwapchainTexture = new Texture(this, IntPtr.Zero, window.SwapchainFormat, 0, 0);
|
window.SwapchainTexture = new Texture(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,12 +119,20 @@ namespace MoonWorks.Graphics
|
||||||
/// Unclaims a window, making it unavailable for presenting and freeing associated resources.
|
/// Unclaims a window, making it unavailable for presenting and freeing associated resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UnclaimWindow(Window window)
|
public void UnclaimWindow(Window window)
|
||||||
|
{
|
||||||
|
if (window.Claimed)
|
||||||
{
|
{
|
||||||
Refresh.Refresh_UnclaimWindow(
|
Refresh.Refresh_UnclaimWindow(
|
||||||
Handle,
|
Handle,
|
||||||
window.Handle
|
window.Handle
|
||||||
);
|
);
|
||||||
window.Claimed = false;
|
window.Claimed = false;
|
||||||
|
|
||||||
|
// The swapchain texture doesn't actually have a permanent texture reference, so we zero the handle before disposing.
|
||||||
|
window.SwapchainTexture.Handle = IntPtr.Zero;
|
||||||
|
window.SwapchainTexture.Dispose();
|
||||||
|
window.SwapchainTexture = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -129,6 +144,7 @@ namespace MoonWorks.Graphics
|
||||||
{
|
{
|
||||||
if (!window.Claimed)
|
if (!window.Claimed)
|
||||||
{
|
{
|
||||||
|
Logger.LogError("Cannot set present mode on unclaimed window!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,6 +354,21 @@ 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)
|
||||||
|
@ -359,6 +390,8 @@ namespace MoonWorks.Graphics
|
||||||
Refresh.Refresh_DestroyDevice(Handle);
|
Refresh.Refresh_DestroyDevice(Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlushEmergencyDisposalQueue();
|
||||||
|
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,23 +16,31 @@ namespace MoonWorks.Graphics
|
||||||
{
|
{
|
||||||
Device = device;
|
Device = device;
|
||||||
|
|
||||||
if (trackResource)
|
|
||||||
{
|
|
||||||
weakReference = new WeakReference<GraphicsResource>(this);
|
weakReference = new WeakReference<GraphicsResource>(this);
|
||||||
Device.AddResourceReference(weakReference);
|
Device.AddResourceReference(weakReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal GraphicsResourceDisposalHandle CreateDisposalHandle()
|
||||||
|
{
|
||||||
|
return new GraphicsResourceDisposalHandle
|
||||||
|
{
|
||||||
|
QueueDestroyAction = QueueDestroyFunction,
|
||||||
|
ResourceHandle = Handle
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
if (weakReference != null)
|
if (Handle != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
QueueDestroyFunction(Device.Handle, Handle);
|
QueueDestroyFunction(Device.Handle, Handle);
|
||||||
Device.RemoveResourceReference(weakReference);
|
Device.RemoveResourceReference(weakReference);
|
||||||
weakReference.SetTarget(null);
|
weakReference.SetTarget(null);
|
||||||
|
|
||||||
weakReference = null;
|
weakReference = null;
|
||||||
|
Handle = IntPtr.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
IsDisposed = true;
|
IsDisposed = true;
|
||||||
|
@ -41,8 +49,19 @@ namespace MoonWorks.Graphics
|
||||||
|
|
||||||
~GraphicsResource()
|
~GraphicsResource()
|
||||||
{
|
{
|
||||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
#if DEBUG
|
||||||
Dispose(disposing: false);
|
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.");
|
||||||
|
}
|
||||||
|
#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());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,9 +12,9 @@ namespace MoonWorks.Graphics
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Fence : GraphicsResource
|
public class Fence : GraphicsResource
|
||||||
{
|
{
|
||||||
protected override Action<nint, nint> QueueDestroyFunction => Release;
|
protected override Action<nint, nint> QueueDestroyFunction => Refresh.Refresh_ReleaseFence;
|
||||||
|
|
||||||
internal Fence(GraphicsDevice device) : base(device, true)
|
internal Fence(GraphicsDevice device) : base(device)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,14 +22,5 @@ namespace MoonWorks.Graphics
|
||||||
{
|
{
|
||||||
Handle = handle;
|
Handle = handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Release(nint deviceHandle, nint fenceHandle)
|
|
||||||
{
|
|
||||||
if (fenceHandle != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
// This will only be called if the client forgot to release a handle. Oh no!
|
|
||||||
Refresh.Refresh_ReleaseFence(deviceHandle, fenceHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,18 +303,14 @@ namespace MoonWorks.Graphics
|
||||||
// Used by AcquireSwapchainTexture.
|
// Used by AcquireSwapchainTexture.
|
||||||
// Should not be tracked, because swapchain textures are managed by Vulkan.
|
// Should not be tracked, because swapchain textures are managed by Vulkan.
|
||||||
internal Texture(
|
internal Texture(
|
||||||
GraphicsDevice device,
|
GraphicsDevice device
|
||||||
IntPtr handle,
|
) : base(device)
|
||||||
TextureFormat format,
|
|
||||||
uint width,
|
|
||||||
uint height
|
|
||||||
) : base(device, false)
|
|
||||||
{
|
{
|
||||||
Handle = handle;
|
Handle = IntPtr.Zero;
|
||||||
|
|
||||||
Format = format;
|
Format = TextureFormat.R8G8B8A8;
|
||||||
Width = width;
|
Width = 0;
|
||||||
Height = height;
|
Height = 0;
|
||||||
Depth = 1;
|
Depth = 1;
|
||||||
IsCube = false;
|
IsCube = false;
|
||||||
LevelCount = 1;
|
LevelCount = 1;
|
||||||
|
|
|
@ -119,19 +119,19 @@ namespace MoonWorks.Input
|
||||||
var openResult = SDL.SDL_GameControllerOpen(index);
|
var openResult = SDL.SDL_GameControllerOpen(index);
|
||||||
if (openResult == 0)
|
if (openResult == 0)
|
||||||
{
|
{
|
||||||
System.Console.WriteLine($"Error opening gamepad!");
|
Logger.LogError("Error opening gamepad!");
|
||||||
System.Console.WriteLine(SDL.SDL_GetError());
|
Logger.LogError(SDL.SDL_GetError());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Gamepads[slot].Register(openResult);
|
Gamepads[slot].Register(openResult);
|
||||||
System.Console.WriteLine($"Gamepad added to slot {slot}!");
|
Logger.LogInfo($"Gamepad added to slot {slot}!");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
System.Console.WriteLine("Too many gamepads already!");
|
Logger.LogInfo("Too many gamepads already!");
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RemoveGamepad(int joystickInstanceID)
|
internal void RemoveGamepad(int joystickInstanceID)
|
||||||
|
@ -142,7 +142,7 @@ namespace MoonWorks.Input
|
||||||
{
|
{
|
||||||
SDL.SDL_GameControllerClose(Gamepads[slot].Handle);
|
SDL.SDL_GameControllerClose(Gamepads[slot].Handle);
|
||||||
Gamepads[slot].Unregister();
|
Gamepads[slot].Unregister();
|
||||||
System.Console.WriteLine($"Removing gamepad from slot {slot}!");
|
Logger.LogInfo($"Removing gamepad from slot {slot}!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@ namespace MoonWorks
|
||||||
{
|
{
|
||||||
public static class Logger
|
public static class Logger
|
||||||
{
|
{
|
||||||
public static Action<string> LogInfo;
|
public static Action<string> LogInfo = LogInfoDefault;
|
||||||
public static Action<string> LogWarn;
|
public static Action<string> LogWarn = LogWarnDefault;
|
||||||
public static Action<string> LogError;
|
public static Action<string> LogError = LogErrorDefault;
|
||||||
|
|
||||||
private static RefreshCS.Refresh.Refresh_LogFunc LogInfoFunc = RefreshLogInfo;
|
private static RefreshCS.Refresh.Refresh_LogFunc LogInfoFunc = RefreshLogInfo;
|
||||||
private static RefreshCS.Refresh.Refresh_LogFunc LogWarnFunc = RefreshLogWarn;
|
private static RefreshCS.Refresh.Refresh_LogFunc LogWarnFunc = RefreshLogWarn;
|
||||||
|
@ -15,19 +15,6 @@ namespace MoonWorks
|
||||||
|
|
||||||
internal static void Initialize()
|
internal static void Initialize()
|
||||||
{
|
{
|
||||||
if (Logger.LogInfo == null)
|
|
||||||
{
|
|
||||||
Logger.LogInfo = Console.WriteLine;
|
|
||||||
}
|
|
||||||
if (Logger.LogWarn == null)
|
|
||||||
{
|
|
||||||
Logger.LogWarn = Console.WriteLine;
|
|
||||||
}
|
|
||||||
if (Logger.LogError == null)
|
|
||||||
{
|
|
||||||
Logger.LogError = Console.WriteLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
Refresh.Refresh_HookLogFunctions(
|
Refresh.Refresh_HookLogFunctions(
|
||||||
LogInfoFunc,
|
LogInfoFunc,
|
||||||
LogWarnFunc,
|
LogWarnFunc,
|
||||||
|
@ -35,6 +22,30 @@ namespace MoonWorks
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void LogInfoDefault(string str)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
|
Console.Write("INFO: ");
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.WriteLine(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LogWarnDefault(string str)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||||
|
Console.Write("WARN: ");
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.WriteLine(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LogErrorDefault(string str)
|
||||||
|
{
|
||||||
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
|
Console.Write("ERROR: ");
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.WriteLine(str);
|
||||||
|
}
|
||||||
|
|
||||||
private static void RefreshLogInfo(IntPtr msg)
|
private static void RefreshLogInfo(IntPtr msg)
|
||||||
{
|
{
|
||||||
LogInfo(UTF8_ToManaged(msg));
|
LogInfo(UTF8_ToManaged(msg));
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace MoonWorks
|
||||||
public ScreenMode ScreenMode { get; private set; }
|
public ScreenMode ScreenMode { get; private set; }
|
||||||
public uint Width { get; private set; }
|
public uint Width { get; private set; }
|
||||||
public uint Height { get; private set; }
|
public uint Height { get; private set; }
|
||||||
internal Texture SwapchainTexture { get; set; } = null;
|
internal Texture SwapchainTexture { get; set; }
|
||||||
|
|
||||||
public bool Claimed { get; internal set; }
|
public bool Claimed { get; internal set; }
|
||||||
public MoonWorks.Graphics.TextureFormat SwapchainFormat { get; internal set; }
|
public MoonWorks.Graphics.TextureFormat SwapchainFormat { get; internal set; }
|
||||||
|
|
Loading…
Reference in New Issue