diff --git a/HexaEngine.Core/Graphics/SamplerState.cs b/HexaEngine.Core/Graphics/SamplerState.cs new file mode 100644 index 00000000..ea5d46ae --- /dev/null +++ b/HexaEngine.Core/Graphics/SamplerState.cs @@ -0,0 +1,23 @@ +namespace HexaEngine.Core.Graphics +{ + public class SamplerState : DisposableBase, ISamplerState + { + private readonly ISamplerState samplerState; + + public SamplerState(SamplerStateDescription description) + { + samplerState = Application.GraphicsDevice.CreateSamplerState(description); + } + + public SamplerStateDescription Description => samplerState.Description; + + public string? DebugName { get => samplerState.DebugName; set => samplerState.DebugName = value; } + + public nint NativePointer => samplerState.NativePointer; + + protected override void DisposeCore() + { + samplerState.Dispose(); + } + } +} \ No newline at end of file diff --git a/HexaEngine.OpenGL/OpenGLGraphicsContext.cs b/HexaEngine.OpenGL/OpenGLGraphicsContext.cs index 9fba0724..09e6b9b3 100644 --- a/HexaEngine.OpenGL/OpenGLGraphicsContext.cs +++ b/HexaEngine.OpenGL/OpenGLGraphicsContext.cs @@ -533,7 +533,7 @@ internal void SetBlendState(BlendDescription blend, Vector4 blendFactor, uint sa } else { - GL.Enable(EnableCap.SampleAlphaToCoverage); + GL.Disable(EnableCap.SampleAlphaToCoverage); } for (uint i = 0; i < blend.RenderTarget.Length; i++) diff --git a/HexaEngine/Graphics/Culling/CullingContext.cs b/HexaEngine/Graphics/Culling/CullingContext.cs index 9f156185..a0eb8a99 100644 --- a/HexaEngine/Graphics/Culling/CullingContext.cs +++ b/HexaEngine/Graphics/Culling/CullingContext.cs @@ -16,11 +16,12 @@ public class CullingContext private readonly StructuredBuffer instanceDataBuffer; private readonly StructuredUavBuffer swapBuffer; private readonly DrawIndirectArgsBuffer drawIndirectArgs; + private readonly StructuredUavBuffer visibleListBuffer; private uint currentType; private int count; private int typeCount; - public CullingContext(StructuredBuffer instanceOffsetsNoCull, StructuredBuffer instanceDataNoCull, StructuredUavBuffer instanceOffsets, StructuredUavBuffer instanceDataOutBuffer, StructuredBuffer typeDataBuffer, StructuredBuffer instanceDataBuffer, StructuredUavBuffer swapBuffer, DrawIndirectArgsBuffer drawIndirectArgs) + public CullingContext(StructuredBuffer instanceOffsetsNoCull, StructuredBuffer instanceDataNoCull, StructuredUavBuffer instanceOffsets, StructuredUavBuffer instanceDataOutBuffer, StructuredBuffer typeDataBuffer, StructuredBuffer instanceDataBuffer, StructuredUavBuffer swapBuffer, DrawIndirectArgsBuffer drawIndirectArgs, StructuredUavBuffer visibleListBuffer) { this.instanceOffsetsNoCull = instanceOffsetsNoCull; this.instanceDataNoCull = instanceDataNoCull; @@ -30,6 +31,7 @@ public CullingContext(StructuredBuffer instanceOffsetsNoCull, StructuredBu this.instanceDataBuffer = instanceDataBuffer; this.swapBuffer = swapBuffer; this.drawIndirectArgs = drawIndirectArgs; + this.visibleListBuffer = visibleListBuffer; } public StructuredBuffer InstanceOffsetsNoCull => instanceOffsetsNoCull; @@ -41,6 +43,8 @@ public CullingContext(StructuredBuffer instanceOffsetsNoCull, StructuredBu public StructuredUavBuffer InstanceDataOutBuffer => instanceDataOutBuffer; public DrawIndirectArgsBuffer DrawIndirectArgs => drawIndirectArgs; + public StructuredUavBuffer SwapBuffer => swapBuffer; + public StructuredUavBuffer VisibleList => visibleListBuffer; public uint CurrentType => currentType; @@ -63,7 +67,7 @@ public void Flush(IGraphicsContext context) swapBuffer.Update(context); drawIndirectArgs.Capacity = instanceOffsets.Capacity = swapBuffer.Capacity; - instanceDataOutBuffer.Capacity = instanceDataBuffer.Capacity; + visibleListBuffer.Capacity = instanceDataOutBuffer.Capacity = instanceDataBuffer.Capacity; instanceDataBuffer.Update(context); typeCount = (int)typeDataBuffer.Count; count = (int)instanceDataBuffer.Count; @@ -79,38 +83,41 @@ public unsafe uint GetDrawArgsOffset() return currentType * (uint)sizeof(DrawIndexedInstancedIndirectArgs); } - public void AppendType(TypeData type) + public uint AppendType(TypeData type) { swapBuffer.Add(new(type.IndexCountPerInstance, 0, type.StartIndexLocation, type.BaseVertexLocation, type.StartInstanceLocation)); instanceOffsetsNoCull.Add(instanceDataNoCull.Count); currentType = typeDataBuffer.Count; typeDataBuffer.Add(type); + return currentType; } - public void AppendType(uint indexCountPerInstance, uint startIndexLocation = 0, int baseVertexLocation = 0, uint startInstanceLocation = 0) + public uint AppendType(uint indexCountPerInstance, uint startIndexLocation = 0, int baseVertexLocation = 0, uint startInstanceLocation = 0) { - AppendType(new(indexCountPerInstance, startIndexLocation, baseVertexLocation, startInstanceLocation)); + return AppendType(new(indexCountPerInstance, startIndexLocation, baseVertexLocation, startInstanceLocation)); } - public void AppendInstance(GPUInstance instance) + public uint AppendInstance(GPUInstance instance) { + uint id = instanceDataBuffer.Count; instanceDataNoCull.Add(instance.World); instanceDataBuffer.Add(instance); + return id; } - public void AppendInstance(Matrix4x4 world, Vector3 center, float radius) + public uint AppendInstance(Matrix4x4 world, Vector3 center, float radius) { - AppendInstance(new(currentType, world, center, radius)); + return AppendInstance(new(currentType, world, center, radius)); } - public void AppendInstance(Matrix4x4 world, BoundingBox boundingBox) + public uint AppendInstance(Matrix4x4 world, BoundingBox boundingBox) { - AppendInstance(new(currentType, world, boundingBox)); + return AppendInstance(new(currentType, world, boundingBox)); } - public void AppendInstance(Matrix4x4 world, BoundingSphere boundingSphere) + public uint AppendInstance(Matrix4x4 world, BoundingSphere boundingSphere) { - AppendInstance(new(currentType, world, boundingSphere)); + return AppendInstance(new(currentType, world, boundingSphere)); } } } \ No newline at end of file diff --git a/HexaEngine/Graphics/Culling/CullingManager.cs b/HexaEngine/Graphics/Culling/CullingManager.cs index c80a5d82..6ea80621 100644 --- a/HexaEngine/Graphics/Culling/CullingManager.cs +++ b/HexaEngine/Graphics/Culling/CullingManager.cs @@ -15,10 +15,10 @@ public class CullingManager { #nullable disable private readonly IGraphicsDevice device; - private CullingFlags cullingFlags = CullingFlags.All | CullingFlags.Debug; - private float depthBias = 0.00001f; + private CullingFlags cullingFlags = CullingFlags.All; + private float depthBias = 0.0f; - private IComputePipeline occlusion; + private IComputePipeline culling; private ConstantBuffer occlusionCameraBuffer; private StructuredUavBuffer instanceOffsets; @@ -27,24 +27,25 @@ public class CullingManager private StructuredBuffer instanceDataBuffer; private StructuredUavBuffer swapBuffer; private DrawIndirectArgsBuffer drawIndirectArgs; + private StructuredUavBuffer visibleListBuffer; private StructuredBuffer instanceOffsetsNoCull; private StructuredBuffer instanceDataNoCull; private ConstantBuffer occlusionParamBuffer; - private ISamplerState sampler; - private unsafe void** occlusionSrvs; - private unsafe void** occlusionUavs; - private unsafe void** occlusionCbs; + private SamplerState sampler; + private unsafe void** cullingSRVs; + private unsafe void** cullingUAVs; + private unsafe void** cullingCBVs; private readonly CullingContext context; #nullable enable public unsafe CullingManager(IGraphicsDevice device) { this.device = device; - occlusion = device.CreateComputePipeline(new() + culling = device.CreateComputePipeline(new() { - Path = "compute/occlusion/occlusion.hlsl", + Path = "compute/culling/culling.hlsl", }); instanceDataNoCull = new(CpuAccessFlags.Write); @@ -58,17 +59,19 @@ public unsafe CullingManager(IGraphicsDevice device) instanceDataBuffer = new(CpuAccessFlags.Write); swapBuffer = new(CpuAccessFlags.RW); drawIndirectArgs = new(CpuAccessFlags.Write); - sampler = device.CreateSamplerState(new(Filter.MaximumMinMagLinearMipPoint, TextureAddressMode.Clamp)); - occlusionCbs = AllocArray(2); - occlusionCbs[0] = (void*)occlusionParamBuffer.Buffer.NativePointer; - occlusionCbs[1] = (void*)occlusionCameraBuffer.Buffer.NativePointer; - occlusionUavs = AllocArray(3); - occlusionUavs[0] = (void*)instanceDataOutBuffer.UAV.NativePointer; - occlusionUavs[1] = (void*)instanceOffsets.UAV.NativePointer; - occlusionUavs[2] = (void*)swapBuffer.UAV.NativePointer; - occlusionSrvs = AllocArray(2); - occlusionSrvs[1] = (void*)instanceDataBuffer.SRV.NativePointer; - context = new(instanceOffsetsNoCull, instanceDataNoCull, instanceOffsets, instanceDataOutBuffer, typeDataBuffer, instanceDataBuffer, swapBuffer, drawIndirectArgs); + visibleListBuffer = new(CpuAccessFlags.Read); + sampler = new(new(Filter.MaximumMinMagLinearMipPoint, TextureAddressMode.Clamp)); + cullingCBVs = AllocArray(2); + cullingCBVs[0] = (void*)occlusionParamBuffer.Buffer.NativePointer; + cullingCBVs[1] = (void*)occlusionCameraBuffer.Buffer.NativePointer; + cullingUAVs = AllocArray(4); + cullingUAVs[0] = (void*)instanceDataOutBuffer.UAV.NativePointer; + cullingUAVs[1] = (void*)instanceOffsets.UAV.NativePointer; + cullingUAVs[2] = (void*)swapBuffer.UAV.NativePointer; + cullingUAVs[3] = (void*)visibleListBuffer.UAV.NativePointer; + cullingSRVs = AllocArray(2); + cullingSRVs[1] = (void*)instanceDataBuffer.SRV.NativePointer; + context = new(instanceOffsetsNoCull, instanceDataNoCull, instanceOffsets, instanceDataOutBuffer, typeDataBuffer, instanceDataBuffer, swapBuffer, drawIndirectArgs, visibleListBuffer); } public static CullingManager Current { get; internal set; } = new(Application.GraphicsDevice); @@ -116,7 +119,7 @@ private static Vector3 ExtractScale(Matrix4x4 matrix) return scale; } - public unsafe void ExecuteCulling(IGraphicsContext context, Camera camera, int instanceCount, int typeCount, DepthMipChain mipChain) + public unsafe void ExecuteCulling(IGraphicsContext context, Camera camera, int instanceCount, int typeCount, DepthMipChain mipChain, ICPUProfiler? profiler) { if (instanceCount == 0) { @@ -145,30 +148,31 @@ public unsafe void ExecuteCulling(IGraphicsContext context, Camera camera, int i }; occlusionParamBuffer.Update(context); - occlusionUavs[0] = (void*)instanceDataOutBuffer.UAV.NativePointer; - occlusionUavs[1] = (void*)instanceOffsets.UAV.NativePointer; - occlusionUavs[2] = (void*)swapBuffer.UAV.NativePointer; + cullingUAVs[0] = (void*)instanceDataOutBuffer.UAV.NativePointer; + cullingUAVs[1] = (void*)instanceOffsets.UAV.NativePointer; + cullingUAVs[2] = (void*)swapBuffer.UAV.NativePointer; + cullingUAVs[3] = (void*)visibleListBuffer.UAV.NativePointer; - occlusionSrvs[1] = (void*)instanceDataBuffer.SRV.NativePointer; - occlusionSrvs[0] = (void*)mipChain.SRV.NativePointer; + cullingSRVs[1] = (void*)instanceDataBuffer.SRV.NativePointer; + cullingSRVs[0] = (void*)mipChain.SRV.NativePointer; uint* initialCount = stackalloc uint[] { unchecked((uint)-1), unchecked((uint)-1), unchecked((uint)-1) }; - context.CSSetShaderResources(0, 2, occlusionSrvs); - context.CSSetUnorderedAccessViews(3, occlusionUavs, initialCount); + context.CSSetShaderResources(0, 2, cullingSRVs); + context.CSSetUnorderedAccessViews(4, cullingUAVs, initialCount); context.CSSetSampler(0, sampler); - context.CSSetConstantBuffers(0, 2, occlusionCbs); - occlusion.Dispatch(context, (uint)instanceCount / 1024 + 1, 1, 1); + context.CSSetConstantBuffers(0, 2, cullingCBVs); + culling.Dispatch(context, (uint)instanceCount / 1024 + 1, 1, 1); context.ClearState(); swapBuffer.CopyTo(context, drawIndirectArgs.Buffer); + visibleListBuffer.Read(context); + swapBuffer.Read(context); if ((cullingFlags & CullingFlags.Debug) == 0) { return; } - swapBuffer.Read(context); - uint drawCalls = 0; uint drawInstanceCount = 0; uint vertexCount = 0; @@ -210,7 +214,7 @@ public unsafe void ExecuteCulling(IGraphicsContext context, Camera camera, int i _ => 'M', }; - ImGui.Text($"Draw Calls: {drawCalls}, Instances: {drawInstanceCount}, Vertices: {vertexCount}{suffix}"); + ImGui.Text($"Draw Calls: {typeCount}/{drawCalls}, Instances: {instanceCount}/{drawInstanceCount}, Vertices: {vertexCount}{suffix}"); var flags = (int)cullingFlags; ImGui.CheckboxFlags("Frustum Culling", ref flags, (int)CullingFlags.Frustum); @@ -244,17 +248,17 @@ public unsafe void Release() occlusionParamBuffer.Dispose(); occlusionParamBuffer = null; - occlusion.Dispose(); - occlusion = null; + culling.Dispose(); + culling = null; sampler.Dispose(); sampler = null; - Free(occlusionSrvs); - occlusionSrvs = null; - Free(occlusionUavs); - occlusionUavs = null; - Free(occlusionCbs); - occlusionCbs = null; + Free(cullingSRVs); + cullingSRVs = null; + Free(cullingUAVs); + cullingUAVs = null; + Free(cullingCBVs); + cullingCBVs = null; } } } \ No newline at end of file diff --git a/HexaEngine/Graphics/Passes/ObjectCullPass.cs b/HexaEngine/Graphics/Passes/ObjectCullPass.cs index 813dcb5f..2259ebd9 100644 --- a/HexaEngine/Graphics/Passes/ObjectCullPass.cs +++ b/HexaEngine/Graphics/Passes/ObjectCullPass.cs @@ -35,7 +35,7 @@ public override void Execute(IGraphicsContext context, GraphResourceBuilder crea var cull = manager.Context; manager.UpdateCamera(context, camera, creator.Viewport); - manager.ExecuteCulling(context, camera, cull.Count, cull.TypeCount, chain.Value); + manager.ExecuteCulling(context, camera, cull.Count, cull.TypeCount, chain.Value, profiler); } } } \ No newline at end of file diff --git a/HexaEngine/Meshes/DrawInstance.cs b/HexaEngine/Meshes/DrawInstance.cs index 4f1d3dd6..3ef39c9b 100644 --- a/HexaEngine/Meshes/DrawInstance.cs +++ b/HexaEngine/Meshes/DrawInstance.cs @@ -5,6 +5,7 @@ public class DrawInstance { + public uint InstanceId; public int NodeId; public Matrix4x4 Transform; public BoundingSphere BoundingSphere; diff --git a/HexaEngine/assets/shared/shaders/compute/occlusion/occlusion.hlsl b/HexaEngine/assets/shared/shaders/compute/culling/culling.hlsl similarity index 98% rename from HexaEngine/assets/shared/shaders/compute/occlusion/occlusion.hlsl rename to HexaEngine/assets/shared/shaders/compute/culling/culling.hlsl index 0c956d6c..2416811a 100644 --- a/HexaEngine/assets/shared/shaders/compute/occlusion/occlusion.hlsl +++ b/HexaEngine/assets/shared/shaders/compute/culling/culling.hlsl @@ -82,6 +82,7 @@ StructuredBuffer instanceDataIn : register(t1); RWStructuredBuffer instanceDataOut : register(u0); RWStructuredBuffer instanceOffsets : register(u1); RWStructuredBuffer drawArgs : register(u2); +RWStructuredBuffer visibleListOut : register(u3); SamplerState samplerPoint : register(s0); groupshared uint temp[1024]; @@ -151,6 +152,7 @@ void main(uint3 threadID : SV_DispatchThreadID) } temp[di] = visible; + visibleListOut[di] = visible; GroupMemoryBarrier(); diff --git a/HexaEngine/assets/shared/shaders/compute/occlusion/sort.hlsl b/HexaEngine/assets/shared/shaders/compute/culling/sort.hlsl similarity index 100% rename from HexaEngine/assets/shared/shaders/compute/occlusion/sort.hlsl rename to HexaEngine/assets/shared/shaders/compute/culling/sort.hlsl