Update RenderingContext and D3D12Renderer to use new API.

This commit is contained in:
2025-11-06 04:13:20 +00:00
parent b3eeb8d366
commit 15aca9aefb
17 changed files with 184 additions and 195 deletions

View File

@@ -13,8 +13,8 @@ public enum ShaderPropertyType
Int, Int2, Int3, Int4, Int, Int2, Int3, Int4,
UInt, UInt2, UInt3, UInt4, UInt, UInt2, UInt3, UInt4,
Bool, Bool2, Bool3, Bool4, Bool, Bool2, Bool3, Bool4,
Texture2D, Texture3D, TextureCube, Texture2DBindless, Texture3DBindless, TextureCubeBindless,
Texture2DArray, TextureCubeArray, Texture2DArrayBindless, TextureCubeArrayBindless,
} }
public struct ShaderEntryPoint public struct ShaderEntryPoint

View File

@@ -1,10 +1,11 @@
using Ghost.Graphics.Core;
using Ghost.Graphics.RHI; using Ghost.Graphics.RHI;
namespace Ghost.Graphics.Contracts; namespace Ghost.Graphics.Contracts;
public interface IRenderPass public interface IRenderPass
{ {
public void Initialize(ICommandBuffer cmd); public void Initialize(ref readonly RenderingContext ctx);
public void Execute(ICommandBuffer cmd); public void Execute(ref readonly RenderingContext ctx);
public void Cleanup(IResourceDatabase resourceDatabase); public void Cleanup(IResourceDatabase resourceDatabase);
} }

View File

@@ -211,7 +211,7 @@ public ref struct MaterialAccessor
for (var i = 0; i < _shader.PassCount; i++) for (var i = 0; i < _shader.PassCount; i++)
{ {
ref var cache = ref _materialData.GetPassCache(i); ref var cache = ref _materialData.GetPassCache(i);
cmb.Upload(cache.GpuResource, cache.CpuData.AsSpan()); cmb.UploadBuffer<byte>(cache.GpuResource, cache.CpuData.AsSpan());
} }
} }
} }

View File

