feat(resource): refactor heap management & suballocation

Major overhaul of GPU resource/heap management:
- Replace resource pooling and upload buffer logic with transient heap/page-based suballocation in ResourceManager.
- Add support for suballocation and heap flags/types, with D3D12 helpers.
- Remove ICommandBuffer.UploadBuffer/UploadTexture; add UpdateSubResources and CopyBuffer, move upload logic to RenderingContext.
- Refactor D3D12ResourceAllocator/Database for suballocation, heap flags, and mapping.
- Standardize on Handle<GPUBuffer> usage.
- Update meshlet/mesh utilities for new allocation handles and memory pools.
- Refactor RenderGraph and docs to use "heap" terminology.
- Use cpuFrame/gpuFrame consistently for frame sync.
- Add s2h.hlsl, s2h_3d.hlsl, s2h_scatter.hlsl shader debug libs.
- Miscellaneous fixes, cleanup, and dependency updates.

BREAKING CHANGE: Resource pooling and upload APIs replaced with new heap/page-based suballocation system. Update all buffer/texture creation and upload code to use new ResourceManager and ICommandBuffer methods.
This commit is contained in:
2026-04-03 01:48:49 +09:00
parent d03eb659fa
commit 6321b36ef5
47 changed files with 2552 additions and 526 deletions

View File

