First working effects with new pipeline

This commit is contained in:
Simon Lübeß
2024-08-22 00:34:20 +02:00
parent 7b7a3dc645
commit 66e62f42ec
20 changed files with 652 additions and 43 deletions
@@ -1,5 +1,13 @@
{ {
AssetLoader = "EffectAssetLoader", AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}/* No reflection data for GlitchyEditor.Assets.EffectAssetLoaderConfig. Add [BonTarget] or force it */, 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
} }
@@ -1,5 +1,13 @@
{ {
AssetLoader = "EffectAssetLoader", AssetLoader = "EffectAssetLoader",
Config = (GlitchyEditor.Assets.EffectAssetLoaderConfig){}/* No reflection data for GlitchyEditor.Assets.EffectAssetLoaderConfig. Add [BonTarget] or force it */, 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
} }
@@ -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<void> 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<uint8> vsData = shader.VertexShader?.Blob ?? Span<uint8>();
Span<uint8> psData = shader.PixelShader?.Blob ?? Span<uint8>();
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<void> 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<void> 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<uint8>(buffer.RawData, 0, buffer.Size)));
}
return .Ok;
}
}
@@ -26,7 +26,7 @@ class TextureExporter : IAssetExporter
/* /*
File Format: File Format:
TextureType (1 byte) Texture Dimension (1 byte)
Pixel Format (4 bytes) Pixel Format (4 bytes)
Width of larges mip-slice (4 bytes) Width of larges mip-slice (4 bytes)
Height of larges mip-slice (4 bytes) Height of larges mip-slice (4 bytes)
@@ -35,6 +35,11 @@ class CompiledShader
private Dictionary<StringView, ReflectedConstantBuffer> _buffers = new .() ~ DeleteDictionaryAndValues!(_); private Dictionary<StringView, ReflectedConstantBuffer> _buffers = new .() ~ DeleteDictionaryAndValues!(_);
private Dictionary<StringView, ReflectedTexture> _textures = new .() ~ DeleteDictionaryAndValues!(_); private Dictionary<StringView, ReflectedTexture> _textures = new .() ~ DeleteDictionaryAndValues!(_);
public Dictionary<StringView, ReflectedConstantBuffer> ConstantBuffers => _buffers;
public Dictionary<StringView, ReflectedTexture> Textures => _textures;
public extern Span<uint8> Blob {get;}
public void AddConstantBuffer(ReflectedConstantBuffer buffer) public void AddConstantBuffer(ReflectedConstantBuffer buffer)
{ {
_buffers.Add(buffer.Name, buffer); _buffers.Add(buffer.Name, buffer);
@@ -49,17 +54,28 @@ class CompiledShader
class ReflectedConstantBuffer class ReflectedConstantBuffer
{ {
private String _name ~ delete _; private String _name ~ delete _;
private String _engineBufferName ~ delete _;
public int Size; public int Size;
public int BindPoint;
public StringView Name public StringView Name
{ {
get => _name; get => _name;
set => String.NewOrSet!(_name, value); set => String.NewOrSet!(_name, value);
} }
public StringView EngineBufferName
{
get => _engineBufferName;
set => String.NewOrSet!(_engineBufferName, value);
}
private Dictionary<StringView, ReflectedConstantBufferVariable> _variables = new .() ~ DeleteDictionaryAndValues!(_); private Dictionary<StringView, ReflectedConstantBufferVariable> _variables = new .() ~ DeleteDictionaryAndValues!(_);
public Dictionary<StringView, ReflectedConstantBufferVariable> Variables => _variables;
public void AddVariable(ReflectedConstantBufferVariable vaiable) public void AddVariable(ReflectedConstantBufferVariable vaiable)
{ {
_variables.Add(vaiable.Name, vaiable); _variables.Add(vaiable.Name, vaiable);
@@ -115,6 +131,8 @@ class ReflectedConstantBufferVariable
extension CompiledShader extension CompiledShader
{ {
internal ID3DBlob* _shaderBlob; internal ID3DBlob* _shaderBlob;
public override Span<uint8> Blob => Span<uint8>((uint8*)_shaderBlob.GetBufferPointer(), (int)_shaderBlob.GetBufferSize());
} }
class ShaderCompiler class ShaderCompiler
@@ -226,6 +244,7 @@ extension ShaderCompiler
switch(bindDesc.Type) switch(bindDesc.Type)
{ {
case .ConstantBuffer: case .ConstantBuffer:
//var bufferReflection = reflection.GetConstantBufferByName(bindDesc.Name);
var bufferReflection = reflection.GetConstantBufferByName(bindDesc.Name); var bufferReflection = reflection.GetConstantBufferByName(bindDesc.Name);
bufferReflection.GetDescription(let bufferDesc); bufferReflection.GetDescription(let bufferDesc);
@@ -233,7 +252,7 @@ extension ShaderCompiler
// ConstantBuffer // ConstantBuffer
if(bufferDesc.Type == .D3D11_CT_CBUFFER) if(bufferDesc.Type == .D3D11_CT_CBUFFER)
{ {
ReflectedConstantBuffer cbuffer = Try!(ReflectConstantBuffer(bufferReflection)); ReflectedConstantBuffer cbuffer = Try!(ReflectConstantBuffer(bindDesc, bufferReflection));
shader.AddConstantBuffer(cbuffer); shader.AddConstantBuffer(cbuffer);
} }
case .Texture: case .Texture:
@@ -261,8 +280,7 @@ extension ShaderCompiler
shader.AddTexture(new ReflectedTexture(StringView(bindDesc.Name), bindDesc.BindPoint, textureDimension)); shader.AddTexture(new ReflectedTexture(StringView(bindDesc.Name), bindDesc.BindPoint, textureDimension));
case .Sampler: case .Sampler:
// TODO: do we have to do something for samplers? // There is nothing to do for samplers
// i.e. can we get default values?
default: default:
Log.EngineLogger.Warning($"Unhandled shader resource type: \"{bindDesc.Type}\""); Log.EngineLogger.Warning($"Unhandled shader resource type: \"{bindDesc.Type}\"");
} }
@@ -271,7 +289,7 @@ extension ShaderCompiler
return .Ok; return .Ok;
} }
private static Result<ReflectedConstantBuffer> ReflectConstantBuffer(ID3D11ShaderReflectionConstantBuffer* bufferReflection) private static Result<ReflectedConstantBuffer> ReflectConstantBuffer(ShaderInputBindDescription bindDesc, ID3D11ShaderReflectionConstantBuffer* bufferReflection)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -284,6 +302,7 @@ extension ShaderCompiler
buffer.Name = StringView(bufferDescription.Name); buffer.Name = StringView(bufferDescription.Name);
buffer.Size = bufferDescription.Size; buffer.Size = bufferDescription.Size;
buffer.BindPoint = bindDesc.BindPoint;
buffer.RawData = new uint8[buffer.Size]; buffer.RawData = new uint8[buffer.Size];
for(uint32 v = 0; v < bufferDescription.Variables; v++) for(uint32 v = 0; v < bufferDescription.Variables; v++)
@@ -10,15 +10,60 @@ namespace GlitchyEditor.Assets.Processors;
class ProcessedShader : ProcessedResource 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 override AssetType AssetType => .Shader;
public CompiledShader VertexShader ~ delete _; public CompiledShader VertexShader ~ delete _;
public CompiledShader PixelShader ~ delete _; public CompiledShader PixelShader ~ delete _;
Dictionary<StringView, ConstantBufferEntry> _constantBuffers = new .() ~ delete _; // Only delete container, Buffers come from shaders
Dictionary<StringView, TextureEntry> _textures = new .() ~ delete _;
public Dictionary<StringView, ConstantBufferEntry> ConstantBuffers => _constantBuffers;
public Dictionary<StringView, TextureEntry> Textures => _textures;
public this(AssetIdentifier ownAssetIdentifier, AssetHandle assetHandle) : base(ownAssetIdentifier, assetHandle) 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 class ShaderVariable
@@ -72,23 +117,20 @@ class ShaderProcessor : IAssetProcessor
String psName = scope String(); String psName = scope String();
Dictionary<StringView, ShaderVariable> variables = scope .(); Dictionary<StringView, ShaderVariable> variables = scope .();
Dictionary<String, String> engineBuffers = scope .(); List<String> bufferNames = scope .();
// Name in Shader -> Name in Engine
Dictionary<StringView, StringView> engineBuffers = scope .();
defer defer
{ {
ClearDictionaryAndDeleteValues!(variables); ClearDictionaryAndDeleteValues!(variables);
ClearAndDeleteItems!(bufferNames);
for (let (key, value) in engineBuffers)
{
delete key;
delete value;
}
} }
String code = new String(importedShader.HlslCode); String code = new String(importedShader.HlslCode);
defer { delete code; } 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)) if (String.IsNullOrWhiteSpace(vsName) && String.IsNullOrWhiteSpace(psName))
{ {
@@ -100,16 +142,108 @@ class ShaderProcessor : IAssetProcessor
Try!(CompileAndReflect(vsName, psName, importedShader, code, processedShader)); Try!(CompileAndReflect(vsName, psName, importedShader, code, processedShader));
Try!(MergeResources(processedShader)); Try!(MergeResources(processedShader, variables, engineBuffers));
outProcessedResources.Add(processedShader); outProcessedResources.Add(processedShader);
return .Ok; return .Ok;
} }
private static Result<void> MergeResources(ProcessedShader processedShader) private static Result<void> MergeResources(ProcessedShader processedShader,
Dictionary<StringView, ShaderVariable> variables,
Dictionary<StringView, StringView> engineBuffers)
{ {
Try!(MergeConstantBuffers(processedShader, variables, engineBuffers));
Try!(MergeTextures(processedShader));
return .Ok;
}
private static Result<void> MergeConstantBuffers(ProcessedShader processedShader,
Dictionary<StringView, ShaderVariable> variables,
Dictionary<StringView, StringView> engineBuffers)
{
HashSet<StringView> 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<ReflectedConstantBuffer> vsBufferResult = processedShader.VertexShader.ConstantBuffers.GetValue(bufferName);
Result<ReflectedConstantBuffer> 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<void> 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; return .Ok;
} }
@@ -143,7 +277,9 @@ class ShaderProcessor : IAssetProcessor
return ShaderCompiler.CompileAndReflectShader(code, importedShader.AssetIdentifier, vsName, "ps_5_0", .()); return ShaderCompiler.CompileAndReflectShader(code, importedShader.AssetIdentifier, vsName, "ps_5_0", .());
} }
private static Result<void> ProcessFileContent(String fileContent, String outVsName, String outPsName, Dictionary<StringView, ShaderVariable> outVarDescs, Dictionary<String, String> outEngineBuffers) private static Result<void> ProcessFileContent(String fileContent, String outVsName, String outPsName,
Dictionary<StringView, ShaderVariable> outVarDescs,
List<String> outBufferNames, Dictionary<StringView, StringView> outEngineBuffers)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -176,7 +312,7 @@ class ShaderProcessor : IAssetProcessor
case "EditorVariable": case "EditorVariable":
Try!(ProcessEditorVariables(arguments, outVarDescs)); Try!(ProcessEditorVariables(arguments, outVarDescs));
case "EngineBuffer": case "EngineBuffer":
Try!(ProcessEngineBuffer(arguments, outEngineBuffers)); Try!(ProcessEngineBuffer(arguments, outBufferNames, outEngineBuffers));
default: default:
continue; continue;
} }
@@ -273,7 +409,8 @@ class ShaderProcessor : IAssetProcessor
return .Ok((startOfLine, endOfLine)); return .Ok((startOfLine, endOfLine));
} }
private static Result<void> ProcessEngineBuffer(Dictionary<StringView, StringView> arguments, Dictionary<String, String> outEngineBuffers) private static Result<void> ProcessEngineBuffer(Dictionary<StringView, StringView> arguments,
List<String> outBufferNames, Dictionary<StringView, StringView> outEngineBuffers)
{ {
String nameInEngine = null; String nameInEngine = null;
String nameInShader = null; String nameInShader = null;
@@ -306,7 +443,9 @@ class ShaderProcessor : IAssetProcessor
return .Err; return .Err;
} }
outEngineBuffers.Add(nameInEngine, nameInShader); outBufferNames.Add(nameInShader);
outBufferNames.Add(nameInEngine);
outEngineBuffers.Add(nameInShader, nameInEngine);
return .Ok; return .Ok;
} }
+1 -1
View File
@@ -45,7 +45,7 @@ namespace GlitchyEditor
_contentManager.RegisterAssetImporter<ShaderImporter>(); _contentManager.RegisterAssetImporter<ShaderImporter>();
_contentManager.RegisterAssetProcessor<ShaderProcessor>(); _contentManager.RegisterAssetProcessor<ShaderProcessor>();
//_contentManager.RegisterAssetExporter<ShaderEx>(); _contentManager.RegisterAssetExporter<ShaderExporter>();
_contentManager.SetGlobalAssetCacheDirectory(".cache"); _contentManager.SetGlobalAssetCacheDirectory(".cache");
_contentManager.SetResourcesDirectory("Resources"); _contentManager.SetResourcesDirectory("Resources");
@@ -11,6 +11,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using GlitchyEditor.Assets.Importers; using GlitchyEditor.Assets.Importers;
using GlitchyEngine.Core; using GlitchyEngine.Core;
using GlitchyEngine.Content.Loaders;
using internal GlitchyEngine.Content.Asset; using internal GlitchyEngine.Content.Asset;
@@ -944,6 +945,7 @@ class EditorContentManager : IContentManager
// TODO: obviously use a map or something... // TODO: obviously use a map or something...
TextureLoader textureLoader = new .() ~ delete _; TextureLoader textureLoader = new .() ~ delete _;
SpriteLoader spriteLoader = new .() ~ delete _; SpriteLoader spriteLoader = new .() ~ delete _;
ShaderLoader shaderLoader = new .() ~ delete _;
private IProcessedAssetLoader GetLoader(AssetType assetType) private IProcessedAssetLoader GetLoader(AssetType assetType)
{ {
@@ -953,6 +955,8 @@ class EditorContentManager : IContentManager
return textureLoader; return textureLoader;
case .Sprite: case .Sprite:
return spriteLoader; return spriteLoader;
case .Shader:
return shaderLoader;
default: default:
return null; return null;
} }
@@ -0,0 +1,149 @@
using System;
using System.Collections;
using System.IO;
using GlitchyEngine.Renderer;
namespace GlitchyEngine.Content.Loaders;
class ShaderLoader : IProcessedAssetLoader
{
public Result<Asset> Load(Stream stream)
{
uint64 vsDataSize = Try!(stream.Read<uint64>());
uint64 psDataSize = Try!(stream.Read<uint64>());
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<uint16>());
for (int i < textureCount)
{
TextureDimension dimension = Try!(stream.Read<TextureDimension>());
int32 vertexShaderBindPoint = Try!(stream.Read<int32>());
int32 pixelShaderBindPoint = Try!(stream.Read<int32>());
int16 textureNameLength = Try!(stream.Read<int16>());
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<uint16>());
for (int i < bufferCount)
{
int64 bufferSize = Try!(stream.Read<int64>());
int32 vertexShaderBindPoint = Try!(stream.Read<int32>());
int32 pixelShaderBindPoint = Try!(stream.Read<int32>());
int16 bufferNameLength = Try!(stream.Read<int16>());
String bufferName = scope String(bufferNameLength);
stream.ReadStrSized32(bufferNameLength, bufferName);
int16 engineBufferNameLength = Try!(stream.Read<int16>());
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<uint16>());
ConstantBuffer buffer = new ConstantBuffer(bufferName, bufferSize);
defer buffer.ReleaseRef();
for (int v < variableCount)
{
uint64 variableOffset = Try!(stream.Read<uint64>());
uint64 sizeInBytes = Try!(stream.Read<uint64>());
bool isUsed = Try!(stream.Read<uint8>()) > 0;
ShaderVariableType type = Try!(stream.Read<ShaderVariableType>());
uint8 rows = Try!(stream.Read<uint8>());
uint8 columns = Try!(stream.Read<uint8>());
uint64 arraySize = Try!(stream.Read<uint64>());
int16 variableNameLength = Try!(stream.Read<int16>());
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;
}
}
@@ -11,6 +11,18 @@ using GlitchyEngine.Content;
using System.Collections; using System.Collections;
using internal GlitchyEngine.Renderer; 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 namespace GlitchyEngine.Renderer
{ {
@@ -115,6 +127,40 @@ namespace GlitchyEngine.Renderer
*/ */
internal ID3DBlob* nativeCode ~ _?.Release(); internal ID3DBlob* nativeCode ~ _?.Release();
protected override Result<void> InternalCreateFromBlob(Span<uint8> 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 | protected const ShaderCompileFlags DefaultCompileFlags = .EnableStrictness |
#if DEBUG #if DEBUG
.Debug; .Debug;
@@ -29,5 +29,7 @@ namespace GlitchyEngine.Renderer
_nativeShaderResourceView?.Release(); _nativeShaderResourceView?.Release();
_nativeSamplerState?.Release(); _nativeSamplerState?.Release();
} }
public static override TextureViewBinding CreateDefault() => .(null, null);
} }
} }
@@ -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); 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. /// Validates or gets the validated input layout for the given vertexshader.
internal ID3D11InputLayout* GetNativeVertexLayout(ID3DBlob* vertexShaderCode) internal ID3D11InputLayout* GetNativeVertexLayout(ID3DBlob* vertexShaderCode)
{ {
+2 -1
View File
@@ -38,8 +38,9 @@ namespace GlitchyEngine.Renderer
[Inline] [Inline]
internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset; 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(); _constantBuffer = constantBuffer..AddRef();
_type = type; _type = type;
_columns = columns; _columns = columns;
+17 -2
View File
@@ -74,13 +74,28 @@ namespace GlitchyEngine.Renderer
public BufferVariableCollection Variables => _variables; public BufferVariableCollection Variables => _variables;
/// Gets a span to the rawData held on the CPU.
public Span<uint8> RawData => rawData;
protected this() {} protected this() {}
public this(StringView name, int64 size)
{
_name = new String(name);
rawData = new uint8[size];
ConstructBuffer();
}
protected internal void AddVariable(BufferVariable ownVariable) protected internal void AddVariable(BufferVariable ownVariable)
{ {
_variables.Add(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. * Construct the buffer description.
*/ */
@@ -96,9 +111,9 @@ namespace GlitchyEngine.Renderer
/** /**
* Uploads the date to the GPU. * Uploads the date to the GPU.
*/ */
public void Update() public Result<void> Update()
{ {
PlatformSetData(rawData.CArray(), (uint32)rawData.Count, 0, .WriteDiscard); return PlatformSetData(rawData.CArray(), (uint32)rawData.Count, 0, .WriteDiscard);
} }
} }
+11 -3
View File
@@ -65,7 +65,7 @@ public class Effect : Asset
} }
} }
Dictionary<String, TextureEntry> _textures ~ delete _; Dictionary<String, TextureEntry> _textures ~ DeleteDictionaryAndKeys!(_);
public Dictionary<String, TextureEntry> Textures => _textures; public Dictionary<String, TextureEntry> Textures => _textures;
@@ -99,7 +99,8 @@ public class Effect : Asset
MergeResources(); MergeResources();
} }
[Obsolete("", false)]
public this(Stream data, StringView assetIdentifier, IContentManager contentManager) public this(Stream data, StringView assetIdentifier, IContentManager contentManager)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -115,6 +116,13 @@ public class Effect : Asset
MergeResources(); MergeResources();
} }
public this()
{
_bufferCollection = new BufferCollection();
_variables = new BufferVariableCollection(false);
_textures = new Dictionary<String, TextureEntry>();
}
public ~this() public ~this()
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -668,7 +676,7 @@ public class Effect : Asset
} }
// save entry // save entry
_textures[shaderEntry.Name] = entry; _textures[new String(shaderEntry.Name)] = entry;
} }
} }
} }
@@ -8,5 +8,7 @@ namespace GlitchyEngine.Renderer
[AllowAppend] [AllowAppend]
public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null) public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null)
: base(code, fileName, entryPoint, contentManager, macros) { } : base(code, fileName, entryPoint, contentManager, macros) { }
public this() : base() { }
} }
} }
+53 -15
View File
@@ -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 internal BufferCollection _buffers ~ _.ReleaseRef();//:append _;
protected ShaderTextureCollection _textures ~ delete _; protected ShaderTextureCollection _textures ~ delete _;
protected ShaderType _shaderType;
public BufferCollection Buffers => _buffers; public BufferCollection Buffers => _buffers;
public ShaderTextureCollection Textures => _textures; public ShaderTextureCollection Textures => _textures;
public ShaderType ShaderType => _shaderType;
[AllowAppend] [AllowAppend]
public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null) 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); CompileFromSource(code, fileName, entryPoint, contentManager);
} }
public this()
{
_buffers = new BufferCollection();
_textures = new ShaderTextureCollection();
}
public static Result<Shader> CreateFromBlob(Span<uint8> 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() public ~this()
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
} }
/*public static mixin FromFile<T>(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); public abstract void CompileFromSource(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null);
protected abstract Result<void> InternalCreateFromBlob(Span<uint8> blob);
} }
} }
@@ -38,6 +38,8 @@ namespace GlitchyEngine.Renderer
} }
// TODO: finish implementation (like BufferCollection) // 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) public void Add(String name, uint32 index, TextureViewBinding texture, TextureDimension dimension)
{ {
@@ -2,6 +2,7 @@ using System;
namespace GlitchyEngine.Renderer 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. /// Represents a reference to a texture that can be used as shader input resource.
public struct TextureViewBinding : IRefCounted, IDisposable public struct TextureViewBinding : IRefCounted, IDisposable
{ {
@@ -11,6 +12,8 @@ namespace GlitchyEngine.Renderer
public extern void AddRef(); public extern void AddRef();
public extern void Release(); public extern void Release();
public static extern TextureViewBinding CreateDefault();
public void Dispose() => Release(); public void Dispose() => Release();
} }
} }
@@ -8,5 +8,7 @@ namespace GlitchyEngine.Renderer
[AllowAppend] [AllowAppend]
public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager = null, ShaderDefine[] macros = null) public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager = null, ShaderDefine[] macros = null)
: base(code, fileName, entryPoint, contentManager, macros) { } : base(code, fileName, entryPoint, contentManager, macros) { }
public this() : base() { }
} }
} }