@@ -9,35 +9,54 @@ namespace Ghost.Graphics.Core;
public unsafe readonly ref struct RenderingContext public unsafe readonly ref struct RenderingContext
{ {
private readonly IRenderDevice _device; private readonly IGraphicsEngine _engine;
private readonly ICommandBuffer _directCmb; private readonly ICommandBuffer _directCmb;
private readonly ICommandBuffer _copyCmb; private readonly ICommandBuffer _copyCmb;
private readonly ICommandBuffer _computeCmb; private readonly ICommandBuffer _computeCmb;
private readonly IResourceAllocator _resourceAllocator;
private readonly IResourceDatabase _resourceDatabase; public ICommandBuffer DirectCommandBuffer => _directCmb;
private readonly IPipelineLibrary _stateController; public ICommandBuffer CopyCommandBuffer => _copyCmb;
public ICommandBuffer ComputeCommandBuffer => _computeCmb;
public IResourceAllocator ResourceAllocator => _engine.ResourceAllocator;
public IResourceDatabase ResourceDatabase => _engine.ResourceDatabase;
public IPipelineLibrary PipelineLibrary => _engine.PipelineLibrary;
internal RenderingContext( internal RenderingContext(
IRenderDevice device, IGraphicsEngine engine,
ICommandBuffer directCmd, ICommandBuffer directCmd,
ICommandBuffer copyCmd, ICommandBuffer copyCmd,
ICommandBuffer computeCmd, ICommandBuffer computeCmd)
IResourceAllocator resourceAllocator,
IResourceDatabase resourceDatabase,
IPipelineLibrary stateController)
{ {
_device = device; _engine = engine;
_directCmb = directCmd; _directCmb = directCmd;
_copyCmb = copyCmd; _copyCmb = copyCmd;
_computeCmb = computeCmd; _computeCmb = computeCmd;
_resourceAllocator = resourceAllocator; }
_resourceDatabase = resourceDatabase;
_stateController = stateController; public ICommandBuffer CrearteCommandBuffer(CommandBufferType type)
{
return _engine.CreateCommandBuffer(type);
}
// TODO: ExecuteCommandBufferAsync with fencene.Device.GraphicsQueue.Submit(commandBuffer);
public void ExecuteCommandBuffer(ICommandBuffer commandBuffer)
{
var queue = commandBuffer.Type switch
{
CommandBufferType.Graphics => _engine.Device.GraphicsQueue,
CommandBufferType.Compute => _engine.Device.ComputeQueue,
CommandBufferType.Copy => _engine.Device.CopyQueue,
_ => throw new ArgumentOutOfRangeException(),
};
queue.Submit(commandBuffer);
queue.WaitIdle();
} }
public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices) public Handle<Mesh> CreateMesh(UnsafeList<Vertex> vertices, UnsafeList<uint> indices)
{ {
var mesh = _resourceAllocator.CreateMesh(vertices, indices); var mesh = ResourceAllocator.CreateMesh(vertices, indices);
return mesh; return mesh;
} }
@@ -61,36 +80,36 @@ public unsafe readonly ref struct RenderingContext
/// <param name="markMeshStatic">Whether to mark the mesh as static. If it's true, the cpu buffer of the mesh will not be avaliable any more</param> /// <param name="markMeshStatic">Whether to mark the mesh as static. If it's true, the cpu buffer of the mesh will not be avaliable any more</param>
public void UploadMesh(Handle<Mesh> mesh, bool markMeshStatic) public void UploadMesh(Handle<Mesh> mesh, bool markMeshStatic)
{ {
ref var meshData = ref _resourceDatabase.GetMeshReference(mesh); ref var meshData = ref ResourceDatabase.GetMeshReference(mesh);
var vertexState = _resourceDatabase.GetResourceState(meshData.vertexBuffer.AsResource()); var vertexState = ResourceDatabase.GetResourceState(meshData.vertexBuffer.AsResource());
var indexState = _resourceDatabase.GetResourceState(meshData.indexBuffer.AsResource()); var indexState = ResourceDatabase.GetResourceState(meshData.indexBuffer.AsResource());
var needVertexTransition = vertexState != ResourceState.CopyDest; var needVertexTransition = vertexState != ResourceState.CopyDest;
var needIndexTransition = indexState != ResourceState.CopyDest; var needIndexTransition = indexState != ResourceState.CopyDest;
if (needVertexTransition) if (needVertexTransition)
{ {
_copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest); _copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
_resourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest); ResourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest);
} }
if (needIndexTransition) if (needIndexTransition)
{ {
_copyCmb.ResourceBarrier(meshData.indexBuffer.AsResource(), indexState, ResourceState.CopyDest); _copyCmb.ResourceBarrier(meshData.indexBuffer.AsResource(), indexState, ResourceState.CopyDest);
_resourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), ResourceState.CopyDest); ResourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), ResourceState.CopyDest);
} }
_copyCmb.Upload(meshData.vertexBuffer, meshData.vertices.AsSpan()); _copyCmb.UploadBuffer<Vertex>(meshData.vertexBuffer, meshData.vertices.AsSpan());
_copyCmb.Upload(meshData.indexBuffer, meshData.indices.AsSpan()); _copyCmb.UploadBuffer<uint>(meshData.indexBuffer, meshData.indices.AsSpan());
if (needVertexTransition) if (needVertexTransition)
{ {
_copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState); _copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
_resourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), vertexState); ResourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), vertexState);
} }
if (needIndexTransition) if (needIndexTransition)
{ {
_resourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), indexState); ResourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), indexState);
_copyCmb.ResourceBarrier(meshData.indexBuffer.AsResource(), ResourceState.CopyDest, indexState); _copyCmb.ResourceBarrier(meshData.indexBuffer.AsResource(), ResourceState.CopyDest, indexState);
} }
@@ -102,12 +121,12 @@ public unsafe readonly ref struct RenderingContext
public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool tempResource = false) public Handle<Texture> CreateTexture(ref readonly TextureDesc desc, bool tempResource = false)
{ {
return _resourceAllocator.CreateTexture(in desc, tempResource); return ResourceAllocator.CreateTexture(in desc, tempResource);
} }
public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<byte> data) public void UploadTexture(Handle<Texture> texture, ReadOnlySpan<byte> data)
{ {
var desc = _resourceDatabase.GetResourceDescription(texture.AsResource()); var desc = ResourceDatabase.GetResourceDescription(texture.AsResource());
desc.textureDescription.Format.GetSurfaceInfo((int)desc.textureDescription.Width, (int)desc.textureDescription.Height, out var rowPitch, out var slicePitch, out _); desc.textureDescription.Format.GetSurfaceInfo((int)desc.textureDescription.Width, (int)desc.textureDescription.Height, out var rowPitch, out var slicePitch, out _);
var subresourceData = new SubResourceData var subresourceData = new SubResourceData
@@ -117,78 +136,31 @@ public unsafe readonly ref struct RenderingContext
slicePitch = slicePitch slicePitch = slicePitch
}; };
var sateBefore = _resourceDatabase.GetResourceState(texture.AsResource()); var sateBefore = ResourceDatabase.GetResourceState(texture.AsResource());
var needTransition = sateBefore != ResourceState.CopyDest; var needTransition = sateBefore != ResourceState.CopyDest;
if (needTransition) if (needTransition)
{ {
_copyCmb.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest); _copyCmb.ResourceBarrier(texture.AsResource(), sateBefore, ResourceState.CopyDest);
_resourceDatabase.SetResourceState(texture.AsResource(), ResourceState.CopyDest); ResourceDatabase.SetResourceState(texture.AsResource(), ResourceState.CopyDest);
} }
_copyCmb.Upload(texture, subresourceData); _copyCmb.UploadTexture(texture, subresourceData);
if (needTransition) if (needTransition)
{ {
_copyCmb.ResourceBarrier(texture.AsResource(), ResourceState.CopyDest, sateBefore); _copyCmb.ResourceBarrier(texture.AsResource(), ResourceState.CopyDest, sateBefore);
_resourceDatabase.SetResourceState(texture.AsResource(), sateBefore); ResourceDatabase.SetResourceState(texture.AsResource(), sateBefore);
} }
} }
#if false
// TODO: Ideally we should queue the draw call to our rendering system, and render it in the full rendering pipeline.
// This is just a place holder for now for testing purpose.
// TODO: Since we are using mesh shader, we should use dispatch mesh instead of draw calls.
public void RenderMesh(Handle<Mesh> mesh, Handle<Material> material, string passName)
{
ref var meshRef = ref _resourceDatabase.GetMeshReference(mesh);
ref var materialRef = ref _resourceDatabase.GetMaterialReference(material);
var shader = _resourceDatabase.GetShaderReference(materialRef.Shader);
shader.TryGetPassKey(passName, out var passIndex, out var passKey);
var hash = new GraphicsPipelineHash
{
id = passKey,
rtvCount = 1,
dsvFormat = TextureFormat.Unknown,
};
hash.rtvFormats[0] = TextureFormat.B8G8R8A8_UNorm;
var pipelineKey = hash.GetKey();
_directCmb.SetPipelineState(pipelineKey);
// FIX: Get valid root signature. In D3D12, we use fixed root signature layout for bindless rendering.
// However, our code should not assume that blindly. Each pipeline should have contained root signature info even if there are fixed.
// This ensures that future changes to root signature layout can be accommodated.
// for (int i = 0; i < 4; i++)
{
ref var cache = ref materialRef.GetPassCache(passIndex);
_directCmb.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource);
}
// NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables.
// TODO: Matbe handle the transitional bindless model?
#if false
var samplerGpuHandle = _descriptorAllocator.GetSamplerHeap()->GetGPUDescriptorHandleForHeapStart();
_commandList.Get()->SetGraphicsRootDescriptorTable(rootParamIndex, samplerGpuHandle);
#endif
_directCmb.SetPrimitiveTopology(PrimitiveTopology.Triangle);
// Draw without vertex/index buffers - use instanced drawing
// Each instance represents a triangle (3 vertices)
var triangleCount = (uint)meshRef.indices.Count / 3;
_directCmb.Draw(3, triangleCount, 0, 0);
}
#endif
// TODO: Ideally we should queue the draw call to our rendering system, and render it in the full rendering pipeline. // TODO: Ideally we should queue the draw call to our rendering system, and render it in the full rendering pipeline.
// This is just a place holder for now for testing purpose. // This is just a place holder for now for testing purpose.
// TODO: Since we are using mesh shader, we should use dispatch mesh instead of draw calls.
public void DispatchMesh(Handle<Mesh> mesh, Handle<Material> material, string passName, uint numThreadsX) public void DispatchMesh(Handle<Mesh> mesh, Handle<Material> material, string passName, uint numThreadsX)
{ {
ref var meshRef = ref _resourceDatabase.GetMeshReference(mesh); ref var meshRef = ref ResourceDatabase.GetMeshReference(mesh);
ref var materialRef = ref _resourceDatabase.GetMaterialReference(material); ref var materialRef = ref ResourceDatabase.GetMaterialReference(material);
var shader = _resourceDatabase.GetShaderReference(materialRef.Shader); var shader = ResourceDatabase.GetShaderReference(materialRef.Shader);
shader.TryGetPassKey(passName, out var passIndex, out var passKey); shader.TryGetPassKey(passName, out var passIndex, out var passKey);
var hash = new GraphicsPipelineHash var hash = new GraphicsPipelineHash
@@ -202,15 +174,9 @@ public unsafe readonly ref struct RenderingContext
var pipelineKey = hash.GetKey(); var pipelineKey = hash.GetKey();
_directCmb.SetPipelineState(pipelineKey); _directCmb.SetPipelineState(pipelineKey);
// FIX: Get valid root signature. In D3D12, we use fixed root signature layout for bindless rendering. // NOTE: We use fixed root signature layout for bindless rendering.
// However, our code should not assume that blindly. Each pipeline should have contained root signature info even if there are fixed.
// This ensures that future changes to root signature layout can be accommodated.
// for (int i = 0; i < 4; i++)
{
ref var cache = ref materialRef.GetPassCache(passIndex); ref var cache = ref materialRef.GetPassCache(passIndex);
_directCmb.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource); _directCmb.SetConstantBufferView(RootSignatureLayout.PER_MATERIAL_BUFFER_SLOT, cache.GpuResource);
}
// NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables. // NOTE: Since we are using true bindless resources, we only need to set the descriptor heaps, not individual tables.
// TODO: Matbe handle the transitional bindless model? // TODO: Matbe handle the transitional bindless model?
@@ -222,10 +188,4 @@ public unsafe readonly ref struct RenderingContext
var threadGroupCountX = ((uint)meshRef.indices.Count + numThreadsX - 1) / numThreadsX; var threadGroupCountX = ((uint)meshRef.indices.Count + numThreadsX - 1) / numThreadsX;
_directCmb.DispatchMesh(threadGroupCountX, 1, 1); _directCmb.DispatchMesh(threadGroupCountX, 1, 1);
} }
public void ExecuteCopyCommands()
{
_device.CopyQueue.Submit(_copyCmb);
_device.CopyQueue.WaitIdle();
}
} }

