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
+2 -2
View File
@@ -295,7 +295,7 @@ namespace GlitchyEditor
mat.SetVariable("MetallicFactor", 1.0f); mat.SetVariable("MetallicFactor", 1.0f);
mat.SetVariable("RoughnessFactor", 1.0f); mat.SetVariable("RoughnessFactor", 1.0f);
EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", myEffect, mat, _scene.[Friend]_ecsWorld, clips, "Sphere 1"); EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", mat, _scene.[Friend]_ecsWorld, clips, "Sphere 1");
Entity entity = .(e, _scene); Entity entity = .(e, _scene);
var transform = entity.GetComponent<TransformComponent>(); var transform = entity.GetComponent<TransformComponent>();
@@ -342,7 +342,7 @@ namespace GlitchyEditor
mat.SetVariable("RoughnessFactor", (x + 1) / 10.0f); mat.SetVariable("RoughnessFactor", (x + 1) / 10.0f);
mat.SetVariable("MetallicFactor", y / 9.0f); mat.SetVariable("MetallicFactor", y / 9.0f);
EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", myEffect, mat, _scene.[Friend]_ecsWorld, clips, scope $"Sphere {x} {y}"); EcsEntity e = ModelLoader.LoadModel("content/Models/sphere.glb", mat, _scene.[Friend]_ecsWorld, clips, scope $"Sphere {x} {y}");
Entity entity = .(e, _scene); Entity entity = .(e, _scene);
var transform = entity.GetComponent<TransformComponent>(); var transform = entity.GetComponent<TransformComponent>();
+8 -8
View File
@@ -12,7 +12,7 @@ namespace GlitchyEngine.Content
{ {
static readonly Matrix RightToLeftHand = .Scaling(1, 1, -1); static readonly Matrix RightToLeftHand = .Scaling(1, 1, -1);
public static EcsEntity LoadModel(String filename, Effect validationEffect, Material material, EcsWorld world, public static EcsEntity LoadModel(String filename, Material material, EcsWorld world,
List<AnimationClip> outClips, StringView entityName = StringView()) List<AnimationClip> outClips, StringView entityName = StringView())
{ {
CGLTF.Options options = .(); CGLTF.Options options = .();
@@ -29,7 +29,7 @@ namespace GlitchyEngine.Content
for(var node in data.Scenes[0].Nodes) for(var node in data.Scenes[0].Nodes)
{ {
NodesToEntities(data, node, entity, world, validationEffect, material, outClips); NodesToEntities(data, node, entity, world, material, outClips);
} }
CGLTF.Free(data); CGLTF.Free(data);
@@ -63,7 +63,7 @@ namespace GlitchyEngine.Content
return (entity, childTransform); return (entity, childTransform);
} }
private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, EcsEntity parentEntity, EcsWorld world, Effect validationEffect, Material material, List<AnimationClip> clips) private static void NodesToEntities(CGLTF.Data* data, CGLTF.Node* node, EcsEntity parentEntity, EcsWorld world, Material material, List<AnimationClip> clips)
{ {
(EcsEntity entity, TransformComponent* childTransform) = CreateEntity(world, node.Name == null ? null : StringView(node.Name), parentEntity); (EcsEntity entity, TransformComponent* childTransform) = CreateEntity(world, node.Name == null ? null : StringView(node.Name), parentEntity);
@@ -109,7 +109,7 @@ namespace GlitchyEngine.Content
{ {
var mesh = world.AssignComponent<MeshComponent>(entity); var mesh = world.AssignComponent<MeshComponent>(entity);
using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0], validationEffect)) using (var geo = PrimitiveToGeoBinding(node.Mesh.Primitives[0]))
{ {
mesh.Mesh = geo; mesh.Mesh = geo;
} }
@@ -137,7 +137,7 @@ namespace GlitchyEngine.Content
meshParent.Entity = entity; meshParent.Entity = entity;
var mesh = world.AssignComponent<MeshComponent>(meshEntity); var mesh = world.AssignComponent<MeshComponent>(meshEntity);
mesh.Mesh = PrimitiveToGeoBinding(primitive, validationEffect); mesh.Mesh = PrimitiveToGeoBinding(primitive);
if(skeleton == null) if(skeleton == null)
{ {
@@ -158,11 +158,11 @@ namespace GlitchyEngine.Content
for(var child in node.Children) for(var child in node.Children)
{ {
NodesToEntities(data, child, entity, world, validationEffect, material, clips); NodesToEntities(data, child, entity, world, material, clips);
} }
} }
public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive, Effect validationEffect) public static GeometryBinding PrimitiveToGeoBinding(CGLTF.Primitive primitive)
{ {
GeometryBinding binding = new GeometryBinding(); GeometryBinding binding = new GeometryBinding();
@@ -327,7 +327,7 @@ namespace GlitchyEngine.Content
vertexElements[i] = elements[i]; vertexElements[i] = elements[i];
} }
VertexLayout layout = new VertexLayout(vertexElements, true, validationEffect.VertexShader); VertexLayout layout = new VertexLayout(vertexElements, true);
binding.SetVertexLayout(layout..ReleaseRefNoDelete()); binding.SetVertexLayout(layout..ReleaseRefNoDelete());
} }
@@ -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] bufferStrides;
internal uint32[DirectX.D3D11.D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] bufferOffsets; internal uint32[DirectX.D3D11.D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] bufferOffsets;
internal ID3D11InputLayout* nativeVertexLayout;
internal ID3D11Buffer* nativeIndexBuffer; internal ID3D11Buffer* nativeIndexBuffer;
public ~this() public ~this()
@@ -25,7 +24,6 @@ namespace GlitchyEngine.Renderer
buffer?.Release(); buffer?.Release();
} }
nativeVertexLayout?.Release();
nativeIndexBuffer?.Release(); nativeIndexBuffer?.Release();
} }
@@ -61,10 +59,6 @@ namespace GlitchyEngine.Renderer
protected override void PlatformSetVertexLayout(VertexLayout vertexLayout) protected override void PlatformSetVertexLayout(VertexLayout vertexLayout)
{ {
Debug.Profiler.ProfileResourceFunction!();
nativeVertexLayout?.Release();
nativeVertexLayout = vertexLayout?.nativeLayout..AddRef();
} }
protected override void PlatformSetIndexBuffer(IndexBuffer indexBuffer) protected override void PlatformSetIndexBuffer(IndexBuffer indexBuffer)
@@ -88,7 +82,7 @@ namespace GlitchyEngine.Renderer
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets); NativeContext.InputAssembler.SetVertexBuffers(0, nativeBuffers.Count, &nativeBuffers, &bufferStrides, &bufferOffsets);
NativeContext.InputAssembler.SetInputLayout(_vertexLayout.nativeLayout); GraphicsContext.Get().SetVertexLayout(_vertexLayout);
NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology); NativeContext.InputAssembler.SetPrimitiveTopology((.)_primitiveTopology);
if(_indexBuffer != null) if(_indexBuffer != null)
@@ -34,6 +34,11 @@ namespace GlitchyEngine.Renderer
private const uint32 MaxRTVCount = DirectX.D3D11.D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; 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 static override uint32 MaxRenderTargetCount() => MaxRTVCount;
public this(Windows.HWnd windowHandle) public this(Windows.HWnd windowHandle)
@@ -168,16 +173,39 @@ namespace GlitchyEngine.Renderer
NativeContext.InputAssembler.SetVertexBuffers(slot, 1, &buffer.nativeBuffer, &stride, &offset); 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) public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0)
{ {
BindInputLayout();
NativeContext.Draw(vertexCount, startVertexIndex); NativeContext.Draw(vertexCount, startVertexIndex);
} }
public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0) public override void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0)
{ {
BindInputLayout();
NativeContext.DrawIndexed(indexCount, startIndexLocation, vertexOffset); 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) public override void SetIndexBuffer(Buffer buffer, IndexFormat indexFormat = .Index16Bit, uint32 byteOffset = 0)
{ {
NativeContext.InputAssembler.SetIndexBuffer(buffer.nativeBuffer, indexFormat == .Index32Bit ? .R32_UInt : .R16_UInt, byteOffset); 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) 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) public override void SetPrimitiveTopology(GlitchyEngine.Renderer.PrimitiveTopology primitiveTopology)
@@ -262,6 +295,14 @@ namespace GlitchyEngine.Renderer
case typeof(VertexShader): case typeof(VertexShader):
NativeContext.VertexShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers); NativeContext.VertexShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers);
NativeContext.VertexShader.SetShader((ID3D11VertexShader*)shader.nativeShader); NativeContext.VertexShader.SetShader((ID3D11VertexShader*)shader.nativeShader);
if (VertexShader vs = shader as VertexShader)
{
SetReference!(_currentVertexShader, vs);
_currentInputLayout?.Release();
_currentInputLayout = null;
}
default: default:
Runtime.FatalError(scope $"Shader stage \"{typeof(TShader)}\" not implemented."); Runtime.FatalError(scope $"Shader stage \"{typeof(TShader)}\" not implemented.");
} }
@@ -216,7 +216,7 @@ namespace GlitchyEngine.Renderer
{ {
Debug.Profiler.ProfileRendererFunction!(); 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) public override void SetViewport(Viewport viewport)
@@ -5,6 +5,7 @@ using System.Diagnostics;
using DirectX.Common; using DirectX.Common;
using DirectX.D3D11; using DirectX.D3D11;
using GlitchyEngine.Platform.DX11; using GlitchyEngine.Platform.DX11;
using System.Collections;
using internal GlitchyEngine.Renderer; using internal GlitchyEngine.Renderer;
using internal GlitchyEngine.Platform.DX11; using internal GlitchyEngine.Platform.DX11;
@@ -13,20 +14,20 @@ namespace GlitchyEngine.Renderer
{ {
public extension VertexLayout public extension VertexLayout
{ {
internal ID3D11InputLayout* nativeLayout ~ _?.Release(); private Dictionary<ID3DBlob*, ID3D11InputLayout*> _validatedShaders = new .() ~
public ID3DBlob* nativeShaderCode ~ _?.Release();
public this(VertexElement[] elements, bool ownsElements, VertexShader vertexShader)
{ {
nativeShaderCode = vertexShader.nativeCode..AddRef(); if (_ != null)
{
_elements = elements; for (let entry in _)
_ownsElements = ownsElements; {
entry.key.Release();
CreateNativeLayout(); entry.value.Release();
} }
delete _;
}
};
private void ToNativeLayout(VertexElement[] input, InputElementDescription[] output) private void ToNativeLayout(VertexElement[] input, InputElementDescription[] output)
{ {
Debug.Assert(input.Count == output.Count); Debug.Assert(input.Count == output.Count);
@@ -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); 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!(); Debug.Profiler.ProfileResourceFunction!();
ID3D11InputLayout* layout = null;
if (!_validatedShaders.TryGetValue(vertexShaderCode, out layout))
{
var nativeElements = scope InputElementDescription[_elements.Count]; var nativeElements = scope InputElementDescription[_elements.Count];
ToNativeLayout(_elements, nativeElements); ToNativeLayout(_elements, nativeElements);
var result = NativeDevice.CreateInputLayout(nativeElements.CArray(), (.)nativeElements.Count, nativeShaderCode.GetBufferPointer(), nativeShaderCode.GetBufferSize(), &nativeLayout); var result = NativeDevice.CreateInputLayout(nativeElements.CArray(), (.)nativeElements.Count, vertexShaderCode.GetBufferPointer(), vertexShaderCode.GetBufferSize(), &layout);
if(result.Failed) if(result.Failed)
{ {
Log.EngineLogger.Error($"Failed to create D3D11 input layout: Message({(int)result}): {result}"); Log.EngineLogger.Error($"Failed to create D3D11 input layout: Message({(int)result}): {result}");
Debug.FatalError();
} }
_validatedShaders[vertexShaderCode..AddRef()] = layout;
}
return layout;
} }
} }
} }
@@ -80,6 +80,8 @@ namespace GlitchyEngine.Renderer
public extern void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0); public extern void DrawIndexed(uint32 indexCount, uint32 startIndexLocation = 0, int32 vertexOffset = 0);
public extern void DrawIndexedInstanced(uint32 indexCountPerInstance, uint32 instanceCount, uint32 startIndexLocation, int32 baseVertexLocation, uint32 startInstanceLocation);
public void SetIndexBuffer(IndexBuffer indexBuffer, uint32 byteOffset = 0) public void SetIndexBuffer(IndexBuffer indexBuffer, uint32 byteOffset = 0)
{ {
SetIndexBuffer(indexBuffer, indexBuffer.Format, byteOffset); SetIndexBuffer(indexBuffer, indexBuffer.Format, byteOffset);
+2 -2
View File
@@ -210,7 +210,7 @@ namespace GlitchyEngine.Renderer
VertexElement[] vertexElements = new VertexElement[1]; VertexElement[] vertexElements = new VertexElement[1];
vertexElements[0] = .(.R32G32B32_Float, "POSITION"); vertexElements[0] = .(.R32G32B32_Float, "POSITION");
VertexLayout layout = new VertexLayout(vertexElements, true, LineEffect.VertexShader); VertexLayout layout = new VertexLayout(vertexElements, true);
LineGeometry.SetVertexLayout(layout..ReleaseRefNoDelete()); LineGeometry.SetVertexLayout(layout..ReleaseRefNoDelete());
} }
@@ -258,7 +258,7 @@ namespace GlitchyEngine.Renderer
VertexElement(.R32G32_Float, "TEXCOORD") VertexElement(.R32G32_Float, "TEXCOORD")
); );
using (var quadBatchLayout = new VertexLayout(vertexElements, true, TestFullscreenEffect.VertexShader)) using (var quadBatchLayout = new VertexLayout(vertexElements, true))
{ {
s_fullscreenQuadGeometry.SetVertexLayout(quadBatchLayout); s_fullscreenQuadGeometry.SetVertexLayout(quadBatchLayout);
} }
+2 -2
View File
@@ -211,7 +211,7 @@ namespace GlitchyEngine.Renderer
s_quadBatchBinding = new GeometryBinding(); s_quadBatchBinding = new GeometryBinding();
s_quadBatchBinding.SetPrimitiveTopology(.TriangleList); s_quadBatchBinding.SetPrimitiveTopology(.TriangleList);
using (var quadBatchLayout = new VertexLayout(vertexElements, true, s_batchEffect.VertexShader)) using (var quadBatchLayout = new VertexLayout(vertexElements, true))
{ {
s_quadBatchBinding.SetVertexLayout(quadBatchLayout); s_quadBatchBinding.SetVertexLayout(quadBatchLayout);
} }
@@ -238,7 +238,7 @@ namespace GlitchyEngine.Renderer
s_circleBatchBinding = new GeometryBinding(); s_circleBatchBinding = new GeometryBinding();
s_circleBatchBinding.SetPrimitiveTopology(.TriangleList); s_circleBatchBinding.SetPrimitiveTopology(.TriangleList);
using (var circleBatchLayout = new VertexLayout(vertexElements, true, s_circleBatchEffect.VertexShader)) using (var circleBatchLayout = new VertexLayout(vertexElements, true))
{ {
s_circleBatchBinding.SetVertexLayout(circleBatchLayout); s_circleBatchBinding.SetVertexLayout(circleBatchLayout);
} }
+6 -3
View File
@@ -3,7 +3,6 @@ using GlitchyEngine.Core;
namespace GlitchyEngine.Renderer namespace GlitchyEngine.Renderer
{ {
/** /**
* Type of data contained in an input slot. * Type of data contained in an input slot.
*/ */
@@ -86,6 +85,12 @@ namespace GlitchyEngine.Renderer
public VertexElement[] Elements => _elements; public VertexElement[] Elements => _elements;
public this(VertexElement[] elements, bool ownsElements)
{
_elements = elements;
_ownsElements = ownsElements;
}
public ~this() public ~this()
{ {
if(_ownsElements) if(_ownsElements)
@@ -99,8 +104,6 @@ namespace GlitchyEngine.Renderer
delete _elements; delete _elements;
} }
} }
protected extern void CreateNativeLayout();
} }
public interface IVertexData public interface IVertexData
+2 -2
View File
@@ -97,7 +97,7 @@ namespace Sandbox
// Create Input Layout // Create Input Layout
VertexLayout vertexLayout = new VertexLayout(VertexColorTexture.VertexElements, false, textureEffect.VertexShader); VertexLayout vertexLayout = new VertexLayout(VertexColorTexture.VertexElements, false);
textureEffect.ReleaseRef(); textureEffect.ReleaseRef();
@@ -233,7 +233,7 @@ namespace Sandbox
materialTestMaterial.SetVariable("BaseColor", Color.White); materialTestMaterial.SetVariable("BaseColor", Color.White);
materialTestMaterial.SetVariable("LightDir", Vector3(1, 1, -0.5f).Normalized()); materialTestMaterial.SetVariable("LightDir", Vector3(1, 1, -0.5f).Normalized());
ModelLoader.LoadModel("content\\Models\\RiggedFigure\\RiggedFigure.glb", testEffect, materialTestMaterial, _world, Clips); ModelLoader.LoadModel("content\\Models\\RiggedFigure\\RiggedFigure.glb", materialTestMaterial, _world, Clips);
materialTestMaterial.ReleaseRef(); materialTestMaterial.ReleaseRef();
testEffect.ReleaseRef(); testEffect.ReleaseRef();