using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; namespace AcDream.App.Rendering.Wb { /// /// Resource types for GPU memory tracking. /// public enum GpuResourceType { Texture, Buffer, Shader, VAO, FBO, RBO, Other } /// /// Details about a GPU resource type. /// public record GpuResourceDetails(GpuResourceType Type, int Count, long Bytes); /// /// Details about a specific named buffer. /// public record NamedBufferDetails(string Name, long CapacityBytes, long UsedBytes); /// /// Tracks manual VRAM allocations for buffers and textures. /// public static class GpuMemoryTracker { private static long _allocatedBytes; private static readonly long[] _allocatedBytesByType = new long[Enum.GetValues().Length]; private static readonly int[] _resourceCountsByType = new int[Enum.GetValues().Length]; private static readonly ConcurrentDictionary _namedBuffers = new(); public static long AllocatedBytes => Interlocked.Read(ref _allocatedBytes); public static int VaoCount => _resourceCountsByType[(int)GpuResourceType.VAO]; public static int ShaderCount => _resourceCountsByType[(int)GpuResourceType.Shader]; public static int BufferCount => _resourceCountsByType[(int)GpuResourceType.Buffer]; public static int TextureCount => _resourceCountsByType[(int)GpuResourceType.Texture]; public static int FboCount => _resourceCountsByType[(int)GpuResourceType.FBO]; public static int RboCount => _resourceCountsByType[(int)GpuResourceType.RBO]; public static void TrackAllocation(long sizeInBytes, GpuResourceType type = GpuResourceType.Other) { Interlocked.Add(ref _allocatedBytes, sizeInBytes); Interlocked.Add(ref _allocatedBytesByType[(int)type], sizeInBytes); } public static void TrackDeallocation(long sizeInBytes, GpuResourceType type = GpuResourceType.Other) { Interlocked.Add(ref _allocatedBytes, -sizeInBytes); Interlocked.Add(ref _allocatedBytesByType[(int)type], -sizeInBytes); } public static void TrackResourceAllocation(GpuResourceType type) => Interlocked.Increment(ref _resourceCountsByType[(int)type]); public static void TrackResourceDeallocation(GpuResourceType type) => Interlocked.Decrement(ref _resourceCountsByType[(int)type]); public static void TrackNamedBuffer(string name, long capacityBytes, long usedBytes) { _namedBuffers[name] = new NamedBufferDetails(name, capacityBytes, usedBytes); } public static void UntrackNamedBuffer(string name) { _namedBuffers.TryRemove(name, out _); } public static IEnumerable GetNamedBufferDetails() => _namedBuffers.Values.OrderBy(b => b.Name); public static IEnumerable GetDetails() { var types = Enum.GetValues(); foreach (var type in types) { yield return new GpuResourceDetails( type, _resourceCountsByType[(int)type], Interlocked.Read(ref _allocatedBytesByType[(int)type]) ); } } } }