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,
UInt, UInt2, UInt3, UInt4,
Bool, Bool2, Bool3, Bool4,
Texture2D, Texture3D, TextureCube,
Texture2DArray, TextureCubeArray,
Texture2DBindless, Texture3DBindless, TextureCubeBindless,
Texture2DArrayBindless, TextureCubeArrayBindless,
}
public struct ShaderEntryPoint

View File

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

View File

@@ -211,7 +211,7 @@ public ref struct MaterialAccessor
for (var i = 0; i < _shader.PassCount; 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
{
private readonly IRenderDevice _device;
private readonly IGraphicsEngine _engine;
private readonly ICommandBuffer _directCmb;
private readonly ICommandBuffer _copyCmb;
private readonly ICommandBuffer _computeCmb;
private readonly IResourceAllocator _resourceAllocator;
private readonly IResourceDatabase _resourceDatabase;
private readonly IPipelineLibrary _stateController;
public ICommandBuffer DirectCommandBuffer => _directCmb;
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(
IRenderDevice device,
IGraphicsEngine engine,
ICommandBuffer directCmd,
ICommandBuffer copyCmd,
ICommandBuffer computeCmd,
IResourceAllocator resourceAllocator,
IResourceDatabase resourceDatabase,
IPipelineLibrary stateController)
ICommandBuffer computeCmd)
{
_device = device;
_engine = engine;
_directCmb = directCmd;
_copyCmb = copyCmd;
_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)
{
var mesh = _resourceAllocator.CreateMesh(vertices, indices);
var mesh = ResourceAllocator.CreateMesh(vertices, indices);
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>
public void UploadMesh(Handle<Mesh> mesh, bool markMeshStatic)
{
ref var meshData = ref _resourceDatabase.GetMeshReference(mesh);
var vertexState = _resourceDatabase.GetResourceState(meshData.vertexBuffer.AsResource());
var indexState = _resourceDatabase.GetResourceState(meshData.indexBuffer.AsResource());
ref var meshData = ref ResourceDatabase.GetMeshReference(mesh);
var vertexState = ResourceDatabase.GetResourceState(meshData.vertexBuffer.AsResource());
var indexState = ResourceDatabase.GetResourceState(meshData.indexBuffer.AsResource());
var needVertexTransition = vertexState != ResourceState.CopyDest;
var needIndexTransition = indexState != ResourceState.CopyDest;
if (needVertexTransition)
{
_copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), vertexState, ResourceState.CopyDest);
_resourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest);
ResourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest);
}
if (needIndexTransition)
{
_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.Upload(meshData.indexBuffer, meshData.indices.AsSpan());
_copyCmb.UploadBuffer<Vertex>(meshData.vertexBuffer, meshData.vertices.AsSpan());
_copyCmb.UploadBuffer<uint>(meshData.indexBuffer, meshData.indices.AsSpan());
if (needVertexTransition)
{
_copyCmb.ResourceBarrier(meshData.vertexBuffer.AsResource(), ResourceState.CopyDest, vertexState);
_resourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), vertexState);
ResourceDatabase.SetResourceState(meshData.vertexBuffer.AsResource(), vertexState);
}
if (needIndexTransition)
{
_resourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), indexState);
ResourceDatabase.SetResourceState(meshData.indexBuffer.AsResource(), 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)
{
return _resourceAllocator.CreateTexture(in desc, tempResource);
return ResourceAllocator.CreateTexture(in desc, tempResource);
}
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 _);
var subresourceData = new SubResourceData
@@ -117,78 +136,31 @@ public unsafe readonly ref struct RenderingContext
slicePitch = slicePitch
};
var sateBefore = _resourceDatabase.GetResourceState(texture.AsResource());
var sateBefore = ResourceDatabase.GetResourceState(texture.AsResource());
var needTransition = sateBefore != ResourceState.CopyDest;
if (needTransition)
{
_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)
{
_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.
// 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)
{
ref var meshRef = ref _resourceDatabase.GetMeshReference(mesh);
ref var materialRef = ref _resourceDatabase.GetMaterialReference(material);
var shader = _resourceDatabase.GetShaderReference(materialRef.Shader);
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
@@ -202,15 +174,9 @@ public unsafe readonly ref struct RenderingContext
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++)
{
// NOTE: We use fixed root signature layout for bindless rendering.
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?
@@ -222,10 +188,4 @@ public unsafe readonly ref struct RenderingContext
var threadGroupCountX = ((uint)meshRef.indices.Count + numThreadsX - 1) / numThreadsX;
_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();
}
public void Upload<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
public void UploadBuffer<T>(Handle<GraphicsBuffer> buffer, ReadOnlySpan<T> data)
where T : unmanaged
{
ThrowIfDisposed();
@@ -422,7 +422,7 @@ internal unsafe class D3D12CommandBuffer : ICommandBuffer
_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();
ThrowIfNotRecording();

View File

@@ -9,7 +9,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
#endif
private readonly D3D12RenderDevice _device;
private readonly D3D12PipelineLibrary _stateController;
private readonly D3D12PipelineLibrary _pipelineLibrary;
private readonly D3D12DescriptorAllocator _descriptorAllocator;
private readonly D3D12ResourceDatabase _resourceDatabase;
@@ -17,13 +17,11 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
private readonly D3D12CommandBuffer _copyCommandBuffer;
public IRenderDevice Device => _device;
public IPipelineLibrary PipelineLibrary => _pipelineLibrary;
public IResourceDatabase ResourceDatabase => _resourceDatabase;
public IResourceAllocator ResourceAllocator => _resourceAllocator;
public IPipelineLibrary PipelineStateController => _stateController;
public D3D12GraphicsEngine(RenderSystem renderSystem)
{
#if DEBUG
@@ -35,10 +33,10 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
_resourceDatabase = new(_descriptorAllocator);
_resourceAllocator = new(renderSystem, _device, _descriptorAllocator, _resourceDatabase);
_stateController = new(_device, _resourceDatabase, null);
_pipelineLibrary = new(_device, _resourceDatabase);
_copyCommandBuffer = new(
_device,
_stateController,
_pipelineLibrary,
_resourceDatabase,
_resourceAllocator,
_descriptorAllocator,
@@ -59,7 +57,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
{
return new D3D12CommandBuffer(
_device,
_stateController,
_pipelineLibrary,
_resourceDatabase,
_resourceAllocator,
_descriptorAllocator,
@@ -84,7 +82,7 @@ internal unsafe class D3D12GraphicsEngine : IGraphicsEngine
public void Dispose()
{
_copyCommandBuffer.Dispose();
_stateController.Dispose();
_pipelineLibrary.Dispose();
_resourceAllocator.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 };
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 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
// 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:
// 1. Set render target to the destination
// 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.)
// 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
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 UnsafeSlotMap<ResourceRecord> _resources;

View File

@@ -1,11 +1,9 @@
using Ghost.Core;
using Ghost.Core.Utilities;
using Ghost.Graphics.D3D12.Utilities;
using Ghost.Graphics.RHI;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections;
using Misaki.HighPerformance.LowLevel.Utilities;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
@@ -204,11 +202,11 @@ internal static unsafe class D3D12ShaderCompiler
using ComPtr<IDxcIncludeHandler> includeHandler = default;
// Create DXC compiler and utils
var pDxcCompiler = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcCompiler);
var pDxcUtils = (Guid*)Unsafe.AsPointer(in CLSID.CLSID_DxcUtils);
var dxccID = CLSID.CLSID_DxcCompiler;
var dxcuID = CLSID.CLSID_DxcUtils;
ThrowIfFailed(DxcCreateInstance(pDxcCompiler, compiler.IID(), compiler.PPV()));
ThrowIfFailed(DxcCreateInstance(pDxcUtils, utils.IID(), utils.PPV()));
ThrowIfFailed(DxcCreateInstance(&dxccID, compiler.IID(), compiler.PPV()));
ThrowIfFailed(DxcCreateInstance(&dxcuID, utils.IID(), utils.PPV()));
//includeHandler.Get()->LoadSource();
utils.Get()->CreateDefaultIncludeHandler(includeHandler.GetAddressOf());
@@ -299,9 +297,9 @@ internal static unsafe class D3D12ShaderCompiler
}
// 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;
ThrowIfFailed(DxcCreateInstance(pDxcUtils, utils.IID(), utils.PPV()));
ThrowIfFailed(DxcCreateInstance(&dxcuID, utils.IID(), utils.PPV()));
// Create reflection interface from blob
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="data">A read-only span containing the data to upload to the buffer. The span must contain elements of type
/// <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;
/// <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="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>
void Upload(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources);
void UploadTexture(Handle<Texture> texture, params ReadOnlySpan<SubResourceData> subresources);
/// <summary>
/// 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 IRenderDevice Device
IRenderDevice Device
{
get;
}
public IResourceDatabase ResourceDatabase
IPipelineLibrary PipelineLibrary
{
get;
}
public IResourceAllocator ResourceAllocator
IResourceDatabase ResourceDatabase
{
get;
}
public IRenderer CreateRenderer();
IResourceAllocator ResourceAllocator
{
get;
}
IRenderer CreateRenderer();
/// <summary>
/// Creates a command buffer for recording rendering commands
/// </summary>
/// <param name="type">Type of command buffer to create</param>
/// <returns>A new command buffer instance</returns>
public ICommandBuffer CreateCommandBuffer(CommandBufferType type = CommandBufferType.Graphics);
ICommandBuffer CreateCommandBuffer(CommandBufferType type = CommandBufferType.Graphics);
/// <summary>
/// Creates a swap chain for presentation
/// </summary>
/// <param name="desc">Swap chain description</param>
/// <returns>A new swap chain instance</returns>
public ISwapChain CreateSwapChain(SwapChainDesc desc);
ISwapChain CreateSwapChain(SwapChainDesc desc);
/// <summary>
/// Begins a new rendering frame, preparing the graphics context for drawing operations.
/// </summary>
public void BeginFrame();
void BeginFrame();
/// <summary>
/// Completes the current rendering frame and performs any necessary finalization steps.
/// </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"
];
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 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);
_mesh = ctx.CreateMesh(vertices, indices);
ctx.UploadMesh(_mesh, true);
_shader = resourceAllocator.CreateShader(shaderDescriptor);
_material = resourceAllocator.CreateMaterial(_shader);
_shader = ctx.ResourceAllocator.CreateShader(shaderDescriptor);
_material = ctx.ResourceAllocator.CreateMaterial(_shader);
var imageResults = new ImageResult[_textureFiles.Length];

View File

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

View File

@@ -3,6 +3,9 @@
#undef USE_TRADITIONAL_BINDLESS // Just for testing, this should be handled by engine feature level.
// Resource descriptor heap definitions
#if defined(USE_TRADITIONAL_BINDLESS)
#define GLOBAL_TEXTURE2D_HEAP_SIZE 32768
#define GLOBAL_TEXTURE3D_HEAP_SIZE 32
@@ -27,6 +30,8 @@
#endif
// Bindless resource type definitions
#define TEXTURE2D_BINDLESS uint
#define TEXTURE3D_BINDLESS uint
#define TEXTURECUBE_BINDLESS uint
@@ -38,6 +43,19 @@
#define STRUCT_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_ARRAY_BINDLESS(id) GLOBAL_TEXTURE2D_ARRAY_HEAP[id]
@@ -47,6 +65,8 @@
#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_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)
@@ -55,4 +75,8 @@
#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 MESH_SHADER_THREADS(x) [NumThreads(x, 1, 1)]
#endif // COMMON_HLSL

View File

@@ -73,9 +73,9 @@ internal class PropertiesBlock : IBlockParser<PropertiesSyntax, List<PropertySem
ParseBoolValue(syntax[3], errors))),
// Textures (single identifier argument)
[ShaderPropertyType.Texture2D] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
[ShaderPropertyType.Texture3D] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
[ShaderPropertyType.TextureCube] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
[ShaderPropertyType.Texture2DBindless] = new(1, TokenType.Identifier, (syntax, errors) => ParseTextureDefault(syntax[0], errors)),
[ShaderPropertyType.Texture3DBindless] = 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)
@@ -162,25 +162,25 @@ internal class PropertiesBlock : IBlockParser<PropertiesSyntax, List<PropertySem
{
return type.ToLower() switch
{
"float" => ShaderPropertyType.Float,
"float2" => ShaderPropertyType.Float2,
"float3" => ShaderPropertyType.Float3,
"float4" => ShaderPropertyType.Float4,
"int" => ShaderPropertyType.Int,
"int2" => ShaderPropertyType.Int2,
"int3" => ShaderPropertyType.Int3,
"int4" => ShaderPropertyType.Int4,
"uint" => ShaderPropertyType.UInt,
"uint2" => ShaderPropertyType.UInt2,
"uint3" => ShaderPropertyType.UInt3,
"uint4" => ShaderPropertyType.UInt4,
"bool" => ShaderPropertyType.Bool,
"bool2" => ShaderPropertyType.Bool2,
"bool3" => ShaderPropertyType.Bool3,
"bool4" => ShaderPropertyType.Bool4,
"texture2d" => ShaderPropertyType.Texture2D,
"texture3d" => ShaderPropertyType.Texture3D,
"texturecube" => ShaderPropertyType.TextureCube,
TokenLexicon.KnownTypes.FLOAT => ShaderPropertyType.Float,
TokenLexicon.KnownTypes.FLOAT2 => ShaderPropertyType.Float2,
TokenLexicon.KnownTypes.FLOAT3 => ShaderPropertyType.Float3,
TokenLexicon.KnownTypes.FLOAT4 => ShaderPropertyType.Float4,
TokenLexicon.KnownTypes.INT => ShaderPropertyType.Int,
TokenLexicon.KnownTypes.INT2 => ShaderPropertyType.Int2,
TokenLexicon.KnownTypes.INT3 => ShaderPropertyType.Int3,
TokenLexicon.KnownTypes.INT4 => ShaderPropertyType.Int4,
TokenLexicon.KnownTypes.UINT => ShaderPropertyType.UInt,
TokenLexicon.KnownTypes.UINT2 => ShaderPropertyType.UInt2,
TokenLexicon.KnownTypes.UINT3 => ShaderPropertyType.UInt3,
TokenLexicon.KnownTypes.UINT4 => ShaderPropertyType.UInt4,
TokenLexicon.KnownTypes.BOOL => ShaderPropertyType.Bool,
TokenLexicon.KnownTypes.BOOL2 => ShaderPropertyType.Bool2,
TokenLexicon.KnownTypes.BOOL3 => ShaderPropertyType.Bool3,
TokenLexicon.KnownTypes.BOOL4 => ShaderPropertyType.Bool4,
TokenLexicon.KnownTypes.TEXTURE2D_BINDLESS => ShaderPropertyType.Texture2DBindless,
TokenLexicon.KnownTypes.TEXTURE3D_BINDLESS => ShaderPropertyType.Texture3DBindless,
TokenLexicon.KnownTypes.TEXTURECUBE_BINDLESS => ShaderPropertyType.TextureCubeBindless,
_ => 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 _GENERATED_FILE_HEADER = "// Auto-generated shader file. Please do not edit this file directly.";
private struct ShaderInheritance
{
public SDLSemantics? parent;
public List<ShaderInheritance>? children;
}
// private struct ShaderInheritance
// {
// public SDLSemantics? parent;
// public List<ShaderInheritance>? children;
// }
public static List<SDLSyntax> ParseShaders(TokenStream stream)
{
@@ -289,11 +289,11 @@ internal static class SDLCompiler
ShaderPropertyType.Bool3 => "bool3",
ShaderPropertyType.Bool4 => "bool4",
// NOTE: Textures here are bindless, represented as uint (descriptor index).
ShaderPropertyType.Texture2D => "TEXTURE2D_BINDLESS",
ShaderPropertyType.Texture3D => "TEXTURE3D_BINDLESS",
ShaderPropertyType.TextureCube => "TEXTURECUBE_BINDLESS",
ShaderPropertyType.Texture2DArray => "TEXTURE2D_ARRAY_BINDLESS",
ShaderPropertyType.TextureCubeArray => "TEXTURECUBE_ARRAY_BINDLESS",
ShaderPropertyType.Texture2DBindless => "TEXTURE2D_BINDLESS",
ShaderPropertyType.Texture3DBindless => "TEXTURE3D_BINDLESS",
ShaderPropertyType.TextureCubeBindless => "TEXTURECUBE_BINDLESS",
ShaderPropertyType.Texture2DArrayBindless => "TEXTURE2D_ARRAY_BINDLESS",
ShaderPropertyType.TextureCubeArrayBindless => "TEXTURECUBE_ARRAY_BINDLESS",
_ => 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";
// Texture types
public const string TEXTURE2D = "texture2d";
public const string TEXTURE2D_ARRAY = "texture2d_array";
public const string TEXTURE3D = "texture3d";
public const string TEXTURECUBE = "texturecube";
public const string TEXTURECUBE_ARRAY = "texturecube_array";
public const string TEXTURE2D_BINDLESS = "tex2d_b";
public const string TEXTURE2D_ARRAY_BINDLESS = "tex2d_arr_b";
public const string TEXTURE3D_BINDLESS = "tex3d_b";
public const string TEXTURECUBE_BINDLESS = "texcube_b";
public const string TEXTURECUBE_ARRAY_BINDLESS = "texcube_arr_b";
}
public static class KnownTextureValue
@@ -215,8 +215,8 @@ internal static class TokenLexicon
KnownTypes.INT, KnownTypes.INT2, KnownTypes.INT3, KnownTypes.INT4,
KnownTypes.UINT, KnownTypes.UINT2, KnownTypes.UINT3, KnownTypes.UINT4,
KnownTypes.BOOL, KnownTypes.BOOL2, KnownTypes.BOOL3, KnownTypes.BOOL4,
KnownTypes.TEXTURE2D, KnownTypes.TEXTURE2D_ARRAY, KnownTypes.TEXTURE3D,
KnownTypes.TEXTURECUBE, KnownTypes.TEXTURECUBE_ARRAY,
KnownTypes.TEXTURE2D_BINDLESS, KnownTypes.TEXTURE2D_ARRAY_BINDLESS, KnownTypes.TEXTURE3D_BINDLESS,
KnownTypes.TEXTURECUBE_BINDLESS, KnownTypes.TEXTURECUBE_ARRAY_BINDLESS,
};
private static readonly HashSet<string> s_textureDefaultValues = new()