View File

@@ -397,7 +397,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
// _commandList.Get()->DispatchRays(); // _commandList.Get()->DispatchRays();
} }
public void Upload<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data) public void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
where T : unmanaged where T : unmanaged
{ {
ThrowIfDisposed(); ThrowIfDisposed();
@@ -422,7 +422,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
_commandList.Get()->CopyBufferRegion(pResource, 0, pUploadResource, 0, sizeInBytes); _commandList.Get()->CopyBufferRegion(pResource, 0, pUploadResource, 0, sizeInBytes);
} }
public void Upload(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources) public void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources)
{ {
ThrowIfDisposed(); ThrowIfDisposed();
ThrowIfNotRecording(); ThrowIfNotRecording();

View File

@@ -9,7 +9,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
#endif #endif
private readonly D3D12RenderDevice _device; private readonly D3D12RenderDevice _device;
private readonly D3D12PipelineLibrary _stateController; private readonly D3D12PipelineLibrary _pipelineLibrary;
private readonly D3D12DescriptorAllocator _descriptorAllocator; private readonly D3D12DescriptorAllocator _descriptorAllocator;
private readonly D3D12ResourceDatabase _resourceDatabase; private readonly D3D12ResourceDatabase _resourceDatabase;
@@ -17,13 +17,11 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
private readonly D3D12CommandBuffer _copyCommandBuffer; private readonly D3D12CommandBuffer _copyCommandBuffer;
public IRenderDevice Device => _device; public IRenderDevice Device => _device;
public IPipelineLibrary PipelineLibrary => _pipelineLibrary;
public IResourceDatabase ResourceDatabase => _resourceDatabase; public IResourceDatabase ResourceDatabase => _resourceDatabase;
public IResourceAllocator ResourceAllocator => _resourceAllocator; public IResourceAllocator ResourceAllocator => _resourceAllocator;
public IPipelineLibrary PipelineStateController => _stateController;
public D3D12GraphicsEngine(RenderSystem renderSystem) public D3D12GraphicsEngine(RenderSystem renderSystem)
{ {
#if DEBUG #if DEBUG
@@ -35,10 +33,10 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
_resourceDatabase = new(_descriptorAllocator); _resourceDatabase = new(_descriptorAllocator);
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase); _resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase);
_stateController = new(_device, _resourceDatabase, null); _pipelineLibrary = new(_device, _resourceDatabase);
_copyCommandBuffer = new( _copyCommandBuffer = new(
_device, _device,
_stateController, _pipelineLibrary,
_resourceDatabase, _resourceDatabase,
_resourceAllocator, _resourceAllocator,
_descriptorAllocator, _descriptorAllocator,
@@ -59,7 +57,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
{ {
return new D3D12CommandBuffer( return new D3D12CommandBuffer(
_device, _device,
_stateController, _pipelineLibrary,
_resourceDatabase, _resourceDatabase,
_resourceAllocator, _resourceAllocator,
_descriptorAllocator, _descriptorAllocator,
@@ -84,7 +82,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
public void Dispose() public void Dispose()
{ {
_copyCommandBuffer.Dispose(); _copyCommandBuffer.Dispose();
_stateController.Dispose(); _pipelineLibrary.Dispose();
_resourceAllocator.Dispose(); _resourceAllocator.Dispose();
_resourceDatabase.Dispose(); _resourceDatabase.Dispose();

View File

@@ -184,7 +184,21 @@ internal unsafe class D3D12Renderer : IRenderer
{ {
var clearColor = new Color128 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f }; var clearColor = new Color128 { r = 1.0f, g = 0.0f, b = 1.0f, a = 1.0f };
cmd.BeginRenderPass(target, Handle<Texture>.Invalid, clearColor); Span<PassRenderTargetDesc> rtDesc = stackalloc PassRenderTargetDesc[1];
rtDesc[0] = new PassRenderTargetDesc
{
texture = target,
clearColor = clearColor,
};
var depthDesc = new PassDepthStencilDesc
{
texture = Handle<Texture>.Invalid,
clearDepth = 1.0f,
clearStencil = 0,
};
cmd.BeginRenderPass(rtDesc, depthDesc, false);
var viewport = new ViewportDesc { width = _currentSize.x, height = _currentSize.y, minDepth = 0, maxDepth = 1 }; var viewport = new ViewportDesc { width = _currentSize.x, height = _currentSize.y, minDepth = 0, maxDepth = 1 };
var scissor = new RectDesc { right = _currentSize.x, bottom = _currentSize.y }; var scissor = new RectDesc { right = _currentSize.x, bottom = _currentSize.y };
@@ -213,17 +227,12 @@ internal unsafe class D3D12Renderer : IRenderer
// For now, we'll do a simple copy operation // For now, we'll do a simple copy operation
// In a real implementation, you would use a blit shader for post-processing // In a real implementation, you would use a blit shader for post-processing
// TODO: Implement proper blit operation with shader // FIX: Implement proper blit operation with shader
// This is a placeholder - in D3D12, you would typically: // 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 // 2. Use a full-screen quad/triangle with a shader that samples from the source
// 3. Apply post-processing effects (tone mapping, gamma correction, etc.) // 3. Apply post-processing effects (tone mapping, gamma correction, etc.)
// For now, just clear the destination (this should be replaced with actual blit)
var clearColor = new Color128 { r = 0.0f, g = 0.0f, b = 0.0f, a = 1.0f };
cmd.BeginRenderPass(destination, Handle<Texture>.Invalid, clearColor);
cmd.EndRenderPass();
// Handle swap chain back buffer transitions if needed // Handle swap chain back buffer transitions if needed
if (_swapChain != null) if (_swapChain != null)
{ {

View File

@@ -90,12 +90,6 @@ internal class D3D12ResourceDatabase : IResourceDatabase, IDisposable
} }
} }
private struct Slot<T>
{
public T value;
public bool occupied;
}
private readonly D3D12DescriptorAllocator _descriptorAllocator; private readonly D3D12DescriptorAllocator _descriptorAllocator;
private UnsafeSlotMap<ResourceRecord> _resources; private UnsafeSlotMap<ResourceRecord> _resources;

View File

@@ -1,11 +1,9 @@
using Ghost.Core; using Ghost.Core;
using Ghost.Core.Utilities; using Ghost.Core.Utilities;
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI; using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Collections;
using Misaki.HighPerformance.LowLevel.Utilities; using Misaki.HighPerformance.LowLevel.Utilities;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using TerraFX.Interop.DirectX; using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows; using TerraFX.Interop.Windows;
@@ -204,11 +202,11 @@ internal static unsafe class D3D12ShaderCompiler
using ComPtr<IDxcIncludeHandler> includeHandler = default; using ComPtr<IDxcIncludeHandler> includeHandler = default;
// Create DXC compiler and utils // Create DXC compiler and utils
var pDxcCompiler = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcCompiler); var dxccID = CLSID.CLSID_DxcCompiler;
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils); var dxcuID = CLSID.CLSID_DxcUtils;
ThrowIfFailed(DxcCreateInstance(pDxcCompiler, compiler.IID(), compiler.PPV())); ThrowIfFailed(DxcCreateInstance(&dxccID, compiler.IID(), compiler.PPV()));
ThrowIfFailed(DxcCreateInstance(pDxcUtils, utils.IID(), utils.PPV())); ThrowIfFailed(DxcCreateInstance(&dxcuID, utils.IID(), utils.PPV()));
//includeHandler.Get()->LoadSource(); //includeHandler.Get()->LoadSource();
utils.Get()->CreateDefaultIncludeHandler(includeHandler.GetAddressOf()); utils.Get()->CreateDefaultIncludeHandler(includeHandler.GetAddressOf());
@@ -299,9 +297,9 @@ internal static unsafe class D3D12ShaderCompiler
} }
// Create DXC utils to parse reflection data // Create DXC utils to parse reflection data
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils); var dxcuID = CLSID.CLSID_DxcUtils;
using ComPtr<IDxcUtils> utils = default; using ComPtr<IDxcUtils> utils = default;
ThrowIfFailed(DxcCreateInstance(pDxcUtils, utils.IID(), utils.PPV())); ThrowIfFailed(DxcCreateInstance(&dxcuID, utils.IID(), utils.PPV()));
// Create reflection interface from blob // Create reflection interface from blob
var reflectionBuffer = new DxcBuffer var reflectionBuffer = new DxcBuffer

View File

@@ -171,7 +171,7 @@ public interface ICommandBuffer : IDisposable
/// <param name="buffer">A handle to the buffer that will receive the uploaded data.</param> /// <param name="buffer">A handle to the buffer that will receive the uploaded data.</param>
/// <param name="data">A read-only span containing the data to upload to the buffer. The span must contain elements of type /// <param name="data">A read-only span containing the data to upload to the buffer. The span must contain elements of type
/// <typeparamref name="T"/>.</param> /// <typeparamref name="T"/>.</param>
void Upload<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data) void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
where T : unmanaged; where T : unmanaged;
/// <summary> /// <summary>
@@ -182,7 +182,7 @@ public interface ICommandBuffer : IDisposable
/// <param name="subresources">A reference to the structure containing the subresource data to upload. The data must match the format and layout expected by the texture.</param> /// <param name="subresources">A reference to the structure containing the subresource data to upload. The data must match the format and layout expected by the texture.</param>
/// <param name="numSubresources">The number of subresources to upload, starting from <paramref name="firstSubresource"/>. /// <param name="numSubresources">The number of subresources to upload, starting from <paramref name="firstSubresource"/>.
/// Must be greater than zero and not exceed the remaining subresources in the texture.</param> /// Must be greater than zero and not exceed the remaining subresources in the texture.</param>
void Upload(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources); void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources);
/// <summary> /// <summary>
/// Copies a specified number of bytes from the source graphics buffer to the destination graphics buffer. /// Copies a specified number of bytes from the source graphics buffer to the destination graphics buffer.

View File

@@ -2,44 +2,49 @@ namespace Ghost.Graphics.RHI;
public interface IGraphicsEngine : IDisposable public interface IGraphicsEngine : IDisposable
{ {
public IRenderDevice Device IRenderDevice Device
{ {
get; get;
} }
public IResourceDatabase ResourceDatabase IPipelineLibrary PipelineLibrary
{ {
get; get;
} }
public IResourceAllocator ResourceAllocator IResourceDatabase ResourceDatabase
{ {
get; get;
} }
public IRenderer CreateRenderer(); IResourceAllocator ResourceAllocator
{
get;
}
IRenderer CreateRenderer();
/// <summary> /// <summary>
/// Creates a command buffer for recording rendering commands /// Creates a command buffer for recording rendering commands
/// </summary> /// </summary>
/// <param name="type">Type of command buffer to create</param> /// <param name="type">Type of command buffer to create</param>
/// <returns>A new command buffer instance</returns> /// <returns>A new command buffer instance</returns>
public ICommandBuffer CreateCommandBuffer(CommandBufferType type = CommandBufferType.Graphics); ICommandBuffer CreateCommandBuffer(CommandBufferType type = CommandBufferType.Graphics);
/// <summary> /// <summary>
/// Creates a swap chain for presentation /// Creates a swap chain for presentation
/// </summary> /// </summary>
/// <param name="desc">Swap chain description</param> /// <param name="desc">Swap chain description</param>
/// <returns>A new swap chain instance</returns> /// <returns>A new swap chain instance</returns>
public ISwapChain CreateSwapChain(SwapChainDesc desc); ISwapChain CreateSwapChain(SwapChainDesc desc);
/// <summary> /// <summary>
/// Begins a new rendering frame, preparing the graphics context for drawing operations. /// Begins a new rendering frame, preparing the graphics context for drawing operations.
/// </summary> /// </summary>
public void BeginFrame(); void BeginFrame();
/// <summary> /// <summary>
/// Completes the current rendering frame and performs any necessary finalization steps. /// Completes the current rendering frame and performs any necessary finalization steps.
/// </summary> /// </summary>
public void EndFrame(); void EndFrame();
} }

View File

@@ -26,19 +26,19 @@ internal unsafe class MeshRenderPass : IRenderPass
"C:/Users/Misaki/Downloads/Im/yande.re 1134666 blue_archive nakamasa_ichika sugarhigh.jpg" "C:/Users/Misaki/Downloads/Im/yande.re 1134666 blue_archive nakamasa_ichika sugarhigh.jpg"
]; ];
public void Initialize(ref readonly RenderingContext ctx, IResourceAllocator resourceAllocator, IPipelineLibrary pipelineLibrary) public void Initialize(ref readonly RenderingContext ctx)
{ {
var shaderDescriptor = SDLCompiler.CompileShader("F:\\csharp\\GhostEngine\\Ghost.Graphics\\RenderPasses\\ShaderCode.hlsl").GetValueOrThrow(); var shaderDescriptor = SDLCompiler.CompileShader("F:\\csharp\\GhostEngine\\Ghost.Graphics\\RenderPasses\\ShaderCode.hlsl").GetValueOrThrow();
var key = pipelineLibrary.CompilePassPSO(shaderDescriptor.passes[0], [TextureFormat.B8G8R8A8_UNorm], TextureFormat.Unknown); var key = ctx.PipelineLibrary.CompilePassPSO(shaderDescriptor.passes[0], [TextureFormat.B8G8R8A8_UNorm], TextureFormat.Unknown);
MeshBuilder.CreateCube(0.75f, default, out var vertices, out var indices); MeshBuilder.CreateCube(0.75f, default, out var vertices, out var indices);
_mesh = ctx.CreateMesh(vertices, indices); _mesh = ctx.CreateMesh(vertices, indices);
ctx.UploadMesh(_mesh, true); ctx.UploadMesh(_mesh, true);
_shader = resourceAllocator.CreateShader(shaderDescriptor); _shader = ctx.ResourceAllocator.CreateShader(shaderDescriptor);
_material = resourceAllocator.CreateMaterial(_shader); _material = ctx.ResourceAllocator.CreateMaterial(_shader);
var imageResults = new ImageResult[_textureFiles.Length]; var imageResults = new ImageResult[_textureFiles.Length];

View File

@@ -3,10 +3,10 @@ shader "MyShader/Standard"
properties properties
{ {
float4 color = float4(1, 1, 1, 1); float4 color = float4(1, 1, 1, 1);
texture2d texture1 = texture2d(black); tex2d_b texture1 = tex2d_b(black);
texture2d texture2 = texture2d(white); tex2d_b texture2 = tex2d_b(white);
texture2d texture3 = texture2d(grey); tex2d_b texture3 = tex2d_b(grey);
texture2d texture4 = texture2d(normal); tex2d_b texture4 = tex2d_b(normal);
} }
pipeline pipeline

View File

@@ -3,6 +3,9 @@
#undef USE_TRADITIONAL_BINDLESS // Just for testing, this should be handled by engine feature level. #undef USE_TRADITIONAL_BINDLESS // Just for testing, this should be handled by engine feature level.
// Resource descriptor heap definitions
#if defined(USE_TRADITIONAL_BINDLESS) #if defined(USE_TRADITIONAL_BINDLESS)
#define GLOBAL_TEXTURE2D_HEAP_SIZE 32768 #define GLOBAL_TEXTURE2D_HEAP_SIZE 32768
#define GLOBAL_TEXTURE3D_HEAP_SIZE 32 #define GLOBAL_TEXTURE3D_HEAP_SIZE 32
@@ -27,6 +30,8 @@
#endif #endif
// Bindless resource type definitions
#define TEXTURE2D_BINDLESS uint #define TEXTURE2D_BINDLESS uint
#define TEXTURE3D_BINDLESS uint #define TEXTURE3D_BINDLESS uint
#define TEXTURECUBE_BINDLESS uint #define TEXTURECUBE_BINDLESS uint
@@ -38,6 +43,19 @@
#define STRUCT_BUFFER_BINDLESS uint #define STRUCT_BUFFER_BINDLESS uint
#define BYTE_ADDRESS_BUFFER_BINDLESS uint #define BYTE_ADDRESS_BUFFER_BINDLESS uint
#define TEXTURE2D Texture2D<float4>
#define TEXTURE3D Texture3D<float4>
#define TEXTURECUBE TextureCube<float4>
#define TEXTURE2D_ARRAY Texture2DArray<float4>
#define TEXTURECUBE_ARRAY TextureCubeArray<float4>
#define SAMPLER SamplerState
#define STRUCT_BUFFER(type) StructuredBuffer<type>
#define BYTE_ADDRESS_BUFFER ByteAddressBuffer
// Texture and sampler access macros
#define GET_TEXTURE2D_BINDLESS(id) GLOBAL_TEXTURE2D_HEAP[id] #define GET_TEXTURE2D_BINDLESS(id) GLOBAL_TEXTURE2D_HEAP[id]
#define GET_TEXTURE2D_ARRAY_BINDLESS(id) GLOBAL_TEXTURE2D_ARRAY_HEAP[id] #define GET_TEXTURE2D_ARRAY_BINDLESS(id) GLOBAL_TEXTURE2D_ARRAY_HEAP[id]
@@ -47,6 +65,8 @@
#define GET_SAMPLER_BINDLESS(id) GLOBAL_SAMPLER_HEAP[id] #define GET_SAMPLER_BINDLESS(id) GLOBAL_SAMPLER_HEAP[id]
// Texture sampling macros
#define SAMPLE_TEXTURE2D(tex, samp, uv) tex.Sample(samp, uv) #define SAMPLE_TEXTURE2D(tex, samp, uv) tex.Sample(samp, uv)
#define SAMPLE_TEXTURE2D_LEVEL(tex, samp, uv, level) tex.SampleLevel(samp, uv, level) #define SAMPLE_TEXTURE2D_LEVEL(tex, samp, uv, level) tex.SampleLevel(samp, uv, level)
#define SAMPLE_TEXTURE2D_BINDLESS(texId, sampId, uv) GET_TEXTURE2D_BINDLESS(texId).Sample(GET_BINDLESS_SAMPLER(sampId), uv) #define SAMPLE_TEXTURE2D_BINDLESS(texId, sampId, uv) GET_TEXTURE2D_BINDLESS(texId).Sample(GET_BINDLESS_SAMPLER(sampId), uv)
@@ -55,4 +75,8 @@
#define SAMPLE_TEXTURE2D_ARRAY(tex, samp, uv, index) tex.Sample(samp, uv, index) #define SAMPLE_TEXTURE2D_ARRAY(tex, samp, uv, index) tex.Sample(samp, uv, index)
#define SAMPLE_TEXTURE2D_ARRAY_BINDLESS(texId, sampId, uv, index) GET_TEXTURE2D_ARRAY_BINDLESS(texId).Sample(GET_BINDLESS_SAMPLER(sampId), uv, index) #define SAMPLE_TEXTURE2D_ARRAY_BINDLESS(texId, sampId, uv, index) GET_TEXTURE2D_ARRAY_BINDLESS(texId).Sample(GET_BINDLESS_SAMPLER(sampId), uv, index)
#define MESH_SHADER_THREADS(x) [NumThreads(x, 1, 1)]
#endif // COMMON_HLSL #endif // COMMON_HLSL

View File

@@ -73,9 +73,9 @@ internal class PropertiesBlock : IBlockParser<PropertiesSyntax, List<PropertySem
ParseBoolValue(syntax[3], errors))), ParseBoolValue(syntax[3], errors))),
// Textures (single identifier argument) // Textures (single identifier argument)
[ShaderPropertyType.Texture2D] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)), [ShaderPropertyType.Texture2DBindless] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
[ShaderPropertyType.Texture3D] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)), [ShaderPropertyType.Texture3DBindless] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
[ShaderPropertyType.TextureCube] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)), [ShaderPropertyType.TextureCubeBindless] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
}; };
private static float ParseFloatValue(Token token, List<SDLError> errors) private static float ParseFloatValue(Token token, List<SDLError> errors)
@@ -162,25 +162,25 @@ internal class PropertiesBlock : IBlockParser<PropertiesSyntax, List<PropertySem
{ {
return type.ToLower() switch return type.ToLower() switch
{ {
"float" => ShaderPropertyType.Float, TokenLexicon.KnownTypes.FLOAT => ShaderPropertyType.Float,
"float2" => ShaderPropertyType.Float2, TokenLexicon.KnownTypes.FLOAT2 => ShaderPropertyType.Float2,
"float3" => ShaderPropertyType.Float3, TokenLexicon.KnownTypes.FLOAT3 => ShaderPropertyType.Float3,
"float4" => ShaderPropertyType.Float4, TokenLexicon.KnownTypes.FLOAT4 => ShaderPropertyType.Float4,
"int" => ShaderPropertyType.Int, TokenLexicon.KnownTypes.INT => ShaderPropertyType.Int,
"int2" => ShaderPropertyType.Int2, TokenLexicon.KnownTypes.INT2 => ShaderPropertyType.Int2,
"int3" => ShaderPropertyType.Int3, TokenLexicon.KnownTypes.INT3 => ShaderPropertyType.Int3,
"int4" => ShaderPropertyType.Int4, TokenLexicon.KnownTypes.INT4 => ShaderPropertyType.Int4,
"uint" => ShaderPropertyType.UInt, TokenLexicon.KnownTypes.UINT => ShaderPropertyType.UInt,
"uint2" => ShaderPropertyType.UInt2, TokenLexicon.KnownTypes.UINT2 => ShaderPropertyType.UInt2,
"uint3" => ShaderPropertyType.UInt3, TokenLexicon.KnownTypes.UINT3 => ShaderPropertyType.UInt3,
"uint4" => ShaderPropertyType.UInt4, TokenLexicon.KnownTypes.UINT4 => ShaderPropertyType.UInt4,
"bool" => ShaderPropertyType.Bool, TokenLexicon.KnownTypes.BOOL => ShaderPropertyType.Bool,
"bool2" => ShaderPropertyType.Bool2, TokenLexicon.KnownTypes.BOOL2 => ShaderPropertyType.Bool2,
"bool3" => ShaderPropertyType.Bool3, TokenLexicon.KnownTypes.BOOL3 => ShaderPropertyType.Bool3,
"bool4" => ShaderPropertyType.Bool4, TokenLexicon.KnownTypes.BOOL4 => ShaderPropertyType.Bool4,
"texture2d" => ShaderPropertyType.Texture2D, TokenLexicon.KnownTypes.TEXTURE2D_BINDLESS => ShaderPropertyType.Texture2DBindless,
"texture3d" => ShaderPropertyType.Texture3D, TokenLexicon.KnownTypes.TEXTURE3D_BINDLESS => ShaderPropertyType.Texture3DBindless,
"texturecube" => ShaderPropertyType.TextureCube, TokenLexicon.KnownTypes.TEXTURECUBE_BINDLESS => ShaderPropertyType.TextureCubeBindless,
_ => ShaderPropertyType.None, _ => ShaderPropertyType.None,
}; };
} }

