Render graph: native pass merging & heap-based aliasing

Major architecture upgrade:
- Add native render pass merging (hardware pass grouping, load/store op inference)
- Implement heap-based aliasing for textures & buffers (D3D12-style)
- Unify resource model: buffers and textures in one registry
- Extend builder API for buffer creation/usage, access flags, hints
- Improve barrier/state tracking (buffer hints, indirect argument state)
- Update caching, hashing, and debug output for new model
- Add enums/structs: AttachmentLoadOp, StoreOp, BufferHint, etc.
- D3D12 backend: support named resources, temp upload buffers, correct heap usage
- Update docs, benchmarks, and project files for new features

Brings render graph closer to AAA engine standards, enabling efficient memory usage, lower driver overhead, and a more flexible API.
This commit is contained in:
2026-01-16 01:59:33 +09:00
parent ac36bbf8c7
commit 1c155f962c
51 changed files with 2002 additions and 2314 deletions

View File

@@ -151,8 +151,8 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
// Set descriptor heaps for bindless resources and samplers
var heaps = stackalloc ID3D12DescriptorHeap*[2];
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource heap
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler heap
heaps[0] = _descriptorAllocator.GetCbvSrvUavHeap(); // Bindless resource Heap
heaps[1] = _descriptorAllocator.GetSamplerHeap(); // Bindless sampler Heap
_commandList.Get()->SetDescriptorHeaps(2, heaps);
}
@@ -401,20 +401,39 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var format = record.desc.TextureDescription.Format.ToDXGIFormat();
var clearColor = rtDesc.ClearColor;
// Map load operation
var loadAccessType = rtDesc.LoadOp switch
{
AttachmentLoadOp.Load => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE,
AttachmentLoadOp.Clear => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR,
AttachmentLoadOp.DontCare => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD,
_ => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE
};
// Map store operation
var storeAccessType = rtDesc.StoreOp switch
{
AttachmentStoreOp.Store => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
AttachmentStoreOp.DontCare => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD,
_ => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE
};
var desc = new D3D12_RENDER_PASS_RENDER_TARGET_DESC
{
cpuDescriptor = cpuHandle,
BeginningAccess = new D3D12_RENDER_PASS_BEGINNING_ACCESS
{
Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR,
Clear = new D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
{
ClearValue = new D3D12_CLEAR_VALUE(format, (float*)&clearColor)
}
Type = loadAccessType,
Clear = loadAccessType == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR
? new D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
{
ClearValue = new D3D12_CLEAR_VALUE(format, (float*)&clearColor)
}
: default
},
EndingAccess = new D3D12_RENDER_PASS_ENDING_ACCESS
{
Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE
Type = storeAccessType
}
};
@@ -435,16 +454,70 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var cpuHandle = _descriptorAllocator.GetCpuHandle(record.viewGroup.dsv);
var format = record.desc.TextureDescription.Format.ToDXGIFormat();
// Map depth load operation
var depthLoadAccessType = depthDesc.DepthLoadOp switch
{
AttachmentLoadOp.Load => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE,
AttachmentLoadOp.Clear => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR,
AttachmentLoadOp.DontCare => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD,
_ => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE
};
// Map depth store operation
var depthStoreAccessType = depthDesc.DepthStoreOp switch
{
AttachmentStoreOp.Store => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
AttachmentStoreOp.DontCare => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD,
_ => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE
};
// Map stencil load operation
var stencilLoadAccessType = depthDesc.StencilLoadOp switch
{
AttachmentLoadOp.Load => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE,
AttachmentLoadOp.Clear => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR,
AttachmentLoadOp.DontCare => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD,
_ => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE
};
// Map stencil store operation
var stencilStoreAccessType = depthDesc.StencilStoreOp switch
{
AttachmentStoreOp.Store => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
AttachmentStoreOp.DontCare => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD,
_ => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE
};
var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC
{
cpuDescriptor = cpuHandle,
DepthBeginningAccess = new D3D12_RENDER_PASS_BEGINNING_ACCESS
{
Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR,
Clear = new D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
{
ClearValue = new D3D12_CLEAR_VALUE(format, depthDesc.ClearDepth, depthDesc.ClearStencil)
}
Type = depthLoadAccessType,
Clear = depthLoadAccessType == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR
? new D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
{
ClearValue = new D3D12_CLEAR_VALUE(format, depthDesc.ClearDepth, depthDesc.ClearStencil)
}
: default
},
DepthEndingAccess = new D3D12_RENDER_PASS_ENDING_ACCESS
{
Type = depthStoreAccessType
},
StencilBeginningAccess = new D3D12_RENDER_PASS_BEGINNING_ACCESS
{
Type = stencilLoadAccessType,
Clear = stencilLoadAccessType == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR
? new D3D12_RENDER_PASS_BEGINNING_ACCESS_CLEAR_PARAMETERS
{
ClearValue = new D3D12_CLEAR_VALUE(format, depthDesc.ClearDepth, depthDesc.ClearStencil)
}
: default
},
StencilEndingAccess = new D3D12_RENDER_PASS_ENDING_ACCESS
{
Type = stencilStoreAccessType
}
};
@@ -731,22 +804,19 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var sizeInBytes = (uint)(data.Length * sizeof(T));
var uploadHandle = _resourceAllocator.CreateUploadBuffer(sizeInBytes);
var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(sizeInBytes, out var offset);
var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
void* pMappedData;
uploadResource.Get()->Map(0, null, &pMappedData);
fixed (T* pData = data)
{
MemoryUtility.MemCpy(pMappedData, pData, sizeInBytes);
MemoryUtility.MemCpy((byte*)pMappedData + offset, pData, sizeInBytes);
}
uploadResource.Get()->Unmap(0, null);
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes);
// D3D12 transition resource to COPY_DEST when copying
_resourceDatabase.SetResourceState(buffer.AsResource(), ResourceState.CopyDest);
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, offset, sizeInBytes);
}
public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<SubResourceData> subresources)
@@ -766,7 +836,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
var resourceDesc = resource.Get()->GetDesc();
var requiredSize = GetRequiredIntermediateSize(resource, 0, (uint)subresources.Length);
var uploadHandle = _resourceAllocator.CreateUploadBuffer(requiredSize);
var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(requiredSize, out var offset);
var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
var d3d12Subresources = stackalloc D3D12_SUBRESOURCE_DATA[subresources.Length];
@@ -784,7 +854,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
(ID3D12GraphicsCommandList*)_commandList.Get(),
resource,
pUploadResource,
0,
offset,
0,
(uint)subresources.Length,
d3d12Subresources);

