From 66e62f42ec196bc1443c47a259865000b3646c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20L=C3=BCbe=C3=9F?= Date: Thu, 22 Aug 2024 00:34:20 +0200 Subject: [PATCH] First working effects with new pipeline --- .../resources/Shaders/ClearUInt.hlsl.ass | 10 +- .../resources/Shaders/spritebatch.hlsl.ass | 10 +- .../src/Assets/Exporters/ShaderExporter.bf | 162 +++++++++++++++++ .../src/Assets/Exporters/TextureExporter.bf | 2 +- .../src/Assets/Processors/ShaderCompiler.bf | 27 ++- .../src/Assets/Processors/ShaderProcessor.bf | 167 ++++++++++++++++-- GlitchyEditor/src/EditorApp.bf | 2 +- GlitchyEditor/src/EditorContentManager.bf | 4 + .../src/Content/Loaders/ShaderLoader.bf | 149 ++++++++++++++++ .../src/Platform/DX11/Renderer/Dx11Shader.bf | 46 +++++ .../DX11/Renderer/Dx11TextureViewBinding.bf | 2 + .../DX11/Renderer/Dx11VertexLayout.bf | 1 + GlitchyEngine/src/Renderer/BufferVariable.bf | 3 +- GlitchyEngine/src/Renderer/ConstantBuffer.bf | 19 +- GlitchyEngine/src/Renderer/Effect.bf | 14 +- GlitchyEngine/src/Renderer/PixelShader.bf | 2 + GlitchyEngine/src/Renderer/Shader.bf | 68 +++++-- .../src/Renderer/ShaderTextureCollection.bf | 2 + .../src/Renderer/TextureViewBinding.bf | 3 + GlitchyEngine/src/Renderer/VertexShader.bf | 2 + 20 files changed, 652 insertions(+), 43 deletions(-) create mode 100644 GlitchyEditor/src/Assets/Exporters/ShaderExporter.bf create mode 100644 GlitchyEngine/src/Content/Loaders/ShaderLoader.bf diff --git a/GlitchyEditor/resources/Shaders/ClearUInt.hlsl.ass b/GlitchyEditor/resources/Shaders/ClearUInt.hlsl.ass index 903995b..10001c6 100644 --- a/GlitchyEditor/resources/Shaders/ClearUInt.hlsl.ass +++ b/GlitchyEditor/resources/Shaders/ClearUInt.hlsl.ass @@ -1,5 +1,13 @@ { AssetLoader = "EffectAssetLoader", Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}/* No reflection data for GlitchyEditor.Assets.EffectAssetLoaderConfig. Add [BonTarget] or force it */, - AssetHandle = 15597986932192091061 + Importer = "ShaderImporter", + ImporterConfig = null, + Processor = null, + ProcessorConfig = null, + Exporter = null, + ExporterConfig = { + _compression = .None + }, + AssetHandle = 7951861132321655812 } \ No newline at end of file diff --git a/GlitchyEditor/resources/Shaders/spritebatch.hlsl.ass b/GlitchyEditor/resources/Shaders/spritebatch.hlsl.ass index 5657c97..f0725b7 100644 --- a/GlitchyEditor/resources/Shaders/spritebatch.hlsl.ass +++ b/GlitchyEditor/resources/Shaders/spritebatch.hlsl.ass @@ -1,5 +1,13 @@ { AssetLoader = "EffectAssetLoader", Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}/* No reflection data for GlitchyEditor.Assets.EffectAssetLoaderConfig. Add [BonTarget] or force it */, - AssetHandle = 14473519405124742382 + Importer = "ShaderImporter", + ImporterConfig = null, + Processor = null, + ProcessorConfig = null, + Exporter = null, + ExporterConfig = { + _compression = .None + }, + AssetHandle = 959631876667366082 } \ No newline at end of file diff --git a/GlitchyEditor/src/Assets/Exporters/ShaderExporter.bf b/GlitchyEditor/src/Assets/Exporters/ShaderExporter.bf new file mode 100644 index 0000000..4d37adc --- /dev/null +++ b/GlitchyEditor/src/Assets/Exporters/ShaderExporter.bf @@ -0,0 +1,162 @@ +using GlitchyEngine; +using GlitchyEditor.Assets.Importers; +using GlitchyEditor.Assets.Processors; +using GlitchyEngine.Content; +using System; +using System.IO; + +namespace GlitchyEditor.Assets.Exporters; + +class ShaderExporter : IAssetExporter +{ + public static AssetType ExportedAssetType => .Shader; + + public AssetExporterConfig CreateDefaultConfig() => new AssetExporterConfig(); + + public Result Export(Stream stream, ProcessedResource processedResource, AssetConfig config) + { + Log.EngineLogger.AssertDebug(processedResource is ProcessedShader); + + ProcessedShader shader = (.)processedResource; + + /* + + File Format: + Vertex Shader Blob Length (uint64 / 8 bytes) (0 if null) + Vertex Shader Data... + Pixel Shader Blob Length (uint64 / 8 bytes) (0 if null) + Pixel Shader Data... + Texture Count (uint16) + Textures + { + Texture Dimension (1 byte) + Vertex Shader Bind Point (int32, 4 bytes) + Pixel Shader Bind Point (int32, 4 bytes) + Texture Name Length (16 bytes) + Texture Name Data... + } + Buffer Count (uint16) + Buffers + { + Buffer Size (int64) + Vertex Shader Bind Point (int32, 4 bytes) + Pixel Shader Bind Point (int32, 4 bytes) + Buffer Name Length (16 bytes) + Buffer Name Data... + Engine Buffer Name Length (16 bytes) + Engine Buffer Name Data... + Variable Count (uint16) + Variables + { + Offset (uint64) + Size In Bytes (uint64) + IsUsed (bool, 1 byte) + ShaderVariableType (1 Byte) + Rows (uint8) + Columns (uint8) + ArraySize (uint64) + Name Length (16 bytes) + Name Data... + } + RawData... + } + + */ + + Span vsData = shader.VertexShader?.Blob ?? Span(); + Span psData = shader.PixelShader?.Blob ?? Span(); + + Try!(stream.Write((uint64)vsData.Length)); + Try!(stream.Write((uint64)psData.Length)); + + if (vsData.Ptr != null) + Try!(stream.Write(vsData)); + + if (psData.Ptr != null) + Try!(stream.Write(psData)); + + Try!(WriteTextures(stream, shader)); + Try!(WriteConstantBuffers(stream, shader)); + + return .Ok; + } + + private Result WriteTextures(Stream stream, ProcessedShader shader) + { + Log.EngineLogger.Assert(shader.Textures.Count < int16.MaxValue); + + Try!(stream.Write((uint16)shader.Textures.Count)); + + for (let (textureName, textureEntry) in shader.Textures) + { + Try!(stream.Write((uint8)textureEntry.TextureDimension)); + Try!(stream.Write((int32)textureEntry.VertexShaderBindPoint)); + Try!(stream.Write((int32)textureEntry.PixelShaderBindPoint)); + + Log.EngineLogger.Assert(textureName.Length < int16.MaxValue); + + Try!(stream.Write((int16)textureName.Length)); + Try!(stream.Write(textureName)); + } + + return .Ok; + } + + private Result WriteConstantBuffers(Stream stream, ProcessedShader shader) + { + Log.EngineLogger.Assert(shader.ConstantBuffers.Count < int16.MaxValue); + + Try!(stream.Write((uint16)shader.ConstantBuffers.Count)); + + for (let (bufferName, bufferEntry) in shader.ConstantBuffers) + { + ReflectedConstantBuffer buffer = bufferEntry.ConstantBuffer; + + Try!(stream.Write((uint64)buffer.Size)); + + Try!(stream.Write((int32)bufferEntry.VertexShaderBindPoint)); + Try!(stream.Write((int32)bufferEntry.PixelShaderBindPoint)); + + Log.EngineLogger.Assert(bufferName.Length < int16.MaxValue); + + Try!(stream.Write((uint16)bufferName.Length)); + Try!(stream.Write(bufferName)); + + int engineBufferNameLength = bufferEntry.ConstantBuffer.EngineBufferName.Length; + Log.EngineLogger.Assert(engineBufferNameLength < int16.MaxValue); + + Try!(stream.Write((uint16)engineBufferNameLength)); + + if (engineBufferNameLength > 0) + Try!(stream.Write(bufferEntry.ConstantBuffer.EngineBufferName)); + + Log.EngineLogger.Assert(buffer.Variables.Count < int16.MaxValue); + + Try!(stream.Write((uint16)buffer.Variables.Count)); + + for (let (variableName, variable) in buffer.Variables) + { + Try!(stream.Write((uint64)variable.Offset)); + Try!(stream.Write((uint64)variable.SizeInBytes)); + Try!(stream.Write((uint8)(variable.IsUsed ? 1 : 0))); + Try!(stream.Write((uint8)(variable.ElementType))); + + Log.EngineLogger.Assert(variable.Rows < int8.MaxValue); + Log.EngineLogger.Assert(variable.Columns < int8.MaxValue); + + Try!(stream.Write((uint8)variable.Rows)); + Try!(stream.Write((uint8)variable.Columns)); + Try!(stream.Write((uint64)variable.ArraySize)); + + Log.EngineLogger.Assert(variableName.Length < int16.MaxValue); + + Try!(stream.Write((uint16)variableName.Length)); + Try!(stream.Write(variableName)); + } + + Try!(stream.Write(Span(buffer.RawData, 0, buffer.Size))); + } + + return .Ok; + } +} diff --git a/GlitchyEditor/src/Assets/Exporters/TextureExporter.bf b/GlitchyEditor/src/Assets/Exporters/TextureExporter.bf index d8941ca..643d486 100644 --- a/GlitchyEditor/src/Assets/Exporters/TextureExporter.bf +++ b/GlitchyEditor/src/Assets/Exporters/TextureExporter.bf @@ -26,7 +26,7 @@ class TextureExporter : IAssetExporter /* File Format: - TextureType (1 byte) + Texture Dimension (1 byte) Pixel Format (4 bytes) Width of larges mip-slice (4 bytes) Height of larges mip-slice (4 bytes) diff --git a/GlitchyEditor/src/Assets/Processors/ShaderCompiler.bf b/GlitchyEditor/src/Assets/Processors/ShaderCompiler.bf index dfc3371..34dfa78 100644 --- a/GlitchyEditor/src/Assets/Processors/ShaderCompiler.bf +++ b/GlitchyEditor/src/Assets/Processors/ShaderCompiler.bf @@ -35,6 +35,11 @@ class CompiledShader private Dictionary _buffers = new .() ~ DeleteDictionaryAndValues!(_); private Dictionary _textures = new .() ~ DeleteDictionaryAndValues!(_); + public Dictionary ConstantBuffers => _buffers; + public Dictionary Textures => _textures; + + public extern Span Blob {get;} + public void AddConstantBuffer(ReflectedConstantBuffer buffer) { _buffers.Add(buffer.Name, buffer); @@ -49,17 +54,28 @@ class CompiledShader class ReflectedConstantBuffer { private String _name ~ delete _; + private String _engineBufferName ~ delete _; public int Size; + public int BindPoint; + public StringView Name { get => _name; set => String.NewOrSet!(_name, value); } + + public StringView EngineBufferName + { + get => _engineBufferName; + set => String.NewOrSet!(_engineBufferName, value); + } private Dictionary _variables = new .() ~ DeleteDictionaryAndValues!(_); + public Dictionary Variables => _variables; + public void AddVariable(ReflectedConstantBufferVariable vaiable) { _variables.Add(vaiable.Name, vaiable); @@ -115,6 +131,8 @@ class ReflectedConstantBufferVariable extension CompiledShader { internal ID3DBlob* _shaderBlob; + + public override Span Blob => Span((uint8*)_shaderBlob.GetBufferPointer(), (int)_shaderBlob.GetBufferSize()); } class ShaderCompiler @@ -226,6 +244,7 @@ extension ShaderCompiler switch(bindDesc.Type) { case .ConstantBuffer: + //var bufferReflection = reflection.GetConstantBufferByName(bindDesc.Name); var bufferReflection = reflection.GetConstantBufferByName(bindDesc.Name); bufferReflection.GetDescription(let bufferDesc); @@ -233,7 +252,7 @@ extension ShaderCompiler // ConstantBuffer if(bufferDesc.Type == .D3D11_CT_CBUFFER) { - ReflectedConstantBuffer cbuffer = Try!(ReflectConstantBuffer(bufferReflection)); + ReflectedConstantBuffer cbuffer = Try!(ReflectConstantBuffer(bindDesc, bufferReflection)); shader.AddConstantBuffer(cbuffer); } case .Texture: @@ -261,8 +280,7 @@ extension ShaderCompiler shader.AddTexture(new ReflectedTexture(StringView(bindDesc.Name), bindDesc.BindPoint, textureDimension)); case .Sampler: - // TODO: do we have to do something for samplers? - // i.e. can we get default values? + // There is nothing to do for samplers default: Log.EngineLogger.Warning($"Unhandled shader resource type: \"{bindDesc.Type}\""); } @@ -271,7 +289,7 @@ extension ShaderCompiler return .Ok; } - private static Result ReflectConstantBuffer(ID3D11ShaderReflectionConstantBuffer* bufferReflection) + private static Result ReflectConstantBuffer(ShaderInputBindDescription bindDesc, ID3D11ShaderReflectionConstantBuffer* bufferReflection) { Debug.Profiler.ProfileResourceFunction!(); @@ -284,6 +302,7 @@ extension ShaderCompiler buffer.Name = StringView(bufferDescription.Name); buffer.Size = bufferDescription.Size; + buffer.BindPoint = bindDesc.BindPoint; buffer.RawData = new uint8[buffer.Size]; for(uint32 v = 0; v < bufferDescription.Variables; v++) diff --git a/GlitchyEditor/src/Assets/Processors/ShaderProcessor.bf b/GlitchyEditor/src/Assets/Processors/ShaderProcessor.bf index ae015f5..39b8c76 100644 --- a/GlitchyEditor/src/Assets/Processors/ShaderProcessor.bf +++ b/GlitchyEditor/src/Assets/Processors/ShaderProcessor.bf @@ -10,15 +10,60 @@ namespace GlitchyEditor.Assets.Processors; class ProcessedShader : ProcessedResource { + public struct TextureEntry + { + public StringView Name; + public TextureDimension TextureDimension; + public int32 VertexShaderBindPoint; + public int32 PixelShaderBindPoint; + + public static readonly TextureEntry Default = .() { + Name = null, + TextureDimension = .Unknown, + VertexShaderBindPoint = -1, + PixelShaderBindPoint = -1 + }; + } + + public struct ConstantBufferEntry + { + public ReflectedConstantBuffer ConstantBuffer; + public int32 VertexShaderBindPoint; + public int32 PixelShaderBindPoint; + + public static readonly Self Default = .() { + ConstantBuffer = null, + VertexShaderBindPoint = -1, + PixelShaderBindPoint = -1, + }; + } + public override AssetType AssetType => .Shader; public CompiledShader VertexShader ~ delete _; public CompiledShader PixelShader ~ delete _; + Dictionary _constantBuffers = new .() ~ delete _; // Only delete container, Buffers come from shaders + + Dictionary _textures = new .() ~ delete _; + + public Dictionary ConstantBuffers => _constantBuffers; + public Dictionary Textures => _textures; + public this(AssetIdentifier ownAssetIdentifier, AssetHandle assetHandle) : base(ownAssetIdentifier, assetHandle) { } + + public void AddConstantBuffer(ConstantBufferEntry buffer) + { + _constantBuffers.Add(buffer.ConstantBuffer.Name, buffer); + } + + public void AddTextureEntry(TextureEntry textureEntry) + { + _textures.Add(textureEntry.Name, textureEntry); + } } class ShaderVariable @@ -72,23 +117,20 @@ class ShaderProcessor : IAssetProcessor String psName = scope String(); Dictionary variables = scope .(); - Dictionary engineBuffers = scope .(); + List bufferNames = scope .(); + // Name in Shader -> Name in Engine + Dictionary engineBuffers = scope .(); defer { ClearDictionaryAndDeleteValues!(variables); - - for (let (key, value) in engineBuffers) - { - delete key; - delete value; - } + ClearAndDeleteItems!(bufferNames); } String code = new String(importedShader.HlslCode); defer { delete code; } - Try!(ProcessFileContent(code, vsName, psName, variables, engineBuffers)); + Try!(ProcessFileContent(code, vsName, psName, variables, bufferNames, engineBuffers)); if (String.IsNullOrWhiteSpace(vsName) && String.IsNullOrWhiteSpace(psName)) { @@ -100,16 +142,108 @@ class ShaderProcessor : IAssetProcessor Try!(CompileAndReflect(vsName, psName, importedShader, code, processedShader)); - Try!(MergeResources(processedShader)); + Try!(MergeResources(processedShader, variables, engineBuffers)); outProcessedResources.Add(processedShader); return .Ok; } - private static Result MergeResources(ProcessedShader processedShader) + private static Result MergeResources(ProcessedShader processedShader, + Dictionary variables, + Dictionary engineBuffers) { + Try!(MergeConstantBuffers(processedShader, variables, engineBuffers)); + Try!(MergeTextures(processedShader)); + return .Ok; + } + + private static Result MergeConstantBuffers(ProcessedShader processedShader, + Dictionary variables, + Dictionary engineBuffers) + { + HashSet bufferNames = scope .(); + + void AddBufferNames(CompiledShader shader) + { + for (StringView name in shader.ConstantBuffers.Keys) + { + bufferNames.Add(name); + } + } + + AddBufferNames(processedShader.VertexShader); + AddBufferNames(processedShader.PixelShader); + + for (StringView bufferName in bufferNames) + { + Result vsBufferResult = processedShader.VertexShader.ConstantBuffers.GetValue(bufferName); + Result psBufferResult = processedShader.PixelShader.ConstantBuffers.GetValue(bufferName); + + ProcessedShader.ConstantBufferEntry constantBufferEntry = .Default; + + if (vsBufferResult case .Ok(let vsBuffer) && psBufferResult case .Ok(let psBuffer)) + { + // Choose larger buffer + constantBufferEntry.ConstantBuffer = (vsBuffer.Size >= psBuffer.Size) ? vsBuffer : psBuffer; + constantBufferEntry.VertexShaderBindPoint = (.)vsBuffer.BindPoint; + constantBufferEntry.PixelShaderBindPoint = (.)psBuffer.BindPoint; + } + else if (vsBufferResult case .Ok(let vsBuffer)) + { + constantBufferEntry.ConstantBuffer = vsBuffer; + constantBufferEntry.VertexShaderBindPoint = (.)vsBuffer.BindPoint; + } + else if (psBufferResult case .Ok(let psBuffer)) + { + constantBufferEntry.ConstantBuffer = psBuffer; + constantBufferEntry.PixelShaderBindPoint = (.)psBuffer.BindPoint; + } + + Log.EngineLogger.Assert(constantBufferEntry.ConstantBuffer != null); + Log.EngineLogger.Assert(constantBufferEntry.VertexShaderBindPoint > -1 || constantBufferEntry.PixelShaderBindPoint > -1); + + if (engineBuffers.TryGetValue(constantBufferEntry.ConstantBuffer.Name, let engineBufferName)) + { + constantBufferEntry.ConstantBuffer.EngineBufferName = engineBufferName; + } + + processedShader.AddConstantBuffer(constantBufferEntry); + } + + return .Ok; + } + + static ref ProcessedShader.TextureEntry AddOrGetTextureEntry(ProcessedShader processedShader, ReflectedTexture reflectedTexture) + { + if (!processedShader.Textures.ContainsKey(reflectedTexture.Name)) + { + ProcessedShader.TextureEntry textureEntry = .Default; + textureEntry.Name = reflectedTexture.Name; + textureEntry.TextureDimension = reflectedTexture.TextureDimension; + + processedShader.Textures.Add(textureEntry.Name, textureEntry); + } + + ref ProcessedShader.TextureEntry entry = ref processedShader.Textures[reflectedTexture.Name]; + + return ref entry; + } + + private static Result MergeTextures(ProcessedShader processedShader) + { + for (let (textureName, reflectedTexture) in processedShader.VertexShader.Textures) + { + ref ProcessedShader.TextureEntry textureEntry = ref AddOrGetTextureEntry(processedShader, reflectedTexture); + textureEntry.VertexShaderBindPoint = (int32)reflectedTexture.BindPoint; + } + + for (let (textureName, reflectedTexture) in processedShader.PixelShader.Textures) + { + ref ProcessedShader.TextureEntry textureEntry = ref AddOrGetTextureEntry(processedShader, reflectedTexture); + textureEntry.PixelShaderBindPoint = (int32)reflectedTexture.BindPoint; + } return .Ok; } @@ -143,7 +277,9 @@ class ShaderProcessor : IAssetProcessor return ShaderCompiler.CompileAndReflectShader(code, importedShader.AssetIdentifier, vsName, "ps_5_0", .()); } - private static Result ProcessFileContent(String fileContent, String outVsName, String outPsName, Dictionary outVarDescs, Dictionary outEngineBuffers) + private static Result ProcessFileContent(String fileContent, String outVsName, String outPsName, + Dictionary outVarDescs, + List outBufferNames, Dictionary outEngineBuffers) { Debug.Profiler.ProfileResourceFunction!(); @@ -176,7 +312,7 @@ class ShaderProcessor : IAssetProcessor case "EditorVariable": Try!(ProcessEditorVariables(arguments, outVarDescs)); case "EngineBuffer": - Try!(ProcessEngineBuffer(arguments, outEngineBuffers)); + Try!(ProcessEngineBuffer(arguments, outBufferNames, outEngineBuffers)); default: continue; } @@ -273,7 +409,8 @@ class ShaderProcessor : IAssetProcessor return .Ok((startOfLine, endOfLine)); } - private static Result ProcessEngineBuffer(Dictionary arguments, Dictionary outEngineBuffers) + private static Result ProcessEngineBuffer(Dictionary arguments, + List outBufferNames, Dictionary outEngineBuffers) { String nameInEngine = null; String nameInShader = null; @@ -306,7 +443,9 @@ class ShaderProcessor : IAssetProcessor return .Err; } - outEngineBuffers.Add(nameInEngine, nameInShader); + outBufferNames.Add(nameInShader); + outBufferNames.Add(nameInEngine); + outEngineBuffers.Add(nameInShader, nameInEngine); return .Ok; } diff --git a/GlitchyEditor/src/EditorApp.bf b/GlitchyEditor/src/EditorApp.bf index ec9aa5e..26be3a2 100644 --- a/GlitchyEditor/src/EditorApp.bf +++ b/GlitchyEditor/src/EditorApp.bf @@ -45,7 +45,7 @@ namespace GlitchyEditor _contentManager.RegisterAssetImporter(); _contentManager.RegisterAssetProcessor(); - //_contentManager.RegisterAssetExporter(); + _contentManager.RegisterAssetExporter(); _contentManager.SetGlobalAssetCacheDirectory(".cache"); _contentManager.SetResourcesDirectory("Resources"); diff --git a/GlitchyEditor/src/EditorContentManager.bf b/GlitchyEditor/src/EditorContentManager.bf index a9d9e21..bf7504d 100644 --- a/GlitchyEditor/src/EditorContentManager.bf +++ b/GlitchyEditor/src/EditorContentManager.bf @@ -11,6 +11,7 @@ using System.Linq; using System.Threading.Tasks; using GlitchyEditor.Assets.Importers; using GlitchyEngine.Core; +using GlitchyEngine.Content.Loaders; using internal GlitchyEngine.Content.Asset; @@ -944,6 +945,7 @@ class EditorContentManager : IContentManager // TODO: obviously use a map or something... TextureLoader textureLoader = new .() ~ delete _; SpriteLoader spriteLoader = new .() ~ delete _; + ShaderLoader shaderLoader = new .() ~ delete _; private IProcessedAssetLoader GetLoader(AssetType assetType) { @@ -953,6 +955,8 @@ class EditorContentManager : IContentManager return textureLoader; case .Sprite: return spriteLoader; + case .Shader: + return shaderLoader; default: return null; } diff --git a/GlitchyEngine/src/Content/Loaders/ShaderLoader.bf b/GlitchyEngine/src/Content/Loaders/ShaderLoader.bf new file mode 100644 index 0000000..a12ec69 --- /dev/null +++ b/GlitchyEngine/src/Content/Loaders/ShaderLoader.bf @@ -0,0 +1,149 @@ +using System; +using System.Collections; +using System.IO; +using GlitchyEngine.Renderer; + +namespace GlitchyEngine.Content.Loaders; + +class ShaderLoader : IProcessedAssetLoader +{ + public Result Load(Stream stream) + { + uint64 vsDataSize = Try!(stream.Read()); + uint64 psDataSize = Try!(stream.Read()); + + VertexShader vertexShader = null; + PixelShader pixelShader = null; + + Effect effect = new Effect(); + + // Properly clean up in case of an error + defer + { + vertexShader?.ReleaseRef(); + pixelShader?.ReleaseRef(); + if (@return case .Err) + { + effect.ReleaseLastRef(); + } + } + + if (vsDataSize > 0) + { + uint8[] vsData = new:ScopedAlloc! uint8[vsDataSize]; + Try!(stream.TryRead(vsData)); + + vertexShader = (VertexShader)Try!(Shader.CreateFromBlob(vsData, .Vertex)); + } + + if (psDataSize > 0) + { + uint8[] psData = new:ScopedAlloc! uint8[psDataSize]; + Try!(stream.TryRead(psData)); + + pixelShader = (PixelShader)Try!(Shader.CreateFromBlob(psData, .Pixel)); + } + + uint16 textureCount = Try!(stream.Read()); + + for (int i < textureCount) + { + TextureDimension dimension = Try!(stream.Read()); + int32 vertexShaderBindPoint = Try!(stream.Read()); + int32 pixelShaderBindPoint = Try!(stream.Read()); + + int16 textureNameLength = Try!(stream.Read()); + String textureName = new String(textureNameLength); + stream.ReadStrSized32(textureNameLength, textureName); + + Effect.TextureEntry entry = .(TextureViewBinding.CreateDefault(), dimension, null, null); + + if (vertexShaderBindPoint != -1 && vertexShader != null) + { + vertexShader.Textures.Add(textureName, (.)vertexShaderBindPoint, entry.BoundTexture, dimension); + entry.VsSlot = vertexShader.Textures[textureName]; + } + + if (pixelShaderBindPoint != -1) + { + pixelShader?.Textures.Add(textureName, (.)pixelShaderBindPoint, entry.BoundTexture, dimension); + entry.PsSlot = pixelShader.Textures[textureName]; + } + + effect.Textures[textureName] = entry; + } + + uint16 bufferCount = Try!(stream.Read()); + + for (int i < bufferCount) + { + int64 bufferSize = Try!(stream.Read()); + + int32 vertexShaderBindPoint = Try!(stream.Read()); + int32 pixelShaderBindPoint = Try!(stream.Read()); + + int16 bufferNameLength = Try!(stream.Read()); + String bufferName = scope String(bufferNameLength); + stream.ReadStrSized32(bufferNameLength, bufferName); + + int16 engineBufferNameLength = Try!(stream.Read()); + String engineBufferName = null; + + if (engineBufferNameLength > 0) + { + scope String(engineBufferNameLength); + stream.ReadStrSized32(engineBufferNameLength, engineBufferName); + + // TODO: Engine buffers currently do nothing. The bind points for each engine buffer are hardcoded. + // It only marks the buffer as engine buffer, preventing the variables from becomming accessible. + //effect.[Friend]_engineBuffers.Add() + } + + uint16 variableCount = Try!(stream.Read()); + + ConstantBuffer buffer = new ConstantBuffer(bufferName, bufferSize); + defer buffer.ReleaseRef(); + + for (int v < variableCount) + { + uint64 variableOffset = Try!(stream.Read()); + uint64 sizeInBytes = Try!(stream.Read()); + bool isUsed = Try!(stream.Read()) > 0; + ShaderVariableType type = Try!(stream.Read()); + uint8 rows = Try!(stream.Read()); + uint8 columns = Try!(stream.Read()); + uint64 arraySize = Try!(stream.Read()); + + int16 variableNameLength = Try!(stream.Read()); + String variableName = scope String(variableNameLength); + stream.ReadStrSized32(variableNameLength, variableName); + + if (engineBufferName == null) + buffer.AddVariable(variableName, variableOffset, sizeInBytes, isUsed, type, rows, columns, arraySize); + } + + Try!(stream.TryRead(buffer.RawData)); + Try!(buffer.Update()); + + if (vertexShaderBindPoint != -1) + vertexShader.Buffers.Add(vertexShaderBindPoint, buffer.Name, buffer); + + if (pixelShaderBindPoint != -1) + pixelShader.Buffers.Add(pixelShaderBindPoint, buffer.Name, buffer); + + // TODO: Allow binding buffers to different indices? Does this theoretically work with textures? + let tempBindPoint = (vertexShaderBindPoint != -1) ? vertexShaderBindPoint : pixelShaderBindPoint; + effect.Buffers.Add(tempBindPoint, buffer.Name, buffer); + + for (var variable in buffer.Variables) + { + effect.Variables.Add(variable); + } + } + + effect.[Friend]VertexShader = vertexShader; + effect.[Friend]PixelShader = pixelShader; + + return effect; + } +} diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Shader.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Shader.bf index 1acf6d8..f3a6455 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Shader.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11Shader.bf @@ -11,6 +11,18 @@ using GlitchyEngine.Content; using System.Collections; using internal GlitchyEngine.Renderer; +using internal GlitchyEngine.Platform.DX11; + +using System; +using GlitchyEngine.Renderer; +using DirectX.D3D11; +using DirectX.D3DCompiler; +using GlitchyEngine.Platform.DX11; +using GlitchyEngine.Content; +using DirectX.Common; + +using internal GlitchyEngine.Renderer; +using internal GlitchyEngine.Platform.DX11; namespace GlitchyEngine.Renderer { @@ -115,6 +127,40 @@ namespace GlitchyEngine.Renderer */ internal ID3DBlob* nativeCode ~ _?.Release(); + protected override Result InternalCreateFromBlob(Span blob) + { + HResult shaderCreationResult = HResult.S_FALSE; + + // TODO Temporary, because we need to generate the vertex layout from it! + D3DCompiler.D3DCreateBlob((.)blob.Length, &nativeCode); + Internal.MemCpy(nativeCode.GetBufferPointer(), blob.Ptr, blob.Length); + + switch (_shaderType) + { + case .Vertex: + shaderCreationResult = NativeDevice.CreateVertexShader(blob.Ptr, (uint)blob.Length, null, (ID3D11VertexShader**)&nativeShader); + case .Pixel: + shaderCreationResult = NativeDevice.CreatePixelShader(blob.Ptr, (uint)blob.Length, null, (ID3D11PixelShader**)&nativeShader); + default: + Log.EngineLogger.Error($"Can't create native shader of type {_shaderType}."); + return .Err; + } + + if(shaderCreationResult.Failed) + { + Log.EngineLogger.Error($"Failed to create native shader from blob: {shaderCreationResult} ({(int)shaderCreationResult})"); + + if (nativeShader != null) + { + nativeShader.Release(); + } + + return .Err; + } + + return .Ok; + } + protected const ShaderCompileFlags DefaultCompileFlags = .EnableStrictness | #if DEBUG .Debug; diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11TextureViewBinding.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11TextureViewBinding.bf index 409783e..99b738e 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11TextureViewBinding.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11TextureViewBinding.bf @@ -29,5 +29,7 @@ namespace GlitchyEngine.Renderer _nativeShaderResourceView?.Release(); _nativeSamplerState?.Release(); } + + public static override TextureViewBinding CreateDefault() => .(null, null); } } diff --git a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11VertexLayout.bf b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11VertexLayout.bf index 4bcd3df..31b6aad 100644 --- a/GlitchyEngine/src/Platform/DX11/Renderer/Dx11VertexLayout.bf +++ b/GlitchyEngine/src/Platform/DX11/Renderer/Dx11VertexLayout.bf @@ -36,6 +36,7 @@ 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); } + /// This should happen during shader compilation! /// Validates or gets the validated input layout for the given vertexshader. internal ID3D11InputLayout* GetNativeVertexLayout(ID3DBlob* vertexShaderCode) { diff --git a/GlitchyEngine/src/Renderer/BufferVariable.bf b/GlitchyEngine/src/Renderer/BufferVariable.bf index 705bdd2..007393d 100644 --- a/GlitchyEngine/src/Renderer/BufferVariable.bf +++ b/GlitchyEngine/src/Renderer/BufferVariable.bf @@ -38,8 +38,9 @@ namespace GlitchyEngine.Renderer [Inline] internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset; - public this(ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 elements, bool isUsed) + public this(StringView name, ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 elements, bool isUsed) { + _name = new String(name); _constantBuffer = constantBuffer..AddRef(); _type = type; _columns = columns; diff --git a/GlitchyEngine/src/Renderer/ConstantBuffer.bf b/GlitchyEngine/src/Renderer/ConstantBuffer.bf index 9efa9a1..07a0f99 100644 --- a/GlitchyEngine/src/Renderer/ConstantBuffer.bf +++ b/GlitchyEngine/src/Renderer/ConstantBuffer.bf @@ -74,13 +74,28 @@ namespace GlitchyEngine.Renderer public BufferVariableCollection Variables => _variables; + /// Gets a span to the rawData held on the CPU. + public Span RawData => rawData; + protected this() {} + public this(StringView name, int64 size) + { + _name = new String(name); + rawData = new uint8[size]; + ConstructBuffer(); + } + protected internal void AddVariable(BufferVariable ownVariable) { _variables.Add(ownVariable); } + public void AddVariable(StringView name, uint64 offset, uint64 sizeInBytes, bool isUsed, ShaderVariableType type, uint8 rows, uint8 columns, uint64 arraySize) + { + _variables.Add(new BufferVariable(name, this, type, columns, rows, (uint32)offset, (uint32)sizeInBytes, (uint32)arraySize, isUsed)); + } + /** * Construct the buffer description. */ @@ -96,9 +111,9 @@ namespace GlitchyEngine.Renderer /** * Uploads the date to the GPU. */ - public void Update() + public Result Update() { - PlatformSetData(rawData.CArray(), (uint32)rawData.Count, 0, .WriteDiscard); + return PlatformSetData(rawData.CArray(), (uint32)rawData.Count, 0, .WriteDiscard); } } diff --git a/GlitchyEngine/src/Renderer/Effect.bf b/GlitchyEngine/src/Renderer/Effect.bf index 03fdf1e..1fcce8b 100644 --- a/GlitchyEngine/src/Renderer/Effect.bf +++ b/GlitchyEngine/src/Renderer/Effect.bf @@ -65,7 +65,7 @@ public class Effect : Asset } } - Dictionary _textures ~ delete _; + Dictionary _textures ~ DeleteDictionaryAndKeys!(_); public Dictionary Textures => _textures; @@ -99,7 +99,8 @@ public class Effect : Asset MergeResources(); } - + + [Obsolete("", false)] public this(Stream data, StringView assetIdentifier, IContentManager contentManager) { Debug.Profiler.ProfileResourceFunction!(); @@ -115,6 +116,13 @@ public class Effect : Asset MergeResources(); } + public this() + { + _bufferCollection = new BufferCollection(); + _variables = new BufferVariableCollection(false); + _textures = new Dictionary(); + } + public ~this() { Debug.Profiler.ProfileResourceFunction!(); @@ -668,7 +676,7 @@ public class Effect : Asset } // save entry - _textures[shaderEntry.Name] = entry; + _textures[new String(shaderEntry.Name)] = entry; } } } diff --git a/GlitchyEngine/src/Renderer/PixelShader.bf b/GlitchyEngine/src/Renderer/PixelShader.bf index 7d222b5..ba66a49 100644 --- a/GlitchyEngine/src/Renderer/PixelShader.bf +++ b/GlitchyEngine/src/Renderer/PixelShader.bf @@ -8,5 +8,7 @@ namespace GlitchyEngine.Renderer [AllowAppend] public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null) : base(code, fileName, entryPoint, contentManager, macros) { } + + public this() : base() { } } } diff --git a/GlitchyEngine/src/Renderer/Shader.bf b/GlitchyEngine/src/Renderer/Shader.bf index 1d33a07..4c40edd 100644 --- a/GlitchyEngine/src/Renderer/Shader.bf +++ b/GlitchyEngine/src/Renderer/Shader.bf @@ -20,16 +20,29 @@ namespace GlitchyEngine.Renderer } } - public abstract class Shader : RefCounter + public enum ShaderType + { + Unknown, + Vertex, + Pixel + } + + // TODO: We may not even need the distinction between shader types anymore (maybe just as an enum) + public abstract class + Shader : RefCounter { protected internal BufferCollection _buffers ~ _.ReleaseRef();//:append _; protected ShaderTextureCollection _textures ~ delete _; - + + protected ShaderType _shaderType; + public BufferCollection Buffers => _buffers; public ShaderTextureCollection Textures => _textures; + public ShaderType ShaderType => _shaderType; + [AllowAppend] public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null) { @@ -43,24 +56,49 @@ namespace GlitchyEngine.Renderer CompileFromSource(code, fileName, entryPoint, contentManager); } + public this() + { + _buffers = new BufferCollection(); + _textures = new ShaderTextureCollection(); + } + + public static Result CreateFromBlob(Span shaderBlob, ShaderType shaderType) + { + Shader shader = null; + + defer + { + if (@return case .Err) + { + shader?.ReleaseRef(); + } + } + + switch (shaderType) + { + case .Vertex: + shader = new VertexShader(); + case .Pixel: + shader = new PixelShader(); + default: + Log.EngineLogger.Error($"Can't create shader of type {shaderType}"); + return .Err; + } + + shader._shaderType = shaderType; + + Try!(shader.InternalCreateFromBlob(shaderBlob)); + + return shader; + } + public ~this() { Debug.Profiler.ProfileResourceFunction!(); } - /*public static mixin FromFile(String fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null) where T : Shader - { - Debug.Profiler.ProfileResourceFunction!(); - - String fileContent = new String(); - File.ReadAllText(fileName, fileContent, true); - T shader = new T(fileContent, (StringView)fileName, contentManager, entryPoint, macros); - - delete fileContent; - - shader - }*/ - public abstract void CompileFromSource(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null); + + protected abstract Result InternalCreateFromBlob(Span blob); } } diff --git a/GlitchyEngine/src/Renderer/ShaderTextureCollection.bf b/GlitchyEngine/src/Renderer/ShaderTextureCollection.bf index ccdfc46..2587af8 100644 --- a/GlitchyEngine/src/Renderer/ShaderTextureCollection.bf +++ b/GlitchyEngine/src/Renderer/ShaderTextureCollection.bf @@ -38,6 +38,8 @@ namespace GlitchyEngine.Renderer } // TODO: finish implementation (like BufferCollection) + public ResourceEntry* this[int idx] => _idxToBuf[idx]; + public ResourceEntry* this[String name] => _strToBuf[name]; public void Add(String name, uint32 index, TextureViewBinding texture, TextureDimension dimension) { diff --git a/GlitchyEngine/src/Renderer/TextureViewBinding.bf b/GlitchyEngine/src/Renderer/TextureViewBinding.bf index 9aa24fc..ff67b25 100644 --- a/GlitchyEngine/src/Renderer/TextureViewBinding.bf +++ b/GlitchyEngine/src/Renderer/TextureViewBinding.bf @@ -2,6 +2,7 @@ using System; namespace GlitchyEngine.Renderer { + // TODO: I hate this. It is a reference counting struct?! /// Represents a reference to a texture that can be used as shader input resource. public struct TextureViewBinding : IRefCounted, IDisposable { @@ -11,6 +12,8 @@ namespace GlitchyEngine.Renderer public extern void AddRef(); public extern void Release(); + public static extern TextureViewBinding CreateDefault(); + public void Dispose() => Release(); } } diff --git a/GlitchyEngine/src/Renderer/VertexShader.bf b/GlitchyEngine/src/Renderer/VertexShader.bf index 68fbc60..c128842 100644 --- a/GlitchyEngine/src/Renderer/VertexShader.bf +++ b/GlitchyEngine/src/Renderer/VertexShader.bf @@ -8,5 +8,7 @@ namespace GlitchyEngine.Renderer [AllowAppend] public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager = null, ShaderDefine[] macros = null) : base(code, fileName, entryPoint, contentManager, macros) { } + + public this() : base() { } } }