View File

@@ -22,11 +22,11 @@ internal static class SDLCompiler
private const string _GLOBAL_PROPERTY_FILE_NAME = "GlobalData.g.hlsl"; private const string _GLOBAL_PROPERTY_FILE_NAME = "GlobalData.g.hlsl";
private const string _GENERATED_FILE_HEADER = "// Auto-generated shader file. Please do not edit this file directly."; private const string _GENERATED_FILE_HEADER = "// Auto-generated shader file. Please do not edit this file directly.";
private struct ShaderInheritance // private struct ShaderInheritance
{ // {
public SDLSemantics? parent; // public SDLSemantics? parent;
public List<ShaderInheritance>? children; // public List<ShaderInheritance>? children;
} // }
public static List<SDLSyntax> ParseShaders(TokenStream stream) public static List<SDLSyntax> ParseShaders(TokenStream stream)
{ {
@@ -289,11 +289,11 @@ internal static class SDLCompiler
ShaderPropertyType.Bool3 => "bool3", ShaderPropertyType.Bool3 => "bool3",
ShaderPropertyType.Bool4 => "bool4", ShaderPropertyType.Bool4 => "bool4",
// NOTE: Textures here are bindless, represented as uint (descriptor index). // NOTE: Textures here are bindless, represented as uint (descriptor index).
ShaderPropertyType.Texture2D => "TEXTURE2D_BINDLESS", ShaderPropertyType.Texture2DBindless => "TEXTURE2D_BINDLESS",
ShaderPropertyType.Texture3D => "TEXTURE3D_BINDLESS", ShaderPropertyType.Texture3DBindless => "TEXTURE3D_BINDLESS",
ShaderPropertyType.TextureCube => "TEXTURECUBE_BINDLESS", ShaderPropertyType.TextureCubeBindless => "TEXTURECUBE_BINDLESS",
ShaderPropertyType.Texture2DArray => "TEXTURE2D_ARRAY_BINDLESS", ShaderPropertyType.Texture2DArrayBindless => "TEXTURE2D_ARRAY_BINDLESS",
ShaderPropertyType.TextureCubeArray => "TEXTURECUBE_ARRAY_BINDLESS", ShaderPropertyType.TextureCubeArrayBindless => "TEXTURECUBE_ARRAY_BINDLESS",
_ => throw new ArgumentOutOfRangeException(nameof(type), $"Unsupported shader property type: {type}") _ => throw new ArgumentOutOfRangeException(nameof(type), $"Unsupported shader property type: {type}")
}; };
} }

