Refactor and optimize rendering pipeline
- Added `<IsTrimmable>` property in project files for trimming. - Replaced bindless texture types with non-bindless equivalents. - Refactored `ShaderDescriptor` and `ShaderPass` for better modularity. - Introduced `ShaderDescriptorExtensions` for property size calculations. - Simplified constant buffer handling in `Material.cs`. - Improved resource management in `D3D12` components. - Added support for static meshes and optimized resource barriers. - Refactored shader code generation and property merging in `SDLCompiler`. - Removed unused or redundant code (e.g., `IncludesBlock` parser). - Updated comments, documentation, and error handling for clarity.
This commit is contained in:
@@ -173,17 +173,65 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
||||
_commandList.Get()->RSSetScissorRects(1, &d3d12Rect);
|
||||
}
|
||||
|
||||
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState before, ResourceState after)
|
||||
public void ResourceBarrier(ReadOnlySpan<BarrierDesc> barrierDescs)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ThrowIfNotRecording();
|
||||
IncrementCommandCount();
|
||||
|
||||
var d3d12Resource = _resourceDatabase.GetResource(resource);
|
||||
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(d3d12Resource,
|
||||
before.ToD3D12States(), after.ToD3D12States());
|
||||
var count = 0u;
|
||||
var pBarriers = stackalloc D3D12_RESOURCE_BARRIER[barrierDescs.Length];
|
||||
|
||||
for (int i = 0; i < barrierDescs.Length; i++)
|
||||
{
|
||||
var desc = barrierDescs[i];
|
||||
if (desc.StateBefore == desc.StateAfter)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!desc.Resource.IsValid)
|
||||
{
|
||||
throw new ArgumentException($"Barrier resource at index {i} is not a valid resource handle");
|
||||
}
|
||||
|
||||
ref var resourceRecord = ref _resourceDatabase.GetResourceRecord(desc.Resource.AsResource());
|
||||
if (resourceRecord.state != desc.StateBefore)
|
||||
{
|
||||
throw new InvalidOperationException($"Resource state mismatch: expected {desc.StateBefore}, actual {resourceRecord.state}");
|
||||
}
|
||||
|
||||
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(resourceRecord.ResourcePtr,
|
||||
desc.StateBefore.ToD3D12States(), desc.StateAfter.ToD3D12States());
|
||||
|
||||
pBarriers[count] = barrier;
|
||||
count++;
|
||||
|
||||
// Update the resource state in the database
|
||||
resourceRecord.state = desc.StateAfter;
|
||||
}
|
||||
|
||||
_commandList.Get()->ResourceBarrier(count, pBarriers);
|
||||
}
|
||||
|
||||
public void ResourceBarrier(Handle<GPUResource> resource, ResourceState stateBefore, ResourceState stateAfter)
|
||||
{
|
||||
if (stateBefore == stateAfter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ref var resourceRecord = ref _resourceDatabase.GetResourceRecord(resource);
|
||||
if (resourceRecord.state != stateBefore)
|
||||
{
|
||||
throw new InvalidOperationException($"Resource state mismatch: expected {stateBefore}, actual {resourceRecord.state}");
|
||||
}
|
||||
|
||||
var barrier = D3D12_RESOURCE_BARRIER.InitTransition(resourceRecord.ResourcePtr,
|
||||
stateBefore.ToD3D12States(), stateAfter.ToD3D12States());
|
||||
|
||||
_commandList.Get()->ResourceBarrier(1, &barrier);
|
||||
resourceRecord.state = stateAfter;
|
||||
}
|
||||
|
||||
public void SetRenderTargets(ReadOnlySpan<Handle<Texture>> renderTargets, Handle<Texture> depthTarget)
|
||||
@@ -465,7 +513,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
|
||||
_commandList.Get()->CopyBufferRegion(pResource, 0, uploadResource, 0, sizeInBytes);
|
||||
}
|
||||
|
||||
public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources)
|
||||
public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<SubResourceData> subresources)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ThrowIfNotRecording();
|
||||
|
||||
@@ -19,7 +19,7 @@ internal unsafe class D3D12DescriptorAllocator : IDisposable
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public unsafe D3D12DescriptorAllocator(D3D12RenderDevice device, int initialRtvCount = 256, int initialDsvCount = 256, int initialSrvCount = 200_000, int initialSamplerCount = 256)
|
||||
public D3D12DescriptorAllocator(D3D12RenderDevice device, int initialRtvCount = 256, int initialDsvCount = 256, int initialSrvCount = 200_000, int initialSamplerCount = 256)
|
||||
{
|
||||
_rtvHeap = new D3D12DescriptorHeap("rtv", device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV, initialRtvCount, initialRtvCount / 2);
|
||||
_dsvHeap = new D3D12DescriptorHeap("dsv", device, D3D12_DESCRIPTOR_HEAP_TYPE_DSV, initialDsvCount, initialDsvCount / 2);
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Graphics.D3D12;
|
||||
|
||||
internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
internal class D3D12GraphicsEngine : IGraphicsEngine
|
||||
{
|
||||
#if DEBUG
|
||||
private readonly D3D12DebugLayer _debugLayer;
|
||||
@@ -34,17 +34,17 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
public D3D12GraphicsEngine(IRenderSystem renderSystem)
|
||||
{
|
||||
#if DEBUG
|
||||
_debugLayer = new();
|
||||
_debugLayer = new D3D12DebugLayer();
|
||||
#endif
|
||||
_device = new();
|
||||
_shaderCompiler = new();
|
||||
_descriptorAllocator = new(_device);
|
||||
_device = new D3D12RenderDevice();
|
||||
_shaderCompiler = new DxcShaderCompiler();
|
||||
_descriptorAllocator = new D3D12DescriptorAllocator(_device);
|
||||
|
||||
_resourceDatabase = new(_descriptorAllocator);
|
||||
_pipelineLibrary = new(_device, _resourceDatabase);
|
||||
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
|
||||
_resourceDatabase = new D3D12ResourceDatabase(_descriptorAllocator);
|
||||
_pipelineLibrary = new D3D12PipelineLibrary(_device, _resourceDatabase);
|
||||
_resourceAllocator = new D3D12ResourceAllocator(renderSystem, _device, _descriptorAllocator, _resourceDatabase, _pipelineLibrary);
|
||||
|
||||
_copyCommandBuffer = new(
|
||||
_copyCommandBuffer = new D3D12CommandBuffer(
|
||||
_device,
|
||||
_pipelineLibrary,
|
||||
_resourceDatabase,
|
||||
@@ -136,6 +136,9 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
|
||||
|
||||
_copyCommandBuffer.End();
|
||||
_resourceAllocator.ReleaseTempResources();
|
||||
_descriptorAllocator.ResetCbvSrvUavDynamicHeap();
|
||||
_descriptorAllocator.ResetDSVDynamicHeap();
|
||||
_descriptorAllocator.ResetRTVDynamicHeap();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -8,8 +8,6 @@ using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using Misaki.HighPerformance.LowLevel.Utilities;
|
||||
using Misaki.HighPerformance.Utilities;
|
||||
using System.Runtime.InteropServices;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
@@ -40,7 +38,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
||||
private UniquePtr<ID3D12RootSignature> _defaultRootSignature;
|
||||
|
||||
private readonly Dictionary<GraphicsPipelineKey, D3D12PipelineState> _pipelineCache;
|
||||
private readonly Dictionary<ShaderPassKey, CBufferInfo> _cbufferInfoCache;
|
||||
|
||||
public ID3D12RootSignature* DefaultRootSignature => _defaultRootSignature.Get();
|
||||
|
||||
@@ -50,9 +47,8 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
||||
_resourceDatabase = resourceDatabase;
|
||||
|
||||
_pipelineCache = new Dictionary<GraphicsPipelineKey, D3D12PipelineState>();
|
||||
_cbufferInfoCache = new Dictionary<ShaderPassKey, CBufferInfo>();
|
||||
|
||||
CreateDefaultRootSignature();
|
||||
CreateDefaultRootSignature().ThrowIfFailed();
|
||||
}
|
||||
|
||||
private Result CreateDefaultRootSignature()
|
||||
@@ -140,36 +136,21 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
||||
Desc_1_1 = rootSignatureDesc
|
||||
};
|
||||
|
||||
ID3DBlob* pSignature = default;
|
||||
ID3DBlob* pError = default;
|
||||
using ComPtr<ID3DBlob> pSignature = default;
|
||||
using ComPtr<ID3DBlob> pError = default;
|
||||
|
||||
try
|
||||
var serializeResult = D3D12SerializeVersionedRootSignature(&versionedDesc, pSignature.GetAddressOf(), pError.GetAddressOf());
|
||||
if (serializeResult.FAILED)
|
||||
{
|
||||
var serializeResult = D3D12SerializeVersionedRootSignature(&versionedDesc, &pSignature, &pError);
|
||||
if (serializeResult.FAILED)
|
||||
{
|
||||
var errorMsg = pError != null ? Marshal.PtrToStringUTF8((nint)pError->GetBufferPointer()) : "Unknown error";
|
||||
return Result.Failure($"Failed to serialize default root signature: {errorMsg}");
|
||||
}
|
||||
|
||||
ID3D12RootSignature* pRootSignature = default;
|
||||
ThrowIfFailed(_device.NativeDevice.Get()->CreateRootSignature(0, pSignature->GetBufferPointer(), pSignature->GetBufferSize(),
|
||||
__uuidof(pRootSignature), (void**)&pRootSignature));
|
||||
|
||||
_defaultRootSignature.Attach(pRootSignature);
|
||||
var errorMsg = pError.Get() != null ? Marshal.PtrToStringUTF8((nint)pError.Get()->GetBufferPointer()) : "Unknown error";
|
||||
return Result.Failure($"Failed to serialize default root signature: {errorMsg}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pSignature != null)
|
||||
{
|
||||
pSignature->Release();
|
||||
}
|
||||
|
||||
if (pError != null)
|
||||
{
|
||||
pError->Release();
|
||||
}
|
||||
}
|
||||
ID3D12RootSignature* pRootSignature = default;
|
||||
ThrowIfFailed(_device.NativeDevice.Get()->CreateRootSignature(0, pSignature.Get()->GetBufferPointer(), pSignature.Get()->GetBufferSize(),
|
||||
__uuidof(pRootSignature), (void**)&pRootSignature));
|
||||
|
||||
_defaultRootSignature.Attach(pRootSignature);
|
||||
|
||||
return Result.Success();
|
||||
}
|
||||
@@ -337,8 +318,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
||||
return Result.Failure(result.Message);
|
||||
}
|
||||
|
||||
_cbufferInfoCache[descriptor.PassId] = result.Value;
|
||||
|
||||
var desc = new D3DX12_MESH_SHADER_PIPELINE_STATE_DESC
|
||||
{
|
||||
pRootSignature = _defaultRootSignature.Get(),
|
||||
@@ -422,16 +401,6 @@ internal unsafe class D3D12PipelineLibrary : IPipelineLibrary
|
||||
return key;
|
||||
}
|
||||
|
||||
public Result<CBufferInfo, ResultStatus> GetCBufferInfo(ShaderPassKey passId)
|
||||
{
|
||||
if (_cbufferInfoCache.TryGetValue(passId, out var cbufferInfo))
|
||||
{
|
||||
return Result.Create(cbufferInfo, ResultStatus.Success);
|
||||
}
|
||||
|
||||
return Result.Create(default(CBufferInfo), ResultStatus.NotFound);
|
||||
}
|
||||
|
||||
public Result<SharedPtr<ID3D12PipelineState>, ResultStatus> GetGraphicsPSO(GraphicsPipelineKey key)
|
||||
{
|
||||
if (_pipelineCache.TryGetValue(key, out var cacheEntry))
|
||||
|
||||
@@ -31,7 +31,6 @@ internal class D3D12Renderer : IRenderer
|
||||
}
|
||||
|
||||
private readonly D3D12GraphicsEngine _graphicsEngine;
|
||||
private readonly D3D12CommandQueue _commandQueue;
|
||||
private readonly FrameResource[] _frameResources;
|
||||
private uint _frameIndex;
|
||||
|
||||
@@ -60,7 +59,6 @@ internal class D3D12Renderer : IRenderer
|
||||
public D3D12Renderer(D3D12GraphicsEngine graphicsEngine, D3D12ResourceAllocator resourceAllocator, D3D12ResourceDatabase resourceDatabase)
|
||||
{
|
||||
_graphicsEngine = graphicsEngine;
|
||||
_commandQueue = (D3D12CommandQueue)graphicsEngine.Device.GraphicsQueue;
|
||||
_resourceAllocator = resourceAllocator;
|
||||
_resourceDatabase = resourceDatabase;
|
||||
|
||||
@@ -153,7 +151,7 @@ internal class D3D12Renderer : IRenderer
|
||||
_swapChain?.Resize(newSize.x, newSize.y);
|
||||
_currentSize = newSize;
|
||||
|
||||
// Update off-screen render target size
|
||||
// Update off-screen render Target size
|
||||
if (_swapChain != null)
|
||||
{
|
||||
_resourceDatabase.ReleaseResource(_renderTarget.AsResource());
|
||||
@@ -170,7 +168,7 @@ internal class D3D12Renderer : IRenderer
|
||||
|
||||
if (frame.fenceValue > 0)
|
||||
{
|
||||
_commandQueue.WaitForValue(frame.fenceValue);
|
||||
_graphicsEngine.Device.GraphicsQueue.WaitForValue(frame.fenceValue);
|
||||
}
|
||||
|
||||
if (_renderTarget.IsValid)
|
||||
@@ -202,12 +200,12 @@ internal class D3D12Renderer : IRenderer
|
||||
|
||||
frame.commandBuffer.End();
|
||||
|
||||
_commandQueue.Submit(frame.commandBuffer);
|
||||
_graphicsEngine.Device.GraphicsQueue.Submit(frame.commandBuffer);
|
||||
_swapChain?.Present();
|
||||
|
||||
}
|
||||
|
||||
frame.fenceValue = _commandQueue.Signal(_frameIndex);
|
||||
frame.fenceValue = _graphicsEngine.Device.GraphicsQueue.Signal(_frameIndex);
|
||||
_frameIndex++;
|
||||
}
|
||||
|
||||
@@ -257,7 +255,7 @@ internal class D3D12Renderer : IRenderer
|
||||
// Handle swap chain back buffer transitions if needed
|
||||
if (_swapChain != null)
|
||||
{
|
||||
// Transition back buffer to render target
|
||||
// Transition back buffer to render Target
|
||||
cmd.ResourceBarrier(destination.AsResource(), ResourceState.Present, ResourceState.RenderTarget);
|
||||
}
|
||||
|
||||
@@ -266,7 +264,7 @@ internal class D3D12Renderer : IRenderer
|
||||
|
||||
// FIX: Implement proper blit operation with shader
|
||||
// This is a placeholder - in D3D12, you would typically:
|
||||
// 1. Set render target to the destination
|
||||
// 1. Set render Target to the destination
|
||||
// 2. Use a full-screen quad/triangle with a shader that samples from the source
|
||||
|
||||
// Handle swap chain back buffer transitions if needed
|
||||
@@ -284,7 +282,7 @@ internal class D3D12Renderer : IRenderer
|
||||
{
|
||||
if (frame.fenceValue > 0)
|
||||
{
|
||||
_commandQueue.WaitForValue(frame.fenceValue);
|
||||
_graphicsEngine.Device.GraphicsQueue.WaitForValue(frame.fenceValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,8 +299,8 @@ internal class D3D12Renderer : IRenderer
|
||||
// NOTE: Testing only.
|
||||
_pass.Cleanup(_resourceDatabase);
|
||||
|
||||
// If using a swap chain, release the off-screen render target.
|
||||
// Otherwise, the render target is managed externally.
|
||||
// If using a swap chain, release the off-screen render Target.
|
||||
// Otherwise, the render Target is managed externally.
|
||||
if (_swapChain != null)
|
||||
{
|
||||
_resourceDatabase.ReleaseResource(_renderTarget.AsResource());
|
||||
|
||||
@@ -5,7 +5,7 @@ using Ghost.Graphics.Core;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.LowLevel;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using Misaki.HighPerformance.Mathematics;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
@@ -522,10 +522,11 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
return D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
}
|
||||
|
||||
// Default to Common, but check for specific roles
|
||||
var state = D3D12_RESOURCE_STATE_COMMON;
|
||||
#if true
|
||||
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
|
||||
@@ -564,6 +565,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator
|
||||
|
||||
// If it's a mix, start in common and let the user barrier
|
||||
return D3D12_RESOURCE_STATE_COMMON;
|
||||
#endif
|
||||
}
|
||||
|
||||
private static ResourceState D3D12StatesToRHIState(D3D12_RESOURCE_STATES states)
|
||||
@@ -605,7 +607,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
private readonly D3D12ResourceDatabase _resourceDatabase;
|
||||
private readonly D3D12PipelineLibrary _pipelineLibrary;
|
||||
|
||||
private UnsafeQueue<Handle<GPUResource>> _temResources;
|
||||
private UnsafeQueue<Handle<GPUResource>> _tempResources;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
@@ -633,7 +635,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
_resourceDatabase = resourceDatabase;
|
||||
_pipelineLibrary = pipelineLibrary;
|
||||
|
||||
_temResources = new(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||
_tempResources = new UnsafeQueue<Handle<GPUResource>>(64, Misaki.HighPerformance.LowLevel.Buffer.Allocator.Persistent);
|
||||
}
|
||||
|
||||
~D3D12ResourceAllocator()
|
||||
@@ -648,7 +650,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
|
||||
if (isTemp)
|
||||
{
|
||||
_temResources.Enqueue(handle);
|
||||
_tempResources.Enqueue(handle);
|
||||
}
|
||||
|
||||
return handle;
|
||||
@@ -714,13 +716,15 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
var initialState = DetermineInitialTextureState(desc.Usage);
|
||||
|
||||
D3D12MA_Allocation* pAllocation = default;
|
||||
ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, Win32Utility.IID_NULL, null));
|
||||
var iid = IID.IID_NULL;
|
||||
ThrowIfFailed(_d3d12MA.Get()->CreateResource(&allocationDesc, &resourceDesc, initialState, null, &pAllocation, &iid, null));
|
||||
|
||||
var resourceDescriptor = ResourceViewGroup.Invalid;
|
||||
if (desc.Usage.HasFlag(TextureUsage.ShaderResource))
|
||||
{
|
||||
resourceDescriptor.srv = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.srv);
|
||||
// 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;
|
||||
var srvDesc = CreateTextureSrvDesc(pAllocation->GetResource(), mipLevels, desc.Slice, isCubeMap);
|
||||
@@ -749,7 +753,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
if (desc.Usage.HasFlag(TextureUsage.UnorderedAccess))
|
||||
{
|
||||
resourceDescriptor.uav = _descriptorAllocator.AllocateCbvSrvUav(isTemp);
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandle(resourceDescriptor.uav);
|
||||
var cpuHandle = _descriptorAllocator.GetCpuHandleShaderVisible(resourceDescriptor.uav);
|
||||
var uavDesc = CreateTextureUavDesc(pAllocation->GetResource());
|
||||
|
||||
_device.NativeDevice.Get()->CreateUnorderedAccessView(pAllocation->GetResource(), null, &uavDesc, cpuHandle);
|
||||
@@ -906,24 +910,6 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var shader = new Shader(descriptor);
|
||||
foreach (var pass in descriptor.passes)
|
||||
{
|
||||
if (pass is not FullPassDescriptor fullPass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Cache the pass key because we hash it multiple times right now.
|
||||
var passKey = new ShaderPassKey(fullPass.Identifier);
|
||||
var cbr = _pipelineLibrary.GetCBufferInfo(passKey);
|
||||
if (cbr.Status != ResultStatus.Success)
|
||||
{
|
||||
return Identifier<Shader>.Invalid;
|
||||
}
|
||||
|
||||
_resourceDatabase.AddShaderPass(passKey, new ShaderPass(cbr.Value));
|
||||
}
|
||||
|
||||
return _resourceDatabase.AddShader(shader);
|
||||
}
|
||||
|
||||
@@ -931,14 +917,14 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
while (_temResources.Count > 0)
|
||||
while (_tempResources.Count > 0)
|
||||
{
|
||||
var handle = _temResources.Peek();
|
||||
ref var info = ref _resourceDatabase.GetResourceInfo(handle, out var exist);
|
||||
var handle = _tempResources.Peek();
|
||||
ref var info = ref _resourceDatabase.GetResourceRecord(handle, out var exist);
|
||||
if (!exist || !info.Allocated)
|
||||
{
|
||||
// Resource already released or invalid, just dequeue
|
||||
_temResources.Dequeue();
|
||||
_tempResources.Dequeue();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -950,7 +936,7 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
}
|
||||
|
||||
_resourceDatabase.ReleaseResource(handle);
|
||||
_temResources.Dequeue();
|
||||
_tempResources.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -961,20 +947,15 @@ internal sealed unsafe partial class D3D12ResourceAllocator : IResourceAllocator
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
if (_temResources.Count > 0)
|
||||
{
|
||||
throw new InvalidOperationException($"ResourceAllocator is being disposed with {_temResources.Count} temp allocations still registered. Ensure all resources are released before disposing.");
|
||||
}
|
||||
#endif
|
||||
Debug.Assert(_tempResources.Count == 0, "Temporary resources should be released before disposing the allocator.");
|
||||
|
||||
foreach (var handle in _temResources)
|
||||
foreach (var handle in _tempResources)
|
||||
{
|
||||
_resourceDatabase.ReleaseResource(handle);
|
||||
}
|
||||
|
||||
_d3d12MA.Dispose();
|
||||
_temResources.Dispose();
|
||||
_tempResources.Dispose();
|
||||
|
||||
_disposed = true;
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using Ghost.Core;
|
||||
using Ghost.Graphics.Core;
|
||||
using Ghost.Graphics.D3D12.Utilities;
|
||||
using Ghost.Graphics.RHI;
|
||||
using Misaki.HighPerformance.Collections;
|
||||
using Misaki.HighPerformance.LowLevel;
|
||||
using Misaki.HighPerformance.LowLevel.Buffer;
|
||||
using Misaki.HighPerformance.LowLevel.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using TerraFX.Interop.DirectX;
|
||||
|
||||
@@ -42,7 +42,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
public readonly bool isExternal;
|
||||
|
||||
public readonly bool Allocated => isExternal ? resourceUnion.resource.Get() != null : resourceUnion.allocation.Get() != null;
|
||||
public readonly ID3D12Resource* ResourcePtr => isExternal ? resourceUnion.resource.Get() : resourceUnion.allocation.Get()->GetResource();
|
||||
public readonly SharedPtr<ID3D12Resource> ResourcePtr => isExternal ? resourceUnion.resource.Get() : resourceUnion.allocation.Get()->GetResource();
|
||||
|
||||
public ResourceRecord(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState state, ResourceViewGroup resourceDescriptor, ResourceDesc desc)
|
||||
{
|
||||
@@ -131,7 +131,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
resource = default!;
|
||||
}
|
||||
|
||||
public unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string? name = null)
|
||||
public unsafe Handle<GPUResource> ImportExternalResource(ID3D12Resource* pResource, ResourceState initialState, ResourceViewGroup viewGroup, string name = "")
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
@@ -139,16 +139,14 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
var handle = new Handle<GPUResource>(id, generation);
|
||||
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
if (name != null)
|
||||
{
|
||||
_resourceName[handle] = name;
|
||||
}
|
||||
pResource->SetName(name);
|
||||
_resourceName[handle] = name;
|
||||
#endif
|
||||
|
||||
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> AddResource(D3D12MA_Allocation* allocation, uint cpuFenceValue, ResourceState initialState, ResourceViewGroup resourceDescriptor, ResourceDesc desc, string name = "")
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
@@ -156,10 +154,8 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
var handle = new Handle<GPUResource>(id, generation);
|
||||
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
if (name != null)
|
||||
{
|
||||
_resourceName[handle] = name;
|
||||
}
|
||||
allocation->SetName(name);
|
||||
_resourceName[handle] = name;
|
||||
#endif
|
||||
|
||||
return handle;
|
||||
@@ -184,7 +180,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
return ref info;
|
||||
}
|
||||
|
||||
public ref ResourceRecord GetResourceInfo(Handle<GPUResource> handle, out bool exist)
|
||||
public ref ResourceRecord GetResourceRecord(Handle<GPUResource> handle, out bool exist)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
return ref _resources.GetElementReferenceAt(handle.id, handle.generation, out exist);
|
||||
@@ -232,7 +228,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
ref var info = ref GetResourceInfo(handle, out var exist);
|
||||
ref var info = ref GetResourceRecord(handle, out var exist);
|
||||
if (!exist || !info.Allocated)
|
||||
{
|
||||
return -1;
|
||||
@@ -254,7 +250,7 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
return null;
|
||||
}
|
||||
|
||||
public unsafe void ReleaseResource(Handle<GPUResource> handle)
|
||||
public void ReleaseResource(Handle<GPUResource> handle)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
@@ -269,14 +265,10 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
return;
|
||||
}
|
||||
|
||||
var refCount = info.Release(_descriptorAllocator);
|
||||
info.Release(_descriptorAllocator);
|
||||
//Debug.Assert(info.Release(_descriptorAllocator) == 0);
|
||||
#if DEBUG || GHOST_EDITOR
|
||||
_resourceName.Remove(handle, out var name);
|
||||
//if (refCount > 0)
|
||||
//{
|
||||
// throw new GPUResourceLeakException(refCount, info.ResourcePtr, name ?? "Unknown Resource");
|
||||
//}
|
||||
//Debug.Assert(refCount == 0, "Resource released with non-zero reference count.");
|
||||
#endif
|
||||
|
||||
_resources.Remove(handle.id, handle.generation);
|
||||
@@ -405,34 +397,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase
|
||||
ReleaseResource(ref shader);
|
||||
}
|
||||
|
||||
public void AddShaderPass(ShaderPassKey passKey, ShaderPass pass)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
_shaderPasses.Add(passKey, pass);
|
||||
}
|
||||
|
||||
public ShaderPass GetShaderPass(ShaderPassKey passKey)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (!_shaderPasses.TryGetValue(passKey, out var pass))
|
||||
{
|
||||
throw new KeyNotFoundException($"Shader pass '{passKey}' not found.");
|
||||
}
|
||||
|
||||
return pass;
|
||||
}
|
||||
|
||||
public void RemoveShaderPass(ShaderPassKey passKey)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
if (_shaderPasses.Remove(passKey, out var pass))
|
||||
{
|
||||
ReleaseResource(ref pass);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
static void ThrowMemoryLeakException(string resourceType, int count)
|
||||
|
||||
@@ -7,6 +7,7 @@ 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 TerraFX.Interop.DirectX;
|
||||
using TerraFX.Interop.Windows;
|
||||
@@ -27,7 +28,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
||||
private UniquePtr<IDXGISwapChain4> _swapChain;
|
||||
private UnsafeArray<Handle<Texture>> _backBuffers;
|
||||
|
||||
private object? _compositionSurface;
|
||||
private readonly object? _compositionSurface;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
@@ -48,20 +49,22 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
||||
|
||||
public D3D12SwapChain(D3D12ResourceDatabase resourceDatabase, D3D12DescriptorAllocator descriptorAllocator, D3D12RenderDevice device, SwapChainDesc desc)
|
||||
{
|
||||
Debug.Assert(desc.BufferCount >= 2);
|
||||
|
||||
_resourceDatabase = resourceDatabase;
|
||||
_descriptorAllocator = descriptorAllocator;
|
||||
_renderDevice = device;
|
||||
|
||||
_backBuffers = new UnsafeArray<Handle<Texture>>(D3D12PipelineResource.BACK_BUFFER_COUNT, Allocator.Persistent);
|
||||
_backBuffers = new UnsafeArray<Handle<Texture>>((int)desc.BufferCount, Allocator.Persistent);
|
||||
|
||||
Width = desc.width;
|
||||
Height = desc.height;
|
||||
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT;
|
||||
Width = desc.Width;
|
||||
Height = desc.Height;
|
||||
BufferCount = desc.BufferCount;
|
||||
|
||||
CreateSwapChain(desc);
|
||||
CreateBackBuffers();
|
||||
|
||||
_compositionSurface = desc.target.compositionSurface;
|
||||
_compositionSurface = desc.Target.CompositionSurface;
|
||||
}
|
||||
|
||||
~D3D12SwapChain()
|
||||
@@ -73,9 +76,9 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
||||
{
|
||||
var swapChainDesc = new DXGI_SWAP_CHAIN_DESC1
|
||||
{
|
||||
Width = desc.width,
|
||||
Height = desc.height,
|
||||
Format = desc.format.ToDXGIFormat(),
|
||||
Width = desc.Width,
|
||||
Height = desc.Height,
|
||||
Format = desc.Format.ToDXGIFormat(),
|
||||
SampleDesc = new DXGI_SAMPLE_DESC(1, 0),
|
||||
BufferUsage = DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
||||
BufferCount = D3D12PipelineResource.BACK_BUFFER_COUNT,
|
||||
@@ -91,15 +94,15 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
||||
var pFactory = _renderDevice.DXGIFactory.Get();
|
||||
var pCommandQueue = _renderDevice.NativeGraphicsQueue.Get();
|
||||
|
||||
switch (desc.target.type)
|
||||
switch (desc.Target.Type)
|
||||
{
|
||||
case SwapChainTargetType.Composition:
|
||||
ThrowIfFailed(pFactory->CreateSwapChainForComposition((IUnknown*)pCommandQueue, &swapChainDesc, null, &pTempSwapChain));
|
||||
|
||||
// Set the composition surface
|
||||
if (desc.target.compositionSurface != null)
|
||||
if (desc.Target.CompositionSurface != null)
|
||||
{
|
||||
using var swapChainPanelNative = ISwapChainPanelNative.FromSwapChainPanel(desc.target.compositionSurface);
|
||||
using var swapChainPanelNative = ISwapChainPanelNative.FromSwapChainPanel(desc.Target.CompositionSurface);
|
||||
swapChainPanelNative.SetSwapChain((IntPtr)pTempSwapChain);
|
||||
}
|
||||
break;
|
||||
@@ -112,7 +115,7 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
||||
|
||||
pFactory->CreateSwapChainForHwnd(
|
||||
(IUnknown*)pCommandQueue,
|
||||
new HWND(desc.target.windowHandle.ToPointer()),
|
||||
new HWND(desc.Target.WindowHandle.ToPointer()),
|
||||
&swapChainDesc,
|
||||
&swapChainFullscreenDesc,
|
||||
null,
|
||||
@@ -141,7 +144,12 @@ internal unsafe class D3D12SwapChain : ISwapChain
|
||||
var rtv = _descriptorAllocator.AllocateRTV();
|
||||
_renderDevice.NativeDevice.Get()->CreateRenderTargetView(pBackBuffer, null, _descriptorAllocator.GetCpuHandle(rtv));
|
||||
|
||||
var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present, new ResourceViewGroup() { rtv = rtv });
|
||||
var view = ResourceViewGroup.Invalid with
|
||||
{
|
||||
rtv = rtv
|
||||
};
|
||||
|
||||
var handle = _resourceDatabase.ImportExternalResource(pBackBuffer, ResourceState.Present, view);
|
||||
_backBuffers[i] = handle.AsTexture();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,12 +164,17 @@ internal unsafe struct D3D12DescriptorHeap : IDisposable
|
||||
|
||||
public void ReleaseDescriptors(int baseIndex, int count = 1)
|
||||
{
|
||||
if (baseIndex == _INVALID_DESCRIPTOR_INDEX)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (baseIndex < _dynamicHeapStart)
|
||||
if (baseIndex >= _dynamicHeapStart)
|
||||
{
|
||||
// Dynamic allocations are not released individually.
|
||||
return;
|
||||
|
||||
@@ -10,6 +10,19 @@ internal unsafe static class D3D12Utility
|
||||
{
|
||||
public static void SetName<T>(ref this T obj, ReadOnlySpan<char> name)
|
||||
where T : unmanaged, ID3D12Object.Interface
|
||||
{
|
||||
if (name.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fixed (char* pName = name)
|
||||
{
|
||||
obj.SetName(pName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetName(ref this D3D12MA_Allocation obj, ReadOnlySpan<char> name)
|
||||
{
|
||||
fixed (char* pName = name)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user