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:
2025-11-28 18:58:50 +09:00
parent 0720444c2c
commit bd97d233cb
49 changed files with 842 additions and 1025 deletions

View File

@@ -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();

View File

@@ -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);

View File

@@ -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()

View File

@@ -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))

View File

@@ -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());

View File

@@ -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);

View File

@@ -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)

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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)
{