View File

@@ -170,11 +170,11 @@ internal static class TokenLexicon
public const string BOOL4 = "bool4"; public const string BOOL4 = "bool4";
// Texture types // Texture types
public const string TEXTURE2D = "texture2d"; public const string TEXTURE2D_BINDLESS = "tex2d_b";
public const string TEXTURE2D_ARRAY = "texture2d_array"; public const string TEXTURE2D_ARRAY_BINDLESS = "tex2d_arr_b";
public const string TEXTURE3D = "texture3d"; public const string TEXTURE3D_BINDLESS = "tex3d_b";
public const string TEXTURECUBE = "texturecube"; public const string TEXTURECUBE_BINDLESS = "texcube_b";
public const string TEXTURECUBE_ARRAY = "texturecube_array"; public const string TEXTURECUBE_ARRAY_BINDLESS = "texcube_arr_b";
} }
public static class KnownTextureValue public static class KnownTextureValue
@@ -215,8 +215,8 @@ internal static class TokenLexicon
KnownTypes.INT, KnownTypes.INT2, KnownTypes.INT3, KnownTypes.INT4, KnownTypes.INT, KnownTypes.INT2, KnownTypes.INT3, KnownTypes.INT4,
KnownTypes.UINT, KnownTypes.UINT2, KnownTypes.UINT3, KnownTypes.UINT4, KnownTypes.UINT, KnownTypes.UINT2, KnownTypes.UINT3, KnownTypes.UINT4,
KnownTypes.BOOL, KnownTypes.BOOL2, KnownTypes.BOOL3, KnownTypes.BOOL4, KnownTypes.BOOL, KnownTypes.BOOL2, KnownTypes.BOOL3, KnownTypes.BOOL4,
KnownTypes.TEXTURE2D, KnownTypes.TEXTURE2D_ARRAY, KnownTypes.TEXTURE3D, KnownTypes.TEXTURE2D_BINDLESS, KnownTypes.TEXTURE2D_ARRAY_BINDLESS, KnownTypes.TEXTURE3D_BINDLESS,
KnownTypes.TEXTURECUBE, KnownTypes.TEXTURECUBE_ARRAY, KnownTypes.TEXTURECUBE_BINDLESS, KnownTypes.TEXTURECUBE_ARRAY_BINDLESS,
}; };
private static readonly HashSet<string> s_textureDefaultValues = new() private static readonly HashSet<string> s_textureDefaultValues = new()