diff --git a/.gitignore b/.gitignore index d60b401..e88f367 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ AGENTS.md ref/ docfx/ +.opencode/ NUL # User-specific files (MonoDevelop/Xamarin Studio) diff --git a/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandBuffer.cs b/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandBuffer.cs index 60dd476..c0828a6 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandBuffer.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/D3D12CommandBuffer.cs @@ -509,6 +509,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, AttachmentLoadOp.Clear => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, AttachmentLoadOp.DontCare => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD, + AttachmentLoadOp.NoAccess => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, _ => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE }; @@ -517,7 +518,8 @@ internal unsafe class D3D12CommandBuffer : D3D12Object D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, AttachmentStoreOp.DontCare => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD, - _ => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE + AttachmentStoreOp.NoAccess => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, + _ => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS }; // Map stencil load operation @@ -526,6 +528,7 @@ internal unsafe class D3D12CommandBuffer : D3D12Object D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, AttachmentLoadOp.Clear => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, AttachmentLoadOp.DontCare => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD, + AttachmentLoadOp.NoAccess => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, _ => D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE }; @@ -534,15 +537,10 @@ internal unsafe class D3D12CommandBuffer : D3D12Object D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, AttachmentStoreOp.DontCare => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD, - _ => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE + AttachmentStoreOp.NoAccess => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, + _ => D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS }; - if (!depthDesc.HasStencil) - { - stencilLoadAccessType = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS; - stencilStoreAccessType = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; - } - var desc = new D3D12_RENDER_PASS_DEPTH_STENCIL_DESC { cpuDescriptor = cpuHandle, diff --git a/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs b/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs index 4352b58..579bc66 100644 --- a/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs +++ b/src/Runtime/Ghost.Graphics.D3D12/Utilities/D3D12Utility.cs @@ -504,7 +504,7 @@ internal static unsafe class D3D12Utility public static D3D12_RASTERIZER_DESC D3D12_RASTERIZER_DESC_CREATE( D3D12_FILL_MODE fillMode, D3D12_CULL_MODE cullMode, - bool frontCounterClockwise = true, + bool frontCounterClockwise = false, int depthBias = D3D12_DEFAULT_DEPTH_BIAS, float depthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP, float slopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS, diff --git a/src/Runtime/Ghost.Graphics.RHI/Common.cs b/src/Runtime/Ghost.Graphics.RHI/Common.cs index 85947d3..8f149ea 100644 --- a/src/Runtime/Ghost.Graphics.RHI/Common.cs +++ b/src/Runtime/Ghost.Graphics.RHI/Common.cs @@ -1359,11 +1359,13 @@ public enum AttachmentLoadOp { Load, Clear, - DontCare + DontCare, + NoAccess } public enum AttachmentStoreOp { Store, - DontCare + DontCare, + NoAccess } diff --git a/src/Runtime/Ghost.Graphics.RHI/RHIUtility.cs b/src/Runtime/Ghost.Graphics.RHI/RHIUtility.cs index 197392b..ca2d6e8 100644 --- a/src/Runtime/Ghost.Graphics.RHI/RHIUtility.cs +++ b/src/Runtime/Ghost.Graphics.RHI/RHIUtility.cs @@ -2,6 +2,7 @@ using Ghost.Core; using Ghost.Core.Graphics; using Ghost.Core.Utilities; using System.IO.Hashing; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ghost.Graphics.RHI; @@ -10,6 +11,7 @@ public static class RHIUtility { public const int MAX_RENDER_TARGETS = 8; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint GetBytesPerPixel(this TextureFormat format) { return format switch @@ -24,9 +26,16 @@ public static class RHIUtility }; } - public static uint GetTotalBytes(this TextureDesc desc) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsDepthStencilFormat(this TextureFormat format) { - return desc.Format.GetBytesPerPixel() * desc.Width * desc.Height * desc.Slice; + return format == TextureFormat.D24_UNorm_S8_UInt || format == TextureFormat.D32_Float; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsStencilFormat(this TextureFormat format) + { + return format == TextureFormat.D24_UNorm_S8_UInt; } public static void GetSurfaceInfo(this TextureFormat format, uint width, uint height, out uint rowPitch, out uint slicePitch, out uint rowCount) @@ -136,12 +145,14 @@ public static class RHIUtility } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Key64 CreateShaderPassKey(string passID) { var passIdSpan = passID.AsSpan(); return new Key64(XxHash3.HashToUInt64(MemoryMarshal.AsBytes(passIdSpan))); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Key64 CreateShaderVariantKey(Key64 passKey, ref readonly LocalKeywordSet keywords) { var passHash = passKey.Value; @@ -176,6 +187,7 @@ public static class RHIUtility return new Key128(new UInt128(lo, hi)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryGetString(this Key128 key, Span destination) { return key.Value.TryFormat(destination, out var _, "X16"); diff --git a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphBuilder.cs b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphBuilder.cs index 2ff75b3..66a0ab2 100644 --- a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphBuilder.cs +++ b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphBuilder.cs @@ -294,7 +294,7 @@ internal class RenderGraphBuilder : IRasterRenderGraphBuilder, IComputeRenderGra } } - public void SetDepthAttachment(Identifier texture, AccessFlags flags = AccessFlags.WriteAll) + public void SetDepthAttachment(Identifier texture, AccessFlags flags = AccessFlags.ReadWrite) { ThrowIfDisposed(); diff --git a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs index 83dc19e..2a1c90c 100644 --- a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs +++ b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphExecutor.cs @@ -139,18 +139,16 @@ internal sealed class RenderGraphExecutor ClearStencil = nativePass.depthAttachment.clearStencil, DepthLoadOp = nativePass.hasDepthAttachment ? nativePass.depthAttachment.loadOp - : AttachmentLoadOp.DontCare, + : AttachmentLoadOp.NoAccess, DepthStoreOp = nativePass.hasDepthAttachment ? nativePass.depthAttachment.storeOp - : AttachmentStoreOp.DontCare, + : AttachmentStoreOp.NoAccess, StencilLoadOp = nativePass.hasDepthAttachment ? nativePass.depthAttachment.stencilLoadOp - : AttachmentLoadOp.DontCare, + : AttachmentLoadOp.NoAccess, StencilStoreOp = nativePass.hasDepthAttachment ? nativePass.depthAttachment.stencilStoreOp - : AttachmentStoreOp.DontCare, - HasStencil = nativePass.hasDepthAttachment && - (_resources.GetResource(nativePass.depthAttachment.texture).rgTextureDesc.format == TextureFormat.D24_UNorm_S8_UInt) + : AttachmentStoreOp.NoAccess, }; commandBuffer.BeginRenderPass(new Span(pPassRTDescs, nativePass.colorAttachmentCount), depthDesc); diff --git a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphNativePassBuilder.cs b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphNativePassBuilder.cs index 0181bc4..0142212 100644 --- a/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphNativePassBuilder.cs +++ b/src/Runtime/Ghost.Graphics/RenderGraphModule/RenderGraphNativePassBuilder.cs @@ -365,18 +365,16 @@ internal sealed class RenderGraphNativePassBuilder attachment.storeOp = AttachmentStoreOp.Store; } - var hasStencil = resource.rgTextureDesc.format == TextureFormat.D24_UNorm_S8_UInt; - if (hasStencil) + if (resource.rgTextureDesc.format.IsStencilFormat()) { attachment.stencilLoadOp = attachment.loadOp; attachment.stencilStoreOp = attachment.storeOp; } else { - attachment.stencilLoadOp = AttachmentLoadOp.DontCare; - attachment.stencilStoreOp = AttachmentStoreOp.DontCare; + attachment.stencilLoadOp = AttachmentLoadOp.NoAccess; + attachment.stencilStoreOp = AttachmentStoreOp.NoAccess; } - } } } diff --git a/src/Runtime/Ghost.Graphics/test.gshdr b/src/Runtime/Ghost.Graphics/test.gshdr index cd293bc..9cf9176 100644 --- a/src/Runtime/Ghost.Graphics/test.gshdr +++ b/src/Runtime/Ghost.Graphics/test.gshdr @@ -112,14 +112,14 @@ shader "MyShader/Standard" // float4 blendedColor = (color1 + color2 + color3 + color4) * 0.25f; // return perMaterialData.color * blendedColor + input.color; - // uint hash = PCGHash(input.meshletID); - // - // float r = float((hash & 0xFF0000u) >> 16) / 255.0; - // float g = float((hash & 0x00FF00u) >> 8) / 255.0; - // float b = float((hash & 0x0000FFu)) / 255.0; - // - // return float4(r, g, b, 1.0); - return float4(input.normal, 1.0); + uint hash = PCGHash(input.meshletID); + + float r = float((hash & 0xFF0000u) >> 16) / 255.0; + float g = float((hash & 0x00FF00u) >> 8) / 255.0; + float b = float((hash & 0x0000FFu)) / 255.0; + + return float4(r, g, b, 1.0); + // return float4(input.normal, 1.0); } } diff --git a/src/Test/Ghost.Graphics.Test/Utilities/MeshUtility.cs b/src/Test/Ghost.Graphics.Test/Utilities/MeshUtility.cs index 334d944..0adb3fd 100644 --- a/src/Test/Ghost.Graphics.Test/Utilities/MeshUtility.cs +++ b/src/Test/Ghost.Graphics.Test/Utilities/MeshUtility.cs @@ -1,6 +1,5 @@ using Ghost.Core; using Ghost.Graphics.RHI; -using Ghost.Graphics.Utilities; using Ghost.MeshOptimizer; using Ghost.Ufbx; using Misaki.HighPerformance.LowLevel; @@ -8,12 +7,14 @@ using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Utilities; using Misaki.HighPerformance.Mathematics; +using System.Runtime.CompilerServices; using System.Text; namespace Ghost.Graphics.Test.Utilities; internal static class MeshUtility { + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float4 ComputeTangent(float3 t, float3 n, float3 b) { var proj = n * math.dot(n, t); @@ -22,6 +23,12 @@ internal static class MeshUtility return new float4(t.xyz, w); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float3 RightHandToLeft(float3 p) + { + return new float3(p.x, p.y, -p.z); + } + public static unsafe Result LoadMesh(string filePath, Allocator allocator, out UnsafeList vertices, out UnsafeList indices) { vertices = default; @@ -38,7 +45,25 @@ internal static class MeshUtility return Result.Failure("Unsupported file format. Only .obj and .fbx are supported."); } - var load_Opts = new ufbx_load_opts(); + var load_Opts = new ufbx_load_opts + { + target_axes = new ufbx_coordinate_axes + { + right = ufbx_coordinate_axis.UFBX_COORDINATE_AXIS_POSITIVE_X, + up = ufbx_coordinate_axis.UFBX_COORDINATE_AXIS_POSITIVE_Y, + front = ufbx_coordinate_axis.UFBX_COORDINATE_AXIS_POSITIVE_Z + }, + obj_axes = new ufbx_coordinate_axes + { + right = ufbx_coordinate_axis.UFBX_COORDINATE_AXIS_POSITIVE_X, + up = ufbx_coordinate_axis.UFBX_COORDINATE_AXIS_POSITIVE_Y, + front = ufbx_coordinate_axis.UFBX_COORDINATE_AXIS_NEGATIVE_Z + }, + // Force X-axis mirroring to correctly convert handedness to Left-Handed, + // while preserving correct left/right orientation when viewed from the front. + handedness_conversion_axis = ufbx_mirror_axis.UFBX_MIRROR_AXIS_X, + space_conversion = ufbx_space_conversion.UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY, + }; var error = new ufbx_error(); using var pool = new MemoryPool(new VirtualStack.CreationOpts @@ -81,7 +106,7 @@ internal static class MeshUtility } var maxScratchIndices = (int)(pMesh->max_face_triangles * 3u); - + using var triIndicesArray = new UnsafeArray(maxScratchIndices, scope1.AllocationHandle); for (var j = 0u; j < pMesh->num_faces; j++) @@ -95,12 +120,9 @@ internal static class MeshUtility { var ufbxTopologyIndex = triIndicesArray[k]; - // TODO: Check if normals/UVs exist before accessing .flatIndices.data - // If it does not exist, we leave uv as (0,0) and compute normals/tangents later - var posIdx = pMesh->vertex_position.indices.data[ufbxTopologyIndex]; var normIdx = pMesh->vertex_normal.exists ? pMesh->vertex_normal.indices.data[ufbxTopologyIndex] : uint.MaxValue; - var tanIdx = pMesh->vertex_tangent.exists ? pMesh->vertex_tangent.indices.data[ufbxTopologyIndex] : uint.MaxValue; + var tanIdx = pMesh->vertex_tangent.exists ? pMesh->vertex_tangent.indices.data[ufbxTopologyIndex] : uint.MaxValue; var uvIdx = pMesh->vertex_uv.exists ? pMesh->vertex_uv.indices.data[ufbxTopologyIndex] : uint.MaxValue; var colIdx = pMesh->vertex_color.exists ? pMesh->vertex_color.indices.data[ufbxTopologyIndex] : uint.MaxValue; var btanIdx = pMesh->vertex_bitangent.exists ? pMesh->vertex_bitangent.indices.data[ufbxTopologyIndex] : uint.MaxValue; @@ -124,7 +146,6 @@ internal static class MeshUtility var newIndex = (uint)flatVertices.Count; flatVertices.Add(vertex); - //flatIndices.Add(newIndex); if (!needComputeNormals) { diff --git a/src/Test/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs b/src/Test/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs index bf2ec43..f73f70a 100644 --- a/src/Test/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs +++ b/src/Test/Ghost.Graphics.Test/Windows/GraphicsTestWindow.xaml.cs @@ -5,12 +5,10 @@ using Ghost.Engine.Utilities; using Ghost.Entities; using Ghost.Graphics.Core; using Ghost.Graphics.RHI; -using Ghost.Graphics.Test.Utilities; using Ghost.Graphics.Utilities; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; -using Misaki.HighPerformance.Jobs; using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.Mathematics; @@ -20,7 +18,7 @@ public sealed partial class GraphicsTestWindow : Window { private RenderSystem? _renderSystem; private ISwapChain? _swapChain; - private JobScheduler _jobScheduler; + //private JobScheduler _jobScheduler; private World? _world; private Handle _meshHandle; @@ -36,7 +34,7 @@ public sealed partial class GraphicsTestWindow : Window Panel.SizeChanged += SwapChainPanel_SizeChanged; Panel.CompositionScaleChanged += SwapChainPanel_CompositionScaleChanged; - + var opts = new AllocationManagerInitOpts { ArenaCapacity = 1024 * 1024 * 1024, // 1GB @@ -46,7 +44,7 @@ public sealed partial class GraphicsTestWindow : Window AllocationManager.Initialize(opts); - _jobScheduler = new JobScheduler(Environment.ProcessorCount - 1); + //_jobScheduler = new JobScheduler(Environment.ProcessorCount - 1); } private void GraphicsTestWindow_Activated(object sender, WindowActivatedEventArgs e) @@ -79,7 +77,7 @@ public sealed partial class GraphicsTestWindow : Window _renderSystem.Start(); // ECS Setup - _world = World.Create(_jobScheduler); + _world = World.Create(); _world.AddService(_renderSystem); // Add Systems @@ -109,12 +107,12 @@ public sealed partial class GraphicsTestWindow : Window _world.EntityManager.SetComponent(cameraEntity, new LocalToWorld { - matrix = float4x4.TRS(new float3(0.0f, 1.0f, -5.0f), quaternion.EulerXYZ(new float3(0, 0, 0)), float3.one) + matrix = float4x4.TRS(new float3(0.0f, 1.0f, 5.0f), quaternion.EulerXYZ(new float3(0, math.radians(180.0f), 0)), float3.one) }); // Create Mesh Entity //MeshBuilder.CreateCube(0.75f, default, Allocator.Persistent, out var vertices, out var indices); - MeshUtility.LoadMesh("F:/c/SimpleRayTracer/native/assets/bunny.obj", Allocator.Persistent, out var vertices, out var indices).ThrowIfFailed(); + Utilities.MeshUtility.LoadMesh("F:/c/SimpleRayTracer/native/assets/bunny.obj", Allocator.Persistent, out var vertices, out var indices).ThrowIfFailed(); // TODO: Put this to the beginning of the frame without createing another command buffer? using var directCmd = _renderSystem.GraphicsEngine.CreateCommandBuffer(CommandBufferType.Graphics); @@ -141,7 +139,7 @@ public sealed partial class GraphicsTestWindow : Window _world.EntityManager.SetComponent(meshEntity, new LocalToWorld { - matrix = float4x4.identity + matrix = float4x4.TRS(float3.zero, quaternion.EulerXYZ(new float3(0, 0, 0)), float3.one) }); CompositionTarget.Rendering += OnRendering; @@ -162,7 +160,7 @@ public sealed partial class GraphicsTestWindow : Window _renderSystem?.ResourceManager.ReleaseMesh(_meshHandle); _swapChain?.Dispose(); - _jobScheduler.Dispose(); + //_jobScheduler.Dispose(); _renderSystem?.Dispose(); AllocationManager.Dispose();