forked from MoonsideGames/MoonWorks
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)
|
||||
{
|
||||
System.Console.WriteLine("Failed to initialize SDL!");
|
||||
Logger.LogError("Failed to initialize SDL!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -235,6 +235,8 @@ namespace MoonWorks
|
|||
|
||||
Draw(alpha);
|
||||
accumulatedDrawTime -= FramerateCapTimeSpan;
|
||||
|
||||
GraphicsDevice.FlushEmergencyDisposalQueue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,14 +340,14 @@ namespace MoonWorks
|
|||
var index = evt.cdevice.which;
|
||||
if (SDL.SDL_IsGameController(index) == SDL.SDL_bool.SDL_TRUE)
|
||||
{
|
||||
System.Console.WriteLine($"New controller detected!");
|
||||
Logger.LogInfo("New controller detected!");
|
||||
Inputs.AddGamepad(index);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleControllerRemoved(SDL.SDL_Event evt)
|
||||
{
|
||||
System.Console.WriteLine($"Controller removal detected!");
|
||||
Logger.LogInfo("Controller removal detected!");
|
||||
Inputs.RemoveGamepad(evt.cdevice.which);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace MoonWorks.Graphics
|
||||
{
|
||||
internal class FencePool
|
||||
{
|
||||
private GraphicsDevice GraphicsDevice;
|
||||
private Queue<Fence> Fences = new Queue<Fence>();
|
||||
private ConcurrentQueue<Fence> Fences = new ConcurrentQueue<Fence>();
|
||||
|
||||
public FencePool(GraphicsDevice graphicsDevice)
|
||||
{
|
||||
|
@ -14,12 +14,14 @@ namespace MoonWorks.Graphics
|
|||
|
||||
public Fence Obtain()
|
||||
{
|
||||
if (Fences.Count == 0)
|
||||
if (Fences.TryDequeue(out var fence))
|
||||
{
|
||||
return fence;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Fence(GraphicsDevice);
|
||||
}
|
||||
|
||||
return Fences.Dequeue();
|
||||
}
|
||||
|
||||
public void Return(Fence fence)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using RefreshCS;
|
||||
|
@ -87,6 +88,12 @@ namespace MoonWorks.Graphics
|
|||
/// <returns>True if successfully claimed.</returns>
|
||||
public bool ClaimWindow(Window window, PresentMode presentMode)
|
||||
{
|
||||
if (window.Claimed)
|
||||
{
|
||||
Logger.LogError("Window already claimed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
var success = Conversions.ByteToBool(
|
||||
Refresh.Refresh_ClaimWindow(
|
||||
Handle,
|
||||
|
@ -101,7 +108,7 @@ namespace MoonWorks.Graphics
|
|||
window.SwapchainFormat = GetSwapchainFormat(window);
|
||||
if (window.SwapchainTexture == null)
|
||||
{
|
||||
window.SwapchainTexture = new Texture(this, IntPtr.Zero, window.SwapchainFormat, 0, 0);
|
||||
window.SwapchainTexture = new Texture(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,11 +120,19 @@ namespace MoonWorks.Graphics
|
|||
/// </summary>
|
||||
public void UnclaimWindow(Window window)
|
||||
{
|
||||
Refresh.Refresh_UnclaimWindow(
|
||||
Handle,
|
||||
window.Handle
|
||||
);
|
||||
window.Claimed = false;
|
||||
if (window.Claimed)
|
||||
{
|
||||
Refresh.Refresh_UnclaimWindow(
|
||||
Handle,
|
||||
window.Handle
|
||||
);
|
||||
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>
|
||||
|
@ -129,6 +144,7 @@ namespace MoonWorks.Graphics
|
|||
{
|
||||
if (!window.Claimed)
|
||||
{
|
||||
Logger.LogError("Cannot set present mode on unclaimed window!");
|
||||
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)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
|
@ -359,6 +390,8 @@ namespace MoonWorks.Graphics
|
|||
Refresh.Refresh_DestroyDevice(Handle);
|
||||
}
|
||||
|
||||
FlushEmergencyDisposalQueue();
|
||||
|
||||
IsDisposed = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,23 +16,31 @@ namespace MoonWorks.Graphics
|
|||
{
|
||||
Device = device;
|
||||
|
||||
if (trackResource)
|
||||
weakReference = new WeakReference<GraphicsResource>(this);
|
||||
Device.AddResourceReference(weakReference);
|
||||
}
|
||||
|
||||
internal GraphicsResourceDisposalHandle CreateDisposalHandle()
|
||||
{
|
||||
weakReference = new WeakReference<GraphicsResource>(this);
|
||||
Device.AddResourceReference(weakReference);
|
||||
}
|
||||
return new GraphicsResourceDisposalHandle
|
||||
{
|
||||
QueueDestroyAction = QueueDestroyFunction,
|
||||
ResourceHandle = Handle
|
||||
};
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
{
|
||||
if (weakReference != null)
|
||||
if (Handle != IntPtr.Zero)
|
||||
{
|
||||
QueueDestroyFunction(Device.Handle, Handle);
|
||||
Device.RemoveResourceReference(weakReference);
|
||||
weakReference.SetTarget(null);
|
||||
|
||||
weakReference = null;
|
||||
Handle = IntPtr.Zero;
|
||||
}
|
||||
|
||||
IsDisposed = true;
|
||||
|
@ -41,8 +49,19 @@ namespace MoonWorks.Graphics
|
|||
|
||||
~GraphicsResource()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: false);
|
||||
#if DEBUG
|
||||
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()
|
||||
|
|
|
@ -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>
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
// Should not be tracked, because swapchain textures are managed by Vulkan.
|
||||
internal Texture(
|
||||
GraphicsDevice device,
|
||||
IntPtr handle,
|
||||
TextureFormat format,
|
||||
uint width,
|
||||
uint height
|
||||
) : base(device, false)
|
||||
GraphicsDevice device
|
||||
) : base(device)
|
||||
{
|
||||
Handle = handle;
|
||||
Handle = IntPtr.Zero;
|
||||
|
||||
Format = format;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Format = TextureFormat.R8G8B8A8;
|
||||
Width = 0;
|
||||
Height = 0;
|
||||
Depth = 1;
|
||||
IsCube = false;
|
||||
LevelCount = 1;
|
||||
|
|
|
@ -119,19 +119,19 @@ namespace MoonWorks.Input
|
|||
var openResult = SDL.SDL_GameControllerOpen(index);
|
||||
if (openResult == 0)
|
||||
{
|
||||
System.Console.WriteLine($"Error opening gamepad!");
|
||||
System.Console.WriteLine(SDL.SDL_GetError());
|
||||
Logger.LogError("Error opening gamepad!");
|
||||
Logger.LogError(SDL.SDL_GetError());
|
||||
}
|
||||
else
|
||||
{
|
||||
Gamepads[slot].Register(openResult);
|
||||
System.Console.WriteLine($"Gamepad added to slot {slot}!");
|
||||
Logger.LogInfo($"Gamepad added to slot {slot}!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
System.Console.WriteLine("Too many gamepads already!");
|
||||
Logger.LogInfo("Too many gamepads already!");
|
||||
}
|
||||
|
||||
internal void RemoveGamepad(int joystickInstanceID)
|
||||
|
@ -142,7 +142,7 @@ namespace MoonWorks.Input
|
|||
{
|
||||
SDL.SDL_GameControllerClose(Gamepads[slot].Handle);
|
||||
Gamepads[slot].Unregister();
|
||||
System.Console.WriteLine($"Removing gamepad from slot {slot}!");
|
||||
Logger.LogInfo($"Removing gamepad from slot {slot}!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ namespace MoonWorks
|
|||
{
|
||||
public static class Logger
|
||||
{
|
||||
public static Action<string> LogInfo;
|
||||
public static Action<string> LogWarn;
|
||||
public static Action<string> LogError;
|
||||
public static Action<string> LogInfo = LogInfoDefault;
|
||||
public static Action<string> LogWarn = LogWarnDefault;
|
||||
public static Action<string> LogError = LogErrorDefault;
|
||||
|
||||
private static RefreshCS.Refresh.Refresh_LogFunc LogInfoFunc = RefreshLogInfo;
|
||||
private static RefreshCS.Refresh.Refresh_LogFunc LogWarnFunc = RefreshLogWarn;
|
||||
|
@ -15,19 +15,6 @@ namespace MoonWorks
|
|||
|
||||
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(
|
||||
LogInfoFunc,
|
||||
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)
|
||||
{
|
||||
LogInfo(UTF8_ToManaged(msg));
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace MoonWorks
|
|||
public ScreenMode ScreenMode { get; private set; }
|
||||
public uint Width { 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 MoonWorks.Graphics.TextureFormat SwapchainFormat { get; internal set; }
|
||||
|
|
Loading…
Reference in New Issue