Handle EngineBuffers, Preview Names and variable editor types for materials

This commit is contained in:
Simon Lübeß
2025-03-22 23:40:43 +01:00
parent 77a7a04637
commit 5e50d75eb9
13 changed files with 696 additions and 431 deletions
@@ -9,12 +9,14 @@ namespace GlitchyEditor.Assets.Editors;
class MaterialEditor class MaterialEditor
{ {
public static void ShowEditor(AssetFile assetFile) public static bool ShowEditor(AssetFile assetFile)
{ {
bool isDirty = false;
let material = assetFile.LoadedAsset as Material; let material = assetFile.LoadedAsset as Material;
if (material == null) if (material == null)
return; return isDirty;
ImGui.PropertyTableStartNewProperty("Base Material"); ImGui.PropertyTableStartNewProperty("Base Material");
@@ -30,8 +32,15 @@ class MaterialEditor
ImGui.PropertyTableStartNewRow(); ImGui.PropertyTableStartNewRow();
if (ImGui.CollapsingHeader("Parameters", .DefaultOpen | .AllowOverlap | .Framed | .SpanFullWidth | .SpanAllColumns)) if (ImGui.CollapsingHeader("Parameters", .DefaultOpen | .AllowOverlap | .Framed | .SpanFullWidth | .SpanAllColumns))
{ {
String prettyVariableName = scope .();
for (let (variableName, bufferVariable) in material.Variables) for (let (variableName, bufferVariable) in material.Variables)
{ {
// Don't show engine buffer variables
if (!bufferVariable.ConstantBuffer.EngineBufferName.IsEmpty)
{
continue;
}
ImGui.PushID(variableName); ImGui.PushID(variableName);
ImGui.PropertyTableStartNewRow(); ImGui.PropertyTableStartNewRow();
@@ -47,47 +56,90 @@ class MaterialEditor
ImGui.SameLine(); ImGui.SameLine();
StringView displayName = variableName; StringView displayName = bufferVariable.PreviewName;
if (displayName.IsEmpty)
{
ToPrettyName(variableName, prettyVariableName);
displayName = prettyVariableName;
}
ImGui.PropertyTableName(displayName); ImGui.PropertyTableName(displayName);
// TODO: Somehow pass display name and type from imported shader to here! // TODO: Somehow pass display name and type from imported shader to here!
switch (bufferVariable.ElementType) bool handled = false;
switch (bufferVariable.EditorTypeName)
{ {
case .Float: case "Color", "ColorHDR":
// TODO: min and max values specified in shader if (bufferVariable.ElementType != .Float || bufferVariable.Rows != 1 ||
// TODO: support drag and enter number (specified in shader) bufferVariable.Columns < 3)
//for (int r < bufferVariable.Rows)
if (bufferVariable.Rows == 1)
{ {
switch (bufferVariable.Columns) break;
}
ImGui.ColorEditFlags flags = .None;
if (_ == "ColorHDR")
{
flags |= .HDR | .Float;
}
if (bufferVariable.Columns == 3)
{
material.GetVariable<float3>(bufferVariable.Name, var value);
if (ImGui.ColorEdit3("", ref *(float[3]*)&value, flags))
material.SetVariable(bufferVariable.Name, value);
}
else if (bufferVariable.Columns == 4)
{
material.GetVariable<float4>(bufferVariable.Name, var value);
if (ImGui.ColorEdit4("", ref *(float[4]*)&value, flags))
material.SetVariable(bufferVariable.Name, value);
}
handled = true;
}
if (!handled)
{
switch (bufferVariable.ElementType)
{
case .Float:
// TODO: min and max values specified in shader
// TODO: support drag and enter number (specified in shader)
//for (int r < bufferVariable.Rows)
if (bufferVariable.Rows == 1)
{ {
case 1: switch (bufferVariable.Columns)
material.GetVariable<float>(bufferVariable.Name, var value); {
case 1:
//float[1] minV = hasMin ? min.Get<float[1]>() : .(float.MinValue); material.GetVariable<float>(bufferVariable.Name, var value);
//float[1] maxV = hasMax ? max.Get<float[1]>() : .(float.MaxValue);
//float[1] minV = hasMin ? min.Get<float[1]>() : .(float.MinValue);
if (ImGui.VectorEditor<1>("", ref *(float[1]*)&value, .(), 0.1f /*, minV, maxV*/)) //float[1] maxV = hasMax ? max.Get<float[1]>() : .(float.MaxValue);
material.SetVariable(bufferVariable.Name, value);
case 2: if (ImGui.VectorEditor<1>("", ref *(float[1]*)&value, .(), 0.1f /*, minV, maxV*/))
material.GetVariable<float2>(bufferVariable.Name, var value); material.SetVariable(bufferVariable.Name, value);
if (ImGui.Float2Editor("", ref value, .Zero, 0.1f, 100.0f)) case 2:
material.SetVariable(bufferVariable.Name, value); material.GetVariable<float2>(bufferVariable.Name, var value);
case 3: if (ImGui.Float2Editor("", ref value, .Zero, 0.1f, 100.0f))
material.GetVariable<float3>(bufferVariable.Name, var value); material.SetVariable(bufferVariable.Name, value);
if (ImGui.Float3Editor("", ref value, .Zero, 0.1f, 100.0f)) case 3:
material.SetVariable(bufferVariable.Name, value); material.GetVariable<float3>(bufferVariable.Name, var value);
case 4: if (ImGui.Float3Editor("", ref value, .Zero, 0.1f, 100.0f))
material.GetVariable<float4>(bufferVariable.Name, var value); material.SetVariable(bufferVariable.Name, value);
if (ImGui.Float4Editor("", ref value, .Zero, 0.1f, 100.0f)) case 4:
material.SetVariable(bufferVariable.Name, value); material.GetVariable<float4>(bufferVariable.Name, var value);
if (ImGui.Float4Editor("", ref value, .Zero, 0.1f, 100.0f))
material.SetVariable(bufferVariable.Name, value);
}
} }
default:
ImGui.TextUnformatted(scope $"Element Type {_} not supported");
} }
default:
ImGui.TextUnformatted(scope $"Element Type {_} not supported");
} }
ImGui.EndDisabled(); ImGui.EndDisabled();
@@ -99,6 +151,7 @@ class MaterialEditor
ImGui.PropertyTableStartNewRow(); ImGui.PropertyTableStartNewRow();
if (ImGui.CollapsingHeader("Textures", .DefaultOpen | .AllowOverlap | .Framed | .SpanFullWidth | .SpanAllColumns)) if (ImGui.CollapsingHeader("Textures", .DefaultOpen | .AllowOverlap | .Framed | .SpanFullWidth | .SpanAllColumns))
{ {
String prettyVariableName = scope .();
for (var (textureName, texture) in ref material.Textures) for (var (textureName, texture) in ref material.Textures)
{ {
ImGui.PushID(textureName); ImGui.PushID(textureName);
@@ -116,7 +169,17 @@ class MaterialEditor
ImGui.SameLine(); ImGui.SameLine();
ImGui.PropertyTableName(textureName); // TODO: Preview Name for textures
StringView displayName = "";//texture.PreviewName;
if (displayName.IsEmpty)
{
ToPrettyName(textureName, prettyVariableName);
displayName = prettyVariableName;
}
ImGui.PropertyTableName(displayName);
if (ComponentEditWindow.ShowAssetDropTarget<Texture>(ref texture.TextureHandle)) if (ComponentEditWindow.ShowAssetDropTarget<Texture>(ref texture.TextureHandle))
{ {
@@ -128,6 +191,8 @@ class MaterialEditor
ImGui.PopID(); ImGui.PopID();
} }
} }
return isDirty;
} }
private static bool DrawLockButton(bool isLocked) private static bool DrawLockButton(bool isLocked)
@@ -166,4 +231,70 @@ class MaterialEditor
return result; return result;
} }
/// <summary>
/// Converts a variable name to a pretty name as good as reasonably possible.
/// </summary>
/// <param name="uglyName">The name of a variable to prettify.</param>
/// <returns>The pretty string.</returns>
public static void ToPrettyName(StringView uglyName, String outPrettyName)
{
outPrettyName.PrepareBuffer(uglyName.Length);
outPrettyName.Clear();
bool wasUpper = false;
bool inWord = false;
bool inNumber = false;
for (char8 c in uglyName)
{
if (c.IsLetter)
{
if (inNumber)
{
outPrettyName.Append(' ');
inNumber = false;
}
bool newWord = !inWord;
if (c.IsUpper && !wasUpper)
{
newWord = true;
wasUpper = true;
if (inWord)
{
outPrettyName.Append(' ');
}
}
else if (c.IsLower)
{
wasUpper = false;
}
outPrettyName.Append(newWord ? c.ToUpper : c.ToLower);
inWord = true;
}
else if (c.IsDigit)
{
if (inWord)
{
outPrettyName.Append(' ');
inWord = false;
inNumber = true;
}
outPrettyName.Append(c);
}
else if (inWord || inNumber)
{
outPrettyName.Append(' ');
inWord = false;
inNumber = false;
wasUpper = false;
}
}
}
} }
@@ -23,8 +23,8 @@ class ShaderExporter : IAssetExporter
File Format: File Format:
Vertex Shader Blob Length (uint64 / 8 bytes) (0 if null) 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 Blob Length (uint64 / 8 bytes) (0 if null)
Vertex Shader Data...
Pixel Shader Data... Pixel Shader Data...
Texture Count (uint16) Texture Count (uint16)
Textures Textures
@@ -57,6 +57,11 @@ class ShaderExporter : IAssetExporter
ArraySize (uint64) ArraySize (uint64)
Name Length (uint16) Name Length (uint16)
Name Data... Name Data...
Preview Name Length (uint16)
Preview Name Data...
Type Editor Name Length (uint16)
Type Editor Name Data...
# TODO: Min and Max
} }
RawData... RawData...
} }
@@ -92,11 +97,7 @@ class ShaderExporter : IAssetExporter
Try!(stream.Write((uint8)textureEntry.TextureDimension)); Try!(stream.Write((uint8)textureEntry.TextureDimension));
Try!(stream.Write((int32)textureEntry.VertexShaderBindPoint)); Try!(stream.Write((int32)textureEntry.VertexShaderBindPoint));
Try!(stream.Write((int32)textureEntry.PixelShaderBindPoint)); Try!(stream.Write((int32)textureEntry.PixelShaderBindPoint));
WriteSizedString<uint16>(stream, textureName);
Log.EngineLogger.Assert(textureName.Length < int16.MaxValue);
Try!(stream.Write((int16)textureName.Length));
Try!(stream.Write(textureName));
} }
return .Ok; return .Ok;
@@ -117,18 +118,9 @@ class ShaderExporter : IAssetExporter
Try!(stream.Write((int32)bufferEntry.VertexShaderBindPoint)); Try!(stream.Write((int32)bufferEntry.VertexShaderBindPoint));
Try!(stream.Write((int32)bufferEntry.PixelShaderBindPoint)); Try!(stream.Write((int32)bufferEntry.PixelShaderBindPoint));
Log.EngineLogger.Assert(bufferName.Length < int16.MaxValue); WriteSizedString<uint16>(stream, bufferName);
Try!(stream.Write((uint16)bufferName.Length)); WriteSizedString<uint16>(stream, bufferEntry.ConstantBuffer.EngineBufferName);
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); Log.EngineLogger.Assert(buffer.Variables.Count < int16.MaxValue);
@@ -148,10 +140,9 @@ class ShaderExporter : IAssetExporter
Try!(stream.Write((uint8)variable.Columns)); Try!(stream.Write((uint8)variable.Columns));
Try!(stream.Write((uint64)variable.ArraySize)); Try!(stream.Write((uint64)variable.ArraySize));
Log.EngineLogger.Assert(variableName.Length < int16.MaxValue); WriteSizedString<uint16>(stream, variableName);
WriteSizedString<uint16>(stream, variable.PreviewName);
Try!(stream.Write((uint16)variableName.Length)); WriteSizedString<uint16>(stream, variable.EditorType);
Try!(stream.Write(variableName));
} }
Try!(stream.Write(Span<uint8>(buffer.RawData, 0, buffer.Size))); Try!(stream.Write(Span<uint8>(buffer.RawData, 0, buffer.Size)));
@@ -159,4 +150,20 @@ class ShaderExporter : IAssetExporter
return .Ok; return .Ok;
} }
private static Result<void> WriteSizedString<Tint>(Stream stream, StringView string)
where Tint : IInteger
where int : operator explicit Tint
where Tint : operator explicit int
where Tint : struct
{
Log.EngineLogger.Assert(string.Length < (int)typeof(Tint).MaxValue);
Try!(stream.Write((Tint)string.Length));
if (string.Length > 0)
Try!(stream.WriteStrUnsized(string));
return .Ok;
}
} }
+1 -1
View File
@@ -8,7 +8,7 @@ namespace GlitchyEditor.Assets.Importers;
abstract class Config abstract class Config
{ {
[BonIgnore] [BonIgnore]
protected bool _changed = true; protected bool _changed = false;
public bool Changed => _changed; public bool Changed => _changed;
@@ -0,0 +1,331 @@
using System;
using System.Collections;
using GlitchyEngine;
using GlitchyEngine.Math;
namespace GlitchyEditor.Assets.Processors;
static class ShaderCodePreprocessor
{
public static Result<void> ProcessFileContent(String fileContent, String outVsName, String outPsName,
Dictionary<StringView, ShaderVariable> outVarDescs,
List<String> outBufferNames, Dictionary<StringView, StringView> outEngineBuffers)
{
Debug.Profiler.ProfileResourceFunction!();
Dictionary<StringView, StringView> arguments = scope .();
int index = 0;
while (true)
{
if ((int Start, int End) value = GetNextPreprocessor(fileContent, index, let name, arguments..Clear()))
{
index = value.End;
switch(name)
{
case "Effect":
for (let (argName, argValue) in arguments)
{
switch(argName)
{
case "VS", "VertexShader":
outVsName.Append(argValue);
case "PS", "PixelShader":
outPsName.Append(argValue);
default:
Log.EngineLogger.Error($"Unknown parameter name \"{name}\".");
return .Err;
}
}
case "EditorVariable":
Try!(ProcessEditorVariables(arguments, outVarDescs));
case "EngineBuffer":
Try!(ProcessEngineBuffer(arguments, outBufferNames, outEngineBuffers));
default:
continue;
}
CommentLine(fileContent, value.Start);
}
else
{
break;
}
}
return .Ok;
}
private static void CommentLine(StringView code, int commentPosition)
{
code[commentPosition] = '/';
code[commentPosition + 1] = '/';
}
private static Result<(int Start, int End)> GetNextPreprocessor(StringView code, int startindex, out StringView name, Dictionary<StringView, StringView> arguments)
{
var startindex;
name = .();
int startOfLine = -1;
int startOfPragma = -1;
int endOfLine = startindex;
do
{
repeat
{
startindex = endOfLine;
startOfPragma = code.IndexOf("#pragma", startindex);
if (startOfPragma == -1)
return .Err;
endOfLine = code.IndexOf('\n', startOfPragma);
startOfLine = code[...startOfPragma].LastIndexOf('\n');
// If the line is commented out, look for the next
} while (startOfLine != -1 && code[startOfLine...startOfPragma].Contains("//"));
StringView line = (endOfLine != -1) ? code.Substring(startOfPragma, endOfLine - startOfPragma) : code.Substring(startOfPragma);
// cut off the #pragma
line = line.Substring(7);
int lBracketIndex = line.IndexOf('[');
if (lBracketIndex == -1)
{
name = line..Trim();
break;
}
name = line.Substring(0, lBracketIndex);
name.Trim();
int rBracketIndex = line.IndexOf(']');
if (rBracketIndex == -1)
{
Log.EngineLogger.Error($"Pragma is missing closing Bracket (\"{line}\")");
rBracketIndex = line.Length;
}
StringView argumentText = line.Substring(lBracketIndex + 1, rBracketIndex - lBracketIndex - 1);
for (StringView argument in argumentText.Split(';'))
{
int equalsIndex = argument.IndexOf('=');
StringView argumentName = .();
StringView argumentValue = .();
if (equalsIndex == -1)
{
argumentName = argument;
argumentName.Trim();
}
else
{
argumentName = argument.Substring(0, equalsIndex);
argumentName.Trim();
argumentValue = argument.Substring(equalsIndex + 1);
argumentValue.Trim();
}
if (arguments.ContainsKey(argumentName))
{
Log.EngineLogger.Error($"Arguments \"{argumentName}\" already exists.");
continue;
}
arguments.Add(argumentName, argumentValue);
}
}
return .Ok((startOfPragma, endOfLine));
}
private static Result<void> ProcessEngineBuffer(Dictionary<StringView, StringView> arguments,
List<String> outBufferNames, Dictionary<StringView, StringView> outEngineBuffers)
{
String nameInEngine = null;
String nameInShader = null;
defer
{
if (@return case .Err)
{
delete nameInEngine;
delete nameInShader;
}
}
for (var (argName, argValue) in arguments)
{
if (argValue.StartsWith('"') && argValue.EndsWith('"'))
{
argValue = argValue[1...^2];
}
switch (argName)
{
case "Name":
nameInShader = new String(argValue);
case "Binding":
nameInEngine = new String(argValue);
default:
Log.EngineLogger.Error($"Unknown parameter for EngineBuffer: \"{argName}\".");
return .Err;
}
}
if (String.IsNullOrWhiteSpace(nameInEngine) || String.IsNullOrWhiteSpace(nameInShader))
{
Log.EngineLogger.Error($"Name and Binding need to be defined.");
return .Err;
}
outBufferNames.Add(nameInShader);
outBufferNames.Add(nameInEngine);
outEngineBuffers.Add(nameInShader, nameInEngine);
return .Ok;
}
private static Result<void> ProcessEditorVariables(Dictionary<StringView, StringView> arguments, Dictionary<StringView, ShaderVariable> outVarDescs)
{
ShaderVariable variable = new .();
defer
{
if (@return case .Err)
delete variable;
}
for (var (name, value) in arguments)
{
if (value.StartsWith('"') && value.EndsWith('"'))
{
value = value[1...^2];
}
switch(name)
{
case "Name":
variable.Name = value;
case "Preview":
variable.PreviewName = value;
case "Type":
variable.EditorType = value;
case "Min":
variable.MinValue = Try!(ParseVariableValue(value));
case "Max":
variable.MaxValue = Try!(ParseVariableValue(value));
default:
Variant paramValue = Variant.Create(new String(value), true);
variable.AddParameter(name, paramValue);
}
}
if (variable.Name.IsWhiteSpace)
{
Log.EngineLogger.Error("Failed to process shader: Missing argument \"Name\" int variable description.");
return .Err;
}
outVarDescs.Add(variable.Name, variable);
return .Ok;
}
private static Result<Variant> ParseVariableValue(StringView valueString)
{
// TODO: Simply always use double?
if (valueString[0].IsDigit || valueString[0] == '-')
{
var valueString;
if (valueString.EndsWith('f'))
valueString.Length--;
float value = Try!(float.Parse(valueString));
return Variant.Create(value);
}
else if (valueString.StartsWith("float"))
{
int index = 5;
int numComponents = valueString[index++] - '0';
while (valueString[index] != '(')
{
if (!valueString[index].IsWhiteSpace)
{
Log.EngineLogger.Error("Failed to process shader: Expected '('.");
return .Err;
}
index++;
}
if (numComponents < 2 || numComponents > 4)
{
Log.EngineLogger.Error($"Failed to process shader: Unsupported component count {numComponents}. Value must be between 2 and 4.");
return .Err;
}
float[] floats = scope float[numComponents];
for (int i < numComponents)
{
while (true)
{
char8 c = valueString[++index];
if (c.IsDigit || c == '.' || c == '-')
break;
}
int start = index;
while (true)
{
char8 c = valueString[++index];
if (!c.IsDigit && c != '.')
break;
}
int end = index;
StringView numberView = .(valueString, start, end - start);
var result = float.Parse(numberView);
if (result case .Ok(let value))
{
floats[i] = value;
}
}
if (numComponents == 2)
return Variant.Create(*(float2*)floats.Ptr);
else if (numComponents == 3)
return Variant.Create(*(float3*)floats.Ptr);
else
return Variant.Create(*(float4*)floats.Ptr);
}
else
{
Log.EngineLogger.Error($"Failed to process shader: Unsupported variable value: \"{valueString}\".");
return .Err;
}
}
}
@@ -109,6 +109,8 @@ class ReflectedTexture
class ReflectedConstantBufferVariable class ReflectedConstantBufferVariable
{ {
private String _name ~ delete _; private String _name ~ delete _;
private String _previewName ~ delete _;
private String _editorType ~ delete _;
public StringView Name public StringView Name
{ {
@@ -116,6 +118,18 @@ class ReflectedConstantBufferVariable
set => String.NewOrSet!(_name, value); set => String.NewOrSet!(_name, value);
} }
public StringView PreviewName
{
get => _previewName;
set => String.NewOrSet!(_previewName, value);
}
public StringView EditorType
{
get => _editorType;
set => String.NewOrSet!(_editorType, value);
}
public int Offset; public int Offset;
public int SizeInBytes; public int SizeInBytes;
public bool IsUsed; public bool IsUsed;
@@ -125,6 +139,9 @@ class ReflectedConstantBufferVariable
public int Columns; public int Columns;
public int ArraySize; public int ArraySize;
public Variant MinValue;
public Variant MaxValue;
} }
// TODO: Dx11 // TODO: Dx11
@@ -146,16 +163,29 @@ class ShaderCompiler
CompiledShader shader = new CompiledShader(); CompiledShader shader = new CompiledShader();
Try!(PlatformCompileShaderFromSource(code, assetIdentifier, entryPoint, compileTarget, defines, shader)); ShaderCompilationContext context = scope .();
Try!(PlatformReflectShader(shader)); Try!(PlatformCompileShaderFromSource(code, assetIdentifier, entryPoint, compileTarget, defines, shader, context));
Try!(PlatformReflectShader(shader, context));
return shader; return shader;
} }
protected static extern Result<void> PlatformCompileShaderFromSource(StringView code, AssetIdentifier fileName, StringView entryPoint, StringView compileTarget, Span<ShaderDefineValue> defines, CompiledShader outShader); protected static extern Result<void> PlatformCompileShaderFromSource(StringView code, AssetIdentifier fileName, StringView entryPoint, StringView compileTarget, Span<ShaderDefineValue> defines, CompiledShader outShader, ShaderCompilationContext context);
protected static extern Result<void> PlatformReflectShader(CompiledShader shader); protected static extern Result<void> PlatformReflectShader(CompiledShader shader, ShaderCompilationContext context);
}
class ShaderCompilationContext
{
public append String VsName = String();
public append String PsName = String();
public append Dictionary<StringView, ShaderVariable> Variables = .() ~ ClearDictionaryAndDeleteValues!(_);
public append List<String> BufferNames = .() ~ ClearAndDeleteItems!(_);
// Name in Shader -> Name in Engine
public append Dictionary<StringView, StringView> EngineBuffers = .();
} }
// TODO: Dx11 // TODO: Dx11
@@ -169,7 +199,7 @@ extension ShaderCompiler
.OptimizationLevel3; .OptimizationLevel3;
#endif #endif
protected static override Result<void> PlatformCompileShaderFromSource(StringView code, AssetIdentifier fileName, StringView entryPoint, StringView compileTarget, Span<ShaderDefineValue> defines, CompiledShader outShader) protected static override Result<void> PlatformCompileShaderFromSource(StringView code, AssetIdentifier fileName, StringView entryPoint, StringView compileTarget, Span<ShaderDefineValue> defines, CompiledShader outShader, ShaderCompilationContext context)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -192,7 +222,11 @@ extension ShaderCompiler
Path.GetDirectoryPath(fileName, directory); Path.GetDirectoryPath(fileName, directory);
using (let includer = Includer(directory)) String shaderCode = new:ScopedAlloc! String(code);
Try!(ShaderCodePreprocessor.ProcessFileContent(shaderCode, context.VsName, context.PsName, context.Variables, context.BufferNames, context.EngineBuffers));
using (let includer = PreprocessingIncluder(directory, context))
{ {
var result = D3DCompiler.D3DCompile(code.Ptr, (.)code.Length, fileName.FullIdentifier.ToScopeCStr!(), nativeMacros, &includer, entryPoint.ToScopeCStr!(), var result = D3DCompiler.D3DCompile(code.Ptr, (.)code.Length, fileName.FullIdentifier.ToScopeCStr!(), nativeMacros, &includer, entryPoint.ToScopeCStr!(),
compileTarget.ToScopeCStr!(), DefaultCompileFlags /* Pass down compile flags? */, .None, &outShader._shaderBlob, &errorBlob); compileTarget.ToScopeCStr!(), DefaultCompileFlags /* Pass down compile flags? */, .None, &outShader._shaderBlob, &errorBlob);
@@ -210,7 +244,7 @@ extension ShaderCompiler
return .Ok; return .Ok;
} }
protected override static Result<void> PlatformReflectShader(CompiledShader shader) protected override static Result<void> PlatformReflectShader(CompiledShader shader, ShaderCompilationContext context)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -253,7 +287,7 @@ extension ShaderCompiler
// ConstantBuffer // ConstantBuffer
if(bufferDesc.Type == .D3D11_CT_CBUFFER) if(bufferDesc.Type == .D3D11_CT_CBUFFER)
{ {
ReflectedConstantBuffer cbuffer = Try!(ReflectConstantBuffer(bindDesc, bufferReflection)); ReflectedConstantBuffer cbuffer = Try!(ReflectConstantBuffer(bindDesc, bufferReflection, context));
shader.AddConstantBuffer(cbuffer); shader.AddConstantBuffer(cbuffer);
} }
case .Texture: case .Texture:
@@ -290,7 +324,7 @@ extension ShaderCompiler
return .Ok; return .Ok;
} }
private static Result<ReflectedConstantBuffer> ReflectConstantBuffer(ShaderInputBindDescription bindDesc, ID3D11ShaderReflectionConstantBuffer* bufferReflection) private static Result<ReflectedConstantBuffer> ReflectConstantBuffer(ShaderInputBindDescription bindDesc, ID3D11ShaderReflectionConstantBuffer* bufferReflection, ShaderCompilationContext context)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -310,17 +344,22 @@ extension ShaderCompiler
{ {
ID3D11ShaderReflectionVariable* variableReflection = bufferReflection.GetVariableByIndex(v); ID3D11ShaderReflectionVariable* variableReflection = bufferReflection.GetVariableByIndex(v);
if (ReflectConstantBufferVariable(buffer, variableReflection) case .Err) if (ReflectConstantBufferVariable(buffer, variableReflection, context) case .Err)
{ {
delete buffer; delete buffer;
return .Err; return .Err;
} }
} }
if (context.EngineBuffers.TryGetValue(buffer.Name, let engineBufferName))
{
buffer.EngineBufferName = engineBufferName;
}
return buffer; return buffer;
} }
private static Result<void> ReflectConstantBufferVariable(ReflectedConstantBuffer buffer, ID3D11ShaderReflectionVariable* variableReflection) private static Result<void> ReflectConstantBufferVariable(ReflectedConstantBuffer buffer, ID3D11ShaderReflectionVariable* variableReflection, ShaderCompilationContext context)
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
@@ -375,13 +414,23 @@ extension ShaderCompiler
Internal.MemCpy(&buffer.RawData[variable.Offset], variableDescription.DefaultValue, variable.SizeInBytes); Internal.MemCpy(&buffer.RawData[variable.Offset], variableDescription.DefaultValue, variable.SizeInBytes);
} }
if (context.Variables.TryGetValue(variable.Name, let variableAnnotation))
{
variable.PreviewName = variableAnnotation.PreviewName;
variable.EditorType = variableAnnotation.EditorType;
// TODO: We need to somehow validate against our variable type
variable.MinValue = variableAnnotation.MinValue;
variable.MaxValue = variableAnnotation.MaxValue;
}
buffer.AddVariable(variable); buffer.AddVariable(variable);
return .Ok; return .Ok;
} }
} }
struct Includer : ID3DInclude, IDisposable struct PreprocessingIncluder : ID3DInclude, IDisposable
{ {
private VTable _vTable; private VTable _vTable;
@@ -389,7 +438,9 @@ struct Includer : ID3DInclude, IDisposable
private String _parentFileDirectory; private String _parentFileDirectory;
public this(String parentFileDirectory) private ShaderCompilationContext _context;
public this(String parentFileDirectory, ShaderCompilationContext context)
{ {
_parentFileDirectory = parentFileDirectory; _parentFileDirectory = parentFileDirectory;
_loadedFiles = new Dictionary<StringView, (String FileName, String FileContent)>(); _loadedFiles = new Dictionary<StringView, (String FileName, String FileContent)>();
@@ -398,6 +449,8 @@ struct Includer : ID3DInclude, IDisposable
_vTable.Close = => Close; _vTable.Close = => Close;
_vt = &_vTable; _vt = &_vTable;
_context = context;
} }
public void Dispose() public void Dispose()
@@ -413,7 +466,7 @@ struct Includer : ID3DInclude, IDisposable
public static HResult Open(ID3DInclude* self, IncludeType includeType, char8* fileNamePtr, void* parentData, void** data, uint32* bytes) public static HResult Open(ID3DInclude* self, IncludeType includeType, char8* fileNamePtr, void* parentData, void** data, uint32* bytes)
{ {
Includer* includer = (.)self; PreprocessingIncluder* includer = (.)self;
StringView fileName = StringView(fileNamePtr); StringView fileName = StringView(fileNamePtr);
@@ -453,6 +506,7 @@ struct Includer : ID3DInclude, IDisposable
if (fileStream == null) if (fileStream == null)
{ {
return .E_FILENOTFOUND;
} }
String fileContent = new String(); String fileContent = new String();
@@ -469,6 +523,13 @@ struct Includer : ID3DInclude, IDisposable
delete fileStream; delete fileStream;
String trashbin = scope String();
if (ShaderCodePreprocessor.ProcessFileContent(fileContent, trashbin, trashbin, includer._context.Variables, includer._context.BufferNames, includer._context.EngineBuffers) case .Err)
{
return .E_FAIL;
}
*data = (void*)fileContent.Ptr; *data = (void*)fileContent.Ptr;
*bytes = (uint32)fileContent.Length; *bytes = (uint32)fileContent.Length;
@@ -477,7 +538,7 @@ struct Includer : ID3DInclude, IDisposable
public static HResult Close(ID3DInclude* self, void** data) public static HResult Close(ID3DInclude* self, void** data)
{ {
Includer* includer = (.)self; PreprocessingIncluder* includer = (.)self;
for (var v in includer._loadedFiles) for (var v in includer._loadedFiles)
{ {
@@ -69,6 +69,8 @@ class ProcessedShader : ProcessedResource
class ShaderVariable class ShaderVariable
{ {
private String _name ~ delete _; private String _name ~ delete _;
private String _previewName ~ delete _;
private String _editorType ~ delete _;
private Dictionary<String, Variant> _parameters = new .() ~ { private Dictionary<String, Variant> _parameters = new .() ~ {
for (var (entryKey, entry) in _) for (var (entryKey, entry) in _)
@@ -85,6 +87,21 @@ class ShaderVariable
set => String.NewOrSet!(_name, value); set => String.NewOrSet!(_name, value);
} }
public StringView PreviewName
{
get => _previewName;
set => String.NewOrSet!(_previewName, value);
}
public StringView EditorType
{
get => _editorType;
set => String.NewOrSet!(_editorType, value);
}
public Variant MinValue ~ _.Dispose();
public Variant MaxValue ~ _.Dispose();
public Dictionary<String, Variant> Parameters => _parameters; public Dictionary<String, Variant> Parameters => _parameters;
public void AddParameter(StringView name, Variant value) public void AddParameter(StringView name, Variant value)
@@ -134,10 +151,12 @@ class ShaderProcessor : IAssetProcessor
} }
} }
String code = new String(importedShader.HlslCode); String tmpCode = new String(importedShader.HlslCode);
defer { delete code; }
Try!(ProcessFileContent(code, vsName, psName, variables, bufferNames, engineBuffers)); // TODO: This is terrible. Currently we process too often... (here + each shader stage)
Try!(ShaderCodePreprocessor.ProcessFileContent(tmpCode , vsName, psName, variables, bufferNames, engineBuffers));
delete tmpCode;
if (String.IsNullOrWhiteSpace(vsName) && String.IsNullOrWhiteSpace(psName)) if (String.IsNullOrWhiteSpace(vsName) && String.IsNullOrWhiteSpace(psName))
{ {
@@ -147,28 +166,24 @@ class ShaderProcessor : IAssetProcessor
processedShader = new ProcessedShader(new AssetIdentifier(importedShader.AssetIdentifier), config.AssetHandle); processedShader = new ProcessedShader(new AssetIdentifier(importedShader.AssetIdentifier), config.AssetHandle);
Try!(CompileAndReflect(vsName, psName, importedShader, code, processedShader)); Try!(CompileAndReflect(vsName, psName, importedShader, importedShader.HlslCode, processedShader));
Try!(MergeResources(processedShader, variables, engineBuffers)); Try!(MergeResources(processedShader));
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!(MergeConstantBuffers(processedShader));
Try!(MergeTextures(processedShader)); Try!(MergeTextures(processedShader));
return .Ok; return .Ok;
} }
private static Result<void> MergeConstantBuffers(ProcessedShader processedShader, private static Result<void> MergeConstantBuffers(ProcessedShader processedShader)
Dictionary<StringView, ShaderVariable> variables,
Dictionary<StringView, StringView> engineBuffers)
{ {
HashSet<StringView> bufferNames = scope .(); HashSet<StringView> bufferNames = scope .();
@@ -211,11 +226,6 @@ class ShaderProcessor : IAssetProcessor
Log.EngineLogger.Assert(constantBufferEntry.ConstantBuffer != null); Log.EngineLogger.Assert(constantBufferEntry.ConstantBuffer != null);
Log.EngineLogger.Assert(constantBufferEntry.VertexShaderBindPoint > -1 || constantBufferEntry.PixelShaderBindPoint > -1); Log.EngineLogger.Assert(constantBufferEntry.VertexShaderBindPoint > -1 || constantBufferEntry.PixelShaderBindPoint > -1);
if (engineBuffers.TryGetValue(constantBufferEntry.ConstantBuffer.Name, let engineBufferName))
{
constantBufferEntry.ConstantBuffer.EngineBufferName = engineBufferName;
}
processedShader.AddConstantBuffer(constantBufferEntry); processedShader.AddConstantBuffer(constantBufferEntry);
} }
@@ -283,304 +293,4 @@ 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,
List<String> outBufferNames, Dictionary<StringView, StringView> outEngineBuffers)
{
Debug.Profiler.ProfileResourceFunction!();
Dictionary<StringView, StringView> arguments = scope .();
int index = 0;
while (true)
{
if ((int Start, int End) value = GetNextPreprocessor(fileContent, index, let name, arguments..Clear()))
{
index = value.End;
switch(name)
{
case "Effect":
for (let (argName, argValue) in arguments)
{
switch(argName)
{
case "VS", "VertexShader":
outVsName.Append(argValue);
case "PS", "PixelShader":
outPsName.Append(argValue);
default:
Log.EngineLogger.Error($"Unknown parameter name \"{name}\".");
return .Err;
}
}
case "EditorVariable":
Try!(ProcessEditorVariables(arguments, outVarDescs));
case "EngineBuffer":
Try!(ProcessEngineBuffer(arguments, outBufferNames, outEngineBuffers));
default:
continue;
}
CommentLine(fileContent, value.Start);
}
else
{
break;
}
}
return .Ok;
}
private static void CommentLine(StringView code, int commentPosition)
{
code[commentPosition] = '/';
code[commentPosition + 1] = '/';
}
private static Result<(int Start, int End)> GetNextPreprocessor(StringView code, int startindex, out StringView name, Dictionary<StringView, StringView> arguments)
{
name = .();
int startOfLine;
int endOfLine;
do
{
startOfLine = code.IndexOf("#pragma", startindex);
if (startOfLine == -1)
return .Err;
endOfLine = code.IndexOf('\n', startOfLine);
StringView line = (endOfLine != -1) ? code.Substring(startOfLine, endOfLine - startOfLine) : code.Substring(startOfLine);
// cut off the #pragma
line = line.Substring(7);
int lBracketIndex = line.IndexOf('[');
if (lBracketIndex == -1)
{
name = line..Trim();
break;
}
name = line.Substring(0, lBracketIndex);
name.Trim();
int rBracketIndex = line.IndexOf(']');
if (rBracketIndex == -1)
{
Log.EngineLogger.Error($"Pragma is missing closing Bracket (\"{line}\")");
rBracketIndex = line.Length;
}
StringView argumentText = line.Substring(lBracketIndex + 1, rBracketIndex - lBracketIndex - 1);
for (StringView argument in argumentText.Split(';'))
{
int equalsIndex = argument.IndexOf('=');
StringView argumentName = .();
StringView argumentValue = .();
if (equalsIndex == -1)
{
argumentName = argument;
argumentName.Trim();
}
else
{
argumentName = argument.Substring(0, equalsIndex);
argumentName.Trim();
argumentValue = argument.Substring(equalsIndex + 1);
argumentValue.Trim();
}
if (arguments.ContainsKey(argumentName))
{
Log.EngineLogger.Error($"Arguments \"{argumentName}\" already exists.");
continue;
}
arguments.Add(argumentName, argumentValue);
}
}
return .Ok((startOfLine, endOfLine));
}
private static Result<void> ProcessEngineBuffer(Dictionary<StringView, StringView> arguments,
List<String> outBufferNames, Dictionary<StringView, StringView> outEngineBuffers)
{
String nameInEngine = null;
String nameInShader = null;
for (var (argName, argValue) in arguments)
{
if (argValue.StartsWith('"') && argValue.EndsWith('"'))
{
argValue = argValue[1...^2];
}
switch (argName)
{
case "Name":
nameInShader = new String(argValue);
case "Binding":
nameInEngine = new String(argValue);
default:
Log.EngineLogger.Error($"Unknown parameter for EngineBuffer: \"{argName}\".");
delete nameInEngine;
delete nameInShader;
return .Err;
}
}
if (String.IsNullOrWhiteSpace(nameInEngine) || String.IsNullOrWhiteSpace(nameInShader))
{
Log.EngineLogger.Error($"Name and Binding need to be defined.");
delete nameInEngine;
delete nameInShader;
return .Err;
}
outBufferNames.Add(nameInShader);
outBufferNames.Add(nameInEngine);
outEngineBuffers.Add(nameInShader, nameInEngine);
return .Ok;
}
private static Result<void> ProcessEditorVariables(Dictionary<StringView, StringView> arguments, Dictionary<StringView, ShaderVariable> outVarDescs)
{
ShaderVariable variable = new .();
for (var (name, value) in arguments)
{
if (value.StartsWith('"') && value.EndsWith('"'))
{
value = value[1...^2];
}
switch(name)
{
case "Name":
variable.Name = value;
case "Min", "Max":
if (Variant paramValue = ParseVariableValue(value))
variable.AddParameter(name, paramValue);
else
{
delete variable;
return .Err;
}
default:
Variant paramValue = Variant.Create(new String(value), true);
variable.AddParameter(name, paramValue);
}
}
if (variable.Name.IsWhiteSpace)
{
Log.EngineLogger.Error("Failed to process shader: Missing argument \"Name\" int variable description.");
delete variable;
return .Err;
}
outVarDescs.Add(variable.Name, variable);
return .Ok;
}
private static Result<Variant> ParseVariableValue(StringView valueString)
{
if (valueString[0].IsDigit || valueString[0] == '-')
{
var valueString;
if (valueString.EndsWith('f'))
valueString.Length--;
float value = Try!(float.Parse(valueString));
return Variant.Create(value);
}
else if (valueString.StartsWith("float"))
{
int index = 5;
int numComponents = valueString[index++] - '0';
while (valueString[index] != '(')
{
if (!valueString[index].IsWhiteSpace)
{
Log.EngineLogger.Error("Failed to process shader: Expected '('.");
return .Err;
}
index++;
}
if (numComponents < 2 || numComponents > 4)
{
Log.EngineLogger.Error($"Failed to process shader: Unsupported component count {numComponents}. Value must be between 2 and 4.");
return .Err;
}
float[] floats = scope float[numComponents];
for (int i < numComponents)
{
while (true)
{
char8 c = valueString[++index];
if (c.IsDigit || c == '.' || c == '-')
break;
}
int start = index;
while (true)
{
char8 c = valueString[++index];
if (!c.IsDigit && c != '.')
break;
}
int end = index;
StringView numberView = .(valueString, start, end - start);
var result = float.Parse(numberView);
if (result case .Ok(let value))
{
floats[i] = value;
}
}
if (numComponents == 2)
return Variant.Create(*(float2*)floats.Ptr);
else if (numComponents == 3)
return Variant.Create(*(float3*)floats.Ptr);
else
return Variant.Create(*(float4*)floats.Ptr);
}
else
{
Log.EngineLogger.Error($"Failed to process shader: Unsupported variable value: \"{valueString}\".");
return .Err;
}
}
} }
@@ -172,16 +172,14 @@ class InspectorWindow : EditorWindow
(assetFile.AssetConfig?.ProcessorConfig?.Changed == true) || (assetFile.AssetConfig?.ProcessorConfig?.Changed == true) ||
(assetFile.AssetConfig?.ExporterConfig?.Changed == true); (assetFile.AssetConfig?.ExporterConfig?.Changed == true);
if (!hasChanges) ImGui.BeginDisabled(!hasChanges);
ImGui.BeginDisabled();
if (ImGui.Button("Apply")) if (ImGui.Button("Apply"))
{ {
assetFile.SaveAssetConfigIfChanged(); assetFile.SaveAssetConfigIfChanged();
} }
if (!hasChanges) ImGui.EndDisabled();
ImGui.EndDisabled();
} }
private static void ShowEntityProperties(UUID entityId, Editor editor, Type componentType = null) private static void ShowEntityProperties(UUID entityId, Editor editor, Type componentType = null)
@@ -86,6 +86,22 @@ class ShaderLoader : IProcessedAssetLoader
return effect; return effect;
} }
private static mixin ReadScopedSizedString<Tint>(Stream stream)
where Tint : IInteger
where int : operator explicit Tint
where Tint : operator explicit int
where Tint : struct
{
int bufferNameLength = (int)Try!(stream.Read<Tint>());
String string = scope:mixin String(bufferNameLength);
if (bufferNameLength > 0)
stream.ReadStrSized32(bufferNameLength, string);
string
}
private static Result<void> LoadBuffer(Stream stream, Effect effect) private static Result<void> LoadBuffer(Stream stream, Effect effect)
{ {
int64 bufferSize = Try!(stream.Read<int64>()); int64 bufferSize = Try!(stream.Read<int64>());
@@ -93,24 +109,10 @@ class ShaderLoader : IProcessedAssetLoader
int32 vertexShaderBindPoint = Try!(stream.Read<int32>()); int32 vertexShaderBindPoint = Try!(stream.Read<int32>());
int32 pixelShaderBindPoint = Try!(stream.Read<int32>()); int32 pixelShaderBindPoint = Try!(stream.Read<int32>());
int16 bufferNameLength = Try!(stream.Read<int16>()); String bufferName = ReadScopedSizedString!<uint16>(stream);
String bufferName = scope String(bufferNameLength); String engineBufferName = ReadScopedSizedString!<uint16>(stream);
stream.ReadStrSized32(bufferNameLength, bufferName);
int16 engineBufferNameLength = Try!(stream.Read<int16>()); using (ConstantBuffer buffer = new ConstantBuffer(bufferName, bufferSize, engineBufferName))
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()
}
using (ConstantBuffer buffer = new ConstantBuffer(bufferName, bufferSize))
{ {
uint16 variableCount = Try!(stream.Read<uint16>()); uint16 variableCount = Try!(stream.Read<uint16>());
@@ -124,26 +126,25 @@ class ShaderLoader : IProcessedAssetLoader
uint8 columns = Try!(stream.Read<uint8>()); uint8 columns = Try!(stream.Read<uint8>());
uint64 arraySize = Try!(stream.Read<uint64>()); uint64 arraySize = Try!(stream.Read<uint64>());
int16 variableNameLength = Try!(stream.Read<int16>()); String variableName = ReadScopedSizedString!<uint16>(stream);
String variableName = scope String(variableNameLength); String previewName = ReadScopedSizedString!<uint16>(stream);
stream.ReadStrSized32(variableNameLength, variableName); String editorTypeName = ReadScopedSizedString!<uint16>(stream);
if (engineBufferName == null) buffer.AddVariable(variableName, previewName, editorTypeName, variableOffset, sizeInBytes, isUsed, type, rows, columns, arraySize);
buffer.AddVariable(variableName, variableOffset, sizeInBytes, isUsed, type, rows, columns, arraySize);
} }
Try!(stream.TryRead(buffer.RawData)); Try!(stream.TryRead(buffer.RawData));
Try!(buffer.Apply()); Try!(buffer.Apply());
if (vertexShaderBindPoint != -1) if (vertexShaderBindPoint != -1)
effect.VertexShader.Buffers.Add(vertexShaderBindPoint, buffer.Name, buffer); effect.VertexShader.Buffers.Add(vertexShaderBindPoint, buffer.Name, engineBufferName, buffer);
if (pixelShaderBindPoint != -1) if (pixelShaderBindPoint != -1)
effect.PixelShader.Buffers.Add(pixelShaderBindPoint, buffer.Name, buffer); effect.PixelShader.Buffers.Add(pixelShaderBindPoint, buffer.Name, engineBufferName, buffer);
// TODO: Allow binding buffers to different indices? Does this theoretically work with textures? // TODO: Allow binding buffers to different indices? Does this theoretically work with textures?
let tempBindPoint = (vertexShaderBindPoint != -1) ? vertexShaderBindPoint : pixelShaderBindPoint; let tempBindPoint = (vertexShaderBindPoint != -1) ? vertexShaderBindPoint : pixelShaderBindPoint;
effect.Buffers.Add(tempBindPoint, buffer.Name, buffer); effect.Buffers.Add(tempBindPoint, buffer.Name, engineBufferName, buffer);
for (var variable in buffer.Variables) for (var variable in buffer.Variables)
{ {
+15 -3
View File
@@ -4,15 +4,16 @@ using GlitchyEngine.Core;
namespace GlitchyEngine.Renderer namespace GlitchyEngine.Renderer
{ {
public class BufferCollection : RefCounter, IEnumerable<(String Name, Buffer Buffer)> public class BufferCollection : RefCounter, IEnumerable<(String Name, String EngineBufferName, Buffer Buffer)>
{ {
public static extern int MaxBufferSlotCount { get; } public static extern int MaxBufferSlotCount { get; }
public typealias BufferEntry = (String Name, Buffer Buffer); public typealias BufferEntry = (String Name, String EngineBufferName, Buffer Buffer);
BufferEntry[] _buffers ~ DeleteBufferEntries!(_); BufferEntry[] _buffers ~ DeleteBufferEntries!(_);
Dictionary<StringView, BufferEntry*> _strToBuf ~ delete _; Dictionary<StringView, BufferEntry*> _strToBuf ~ delete _;
Dictionary<StringView, BufferEntry*> _engineBuffers ~ delete _;
[AllowAppend] [AllowAppend]
public this() public this()
@@ -22,9 +23,11 @@ namespace GlitchyEngine.Renderer
// Todo: append allocate as soon as it's fixed // Todo: append allocate as soon as it's fixed
let buffers = new BufferEntry[MaxBufferSlotCount]; let buffers = new BufferEntry[MaxBufferSlotCount];
let strToBuf = new Dictionary<StringView, BufferEntry*>(); let strToBuf = new Dictionary<StringView, BufferEntry*>();
let engineBuffers = new Dictionary<StringView, BufferEntry*>();
_buffers = buffers; _buffers = buffers;
_strToBuf = strToBuf; _strToBuf = strToBuf;
_engineBuffers = engineBuffers;
} }
public ~this() public ~this()
@@ -40,6 +43,7 @@ namespace GlitchyEngine.Renderer
for(let entry in entries) for(let entry in entries)
{ {
delete entry.Name; delete entry.Name;
delete entry.EngineBufferName;
entry.Buffer?.ReleaseRef(); entry.Buffer?.ReleaseRef();
} }
@@ -120,13 +124,21 @@ namespace GlitchyEngine.Renderer
} }
} }
public void Add(int slot, StringView name, Buffer buffer) public void Add(int slot, StringView name, StringView engineBufferName, Buffer buffer)
{ {
ref BufferEntry bufferEntry = ref _buffers[slot]; ref BufferEntry bufferEntry = ref _buffers[slot];
SetReference!(bufferEntry.Buffer, buffer); SetReference!(bufferEntry.Buffer, buffer);
String.NewOrSet!(bufferEntry.Name, name); String.NewOrSet!(bufferEntry.Name, name);
if (engineBufferName.IsEmpty)
DeleteAndNullify!(bufferEntry.EngineBufferName);
else
{
String.NewOrSet!(bufferEntry.EngineBufferName, engineBufferName);
_engineBuffers.Add(bufferEntry.EngineBufferName, &bufferEntry);
}
_strToBuf.Add(bufferEntry.Name, &bufferEntry); _strToBuf.Add(bufferEntry.Name, &bufferEntry);
} }
+7 -1
View File
@@ -24,6 +24,8 @@ namespace GlitchyEngine.Renderer
private ConstantBuffer _constantBuffer; private ConstantBuffer _constantBuffer;
private String _name ~ delete _; private String _name ~ delete _;
protected String _previewName ~ delete _;
protected String _editorTypeName ~ delete _;
private ShaderVariableType _elementType; private ShaderVariableType _elementType;
@@ -41,6 +43,8 @@ namespace GlitchyEngine.Renderer
public ShaderVariableType ElementType => _elementType; public ShaderVariableType ElementType => _elementType;
public String Name => _name; public String Name => _name;
public StringView PreviewName => _previewName;
public StringView EditorTypeName => _editorTypeName;
public bool IsUsed => _flags.HasFlag(.Used); public bool IsUsed => _flags.HasFlag(.Used);
@@ -70,9 +74,11 @@ namespace GlitchyEngine.Renderer
[Inline] [Inline]
internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset; internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset;
public this(StringView name, ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 arrayElements, bool isUsed) public this(StringView name, ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 arrayElements, bool isUsed, StringView previewName, StringView editorTypeName)
{ {
_name = new String(name); _name = new String(name);
_previewName = new String(previewName);
_editorTypeName = new String(editorTypeName);
_constantBuffer = constantBuffer; // Only hold a weak reference. This variable has to die with the buffer _constantBuffer = constantBuffer; // Only hold a weak reference. This variable has to die with the buffer
_elementType = type; _elementType = type;
_columns = columns; _columns = columns;
+11 -3
View File
@@ -9,6 +9,7 @@ namespace GlitchyEngine.Renderer
public class ConstantBuffer : Buffer public class ConstantBuffer : Buffer
{ {
protected String _name ~ delete _; protected String _name ~ delete _;
protected String _engineBufferName ~ delete _;
/** /**
* The buffer that contains the buffer data on the CPU. * The buffer that contains the buffer data on the CPU.
@@ -23,6 +24,7 @@ namespace GlitchyEngine.Renderer
/// Gets the name of the constant buffer. /// Gets the name of the constant buffer.
public StringView Name => _name; public StringView Name => _name;
public StringView EngineBufferName => _engineBufferName;
public BufferVariableCollection Variables => _variables; public BufferVariableCollection Variables => _variables;
@@ -31,9 +33,15 @@ namespace GlitchyEngine.Renderer
protected this() {} protected this() {}
public this(StringView name, int64 size) public this(StringView name, int64 size, StringView engineBufferName = "")
{ {
_name = new String(name); _name = new String(name);
if (!engineBufferName.IsEmpty)
{
_engineBufferName = new String(engineBufferName);
}
rawData = new uint8[size]; rawData = new uint8[size];
ConstructBuffer(); ConstructBuffer();
} }
@@ -43,9 +51,9 @@ namespace GlitchyEngine.Renderer
_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) public void AddVariable(StringView name, StringView previewName, StringView editorTypeName, 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)); _variables.Add(new BufferVariable(name, this, type, columns, rows, (uint32)offset, (uint32)sizeInBytes, (uint32)arraySize, isUsed, previewName, editorTypeName));
} }
/** /**
+3 -3
View File
@@ -95,7 +95,7 @@ public class Material : Asset
BufferCollection parentBuffers = _parent?._bufferCollection ?? _effect.Buffers; BufferCollection parentBuffers = _parent?._bufferCollection ?? _effect.Buffers;
for (let (bufferName, buffer) in parentBuffers) for (let (bufferName, engineBufferName, buffer) in parentBuffers)
{ {
if (buffer == null) if (buffer == null)
continue; continue;
@@ -104,7 +104,7 @@ public class Material : Asset
{ {
using (OverridingConstantBuffer childConstBuffer = new OverridingConstantBuffer(parentConstBuffer)) using (OverridingConstantBuffer childConstBuffer = new OverridingConstantBuffer(parentConstBuffer))
{ {
_bufferCollection.Add(@bufferName.Index, childConstBuffer.Name, childConstBuffer); _bufferCollection.Add(@bufferName.Index, childConstBuffer.Name, engineBufferName, childConstBuffer);
InitVariables(childConstBuffer); InitVariables(childConstBuffer);
} }
} }
@@ -177,7 +177,7 @@ public class Material : Asset
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
for (let (bufferName, buffer) in _bufferCollection) for (let (bufferName, engineBufferName, buffer) in _bufferCollection)
{ {
if (let cbuffer = buffer as ConstantBuffer) if (let cbuffer = buffer as ConstantBuffer)
{ {
@@ -12,7 +12,7 @@ class OverridingConstantBuffer : ConstantBuffer
public ConstantBuffer Parent => _parent; public ConstantBuffer Parent => _parent;
public this(ConstantBuffer parent) : base(parent.Name, parent.RawData.Length) public this(ConstantBuffer parent) : base(parent.Name, parent.RawData.Length, parent.EngineBufferName)
{ {
Log.EngineLogger.AssertDebug(parent != null); Log.EngineLogger.AssertDebug(parent != null);
_parent = parent; _parent = parent;
@@ -25,7 +25,7 @@ class OverridingConstantBuffer : ConstantBuffer
for (BufferVariable parentVariable in _parent.Variables) for (BufferVariable parentVariable in _parent.Variables)
{ {
BufferVariable newVariable = new BufferVariable(parentVariable.Name, this, parentVariable.ElementType, parentVariable.Columns, BufferVariable newVariable = new BufferVariable(parentVariable.Name, this, parentVariable.ElementType, parentVariable.Columns,
parentVariable.Rows, parentVariable.Offset, parentVariable._sizeInBytes, parentVariable.ArrayElements, parentVariable.IsUsed); parentVariable.Rows, parentVariable.Offset, parentVariable._sizeInBytes, parentVariable.ArrayElements, parentVariable.IsUsed, parentVariable.PreviewName, parentVariable.EditorTypeName);
if (parentVariable.Flags.HasFlag(.Locked)) if (parentVariable.Flags.HasFlag(.Locked))
{ {