Render graph integration and resource management refactor

Introduces a full-featured render graph system with pass culling, resource aliasing, and automatic barrier generation. Refactors resource and barrier APIs, improves error handling, and unifies result types. Renderer and render passes now use the new graph-based workflow. Updates shader includes, adds a blit shader, and improves HLSL parsing. Removes dynamic descriptor heaps in favor of persistent ones. Project file now includes the render graph module. Lays the foundation for advanced rendering features and improved memory efficiency.
This commit is contained in:
2026-01-21 18:32:03 +09:00
parent 1c155f962c
commit 92b966fe0d
62 changed files with 4843 additions and 621 deletions

View File

@@ -3,16 +3,32 @@ using Ghost.Core.Graphics;
using Ghost.DSL.ShaderCompiler;
using Ghost.Graphics.Contracts;
using Ghost.Graphics.Core;
using Ghost.Graphics.RenderGraphModule;
using Ghost.Graphics.RHI;
using Ghost.Graphics.Utilities;
using Misaki.HighPerformance.Image;
using Misaki.HighPerformance.Mathematics;
using Misaki.HighPerformance.Utilities;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Ghost.Graphics.RenderPasses;
internal class MeshRenderPassData
{
public Handle<Mesh> mesh;
public Handle<Material> material;
public Identifier<RGTexture> renderTarget;
}
internal class BlitPassData
{
public Identifier<RGTexture> source;
public Identifier<RGTexture> destination;
public Handle<Material> blitMaterial;
public Identifier<Sampler> sampler;
}
/// <summary>
/// Simplified bindless mesh render pass using high-level bindless APIs with fully bindless vertex/index buffer access
/// </summary>
@@ -33,12 +49,23 @@ internal class MeshRenderPass : IRenderPass
private readonly uint _padding3;
}
[StructLayout(LayoutKind.Sequential)]
private struct ShaderProperties_Hidden_Blit
{
public uint mainTex;
public uint sampler_mainTex;
private readonly uint _padding1;
private readonly uint _padding2;
}
private Handle<Mesh> _mesh;
private Identifier<Shader> _shader;
private Handle<Material> _material;
private Handle<Texture>[]? _textures;
private Identifier<Sampler> _sampler;
private Identifier<ShaderPass> _forwardPassID;
private Identifier<Shader> _blitShader;
private Handle<Material> _blitMaterial;
// Texture file paths for this demo
private readonly string[] _textureFiles = [
@@ -77,8 +104,32 @@ internal class MeshRenderPass : IRenderPass
}
}
private void CompileBlitShader(ref readonly RenderingContext ctx)
{
var shaderDescriptor = DSLShaderCompiler.CompileShader("F:/csharp/GhostEngine/Ghost.Graphics/Shaders/Blit.gsdef", "C:/Users/Misaki/Downloads/Archive").GetValueOrThrow();
_blitShader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor);
_blitMaterial = ctx.ResourceAllocator.CreateMaterial(_blitShader);
var config = new ShaderCompilationConfig
{
optimizeLevel = CompilerOptimizeLevel.O3,
options = CompilerOption.KeepReflections,
tier = CompilerTier.Tier2
};
var pass = shaderDescriptor.passes[0];
var emptyKeywords = new LocalKeywordSet();
var variantKey = RHIUtility.CreateShaderVariantKey(
RHIUtility.CreateShaderPassKey(pass.identifier),
in emptyKeywords);
ctx.ShaderCompiler.CompilePass(in pass, in config, variantKey).GetValueOrThrow();
}
public void Initialize(ref readonly RenderingContext ctx)
{
CompileBlitShader(in ctx);
var shaderDescriptor = DSLShaderCompiler.CompileShader("F:/csharp/GhostEngine/Ghost.Graphics/test.gsdef", "C:/Users/Misaki/Downloads/Archive").GetValueOrThrow();
_shader = ctx.ResourceAllocator.CreateGraphicsShader(shaderDescriptor);
@@ -108,8 +159,13 @@ internal class MeshRenderPass : IRenderPass
}
else
{
ref var shaderRef = ref ctx.ResourceDatabase.GetShaderReference(_shader);
var shaderResult = ctx.ResourceDatabase.GetShaderReference(_shader);
if (shaderResult.IsFailure)
{
throw new InvalidOperationException("Failed to get shader reference.");
}
ref readonly var shaderRef = ref shaderResult.Value;
foreach (var keyGroup in GetAllVariantCombination(pass.keywords))
{
config.defines = keyGroup.Span;
@@ -157,7 +213,7 @@ internal class MeshRenderPass : IRenderPass
Usage = TextureUsage.ShaderResource,
};
_textures[i] = ctx.CreateTexture(in desc, imageData.AsSpan(), $"Texture_{i}");
_textures[i] = ctx.CreateTexture<byte>(in desc, imageData.AsSpan(), $"Texture_{i}");
}
var samplerDesc = new SamplerDesc
@@ -169,9 +225,15 @@ internal class MeshRenderPass : IRenderPass
MaxAnisotropy = 16,
};
var sampler = ctx.ResourceAllocator.CreateSampler(in samplerDesc);
_sampler = ctx.ResourceAllocator.CreateSampler(in samplerDesc);
ref var matRef = ref ctx.ResourceDatabase.GetMaterialReference(_material);
var meshResult = ctx.ResourceDatabase.GetMaterialReference(_material);
if (meshResult.IsFailure)
{
throw new InvalidOperationException("Failed to get material reference.");
}
ref readonly var matRef = ref meshResult.Value;
var matProps = new ShaderProperties_MyShader_Standard
{
color = new float4(1.0f, 1.0f, 1.0f, 1.0f),
@@ -179,18 +241,72 @@ internal class MeshRenderPass : IRenderPass
texture2 = ctx.ResourceDatabase.GetBindlessIndex(_textures[1].AsResource()),
texture3 = ctx.ResourceDatabase.GetBindlessIndex(_textures[2].AsResource()),
texture4 = ctx.ResourceDatabase.GetBindlessIndex(_textures[3].AsResource()),
tex_sampler = (uint)sampler.Value,
tex_sampler = (uint)_sampler.Value,
};
matRef.SetPropertyCache(in matProps).ThrowIfFailed();
matRef.UploadData(ctx.DirectCommandBuffer);
_forwardPassID = Shader.GetPassID("Forward");
}
public void Execute(ref readonly RenderingContext ctx)
public void Build(RenderGraph graph, Identifier<RGTexture> backbuffer)
{
ctx.DispatchMesh(_mesh, _material, _forwardPassID, 3);
Identifier<RGTexture> renderTarget;
using (var builder = graph.AddRasterRenderPass<MeshRenderPassData>("Mesh Render Pass", out var passData))
{
passData.mesh = _mesh;
passData.material = _material;
passData.renderTarget = builder.CreateTexture(RGTextureDesc.Relative(1.0f, TextureFormat.R8G8B8A8_UNorm), "Render Target");
builder.SetColorAttachment(passData.renderTarget, 0);
renderTarget = passData.renderTarget;
builder.SetRenderFunc<MeshRenderPassData>(static (data, ctx) =>
{
ctx.SetActiveMaterial(data.material);
ctx.SetActiveMesh(data.mesh);
var threadGroupCountX = ((uint)ctx.ActiveMeshIndexCount + 2u) / 3u;
ctx.DispatchMesh(new uint3(threadGroupCountX, 1u, 1u));
});
}
// FIX: We can not upload the blit material properties during a native render pass.
using (var builder = graph.AddUnsafeRenderPass<BlitPassData>("Blit Pass", out var passData))
{
passData.source = renderTarget;
passData.destination = backbuffer;
passData.blitMaterial = _blitMaterial;
passData.sampler = _sampler;
builder.UseTexture(passData.source, AccessFlags.Read);
builder.UseTexture(passData.destination, AccessFlags.WriteAll);
builder.SetRenderFunc<BlitPassData>(static (data, ctx) =>
{
var r = ctx.ResourceDatabase.GetMaterialReference(data.blitMaterial);
if (r.IsFailure)
{
return;
}
ref readonly var matRef = ref r.Value;
var blitProps = new ShaderProperties_Hidden_Blit
{
mainTex = ctx.ResourceDatabase.GetBindlessIndex(ctx.GetActualResource(data.source.AsResource())),
sampler_mainTex = (uint)data.sampler.Value,
};
matRef.SetPropertyCache(in blitProps).ThrowIfFailed();
matRef.UploadData(ctx.CommandBuffer);
ctx.CommandBuffer.SetRenderTargets([ctx.GetActualTexture(data.destination)], Handle<Texture>.Invalid);
ctx.SetActiveMaterial(data.blitMaterial);
ctx.SetActiveMesh(Handle<Mesh>.Invalid);
ctx.DispatchMesh(new uint3(1, 1, 1));
});
}
}
public void Cleanup(IResourceDatabase resourceDatabase)