feat(rhi): refactor resource & barrier management for D3D12
Modernizes resource and barrier management for the D3D12 backend. Key changes: - Simplifies BarrierDesc by removing nullable "before" states; now inferred from resource database. - Adds IsAliasing flag to BarrierDesc for aliasing transitions. - Replaces ResourceMemoryType with HeapType in BufferDesc and related APIs. - Enhances ResourceViewGroup with usage inference methods. - Adds D3D12 utility helpers for heap/flag conversions and resource description extraction. - Optimizes command buffer barrier emission, skipping redundant barriers. - Refactors Material and RenderContext to use new APIs and state tracking. - Updates ResourceManager pooling to use HeapType and standard Queue. - Simplifies RenderGraphExecutor barrier logic and aliasing handling. - Improves RenderSystem frame synchronization and resource retirement. - Cleans up obsolete code and improves debug output. BREAKING CHANGE: Updates to resource and barrier APIs require changes to all code interfacing with resource creation, barriers, and memory types.
This commit is contained in:
@@ -200,13 +200,20 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
switch (desc.Type)
|
||||
{
|
||||
case BarrierType.Global:
|
||||
if (desc.SyncAfter == _resourceDatabase.globalBarrier.sync && desc.AccessAfter == _resourceDatabase.globalBarrier.access)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
pGlobalBarriers[globalIndex++] = new D3D12_GLOBAL_BARRIER
|
||||
{
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? 0),
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)_resourceDatabase.globalBarrier.sync,
|
||||
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? 0),
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)_resourceDatabase.globalBarrier.access,
|
||||
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter
|
||||
};
|
||||
|
||||
_resourceDatabase.globalBarrier = new ResourceBarrierData(BarrierLayout.Undefined, desc.AccessAfter, desc.SyncAfter);
|
||||
break;
|
||||
case BarrierType.Buffer:
|
||||
{
|
||||
@@ -218,12 +225,19 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
}
|
||||
|
||||
ref var record = ref r.Value;
|
||||
var accessBefore = desc.IsAliasing ? BarrierAccess.NoAccess : record.barrierData.access;
|
||||
|
||||
if (record.barrierData.sync == desc.SyncAfter && accessBefore == desc.AccessAfter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var resource = record.ResourcePtr;
|
||||
pBufferBarriers[bufferIndex++] = new D3D12_BUFFER_BARRIER
|
||||
{
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? record.barrierData.sync),
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)record.barrierData.sync,
|
||||
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? record.barrierData.access),
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)accessBefore,
|
||||
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter,
|
||||
pResource = resource,
|
||||
Offset = 0,
|
||||
@@ -243,14 +257,22 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
}
|
||||
|
||||
ref var record = ref r.Value;
|
||||
var accessBefore = desc.IsAliasing ? BarrierAccess.NoAccess : record.barrierData.access;
|
||||
var layoutBefore = desc.IsAliasing ? BarrierLayout.Undefined : record.barrierData.layout;
|
||||
|
||||
if (record.barrierData.sync == desc.SyncAfter && accessBefore == desc.AccessAfter && layoutBefore == desc.LayoutAfter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var resource = record.ResourcePtr;
|
||||
pTextureBarriers[textureIndex++] = new D3D12_TEXTURE_BARRIER
|
||||
{
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)(desc.SyncBefore ?? record.barrierData.sync),
|
||||
SyncBefore = (D3D12_BARRIER_SYNC)record.barrierData.sync,
|
||||
SyncAfter = (D3D12_BARRIER_SYNC)desc.SyncAfter,
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)(desc.AccessBefore ?? record.barrierData.access),
|
||||
AccessBefore = (D3D12_BARRIER_ACCESS)accessBefore,
|
||||
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter,
|
||||
LayoutBefore = (D3D12_BARRIER_LAYOUT)(desc.LayoutBefore ?? record.barrierData.layout),
|
||||
LayoutBefore = (D3D12_BARRIER_LAYOUT)layoutBefore,
|
||||
LayoutAfter = (D3D12_BARRIER_LAYOUT)desc.LayoutAfter,
|
||||
pResource = resource,
|
||||
Subresources = new D3D12_BARRIER_SUBRESOURCE_RANGE
|
||||
@@ -272,39 +294,44 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
||||
var groups = stackalloc D3D12_BARRIER_GROUP[3];
|
||||
var groupCount = 0u;
|
||||
|
||||
if (globalCount > 0)
|
||||
if (globalIndex > 0)
|
||||
{
|
||||
groups[groupCount] = new D3D12_BARRIER_GROUP
|
||||
{
|
||||
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_GLOBAL,
|
||||
NumBarriers = (uint)globalCount,
|
||||
NumBarriers = (uint)globalIndex,
|
||||
};
|
||||
groups[groupCount].Anonymous.pGlobalBarriers = pGlobalBarriers;
|
||||
groupCount++;
|
||||
}
|
||||
|
||||
if (bufferCount > 0)
|
||||
if (bufferIndex > 0)
|
||||
{
|
||||
groups[groupCount] = new D3D12_BARRIER_GROUP
|
||||
{
|
||||
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_BUFFER,
|
||||
NumBarriers = (uint)bufferCount,
|
||||
NumBarriers = (uint)bufferIndex,
|
||||
};
|
||||
groups[groupCount].Anonymous.pBufferBarriers = pBufferBarriers;
|
||||
groupCount++;
|
||||
}
|
||||
|
||||
if (textureCount > 0)
|
||||
if (textureIndex > 0)
|
||||
{
|
||||
groups[groupCount] = new D3D12_BARRIER_GROUP
|
||||
{
|
||||
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_TEXTURE,
|
||||
NumBarriers = (uint)textureCount,
|
||||
NumBarriers = (uint)textureIndex,
|
||||
};
|
||||
groups[groupCount].Anonymous.pTextureBarriers = pTextureBarriers;
|
||||
groupCount++;
|
||||
}
|
||||
|
||||
if (groupCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pNativeObject->Barrier(groupCount, groups);
|
||||
}
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
fs.Write(buffer.AsSpan());
|
||||
}
|
||||
|
||||
private static Result<CBufferInfo> ValidateReflectionData(ShaderReflectionData reflectionData)
|
||||
private static Result ValidateReflectionData(ShaderReflectionData reflectionData)
|
||||
{
|
||||
if (reflectionData.ResourcesBindings.Count > RootSignatureLayout.ROOT_PARAMETER_COUNT)
|
||||
{
|
||||
@@ -149,7 +149,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
|
||||
if (reflectionData.ResourcesBindings.Count == 0)
|
||||
{
|
||||
return Result.Success(default(CBufferInfo));
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
var rootConstant = reflectionData.ResourcesBindings[0];
|
||||
@@ -163,16 +163,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
return Result.Failure($"Root constant buffer size must be {sizeof(PushConstantsData)} bytes.");
|
||||
}
|
||||
|
||||
var cbufferInfo = new CBufferInfo
|
||||
{
|
||||
Name = rootConstant.Name,
|
||||
RegisterSlot = rootConstant.BindPoint,
|
||||
RegisterSpace = rootConstant.Space,
|
||||
SizeInBytes = rootConstant.Size,
|
||||
Properties = rootConstant.Properties
|
||||
};
|
||||
|
||||
return Result.Success(cbufferInfo);
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
private static D3D12_DEPTH_STENCIL_DESC BuildDepthStencil(ZTest ztest, ZWrite zwrite)
|
||||
@@ -185,7 +176,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
|
||||
public Result<Key128<GraphicsPipeline>> CompilePSO(ref readonly GraphicsPSODescriptor descriptor, ref readonly GraphicsCompiledResult compiled)
|
||||
{
|
||||
static Result<CBufferInfo> ValidatePassReflectionData(ref readonly GraphicsCompiledResult compiled)
|
||||
static Result ValidatePassReflectionData(ref readonly GraphicsCompiledResult compiled)
|
||||
{
|
||||
var msr = ValidateReflectionData(compiled.msResult.reflectionData);
|
||||
if (msr.IsFailure)
|
||||
@@ -199,12 +190,6 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
return Result.Failure("Validation of pixel shader reflection data failed: " + psr.Message);
|
||||
}
|
||||
|
||||
if (msr.Value.Properties != null
|
||||
&& msr.Value.SizeInBytes != psr.Value.SizeInBytes)
|
||||
{
|
||||
return Result.Failure("Mesh shader and pixel shader constant buffer layouts do not match.");
|
||||
}
|
||||
|
||||
if (compiled.tsResult.IsCreated)
|
||||
{
|
||||
var tsr = ValidateReflectionData(compiled.tsResult.reflectionData);
|
||||
@@ -212,16 +197,9 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
{
|
||||
return Result.Failure("Validation of task shader reflection data failed: " + tsr.Message);
|
||||
}
|
||||
|
||||
if (tsr.Value.Properties != null
|
||||
&& tsr.Value.SizeInBytes != psr.Value.SizeInBytes)
|
||||
{
|
||||
return Result.Failure("Task shader and pixel shader constant buffer layouts do not match.");
|
||||
}
|
||||
}
|
||||
|
||||
// ts and ms may not use per material cbuffer at all, so we return the psr value.
|
||||
return psr.Value;
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
AssertNotDisposed();
|
||||
@@ -236,11 +214,11 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
||||
|
||||
if (!_pipelineCache.ContainsKey(pipelineKey))
|
||||
{
|
||||
//var result = ValidatePassReflectionData(in compiled);
|
||||
//if (result.IsFailure)
|
||||
//{
|
||||
// return Result.Failure(result.Message);
|
||||
//}
|
||||
var result = ValidatePassReflectionData(in compiled);
|
||||
if (result.IsFailure)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
|
||||
{
|
||||
|
||||
@@ -437,17 +437,6 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
|
||||
return uavDesc;
|
||||
}
|
||||
|
||||
private static D3D12_HEAP_TYPE ConvertMemoryType(ResourceMemoryType memoryType)
|
||||
{
|
||||
return memoryType switch
|
||||
{
|
||||
ResourceMemoryType.Default => D3D12_HEAP_TYPE_DEFAULT,
|
||||
ResourceMemoryType.Upload => D3D12_HEAP_TYPE_UPLOAD,
|
||||
ResourceMemoryType.Readback => D3D12_HEAP_TYPE_READBACK,
|
||||
_ => throw new ArgumentException($"Unsupported memory type: {memoryType}")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
@@ -658,7 +647,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
Handle<GPUResource> resource;
|
||||
if (isSubAllocation)
|
||||
{
|
||||
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, name);
|
||||
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, ResourceDesc.Texture(desc), name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -686,7 +675,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
|
||||
var allocationDesc = new D3D12MA_ALLOCATION_DESC
|
||||
{
|
||||
HeapType = ConvertMemoryType(desc.MemoryType),
|
||||
HeapType = desc.HeapType.ToD3D12HeapType(),
|
||||
Flags = D3D12MA_ALLOCATION_FLAG_NONE,
|
||||
};
|
||||
|
||||
@@ -695,11 +684,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
ID3D12Resource* pResource = default;
|
||||
HRESULT hr;
|
||||
|
||||
var initialState = desc.MemoryType switch
|
||||
var initialState = desc.HeapType switch
|
||||
{
|
||||
ResourceMemoryType.Default => D3D12_RESOURCE_STATE_COMMON,
|
||||
ResourceMemoryType.Upload => D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
ResourceMemoryType.Readback => D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
HeapType.Default => D3D12_RESOURCE_STATE_COMMON,
|
||||
HeapType.Upload => D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
HeapType.Readback => D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
_ => D3D12_RESOURCE_STATE_COMMON
|
||||
};
|
||||
|
||||
@@ -770,7 +759,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
Handle<GPUResource> resource;
|
||||
if (isSubAllocation)
|
||||
{
|
||||
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, name);
|
||||
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, ResourceDesc.Buffer(desc), name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -45,24 +45,24 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
||||
public readonly bool Allocated => isExternal ? resource.resource.Get() != null : resource.allocation.Get() != null;
|
||||
public readonly SharedPtr<ID3D12Resource> ResourcePtr => isExternal ? resource.resource.Get() : resource.allocation.Get()->GetResource();
|
||||
|
||||
public ResourceRecord(D3D12MA_Allocation* allocation, ResourceBarrierData barrierData, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
|
||||
public ResourceRecord(D3D12MA_Allocation* allocation, ResourceBarrierData barrierData, ResourceViewGroup viewGroup, ResourceDesc desc)
|
||||
{
|
||||
this.resource = new ResourceUnion(allocation);
|
||||
this.isExternal = false;
|
||||
|
||||
this.viewGroup = resourceDescriptor;
|
||||
this.viewGroup = viewGroup;
|
||||
this.barrierData = barrierData;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public ResourceRecord(ID3D12Resource* resource, ResourceBarrierData barrierData, ResourceViewGroup viewGroup)
|
||||
public ResourceRecord(ID3D12Resource* resource, ResourceBarrierData barrierData, ResourceViewGroup viewGroup, ResourceDesc desc)
|
||||
{
|
||||
this.resource = new ResourceUnion(resource);
|
||||
this.isExternal = true;
|
||||
|
||||
this.viewGroup = viewGroup;
|
||||
this.barrierData = barrierData;
|
||||
this.desc = resource->GetDesc().ToResourceDesc();
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public readonly uint Release(D3D12DescriptorAllocator descriptorAllocator)
|
||||
@@ -112,6 +112,8 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
||||
private ulong _cpuFrame;
|
||||
private bool _disposed;
|
||||
|
||||
public ResourceBarrierData globalBarrier;
|
||||
|
||||
public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator)
|
||||
{
|
||||
_descriptorAllocator = descriptorAllocator;
|
||||
@@ -130,7 +132,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
||||
Dispose();
|
||||
}
|
||||
|
||||
internal unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceBarrierData initialBarrierData, ResourceViewGroup viewGroup, string? name = null)
|
||||
internal Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceBarrierData initialBarrierData, ResourceViewGroup viewGroup, ResourceDesc desc, string? name = null)
|
||||
{
|
||||
Debug.Assert(!_disposed);
|
||||
|
||||
@@ -150,7 +152,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
||||
|
||||
try
|
||||
{
|
||||
var id = _resources.Add(new ResourceRecord(pResource, initialBarrierData, viewGroup), out var generation);
|
||||
var id = _resources.Add(new ResourceRecord(pResource, initialBarrierData, viewGroup, desc), out var generation);
|
||||
var handle = new Handle<GPUResource>(id, generation);
|
||||
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
@@ -169,7 +171,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
||||
}
|
||||
}
|
||||
|
||||
internal unsafe Handle<GPUResource> AddAllocation(D3D12MA_Allocation* allocation, ResourceBarrierData initialBarrierData, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string? name = null)
|
||||
internal Handle<GPUResource> AddAllocation(D3D12MA_Allocation* allocation, ResourceBarrierData initialBarrierData, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string? name = null)
|
||||
{
|
||||
Debug.Assert(!_disposed);
|
||||
|
||||
@@ -399,7 +401,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
||||
return Error.None;
|
||||
}
|
||||
|
||||
public Error Map(Handle<GPUResource> handle, uint subResource, ResourceRange? readRange, ResourceRange? writeRange, void* pData, nuint size)
|
||||
public Error MapResource(Handle<GPUResource> handle, uint subResource, ResourceRange? readRange, ResourceRange? writeRange, void* pData, nuint size)
|
||||
{
|
||||
var r = GetResourceRecord(handle);
|
||||
if (r.IsFailure)
|
||||
|
||||
@@ -160,7 +160,7 @@ internal unsafe class DXGISwapChain : ISwapChain
|
||||
sync = BarrierSync.None,
|
||||
};
|
||||
|
||||
var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, barrierData, view);
|
||||
var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, barrierData, view, D3D12Utility.GetResourceDesc(pBackBuffer, view));
|
||||
_backBuffers[i] = handle.AsTexture();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.RHI;
|
||||
|
||||
namespace Ghost.Graphics.D3D12;
|
||||
|
||||
@@ -25,4 +26,52 @@ internal struct ResourceViewGroup
|
||||
uav = Identifier<CbvSrvUavDescriptor>.Invalid,
|
||||
sampler = Identifier<SamplerDescriptor>.Invalid,
|
||||
};
|
||||
|
||||
public readonly TextureUsage GetTextureUsage()
|
||||
{
|
||||
var usage = TextureUsage.None;
|
||||
if (rtv.IsValid)
|
||||
{
|
||||
usage |= TextureUsage.RenderTarget;
|
||||
}
|
||||
|
||||
if (dsv.IsValid)
|
||||
{
|
||||
usage |= TextureUsage.DepthStencil;
|
||||
}
|
||||
|
||||
if (srv.IsValid)
|
||||
{
|
||||
usage |= TextureUsage.ShaderResource;
|
||||
}
|
||||
|
||||
if (uav.IsValid)
|
||||
{
|
||||
usage |= TextureUsage.UnorderedAccess;
|
||||
}
|
||||
|
||||
return usage;
|
||||
}
|
||||
|
||||
public readonly BufferUsage GetBufferUsage()
|
||||
{
|
||||
var usage = BufferUsage.None;
|
||||
|
||||
if (cbv.IsValid)
|
||||
{
|
||||
usage |= BufferUsage.Constant;
|
||||
}
|
||||
|
||||
if (srv.IsValid)
|
||||
{
|
||||
usage |= BufferUsage.ShaderResource;
|
||||
}
|
||||
|
||||
if (uav.IsValid)
|
||||
{
|
||||
usage |= BufferUsage.UnorderedAccess;
|
||||
}
|
||||
|
||||
return usage;
|
||||
}
|
||||
}
|
||||
@@ -397,6 +397,17 @@ internal static unsafe class D3D12Utility
|
||||
};
|
||||
}
|
||||
|
||||
public static HeapType ToHeapType(this D3D12_HEAP_TYPE heapType)
|
||||
{
|
||||
return heapType switch
|
||||
{
|
||||
D3D12_HEAP_TYPE_DEFAULT => HeapType.Default,
|
||||
D3D12_HEAP_TYPE_UPLOAD => HeapType.Upload,
|
||||
D3D12_HEAP_TYPE_READBACK => HeapType.Readback,
|
||||
_ => throw new ArgumentException($"Unknown D3D12 heap type: {heapType}")
|
||||
};
|
||||
}
|
||||
|
||||
public static D3D12_HEAP_FLAGS ToD3D12HeapFlags(this HeapFlags flags)
|
||||
{
|
||||
return flags switch
|
||||
@@ -411,6 +422,24 @@ internal static unsafe class D3D12Utility
|
||||
};
|
||||
}
|
||||
|
||||
public static HeapFlags ToHeapFlags(this D3D12_HEAP_FLAGS flags)
|
||||
{
|
||||
if (flags == D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES)
|
||||
{
|
||||
return HeapFlags.AllowAllBufferAndTexture;
|
||||
}
|
||||
|
||||
return flags switch
|
||||
{
|
||||
D3D12_HEAP_FLAG_NONE => HeapFlags.None,
|
||||
D3D12_HEAP_FLAG_SHARED => HeapFlags.Shared,
|
||||
D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS => HeapFlags.AllowOnlyBuffers,
|
||||
D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES => HeapFlags.AllowOnlyTextures,
|
||||
D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES => HeapFlags.AllowOnlyRTAndDS,
|
||||
_ => throw new ArgumentException($"Unknown D3D12 heap flags: {flags}")
|
||||
};
|
||||
}
|
||||
|
||||
public static D3D12_RESOURCE_DESC ToD3D12ResourceDesc(this in TextureDesc desc)
|
||||
{
|
||||
var dxgiFormat = desc.Format.ToDXGIFormat();
|
||||
@@ -497,17 +526,22 @@ internal static unsafe class D3D12Utility
|
||||
return D3D12_RESOURCE_DESC.Buffer(alignedSize, resourceFlags);
|
||||
}
|
||||
|
||||
|
||||
public static ResourceDesc ToResourceDesc(this D3D12_RESOURCE_DESC desc)
|
||||
public static ResourceDesc GetResourceDesc(ID3D12Resource* pResource, ResourceViewGroup viewGroup)
|
||||
{
|
||||
D3D12_HEAP_PROPERTIES heapProperties;
|
||||
D3D12_HEAP_FLAGS heapFlags;
|
||||
|
||||
ThrowIfFailed(pResource->GetHeapProperties(&heapProperties, &heapFlags));
|
||||
var desc = pResource->GetDesc();
|
||||
|
||||
if (desc.Dimension == D3D12_RESOURCE_DIMENSION.D3D12_RESOURCE_DIMENSION_BUFFER)
|
||||
{
|
||||
return ResourceDesc.Buffer(new BufferDesc
|
||||
{
|
||||
Size = (uint)desc.Width,
|
||||
Stride = 0,
|
||||
Usage = BufferUsage.None,
|
||||
MemoryType = ResourceMemoryType.Default
|
||||
Usage = viewGroup.GetBufferUsage(),
|
||||
HeapType = heapProperties.Type.ToHeapType()
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -520,7 +554,7 @@ internal static unsafe class D3D12Utility
|
||||
Format = desc.Format.ToTextureFormat(),
|
||||
Dimension = desc.Dimension.ToTextureDimension(),
|
||||
MipLevels = desc.MipLevels,
|
||||
Usage = TextureUsage.None,
|
||||
Usage = viewGroup.GetTextureUsage(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,31 +556,16 @@ public struct BarrierDesc
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierSync? SyncBefore
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierSync SyncAfter
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierAccess? AccessBefore
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierAccess AccessAfter
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierLayout? LayoutBefore
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public BarrierLayout LayoutAfter
|
||||
{
|
||||
get; set;
|
||||
@@ -601,45 +586,45 @@ public struct BarrierDesc
|
||||
get; set;
|
||||
}
|
||||
|
||||
public static BarrierDesc Global(BarrierSync syncBefore, BarrierSync syncAfter, BarrierAccess accessBefore, BarrierAccess accessAfter)
|
||||
public bool IsAliasing
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public static BarrierDesc Global(BarrierSync syncAfter, BarrierAccess accessAfter)
|
||||
{
|
||||
return new BarrierDesc
|
||||
{
|
||||
Type = BarrierType.Global,
|
||||
SyncBefore = syncBefore,
|
||||
SyncAfter = syncAfter,
|
||||
AccessBefore = accessBefore,
|
||||
AccessAfter = accessAfter
|
||||
};
|
||||
}
|
||||
|
||||
public static BarrierDesc Buffer(Handle<GPUResource> resource, BarrierSync? syncBefore, BarrierSync syncAfter, BarrierAccess? accessBefore, BarrierAccess accessAfter)
|
||||
public static BarrierDesc Buffer(Handle<GPUResource> resource, BarrierSync syncAfter, BarrierAccess accessAfter, bool isAliasing = false)
|
||||
{
|
||||
return new BarrierDesc
|
||||
{
|
||||
Type = BarrierType.Buffer,
|
||||
Resource = resource,
|
||||
SyncBefore = syncBefore,
|
||||
SyncAfter = syncAfter,
|
||||
AccessBefore = accessBefore,
|
||||
AccessAfter = accessAfter
|
||||
AccessAfter = accessAfter,
|
||||
IsAliasing = isAliasing
|
||||
};
|
||||
}
|
||||
|
||||
public static BarrierDesc Texture(Handle<GPUResource> resource, BarrierSync? syncBefore, BarrierSync syncAfter, BarrierAccess? accessBefore, BarrierAccess accessAfter, BarrierLayout? layoutBefore, BarrierLayout layoutAfter, BarrierSubresourceRange subresources = default, bool discard = false)
|
||||
public static BarrierDesc Texture(Handle<GPUResource> resource, BarrierSync syncAfter, BarrierAccess accessAfter, BarrierLayout layoutAfter, BarrierSubresourceRange subresources = default, bool discard = false, bool isAliasing = false)
|
||||
{
|
||||
return new BarrierDesc
|
||||
{
|
||||
Type = BarrierType.Texture,
|
||||
Resource = resource,
|
||||
SyncBefore = syncBefore,
|
||||
SyncAfter = syncAfter,
|
||||
AccessBefore = accessBefore,
|
||||
AccessAfter = accessAfter,
|
||||
LayoutBefore = layoutBefore,
|
||||
LayoutAfter = layoutAfter,
|
||||
Subresources = subresources,
|
||||
Discard = discard
|
||||
Discard = discard,
|
||||
IsAliasing = isAliasing
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -724,6 +709,16 @@ public record struct ResourceDesc
|
||||
_ => throw new InvalidOperationException($"Unknown resource type: {Type}")
|
||||
};
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Type switch
|
||||
{
|
||||
ResourceType.Texture => $"Texture: {TextureDescription}",
|
||||
ResourceType.Buffer => $"Buffer: {BufferDescription}",
|
||||
_ => $"Unknown resource type: {Type}"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -998,7 +993,7 @@ public record struct BufferDesc
|
||||
get; set;
|
||||
}
|
||||
|
||||
public ResourceMemoryType MemoryType
|
||||
public HeapType HeapType
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
@@ -1255,13 +1250,6 @@ public enum RenderTargetCreationFlags
|
||||
GenerateMips = 1 << 3
|
||||
}
|
||||
|
||||
public enum ResourceMemoryType
|
||||
{
|
||||
Default, // GPU memory
|
||||
Upload, // CPU-to-GPU memory
|
||||
Readback // GPU-to-CPU memory
|
||||
}
|
||||
|
||||
public enum ResourceType
|
||||
{
|
||||
Texture,
|
||||
|
||||
@@ -126,7 +126,7 @@ public unsafe interface IResourceDatabase : IDisposable
|
||||
/// <returns>An Error indicating the success or failure of the swap operation.</returns>
|
||||
Error Swap(Handle<GPUResource> handleA, Handle<GPUResource> handleB);
|
||||
|
||||
Error Map(Handle<GPUResource> handle, uint subResource, ResourceRange? readRange, ResourceRange? writeRange, void* pData, nuint size);
|
||||
Error MapResource(Handle<GPUResource> handle, uint subResource, ResourceRange? readRange, ResourceRange? writeRange, void* pData, nuint size);
|
||||
|
||||
ulong GetIntermediateResourceSize(Handle<GPUResource> resource, uint firstSubResource, uint numSubResources);
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public struct Material : IResourceReleasable
|
||||
{
|
||||
Size = shader.CBufferSize,
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
HeapType = HeapType.Default,
|
||||
};
|
||||
|
||||
var buffer = resourceAllocator.CreateBuffer(ref desc, "MaterialCBuffer");
|
||||
@@ -243,7 +243,7 @@ public struct Material : IResourceReleasable
|
||||
return _keywordMask.IsKeywordEnabled(localIndex);
|
||||
}
|
||||
|
||||
public readonly void UploadData(ICommandBuffer cmd, IResourceDatabase resourceDatabase)
|
||||
public readonly void UploadData(RenderContext ctx)
|
||||
{
|
||||
if (!_isDirty)
|
||||
{
|
||||
@@ -251,31 +251,20 @@ public struct Material : IResourceReleasable
|
||||
}
|
||||
|
||||
var cbufferResource = _cBufferCache.GpuResource.AsResource();
|
||||
var r = resourceDatabase.GetResourceBarrierData(cbufferResource);
|
||||
if (r.IsFailure)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var barrierData = r.Value;
|
||||
var desc = BarrierDesc.Buffer(
|
||||
cbufferResource,
|
||||
barrierData.sync,
|
||||
BarrierSync.Copy,
|
||||
barrierData.access,
|
||||
BarrierAccess.CopyDest);
|
||||
|
||||
cmd.Barrier(desc);
|
||||
cmd.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
|
||||
ctx.CommandBuffer.Barrier(desc);
|
||||
ctx.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
|
||||
|
||||
desc = BarrierDesc.Buffer(
|
||||
cbufferResource,
|
||||
BarrierSync.Copy,
|
||||
BarrierSync.AllShading,
|
||||
BarrierAccess.CopyDest,
|
||||
BarrierAccess.ShaderResource);
|
||||
|
||||
cmd.Barrier(desc);
|
||||
ctx.CommandBuffer.Barrier(desc);
|
||||
}
|
||||
|
||||
public void ReleaseResource(IResourceDatabase database)
|
||||
|
||||
@@ -7,13 +7,13 @@ using System.Diagnostics;
|
||||
namespace Ghost.Graphics.Core;
|
||||
|
||||
// TODO: Temporary rendering context for heap creation and data upload. We will refactor it later when we have a better understanding of the engine architecture.
|
||||
public readonly unsafe ref struct RenderingContext
|
||||
public readonly unsafe ref struct RenderContext
|
||||
{
|
||||
private readonly IGraphicsEngine _engine;
|
||||
private readonly ResourceManager _resourceManager;
|
||||
private readonly ICommandBuffer _directCmd;
|
||||
private readonly ICommandBuffer _cmd;
|
||||
|
||||
public ICommandBuffer DirectCommandBuffer => _directCmd;
|
||||
public ICommandBuffer CommandBuffer => _cmd;
|
||||
|
||||
public IShaderCompiler ShaderCompiler => _engine.ShaderCompiler;
|
||||
public ResourceManager ResourceManager => _resourceManager;
|
||||
@@ -21,69 +21,29 @@ public readonly unsafe ref struct RenderingContext
|
||||
public IResourceDatabase ResourceDatabase => _engine.ResourceDatabase;
|
||||
public IPipelineLibrary PipelineLibrary => _engine.PipelineLibrary;
|
||||
|
||||
internal RenderingContext(IGraphicsEngine engine, ResourceManager resourceManager, ICommandBuffer directCmd)
|
||||
internal RenderContext(IGraphicsEngine engine, ResourceManager resourceManager, ICommandBuffer cmd)
|
||||
{
|
||||
_engine = engine;
|
||||
_resourceManager = resourceManager;
|
||||
_directCmd = directCmd;
|
||||
}
|
||||
|
||||
public ICommandBuffer CrearteCommandBuffer(CommandBufferType type)
|
||||
{
|
||||
return _engine.CreateCommandBuffer(type);
|
||||
}
|
||||
|
||||
// TODO: ExecuteCommandBufferAsync with fencene.Device.GraphicsQueue.Submit(commandBuffer);
|
||||
public void ExecuteCommandBuffer(ICommandBuffer commandBuffer)
|
||||
{
|
||||
var queue = commandBuffer.Type switch
|
||||
{
|
||||
CommandBufferType.Graphics => _engine.Device.GraphicsQueue,
|
||||
CommandBufferType.Compute => _engine.Device.ComputeQueue,
|
||||
CommandBufferType.Copy => _engine.Device.CopyQueue,
|
||||
_ => throw new InvalidOperationException("Unknown command buffer type."),
|
||||
};
|
||||
|
||||
queue.Submit(commandBuffer);
|
||||
queue.WaitIdle();
|
||||
_cmd = cmd;
|
||||
}
|
||||
|
||||
private void TransitionBarrier(Handle<GPUResource> resource, bool isTexture, BarrierLayout newLayout, BarrierAccess newAccess, BarrierSync newSync)
|
||||
{
|
||||
var r = ResourceDatabase.GetResourceBarrierData(resource);
|
||||
if (r.IsFailure)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var data = r.Value;
|
||||
if (data.layout == newLayout && data.access == newAccess && data.sync == newSync)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BarrierDesc desc;
|
||||
if (isTexture)
|
||||
{
|
||||
desc = BarrierDesc.Texture(
|
||||
resource,
|
||||
data.sync, newSync,
|
||||
data.access, newAccess,
|
||||
data.layout, newLayout);
|
||||
desc = BarrierDesc.Texture(resource, newSync, newAccess, newLayout);
|
||||
}
|
||||
else
|
||||
{
|
||||
desc = BarrierDesc.Buffer(
|
||||
resource,
|
||||
data.sync, newSync,
|
||||
data.access, newAccess);
|
||||
desc = BarrierDesc.Buffer(resource, newSync, newAccess);
|
||||
}
|
||||
|
||||
_directCmd.Barrier(new ReadOnlySpan<BarrierDesc>(in desc));
|
||||
ResourceDatabase.SetResourceBarrierData(resource, new ResourceBarrierData(newLayout, newAccess, newSync));
|
||||
_cmd.Barrier(desc);
|
||||
}
|
||||
|
||||
private void UploadBuffer<T>(Handle<GPUBuffer> buffer, params ReadOnlySpan<T> data)
|
||||
public void UploadBuffer<T>(Handle<GPUBuffer> buffer, params ReadOnlySpan<T> data)
|
||||
where T : unmanaged
|
||||
{
|
||||
var r = _engine.ResourceDatabase.GetResourceDescription(buffer.AsResource());
|
||||
@@ -95,34 +55,43 @@ public readonly unsafe ref struct RenderingContext
|
||||
Debug.Assert(r.Value.Type == ResourceType.Buffer);
|
||||
|
||||
var sizeInBytes = (nuint)(data.Length * sizeof(T));
|
||||
var memoryType = r.Value.BufferDescription.MemoryType;
|
||||
var memoryType = r.Value.BufferDescription.HeapType;
|
||||
|
||||
if (memoryType == ResourceMemoryType.Upload)
|
||||
if (memoryType == HeapType.Upload)
|
||||
{
|
||||
fixed (T* pData = data)
|
||||
{
|
||||
ResourceDatabase.Map(buffer.AsResource(), 0, null, null, pData, sizeInBytes);
|
||||
ResourceDatabase.MapResource(buffer.AsResource(), 0, null, null, pData, sizeInBytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(sizeInBytes, out var offset);
|
||||
//var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
||||
var uploadDesc = new BufferDesc
|
||||
{
|
||||
Size = sizeInBytes,
|
||||
Usage = BufferUsage.Upload,
|
||||
MemoryType = ResourceMemoryType.Upload,
|
||||
HeapType = HeapType.Upload,
|
||||
};
|
||||
|
||||
var uploadHandle = _resourceManager.CreateTransientBuffer(in uploadDesc);
|
||||
|
||||
fixed (T* pData = data)
|
||||
if (uploadHandle.IsInvalid)
|
||||
{
|
||||
ResourceDatabase.Map(uploadHandle.AsResource(), 0, null, null, pData, sizeInBytes);
|
||||
throw new OutOfMemoryException("Failed to create upload buffer for buffer data.");
|
||||
}
|
||||
|
||||
_directCmd.CopyBuffer(buffer, uploadHandle, 0, 0, sizeInBytes);
|
||||
try
|
||||
{
|
||||
fixed (T* pData = data)
|
||||
{
|
||||
ResourceDatabase.MapResource(uploadHandle.AsResource(), 0, null, null, pData, sizeInBytes);
|
||||
}
|
||||
|
||||
_cmd.CopyBuffer(buffer, uploadHandle, 0, 0, sizeInBytes);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ResourceDatabase.ReleaseResource(uploadHandle.AsResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +138,6 @@ public readonly unsafe ref struct RenderingContext
|
||||
return CreateMesh(vertexList, indexList, staticMesh);
|
||||
}
|
||||
|
||||
// TODO: Make one memory pool for upload.
|
||||
|
||||
/// <summary>
|
||||
/// Uploads the mesh data to the GPU.
|
||||
/// </summary>
|
||||
@@ -221,14 +188,14 @@ public readonly unsafe ref struct RenderingContext
|
||||
Size = (uint)(meshletData.meshlets.Count * sizeof(Meshlet)),
|
||||
Stride = (uint)sizeof(Meshlet),
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
HeapType = HeapType.Default,
|
||||
};
|
||||
var verticesDesc = new BufferDesc
|
||||
{
|
||||
Size = (uint)(meshletData.meshletVertices.Count * sizeof(uint)),
|
||||
Stride = sizeof(uint),
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
HeapType = HeapType.Default,
|
||||
};
|
||||
// Ensure size is multiple of 4 for Raw buffer
|
||||
var trianglesSize = (uint)meshletData.meshletTriangles.Count * sizeof(uint);
|
||||
@@ -237,7 +204,7 @@ public readonly unsafe ref struct RenderingContext
|
||||
Size = trianglesSize,
|
||||
Stride = sizeof(uint),
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
HeapType = HeapType.Default,
|
||||
};
|
||||
|
||||
meshRef.MeshLetBuffer = _engine.ResourceAllocator.CreateBuffer(in meshletDesc, "Meshlets");
|
||||
@@ -296,12 +263,6 @@ public readonly unsafe ref struct RenderingContext
|
||||
public void UploadTexture<T>(Handle<GPUTexture> texture, ReadOnlySpan<T> data)
|
||||
where T : unmanaged
|
||||
{
|
||||
//var size = ResourceAllocator.GetSizeInfo(desc).Size;
|
||||
//if ((ulong)(data.Length * sizeof(T)) != ResourceAllocator.GetSizeInfo(desc).Size)
|
||||
//{
|
||||
// throw new ArgumentException("Data size does not match texture size.");
|
||||
//}
|
||||
|
||||
var desc = ResourceDatabase.GetResourceDescription(texture.AsResource()).GetValueOrThrow();
|
||||
desc.TextureDescription.Format.GetSurfaceInfo(desc.TextureDescription.Width, desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _);
|
||||
|
||||
@@ -310,7 +271,7 @@ public readonly unsafe ref struct RenderingContext
|
||||
{
|
||||
Size = requiredSize,
|
||||
Usage = BufferUsage.Upload,
|
||||
MemoryType = ResourceMemoryType.Upload,
|
||||
HeapType = HeapType.Upload,
|
||||
};
|
||||
|
||||
var uploadHandle = _resourceManager.CreateTransientBuffer(in uploadDesc);
|
||||
@@ -319,18 +280,25 @@ public readonly unsafe ref struct RenderingContext
|
||||
throw new OutOfMemoryException("Failed to create upload buffer for texture data.");
|
||||
}
|
||||
|
||||
TransitionBarrier(texture.AsResource(), true, BarrierLayout.CopyDest, BarrierAccess.CopyDest, BarrierSync.Copy);
|
||||
|
||||
fixed (T* pData = data)
|
||||
try
|
||||
{
|
||||
var subresourceData = new SubResourceData
|
||||
{
|
||||
pData = pData,
|
||||
rowPitch = rowPitch,
|
||||
slicePitch = slicePitch
|
||||
};
|
||||
TransitionBarrier(texture.AsResource(), true, BarrierLayout.CopyDest, BarrierAccess.CopyDest, BarrierSync.Copy);
|
||||
|
||||
_directCmd.UpdateSubResources(texture.AsResource(), uploadHandle.AsResource(), subresourceData);
|
||||
fixed (T* pData = data)
|
||||
{
|
||||
var subresourceData = new SubResourceData
|
||||
{
|
||||
pData = pData,
|
||||
rowPitch = rowPitch,
|
||||
slicePitch = slicePitch
|
||||
};
|
||||
|
||||
_cmd.UpdateSubResources(texture.AsResource(), uploadHandle.AsResource(), subresourceData);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ResourceDatabase.ReleaseResource(uploadHandle.AsResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.RHI;
|
||||
|
||||
namespace Ghost.Graphics.Core;
|
||||
|
||||
internal class SwapChainRenderOutput : IRenderOutput
|
||||
{
|
||||
private readonly ISwapChain _swapChain;
|
||||
|
||||
public ViewportDesc Viewport
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public ScissorRectDesc Scissor
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public SwapChainRenderOutput(ISwapChain swapChain)
|
||||
{
|
||||
_swapChain = swapChain;
|
||||
|
||||
Viewport = new ViewportDesc { Width = swapChain.Width, Height = swapChain.Height, MinDepth = 0, MaxDepth = 1 };
|
||||
Scissor = new ScissorRectDesc { Right = swapChain.Width, Bottom = swapChain.Height };
|
||||
}
|
||||
|
||||
public Handle<GPUTexture> GetRenderTarget()
|
||||
{
|
||||
return _swapChain.GetCurrentBackBuffer();
|
||||
}
|
||||
|
||||
public void BeginRender(ICommandBuffer cmd)
|
||||
{
|
||||
var barrierDesc = BarrierDesc.Texture(_swapChain.GetCurrentBackBuffer().AsResource(),
|
||||
BarrierSync.None, BarrierSync.RenderTarget,
|
||||
BarrierAccess.NoAccess, BarrierAccess.RenderTarget,
|
||||
BarrierLayout.Present, BarrierLayout.RenderTarget);
|
||||
|
||||
cmd.Barrier(barrierDesc);
|
||||
}
|
||||
|
||||
public void EndRender(ICommandBuffer cmd)
|
||||
{
|
||||
var barrierDesc = BarrierDesc.Texture(_swapChain.GetCurrentBackBuffer().AsResource(),
|
||||
BarrierSync.RenderTarget, BarrierSync.None,
|
||||
BarrierAccess.RenderTarget, BarrierAccess.NoAccess,
|
||||
BarrierLayout.RenderTarget, BarrierLayout.Present);
|
||||
|
||||
cmd.Barrier(barrierDesc);
|
||||
}
|
||||
|
||||
public void Present()
|
||||
{
|
||||
_swapChain.Present();
|
||||
}
|
||||
}
|
||||
|
||||
internal class TextureRenderOutput : IRenderOutput
|
||||
{
|
||||
private readonly Handle<GPUTexture> _texture;
|
||||
|
||||
public ViewportDesc Viewport
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public ScissorRectDesc Scissor
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public TextureRenderOutput(Handle<GPUTexture> texture)
|
||||
{
|
||||
_texture = texture;
|
||||
}
|
||||
|
||||
public Handle<GPUTexture> GetRenderTarget()
|
||||
{
|
||||
return _texture;
|
||||
}
|
||||
|
||||
public void BeginRender(ICommandBuffer cmd)
|
||||
{
|
||||
}
|
||||
|
||||
public void EndRender(ICommandBuffer cmd)
|
||||
{
|
||||
}
|
||||
|
||||
public void Present()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -217,6 +217,7 @@ internal sealed class RenderGraphExecutor
|
||||
}
|
||||
|
||||
// Process all pre-compiled barriers for this pass
|
||||
// TODO: We can insert BarrierAccess.NoAccess to the resource that aliased with others after their last usage to reduce cache burden.
|
||||
while (barrierIndex < compiledBarriers.Count && compiledBarriers[barrierIndex].PassIndex == passIndex)
|
||||
{
|
||||
var compiledBarrier = compiledBarriers[barrierIndex++];
|
||||
@@ -231,60 +232,23 @@ internal sealed class RenderGraphExecutor
|
||||
}
|
||||
|
||||
var currentState = currentStateResult.Value;
|
||||
|
||||
BarrierLayout layoutBefore;
|
||||
BarrierAccess accessBefore;
|
||||
BarrierSync syncBefore;
|
||||
|
||||
// Handle aliasing barriers specially
|
||||
if (compiledBarrier.AliasingPredecessor.IsValid)
|
||||
{
|
||||
var predHandle = _resources.GetResource(compiledBarrier.AliasingPredecessor).backingResource;
|
||||
var predStateResult = _resourceDatabase.GetResourceBarrierData(predHandle);
|
||||
if (predStateResult.IsFailure)
|
||||
{
|
||||
return predStateResult.Error;
|
||||
}
|
||||
|
||||
var predState = predStateResult.Value;
|
||||
|
||||
layoutBefore = BarrierLayout.Undefined;
|
||||
accessBefore = BarrierAccess.NoAccess;
|
||||
syncBefore = predState.sync;
|
||||
}
|
||||
else
|
||||
{
|
||||
layoutBefore = currentState.layout;
|
||||
accessBefore = currentState.access;
|
||||
syncBefore = currentState.sync;
|
||||
}
|
||||
|
||||
var target = compiledBarrier.TargetState;
|
||||
|
||||
// Skip if already in target state (optimization)
|
||||
if (!compiledBarrier.AliasingPredecessor.IsValid &&
|
||||
layoutBefore == target.layout &&
|
||||
accessBefore == target.access &&
|
||||
syncBefore == target.sync)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create barrier descriptor
|
||||
BarrierDesc desc;
|
||||
if (compiledBarrier.ResourceType == RenderGraphResourceType.Texture)
|
||||
{
|
||||
desc = BarrierDesc.Texture(resourceHandle,
|
||||
syncBefore, target.sync,
|
||||
accessBefore, target.access,
|
||||
layoutBefore, target.layout,
|
||||
desc = BarrierDesc.Texture(resourceHandle, target.sync, target.access, target.layout,
|
||||
discard: compiledBarrier.Flags.HasFlag(BarrierFlags.Discard));
|
||||
}
|
||||
else
|
||||
{
|
||||
desc = BarrierDesc.Buffer(resourceHandle,
|
||||
syncBefore, target.sync,
|
||||
accessBefore, target.access);
|
||||
desc = BarrierDesc.Buffer(resourceHandle, target.sync, target.access);
|
||||
}
|
||||
|
||||
if (compiledBarrier.AliasingPredecessor.IsValid)
|
||||
{
|
||||
desc.IsAliasing = true;
|
||||
}
|
||||
|
||||
if (barrierCount >= MaxBatch)
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.Core;
|
||||
using Ghost.Graphics.RHI;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ghost.Graphics.RenderPipeline;
|
||||
|
||||
public readonly struct RenderContext
|
||||
{
|
||||
public ICommandBuffer CommandBuffer { get; init; }
|
||||
public ICommandQueue GraphicsQueue { get; init; }
|
||||
public ICommandQueue ComputeQueue { get; init; }
|
||||
public ICommandQueue CopyQueue { get; init; }
|
||||
}
|
||||
|
||||
public interface IRenderPipelineSettings
|
||||
{
|
||||
IRenderPipeline CreatePipeline(RenderSystem renderSystem);
|
||||
|
||||
@@ -100,7 +100,8 @@ public class RenderSystem : IDisposable
|
||||
|
||||
private uint _frameIndex;
|
||||
private ulong _cpuFenceValue;
|
||||
private ulong _gpuFenceValue;
|
||||
private ulong _submittedFenceValue;
|
||||
private ulong _completedFenceValue;
|
||||
|
||||
private bool _isRunning;
|
||||
private bool _disposed;
|
||||
@@ -112,7 +113,8 @@ public class RenderSystem : IDisposable
|
||||
public bool IsRunning => _isRunning;
|
||||
|
||||
public ulong CPUFenceValue => _cpuFenceValue;
|
||||
public ulong GPUFenceValue => _gpuFenceValue;
|
||||
public ulong SubmittedFenceValue => _submittedFenceValue;
|
||||
public ulong CompletedFenceValue => _completedFenceValue;
|
||||
public uint FrameIndex => _frameIndex;
|
||||
public uint MaxFrameLatency => _config.FrameBufferCount;
|
||||
|
||||
@@ -219,7 +221,7 @@ public class RenderSystem : IDisposable
|
||||
|
||||
while (_isRunning)
|
||||
{
|
||||
_frameIndex = (uint)(_gpuFenceValue % _config.FrameBufferCount);
|
||||
_frameIndex = (uint)(_submittedFenceValue % _config.FrameBufferCount);
|
||||
ref var frameResource = ref _frameResources[_frameIndex];
|
||||
|
||||
// Wait for either CPU ready signal or shutdown signal
|
||||
@@ -242,17 +244,7 @@ public class RenderSystem : IDisposable
|
||||
|
||||
if (!_resizeRequest.IsEmpty)
|
||||
{
|
||||
_gpuFenceValue++;
|
||||
var flushFence = _graphicsEngine.Device.GraphicsQueue.Signal(_gpuFenceValue);
|
||||
_graphicsEngine.Device.GraphicsQueue.WaitForValue(flushFence);
|
||||
|
||||
// Sync the current frame heap to this new fence to keep state consistent
|
||||
frameResource.FenceValue = flushFence;
|
||||
|
||||
foreach (var resource in _frameResources)
|
||||
{
|
||||
resource.CommandAllocator.Reset();
|
||||
}
|
||||
WaitIdle();
|
||||
|
||||
var keys = _resizeRequest.Keys.ToArray();
|
||||
foreach (var swapChain in keys)
|
||||
@@ -262,17 +254,19 @@ public class RenderSystem : IDisposable
|
||||
swapChain.Resize(newSize.x, newSize.y);
|
||||
}
|
||||
}
|
||||
|
||||
frameResource.GpuReadyEvent.Set();
|
||||
|
||||
continue; // Skip rendering this frame since we just resized and may have invalid render targets
|
||||
}
|
||||
|
||||
_completedFenceValue = _graphicsEngine.Device.GraphicsQueue.GetCompletedValue();
|
||||
if (_submittedFenceValue < _completedFenceValue)
|
||||
{
|
||||
_submittedFenceValue = _completedFenceValue;
|
||||
}
|
||||
|
||||
// Begin rendering for this frame
|
||||
frameResource.CommandAllocator.Reset();
|
||||
|
||||
_resourceManager.BeginFrame(_cpuFenceValue);
|
||||
var r = _graphicsEngine.BeginFrame(_cpuFenceValue);
|
||||
_resourceManager.BeginFrame(_submittedFenceValue + 1);
|
||||
var r = _graphicsEngine.BeginFrame(_submittedFenceValue + 1);
|
||||
|
||||
if (r.IsFailure)
|
||||
{
|
||||
@@ -290,11 +284,9 @@ public class RenderSystem : IDisposable
|
||||
{
|
||||
cmd.Begin(frameResource.CommandAllocator);
|
||||
|
||||
var renderCtx = new RenderContext
|
||||
{
|
||||
CommandBuffer = cmd
|
||||
};
|
||||
var renderCtx = new RenderContext(_graphicsEngine, _resourceManager, cmd);
|
||||
|
||||
//Debug.WriteLine($"GPU: Frame started.");
|
||||
_renderPipeline.Render(renderCtx, renderRequests.AsSpan());
|
||||
_swapChainManager.TransitionToPresent(cmd);
|
||||
|
||||
@@ -321,9 +313,9 @@ public class RenderSystem : IDisposable
|
||||
renderRequests.Clear();
|
||||
}
|
||||
|
||||
// End the frame and present
|
||||
_resourceManager.EndFrame(_gpuFenceValue);
|
||||
r = _graphicsEngine.EndFrame(_gpuFenceValue);
|
||||
// End the frame and retire resources based on actual GPU progress.
|
||||
_resourceManager.EndFrame(_completedFenceValue);
|
||||
r = _graphicsEngine.EndFrame(_completedFenceValue);
|
||||
|
||||
if (r.IsFailure)
|
||||
{
|
||||
@@ -331,11 +323,9 @@ public class RenderSystem : IDisposable
|
||||
break;
|
||||
}
|
||||
|
||||
// Prepare for the next frame.
|
||||
_gpuFenceValue++;
|
||||
|
||||
_submittedFenceValue++;
|
||||
frameResource.GpuReadyEvent.Set();
|
||||
frameResource.FenceValue = _graphicsEngine.Device.GraphicsQueue.Signal(_gpuFenceValue);
|
||||
frameResource.FenceValue = _graphicsEngine.Device.GraphicsQueue.Signal(_submittedFenceValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,6 +371,21 @@ public class RenderSystem : IDisposable
|
||||
_resizeRequest.AddOrUpdate(swapChain, newSize, (_, _) => newSize);
|
||||
}
|
||||
|
||||
internal bool TryAcquireCPUFrame()
|
||||
{
|
||||
ulong requiredGpuFence = _cpuFenceValue < _config.FrameBufferCount ? 0 : _cpuFenceValue - _config.FrameBufferCount + 1;
|
||||
|
||||
if (requiredGpuFence > 0 && _graphicsEngine.Device.GraphicsQueue.GetCompletedValue() < requiredGpuFence)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var eventIndex = (int)(_cpuFenceValue % _config.FrameBufferCount);
|
||||
_frameResources[eventIndex].RenderRequests.Clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddRenderRequest(in RenderRequest request)
|
||||
{
|
||||
Debug.Assert(!_disposed, "Cannot add render request to a disposed RenderSystem.");
|
||||
|
||||
@@ -10,6 +10,7 @@ public partial class ResourceManager
|
||||
{
|
||||
private const ulong _DEFAULT_TRANSIENT_PAGE_SIZE = 16 * 1024 * 1024; // 16MB
|
||||
|
||||
[DebuggerDisplay("Heap: {heap}, Offset: {offset}, HeapType: {heapType}, HeapFlags: {heapFlags}")]
|
||||
private struct Page
|
||||
{
|
||||
public Handle<GPUResource> heap;
|
||||
@@ -19,6 +20,7 @@ public partial class ResourceManager
|
||||
public HeapType heapType;
|
||||
}
|
||||
|
||||
[DebuggerDisplay("Page Heap: {page.heap}, RetireFrame: {retireFrame}")]
|
||||
private struct RetiringPage
|
||||
{
|
||||
public Page page;
|
||||
@@ -26,14 +28,14 @@ public partial class ResourceManager
|
||||
}
|
||||
|
||||
private UnsafeList<Page> _activePages;
|
||||
private UnsafeQueue<RetiringPage> _retiringPages;
|
||||
private Queue<RetiringPage> _retiringPages;
|
||||
|
||||
private UnsafeList<Handle<GPUResource>> _oversizedTransientResources;
|
||||
|
||||
private void InitializePool()
|
||||
{
|
||||
_activePages = new UnsafeList<Page>(4, Allocator.Persistent);
|
||||
_retiringPages = new UnsafeQueue<RetiringPage>(4, Allocator.Persistent);
|
||||
_retiringPages = new Queue<RetiringPage>(4);
|
||||
_oversizedTransientResources = new UnsafeList<Handle<GPUResource>>(4, Allocator.Persistent);
|
||||
}
|
||||
|
||||
@@ -152,10 +154,10 @@ public partial class ResourceManager
|
||||
return bufHandle;
|
||||
}
|
||||
|
||||
var requiredHeapType = desc.MemoryType switch
|
||||
var requiredHeapType = desc.HeapType switch
|
||||
{
|
||||
ResourceMemoryType.Upload => HeapType.Upload,
|
||||
ResourceMemoryType.Readback => HeapType.Readback,
|
||||
HeapType.Upload => HeapType.Upload,
|
||||
HeapType.Readback => HeapType.Readback,
|
||||
_ => HeapType.Default
|
||||
};
|
||||
|
||||
@@ -265,7 +267,7 @@ public partial class ResourceManager
|
||||
}
|
||||
|
||||
_activePages.Dispose();
|
||||
_retiringPages.Dispose();
|
||||
//_retiringPages.Dispose();
|
||||
_oversizedTransientResources.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public sealed partial class ResourceManager : IDisposable
|
||||
Size = (uint)(vertices.Count * sizeof(Vertex)),
|
||||
Stride = (uint)sizeof(Vertex),
|
||||
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
HeapType = HeapType.Default,
|
||||
};
|
||||
|
||||
var indexBufferDesc = new BufferDesc
|
||||
@@ -91,7 +91,7 @@ public sealed partial class ResourceManager : IDisposable
|
||||
Size = (uint)(indices.Count * sizeof(uint)),
|
||||
Stride = sizeof(uint),
|
||||
Usage = BufferUsage.Index | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
HeapType = HeapType.Default,
|
||||
};
|
||||
|
||||
var objectBufferDesc = new BufferDesc
|
||||
@@ -99,7 +99,7 @@ public sealed partial class ResourceManager : IDisposable
|
||||
Size = (uint)sizeof(MeshData),
|
||||
Stride = (uint)sizeof(MeshData),
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Default,
|
||||
HeapType = HeapType.Default,
|
||||
};
|
||||
|
||||
var vertexBuffer = _resourceAllocator.CreateBuffer(in vertexBufferDesc, "VertexBuffer");
|
||||
|
||||
@@ -127,9 +127,9 @@ internal class SwapChainManager : IDisposable
|
||||
}
|
||||
|
||||
commandBuffer.Barrier(BarrierDesc.Texture(record.SwapChain.GetCurrentBackBuffer().AsResource(),
|
||||
null, BarrierSync.None,
|
||||
null, BarrierAccess.NoAccess,
|
||||
null, BarrierLayout.Present));
|
||||
BarrierSync.None,
|
||||
BarrierAccess.NoAccess,
|
||||
BarrierLayout.Present));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Core.Graphics;
|
||||
using Ghost.DSL.ShaderCompiler;
|
||||
using Ghost.Engine.Components;
|
||||
using Ghost.Graphics.Core;
|
||||
using Ghost.Graphics.RenderGraphModule;
|
||||
using Ghost.Graphics.RenderPipeline;
|
||||
@@ -77,9 +75,9 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
|
||||
private static float3 IntersectFrustumPlanes(float4 p0, float4 p1, float4 p2)
|
||||
{
|
||||
float3 n0 = p0.xyz;
|
||||
float3 n1 = p1.xyz;
|
||||
float3 n2 = p2.xyz;
|
||||
var n0 = p0.xyz;
|
||||
var n1 = p1.xyz;
|
||||
var n2 = p2.xyz;
|
||||
|
||||
float det = math.dot(math.cross(n0, n1), n2);
|
||||
return (math.cross(n2, n1) * p0.w + math.cross(n0, n2) * p1.w - math.cross(n0, n1) * p2.w) * (1.0f / det);
|
||||
@@ -225,7 +223,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
Size = instanceDataSize,
|
||||
Stride = (uint)sizeof(InstanceData),
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Upload, // Upload directly for simplicity in testing
|
||||
HeapType = HeapType.Upload, // Upload directly for simplicity in testing
|
||||
};
|
||||
|
||||
instanceBufferHandle = resourceManager.CreateTransientBuffer(in instanceBufferDesc, "Instance Buffer");
|
||||
@@ -255,9 +253,9 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
};
|
||||
}
|
||||
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(instanceBufferResource, null, BarrierSync.Copy, null, BarrierAccess.CopyDest));
|
||||
ctx.CommandBuffer.UploadBuffer(instanceBufferHandle, instanceDataArray.AsSpan());
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(instanceBufferResource, BarrierSync.Copy, BarrierSync.AllShading, BarrierAccess.CopyDest, BarrierAccess.ShaderResource));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(instanceBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||
ctx.UploadBuffer(instanceBufferHandle, instanceDataArray.AsSpan());
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(instanceBufferResource, BarrierSync.AllShading, BarrierAccess.ShaderResource));
|
||||
|
||||
// 2. Allocate and populate View Data buffer
|
||||
var viewBufferDesc = new BufferDesc
|
||||
@@ -265,7 +263,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
Size = (uint)sizeof(ViewData),
|
||||
Stride = (uint)sizeof(ViewData),
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Upload,
|
||||
HeapType = HeapType.Upload,
|
||||
};
|
||||
|
||||
viewBufferHandle = resourceManager.CreateTransientBuffer(in viewBufferDesc, "View Buffer");
|
||||
@@ -282,9 +280,9 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
screenSize = new float4(request.view.sensorSize.x, request.view.sensorSize.y, 1.0f / request.view.sensorSize.x, 1.0f / request.view.sensorSize.y)
|
||||
};
|
||||
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(viewBufferResource, null, BarrierSync.Copy, null, BarrierAccess.CopyDest));
|
||||
ctx.CommandBuffer.UploadBuffer(viewBufferHandle, new ReadOnlySpan<ViewData>(in viewData));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(viewBufferResource, BarrierSync.Copy, BarrierSync.AllShading, BarrierAccess.CopyDest, BarrierAccess.ShaderResource));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(viewBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||
ctx.UploadBuffer(viewBufferHandle, new ReadOnlySpan<ViewData>(in viewData));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(viewBufferResource, BarrierSync.AllShading, BarrierAccess.ShaderResource));
|
||||
|
||||
// 3. Allocate and populate Global Frame Data buffer
|
||||
var frameDataSize = (uint)sizeof(FrameData);
|
||||
@@ -293,7 +291,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
Size = frameDataSize,
|
||||
Stride = frameDataSize,
|
||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||
MemoryType = ResourceMemoryType.Upload,
|
||||
HeapType = HeapType.Upload,
|
||||
};
|
||||
|
||||
frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
||||
@@ -305,9 +303,9 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
instanceBufferIndex = resourceDatabase.GetBindlessIndex(instanceBufferResource),
|
||||
};
|
||||
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, null, BarrierSync.Copy, null, BarrierAccess.CopyDest));
|
||||
ctx.CommandBuffer.UploadBuffer(frameBufferHandle, new ReadOnlySpan<FrameData>(in frameData));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.Copy, BarrierSync.AllShading, BarrierAccess.CopyDest, BarrierAccess.ShaderResource));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||
ctx.UploadBuffer(frameBufferHandle, new ReadOnlySpan<FrameData>(in frameData));
|
||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.AllShading, BarrierAccess.ShaderResource));
|
||||
|
||||
if (request.renderFunc != null)
|
||||
{
|
||||
@@ -319,7 +317,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
|
||||
var backBuffer = _renderGraph.ImportTexture(rt, "BackBuffer");
|
||||
|
||||
MeshletDebugPass(backBuffer, request.opaqueRenderList,
|
||||
MeshletDebugPass(backBuffer, request.opaqueRenderList,
|
||||
resourceDatabase.GetBindlessIndex(frameBufferResource),
|
||||
resourceDatabase.GetBindlessIndex(viewBufferResource),
|
||||
resourceDatabase.GetBindlessIndex(instanceBufferResource));
|
||||
@@ -360,7 +358,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
||||
builder.SetColorAttachment(backbuffer, 0);
|
||||
builder.SetDepthAttachment(depth);
|
||||
|
||||
builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx)=>
|
||||
builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx) =>
|
||||
{
|
||||
ctx.SetGlobalData(data.globalIndex, data.viewIndex);
|
||||
ctx.SetInstanceData(data.instanceIndex);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ghost.Graphics.Test.Windows;
|
||||
|
||||
@@ -113,9 +114,9 @@ public sealed partial class GraphicsTestWindow : Window
|
||||
//MeshBuilder.CreateCube(0.75f, default, Allocator.Persistent, out var vertices, out var indices);
|
||||
Utilities.MeshUtility.LoadMesh("F:/c/SimpleRayTracer/native/assets/bunny.obj", Allocator.Persistent, out var vertices, out var indices).ThrowIfFailed();
|
||||
|
||||
// TODO: Put this to the beginning of the frame without createing another command buffer?
|
||||
// TODO: Put this to the beginning of the frame without creating another command buffer?
|
||||
using var directCmd = _renderSystem.GraphicsEngine.CreateCommandBuffer(CommandBufferType.Graphics);
|
||||
var ctx = new RenderingContext(_renderSystem.GraphicsEngine, _renderSystem.ResourceManager, directCmd);
|
||||
var ctx = new RenderContext(_renderSystem.GraphicsEngine, _renderSystem.ResourceManager, directCmd);
|
||||
|
||||
using var cmdAllocator = _renderSystem.GraphicsEngine.CreateCommandAllocator(CommandBufferType.Graphics);
|
||||
directCmd.Begin(cmdAllocator);
|
||||
@@ -158,7 +159,6 @@ public sealed partial class GraphicsTestWindow : Window
|
||||
|
||||
_renderSystem?.ResourceManager.ReleaseMesh(_meshHandle);
|
||||
|
||||
_swapChain?.Dispose();
|
||||
//_jobScheduler.Dispose();
|
||||
_renderSystem?.Dispose();
|
||||
|
||||
@@ -203,8 +203,9 @@ public sealed partial class GraphicsTestWindow : Window
|
||||
return;
|
||||
}
|
||||
|
||||
if (_renderSystem.CPUFenceValue < _renderSystem.GPUFenceValue + _renderSystem.MaxFrameLatency)
|
||||
if (_renderSystem.TryAcquireCPUFrame())
|
||||
{
|
||||
//Debug.WriteLine($"CPU: Frame started.");
|
||||
_world.SystemManager.UpdateAll(default);
|
||||
_renderSystem.SignalCPUReady();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user