diff --git a/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapAllocatorDX12.cs b/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapAllocatorDX12.cs index e3a06ce25..2929c3b6a 100644 --- a/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapAllocatorDX12.cs +++ b/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapAllocatorDX12.cs @@ -7,7 +7,7 @@ internal class DescriptorHeapAllocatorDX12 : GpuObject DescriptorHeapType _type; DescriptorHeapDesc _desc; - internal DescriptorHeapAllocatorDX12(DeviceDX12 device, DescriptorHeapType type, DescriptorHeapFlags flags) : + internal DescriptorHeapAllocatorDX12(DeviceDX12 device, DescriptorHeapType type, DescriptorHeapFlags flags, uint numDescriptors) : base(device) { _heaps = new List(); @@ -17,10 +17,16 @@ internal DescriptorHeapAllocatorDX12(DeviceDX12 device, DescriptorHeapType type, NodeMask = 0, Type = type, Flags = flags, - NumDescriptors = 64, + NumDescriptors = numDescriptors, }; } + internal void Reset() + { + for (int i = 0; i < _heaps.Count; i++) + _heaps[i].Reset(); + } + internal HeapHandleDX12 Allocate(uint numDescriptors) { if(numDescriptors > _desc.NumDescriptors) diff --git a/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapDX12.cs b/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapDX12.cs index 992b8a82d..1211f566b 100644 --- a/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapDX12.cs +++ b/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapDX12.cs @@ -29,6 +29,11 @@ internal DescriptorHeapDX12(DeviceDX12 device, DescriptorHeapDesc desc) : _cpuStartHandle = _handle->GetCPUDescriptorHandleForHeapStart(); } + internal void Reset() + { + _availabilityMask = 0; + } + internal bool TryAllocate(uint numSlots, out HeapHandleDX12 handle) { handle = default; @@ -55,7 +60,7 @@ internal bool TryAllocate(uint numSlots, out HeapHandleDX12 handle) if ((i + 1) - startIndex == numSlots) { _availabilityMask |= slotMask; - handle.CpuHandle = new CpuDescriptorHandle(_cpuStartHandle.Ptr + (startIndex * _incrementSize)); + handle.Handle = new CpuDescriptorHandle(_cpuStartHandle.Ptr + (startIndex * _incrementSize)); handle.Heap = this; handle.StartIndex = startIndex; handle.NumSlots = numSlots; diff --git a/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapManagerDX12.cs b/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapManagerDX12.cs index 8b84cda82..c14009355 100644 --- a/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapManagerDX12.cs +++ b/Molten.Graphics.DX12/Pipeline/Heap/DescriptorHeapManagerDX12.cs @@ -11,8 +11,11 @@ internal class DescriptorHeapManagerDX12 : GpuObject DescriptorHeapAllocatorDX12 _dsvHeap; DescriptorHeapAllocatorDX12 _rtvHeap; - GpuFrameBuffer _gpuResourceHeap; - GpuFrameBuffer _gpuSamplerHeap; + GpuFrameBuffer _gpuResourceHeap; + GpuFrameBuffer _gpuSamplerHeap; + + DescriptorHeapAllocatorDX12 _prevGpuResourceHeap; + DescriptorHeapAllocatorDX12 _prevGpuSamplerHeap; /// /// Creates a new instance of . @@ -22,31 +25,25 @@ internal class DescriptorHeapManagerDX12 : GpuObject internal unsafe DescriptorHeapManagerDX12(DeviceDX12 device) : base(device) { - _resourceHeap = new DescriptorHeapAllocatorDX12(device, DescriptorHeapType.CbvSrvUav, DescriptorHeapFlags.None); - _samplerHeap = new DescriptorHeapAllocatorDX12(device, DescriptorHeapType.Sampler, DescriptorHeapFlags.None); - _dsvHeap = new DescriptorHeapAllocatorDX12(device, DescriptorHeapType.Dsv, DescriptorHeapFlags.None); - _rtvHeap = new DescriptorHeapAllocatorDX12(device, DescriptorHeapType.Rtv, DescriptorHeapFlags.None); + _resourceHeap = new DescriptorHeapAllocatorDX12(device, DescriptorHeapType.CbvSrvUav, DescriptorHeapFlags.None, 64); + _samplerHeap = new DescriptorHeapAllocatorDX12(device, DescriptorHeapType.Sampler, DescriptorHeapFlags.None, 64); + _dsvHeap = new DescriptorHeapAllocatorDX12(device, DescriptorHeapType.Dsv, DescriptorHeapFlags.None, 64); + _rtvHeap = new DescriptorHeapAllocatorDX12(device, DescriptorHeapType.Rtv, DescriptorHeapFlags.None, 64); - _gpuResourceHeap = new GpuFrameBuffer(device, (creationDevice) => + _gpuResourceHeap = new GpuFrameBuffer(device, (creationDevice) => { - return new DescriptorHeapDX12(creationDevice as DeviceDX12, new DescriptorHeapDesc() - { - NodeMask = 0, - Type = DescriptorHeapType.CbvSrvUav, - Flags = DescriptorHeapFlags.ShaderVisible, - NumDescriptors = RESOURCE_HEAP_SIZE, - }); + return new DescriptorHeapAllocatorDX12(creationDevice as DeviceDX12, + DescriptorHeapType.CbvSrvUav, + DescriptorHeapFlags.ShaderVisible, + RESOURCE_HEAP_SIZE); }); - _gpuSamplerHeap = new GpuFrameBuffer(device, (creationDevice) => + _gpuSamplerHeap = new GpuFrameBuffer(device, (creationDevice) => { - return new DescriptorHeapDX12(creationDevice as DeviceDX12, new DescriptorHeapDesc() - { - NodeMask = 0, - Type = DescriptorHeapType.Sampler, - Flags = DescriptorHeapFlags.ShaderVisible, - NumDescriptors = SAMPLER_HEAP_SIZE, - }); + return new DescriptorHeapAllocatorDX12(creationDevice as DeviceDX12, + DescriptorHeapType.Sampler, + DescriptorHeapFlags.ShaderVisible, + SAMPLER_HEAP_SIZE); }); } @@ -75,16 +72,44 @@ internal HeapHandleDX12 GetSamplerHandle(uint numDescriptors) /// internal unsafe void PrepareGpuHeap(ShaderPassDX12 pass, PipelineStateDX12 state, CommandListDX12 cmd) { - // throw new Exception("The number of resource bindings in the pass does not match the number of bind points in the root signature."); + HeapHandleDX12 resTable = PrepareResourceTable(pass, state, cmd); + HeapHandleDX12 samplerTable = PrepareSamplerTable(pass, state, cmd); + //state.RootSignature.Meta.ToLog(Device.Log); + + if (resTable.Heap != null && samplerTable.Heap != null) + { + ID3D12DescriptorHeap** pHeaps = stackalloc ID3D12DescriptorHeap*[2] { resTable.Heap.Handle, samplerTable.Heap.Handle }; + + cmd.Handle->SetDescriptorHeaps(2, pHeaps); + cmd.Handle->SetGraphicsRootDescriptorTable(0, resTable.GetGpuHandle()); + cmd.Handle->SetGraphicsRootDescriptorTable(1, samplerTable.GetGpuHandle()); + } + else if (resTable.Heap != null) + { + ID3D12DescriptorHeap** pHeaps = stackalloc ID3D12DescriptorHeap*[1] { resTable.Heap.Handle }; + cmd.Handle->SetDescriptorHeaps(1, pHeaps); + cmd.Handle->SetGraphicsRootDescriptorTable(0, resTable.GetGpuHandle()); + } + else if (samplerTable.Heap != null) + { + ID3D12DescriptorHeap** pHeaps = stackalloc ID3D12DescriptorHeap*[1] { samplerTable.Heap.Handle }; + cmd.Handle->SetDescriptorHeaps(1, pHeaps); + cmd.Handle->SetGraphicsRootDescriptorTable(0, samplerTable.GetGpuHandle()); + } + } + + private unsafe HeapHandleDX12 PrepareResourceTable(ShaderPassDX12 pass, PipelineStateDX12 state, CommandListDX12 cmd) + { + if(pass.Bindings.TotalResourceBindings == 0) + return new HeapHandleDX12(); DeviceDX12 device = pass.Device as DeviceDX12; - DescriptorHeapDX12 resHeap = _gpuResourceHeap.Prepare(); - CpuDescriptorHandle gpuResHandle = resHeap.CpuStartHandle; - uint resBindCount = 0; + DescriptorHeapAllocatorDX12 resAllocator = _gpuResourceHeap.Prepare(); + if (resAllocator != _prevGpuResourceHeap) + resAllocator.Reset(); - DescriptorHeapDX12 samplerHeap = _gpuSamplerHeap.Prepare(); - CpuDescriptorHandle gpuSamplerHandle = samplerHeap.CpuStartHandle; - uint samplerBindCount = 0; + HeapHandleDX12 gpuResHandle = resAllocator.Allocate(pass.Bindings.TotalResourceBindings); + HeapHandleDX12 resTableHandle = gpuResHandle; // TODO Replace this once DX11 is removed and resources can be created during instantiation instead of during Apply(). // Apply resources. @@ -123,55 +148,59 @@ internal unsafe void PrepareGpuHeap(ShaderPassDX12 pass, PipelineStateDX12 state if (cpuHandle.Ptr != 0) { - device.Handle->CopyDescriptorsSimple(1, gpuResHandle, cpuHandle, DescriptorHeapType.CbvSrvUav); - - // Increment GPU heap handle - resBindCount++; + Device.Handle->CopyDescriptorsSimple(1, gpuResHandle.Handle, cpuHandle, DescriptorHeapType.CbvSrvUav); } - gpuResHandle.Ptr += resHeap.IncrementSize; + gpuResHandle.Increment(); } } - // Iterate over pass samplers - for (int i = 0; i < pass.Bindings.Samplers.Length; i++) + _prevGpuResourceHeap = resAllocator; + return resTableHandle; + } + + private unsafe HeapHandleDX12 PrepareSamplerTable(ShaderPassDX12 pass, PipelineStateDX12 state, CommandListDX12 cmd) + { + uint numSamplers = (uint)pass.Bindings.Samplers.Length; + uint numHeapSamplers = 0; + + // Perform a quick check to find out how many heap-based samplers we have, if any. + for (uint i = 0; i < numSamplers; i++) { ref ShaderBind bind = ref pass.Bindings.Samplers[i]; - if (!bind.Object.IsImmutable && bind.Object?.Value != null) - { - ShaderSampler heapSampler = bind.Object.Sampler; - // TODO _handleBuffer[index] = heapSampler.View.CpuHandle; - gpuSamplerHandle.Ptr += samplerHeap.IncrementSize; - samplerBindCount++; - } + if (!bind.Object.IsImmutable) + numHeapSamplers++; } - //state.RootSignature.Meta.ToLog(Device.Log); - // Populate SRV, UAV, and CBV descriptors first. - // TODO Pull descriptor info from our pass, render targets, samplers, depth-stencil, etc. + if (numHeapSamplers == 0) + return new HeapHandleDX12(); - if (gpuResHandle.Ptr != resHeap.CpuStartHandle.Ptr - && gpuSamplerHandle.Ptr != samplerHeap.CpuStartHandle.Ptr) - { - ID3D12DescriptorHeap** pHeaps = stackalloc ID3D12DescriptorHeap*[2] { resHeap.Handle, samplerHeap.Handle }; + DescriptorHeapAllocatorDX12 samplerAllocator = _gpuSamplerHeap.Prepare(); + if (samplerAllocator != _prevGpuSamplerHeap) + samplerAllocator.Reset(); - cmd.Handle->SetDescriptorHeaps(2, pHeaps); - cmd.Handle->SetGraphicsRootDescriptorTable(0, resHeap.GetGpuHandle()); - cmd.Handle->SetGraphicsRootDescriptorTable(1, samplerHeap.GetGpuHandle()); - } - else if (gpuResHandle.Ptr != resHeap.CpuStartHandle.Ptr) - { - ID3D12DescriptorHeap** pHeaps = stackalloc ID3D12DescriptorHeap*[1] { resHeap.Handle }; - cmd.Handle->SetDescriptorHeaps(1, pHeaps); - cmd.Handle->SetGraphicsRootDescriptorTable(0, resHeap.GetGpuHandle()); - } - else if (gpuSamplerHandle.Ptr != samplerHeap.CpuStartHandle.Ptr) + HeapHandleDX12 gpuSamplerHandle = samplerAllocator.Allocate(numHeapSamplers); + HeapHandleDX12 samplerTableHandle = gpuSamplerHandle; + + // Iterate over samplers and bind heap-based ones. + for (int i = 0; i < pass.Bindings.Samplers.Length; i++) { - ID3D12DescriptorHeap** pHeaps = stackalloc ID3D12DescriptorHeap*[1] { samplerHeap.Handle }; - cmd.Handle->SetDescriptorHeaps(1, pHeaps); - cmd.Handle->SetGraphicsRootDescriptorTable(0, samplerHeap.GetGpuHandle()); + ref ShaderBind bind = ref pass.Bindings.Samplers[i]; + if (!bind.Object.IsImmutable && bind.Object?.Value != null) + { + ShaderSampler heapSampler = bind.Object.Sampler; + CpuDescriptorHandle cpuHandle = new(); // TODO Retrieve heap handle for HeapSamplerDX12 and copy it to the sampler heap. + + if (cpuHandle.Ptr != 0) + Device.Handle->CopyDescriptorsSimple(1, gpuSamplerHandle.Handle, cpuHandle, DescriptorHeapType.Sampler); + + gpuSamplerHandle.Increment(); + } } + + _prevGpuSamplerHeap = samplerAllocator; + return samplerTableHandle; } protected unsafe override void OnGpuRelease() @@ -183,5 +212,8 @@ protected unsafe override void OnGpuRelease() _gpuResourceHeap.Dispose(true); _gpuSamplerHeap.Dispose(true); + + _prevGpuResourceHeap = null; + _prevGpuSamplerHeap = null; } } \ No newline at end of file diff --git a/Molten.Graphics.DX12/Pipeline/Heap/HeapHandleDX12.cs b/Molten.Graphics.DX12/Pipeline/Heap/HeapHandleDX12.cs index e1ce9c492..f9a3f5e3e 100644 --- a/Molten.Graphics.DX12/Pipeline/Heap/HeapHandleDX12.cs +++ b/Molten.Graphics.DX12/Pipeline/Heap/HeapHandleDX12.cs @@ -1,10 +1,11 @@ using Molten.Graphics.DX12; using Silk.NET.Direct3D12; +using System.Runtime.CompilerServices; namespace Molten.Graphics; internal struct HeapHandleDX12 { - public CpuDescriptorHandle CpuHandle; + public CpuDescriptorHandle Handle; public uint StartIndex; @@ -19,6 +20,20 @@ internal void Free() internal CpuDescriptorHandle GetCpuHandle(uint index) { - return new CpuDescriptorHandle(CpuHandle.Ptr + (index * Heap.IncrementSize)); + return new CpuDescriptorHandle(Handle.Ptr + (index * Heap.IncrementSize)); + } + + internal GpuDescriptorHandle GetGpuHandle() + { + GpuDescriptorHandle handle = Heap.GetGpuHandle(); + handle.Ptr += (StartIndex * Heap.IncrementSize); + return handle; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Increment() + { + StartIndex++; + Handle.Ptr += Heap.IncrementSize; } }