View File

@@ -386,22 +386,22 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
#region Utility Methods
/// <summary>
/// Gets the RTV heap for binding to the command list.
/// Gets the RTV Heap for binding to the command list.
/// </summary>
public ID3D12DescriptorHeap* GetRTVHeap() => _rtvHeap.Heap;
/// <summary>
/// Gets the DSV heap for binding to the command list.
/// Gets the DSV Heap for binding to the command list.
/// </summary>
public ID3D12DescriptorHeap* GetDSVHeap() => _dsvHeap.Heap;
/// <summary>
/// Gets the CBV/SRV/UAV heap for binding to the command list.
/// Gets the CBV/SRV/UAV Heap for binding to the command list.
/// </summary>
public ID3D12DescriptorHeap* GetCbvSrvUavHeap() => _cbvSrvUavHeap.ShaderVisibleHeap;
/// <summary>
/// Gets the sampler heap for binding to the command list.
/// Gets the sampler Heap for binding to the command list.
/// </summary>
public ID3D12DescriptorHeap* GetSamplerHeap() => _samplerHeap.ShaderVisibleHeap;

View File

@@ -138,7 +138,7 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
}
// NOTE: In dynamic allocation, we use arena-style allocation without freeing.
// We reset the offset at the beginning of each frame instead.
// We reset the Offset at the beginning of each frame instead.
lock (_lock)
{

View File

@@ -165,7 +165,7 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
}
var size = _library.Get()->GetSerializedSize();
using var buffer = new UnsafeArray<byte>((int)size, Allocator.Persistent); // We use persistent heap allocation instead of stack allocation to avoid stack overflow for large pipeline libraries.
using var buffer = new UnsafeArray<byte>((int)size, Allocator.Persistent); // We use persistent Heap allocation instead of stack allocation to avoid stack overflow for large pipeline libraries.
ThrowIfFailed(_library.Get()->Serialize(buffer.GetUnsafePtr(), size));

