Refactor RenderGraph barrier/state tracking system
Major overhaul of resource barrier and state tracking in RenderGraph: - Introduce ResourceBarrierData for explicit (layout, access, sync) tracking. - Separate aliasing and transition barriers; explicit aliasing support. - Remove BufferHint; infer buffer usage from BufferUsage flags. - Update TextureAccess/BufferAccess to include usage requirements. - Improve enums (BarrierSync, BarrierAccess, BarrierLayout) for D3D12 alignment. - Update D3D12CommandBuffer to use new barrier data and error handling. - Make D3D12DescriptorHeap a class; add ReleaseSampler to IResourceDatabase. - Reset resource pools and aliasing managers each frame. - Batch and flush barriers efficiently per pass. - Update HLSL mesh shader macros to [NumThreads]. - Remove obsolete code and improve documentation. This refactor improves correctness, extensibility, and prepares for advanced features.
This commit is contained in:
@@ -248,7 +248,15 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
break;
|
break;
|
||||||
case BarrierType.Buffer:
|
case BarrierType.Buffer:
|
||||||
{
|
{
|
||||||
var resource = _resourceDatabase.GetResource(desc.Resource);
|
var r = _resourceDatabase.GetResourceRecord(desc.Resource);
|
||||||
|
if (r.IsFailure)
|
||||||
|
{
|
||||||
|
RecordError(nameof(ResourceBarrier), r.Error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref var record = ref r.Value;
|
||||||
|
var resource = record.ResourcePtr;
|
||||||
pBufferBarriers[bufferIndex++] = new D3D12_BUFFER_BARRIER
|
pBufferBarriers[bufferIndex++] = new D3D12_BUFFER_BARRIER
|
||||||
{
|
{
|
||||||
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
|
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
|
||||||
@@ -259,11 +267,21 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
Offset = 0,
|
Offset = 0,
|
||||||
Size = ulong.MaxValue
|
Size = ulong.MaxValue
|
||||||
};
|
};
|
||||||
|
|
||||||
|
record.barrierData = new ResourceBarrierData(BarrierLayout.Undefined, desc.AccessAfter, desc.SyncAfter);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BarrierType.Texture:
|
case BarrierType.Texture:
|
||||||
{
|
{
|
||||||
var resource = _resourceDatabase.GetResource(desc.Resource);
|
var r = _resourceDatabase.GetResourceRecord(desc.Resource);
|
||||||
|
if (r.IsFailure)
|
||||||
|
{
|
||||||
|
RecordError(nameof(ResourceBarrier), r.Error);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref var record = ref r.Value;
|
||||||
|
var resource = record.ResourcePtr;
|
||||||
pTextureBarriers[textureIndex++] = new D3D12_TEXTURE_BARRIER
|
pTextureBarriers[textureIndex++] = new D3D12_TEXTURE_BARRIER
|
||||||
{
|
{
|
||||||
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
|
SyncBefore = (D3D12_BARRIER_SYNC)desc.SyncBefore,
|
||||||
@@ -282,6 +300,8 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
|||||||
},
|
},
|
||||||
Flags = desc.Discard ? D3D12_TEXTURE_BARRIER_FLAGS.D3D12_TEXTURE_BARRIER_FLAG_DISCARD : D3D12_TEXTURE_BARRIER_FLAGS.D3D12_TEXTURE_BARRIER_FLAG_NONE
|
Flags = desc.Discard ? D3D12_TEXTURE_BARRIER_FLAGS.D3D12_TEXTURE_BARRIER_FLAG_DISCARD : D3D12_TEXTURE_BARRIER_FLAGS.D3D12_TEXTURE_BARRIER_FLAG_NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
record.barrierData = new ResourceBarrierData(desc.LayoutAfter, desc.AccessAfter, desc.SyncAfter);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using static TerraFX.Aliases.D3D12_Alias;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
internal unsafe struct D3D12DescriptorHeap : IDisposable
|
internal unsafe class D3D12DescriptorHeap : IDisposable
|
||||||
{
|
{
|
||||||
private const int _INVALID_DESCRIPTOR_INDEX = -1;
|
private const int _INVALID_DESCRIPTOR_INDEX = -1;
|
||||||
|
|
||||||
@@ -51,8 +51,8 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly ID3D12DescriptorHeap* Heap => _heap.Get();
|
public ID3D12DescriptorHeap* Heap => _heap.Get();
|
||||||
public readonly ID3D12DescriptorHeap* ShaderVisibleHeap => _shaderVisibleHeap.Get();
|
public ID3D12DescriptorHeap* ShaderVisibleHeap => _shaderVisibleHeap.Get();
|
||||||
|
|
||||||
public D3D12DescriptorHeap(string name, D3D12RenderDevice device, D3D12_DESCRIPTOR_HEAP_TYPE type, int numDescriptors)
|
public D3D12DescriptorHeap(string name, D3D12RenderDevice device, D3D12_DESCRIPTOR_HEAP_TYPE type, int numDescriptors)
|
||||||
{
|
{
|
||||||
@@ -164,17 +164,18 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(int index)
|
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandle(int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= NumDescriptors)
|
if (index < 0 || index >= NumDescriptors)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(index), "Descriptor index is out of range.");
|
throw new ArgumentOutOfRangeException(nameof(index), "Descriptor index is out of range.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return _startCpuHandle.Offset(index, Stride);
|
var handle = _startCpuHandle;
|
||||||
|
return handle.Offset(index, Stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(int index)
|
public D3D12_CPU_DESCRIPTOR_HANDLE GetCpuHandleShaderVisible(int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= NumDescriptors)
|
if (index < 0 || index >= NumDescriptors)
|
||||||
{
|
{
|
||||||
@@ -186,10 +187,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
throw new InvalidOperationException("Descriptor heap is not shader visible.");
|
throw new InvalidOperationException("Descriptor heap is not shader visible.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return _startCpuHandleShaderVisible.Offset(index, Stride);
|
var handle = _startCpuHandleShaderVisible;
|
||||||
|
return handle.Offset(index, Stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(int index)
|
public D3D12_GPU_DESCRIPTOR_HANDLE GetGpuHandle(int index)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= NumDescriptors)
|
if (index < 0 || index >= NumDescriptors)
|
||||||
{
|
{
|
||||||
@@ -201,10 +203,11 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
|||||||
throw new InvalidOperationException("Descriptor heap is not shader visible.");
|
throw new InvalidOperationException("Descriptor heap is not shader visible.");
|
||||||
}
|
}
|
||||||
|
|
||||||
return _startGpuHandleShaderVisible.Offset(index, Stride);
|
var handle = _startGpuHandleShaderVisible;
|
||||||
|
return handle.Offset(index, Stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void CopyToShaderVisibleHeap(int index, int count = 1)
|
public void CopyToShaderVisibleHeap(int index, int count = 1)
|
||||||
{
|
{
|
||||||
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
|
_device.NativeDevice.Get()->CopyDescriptorsSimple((uint)count, GetCpuHandleShaderVisible(index), GetCpuHandle(index), HeapType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -323,6 +323,15 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
return _samplers.TryGetValue(desc, out id);
|
return _samplers.TryGetValue(desc, out id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ReleaseSampler(Identifier<Sampler> id)
|
||||||
|
{
|
||||||
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
|
// NOTE: We almost never release samplers individually, because they are cheap and can be reused.
|
||||||
|
// Ideally we would release all samplers at once when disposing the ResourceDatabase.
|
||||||
|
_descriptorAllocator.Release(new Identifier<SamplerDescriptor>(id.Value));
|
||||||
|
}
|
||||||
|
|
||||||
public Handle<Mesh> AddMesh(ref readonly Mesh mesh)
|
public Handle<Mesh> AddMesh(ref readonly Mesh mesh)
|
||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|||||||
@@ -149,7 +149,8 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
|||||||
pBackBuffer->SetName($"SwapChain_BackBuffer_{i}");
|
pBackBuffer->SetName($"SwapChain_BackBuffer_{i}");
|
||||||
|
|
||||||
var rtv = _descriptorAllocator.AllocateRTV();
|
var rtv = _descriptorAllocator.AllocateRTV();
|
||||||
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, _descriptorAllocator.GetCpuHandle(rtv));
|
var cpuHandle = _descriptorAllocator.GetCpuHandle(rtv);
|
||||||
|
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, cpuHandle);
|
||||||
|
|
||||||
var view = ResourceViewGroup.Invalid with
|
var view = ResourceViewGroup.Invalid with
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -837,36 +837,36 @@ public enum BarrierType
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum BarrierSync : uint
|
public enum BarrierSync
|
||||||
{
|
{
|
||||||
None = 0x0,
|
None = 0x0,
|
||||||
All = 0x0,
|
All = 0x1,
|
||||||
Draw = 0x1,
|
Draw = 0x2,
|
||||||
IndexInput = 0x2,
|
IndexInput = 0x4,
|
||||||
VertexShading = 0x4,
|
VertexShading = 0x8,
|
||||||
PixelShading = 0x8,
|
PixelShading = 0x10,
|
||||||
DepthStencil = 0x10,
|
DepthStencil = 0x20,
|
||||||
RenderTarget = 0x20,
|
RenderTarget = 0x40,
|
||||||
ComputeShading = 0x40,
|
ComputeShading = 0x80,
|
||||||
Raytracing = 0x80,
|
Raytracing = 0x100,
|
||||||
Copy = 0x100,
|
Copy = 0x200,
|
||||||
Resolve = 0x200,
|
Resolve = 0x400,
|
||||||
ExecuteIndirect = 0x400,
|
ExecuteIndirect = 0x800,
|
||||||
Predication = 0x800,
|
Predication = 0x800,
|
||||||
AllShading = VertexShading | PixelShading | ComputeShading | Raytracing,
|
AllShading = 0x1000,
|
||||||
NonPixelShading = VertexShading | ComputeShading | Raytracing,
|
NonPixelShading = 0x2000,
|
||||||
EmitRaytracingAccelerationStructurePostbuildInfo = 0x1000,
|
EmitRaytracingAccelerationStructurePostbuildInfo = 0x4000,
|
||||||
ClearUnorderedAccessView = 0x2000,
|
ClearUnorderedAccessView = 0x8000,
|
||||||
VideoDecode = 0x40000,
|
VideoDecode = 0x100000,
|
||||||
VideoProcess = 0x80000,
|
VideoProcess = 0x200000,
|
||||||
VideoEncode = 0x100000,
|
VideoEncode = 0x400000,
|
||||||
BuildRaytracingAccelerationStructure = 0x200000,
|
BuildRaytracingAccelerationStructure = 0x800000,
|
||||||
CopyRaytracingAccelerationStructure = 0x400000,
|
CopyRaytracingAccelerationStructure = 0x1000000,
|
||||||
Split = 0x800000
|
Split = unchecked((int)0x80000000)
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum BarrierAccess : uint
|
public enum BarrierAccess
|
||||||
{
|
{
|
||||||
Common = 0,
|
Common = 0,
|
||||||
VertexBuffer = 0x1,
|
VertexBuffer = 0x1,
|
||||||
@@ -879,6 +879,7 @@ public enum BarrierAccess : uint
|
|||||||
ShaderResource = 0x80,
|
ShaderResource = 0x80,
|
||||||
StreamOutput = 0x100,
|
StreamOutput = 0x100,
|
||||||
IndirectArgument = 0x200,
|
IndirectArgument = 0x200,
|
||||||
|
Predication = 0x200,
|
||||||
CopyDest = 0x400,
|
CopyDest = 0x400,
|
||||||
CopySource = 0x800,
|
CopySource = 0x800,
|
||||||
ResolveDest = 0x1000,
|
ResolveDest = 0x1000,
|
||||||
@@ -892,7 +893,7 @@ public enum BarrierAccess : uint
|
|||||||
VideoProcessWrite = 0x100000,
|
VideoProcessWrite = 0x100000,
|
||||||
VideoEncodeRead = 0x200000,
|
VideoEncodeRead = 0x200000,
|
||||||
VideoEncodeWrite = 0x400000,
|
VideoEncodeWrite = 0x400000,
|
||||||
NoAccess = 0x80000000
|
NoAccess = unchecked((int)0x80000000)
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum BarrierLayout
|
public enum BarrierLayout
|
||||||
@@ -906,10 +907,10 @@ public enum BarrierLayout
|
|||||||
DepthStencilWrite = 4,
|
DepthStencilWrite = 4,
|
||||||
DepthStencilRead = 5,
|
DepthStencilRead = 5,
|
||||||
ShaderResource = 6,
|
ShaderResource = 6,
|
||||||
CopyDest = 7,
|
CopySource = 7,
|
||||||
CopySource = 8,
|
CopyDest = 8,
|
||||||
ResolveDest = 9,
|
ResolveSource = 9,
|
||||||
ResolveSource = 10,
|
ResolveDest = 10,
|
||||||
ShadingRateSource = 11,
|
ShadingRateSource = 11,
|
||||||
VideoDecodeRead = 12,
|
VideoDecodeRead = 12,
|
||||||
VideoDecodeWrite = 13,
|
VideoDecodeWrite = 13,
|
||||||
@@ -918,8 +919,18 @@ public enum BarrierLayout
|
|||||||
VideoEncodeRead = 16,
|
VideoEncodeRead = 16,
|
||||||
VideoEncodeWrite = 17,
|
VideoEncodeWrite = 17,
|
||||||
DirectQueueCommon = 18,
|
DirectQueueCommon = 18,
|
||||||
ComputeQueueCommon = 19,
|
DirectQueueGenericRead = 19,
|
||||||
VideoQueueCommon = 20
|
DirectQueueUnorderedAccess = 20,
|
||||||
|
DirectQueueShaderResource = 21,
|
||||||
|
DirectQueueCopySource = 22,
|
||||||
|
DirectQueueCopyDest = 23,
|
||||||
|
ComputeQueueCommon = 24,
|
||||||
|
ComputeQueueGenericRead = 25,
|
||||||
|
ComputeQueueUnorderedAccess = 26,
|
||||||
|
ComputeQueueShaderResource = 27,
|
||||||
|
ComputeQueueCopySource = 28,
|
||||||
|
ComputeQueueCopyDest = 29,
|
||||||
|
DirectQueueGenericReadComputeQueueAccessible = 31,
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
|||||||
@@ -110,6 +110,12 @@ public interface IResourceDatabase : IDisposable
|
|||||||
/// <returns>true if a sampler with the given identifier exists; otherwise, false.</returns>
|
/// <returns>true if a sampler with the given identifier exists; otherwise, false.</returns>
|
||||||
bool TryGetSampler(ref readonly SamplerDesc desc, out Identifier<Sampler> id);
|
bool TryGetSampler(ref readonly SamplerDesc desc, out Identifier<Sampler> id);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the sampler associated with the specified identifier and frees any resources allocated to it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The identifier of the sampler to release. Must reference a valid, existing sampler.</param>
|
||||||
|
void ReleaseSampler(Identifier<Sampler> id);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a mesh to the resource database and returns its handle.
|
/// Adds a mesh to the resource database and returns its handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ using Ghost.Graphics.Core;
|
|||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.LowLevel.Collections;
|
using Misaki.HighPerformance.LowLevel.Collections;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO.Hashing;
|
using System.IO.Hashing;
|
||||||
using TerraFX.Interop.Windows;
|
|
||||||
|
|
||||||
namespace Ghost.Graphics.RenderGraphModule;
|
namespace Ghost.Graphics.RenderGraphModule;
|
||||||
|
|
||||||
@@ -25,10 +25,10 @@ public sealed class RenderGraph : IDisposable
|
|||||||
private readonly RenderGraphBuilder _builder;
|
private readonly RenderGraphBuilder _builder;
|
||||||
private readonly ResourceAliasingManager _aliasingManager;
|
private readonly ResourceAliasingManager _aliasingManager;
|
||||||
|
|
||||||
private readonly Dictionary<int, ResourceState> _resourceStates;
|
private readonly Dictionary<int, ResourceBarrierData> _resourceStates = new(128);
|
||||||
private readonly List<ResourceBarrier> _barriers;
|
private readonly List<ResourceBarrier> _barriers = new(128);
|
||||||
|
|
||||||
private readonly RenderGraphCompilationCache _compilationCache;
|
private readonly RenderGraphCompilationCache _compilationCache = new();
|
||||||
private readonly RenderGraphContext _context;
|
private readonly RenderGraphContext _context;
|
||||||
|
|
||||||
private bool _compiled;
|
private bool _compiled;
|
||||||
@@ -54,7 +54,7 @@ public sealed class RenderGraph : IDisposable
|
|||||||
_builder = new RenderGraphBuilder();
|
_builder = new RenderGraphBuilder();
|
||||||
_aliasingManager = new ResourceAliasingManager(_objectPool);
|
_aliasingManager = new ResourceAliasingManager(_objectPool);
|
||||||
|
|
||||||
_resourceStates = new Dictionary<int, ResourceState>(64);
|
_resourceStates = new Dictionary<int, ResourceBarrierData>(64);
|
||||||
_barriers = new List<ResourceBarrier>(128);
|
_barriers = new List<ResourceBarrier>(128);
|
||||||
|
|
||||||
_compilationCache = new RenderGraphCompilationCache();
|
_compilationCache = new RenderGraphCompilationCache();
|
||||||
@@ -70,6 +70,7 @@ public sealed class RenderGraph : IDisposable
|
|||||||
Blackboard = new RenderGraphBlackboard();
|
Blackboard = new RenderGraphBlackboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the render graph for a new frame.
|
/// Resets the render graph for a new frame.
|
||||||
/// Reuses existing allocations to minimize GC.
|
/// Reuses existing allocations to minimize GC.
|
||||||
@@ -80,10 +81,10 @@ public sealed class RenderGraph : IDisposable
|
|||||||
Blackboard.Clear();
|
Blackboard.Clear();
|
||||||
|
|
||||||
// Reset resources but keep allocations
|
// Reset resources but keep allocations
|
||||||
_resources.BeginFrame();
|
_resources.Reset();
|
||||||
|
|
||||||
// Reset aliasing manager
|
// Reset aliasing manager
|
||||||
_aliasingManager.BeginFrame();
|
_aliasingManager.Reset();
|
||||||
|
|
||||||
// Clear resource states and barriers
|
// Clear resource states and barriers
|
||||||
_resourceStates.Clear();
|
_resourceStates.Clear();
|
||||||
@@ -116,7 +117,9 @@ public sealed class RenderGraph : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="texture">The external texture handle.</param>
|
/// <param name="texture">The external texture handle.</param>
|
||||||
/// <returns>The identifier of the imported render graph texture. Invalid if import fails.</returns>
|
/// <returns>The identifier of the imported render graph texture. Invalid if import fails.</returns>
|
||||||
public Identifier<RGTexture> ImportTexture(Handle<Texture> texture, string name)
|
public Identifier<RGTexture> ImportTexture(Handle<Texture> texture, string name,
|
||||||
|
Color128 clearColor = default, float clearDepth = 1.0f, byte clearStencil = 0,
|
||||||
|
bool clearAtFirstUse = true, bool discardAtLastUse = true)
|
||||||
{
|
{
|
||||||
var r = _graphicsEngine.ResourceDatabase.GetResourceDescription(texture.AsResource());
|
var r = _graphicsEngine.ResourceDatabase.GetResourceDescription(texture.AsResource());
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
@@ -125,7 +128,7 @@ public sealed class RenderGraph : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
var desc = r.Value;
|
var desc = r.Value;
|
||||||
return _resources.ImportTexture(in desc._desc.textureDescription, texture, name);
|
return _resources.ImportTexture(in desc._desc.textureDescription, texture, name, clearColor, clearDepth, clearStencil, clearAtFirstUse, discardAtLastUse);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -329,17 +332,6 @@ public sealed class RenderGraph : IDisposable
|
|||||||
*(int*)(pData + offset) = pass.randomAccess[k].Value;
|
*(int*)(pData + offset) = pass.randomAccess[k].Value;
|
||||||
offset += sizeof(int);
|
offset += sizeof(int);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash buffer hints (important for correct barrier generation)
|
|
||||||
*(int*)(pData + offset) = pass.bufferHints.Count;
|
|
||||||
offset += sizeof(int);
|
|
||||||
foreach (var kvp in pass.bufferHints)
|
|
||||||
{
|
|
||||||
*(int*)(pData + offset) = kvp.Key; // Buffer resource ID
|
|
||||||
offset += sizeof(int);
|
|
||||||
*(int*)(pData + offset) = (int)kvp.Value; // BufferHint flags
|
|
||||||
offset += sizeof(int);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*(int*)(pData + offset) = pass.GetRenderFuncHashCode();
|
*(int*)(pData + offset) = pass.GetRenderFuncHashCode();
|
||||||
@@ -439,7 +431,7 @@ public sealed class RenderGraph : IDisposable
|
|||||||
_aliasingManager.AssignPhysicalResources(_resources, _passes.Count);
|
_aliasingManager.AssignPhysicalResources(_resources, _passes.Count);
|
||||||
AllocateResource();
|
AllocateResource();
|
||||||
|
|
||||||
GenerateBarriers();
|
GenerateAliasingBarriers();
|
||||||
BuildNativeRenderPasses();
|
BuildNativeRenderPasses();
|
||||||
StoreInCache(graphHash);
|
StoreInCache(graphHash);
|
||||||
|
|
||||||
@@ -570,6 +562,8 @@ public sealed class RenderGraph : IDisposable
|
|||||||
res.backingResource = cached.backingResources[i];
|
res.backingResource = cached.backingResources[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BuildNativeRenderPasses();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -667,9 +661,9 @@ public sealed class RenderGraph : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates resource barriers for state transitions and aliasing.
|
/// Generates aliasing barriers to synchronize resources sharing memory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void GenerateBarriers()
|
private void GenerateAliasingBarriers()
|
||||||
{
|
{
|
||||||
_barriers.Clear();
|
_barriers.Clear();
|
||||||
_resourceStates.Clear();
|
_resourceStates.Clear();
|
||||||
@@ -681,9 +675,6 @@ public sealed class RenderGraph : IDisposable
|
|||||||
|
|
||||||
// Insert aliasing barriers for resources that reuse physical memory
|
// Insert aliasing barriers for resources that reuse physical memory
|
||||||
InsertAliasingBarriers(pass, passIdx);
|
InsertAliasingBarriers(pass, passIdx);
|
||||||
|
|
||||||
// Insert transition barriers for state changes
|
|
||||||
InsertTransitionBarriers(pass, passIdx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,27 +732,16 @@ public sealed class RenderGraph : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we found a previous resource, insert aliasing barrier
|
// If we found a previous resource, insert aliasing barrier (sync update)
|
||||||
if (mostRecentLastUse >= 0)
|
if (mostRecentLastUse >= 0)
|
||||||
{
|
{
|
||||||
BarrierDesc desc;
|
// Aliasing Requirement: Transition to Undefined, Sync with Predecessor
|
||||||
if (resource.type == RenderGraphResourceType.Texture)
|
var targetState = new ResourceBarrierData(BarrierLayout.Undefined, BarrierAccess.NoAccess, BarrierSync.None);
|
||||||
{
|
var barrier = ResourceBarrier.CreateAliasing(passIdx, id, resourceBefore, targetState);
|
||||||
desc = BarrierDesc.Texture(resource.backingResource,
|
|
||||||
BarrierSync.All, BarrierSync.None,
|
|
||||||
BarrierAccess.NoAccess, BarrierAccess.NoAccess,
|
|
||||||
BarrierLayout.Undefined, BarrierLayout.Common,
|
|
||||||
discard: true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
desc = BarrierDesc.Buffer(resource.backingResource,
|
|
||||||
BarrierSync.All, BarrierSync.None,
|
|
||||||
BarrierAccess.NoAccess, BarrierAccess.NoAccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
var barrier = ResourceBarrier.Create(passIdx, desc, id);
|
|
||||||
_barriers.Add(barrier);
|
_barriers.Add(barrier);
|
||||||
|
|
||||||
|
// Update local tracker so subsequent transitions know it's Undefined
|
||||||
|
_resourceStates[id.Value] = targetState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,227 +750,24 @@ public sealed class RenderGraph : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private ResourceBarrierData GetBufferReadBarrierData(Identifier<RGResource> handle, RenderGraphPassBase pass, RenderGraphResourceType resourceType)
|
||||||
/// Inserts transition barriers when a resource changes state.
|
|
||||||
/// </summary>
|
|
||||||
private void InsertTransitionBarriers(RenderGraphPassBase pass, int passIdx)
|
|
||||||
{
|
{
|
||||||
// Process reads (transition to appropriate state based on resource type and hints)
|
|
||||||
for (var i = 0; i < (int)RenderGraphResourceType.Count; i++)
|
|
||||||
{
|
|
||||||
var readList = pass.resourceReads[i];
|
|
||||||
for (var j = 0; j < readList.Count; j++)
|
|
||||||
{
|
|
||||||
var handle = readList[j];
|
|
||||||
var state = GetBufferReadState(handle, pass, (RenderGraphResourceType)i);
|
|
||||||
InsertTransitionIfNeeded(handle, state, passIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (pass.type)
|
|
||||||
{
|
|
||||||
case RenderPassType.Raster:
|
|
||||||
for (var i = 0; i < pass.maxColorIndex; i++)
|
|
||||||
{
|
|
||||||
var access = pass.colorAccess[i];
|
|
||||||
InsertTransitionIfNeeded(access.id.AsResource(), ResourceState.RenderTarget, passIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pass.depthAccess.id.IsValid)
|
|
||||||
{
|
|
||||||
var depthAccess = pass.depthAccess;
|
|
||||||
InsertTransitionIfNeeded(depthAccess.id.AsResource(), ResourceState.DepthWrite, passIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < pass.randomAccess.Count; i++)
|
|
||||||
{
|
|
||||||
InsertTransitionIfNeeded(pass.randomAccess[i], ResourceState.UnorderedAccess, passIdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case RenderPassType.Compute:
|
|
||||||
for (var i = 0; i < (int)RenderGraphResourceType.Count; i++)
|
|
||||||
{
|
|
||||||
var writeList = pass.resourceWrites[i];
|
|
||||||
for (var j = 0; j < writeList.Count; j++)
|
|
||||||
{
|
|
||||||
var id = writeList[j];
|
|
||||||
InsertTransitionIfNeeded(id, ResourceState.UnorderedAccess, passIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case RenderPassType.Unsafe:
|
|
||||||
for (var i = 0; i < (int)RenderGraphResourceType.Count; i++)
|
|
||||||
{
|
|
||||||
var writeList = pass.resourceWrites[i];
|
|
||||||
for (var j = 0; j < writeList.Count; j++)
|
|
||||||
{
|
|
||||||
var id = writeList[j];
|
|
||||||
InsertTransitionIfNeeded(id, ResourceState.RenderTarget, passIdx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < pass.randomAccess.Count; i++)
|
|
||||||
{
|
|
||||||
InsertTransitionIfNeeded(pass.randomAccess[i], ResourceState.UnorderedAccess, passIdx);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Inserts a transition barrier if the resource state changes.
|
|
||||||
/// </summary>
|
|
||||||
private void InsertTransitionIfNeeded(Identifier<RGResource> resource, ResourceState newState, int passIdx)
|
|
||||||
{
|
|
||||||
if (!_resourceStates.TryGetValue(resource.Value, out var currentState))
|
|
||||||
{
|
|
||||||
// First time seeing this resource, assume undefined
|
|
||||||
// currentState = ResourceState.Common;
|
|
||||||
var r = _graphicsEngine.ResourceDatabase.GetResourceState(_resources.GetResource(resource).backingResource);
|
|
||||||
currentState = r.IsSuccess ? r.Value : ResourceState.Common;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentState != newState)
|
|
||||||
{
|
|
||||||
var res = _resources.GetResource(resource);
|
|
||||||
GetBarrierInfo(currentState, out var syncBefore, out var accessBefore, out var layoutBefore);
|
|
||||||
GetBarrierInfo(newState, out var syncAfter, out var accessAfter, out var layoutAfter);
|
|
||||||
|
|
||||||
BarrierDesc desc;
|
|
||||||
if (res.type == RenderGraphResourceType.Texture)
|
|
||||||
{
|
|
||||||
desc = BarrierDesc.Texture(res.backingResource,
|
|
||||||
syncBefore, syncAfter,
|
|
||||||
accessBefore, accessAfter,
|
|
||||||
layoutBefore, layoutAfter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
desc = BarrierDesc.Buffer(res.backingResource,
|
|
||||||
syncBefore, syncAfter,
|
|
||||||
accessBefore, accessAfter);
|
|
||||||
}
|
|
||||||
|
|
||||||
var barrier = ResourceBarrier.Create(passIdx, desc, resource);
|
|
||||||
_barriers.Add(barrier);
|
|
||||||
_resourceStates[resource.Value] = newState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetBarrierInfo(ResourceState state, out BarrierSync sync, out BarrierAccess access, out BarrierLayout layout)
|
|
||||||
{
|
|
||||||
sync = BarrierSync.None;
|
|
||||||
access = BarrierAccess.Common;
|
|
||||||
layout = BarrierLayout.Common;
|
|
||||||
|
|
||||||
if (state == ResourceState.Common)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state.HasFlag(ResourceState.RenderTarget))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.RenderTarget;
|
|
||||||
access |= BarrierAccess.RenderTarget;
|
|
||||||
layout = BarrierLayout.RenderTarget;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.DepthWrite))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.DepthStencil;
|
|
||||||
access |= BarrierAccess.DepthStencilWrite;
|
|
||||||
layout = BarrierLayout.DepthStencilWrite;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.DepthRead))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.DepthStencil;
|
|
||||||
access |= BarrierAccess.DepthStencilRead;
|
|
||||||
layout = BarrierLayout.DepthStencilRead;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.UnorderedAccess))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.AllShading;
|
|
||||||
access |= BarrierAccess.UnorderedAccess;
|
|
||||||
layout = BarrierLayout.UnorderedAccess;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.PixelShaderResource))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.PixelShading;
|
|
||||||
access |= BarrierAccess.ShaderResource;
|
|
||||||
layout = BarrierLayout.ShaderResource;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.NonPixelShaderResource))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.NonPixelShading;
|
|
||||||
access |= BarrierAccess.ShaderResource;
|
|
||||||
layout = BarrierLayout.ShaderResource;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.CopyDest))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.Copy;
|
|
||||||
access |= BarrierAccess.CopyDest;
|
|
||||||
layout = BarrierLayout.CopyDest;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.CopySource))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.Copy;
|
|
||||||
access |= BarrierAccess.CopySource;
|
|
||||||
layout = BarrierLayout.CopySource;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.VertexAndConstantBuffer))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.VertexShading;
|
|
||||||
access |= BarrierAccess.VertexBuffer | BarrierAccess.ConstantBuffer;
|
|
||||||
layout = BarrierLayout.Common;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.IndexBuffer))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.IndexInput;
|
|
||||||
access |= BarrierAccess.IndexBuffer;
|
|
||||||
layout = BarrierLayout.Common;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.IndirectArgument))
|
|
||||||
{
|
|
||||||
sync |= BarrierSync.ExecuteIndirect;
|
|
||||||
access |= BarrierAccess.IndirectArgument;
|
|
||||||
layout = BarrierLayout.GenericRead;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.GenericRead))
|
|
||||||
{
|
|
||||||
layout = BarrierLayout.GenericRead;
|
|
||||||
}
|
|
||||||
if (state.HasFlag(ResourceState.Present))
|
|
||||||
{
|
|
||||||
sync = BarrierSync.All;
|
|
||||||
access = BarrierAccess.Common;
|
|
||||||
layout = BarrierLayout.Present;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determines the appropriate resource state for a buffer read operation based on usage hints.
|
|
||||||
/// </summary>
|
|
||||||
private static ResourceState GetBufferReadState(Identifier<RGResource> handle, RenderGraphPassBase pass, RenderGraphResourceType resourceType)
|
|
||||||
{
|
|
||||||
// Textures always use ShaderResource state
|
|
||||||
if (resourceType == RenderGraphResourceType.Texture)
|
if (resourceType == RenderGraphResourceType.Texture)
|
||||||
{
|
{
|
||||||
return ResourceState.PixelShaderResource | ResourceState.NonPixelShaderResource;
|
return new ResourceBarrierData(BarrierLayout.ShaderResource, BarrierAccess.ShaderResource, BarrierSync.PixelShading | BarrierSync.NonPixelShading);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for buffer-specific usage hints
|
var sync = BarrierSync.PixelShading | BarrierSync.NonPixelShading;
|
||||||
if (pass.bufferHints.TryGetValue(handle.Value, out var hint))
|
var access = BarrierAccess.ShaderResource;
|
||||||
|
|
||||||
|
var resource = _resources.GetResource(handle);
|
||||||
|
if (resource.bufferDesc.Usage.HasFlag(BufferUsage.IndirectArgument))
|
||||||
{
|
{
|
||||||
if (hint.HasFlag(BufferHint.IndirectArgument))
|
sync = BarrierSync.ExecuteIndirect;
|
||||||
{
|
access = BarrierAccess.IndirectArgument;
|
||||||
return ResourceState.IndirectArgument;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default: ByteAddressBuffer read (SRV) - matches bindless architecture
|
return new ResourceBarrierData(BarrierLayout.Undefined, access, sync);
|
||||||
return ResourceState.PixelShaderResource | ResourceState.NonPixelShaderResource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -1442,35 +1219,193 @@ public sealed class RenderGraph : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private unsafe void ExecuteBarriersForPass(ICommandBuffer cmd, int passIndex, ref int barrierIndex)
|
private unsafe void ExecuteBarriersForPass(ICommandBuffer cmd, int passIndex, ref int barrierIndex)
|
||||||
{
|
{
|
||||||
int start = barrierIndex;
|
const int MaxBatch = 64;
|
||||||
int count = 0;
|
var barriers = stackalloc BarrierDesc[MaxBatch];
|
||||||
|
var barrierCount = 0;
|
||||||
|
|
||||||
while (barrierIndex < _barriers.Count && _barriers[barrierIndex].PassIndex == passIndex)
|
void Flush()
|
||||||
{
|
{
|
||||||
count++;
|
if (barrierCount > 0)
|
||||||
barrierIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
const int BatchSize = 64;
|
|
||||||
var descs = stackalloc BarrierDesc[BatchSize];
|
|
||||||
int processed = 0;
|
|
||||||
while (processed < count)
|
|
||||||
{
|
{
|
||||||
int batch = Math.Min(count - processed, BatchSize);
|
cmd.ResourceBarrier(new ReadOnlySpan<BarrierDesc>(barriers, barrierCount));
|
||||||
for (int i = 0; i < batch; i++)
|
barrierCount = 0;
|
||||||
{
|
|
||||||
descs[i] = _barriers[start + processed + i].Desc;
|
|
||||||
}
|
|
||||||
cmd.ResourceBarrier(new ReadOnlySpan<BarrierDesc>(descs, batch));
|
|
||||||
processed += batch;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1. Process Aliasing Barriers (Explicitly scheduled)
|
||||||
|
while (barrierIndex < _barriers.Count && _barriers[barrierIndex].PassIndex == passIndex)
|
||||||
|
{
|
||||||
|
var barrierReq = _barriers[barrierIndex++];
|
||||||
|
var resourceHandle = _resources.GetResource(barrierReq.Resource).backingResource;
|
||||||
|
|
||||||
|
BarrierLayout layoutBefore;
|
||||||
|
BarrierAccess accessBefore;
|
||||||
|
BarrierSync syncBefore;
|
||||||
|
|
||||||
|
if (barrierReq.AliasingPredecessor.IsValid)
|
||||||
|
{
|
||||||
|
var predHandle = _resources.GetResource(barrierReq.AliasingPredecessor).backingResource;
|
||||||
|
var predState = _graphicsEngine.ResourceDatabase.GetResourceBarrierData(predHandle).GetValueOrThrow();
|
||||||
|
|
||||||
|
layoutBefore = BarrierLayout.Undefined;
|
||||||
|
accessBefore = BarrierAccess.NoAccess;
|
||||||
|
syncBefore = predState.Sync;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var currentState = _graphicsEngine.ResourceDatabase.GetResourceBarrierData(resourceHandle).GetValueOrThrow();
|
||||||
|
layoutBefore = currentState.Layout;
|
||||||
|
accessBefore = currentState.Access;
|
||||||
|
syncBefore = currentState.Sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
var target = barrierReq.TargetState;
|
||||||
|
var resType = _resources.GetResource(barrierReq.Resource).type;
|
||||||
|
|
||||||
|
BarrierDesc desc;
|
||||||
|
if (resType == RenderGraphResourceType.Texture)
|
||||||
|
{
|
||||||
|
desc = BarrierDesc.Texture(resourceHandle,
|
||||||
|
syncBefore, target.Sync,
|
||||||
|
accessBefore, target.Access,
|
||||||
|
layoutBefore, target.Layout,
|
||||||
|
discard: barrierReq.Flags.HasFlag(BarrierFlags.Discard));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desc = BarrierDesc.Buffer(resourceHandle,
|
||||||
|
syncBefore, target.Sync,
|
||||||
|
accessBefore, target.Access);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (barrierCount >= MaxBatch)
|
||||||
|
{
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
barriers[barrierCount++] = desc;
|
||||||
|
|
||||||
|
//_graphicsEngine.ResourceDatabase.SetResourceBarrierData(resourceHandle, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Process Implicit Transitions (Iterate pass resources)
|
||||||
|
var pass = _compiledPasses[passIndex];
|
||||||
|
|
||||||
|
// Helper to check and issue transition
|
||||||
|
void IssueTransition(Identifier<RGResource> id, ResourceBarrierData target)
|
||||||
|
{
|
||||||
|
var resource = _resources.GetResource(id);
|
||||||
|
var handle = resource.backingResource;
|
||||||
|
var current = _graphicsEngine.ResourceDatabase.GetResourceBarrierData(handle).GetValueOrThrow();
|
||||||
|
|
||||||
|
if (current.Layout != target.Layout || current.Access != target.Access || current.Sync != target.Sync)
|
||||||
|
{
|
||||||
|
BarrierDesc desc;
|
||||||
|
if (resource.type == RenderGraphResourceType.Texture)
|
||||||
|
{
|
||||||
|
desc = BarrierDesc.Texture(handle,
|
||||||
|
current.Sync, target.Sync,
|
||||||
|
current.Access, target.Access,
|
||||||
|
current.Layout, target.Layout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
desc = BarrierDesc.Buffer(handle,
|
||||||
|
current.Sync, target.Sync,
|
||||||
|
current.Access, target.Access);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (barrierCount >= MaxBatch) Flush();
|
||||||
|
barriers[barrierCount++] = desc;
|
||||||
|
|
||||||
|
//_graphicsEngine.ResourceDatabase.SetResourceBarrierData(handle, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads
|
||||||
|
for (var i = 0; i < (int)RenderGraphResourceType.Count; i++)
|
||||||
|
{
|
||||||
|
var readList = pass.resourceReads[i];
|
||||||
|
for (var j = 0; j < readList.Count; j++)
|
||||||
|
{
|
||||||
|
var handle = readList[j];
|
||||||
|
var targetState = GetBufferReadBarrierData(handle, pass, (RenderGraphResourceType)i);
|
||||||
|
IssueTransition(handle, targetState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (pass.type)
|
||||||
|
{
|
||||||
|
case RenderPassType.Raster:
|
||||||
|
for (var i = 0; i <= pass.maxColorIndex; i++)
|
||||||
|
{
|
||||||
|
if (pass.colorAccess[i].id.IsValid)
|
||||||
|
{
|
||||||
|
var usage = pass.colorAccess[i].usage;
|
||||||
|
var targetState = new ResourceBarrierData(usage.Layout, usage.Access, usage.Sync);
|
||||||
|
IssueTransition(pass.colorAccess[i].id.AsResource(), targetState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pass.depthAccess.id.IsValid)
|
||||||
|
{
|
||||||
|
var usage = pass.depthAccess.usage;
|
||||||
|
var targetState = new ResourceBarrierData(usage.Layout, usage.Access, usage.Sync);
|
||||||
|
IssueTransition(pass.depthAccess.id.AsResource(), targetState);
|
||||||
|
}
|
||||||
|
|
||||||
|
var uavState = new ResourceBarrierData(BarrierLayout.UnorderedAccess, BarrierAccess.UnorderedAccess, BarrierSync.AllShading);
|
||||||
|
for (var i = 0; i < pass.randomAccess.Count; i++)
|
||||||
|
{
|
||||||
|
IssueTransition(pass.randomAccess[i], uavState);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RenderPassType.Compute:
|
||||||
|
var computeUavState = new ResourceBarrierData(BarrierLayout.UnorderedAccess, BarrierAccess.UnorderedAccess, BarrierSync.ComputeShading);
|
||||||
|
for (var i = 0; i < (int)RenderGraphResourceType.Count; i++)
|
||||||
|
{
|
||||||
|
var writeList = pass.resourceWrites[i];
|
||||||
|
for (var j = 0; j < writeList.Count; j++)
|
||||||
|
{
|
||||||
|
IssueTransition(writeList[j], computeUavState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RenderPassType.Unsafe:
|
||||||
|
var rtState = new ResourceBarrierData(BarrierLayout.RenderTarget, BarrierAccess.RenderTarget, BarrierSync.RenderTarget);
|
||||||
|
for (var i = 0; i < (int)RenderGraphResourceType.Count; i++)
|
||||||
|
{
|
||||||
|
var writeList = pass.resourceWrites[i];
|
||||||
|
for (var j = 0; j < writeList.Count; j++)
|
||||||
|
{
|
||||||
|
IssueTransition(writeList[j], rtState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var unsafeUavState = new ResourceBarrierData(BarrierLayout.UnorderedAccess, BarrierAccess.UnorderedAccess, BarrierSync.AllShading);
|
||||||
|
for (var i = 0; i < pass.randomAccess.Count; i++)
|
||||||
|
{
|
||||||
|
IssueTransition(pass.randomAccess[i], unsafeUavState);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
foreach (var resource in _resources.Resources)
|
||||||
|
{
|
||||||
|
_graphicsEngine.ResourceDatabase.ReleaseResource(resource.backingResource);
|
||||||
|
}
|
||||||
|
|
||||||
_graphicsEngine.ResourceDatabase.ReleaseResource(_resourceHeap);
|
_graphicsEngine.ResourceDatabase.ReleaseResource(_resourceHeap);
|
||||||
|
|
||||||
|
// We need to reset the whole graph to return resources to the pool
|
||||||
|
// FIX: Ideally we should call dispose here for each subsystem
|
||||||
|
Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ internal sealed class ResourceAliasingManager
|
|||||||
_logicalToPlaced = new Dictionary<int, int>(64);
|
_logicalToPlaced = new Dictionary<int, int>(64);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginFrame()
|
public void Reset()
|
||||||
{
|
{
|
||||||
for (var i = 0; i < _placedResources.Count; i++)
|
for (var i = 0; i < _placedResources.Count; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,41 +4,70 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Ghost.Graphics.RenderGraphModule;
|
namespace Ghost.Graphics.RenderGraphModule;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
internal enum BarrierFlags
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
FirstUsage = 1 << 0,
|
||||||
|
Discard = 1 << 1
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a resource barrier that needs to be inserted.
|
/// Represents a resource barrier requirement that needs to be resolved at runtime.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal struct ResourceBarrier
|
internal struct ResourceBarrier
|
||||||
{
|
{
|
||||||
public int PassIndex;
|
public int PassIndex;
|
||||||
public BarrierDesc Desc;
|
public Identifier<RGResource> Resource;
|
||||||
public Identifier<RGResource> LogicalResource;
|
public ResourceBarrierData TargetState;
|
||||||
|
public Identifier<RGResource> AliasingPredecessor; // Invalid if not aliasing
|
||||||
|
public BarrierFlags Flags;
|
||||||
|
|
||||||
public readonly Identifier<RGResource> Resource => LogicalResource;
|
public static ResourceBarrier CreateTransition(int passIndex, Identifier<RGResource> resource, ResourceBarrierData targetState, BarrierFlags flags = BarrierFlags.None)
|
||||||
|
|
||||||
public static ResourceBarrier Create(int passIndex, BarrierDesc desc, Identifier<RGResource> logicalResource)
|
|
||||||
{
|
{
|
||||||
return new ResourceBarrier
|
return new ResourceBarrier
|
||||||
{
|
{
|
||||||
PassIndex = passIndex,
|
PassIndex = passIndex,
|
||||||
Desc = desc,
|
Resource = resource,
|
||||||
LogicalResource = logicalResource
|
TargetState = targetState,
|
||||||
|
AliasingPredecessor = Identifier<RGResource>.Invalid,
|
||||||
|
Flags = flags
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ResourceBarrier CreateAliasing(int passIndex, Identifier<RGResource> resource, Identifier<RGResource> predecessor, ResourceBarrierData targetState)
|
||||||
|
{
|
||||||
|
return new ResourceBarrier
|
||||||
|
{
|
||||||
|
PassIndex = passIndex,
|
||||||
|
Resource = resource,
|
||||||
|
TargetState = targetState,
|
||||||
|
AliasingPredecessor = predecessor,
|
||||||
|
Flags = BarrierFlags.FirstUsage | BarrierFlags.Discard // Aliasing implies starting fresh
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override readonly string ToString()
|
||||||
|
{
|
||||||
|
return AliasingPredecessor.IsValid
|
||||||
|
? $"[Pass {PassIndex}] Aliasing Barrier: {AliasingPredecessor.Value}->{Resource.Value} Target: {TargetState.Layout}"
|
||||||
|
: $"[Pass {PassIndex}] Barrier: {Resource.Value} Target: {TargetState.Layout}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tracks the current state of a resource across passes.
|
/// Tracks the current state of a resource across passes during compilation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class ResourceStateTracker
|
internal sealed class ResourceStateTracker
|
||||||
{
|
{
|
||||||
public int resourceIndex;
|
public int resourceIndex;
|
||||||
public ResourceState currentState = ResourceState.Common;
|
public ResourceBarrierData currentState;
|
||||||
public int lastAccessPass = -1;
|
public int lastAccessPass = -1;
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
resourceIndex = -1;
|
resourceIndex = -1;
|
||||||
currentState = ResourceState.Common;
|
currentState = default;
|
||||||
lastAccessPass = -1;
|
lastAccessPass = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ public interface IRenderGraphBuilder : IDisposable
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="buffer">The identifier of the buffer to be used in the render graph pass.</param>
|
/// <param name="buffer">The identifier of the buffer to be used in the render graph pass.</param>
|
||||||
/// <param name="accessMode">The access mode specifying how the buffer will be read or written during the pass.</param>
|
/// <param name="accessMode">The access mode specifying how the buffer will be read or written during the pass.</param>
|
||||||
/// <param name="hint">Optional hint about how the buffer will be used (e.g., IndirectArgument). Default is None (ByteAddressBuffer SRV).</param>
|
/// <param name="hint">Optional hint about how the buffer will be used.</param>
|
||||||
/// <returns>An identifier for the buffer.</returns>
|
/// <returns>An identifier for the buffer.</returns>
|
||||||
Identifier<RGBuffer> UseBuffer(Identifier<RGBuffer> buffer, AccessFlags accessMode, BufferHint hint = BufferHint.None);
|
Identifier<RGBuffer> UseBuffer(Identifier<RGBuffer> buffer, AccessFlags accessMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IRasterRenderGraphBuilder : IRenderGraphBuilder
|
public interface IRasterRenderGraphBuilder : IRenderGraphBuilder
|
||||||
@@ -212,16 +212,9 @@ internal class RenderGraphBuilder : IRasterRenderGraphBuilder, IComputeRenderGra
|
|||||||
return UseResource(texture.AsResource(), flags, RenderGraphResourceType.Texture).AsTexture();
|
return UseResource(texture.AsResource(), flags, RenderGraphResourceType.Texture).AsTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Identifier<RGBuffer> UseBuffer(Identifier<RGBuffer> buffer, AccessFlags flags, BufferHint hint = BufferHint.None)
|
public Identifier<RGBuffer> UseBuffer(Identifier<RGBuffer> buffer, AccessFlags flags)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
// Store buffer hint if not None
|
|
||||||
if (hint != BufferHint.None)
|
|
||||||
{
|
|
||||||
_pass.bufferHints[buffer.AsResource().Value] = hint;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UseResource(buffer.AsResource(), flags, RenderGraphResourceType.Buffer).AsBuffer();
|
return UseResource(buffer.AsResource(), flags, RenderGraphResourceType.Buffer).AsBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +248,8 @@ internal class RenderGraphBuilder : IRasterRenderGraphBuilder, IComputeRenderGra
|
|||||||
if (_pass.colorAccess[index].id == id || _pass.colorAccess[index].id.IsInvalid)
|
if (_pass.colorAccess[index].id == id || _pass.colorAccess[index].id.IsInvalid)
|
||||||
{
|
{
|
||||||
_pass.maxColorIndex = Math.Max(_pass.maxColorIndex, index);
|
_pass.maxColorIndex = Math.Max(_pass.maxColorIndex, index);
|
||||||
_pass.colorAccess[index] = new TextureAccess(id, flags);
|
var usage = new ResourceBarrierData(BarrierLayout.RenderTarget, BarrierAccess.RenderTarget, BarrierSync.RenderTarget);
|
||||||
|
_pass.colorAccess[index] = new TextureAccess(id, flags, usage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -263,14 +257,18 @@ internal class RenderGraphBuilder : IRasterRenderGraphBuilder, IComputeRenderGra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetDepthAttachment(Identifier<RGTexture> texture, AccessFlags flags = AccessFlags.Write)
|
public void SetDepthAttachment(Identifier<RGTexture> texture, AccessFlags flags = AccessFlags.ReadWrite)
|
||||||
{
|
{
|
||||||
ThrowIfDisposed();
|
ThrowIfDisposed();
|
||||||
|
|
||||||
var id = UseTexture(texture, flags);
|
var id = UseTexture(texture, flags);
|
||||||
if (_pass.depthAccess.id == id || _pass.depthAccess.id.IsInvalid)
|
if (_pass.depthAccess.id == id || _pass.depthAccess.id.IsInvalid)
|
||||||
{
|
{
|
||||||
_pass.depthAccess = new TextureAccess(id, flags);
|
var layout = flags.HasFlag(AccessFlags.Write) ? BarrierLayout.DepthStencilWrite : BarrierLayout.DepthStencilRead;
|
||||||
|
var access = flags.HasFlag(AccessFlags.Write) ? BarrierAccess.DepthStencilWrite : BarrierAccess.DepthStencilRead;
|
||||||
|
var sync = BarrierSync.DepthStencil;
|
||||||
|
var usage = new ResourceBarrierData(layout, access, sync);
|
||||||
|
_pass.depthAccess = new TextureAccess(id, flags, usage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ internal sealed class CachedCompilation
|
|||||||
public readonly List<ResourceBarrier> barriers = new(128);
|
public readonly List<ResourceBarrier> barriers = new(128);
|
||||||
|
|
||||||
// Resource state mappings (for barrier generation)
|
// Resource state mappings (for barrier generation)
|
||||||
public readonly Dictionary<int, ResourceState> resourceStates = new(128);
|
public readonly Dictionary<int, ResourceBarrierData> resourceStates = new(128);
|
||||||
|
|
||||||
// Real gpu resource
|
// Real gpu resource
|
||||||
public readonly List<Handle<GPUResource>> backingResources = new(32);
|
public readonly List<Handle<GPUResource>> backingResources = new(32);
|
||||||
|
|||||||
@@ -37,9 +37,6 @@ internal abstract class RenderGraphPassBase
|
|||||||
public readonly List<Identifier<RGResource>>[] resourceWrites = new List<Identifier<RGResource>>[(int)RenderGraphResourceType.Count];
|
public readonly List<Identifier<RGResource>>[] resourceWrites = new List<Identifier<RGResource>>[(int)RenderGraphResourceType.Count];
|
||||||
public readonly List<Identifier<RGResource>>[] resourceCreates = new List<Identifier<RGResource>>[(int)RenderGraphResourceType.Count];
|
public readonly List<Identifier<RGResource>>[] resourceCreates = new List<Identifier<RGResource>>[(int)RenderGraphResourceType.Count];
|
||||||
|
|
||||||
// Buffer usage hints (maps buffer resource ID to hint)
|
|
||||||
public readonly Dictionary<int, BufferHint> bufferHints = new(8);
|
|
||||||
|
|
||||||
// Execution state
|
// Execution state
|
||||||
public bool culled;
|
public bool culled;
|
||||||
public bool hasSideEffects;
|
public bool hasSideEffects;
|
||||||
@@ -79,8 +76,6 @@ internal abstract class RenderGraphPassBase
|
|||||||
resourceCreates[i].Clear();
|
resourceCreates[i].Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferHints.Clear();
|
|
||||||
|
|
||||||
culled = false;
|
culled = false;
|
||||||
hasSideEffects = false;
|
hasSideEffects = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ internal sealed class RenderGraphResourceRegistry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BeginFrame()
|
public void Reset()
|
||||||
{
|
{
|
||||||
// Return all resources to pool
|
// Return all resources to pool
|
||||||
for (var i = 0; i < _resources.Count; i++)
|
for (var i = 0; i < _resources.Count; i++)
|
||||||
@@ -179,13 +179,30 @@ internal sealed class RenderGraphResourceRegistry
|
|||||||
_resources.Clear();
|
_resources.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Identifier<RGTexture> ImportTexture(ref readonly TextureDesc desc, Handle<Texture> texture, string name)
|
public Identifier<RGTexture> ImportTexture(ref readonly TextureDesc desc, Handle<Texture> texture, string name,
|
||||||
|
Color128 clearColor, float clearDepth, byte clearStencil,
|
||||||
|
bool clearAtFirstUse, bool discardAtLastUse)
|
||||||
{
|
{
|
||||||
var resource = _pool.Rent<RenderGraphResource>();
|
var resource = _pool.Rent<RenderGraphResource>();
|
||||||
resource.name = name;
|
resource.name = name;
|
||||||
resource.type = RenderGraphResourceType.Texture;
|
resource.type = RenderGraphResourceType.Texture;
|
||||||
resource.index = _resources.Count;
|
resource.index = _resources.Count;
|
||||||
resource.rgTextureDesc = RGTextureDesc.FromTextureDesc(in desc);
|
resource.rgTextureDesc = new RGTextureDesc
|
||||||
|
{
|
||||||
|
sizeMode = RGTextureSizeMode.Absolute,
|
||||||
|
width = desc.Width,
|
||||||
|
height = desc.Height,
|
||||||
|
format = desc.Format,
|
||||||
|
clearColor = clearColor,
|
||||||
|
clearDepth = clearDepth,
|
||||||
|
clearStencil = clearStencil,
|
||||||
|
clearAtFirstUse = clearAtFirstUse,
|
||||||
|
discardAtLastUse = discardAtLastUse,
|
||||||
|
dimension = desc.Dimension,
|
||||||
|
mipLevels = desc.MipLevels,
|
||||||
|
slice = desc.Slice,
|
||||||
|
usage = desc.Usage
|
||||||
|
};
|
||||||
resource.isImported = true;
|
resource.isImported = true;
|
||||||
resource.backingResource = texture.AsResource();
|
resource.backingResource = texture.AsResource();
|
||||||
resource.resolvedWidth = desc.Width;
|
resource.resolvedWidth = desc.Width;
|
||||||
|
|||||||
@@ -225,29 +225,6 @@ public struct RGTextureDesc : IEquatable<RGTextureDesc>
|
|||||||
usage = TextureUsage.DepthStencil | TextureUsage.ShaderResource
|
usage = TextureUsage.DepthStencil | TextureUsage.ShaderResource
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an RGTextureDesc from an RHI TextureDesc (for imported textures).
|
|
||||||
/// </summary>
|
|
||||||
public static RGTextureDesc FromTextureDesc(in TextureDesc desc)
|
|
||||||
{
|
|
||||||
return new RGTextureDesc
|
|
||||||
{
|
|
||||||
sizeMode = RGTextureSizeMode.Absolute,
|
|
||||||
width = desc.Width,
|
|
||||||
height = desc.Height,
|
|
||||||
format = desc.Format,
|
|
||||||
clearColor = default,
|
|
||||||
clearDepth = 1.0f,
|
|
||||||
clearStencil = 0,
|
|
||||||
clearAtFirstUse = false,
|
|
||||||
discardAtLastUse = false,
|
|
||||||
dimension = desc.Dimension,
|
|
||||||
mipLevels = desc.MipLevels,
|
|
||||||
slice = desc.Slice,
|
|
||||||
usage = desc.Usage
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -342,131 +319,37 @@ public static class RGResourceExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hints for how a buffer will be used in a pass.
|
|
||||||
/// Used to determine correct resource state transitions.
|
|
||||||
/// </summary>
|
|
||||||
[Flags]
|
|
||||||
public enum BufferHint
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No special usage - buffer will be used as shader resource (SRV) or UAV based on AccessFlags.
|
|
||||||
/// </summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Buffer will be used as indirect argument buffer (ExecuteIndirect).
|
|
||||||
/// Requires ResourceState.IndirectArgument.
|
|
||||||
/// </summary>
|
|
||||||
IndirectArgument = 1 << 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
internal readonly struct TextureAccess
|
internal readonly struct TextureAccess
|
||||||
{
|
{
|
||||||
public readonly Identifier<RGTexture> id;
|
public readonly Identifier<RGTexture> id;
|
||||||
public readonly AccessFlags accessFlags;
|
public readonly AccessFlags accessFlags;
|
||||||
|
public readonly ResourceBarrierData usage;
|
||||||
|
|
||||||
public TextureAccess(Identifier<RGTexture> id, AccessFlags accessFlags)
|
public TextureAccess(Identifier<RGTexture> id, AccessFlags accessFlags, ResourceBarrierData usage)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accessFlags = accessFlags;
|
this.accessFlags = accessFlags;
|
||||||
|
this.usage = usage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tracks buffer access information including usage hints.
|
/// Tracks buffer access information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct BufferAccess
|
internal readonly struct BufferAccess
|
||||||
{
|
{
|
||||||
public readonly Identifier<RGBuffer> id;
|
public readonly Identifier<RGBuffer> id;
|
||||||
public readonly AccessFlags accessFlags;
|
public readonly AccessFlags accessFlags;
|
||||||
public readonly BufferHint hint;
|
public readonly ResourceBarrierData usage;
|
||||||
|
|
||||||
public BufferAccess(Identifier<RGBuffer> id, AccessFlags accessFlags, BufferHint hint = BufferHint.None)
|
public BufferAccess(Identifier<RGBuffer> id, AccessFlags accessFlags, ResourceBarrierData usage)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accessFlags = accessFlags;
|
this.accessFlags = accessFlags;
|
||||||
this.hint = hint;
|
this.usage = usage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///// <summary>
|
|
||||||
///// Descriptor for creating a texture resource.
|
|
||||||
///// </summary>
|
|
||||||
//public readonly struct TextureDescriptor : IEquatable<TextureDescriptor>
|
|
||||||
//{
|
|
||||||
// public readonly int width;
|
|
||||||
// public readonly int height;
|
|
||||||
// public readonly TextureFormat format;
|
|
||||||
// public readonly string name;
|
|
||||||
|
|
||||||
// public TextureDescriptor(int width, int height, TextureFormat format, string name)
|
|
||||||
// {
|
|
||||||
// this.width = width;
|
|
||||||
// this.height = height;
|
|
||||||
// this.format = format;
|
|
||||||
// this.name = name;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public readonly bool Equals(TextureDescriptor other)
|
|
||||||
// {
|
|
||||||
// return width == other.width &&
|
|
||||||
// height == other.height &&
|
|
||||||
// format == other.format &&
|
|
||||||
// name == other.name;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public override readonly bool Equals(object? obj) => obj is TextureDescriptor other && Equals(other);
|
|
||||||
// public override readonly int GetHashCode() => HashCode.Combine(width, height, format, name);
|
|
||||||
|
|
||||||
// public static bool operator ==(TextureDescriptor left, TextureDescriptor right)
|
|
||||||
// {
|
|
||||||
// return left.Equals(right);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public static bool operator !=(TextureDescriptor left, TextureDescriptor right)
|
|
||||||
// {
|
|
||||||
// return !(left == right);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
//public readonly struct BufferDescriptor : IEquatable<BufferDescriptor>
|
|
||||||
//{
|
|
||||||
// public readonly uint sizeInBytes;
|
|
||||||
// public readonly uint stride;
|
|
||||||
// public readonly BufferUsage usage;
|
|
||||||
// public readonly string name;
|
|
||||||
|
|
||||||
// public BufferDescriptor(uint sizeInBytes, uint stride, BufferUsage usage, string name)
|
|
||||||
// {
|
|
||||||
// this.sizeInBytes = sizeInBytes;
|
|
||||||
// this.stride = stride;
|
|
||||||
// this.usage = usage;
|
|
||||||
// this.name = name;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public readonly bool Equals(BufferDescriptor other)
|
|
||||||
// {
|
|
||||||
// return sizeInBytes == other.sizeInBytes &&
|
|
||||||
// stride == other.stride &&
|
|
||||||
// usage == other.usage &&
|
|
||||||
// name == other.name;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public override readonly bool Equals(object? obj) => obj is BufferDescriptor other && Equals(other);
|
|
||||||
// public override readonly int GetHashCode() => HashCode.Combine(sizeInBytes, name);
|
|
||||||
|
|
||||||
// public static bool operator ==(BufferDescriptor left, BufferDescriptor right)
|
|
||||||
// {
|
|
||||||
// return left.Equals(right);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public static bool operator !=(BufferDescriptor left, BufferDescriptor right)
|
|
||||||
// {
|
|
||||||
// return !(left == right);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base interface for pass data that can be stored in the blackboard.
|
/// Base interface for pass data that can be stored in the blackboard.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -497,4 +380,4 @@ internal struct DepthStencilInfo
|
|||||||
public AttachmentStoreOp storeOp;
|
public AttachmentStoreOp storeOp;
|
||||||
public float clearDepth;
|
public float clearDepth;
|
||||||
public byte clearStencil;
|
public byte clearStencil;
|
||||||
}
|
}
|
||||||
@@ -233,7 +233,7 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
throw new InvalidOperationException("Failed to get material reference.");
|
throw new InvalidOperationException("Failed to get material reference.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ref readonly var matRef = ref meshResult.Value;
|
ref var matRef = ref meshResult.Value;
|
||||||
var matProps = new ShaderProperties_MyShader_Standard
|
var matProps = new ShaderProperties_MyShader_Standard
|
||||||
{
|
{
|
||||||
color = new float4(1.0f, 1.0f, 1.0f, 1.0f),
|
color = new float4(1.0f, 1.0f, 1.0f, 1.0f),
|
||||||
@@ -271,7 +271,6 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIX: We can not upload the blit material properties during a native render pass.
|
|
||||||
using (var builder = graph.AddUnsafeRenderPass<BlitPassData>("Blit Pass", out var passData))
|
using (var builder = graph.AddUnsafeRenderPass<BlitPassData>("Blit Pass", out var passData))
|
||||||
{
|
{
|
||||||
passData.source = renderTarget;
|
passData.source = renderTarget;
|
||||||
@@ -281,7 +280,7 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
|
|
||||||
builder.UseTexture(passData.source, AccessFlags.Read);
|
builder.UseTexture(passData.source, AccessFlags.Read);
|
||||||
builder.UseTexture(passData.destination, AccessFlags.WriteAll);
|
builder.UseTexture(passData.destination, AccessFlags.WriteAll);
|
||||||
|
|
||||||
builder.SetRenderFunc<BlitPassData>(static (data, ctx) =>
|
builder.SetRenderFunc<BlitPassData>(static (data, ctx) =>
|
||||||
{
|
{
|
||||||
var r = ctx.ResourceDatabase.GetMaterialReference(data.blitMaterial);
|
var r = ctx.ResourceDatabase.GetMaterialReference(data.blitMaterial);
|
||||||
@@ -290,7 +289,7 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ref readonly var matRef = ref r.Value;
|
ref var matRef = ref r.Value;
|
||||||
var blitProps = new ShaderProperties_Hidden_Blit
|
var blitProps = new ShaderProperties_Hidden_Blit
|
||||||
{
|
{
|
||||||
mainTex = ctx.ResourceDatabase.GetBindlessIndex(ctx.GetActualResource(data.source.AsResource())),
|
mainTex = ctx.ResourceDatabase.GetBindlessIndex(ctx.GetActualResource(data.source.AsResource())),
|
||||||
@@ -311,9 +310,12 @@ internal class MeshRenderPass : IRenderPass
|
|||||||
|
|
||||||
public void Cleanup(IResourceDatabase resourceDatabase)
|
public void Cleanup(IResourceDatabase resourceDatabase)
|
||||||
{
|
{
|
||||||
|
resourceDatabase.ReleaseMaterial(_blitMaterial);
|
||||||
|
|
||||||
resourceDatabase.ReleaseMaterial(_material);
|
resourceDatabase.ReleaseMaterial(_material);
|
||||||
resourceDatabase.ReleaseShader(_shader);
|
resourceDatabase.ReleaseShader(_shader);
|
||||||
resourceDatabase.ReleaseMesh(_mesh);
|
resourceDatabase.ReleaseMesh(_mesh);
|
||||||
|
resourceDatabase.ReleaseSampler(_sampler);
|
||||||
|
|
||||||
if (_textures != null)
|
if (_textures != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ struct PixelInput
|
|||||||
float4 uv : TEXCOORD0;
|
float4 uv : TEXCOORD0;
|
||||||
};
|
};
|
||||||
|
|
||||||
[MESH_SHADER_THREADS(3)] // 3 threads per triangle
|
[NumThreads(3, 1, 1)] // 3 threads per triangle
|
||||||
[OUTPUT_TRIANGLE_TOPOLOGY]
|
[OUTPUT_TRIANGLE_TOPOLOGY]
|
||||||
void MSMain(
|
void MSMain(
|
||||||
uint3 groupThreadID : SV_GroupThreadID,
|
uint3 groupThreadID : SV_GroupThreadID,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ shader "Hidden/Blit"
|
|||||||
float4 uv : TEXCOORD0;
|
float4 uv : TEXCOORD0;
|
||||||
};
|
};
|
||||||
|
|
||||||
[MESH_SHADER_THREADS(4)]
|
[NumThreads(4, 1, 1)]
|
||||||
[OUTPUT_TRIANGLE_TOPOLOGY]
|
[OUTPUT_TRIANGLE_TOPOLOGY]
|
||||||
void MSMain(
|
void MSMain(
|
||||||
uint gtid : SV_GroupThreadID,
|
uint gtid : SV_GroupThreadID,
|
||||||
@@ -45,7 +45,6 @@ shader "Hidden/Blit"
|
|||||||
float2 uv = float2(gtid & 1, (gtid >> 1) & 1);
|
float2 uv = float2(gtid & 1, (gtid >> 1) & 1);
|
||||||
|
|
||||||
verts[gtid].position = float4(uv * 2.0 - 1.0, 0.0, 1.0);
|
verts[gtid].position = float4(uv * 2.0 - 1.0, 0.0, 1.0);
|
||||||
// verts[gtid].position.y *= -1.0;
|
|
||||||
verts[gtid].uv = float4(uv, 0.0, 0.0);
|
verts[gtid].uv = float4(uv, 0.0, 0.0);
|
||||||
|
|
||||||
if (gtid == 0)
|
if (gtid == 0)
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ struct Vertex
|
|||||||
#define SAMPLE_TEXTURE2D_ARRAY(texId, sampId, uvw) SampleTextureArray(texId, sampId, uvw)
|
#define SAMPLE_TEXTURE2D_ARRAY(texId, sampId, uvw) SampleTextureArray(texId, sampId, uvw)
|
||||||
|
|
||||||
|
|
||||||
#define MESH_SHADER_THREADS(x) NumThreads(x, 1, 1)
|
|
||||||
#define OUTPUT_TRIANGLE_TOPOLOGY OutputTopology("triangle")
|
#define OUTPUT_TRIANGLE_TOPOLOGY OutputTopology("triangle")
|
||||||
#define OUTPUT_LINE_TOPOLOGY OutputTopology("line")
|
#define OUTPUT_LINE_TOPOLOGY OutputTopology("line")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user