Major overhaul of render graph system for modularity and performance: - Split compilation and execution logic into dedicated classes (Compiler, Executor, NativePassBuilder, Barriers) - Overhauled barrier system: now uses CompiledBarrier with target state only, querying before state at execution - Resource size/alignment now queried from D3D12 device for accurate heap allocation - ResourceDesc now includes Type field and asserts correct union access - Centralized D3D12 interop logic in D3D12Utility extensions - Added RenderGraphHasher for structural graph hashing and cache invalidation - RenderGraph class simplified to orchestrate specialized components - ResourceAliasingManager now uses allocator for size queries - Compilation cache now stores compiled barriers, reducing memory usage - Improved comments, debug assertions, and removed redundant code Result: more maintainable, efficient, and robust render graph pipeline.
146 lines
4.1 KiB
C#
146 lines
4.1 KiB
C#
using Ghost.Core;
|
|
using Ghost.Graphics.Core;
|
|
using Ghost.Graphics.RHI;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
namespace Ghost.Graphics.RenderGraphModule;
|
|
|
|
/// <summary>
|
|
/// Represents cached compilation results for a render graph.
|
|
/// This avoids recompiling the graph when the structure hasn't changed.
|
|
/// </summary>
|
|
internal sealed class CachedCompilation
|
|
{
|
|
// Compiled pass indices (indices into the _passes list)
|
|
public readonly List<int> compiledPassIndices = new(64);
|
|
|
|
// Culling decisions for each pass
|
|
public readonly List<bool> passCulledFlags = new(64);
|
|
|
|
// Physical resource aliasing mappings (logical index -> physical index)
|
|
public readonly Dictionary<int, int> logicalToPhysical = new(128);
|
|
|
|
// Placed resource metadata
|
|
public readonly List<PlacedResourceData> placedResources = new(32);
|
|
|
|
// Compiled barriers (stores only target states, queries before state from ResourceDatabase)
|
|
public readonly List<CompiledBarrier> compiledBarriers = new(128);
|
|
|
|
// Real gpu resource
|
|
public readonly List<Handle<GPUResource>> backingResources = new(32);
|
|
|
|
// View state used for this compilation
|
|
public ViewState viewState;
|
|
|
|
public void Clear()
|
|
{
|
|
compiledPassIndices.Clear();
|
|
passCulledFlags.Clear();
|
|
logicalToPhysical.Clear();
|
|
placedResources.Clear();
|
|
compiledBarriers.Clear();
|
|
backingResources.Clear();
|
|
viewState = default;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Placed resource data for caching.
|
|
/// </summary>
|
|
internal struct PlacedResourceData
|
|
{
|
|
public int index;
|
|
public RenderGraphResourceType type;
|
|
public ulong heapOffset;
|
|
public ulong sizeInBytes;
|
|
public int firstUsePass;
|
|
public int lastUsePass;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Manages compilation caching for render graphs.
|
|
/// Stores compiled results and allows cache hits when graph structure is unchanged.
|
|
/// </summary>
|
|
internal sealed class RenderGraphCompilationCache
|
|
{
|
|
private readonly CachedCompilation _cached = new();
|
|
private ulong _cachedHash;
|
|
private bool _hasCachedData;
|
|
|
|
// Statistics
|
|
public int CacheHits { get; private set; }
|
|
public int CacheMisses { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Attempts to retrieve cached compilation results.
|
|
/// </summary>
|
|
public bool TryGetCached(ulong hash, [MaybeNullWhen(false)] out CachedCompilation result)
|
|
{
|
|
if (_hasCachedData && _cachedHash == hash)
|
|
{
|
|
result = _cached;
|
|
CacheHits++;
|
|
return true;
|
|
}
|
|
|
|
result = null;
|
|
CacheMisses++;
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stores compilation results in the cache.
|
|
/// </summary>
|
|
public void Store(ulong hash, CachedCompilation data)
|
|
{
|
|
_cachedHash = hash;
|
|
_hasCachedData = true;
|
|
|
|
// Deep copy the data
|
|
_cached.Clear();
|
|
|
|
_cached.compiledPassIndices.AddRange(data.compiledPassIndices);
|
|
_cached.passCulledFlags.AddRange(data.passCulledFlags);
|
|
|
|
foreach (var kvp in data.logicalToPhysical)
|
|
{
|
|
_cached.logicalToPhysical[kvp.Key] = kvp.Value;
|
|
}
|
|
|
|
_cached.placedResources.AddRange(data.placedResources);
|
|
_cached.compiledBarriers.AddRange(data.compiledBarriers);
|
|
|
|
_cached.backingResources.AddRange(data.backingResources);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invalidates the cache, forcing recompilation on next Compile().
|
|
/// </summary>
|
|
public void Invalidate()
|
|
{
|
|
_hasCachedData = false;
|
|
_cachedHash = 0;
|
|
_cached.Clear();
|
|
}
|
|
|
|
public void UpdateBackingResource(int logicalIndex, Handle<GPUResource> resource)
|
|
{
|
|
if (logicalIndex < 0 || logicalIndex >= _cached.backingResources.Count)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_cached.backingResources[logicalIndex] = resource;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets cache statistics for debugging.
|
|
/// </summary>
|
|
public (int hits, int misses, double hitRate) GetStatistics()
|
|
{
|
|
int total = CacheHits + CacheMisses;
|
|
double hitRate = total > 0 ? (double)CacheHits / total : 0.0;
|
|
return (CacheHits, CacheMisses, hitRate);
|
|
}
|
|
}
|