@@ -6,6 +6,7 @@ using Misaki.HighPerformance.LowLevel.Utilities;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Gdiplus;
using TerraFX.Interop.Windows;
using static TerraFX.Aliases.D3D_Alias;
@@ -635,7 +636,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
pNativeObject->SetPipelineState(psor.Value);
}
public void SetConstantBufferView(uint slot, Handle<RHI.GPUBuffer> buffer)
public void SetConstantBufferView(uint slot, Handle<GPUBuffer> buffer)
{
AssertNotDisposed();
ThrowIfNotRecording();
@@ -651,7 +652,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
pNativeObject->SetGraphicsRootConstantBufferView(slot, resource.Get()->GetGPUVirtualAddress());
}
public void SetVertexBuffer(uint slot, Handle<RHI.GPUBuffer> buffer, ulong offset = 0)
public void SetVertexBuffer(uint slot, Handle<GPUBuffer> buffer, ulong offset = 0)
{
AssertNotDisposed();
ThrowIfNotRecording();
@@ -681,7 +682,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
pNativeObject->IASetVertexBuffers(slot, 1, &vbView);
}
public void SetIndexBuffer(Handle<RHI.GPUBuffer> buffer, IndexType type, ulong offset = 0)
public void SetIndexBuffer(Handle<GPUBuffer> buffer, IndexType type, ulong offset = 0)
{
AssertNotDisposed();
ThrowIfNotRecording();
@@ -821,7 +822,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
throw new NotImplementedException();
}
public void ExecuteIndirect(Handle<RHI.GPUBuffer> argumentBuffer, ulong argumentOffset, Handle<RHI.GPUBuffer> countBuffer, ulong countBufferOffset)
public void ExecuteIndirect(Handle<GPUBuffer> argumentBuffer, ulong argumentOffset, Handle<GPUBuffer> countBuffer, ulong countBufferOffset)
{
throw new NotImplementedException();
@@ -845,57 +846,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
}
public void UploadBuffer<T>(Handle<RHI.GPUBuffer> buffer, params ReadOnlySpan<T> data)
where T : unmanaged
{
static void Map(T* pData, nuint size, ulong offset, SharedPtr<ID3D12Resource> resource)
{
void* pMappedData;
resource.Get()->Map(0, null, &pMappedData);
MemoryUtility.MemCpy((byte*)pMappedData + offset, pData, size);
resource.Get()->Unmap(0, null);
}
AssertNotDisposed();
ThrowIfNotRecording();
#if !DEBUG
if (_lastError.Status != Error.None)
{
return;
}
#endif
IncrementCommandCount();
var pResource = _resourceDatabase.GetResource(buffer.AsResource());
D3D12_HEAP_PROPERTIES properties;
D3D12_HEAP_FLAGS flags;
ThrowIfFailed(pResource.Get()->GetHeapProperties(&properties, &flags));
if (properties.Type == D3D12_HEAP_TYPE_UPLOAD)
{
fixed (T* pData = data)
{
Map(pData, (nuint)(data.Length * sizeof(T)), 0, pResource);
}
}
else
{
var sizeInBytes = (uint)(data.Length * sizeof(T));
var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(sizeInBytes, out var offset);
var uploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
fixed (T* pData = data)
{
Map(pData, sizeInBytes, offset, uploadResource);
}
pNativeObject->CopyBufferRegion(pResource, 0, uploadResource, offset, sizeInBytes);
}
}
public void UploadTexture(Handle<GPUTexture> texture, params ReadOnlySpan<SubResourceData> subresources)
public void CopyBuffer(Handle<GPUBuffer> dst, Handle<GPUBuffer> src, ulong dstOffset = 0, ulong srcOffset = 0, ulong numBytes = 0)
{
AssertNotDisposed();
ThrowIfNotRecording();
@@ -905,47 +856,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
return;
}
#endif
IncrementCommandCount();
var resource = _resourceDatabase.GetResource(texture.AsResource());
var resourceDesc = resource.Get()->GetDesc();
var requiredSize = GetRequiredIntermediateSize(resource, 0, (uint)subresources.Length);
var uploadHandle = _resourceAllocator.CreateTempUploadBuffer(requiredSize, out var offset);
var pUploadResource = _resourceDatabase.GetResource(uploadHandle.AsResource());
var d3d12Subresources = stackalloc D3D12_SUBRESOURCE_DATA[subresources.Length];
for (var i = 0; i < subresources.Length; i++)
{
d3d12Subresources[i] = new D3D12_SUBRESOURCE_DATA
{
pData = subresources[i].pData,
RowPitch = (nint)subresources[i].rowPitch,
SlicePitch = (nint)subresources[i].slicePitch
};
}
UpdateSubresources(
(ID3D12GraphicsCommandList*)pNativeObject,
resource,
pUploadResource,
offset,
0,
(uint)subresources.Length,
d3d12Subresources);
}
public void CopyBuffer(Handle<RHI.GPUBuffer> dst, Handle<RHI.GPUBuffer> src, ulong dstOffset = 0, ulong srcOffset = 0, ulong numBytes = 0)
{
AssertNotDisposed();
ThrowIfNotRecording();
#if !DEBUG
if (_lastError.Status != Error.None)
{
return;
}
#endif
if (dst == src)
{
return;
@@ -971,6 +882,48 @@ internal unsafe class D3D12CommandBuffer : D3D12Object<ID3D12GraphicsCommandList
}
}
public void UpdateSubResources(Handle<GPUResource> resource, Handle<GPUResource> intermediate, params ReadOnlySpan<SubResourceData> subResources)
{
AssertNotDisposed();
ThrowIfNotRecording();
#if !DEBUG
if (_lastError.Status != Error.None)
{
return;
}
#endif
IncrementCommandCount();
var d3d12Resource = _resourceDatabase.GetResource(resource);
var d3d12Intermediate = _resourceDatabase.GetResource(intermediate);
if (d3d12Intermediate == null || d3d12Resource == null)
{
RecordError(nameof(UpdateSubResources), Error.InvalidArgument);
return;
}
var d3d12Subresources = stackalloc D3D12_SUBRESOURCE_DATA[subResources.Length];
for (var i = 0; i < subResources.Length; i++)
{
d3d12Subresources[i] = new D3D12_SUBRESOURCE_DATA
{
pData = subResources[i].pData,
RowPitch = (nint)subResources[i].rowPitch,
SlicePitch = (nint)subResources[i].slicePitch
};
}
UpdateSubresources(
(ID3D12GraphicsCommandList*)pNativeObject,
d3d12Resource,
d3d12Intermediate,
0,
0,
(uint)subResources.Length,
d3d12Subresources);
}
private D3D12_TEXTURE_COPY_LOCATION GetTextureCopyLocation(SharedPtr<ID3D12Resource> texture, TextureSubresource subres)
{
var flatIndex = subres.MipLevel + subres.ArrayLayer * texture.Get()->GetDesc().MipLevels;