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)
|
switch (desc.Type)
|
||||||
{
|
{
|
||||||
case BarrierType.Global:
|
case BarrierType.Global:
|
||||||
|
if (desc.SyncAfter == _resourceDatabase.globalBarrier.sync && desc.AccessAfter == _resourceDatabase.globalBarrier.access)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
pGlobalBarriers[globalIndex++] = new D3D12_GLOBAL_BARRIER
|
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,
|
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
|
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_resourceDatabase.globalBarrier = new ResourceBarrierData(BarrierLayout.Undefined, desc.AccessAfter, desc.SyncAfter);
|
||||||
break;
|
break;
|
||||||
case BarrierType.Buffer:
|
case BarrierType.Buffer:
|
||||||
{
|
{
|
||||||
@@ -218,12 +225,19 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref var record = ref r.Value;
|
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;
|
var resource = record.ResourcePtr;
|
||||||
pBufferBarriers[bufferIndex++] = new D3D12_BUFFER_BARRIER
|
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,
|
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,
|
AccessAfter = (D3D12_BARRIER_ACCESS)desc.AccessAfter,
|
||||||
pResource = resource,
|
pResource = resource,
|
||||||
Offset = 0,
|
Offset = 0,
|
||||||
@@ -243,14 +257,22 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
}
|
}
|
||||||
|
|
||||||
ref var record = ref r.Value;
|
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;
|
var resource = record.ResourcePtr;
|
||||||
pTextureBarriers[textureIndex++] = new D3D12_TEXTURE_BARRIER
|
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,
|
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,
|
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,
|
LayoutAfter = (D3D12_BARRIER_LAYOUT)desc.LayoutAfter,
|
||||||
pResource = resource,
|
pResource = resource,
|
||||||
Subresources = new D3D12_BARRIER_SUBRESOURCE_RANGE
|
Subresources = new D3D12_BARRIER_SUBRESOURCE_RANGE
|
||||||
@@ -272,39 +294,44 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
|
|||||||
var groups = stackalloc D3D12_BARRIER_GROUP[3];
|
var groups = stackalloc D3D12_BARRIER_GROUP[3];
|
||||||
var groupCount = 0u;
|
var groupCount = 0u;
|
||||||
|
|
||||||
if (globalCount > 0)
|
if (globalIndex > 0)
|
||||||
{
|
{
|
||||||
groups[groupCount] = new D3D12_BARRIER_GROUP
|
groups[groupCount] = new D3D12_BARRIER_GROUP
|
||||||
{
|
{
|
||||||
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_GLOBAL,
|
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_GLOBAL,
|
||||||
NumBarriers = (uint)globalCount,
|
NumBarriers = (uint)globalIndex,
|
||||||
};
|
};
|
||||||
groups[groupCount].Anonymous.pGlobalBarriers = pGlobalBarriers;
|
groups[groupCount].Anonymous.pGlobalBarriers = pGlobalBarriers;
|
||||||
groupCount++;
|
groupCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bufferCount > 0)
|
if (bufferIndex > 0)
|
||||||
{
|
{
|
||||||
groups[groupCount] = new D3D12_BARRIER_GROUP
|
groups[groupCount] = new D3D12_BARRIER_GROUP
|
||||||
{
|
{
|
||||||
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_BUFFER,
|
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_BUFFER,
|
||||||
NumBarriers = (uint)bufferCount,
|
NumBarriers = (uint)bufferIndex,
|
||||||
};
|
};
|
||||||
groups[groupCount].Anonymous.pBufferBarriers = pBufferBarriers;
|
groups[groupCount].Anonymous.pBufferBarriers = pBufferBarriers;
|
||||||
groupCount++;
|
groupCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textureCount > 0)
|
if (textureIndex > 0)
|
||||||
{
|
{
|
||||||
groups[groupCount] = new D3D12_BARRIER_GROUP
|
groups[groupCount] = new D3D12_BARRIER_GROUP
|
||||||
{
|
{
|
||||||
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_TEXTURE,
|
Type = D3D12_BARRIER_TYPE.D3D12_BARRIER_TYPE_TEXTURE,
|
||||||
NumBarriers = (uint)textureCount,
|
NumBarriers = (uint)textureIndex,
|
||||||
};
|
};
|
||||||
groups[groupCount].Anonymous.pTextureBarriers = pTextureBarriers;
|
groups[groupCount].Anonymous.pTextureBarriers = pTextureBarriers;
|
||||||
groupCount++;
|
groupCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (groupCount == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pNativeObject->Barrier(groupCount, groups);
|
pNativeObject->Barrier(groupCount, groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
|||||||
fs.Write(buffer.AsSpan());
|
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)
|
if (reflectionData.ResourcesBindings.Count > RootSignatureLayout.ROOT_PARAMETER_COUNT)
|
||||||
{
|
{
|
||||||
@@ -149,7 +149,7 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
|||||||
|
|
||||||
if (reflectionData.ResourcesBindings.Count == 0)
|
if (reflectionData.ResourcesBindings.Count == 0)
|
||||||
{
|
{
|
||||||
return Result.Success(default(CBufferInfo));
|
return Result.Success();
|
||||||
}
|
}
|
||||||
|
|
||||||
var rootConstant = reflectionData.ResourcesBindings[0];
|
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.");
|
return Result.Failure($"Root constant buffer size must be {sizeof(PushConstantsData)} bytes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var cbufferInfo = new CBufferInfo
|
return Result.Success();
|
||||||
{
|
|
||||||
Name = rootConstant.Name,
|
|
||||||
RegisterSlot = rootConstant.BindPoint,
|
|
||||||
RegisterSpace = rootConstant.Space,
|
|
||||||
SizeInBytes = rootConstant.Size,
|
|
||||||
Properties = rootConstant.Properties
|
|
||||||
};
|
|
||||||
|
|
||||||
return Result.Success(cbufferInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static D3D12_DEPTH_STENCIL_DESC BuildDepthStencil(ZTest ztest, ZWrite zwrite)
|
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)
|
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);
|
var msr = ValidateReflectionData(compiled.msResult.reflectionData);
|
||||||
if (msr.IsFailure)
|
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);
|
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)
|
if (compiled.tsResult.IsCreated)
|
||||||
{
|
{
|
||||||
var tsr = ValidateReflectionData(compiled.tsResult.reflectionData);
|
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);
|
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 Result.Success();
|
||||||
return psr.Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AssertNotDisposed();
|
AssertNotDisposed();
|
||||||
@@ -236,11 +214,11 @@ internal unsafe class D3D12PipelineLibrary : D3D12Object<ID3D12PipelineLibrary1>
|
|||||||
|
|
||||||
if (!_pipelineCache.ContainsKey(pipelineKey))
|
if (!_pipelineCache.ContainsKey(pipelineKey))
|
||||||
{
|
{
|
||||||
//var result = ValidatePassReflectionData(in compiled);
|
var result = ValidatePassReflectionData(in compiled);
|
||||||
//if (result.IsFailure)
|
if (result.IsFailure)
|
||||||
//{
|
{
|
||||||
// return Result.Failure(result.Message);
|
return result;
|
||||||
//}
|
}
|
||||||
|
|
||||||
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
|
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -437,17 +437,6 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
|||||||
|
|
||||||
return uavDesc;
|
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
|
internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||||
@@ -658,7 +647,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
Handle<GPUResource> resource;
|
Handle<GPUResource> resource;
|
||||||
if (isSubAllocation)
|
if (isSubAllocation)
|
||||||
{
|
{
|
||||||
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, name);
|
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, ResourceDesc.Texture(desc), name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -686,7 +675,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
|
|
||||||
var allocationDesc = new D3D12MA_ALLOCATION_DESC
|
var allocationDesc = new D3D12MA_ALLOCATION_DESC
|
||||||
{
|
{
|
||||||
HeapType = ConvertMemoryType(desc.MemoryType),
|
HeapType = desc.HeapType.ToD3D12HeapType(),
|
||||||
Flags = D3D12MA_ALLOCATION_FLAG_NONE,
|
Flags = D3D12MA_ALLOCATION_FLAG_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -695,11 +684,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
ID3D12Resource* pResource = default;
|
ID3D12Resource* pResource = default;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
var initialState = desc.MemoryType switch
|
var initialState = desc.HeapType switch
|
||||||
{
|
{
|
||||||
ResourceMemoryType.Default => D3D12_RESOURCE_STATE_COMMON,
|
HeapType.Default => D3D12_RESOURCE_STATE_COMMON,
|
||||||
ResourceMemoryType.Upload => D3D12_RESOURCE_STATE_GENERIC_READ,
|
HeapType.Upload => D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||||
ResourceMemoryType.Readback => D3D12_RESOURCE_STATE_COPY_DEST,
|
HeapType.Readback => D3D12_RESOURCE_STATE_COPY_DEST,
|
||||||
_ => D3D12_RESOURCE_STATE_COMMON
|
_ => D3D12_RESOURCE_STATE_COMMON
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -770,7 +759,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
|||||||
Handle<GPUResource> resource;
|
Handle<GPUResource> resource;
|
||||||
if (isSubAllocation)
|
if (isSubAllocation)
|
||||||
{
|
{
|
||||||
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, name);
|
resource = _resourceDatabase.ImportExternalResource(pResource, barrierData, resourceDescriptor, ResourceDesc.Buffer(desc), name);
|
||||||
}
|
}
|
||||||
else
|
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 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 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.resource = new ResourceUnion(allocation);
|
||||||
this.isExternal = false;
|
this.isExternal = false;
|
||||||
|
|
||||||
this.viewGroup = resourceDescriptor;
|
this.viewGroup = viewGroup;
|
||||||
this.barrierData = barrierData;
|
this.barrierData = barrierData;
|
||||||
this.desc = desc;
|
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.resource = new ResourceUnion(resource);
|
||||||
this.isExternal = true;
|
this.isExternal = true;
|
||||||
|
|
||||||
this.viewGroup = viewGroup;
|
this.viewGroup = viewGroup;
|
||||||
this.barrierData = barrierData;
|
this.barrierData = barrierData;
|
||||||
this.desc = resource->GetDesc().ToResourceDesc();
|
this.desc = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly uint Release(D3D12DescriptorAllocator descriptorAllocator)
|
public readonly uint Release(D3D12DescriptorAllocator descriptorAllocator)
|
||||||
@@ -112,6 +112,8 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
private ulong _cpuFrame;
|
private ulong _cpuFrame;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
|
public ResourceBarrierData globalBarrier;
|
||||||
|
|
||||||
public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator)
|
public D3D12ResourceDatabase(D3D12DescriptorAllocator descriptorAllocator)
|
||||||
{
|
{
|
||||||
_descriptorAllocator = descriptorAllocator;
|
_descriptorAllocator = descriptorAllocator;
|
||||||
@@ -130,7 +132,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
Dispose();
|
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);
|
Debug.Assert(!_disposed);
|
||||||
|
|
||||||
@@ -150,7 +152,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
|
|
||||||
try
|
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);
|
var handle = new Handle<GPUResource>(id, generation);
|
||||||
|
|
||||||
#if DEBUG || GHOST_EDITOR
|
#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);
|
Debug.Assert(!_disposed);
|
||||||
|
|
||||||
@@ -399,7 +401,7 @@ internal unsafe class D3D12ResourceDatabase : IResourceDatabase
|
|||||||
return Error.None;
|
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);
|
var r = GetResourceRecord(handle);
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ internal unsafe class DXGISwapChain : ISwapChain
|
|||||||
sync = BarrierSync.None,
|
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();
|
_backBuffers[i] = handle.AsTexture();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
|
using Ghost.Graphics.RHI;
|
||||||
|
|
||||||
namespace Ghost.Graphics.D3D12;
|
namespace Ghost.Graphics.D3D12;
|
||||||
|
|
||||||
@@ -25,4 +26,52 @@ internal struct ResourceViewGroup
|
|||||||
uav = Identifier<CbvSrvUavDescriptor>.Invalid,
|
uav = Identifier<CbvSrvUavDescriptor>.Invalid,
|
||||||
sampler = Identifier<SamplerDescriptor>.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)
|
public static D3D12_HEAP_FLAGS ToD3D12HeapFlags(this HeapFlags flags)
|
||||||
{
|
{
|
||||||
return flags switch
|
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)
|
public static D3D12_RESOURCE_DESC ToD3D12ResourceDesc(this in TextureDesc desc)
|
||||||
{
|
{
|
||||||
var dxgiFormat = desc.Format.ToDXGIFormat();
|
var dxgiFormat = desc.Format.ToDXGIFormat();
|
||||||
@@ -497,17 +526,22 @@ internal static unsafe class D3D12Utility
|
|||||||
return D3D12_RESOURCE_DESC.Buffer(alignedSize, resourceFlags);
|
return D3D12_RESOURCE_DESC.Buffer(alignedSize, resourceFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ResourceDesc GetResourceDesc(ID3D12Resource* pResource, ResourceViewGroup viewGroup)
|
||||||
public static ResourceDesc ToResourceDesc(this D3D12_RESOURCE_DESC desc)
|
|
||||||
{
|
{
|
||||||
|
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)
|
if (desc.Dimension == D3D12_RESOURCE_DIMENSION.D3D12_RESOURCE_DIMENSION_BUFFER)
|
||||||
{
|
{
|
||||||
return ResourceDesc.Buffer(new BufferDesc
|
return ResourceDesc.Buffer(new BufferDesc
|
||||||
{
|
{
|
||||||
Size = (uint)desc.Width,
|
Size = (uint)desc.Width,
|
||||||
Stride = 0,
|
Stride = 0,
|
||||||
Usage = BufferUsage.None,
|
Usage = viewGroup.GetBufferUsage(),
|
||||||
MemoryType = ResourceMemoryType.Default
|
HeapType = heapProperties.Type.ToHeapType()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -520,7 +554,7 @@ internal static unsafe class D3D12Utility
|
|||||||
Format = desc.Format.ToTextureFormat(),
|
Format = desc.Format.ToTextureFormat(),
|
||||||
Dimension = desc.Dimension.ToTextureDimension(),
|
Dimension = desc.Dimension.ToTextureDimension(),
|
||||||
MipLevels = desc.MipLevels,
|
MipLevels = desc.MipLevels,
|
||||||
Usage = TextureUsage.None,
|
Usage = viewGroup.GetTextureUsage(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -556,31 +556,16 @@ public struct BarrierDesc
|
|||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarrierSync? SyncBefore
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BarrierSync SyncAfter
|
public BarrierSync SyncAfter
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarrierAccess? AccessBefore
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BarrierAccess AccessAfter
|
public BarrierAccess AccessAfter
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarrierLayout? LayoutBefore
|
|
||||||
{
|
|
||||||
get; set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BarrierLayout LayoutAfter
|
public BarrierLayout LayoutAfter
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
@@ -601,45 +586,45 @@ public struct BarrierDesc
|
|||||||
get; set;
|
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
|
return new BarrierDesc
|
||||||
{
|
{
|
||||||
Type = BarrierType.Global,
|
Type = BarrierType.Global,
|
||||||
SyncBefore = syncBefore,
|
|
||||||
SyncAfter = syncAfter,
|
SyncAfter = syncAfter,
|
||||||
AccessBefore = accessBefore,
|
|
||||||
AccessAfter = accessAfter
|
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
|
return new BarrierDesc
|
||||||
{
|
{
|
||||||
Type = BarrierType.Buffer,
|
Type = BarrierType.Buffer,
|
||||||
Resource = resource,
|
Resource = resource,
|
||||||
SyncBefore = syncBefore,
|
|
||||||
SyncAfter = syncAfter,
|
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
|
return new BarrierDesc
|
||||||
{
|
{
|
||||||
Type = BarrierType.Texture,
|
Type = BarrierType.Texture,
|
||||||
Resource = resource,
|
Resource = resource,
|
||||||
SyncBefore = syncBefore,
|
|
||||||
SyncAfter = syncAfter,
|
SyncAfter = syncAfter,
|
||||||
AccessBefore = accessBefore,
|
|
||||||
AccessAfter = accessAfter,
|
AccessAfter = accessAfter,
|
||||||
LayoutBefore = layoutBefore,
|
|
||||||
LayoutAfter = layoutAfter,
|
LayoutAfter = layoutAfter,
|
||||||
Subresources = subresources,
|
Subresources = subresources,
|
||||||
Discard = discard
|
Discard = discard,
|
||||||
|
IsAliasing = isAliasing
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -724,6 +709,16 @@ public record struct ResourceDesc
|
|||||||
_ => throw new InvalidOperationException($"Unknown resource type: {Type}")
|
_ => 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>
|
/// <summary>
|
||||||
@@ -998,7 +993,7 @@ public record struct BufferDesc
|
|||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceMemoryType MemoryType
|
public HeapType HeapType
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
@@ -1255,13 +1250,6 @@ public enum RenderTargetCreationFlags
|
|||||||
GenerateMips = 1 << 3
|
GenerateMips = 1 << 3
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ResourceMemoryType
|
|
||||||
{
|
|
||||||
Default, // GPU memory
|
|
||||||
Upload, // CPU-to-GPU memory
|
|
||||||
Readback // GPU-to-CPU memory
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ResourceType
|
public enum ResourceType
|
||||||
{
|
{
|
||||||
Texture,
|
Texture,
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ public unsafe interface IResourceDatabase : IDisposable
|
|||||||
/// <returns>An Error indicating the success or failure of the swap operation.</returns>
|
/// <returns>An Error indicating the success or failure of the swap operation.</returns>
|
||||||
Error Swap(Handle<GPUResource> handleA, Handle<GPUResource> handleB);
|
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);
|
ulong GetIntermediateResourceSize(Handle<GPUResource> resource, uint firstSubResource, uint numSubResources);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public struct Material : IResourceReleasable
|
|||||||
{
|
{
|
||||||
Size = shader.CBufferSize,
|
Size = shader.CBufferSize,
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
HeapType = HeapType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
var buffer = resourceAllocator.CreateBuffer(ref desc, "MaterialCBuffer");
|
var buffer = resourceAllocator.CreateBuffer(ref desc, "MaterialCBuffer");
|
||||||
@@ -243,7 +243,7 @@ public struct Material : IResourceReleasable
|
|||||||
return _keywordMask.IsKeywordEnabled(localIndex);
|
return _keywordMask.IsKeywordEnabled(localIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly void UploadData(ICommandBuffer cmd, IResourceDatabase resourceDatabase)
|
public readonly void UploadData(RenderContext ctx)
|
||||||
{
|
{
|
||||||
if (!_isDirty)
|
if (!_isDirty)
|
||||||
{
|
{
|
||||||
@@ -251,31 +251,20 @@ public struct Material : IResourceReleasable
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cbufferResource = _cBufferCache.GpuResource.AsResource();
|
var cbufferResource = _cBufferCache.GpuResource.AsResource();
|
||||||
var r = resourceDatabase.GetResourceBarrierData(cbufferResource);
|
|
||||||
if (r.IsFailure)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var barrierData = r.Value;
|
|
||||||
var desc = BarrierDesc.Buffer(
|
var desc = BarrierDesc.Buffer(
|
||||||
cbufferResource,
|
cbufferResource,
|
||||||
barrierData.sync,
|
|
||||||
BarrierSync.Copy,
|
BarrierSync.Copy,
|
||||||
barrierData.access,
|
|
||||||
BarrierAccess.CopyDest);
|
BarrierAccess.CopyDest);
|
||||||
|
|
||||||
cmd.Barrier(desc);
|
ctx.CommandBuffer.Barrier(desc);
|
||||||
cmd.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
|
ctx.UploadBuffer(_cBufferCache.GpuResource, _cBufferCache.CpuData.AsSpan());
|
||||||
|
|
||||||
desc = BarrierDesc.Buffer(
|
desc = BarrierDesc.Buffer(
|
||||||
cbufferResource,
|
cbufferResource,
|
||||||
BarrierSync.Copy,
|
|
||||||
BarrierSync.AllShading,
|
BarrierSync.AllShading,
|
||||||
BarrierAccess.CopyDest,
|
|
||||||
BarrierAccess.ShaderResource);
|
BarrierAccess.ShaderResource);
|
||||||
|
|
||||||
cmd.Barrier(desc);
|
ctx.CommandBuffer.Barrier(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReleaseResource(IResourceDatabase database)
|
public void ReleaseResource(IResourceDatabase database)
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ using System.Diagnostics;
|
|||||||
namespace Ghost.Graphics.Core;
|
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.
|
// 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 IGraphicsEngine _engine;
|
||||||
private readonly ResourceManager _resourceManager;
|
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 IShaderCompiler ShaderCompiler => _engine.ShaderCompiler;
|
||||||
public ResourceManager ResourceManager => _resourceManager;
|
public ResourceManager ResourceManager => _resourceManager;
|
||||||
@@ -21,69 +21,29 @@ public readonly unsafe ref struct RenderingContext
|
|||||||
public IResourceDatabase ResourceDatabase => _engine.ResourceDatabase;
|
public IResourceDatabase ResourceDatabase => _engine.ResourceDatabase;
|
||||||
public IPipelineLibrary PipelineLibrary => _engine.PipelineLibrary;
|
public IPipelineLibrary PipelineLibrary => _engine.PipelineLibrary;
|
||||||
|
|
||||||
internal RenderingContext(IGraphicsEngine engine, ResourceManager resourceManager, ICommandBuffer directCmd)
|
internal RenderContext(IGraphicsEngine engine, ResourceManager resourceManager, ICommandBuffer cmd)
|
||||||
{
|
{
|
||||||
_engine = engine;
|
_engine = engine;
|
||||||
_resourceManager = resourceManager;
|
_resourceManager = resourceManager;
|
||||||
_directCmd = directCmd;
|
_cmd = cmd;
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TransitionBarrier(Handle<GPUResource> resource, bool isTexture, BarrierLayout newLayout, BarrierAccess newAccess, BarrierSync newSync)
|
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;
|
BarrierDesc desc;
|
||||||
if (isTexture)
|
if (isTexture)
|
||||||
{
|
{
|
||||||
desc = BarrierDesc.Texture(
|
desc = BarrierDesc.Texture(resource, newSync, newAccess, newLayout);
|
||||||
resource,
|
|
||||||
data.sync, newSync,
|
|
||||||
data.access, newAccess,
|
|
||||||
data.layout, newLayout);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
desc = BarrierDesc.Buffer(
|
desc = BarrierDesc.Buffer(resource, newSync, newAccess);
|
||||||
resource,
|
|
||||||
data.sync, newSync,
|
|
||||||
data.access, newAccess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_directCmd.Barrier(new ReadOnlySpan<BarrierDesc>(in desc));
|
_cmd.Barrier(desc);
|
||||||
ResourceDatabase.SetResourceBarrierData(resource, new ResourceBarrierData(newLayout, newAccess, newSync));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
where T : unmanaged
|
||||||
{
|
{
|
||||||
var r = _engine.ResourceDatabase.GetResourceDescription(buffer.AsResource());
|
var r = _engine.ResourceDatabase.GetResourceDescription(buffer.AsResource());
|
||||||
@@ -95,34 +55,43 @@ public readonly unsafe ref struct RenderingContext
|
|||||||
Debug.Assert(r.Value.Type == ResourceType.Buffer);
|
Debug.Assert(r.Value.Type == ResourceType.Buffer);
|
||||||
|
|
||||||
var sizeInBytes = (nuint)(data.Length * sizeof(T));
|
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)
|
fixed (T* pData = data)
|
||||||
{
|
{
|
||||||
ResourceDatabase.Map(buffer.AsResource(), 0, null, null, pData, sizeInBytes);
|
ResourceDatabase.MapResource(buffer.AsResource(), 0, null, null, pData, sizeInBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(sizeInBytes, out var offset);
|
|
||||||
//var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
|
|
||||||
var uploadDesc = new BufferDesc
|
var uploadDesc = new BufferDesc
|
||||||
{
|
{
|
||||||
Size = sizeInBytes,
|
Size = sizeInBytes,
|
||||||
Usage = BufferUsage.Upload,
|
Usage = BufferUsage.Upload,
|
||||||
MemoryType = ResourceMemoryType.Upload,
|
HeapType = HeapType.Upload,
|
||||||
};
|
};
|
||||||
|
|
||||||
var uploadHandle = _resourceManager.CreateTransientBuffer(in uploadDesc);
|
var uploadHandle = _resourceManager.CreateTransientBuffer(in uploadDesc);
|
||||||
|
if (uploadHandle.IsInvalid)
|
||||||
fixed (T* pData = data)
|
|
||||||
{
|
{
|
||||||
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);
|
return CreateMesh(vertexList, indexList, staticMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Make one memory pool for upload.
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Uploads the mesh data to the GPU.
|
/// Uploads the mesh data to the GPU.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -221,14 +188,14 @@ public readonly unsafe ref struct RenderingContext
|
|||||||
Size = (uint)(meshletData.meshlets.Count * sizeof(Meshlet)),
|
Size = (uint)(meshletData.meshlets.Count * sizeof(Meshlet)),
|
||||||
Stride = (uint)sizeof(Meshlet),
|
Stride = (uint)sizeof(Meshlet),
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
HeapType = HeapType.Default,
|
||||||
};
|
};
|
||||||
var verticesDesc = new BufferDesc
|
var verticesDesc = new BufferDesc
|
||||||
{
|
{
|
||||||
Size = (uint)(meshletData.meshletVertices.Count * sizeof(uint)),
|
Size = (uint)(meshletData.meshletVertices.Count * sizeof(uint)),
|
||||||
Stride = sizeof(uint),
|
Stride = sizeof(uint),
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
HeapType = HeapType.Default,
|
||||||
};
|
};
|
||||||
// Ensure size is multiple of 4 for Raw buffer
|
// Ensure size is multiple of 4 for Raw buffer
|
||||||
var trianglesSize = (uint)meshletData.meshletTriangles.Count * sizeof(uint);
|
var trianglesSize = (uint)meshletData.meshletTriangles.Count * sizeof(uint);
|
||||||
@@ -237,7 +204,7 @@ public readonly unsafe ref struct RenderingContext
|
|||||||
Size = trianglesSize,
|
Size = trianglesSize,
|
||||||
Stride = sizeof(uint),
|
Stride = sizeof(uint),
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
HeapType = HeapType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
meshRef.MeshLetBuffer = _engine.ResourceAllocator.CreateBuffer(in meshletDesc, "Meshlets");
|
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)
|
public void UploadTexture<T>(Handle<GPUTexture> texture, ReadOnlySpan<T> data)
|
||||||
where T : unmanaged
|
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();
|
var desc = ResourceDatabase.GetResourceDescription(texture.AsResource()).GetValueOrThrow();
|
||||||
desc.TextureDescription.Format.GetSurfaceInfo(desc.TextureDescription.Width, desc.TextureDescription.Height, out var rowPitch, out var slicePitch, out _);
|
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,
|
Size = requiredSize,
|
||||||
Usage = BufferUsage.Upload,
|
Usage = BufferUsage.Upload,
|
||||||
MemoryType = ResourceMemoryType.Upload,
|
HeapType = HeapType.Upload,
|
||||||
};
|
};
|
||||||
|
|
||||||
var uploadHandle = _resourceManager.CreateTransientBuffer(in uploadDesc);
|
var uploadHandle = _resourceManager.CreateTransientBuffer(in uploadDesc);
|
||||||
@@ -319,6 +280,8 @@ public readonly unsafe ref struct RenderingContext
|
|||||||
throw new OutOfMemoryException("Failed to create upload buffer for texture data.");
|
throw new OutOfMemoryException("Failed to create upload buffer for texture data.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
TransitionBarrier(texture.AsResource(), true, BarrierLayout.CopyDest, BarrierAccess.CopyDest, BarrierSync.Copy);
|
TransitionBarrier(texture.AsResource(), true, BarrierLayout.CopyDest, BarrierAccess.CopyDest, BarrierSync.Copy);
|
||||||
|
|
||||||
fixed (T* pData = data)
|
fixed (T* pData = data)
|
||||||
@@ -330,7 +293,12 @@ public readonly unsafe ref struct RenderingContext
|
|||||||
slicePitch = slicePitch
|
slicePitch = slicePitch
|
||||||
};
|
};
|
||||||
|
|
||||||
_directCmd.UpdateSubResources(texture.AsResource(), uploadHandle.AsResource(), subresourceData);
|
_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
|
// 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)
|
while (barrierIndex < compiledBarriers.Count && compiledBarriers[barrierIndex].PassIndex == passIndex)
|
||||||
{
|
{
|
||||||
var compiledBarrier = compiledBarriers[barrierIndex++];
|
var compiledBarrier = compiledBarriers[barrierIndex++];
|
||||||
@@ -231,60 +232,23 @@ internal sealed class RenderGraphExecutor
|
|||||||
}
|
}
|
||||||
|
|
||||||
var currentState = currentStateResult.Value;
|
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;
|
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
|
// Create barrier descriptor
|
||||||
BarrierDesc desc;
|
BarrierDesc desc;
|
||||||
if (compiledBarrier.ResourceType == RenderGraphResourceType.Texture)
|
if (compiledBarrier.ResourceType == RenderGraphResourceType.Texture)
|
||||||
{
|
{
|
||||||
desc = BarrierDesc.Texture(resourceHandle,
|
desc = BarrierDesc.Texture(resourceHandle, target.sync, target.access, target.layout,
|
||||||
syncBefore, target.sync,
|
|
||||||
accessBefore, target.access,
|
|
||||||
layoutBefore, target.layout,
|
|
||||||
discard: compiledBarrier.Flags.HasFlag(BarrierFlags.Discard));
|
discard: compiledBarrier.Flags.HasFlag(BarrierFlags.Discard));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
desc = BarrierDesc.Buffer(resourceHandle,
|
desc = BarrierDesc.Buffer(resourceHandle, target.sync, target.access);
|
||||||
syncBefore, target.sync,
|
}
|
||||||
accessBefore, target.access);
|
|
||||||
|
if (compiledBarrier.AliasingPredecessor.IsValid)
|
||||||
|
{
|
||||||
|
desc.IsAliasing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (barrierCount >= MaxBatch)
|
if (barrierCount >= MaxBatch)
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
|
using Ghost.Core;
|
||||||
using Ghost.Graphics.Core;
|
using Ghost.Graphics.Core;
|
||||||
using Ghost.Graphics.RHI;
|
using Ghost.Graphics.RHI;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ghost.Graphics.RenderPipeline;
|
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
|
public interface IRenderPipelineSettings
|
||||||
{
|
{
|
||||||
IRenderPipeline CreatePipeline(RenderSystem renderSystem);
|
IRenderPipeline CreatePipeline(RenderSystem renderSystem);
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ public class RenderSystem : IDisposable
|
|||||||
|
|
||||||
private uint _frameIndex;
|
private uint _frameIndex;
|
||||||
private ulong _cpuFenceValue;
|
private ulong _cpuFenceValue;
|
||||||
private ulong _gpuFenceValue;
|
private ulong _submittedFenceValue;
|
||||||
|
private ulong _completedFenceValue;
|
||||||
|
|
||||||
private bool _isRunning;
|
private bool _isRunning;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
@@ -112,7 +113,8 @@ public class RenderSystem : IDisposable
|
|||||||
public bool IsRunning => _isRunning;
|
public bool IsRunning => _isRunning;
|
||||||
|
|
||||||
public ulong CPUFenceValue => _cpuFenceValue;
|
public ulong CPUFenceValue => _cpuFenceValue;
|
||||||
public ulong GPUFenceValue => _gpuFenceValue;
|
public ulong SubmittedFenceValue => _submittedFenceValue;
|
||||||
|
public ulong CompletedFenceValue => _completedFenceValue;
|
||||||
public uint FrameIndex => _frameIndex;
|
public uint FrameIndex => _frameIndex;
|
||||||
public uint MaxFrameLatency => _config.FrameBufferCount;
|
public uint MaxFrameLatency => _config.FrameBufferCount;
|
||||||
|
|
||||||
@@ -219,7 +221,7 @@ public class RenderSystem : IDisposable
|
|||||||
|
|
||||||
while (_isRunning)
|
while (_isRunning)
|
||||||
{
|
{
|
||||||
_frameIndex = (uint)(_gpuFenceValue % _config.FrameBufferCount);
|
_frameIndex = (uint)(_submittedFenceValue % _config.FrameBufferCount);
|
||||||
ref var frameResource = ref _frameResources[_frameIndex];
|
ref var frameResource = ref _frameResources[_frameIndex];
|
||||||
|
|
||||||
// Wait for either CPU ready signal or shutdown signal
|
// Wait for either CPU ready signal or shutdown signal
|
||||||
@@ -242,17 +244,7 @@ public class RenderSystem : IDisposable
|
|||||||
|
|
||||||
if (!_resizeRequest.IsEmpty)
|
if (!_resizeRequest.IsEmpty)
|
||||||
{
|
{
|
||||||
_gpuFenceValue++;
|
WaitIdle();
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
var keys = _resizeRequest.Keys.ToArray();
|
var keys = _resizeRequest.Keys.ToArray();
|
||||||
foreach (var swapChain in keys)
|
foreach (var swapChain in keys)
|
||||||
@@ -262,17 +254,19 @@ public class RenderSystem : IDisposable
|
|||||||
swapChain.Resize(newSize.x, newSize.y);
|
swapChain.Resize(newSize.x, newSize.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
frameResource.GpuReadyEvent.Set();
|
_completedFenceValue = _graphicsEngine.Device.GraphicsQueue.GetCompletedValue();
|
||||||
|
if (_submittedFenceValue < _completedFenceValue)
|
||||||
continue; // Skip rendering this frame since we just resized and may have invalid render targets
|
{
|
||||||
|
_submittedFenceValue = _completedFenceValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin rendering for this frame
|
// Begin rendering for this frame
|
||||||
frameResource.CommandAllocator.Reset();
|
frameResource.CommandAllocator.Reset();
|
||||||
|
|
||||||
_resourceManager.BeginFrame(_cpuFenceValue);
|
_resourceManager.BeginFrame(_submittedFenceValue + 1);
|
||||||
var r = _graphicsEngine.BeginFrame(_cpuFenceValue);
|
var r = _graphicsEngine.BeginFrame(_submittedFenceValue + 1);
|
||||||
|
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
@@ -290,11 +284,9 @@ public class RenderSystem : IDisposable
|
|||||||
{
|
{
|
||||||
cmd.Begin(frameResource.CommandAllocator);
|
cmd.Begin(frameResource.CommandAllocator);
|
||||||
|
|
||||||
var renderCtx = new RenderContext
|
var renderCtx = new RenderContext(_graphicsEngine, _resourceManager, cmd);
|
||||||
{
|
|
||||||
CommandBuffer = cmd
|
|
||||||
};
|
|
||||||
|
|
||||||
|
//Debug.WriteLine($"GPU: Frame started.");
|
||||||
_renderPipeline.Render(renderCtx, renderRequests.AsSpan());
|
_renderPipeline.Render(renderCtx, renderRequests.AsSpan());
|
||||||
_swapChainManager.TransitionToPresent(cmd);
|
_swapChainManager.TransitionToPresent(cmd);
|
||||||
|
|
||||||
@@ -321,9 +313,9 @@ public class RenderSystem : IDisposable
|
|||||||
renderRequests.Clear();
|
renderRequests.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// End the frame and present
|
// End the frame and retire resources based on actual GPU progress.
|
||||||
_resourceManager.EndFrame(_gpuFenceValue);
|
_resourceManager.EndFrame(_completedFenceValue);
|
||||||
r = _graphicsEngine.EndFrame(_gpuFenceValue);
|
r = _graphicsEngine.EndFrame(_completedFenceValue);
|
||||||
|
|
||||||
if (r.IsFailure)
|
if (r.IsFailure)
|
||||||
{
|
{
|
||||||
@@ -331,11 +323,9 @@ public class RenderSystem : IDisposable
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for the next frame.
|
_submittedFenceValue++;
|
||||||
_gpuFenceValue++;
|
|
||||||
|
|
||||||
frameResource.GpuReadyEvent.Set();
|
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);
|
_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)
|
public void AddRenderRequest(in RenderRequest request)
|
||||||
{
|
{
|
||||||
Debug.Assert(!_disposed, "Cannot add render request to a disposed RenderSystem.");
|
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
|
private const ulong _DEFAULT_TRANSIENT_PAGE_SIZE = 16 * 1024 * 1024; // 16MB
|
||||||
|
|
||||||
|
[DebuggerDisplay("Heap: {heap}, Offset: {offset}, HeapType: {heapType}, HeapFlags: {heapFlags}")]
|
||||||
private struct Page
|
private struct Page
|
||||||
{
|
{
|
||||||
public Handle<GPUResource> heap;
|
public Handle<GPUResource> heap;
|
||||||
@@ -19,6 +20,7 @@ public partial class ResourceManager
|
|||||||
public HeapType heapType;
|
public HeapType heapType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DebuggerDisplay("Page Heap: {page.heap}, RetireFrame: {retireFrame}")]
|
||||||
private struct RetiringPage
|
private struct RetiringPage
|
||||||
{
|
{
|
||||||
public Page page;
|
public Page page;
|
||||||
@@ -26,14 +28,14 @@ public partial class ResourceManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
private UnsafeList<Page> _activePages;
|
private UnsafeList<Page> _activePages;
|
||||||
private UnsafeQueue<RetiringPage> _retiringPages;
|
private Queue<RetiringPage> _retiringPages;
|
||||||
|
|
||||||
private UnsafeList<Handle<GPUResource>> _oversizedTransientResources;
|
private UnsafeList<Handle<GPUResource>> _oversizedTransientResources;
|
||||||
|
|
||||||
private void InitializePool()
|
private void InitializePool()
|
||||||
{
|
{
|
||||||
_activePages = new UnsafeList<Page>(4, Allocator.Persistent);
|
_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);
|
_oversizedTransientResources = new UnsafeList<Handle<GPUResource>>(4, Allocator.Persistent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,10 +154,10 @@ public partial class ResourceManager
|
|||||||
return bufHandle;
|
return bufHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
var requiredHeapType = desc.MemoryType switch
|
var requiredHeapType = desc.HeapType switch
|
||||||
{
|
{
|
||||||
ResourceMemoryType.Upload => HeapType.Upload,
|
HeapType.Upload => HeapType.Upload,
|
||||||
ResourceMemoryType.Readback => HeapType.Readback,
|
HeapType.Readback => HeapType.Readback,
|
||||||
_ => HeapType.Default
|
_ => HeapType.Default
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -265,7 +267,7 @@ public partial class ResourceManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
_activePages.Dispose();
|
_activePages.Dispose();
|
||||||
_retiringPages.Dispose();
|
//_retiringPages.Dispose();
|
||||||
_oversizedTransientResources.Dispose();
|
_oversizedTransientResources.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public sealed partial class ResourceManager : IDisposable
|
|||||||
Size = (uint)(vertices.Count * sizeof(Vertex)),
|
Size = (uint)(vertices.Count * sizeof(Vertex)),
|
||||||
Stride = (uint)sizeof(Vertex),
|
Stride = (uint)sizeof(Vertex),
|
||||||
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw,
|
Usage = BufferUsage.Vertex | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
HeapType = HeapType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
var indexBufferDesc = new BufferDesc
|
var indexBufferDesc = new BufferDesc
|
||||||
@@ -91,7 +91,7 @@ public sealed partial class ResourceManager : IDisposable
|
|||||||
Size = (uint)(indices.Count * sizeof(uint)),
|
Size = (uint)(indices.Count * sizeof(uint)),
|
||||||
Stride = sizeof(uint),
|
Stride = sizeof(uint),
|
||||||
Usage = BufferUsage.Index | BufferUsage.ShaderResource | BufferUsage.Raw,
|
Usage = BufferUsage.Index | BufferUsage.ShaderResource | BufferUsage.Raw,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
HeapType = HeapType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
var objectBufferDesc = new BufferDesc
|
var objectBufferDesc = new BufferDesc
|
||||||
@@ -99,7 +99,7 @@ public sealed partial class ResourceManager : IDisposable
|
|||||||
Size = (uint)sizeof(MeshData),
|
Size = (uint)sizeof(MeshData),
|
||||||
Stride = (uint)sizeof(MeshData),
|
Stride = (uint)sizeof(MeshData),
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||||
MemoryType = ResourceMemoryType.Default,
|
HeapType = HeapType.Default,
|
||||||
};
|
};
|
||||||
|
|
||||||
var vertexBuffer = _resourceAllocator.CreateBuffer(in vertexBufferDesc, "VertexBuffer");
|
var vertexBuffer = _resourceAllocator.CreateBuffer(in vertexBufferDesc, "VertexBuffer");
|
||||||
|
|||||||
@@ -127,9 +127,9 @@ internal class SwapChainManager : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
commandBuffer.Barrier(BarrierDesc.Texture(record.SwapChain.GetCurrentBackBuffer().AsResource(),
|
commandBuffer.Barrier(BarrierDesc.Texture(record.SwapChain.GetCurrentBackBuffer().AsResource(),
|
||||||
null, BarrierSync.None,
|
BarrierSync.None,
|
||||||
null, BarrierAccess.NoAccess,
|
BarrierAccess.NoAccess,
|
||||||
null, BarrierLayout.Present));
|
BarrierLayout.Present));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using Ghost.Core;
|
using Ghost.Core;
|
||||||
using Ghost.Core.Graphics;
|
|
||||||
using Ghost.DSL.ShaderCompiler;
|
using Ghost.DSL.ShaderCompiler;
|
||||||
using Ghost.Engine.Components;
|
|
||||||
using Ghost.Graphics.Core;
|
using Ghost.Graphics.Core;
|
||||||
using Ghost.Graphics.RenderGraphModule;
|
using Ghost.Graphics.RenderGraphModule;
|
||||||
using Ghost.Graphics.RenderPipeline;
|
using Ghost.Graphics.RenderPipeline;
|
||||||
@@ -77,9 +75,9 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
|
|
||||||
private static float3 IntersectFrustumPlanes(float4 p0, float4 p1, float4 p2)
|
private static float3 IntersectFrustumPlanes(float4 p0, float4 p1, float4 p2)
|
||||||
{
|
{
|
||||||
float3 n0 = p0.xyz;
|
var n0 = p0.xyz;
|
||||||
float3 n1 = p1.xyz;
|
var n1 = p1.xyz;
|
||||||
float3 n2 = p2.xyz;
|
var n2 = p2.xyz;
|
||||||
|
|
||||||
float det = math.dot(math.cross(n0, n1), n2);
|
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);
|
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,
|
Size = instanceDataSize,
|
||||||
Stride = (uint)sizeof(InstanceData),
|
Stride = (uint)sizeof(InstanceData),
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
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");
|
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.Barrier(BarrierDesc.Buffer(instanceBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||||
ctx.CommandBuffer.UploadBuffer(instanceBufferHandle, instanceDataArray.AsSpan());
|
ctx.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.AllShading, BarrierAccess.ShaderResource));
|
||||||
|
|
||||||
// 2. Allocate and populate View Data buffer
|
// 2. Allocate and populate View Data buffer
|
||||||
var viewBufferDesc = new BufferDesc
|
var viewBufferDesc = new BufferDesc
|
||||||
@@ -265,7 +263,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
Size = (uint)sizeof(ViewData),
|
Size = (uint)sizeof(ViewData),
|
||||||
Stride = (uint)sizeof(ViewData),
|
Stride = (uint)sizeof(ViewData),
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||||
MemoryType = ResourceMemoryType.Upload,
|
HeapType = HeapType.Upload,
|
||||||
};
|
};
|
||||||
|
|
||||||
viewBufferHandle = resourceManager.CreateTransientBuffer(in viewBufferDesc, "View Buffer");
|
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)
|
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.Barrier(BarrierDesc.Buffer(viewBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||||
ctx.CommandBuffer.UploadBuffer(viewBufferHandle, new ReadOnlySpan<ViewData>(in viewData));
|
ctx.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.AllShading, BarrierAccess.ShaderResource));
|
||||||
|
|
||||||
// 3. Allocate and populate Global Frame Data buffer
|
// 3. Allocate and populate Global Frame Data buffer
|
||||||
var frameDataSize = (uint)sizeof(FrameData);
|
var frameDataSize = (uint)sizeof(FrameData);
|
||||||
@@ -293,7 +291,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
Size = frameDataSize,
|
Size = frameDataSize,
|
||||||
Stride = frameDataSize,
|
Stride = frameDataSize,
|
||||||
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
Usage = BufferUsage.Raw | BufferUsage.ShaderResource,
|
||||||
MemoryType = ResourceMemoryType.Upload,
|
HeapType = HeapType.Upload,
|
||||||
};
|
};
|
||||||
|
|
||||||
frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
frameBufferHandle = resourceManager.CreateTransientBuffer(in frameBufferDesc, "Frame Buffer");
|
||||||
@@ -305,9 +303,9 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
instanceBufferIndex = resourceDatabase.GetBindlessIndex(instanceBufferResource),
|
instanceBufferIndex = resourceDatabase.GetBindlessIndex(instanceBufferResource),
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, null, BarrierSync.Copy, null, BarrierAccess.CopyDest));
|
ctx.CommandBuffer.Barrier(BarrierDesc.Buffer(frameBufferResource, BarrierSync.Copy, BarrierAccess.CopyDest));
|
||||||
ctx.CommandBuffer.UploadBuffer(frameBufferHandle, new ReadOnlySpan<FrameData>(in frameData));
|
ctx.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.AllShading, BarrierAccess.ShaderResource));
|
||||||
|
|
||||||
if (request.renderFunc != null)
|
if (request.renderFunc != null)
|
||||||
{
|
{
|
||||||
@@ -360,7 +358,7 @@ public unsafe partial class TestRenderPipeline : IRenderPipeline
|
|||||||
builder.SetColorAttachment(backbuffer, 0);
|
builder.SetColorAttachment(backbuffer, 0);
|
||||||
builder.SetDepthAttachment(depth);
|
builder.SetDepthAttachment(depth);
|
||||||
|
|
||||||
builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx)=>
|
builder.SetRenderFunc<MeshletDebugPassData>(static (data, ctx) =>
|
||||||
{
|
{
|
||||||
ctx.SetGlobalData(data.globalIndex, data.viewIndex);
|
ctx.SetGlobalData(data.globalIndex, data.viewIndex);
|
||||||
ctx.SetInstanceData(data.instanceIndex);
|
ctx.SetInstanceData(data.instanceIndex);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Microsoft.UI.Xaml.Controls;
|
|||||||
using Microsoft.UI.Xaml.Media;
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||||
using Misaki.HighPerformance.Mathematics;
|
using Misaki.HighPerformance.Mathematics;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace Ghost.Graphics.Test.Windows;
|
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);
|
//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();
|
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);
|
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);
|
using var cmdAllocator = _renderSystem.GraphicsEngine.CreateCommandAllocator(CommandBufferType.Graphics);
|
||||||
directCmd.Begin(cmdAllocator);
|
directCmd.Begin(cmdAllocator);
|
||||||
@@ -158,7 +159,6 @@ public sealed partial class GraphicsTestWindow : Window
|
|||||||
|
|
||||||
_renderSystem?.ResourceManager.ReleaseMesh(_meshHandle);
|
_renderSystem?.ResourceManager.ReleaseMesh(_meshHandle);
|
||||||
|
|
||||||
_swapChain?.Dispose();
|
|
||||||
//_jobScheduler.Dispose();
|
//_jobScheduler.Dispose();
|
||||||
_renderSystem?.Dispose();
|
_renderSystem?.Dispose();
|
||||||
|
|
||||||
@@ -203,8 +203,9 @@ public sealed partial class GraphicsTestWindow : Window
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_renderSystem.CPUFenceValue < _renderSystem.GPUFenceValue + _renderSystem.MaxFrameLatency)
|
if (_renderSystem.TryAcquireCPUFrame())
|
||||||
{
|
{
|
||||||
|
//Debug.WriteLine($"CPU: Frame started.");
|
||||||
_world.SystemManager.UpdateAll(default);
|
_world.SystemManager.UpdateAll(default);
|
||||||
_renderSystem.SignalCPUReady();
|
_renderSystem.SignalCPUReady();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user