View File

@@ -115,6 +115,11 @@ internal unsafe class D3D12RenderDevice : IRenderDevice
{
support |= FeatureSupport.BindlessResources;
}
if (options.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER.D3D12_RESOURCE_HEAP_TIER_2)
{
support |= FeatureSupport.AliasBuffersAndTextures;
}
}
D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5 = default;

View File

@@ -95,6 +95,8 @@ internal class D3D12Renderer : IRenderer
{
Texture = target,
ClearColor = clearColor,
LoadOp = AttachmentLoadOp.Clear,
StoreOp = AttachmentStoreOp.Store,
},
];
@@ -103,6 +105,10 @@ internal class D3D12Renderer : IRenderer
Texture = Handle<Texture>.Invalid,
ClearDepth = 1.0f,
ClearStencil = 0,
DepthLoadOp = AttachmentLoadOp.Clear,
StencilLoadOp = AttachmentLoadOp.Clear,
DepthStoreOp = AttachmentStoreOp.Store,
StencilStoreOp = AttachmentStoreOp.Store,
};
// NOTE: Testing only.

View File

@@ -5,9 +5,11 @@ using Ghost.Graphics.Core;
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
@@ -512,9 +514,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator
var state = D3D12_RESOURCE_STATE_COMMON;
#if true
// D3D12 does not support state other than COMMON for buffers at creation.
return state;
#else
// D3D12 does not support state other than COMMON for buffers at creation.
if (usage.HasFlag(BufferUsage.Vertex) || usage.HasFlag(BufferUsage.Constant))
{
// Vertex and Constant buffers can share this state
@@ -557,13 +559,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator
}
}
// TODO: Dedicated pool for copy, render graph, and persistent resources
// TODO: Thread safety for resource allocator
// A common solution is to use ticket. Each pAllocation request create a ticket and put it into a thread-safe queue. A dedicated thread process the queue and fulfill the requests.
internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
{
private const uint _UPLOAD_BATCH_SIZE = 64 * 1024 * 1024; // 64 MB
private const uint _MAX_RESOURCE_SIZE_TO_FIT_IN_UPLOAD_BATCH = 16 * 1024 * 1024; // 16 MB
private UniquePtr<D3D12MA_Allocator> _d3d12MA;
private readonly IFenceSynchronizer _fenceSynchronizer;
@@ -574,6 +574,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
private UnsafeQueue<Handle<GPUResource>> _tempResources;
private readonly Handle<GraphicsBuffer> _uploadBatch;
private ulong _uploadBatchOffset;
private bool _disposed;
public D3D12ResourceAllocator(
@@ -600,7 +603,18 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
_resourceDatabase = resourceDatabase;
_pipelineLibrary = pipelineLibrary;
_tempResources = new UnsafeQueue<Handle<GPUResource>>(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
_tempResources = new UnsafeQueue<Handle<GPUResource>>(64, Allocator.Persistent);
// Create an upload batch
var uploadDesc = new BufferDesc
{
Size = _UPLOAD_BATCH_SIZE,
Usage = BufferUsage.Upload,
MemoryType = ResourceMemoryType.Upload,
};
_uploadBatch = CreateBuffer(in uploadDesc, "D3D12ResourceAllocator_UploadBatch");
_uploadBatchOffset = 0;
}
~D3D12ResourceAllocator()
@@ -609,9 +623,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Handle<GPUResource> TrackResource(D3D12MA_Allocation* allocation, D3D12_RESOURCE_STATES state, ResourceViewGroup resourceDescriptor, ResourceDesc desc, bool isTemp)
private Handle<GPUResource> TrackResource(D3D12MA_Allocation* allocation, D3D12_RESOURCE_STATES state, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string name, bool isTemp)
{
var handle = _resourceDatabase.AddResource(allocation, _fenceSynchronizer.CPUFenceValue, D3D12Utility.ToResourceState(state) , resourceDescriptor, desc);
var handle = _resourceDatabase.AddAllocation(allocation, _fenceSynchronizer.CPUFenceValue, D3D12Utility.ToResourceState(state), resourceDescriptor, desc, name);
if (isTemp)
{
@@ -621,7 +635,70 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
return handle;
}
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool isTemp = false)
private HRESULT CreateResource(D3D12MA_ALLOCATION_DESC* pAllocationDesc, D3D12_RESOURCE_DESC* pResourceDesc, D3D12_RESOURCE_STATES initialState, CreationOptions options, void** ppv)
{
var hr = S.S_OK;
var iid = IID.IID_NULL;
if (options.AllocationType == ResourceAllocationType.RenderGraphTransient)
{
// pAllocation should be the render graph Heap. ppvResource should be the out resource.
var result = _resourceDatabase.GetResourceRecord(options.Heap);
if (result.IsFailure)
{
return E.E_NOTFOUND;
}
hr = _d3d12MA.Get()->CreateAliasingResource(result.Value.resource.allocation.Get(), options.Offset, pResourceDesc, initialState, null, &iid, ppv);
}
else
{
hr = _d3d12MA.Get()->CreateResource(pAllocationDesc, pResourceDesc, initialState, null, (D3D12MA_Allocation**)ppv, &iid, null);
}
return hr;
}
public Handle<GPUResource> Allocate(ref readonly AllocationDesc desc, string name)
{
var allocDesc = new D3D12MA_ALLOCATION_DESC
{
HeapType = desc.HeapType switch
{
HeapType.Default => D3D12_HEAP_TYPE_DEFAULT,
HeapType.Upload => D3D12_HEAP_TYPE_UPLOAD,
HeapType.Readback => D3D12_HEAP_TYPE_READBACK,
_ => D3D12_HEAP_TYPE_DEFAULT
},
Flags = D3D12MA_ALLOCATION_FLAG_COMMITTED,
ExtraHeapFlags = desc.HeapFlags switch
{
HeapFlags.None => D3D12_HEAP_FLAG_NONE,
HeapFlags.AllowBuffers => D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS,
HeapFlags.AllowTextures => D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES,
HeapFlags.AllowRTAndDS => D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES,
HeapFlags.AlowBufferAndTexture => D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES,
_ => D3D12_HEAP_FLAG_NONE
}
};
// SizeInBytes must be aligned to 64KB for committed resources
var allocInfo = new D3D12_RESOURCE_ALLOCATION_INFO
{
SizeInBytes = desc.Size + 65535 & ~65535u,
Alignment = desc.Alignment
};
D3D12MA_Allocation* alloc = default;
if (_d3d12MA.Get()->AllocateMemory(&allocDesc, &allocInfo, &alloc).FAILED)
{
return Handle<GPUResource>.Invalid;
}
return TrackResource(alloc, D3D12_RESOURCE_STATE_COMMON, ResourceViewGroup.Invalid, default, name, false);
}
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, string name, CreationOptions options = default)
{
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -681,14 +758,17 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
var initialState = DetermineInitialTextureState(desc.Usage);
D3D12MA_Allocation* pAllocation = default;
var iid = IID.IID_NULL;
ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, &iid, null));
if (CreateResource(&allocationDesc, &resourceDesc, initialState, options, (void**)&pAllocation).FAILED)
{
return Handle<Texture>.Invalid;
}
var isTemp = options.AllocationType == ResourceAllocationType.Temporary;
var resourceDescriptor = ResourceViewGroup.Invalid;
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
{
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
// TODO: Maybe use non-shader-visible descriptor first then batch copy to shader-visible heap later?
// TODO: Maybe use non-shader-visible descriptor first then batch copy to shader-visible Heap later?
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.srv);
var isCubeMap = desc.Dimension == TextureDimension.TextureCube || desc.Dimension == TextureDimension.TextureCubeArray;
@@ -724,20 +804,20 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
_device.NativeDevice.Get()->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
}
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), isTemp);
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Texture(desc), name, isTemp);
return handle.AsTexture();
}
public Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, bool isTemp = false)
public Handle<Texture> CreateRenderTarget(ref readonly RenderTargetDesc desc, string name, CreationOptions options = default)
{
ObjectDisposedException.ThrowIf(_disposed, this);
var textureDesc = desc.ToTextureDescripton();
return CreateTexture(in textureDesc, isTemp);
return CreateTexture(in textureDesc, name, options);
}
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, bool isTemp = false)
public Handle<GraphicsBuffer> CreateBuffer(ref readonly BufferDesc desc, string name, CreationOptions options = default)
{
ObjectDisposedException.ThrowIf(_disposed, this);
CheckBufferSize(desc.Size);
@@ -749,21 +829,24 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
alignedSize = (uint)(desc.Size + 255) & ~255u;
}
var resourceDescription = D3D12_RESOURCE_DESC.Buffer(alignedSize, ConvertBufferUsage(desc.Usage));
var resourceDesc = D3D12_RESOURCE_DESC.Buffer(alignedSize, ConvertBufferUsage(desc.Usage));
var isRaw = desc.Usage.HasFlag(BufferUsage.Raw);
var allocationDesc = new D3D12MA_ALLOCATION_DESC
{
HeapType = ConvertMemoryType(desc.MemoryType),
Flags = D3D12MA_ALLOCATION_FLAG_NONE
Flags = D3D12MA_ALLOCATION_FLAG_NONE,
};
var initialState = DetermineInitialBufferState(desc.Usage, desc.MemoryType);
D3D12MA_Allocation* pAllocation = default;
var iid = IID.IID_NULL;
ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDescription, initialState, null, &pAllocation, &iid, null));
if (CreateResource(&allocationDesc, &resourceDesc, initialState, options, (void**)&pAllocation).FAILED)
{
return Handle<GraphicsBuffer>.Invalid;
}
var isTemp = options.AllocationType == ResourceAllocationType.Temporary;
var resourceDescriptor = ResourceViewGroup.Invalid;
var pResource = pAllocation->GetResource();
@@ -798,22 +881,35 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
_device.NativeDevice.Get()->CreateUnorderedAccessView(pResource, null, &uavDesc, cpuHandle);
}
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Buffer(desc), isTemp);
var handle = TrackResource(pAllocation, initialState, resourceDescriptor, ResourceDesc.Buffer(desc), name, isTemp);
return handle.AsGraphicsBuffer();
}
public Handle<GraphicsBuffer> CreateUploadBuffer(ulong size, bool isTemp = true)
public Handle<GraphicsBuffer> CreateTempUploadBuffer(ulong sizeInBytes, out ulong offset)
{
ObjectDisposedException.ThrowIf(_disposed, this);
var desc = new BufferDesc
if (sizeInBytes <= _MAX_RESOURCE_SIZE_TO_FIT_IN_UPLOAD_BATCH && sizeInBytes + _uploadBatchOffset <= _UPLOAD_BATCH_SIZE)
{
Size = size,
Usage = BufferUsage.Upload,
MemoryType = ResourceMemoryType.Upload,
};
offset = _uploadBatchOffset;
_uploadBatchOffset += sizeInBytes;
return _uploadBatch;
}
else
{
var bufferDesc = new BufferDesc
{
Size = (uint)sizeInBytes,
Usage = BufferUsage.Upload,
MemoryType = ResourceMemoryType.Upload,
};
return CreateBuffer(in desc, isTemp);
var options = new CreationOptions
{
AllocationType = ResourceAllocationType.Temporary,
};
offset = 0;
return CreateBuffer(in bufferDesc, "TempUploadBuffer", options);
}
}
public Identifier<Sampler> CreateSampler(ref readonly SamplerDesc desc)
@@ -873,9 +969,9 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
MemoryType = ResourceMemoryType.Default,
};
var vertexBuffer = CreateBuffer(in vertexBufferDesc);
var indexBuffer = CreateBuffer(in indexBufferDesc);
var objectBuffer = CreateBuffer(in objectBufferDesc);
var vertexBuffer = CreateBuffer(in vertexBufferDesc, "VertexBuffer");
var indexBuffer = CreateBuffer(in indexBufferDesc, "IndexBuffer");
var objectBuffer = CreateBuffer(in objectBufferDesc, "ObjectBuffer");
var data = new Mesh
{
@@ -935,6 +1031,8 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
_resourceDatabase.ReleaseResource(handle);
_tempResources.Dequeue();
}
_uploadBatchOffset = 0;
}
public void Dispose()
@@ -951,6 +1049,8 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
_resourceDatabase.ReleaseResource(handle);
}
_resourceDatabase.ReleaseResource(_uploadBatch.AsResource());
_d3d12MA.Dispose();
_tempResources.Dispose();

