DX11: Automatically validate input layouts against vertex shaders

This commit is contained in:
Simon Lübeß
2022-05-26 11:27:02 +02:00
parent 28f1fad464
commit 164d420a25
11 changed files with 101 additions and 49 deletions
@@ -15,7 +15,6 @@ namespace GlitchyEngine.Renderer
internal uint32[DirectX.D3D11.D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] bufferStrides;
internal uint32[DirectX.D3D11.D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] bufferOffsets;
internal ID3D11InputLayout* nativeVertexLayout;
internal ID3D11Buffer* nativeIndexBuffer;
public ~this()
@@ -25,7 +24,6 @@ namespace GlitchyEngine.Renderer
buffer?.Release();
}
nativeVertexLayout?.Release();
nativeIndexBuffer?.Release();
}
@@ -61,10 +59,6 @@ namespace GlitchyEngine.Renderer
protected override void PlatformSetVertexLayout(VertexLayout vertexLayout)
{
Debug.Profiler.ProfileResourceFunction!();
nativeVertexLayout?.Release();
nativeVertexLayout = vertexLayout?.nativeLayout..AddRef();
}
protected override void PlatformSetIndexBuffer(IndexBuffer indexBuffer)
@@ -88,7 +82,7 @@ namespace GlitchyEngine.Renderer
Debug.Profiler.ProfileRendererFunction!();
NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets);
NativeContext.InputAssembler.SetInputLayout(_vertexLayout.nativeLayout);
GraphicsContext.Get().SetVertexLayout(_vertexLayout);
NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology);
if(_indexBuffer != null)
@@ -34,6 +34,11 @@ namespace GlitchyEngine.Renderer
private const uint32 MaxRTVCount = DirectX.D3D11.D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT;
// current vertex layout and vertex shader needed for validation.
ID3D11InputLayout* _currentInputLayout ~ _?.Release();
VertexLayout _currentVertexLayout ~ _?.ReleaseRef();
VertexShader _currentVertexShader ~ _?.ReleaseRef();
//public static override uint32 MaxRenderTargetCount() => MaxRTVCount;
public this(Windows.HWnd windowHandle)
@@ -168,16 +173,39 @@ namespace GlitchyEngine.Renderer
NativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset);
}
[Inline]
private void BindInputLayout()
{
if (_currentInputLayout == null)
{
_currentInputLayout = _currentVertexLayout.GetNativeVertexLayout(_currentVertexShader.nativeCode);
_currentInputLayout.AddRef();
NativeContext.InputAssembler.SetInputLayout(_currentInputLayout);
}
}
public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0)
{
BindInputLayout();
NativeContext.Draw(vertexCount, startVertexIndex);
}
public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0)
{
BindInputLayout();
NativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset);
}
public override void DrawIndexedInstanced(uint32 indexCountPerInstance, uint32 instanceCount, uint32 startIndexLocation, int32 baseVertexLocation, uint32 startInstanceLocation)
{
BindInputLayout();
NativeContext.DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation);
}
public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0)
{
NativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset);
@@ -190,7 +218,12 @@ namespace GlitchyEngine.Renderer
public override void SetVertexLayout(VertexLayout vertexLayout)
{
NativeContext.InputAssembler.SetInputLayout(vertexLayout.nativeLayout);
if (_currentVertexLayout != vertexLayout)
{
SetReference!(_currentVertexLayout, vertexLayout);
_currentInputLayout?.Release();
_currentInputLayout = null;
}
}
public override void SetPrimitiveTopology(GlitchyEngine.Renderer.PrimitiveTopology primitiveTopology)
@@ -252,7 +285,7 @@ namespace GlitchyEngine.Renderer
}
shader.Buffers.PlatformFetchNativeBuffers();
switch(typeof(TShader))
{
// TODO: Add remaining shader stages
@@ -262,6 +295,14 @@ namespace GlitchyEngine.Renderer
case typeof(VertexShader):
NativeContext.VertexShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers);
NativeContext.VertexShader.SetShader((ID3D11VertexShader*)shader.nativeShader);
if (VertexShader vs = shader as VertexShader)
{
SetReference!(_currentVertexShader, vs);
_currentInputLayout?.Release();
_currentInputLayout = null;
}
default:
Runtime.FatalError(scope $"Shader stage \"{typeof(TShader)}\" not implemented.");
}
@@ -216,7 +216,7 @@ namespace GlitchyEngine.Renderer
{
Debug.Profiler.ProfileRendererFunction!();
NativeContext.DrawIndexedInstanced(geometry.IndexCount, geometry.InstanceCount, geometry.IndexByteOffset, 0, 0);
_context.DrawIndexedInstanced(geometry.IndexCount, geometry.InstanceCount, geometry.IndexByteOffset, 0, 0);
}
public override void SetViewport(Viewport viewport)
@@ -5,6 +5,7 @@ using System.Diagnostics;
using DirectX.Common;
using DirectX.D3D11;
using GlitchyEngine.Platform.DX11;
using System.Collections;
using internal GlitchyEngine.Renderer;
using internal GlitchyEngine.Platform.DX11;
@@ -13,19 +14,19 @@ namespace GlitchyEngine.Renderer
{
public extension VertexLayout
{
internal ID3D11InputLayout* nativeLayout ~ _?.Release();
private Dictionary<ID3DBlob*, ID3D11InputLayout*> _validatedShaders = new .() ~
{
if (_ != null)
{
for (let entry in _)
{
entry.key.Release();
entry.value.Release();
}
public ID3DBlob* nativeShaderCode ~ _?.Release();
public this(VertexElement[] elements, bool ownsElements, VertexShader vertexShader)
{
nativeShaderCode = vertexShader.nativeCode..AddRef();
_elements = elements;
_ownsElements = ownsElements;
CreateNativeLayout();
}
delete _;
}
};
private void ToNativeLayout(VertexElement[] input, InputElementDescription[] output)
{
@@ -35,19 +36,30 @@ namespace GlitchyEngine.Renderer
output[i] = .(input[i].SemanticName, input[i].SemanticIndex, input[i].Format, input[i].InputSlot, input[i].AlignedByteOffset, (.)input[i].InputSlotClass, input[i].InstanceDataStepRate);
}
protected override void CreateNativeLayout()
/// Validates or gets the validated input layout for the given vertexshader.
internal ID3D11InputLayout* GetNativeVertexLayout(ID3DBlob* vertexShaderCode)
{
Debug.Profiler.ProfileResourceFunction!();
var nativeElements = scope InputElementDescription[_elements.Count];
ID3D11InputLayout* layout = null;
ToNativeLayout(_elements, nativeElements);
var result = NativeDevice.CreateInputLayout(nativeElements.CArray(), (.)nativeElements.Count, nativeShaderCode.GetBufferPointer(), nativeShaderCode.GetBufferSize(), &nativeLayout);
if(result.Failed)
if (!_validatedShaders.TryGetValue(vertexShaderCode, out layout))
{
Log.EngineLogger.Error($"Failed to create D3D11 input layout: Message({(int)result}): {result}");
var nativeElements = scope InputElementDescription[_elements.Count];
ToNativeLayout(_elements, nativeElements);
var result = NativeDevice.CreateInputLayout(nativeElements.CArray(), (.)nativeElements.Count, vertexShaderCode.GetBufferPointer(), vertexShaderCode.GetBufferSize(), &layout);
if(result.Failed)
{
Log.EngineLogger.Error($"Failed to create D3D11 input layout: Message({(int)result}): {result}");
Debug.FatalError();
}
_validatedShaders[vertexShaderCode..AddRef()] = layout;
}
return layout;
}
}
}