View File

@@ -36,17 +36,17 @@ internal class D3D12ResourceDatabase : IResourceDatabase
public ResourceDesc desc;
public ResourceViewGroup viewGroup;
public ResourceUnion resourceUnion;
public ResourceUnion resource;
public ResourceState state;
public uint cpuFenceValue;
public readonly bool isExternal;
public readonly bool Allocated => isExternal ? resourceUnion.resource.Get() != null : resourceUnion.allocation.Get() != null;
public readonly SharedPtr<ID3D12Resource> ResourcePtr => isExternal ? resourceUnion.resource.Get() : resourceUnion.allocation.Get()->GetResource();
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, uint cpuFenceValue, ResourceState state, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
{
this.resourceUnion = new ResourceUnion(allocation);
this.resource = new ResourceUnion(allocation);
this.isExternal = false;
this.viewGroup = resourceDescriptor;
@@ -57,7 +57,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
public ResourceRecord(ID3D12Resource* resource, ResourceState state, ResourceViewGroup viewGroup)
{
this.resourceUnion = new ResourceUnion(resource);
this.resource = new ResourceUnion(resource);
this.isExternal = true;
this.viewGroup = viewGroup;
@@ -73,17 +73,17 @@ internal class D3D12ResourceDatabase : IResourceDatabase
{
if (isExternal)
{
refCount = resourceUnion.resource.Get()->Release();
refCount = resource.resource.Get()->Release();
}
else
{
refCount = resourceUnion.allocation.Get()->Release();
refCount = resource.allocation.Get()->Release();
}
}
descriptorAllocator.Release(viewGroup);
resourceUnion = default;
resource = default;
viewGroup = default;
return refCount;
@@ -116,7 +116,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
_meshes = new UnsafeSlotMap<Mesh>(64, Allocator.Persistent, AllocationOption.Clear);
_materials = new UnsafeSlotMap<Material>(16, Allocator.Persistent, AllocationOption.Clear);
_shaders = new DynamicArray<Shader>(16);
// _shaderPasses = new UnsafeHashMap<ShaderPassKey, ShaderPass>(32, Allocator.Persistent);
}
~D3D12ResourceDatabase()
@@ -149,7 +148,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
return handle;
}
public unsafe Handle<GPUResource> AddResource(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState initialState, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string? name = null)
public unsafe Handle<GPUResource> AddAllocation(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState initialState, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string? name = null)
{
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -160,6 +159,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
if (!string.IsNullOrEmpty(name))
{
allocation->SetName(name);
allocation->GetResource()->SetName(name);
_resourceName[handle] = name;
}
#endif
@@ -475,7 +475,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
_samplers.Dispose();
_meshes.Dispose();
_materials.Dispose();
// _shaderPasses.Dispose();
_disposed = true;

View File

@@ -11,7 +11,6 @@ using System.Diagnostics;
using System.Runtime.CompilerServices;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
using static TerraFX.Aliases.DXGI_Alias;
namespace Ghost.Graphics.D3D12;
@@ -71,7 +70,8 @@ internal unsafe class D3D12SwapChain : ISwapChain
CreateBackBuffers();
SetScale(desc.ScaleX, desc.ScaleY);
_compositionSurface = desc.Target.CompositionSurface;
if (desc.Target.Type == SwapChainTargetType.Composition)
_compositionSurface = desc.Target.CompositionSurface;
}
~D3D12SwapChain()
@@ -106,12 +106,12 @@ internal unsafe class D3D12SwapChain : ISwapChain
case SwapChainTargetType.Composition:
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)pCommandQueue, &swapChainDesc, null, &pTempSwapChain));
// Set the composition surface
if (desc.Target.CompositionSurface != null)
{
using var swapChainPanelNative = ISwapChainPanelNative.FromSwapChainPanel(desc.Target.CompositionSurface);
swapChainPanelNative.SetSwapChain((IntPtr)pTempSwapChain);
using var compositionSurface = ISwapChainPanelNative.FromSwapChainPanel(desc.Target.CompositionSurface);
compositionSurface.SetSwapChain((nint)pTempSwapChain);
}
break;
case SwapChainTargetType.WindowHandle:
@@ -213,7 +213,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
var inverseScaleX = 1.0f / scaleX;
var inverseScaleY = 1.0f / scaleY;
DXGI_MATRIX_3X2_F inverseScaleMatrix = new DXGI_MATRIX_3X2_F
var inverseScaleMatrix = new DXGI_MATRIX_3X2_F
{
_11 = inverseScaleX, // Scale X
_22 = inverseScaleY, // Scale Y
@@ -238,8 +238,8 @@ internal unsafe class D3D12SwapChain : ISwapChain
if (_compositionSurface != null)
{
using var panelNative = ISwapChainPanelNative.FromSwapChainPanel(_compositionSurface);
panelNative.SetSwapChain(IntPtr.Zero);
using var compositionSurface = ISwapChainPanelNative.FromSwapChainPanel(_compositionSurface);
compositionSurface.SetSwapChain(0);
}
for (var i = 0; i < _backBuffers.Count; i++)

View File

@@ -79,62 +79,62 @@ internal unsafe static class D3D12Utility
{
var d3dStates = D3D12_RESOURCE_STATES.D3D12_RESOURCE_STATE_COMMON;
if (state.HasFlag(ResourceState.VertexAndConstantBuffer))
if ((state & ResourceState.VertexAndConstantBuffer) == ResourceState.VertexAndConstantBuffer)
{
d3dStates |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
}
if (state.HasFlag(ResourceState.IndexBuffer))
if ((state & ResourceState.IndexBuffer) == ResourceState.IndexBuffer)
{
d3dStates |= D3D12_RESOURCE_STATE_INDEX_BUFFER;
}
if (state.HasFlag(ResourceState.RenderTarget))
if ((state & ResourceState.RenderTarget) == ResourceState.RenderTarget)
{
d3dStates |= D3D12_RESOURCE_STATE_RENDER_TARGET;
}
if (state.HasFlag(ResourceState.UnorderedAccess))
if ((state & ResourceState.UnorderedAccess) == ResourceState.UnorderedAccess)
{
d3dStates |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
}
if (state.HasFlag(ResourceState.DepthWrite))
if ((state & ResourceState.DepthWrite) == ResourceState.DepthWrite)
{
d3dStates |= D3D12_RESOURCE_STATE_DEPTH_WRITE;
}
if (state.HasFlag(ResourceState.DepthRead))
if ((state & ResourceState.DepthRead) == ResourceState.DepthRead)
{
d3dStates |= D3D12_RESOURCE_STATE_DEPTH_READ;
}
if (state.HasFlag(ResourceState.PixelShaderResource))
if ((state & ResourceState.PixelShaderResource) == ResourceState.PixelShaderResource)
{
d3dStates |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
}
if (state.HasFlag(ResourceState.CopyDest))
if ((state & ResourceState.CopyDest) == ResourceState.CopyDest)
{
d3dStates |= D3D12_RESOURCE_STATE_COPY_DEST;
}
if (state.HasFlag(ResourceState.CopySource))
if ((state & ResourceState.CopySource) == ResourceState.CopySource)
{
d3dStates |= D3D12_RESOURCE_STATE_COPY_SOURCE;
}
if (state.HasFlag(ResourceState.GenericRead))
if ((state & ResourceState.GenericRead) == ResourceState.GenericRead)
{
d3dStates |= D3D12_RESOURCE_STATE_GENERIC_READ;
}
if (state.HasFlag(ResourceState.IndirectArgument))
if ((state & ResourceState.IndirectArgument) == ResourceState.IndirectArgument)
{
d3dStates |= D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT;
}
if (state.HasFlag(ResourceState.NonPixelShaderResource))
if ((state & ResourceState.NonPixelShaderResource) == ResourceState.NonPixelShaderResource)
{
d3dStates |= D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
}