mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 21:01:52 +00:00
Materials kind of working and used in some places
- Also Texture viewer fixes
This commit is contained in:
@@ -176,5 +176,7 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
return _buffers.GetEnumerator();
|
||||
}
|
||||
|
||||
protected internal extern void PlatformFetchNativeBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,21 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
using internal GlitchyEngine.Renderer;
|
||||
|
||||
public enum VariableFlags
|
||||
{
|
||||
None = 0x00,
|
||||
/// The variable is dirty and needs to be sent do the GPU.
|
||||
Dirty = 0x01,
|
||||
/// The variable is locked, its value cannot be overwritten in child buffers.
|
||||
Locked = 0x02,
|
||||
/// The variable is used in the shader. Conversely, this means that the variable is unused.
|
||||
Used = 0x04,
|
||||
/// (For inherited variables only) The variable doesn't override the value set in the parent buffer.
|
||||
Unset = 0x08,
|
||||
/// The variables value cannot be changed. (i.e. it is locked in the parent buffer)
|
||||
Readonly = 0x10
|
||||
}
|
||||
|
||||
public class BufferVariable
|
||||
{
|
||||
private ConstantBuffer _constantBuffer;
|
||||
@@ -19,7 +34,7 @@ namespace GlitchyEngine.Renderer
|
||||
// Number of elements in the array
|
||||
internal uint32 _arrayElements;
|
||||
|
||||
private bool _isUsed;
|
||||
private VariableFlags _flags;
|
||||
|
||||
public ConstantBuffer ConstantBuffer => _constantBuffer;
|
||||
|
||||
@@ -27,7 +42,7 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
public String Name => _name;
|
||||
|
||||
public bool IsUsed => _isUsed;
|
||||
public bool IsUsed => _flags.HasFlag(.Used);
|
||||
|
||||
public uint32 Columns => _columns;
|
||||
public uint32 Rows => _rows;
|
||||
@@ -35,6 +50,20 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
public uint32 Offset => _offset;
|
||||
|
||||
public bool IsDirty => _flags.HasFlag(.Dirty);
|
||||
public bool IsLocked => _flags.HasFlag(.Locked);
|
||||
|
||||
/// Only applies to variables of child buffers. If true, the variable is unset and
|
||||
/// it's value will come from the parent buffer.
|
||||
/// Note: Setting IsUnset to true will only have a guaranteed effect on the value stored in this BufferVariable once Apply has been called on the constant buffer.
|
||||
public bool IsUnset
|
||||
{
|
||||
get => _flags.HasFlag(.Unset);
|
||||
set => Enum.SetFlagConditionally(ref _flags, .Unset, value);
|
||||
}
|
||||
|
||||
public VariableFlags Flags => _flags;
|
||||
|
||||
/**
|
||||
* Gets a pointer to the start of the variable in the constant buffers backing data.
|
||||
*/
|
||||
@@ -51,7 +80,12 @@ namespace GlitchyEngine.Renderer
|
||||
_offset = offset;
|
||||
_sizeInBytes = sizeInBytes;
|
||||
_arrayElements = arrayElements;
|
||||
_isUsed = isUsed;
|
||||
|
||||
_flags = .None;
|
||||
|
||||
Enum.SetFlagConditionally(ref _flags, .Used, isUsed);
|
||||
Enum.SetFlag(ref _flags, .Dirty);
|
||||
//Enum.SetFlag(ref _flags, .Locked);
|
||||
}
|
||||
|
||||
public void EnsureTypeMatch(int rows, int cols, ShaderVariableType type)
|
||||
@@ -130,12 +164,21 @@ namespace GlitchyEngine.Renderer
|
||||
EnsureTypeMatch(1, 4, .Float);
|
||||
}
|
||||
}
|
||||
|
||||
enum SetDataError
|
||||
{
|
||||
VariableNotFound,
|
||||
TypeMismatch
|
||||
}
|
||||
|
||||
[Inline]
|
||||
private void SetData<T>(T value)
|
||||
{
|
||||
EnsureTypeMatch<T>();
|
||||
|
||||
_flags |= .Dirty;
|
||||
Enum.ClearFlag(ref _flags, .Unset);
|
||||
|
||||
*(T*)firstByte = value;
|
||||
}
|
||||
|
||||
@@ -175,6 +218,9 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
EnsureTypeMatch<Matrix4x3>();
|
||||
|
||||
_flags |= .Dirty;
|
||||
Enum.ClearFlag(ref _flags, .Unset);
|
||||
|
||||
// TODO: assert length
|
||||
|
||||
Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix4x3) * Math.Min(value.Count, _arrayElements));
|
||||
@@ -182,16 +228,23 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
public void SetData(Matrix3x3 value)
|
||||
{
|
||||
EnsureTypeMatch<Matrix3x3>();
|
||||
EnsureTypeMatch<Matrix3x3>();
|
||||
|
||||
_flags |= .Dirty;
|
||||
Enum.ClearFlag(ref _flags, .Unset);
|
||||
|
||||
// TODO: D3D uses 16 Byte rows, smaller rows are padded.
|
||||
// OpenGL and Vulkan do this by default, too. However they support compact buffers,
|
||||
// if we want to support that we need to handle it here somehow (simple size check?).
|
||||
*(Matrix4x3*)firstByte = Matrix4x3(value);
|
||||
|
||||
// Todo: maybe manual copy
|
||||
}
|
||||
|
||||
public void SetData(Matrix3x3[] value)
|
||||
{
|
||||
EnsureTypeMatch<Matrix3x3>();
|
||||
EnsureTypeMatch<Matrix3x3>();
|
||||
|
||||
_flags |= .Dirty;
|
||||
Enum.ClearFlag(ref _flags, .Unset);
|
||||
|
||||
// TODO: assert length
|
||||
|
||||
@@ -205,7 +258,10 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
public void SetData(Matrix[] value)
|
||||
{
|
||||
EnsureTypeMatch<Matrix>();
|
||||
EnsureTypeMatch<Matrix>();
|
||||
|
||||
_flags |= .Dirty;
|
||||
Enum.ClearFlag(ref _flags, .Unset);
|
||||
|
||||
// TODO: assert length
|
||||
|
||||
@@ -223,11 +279,14 @@ namespace GlitchyEngine.Renderer
|
||||
#if GE_SHADER_UNUSED_VARIABLE_IS_ERROR
|
||||
Log.EngineLogger.Assert(_isUsed, scope $"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\".");
|
||||
#elif GE_SHADER_UNUSED_VARIABLE_IS_WARNING
|
||||
if(!_isUsed)
|
||||
if(!_flags.HasFlag(.Used))
|
||||
{
|
||||
Log.EngineLogger.Warning($"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\".");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
_flags |= .Dirty;
|
||||
Enum.ClearFlag(ref _flags, .Unset);
|
||||
|
||||
if(rawData != null)
|
||||
Internal.MemCpy(firstByte, rawData, _sizeInBytes);
|
||||
|
||||
@@ -17,8 +17,12 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
protected BufferVariableCollection _variables = new BufferVariableCollection() ~ delete _;
|
||||
|
||||
protected bool _isDirty = true;
|
||||
|
||||
protected internal int _generation = 0;
|
||||
|
||||
/// Gets the name of the constant buffer.
|
||||
public String Name => _name;
|
||||
public StringView Name => _name;
|
||||
|
||||
public BufferVariableCollection Variables => _variables;
|
||||
|
||||
@@ -58,10 +62,32 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
/**
|
||||
* Uploads the date to the GPU.
|
||||
* @returns true if the GPU buffer was updated, false otherwise (i.e. it wasn't dirty).
|
||||
*/
|
||||
public Result<void> Update()
|
||||
public virtual Result<void> Apply()
|
||||
{
|
||||
return PlatformSetData(rawData.CArray(), (uint32)rawData.Count, 0, .WriteDiscard);
|
||||
bool isDirty = false;
|
||||
|
||||
for (BufferVariable variable in _variables)
|
||||
{
|
||||
if (variable.IsDirty)
|
||||
{
|
||||
isDirty = true;
|
||||
Enum.ClearFlag(ref variable.[Friend]_flags, .Dirty);
|
||||
}
|
||||
}
|
||||
|
||||
if (isDirty)
|
||||
{
|
||||
Result<void> setDataResult = PlatformSetData(rawData.CArray(), (uint32)rawData.Count, 0, .WriteDiscard);
|
||||
|
||||
if (setDataResult case .Err)
|
||||
return .Err;
|
||||
|
||||
_generation++;
|
||||
}
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ public class Effect : Asset
|
||||
{
|
||||
if(let cbuffer = buffer.Buffer as ConstantBuffer)
|
||||
{
|
||||
cbuffer.Update();
|
||||
cbuffer.Apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,5 +116,9 @@ namespace GlitchyEngine.Renderer
|
||||
public extern void UnbindTextures();
|
||||
|
||||
public extern void BindConstantBuffer(Buffer buffer, int slot, ShaderStage stage);
|
||||
|
||||
public extern void BindConstantBuffers(BufferCollection bufferCollection, ShaderStage shaderStage);
|
||||
|
||||
public extern void BindTexture(TextureViewBinding textureBinding, int slot, ShaderStage shaderStage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ public class Material : Asset
|
||||
{
|
||||
private Effect _effect ~ _?.ReleaseRef();
|
||||
|
||||
private uint8[] _rawVariables ~ delete _;
|
||||
private Dictionary<String, (AssetHandle<Texture> Handle, TextureDimension Dimension, int32? groupTarget)> _textures = new .() ~ DeleteDictionaryAndKeys!(_);
|
||||
|
||||
private Dictionary<String, (AssetHandle<Texture> Handle, TextureDimension Dimension)> _textures = new .() ~ DeleteDictionaryAndKeys!(_);
|
||||
private Dictionary<StringView, BufferVariable> _variables = new .() ~ delete _;
|
||||
|
||||
private Dictionary<String, (uint32 Offset, BufferVariable Variable)> _variables = new .() ~ DeleteDictionaryAndKeys!(_);
|
||||
private BufferCollection _bufferCollection ~ _?.ReleaseRef();
|
||||
|
||||
public Effect Effect
|
||||
{
|
||||
@@ -28,36 +28,7 @@ public class Material : Asset
|
||||
if (_effect == null)
|
||||
return;
|
||||
|
||||
// TODO: get variables from effect
|
||||
decltype(_textures) newTextures = new .();
|
||||
|
||||
// Get texture slots from effect
|
||||
for(let (name, effectTexture) in _effect.Textures)
|
||||
{
|
||||
// TODO: We need to be able to define default textures in the shader.
|
||||
// At least things like "Black", "White", "Normal"
|
||||
// At best whole paths. Shouldn't be that hard to do...
|
||||
|
||||
AssetHandle<Texture> textureHandle = .Invalid;
|
||||
|
||||
if (_textures.TryGetValue(name, let oldMaterialTexture))
|
||||
{
|
||||
textureHandle = oldMaterialTexture.Handle;
|
||||
}
|
||||
|
||||
if (textureHandle.IsValid)
|
||||
{
|
||||
if (textureHandle.Dimension != effectTexture.TextureDimension)
|
||||
textureHandle = .Invalid;
|
||||
}
|
||||
|
||||
newTextures[new String(name)] = (textureHandle, effectTexture.TextureDimension);
|
||||
}
|
||||
|
||||
DeleteDictionaryAndKeys!(_textures);
|
||||
_textures = newTextures;
|
||||
|
||||
InitRawData();
|
||||
Init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,51 +42,81 @@ public class Material : Asset
|
||||
Effect = effect;
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
decltype(_textures) newTextures = new .();
|
||||
|
||||
/** @brief Initializes the raw data array for the variables.
|
||||
*/
|
||||
private void InitRawData()
|
||||
{
|
||||
uint32 bufferSize = 0;
|
||||
|
||||
decltype(_variables) newVariables = new Dictionary<String, (uint32 Offset, BufferVariable Variable)>();
|
||||
|
||||
for(let variable in _effect.Variables)
|
||||
// Get texture slots from effect
|
||||
for(let (name, effectTexture) in _effect.Textures)
|
||||
{
|
||||
newVariables.Add(new .(variable.Name), (bufferSize, variable));
|
||||
// TODO: We need to be able to define default textures in the shader.
|
||||
// At least things like "Black", "White", "Normal"
|
||||
// At best whole paths. Shouldn't be that hard to do...
|
||||
|
||||
bufferSize += variable._sizeInBytes;
|
||||
AssetHandle<Texture> textureHandle = .Invalid;
|
||||
int32? groupTarget = null;
|
||||
|
||||
if (_textures.TryGetValue(name, let oldMaterialTexture))
|
||||
{
|
||||
textureHandle = oldMaterialTexture.Handle;
|
||||
groupTarget = oldMaterialTexture.groupTarget;
|
||||
}
|
||||
|
||||
if (textureHandle.IsValid)
|
||||
{
|
||||
if (textureHandle.Dimension != effectTexture.TextureDimension)
|
||||
textureHandle = .Invalid;
|
||||
}
|
||||
|
||||
newTextures[new String(name)] = (textureHandle, effectTexture.TextureDimension, groupTarget);
|
||||
}
|
||||
|
||||
uint8[] newData = new uint8[bufferSize];
|
||||
DeleteDictionaryAndKeys!(_textures);
|
||||
_textures = newTextures;
|
||||
|
||||
for (let (newKey, newValue) in newVariables)
|
||||
//InitRawData();
|
||||
InitBuffers();
|
||||
}
|
||||
|
||||
private void InitBuffers()
|
||||
{
|
||||
_variables.Clear();
|
||||
_bufferCollection?.ReleaseRef();
|
||||
_bufferCollection = new BufferCollection();
|
||||
|
||||
void InitVariables(ConstantBuffer buffer)
|
||||
{
|
||||
if (_variables.TryGetValue(newKey, let oldEntry))
|
||||
for (BufferVariable variable in buffer.Variables)
|
||||
{
|
||||
if (oldEntry.Variable.ElementType == newValue.Variable.ElementType)
|
||||
if (_variables.ContainsKey(variable.Name))
|
||||
{
|
||||
int elementSize = newValue.Variable.ElementType.ElementSizeInBytes();
|
||||
|
||||
for (int r = 0; r < Math.Min(oldEntry.Variable.Rows, newValue.Variable.Rows); r++)
|
||||
for (int c = 0; c < Math.Min(oldEntry.Variable.Columns, newValue.Variable.Columns); c++)
|
||||
{
|
||||
int oldElementIndex = r * oldEntry.Variable.Columns + c;
|
||||
int newElementIndex = r * newValue.Variable.Columns + c;
|
||||
|
||||
Internal.MemCpy(newData.Ptr + (newValue.Offset + elementSize * oldElementIndex),
|
||||
_rawVariables.Ptr + (oldEntry.Offset + elementSize * newElementIndex), elementSize);
|
||||
}
|
||||
// TODO: Handle overlapping variable names?
|
||||
Log.EngineLogger.Error("Variable with same name already added to Material, skipping...");
|
||||
continue;
|
||||
}
|
||||
// TODO: we could try to convert e.g. Int <-> Float
|
||||
|
||||
_variables.Add(variable.Name, variable);
|
||||
}
|
||||
}
|
||||
|
||||
delete _rawVariables;
|
||||
_rawVariables = newData;
|
||||
for (let (bufferName, buffer) in _effect.Buffers)
|
||||
{
|
||||
if (buffer == null)
|
||||
continue;
|
||||
|
||||
DeleteDictionaryAndKeys!(_variables);
|
||||
_variables = newVariables;
|
||||
if (ConstantBuffer parentConstBuffer = buffer as ConstantBuffer)
|
||||
{
|
||||
using (OverridingConstantBuffer childConstBuffer = new OverridingConstantBuffer(parentConstBuffer))
|
||||
{
|
||||
_bufferCollection.Add(@bufferName.Index, childConstBuffer.Name, childConstBuffer);
|
||||
InitVariables(childConstBuffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Error("Found buffer in constant buffer collection that is not a constant buffer.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +125,8 @@ public class Material : Asset
|
||||
public void Bind()
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
|
||||
// TODO: Bind textures, don't go through effect for that
|
||||
for(let (name, texture) in _textures)
|
||||
{
|
||||
switch (texture.Dimension)
|
||||
@@ -142,20 +144,30 @@ public class Material : Asset
|
||||
}
|
||||
}
|
||||
|
||||
for(let (name, variable) in _variables)
|
||||
for (let (bufferName, buffer) in _bufferCollection)
|
||||
{
|
||||
variable.Variable.SetRawData(RawPointer!<uint8>(variable.Offset));
|
||||
if (let cbuffer = buffer as ConstantBuffer)
|
||||
{
|
||||
TrySilent!(cbuffer.Apply());
|
||||
}
|
||||
}
|
||||
|
||||
_effect.ApplyChanges();
|
||||
/*for(let (name, variable) in _variables)
|
||||
{
|
||||
variable.Variable.SetRawData(RawPointer!<uint8>(variable.Offset));
|
||||
}*/
|
||||
|
||||
//_effect.ApplyChanges();
|
||||
_effect.Bind();
|
||||
|
||||
RenderCommand.BindConstantBuffers(_bufferCollection);
|
||||
}
|
||||
|
||||
/** @brief Sets a texture of the material.
|
||||
* @param name The name of the texture to set.
|
||||
* @param texture The texture to bind to the effect.
|
||||
*/
|
||||
public void SetTexture(String name, AssetHandle<Texture> texture)
|
||||
public void SetTexture(String name, AssetHandle<Texture> texture, int32? groupTargetIndex = null)
|
||||
{
|
||||
if(_textures.TryGetValue(name, var entry))
|
||||
{
|
||||
@@ -174,6 +186,7 @@ public class Material : Asset
|
||||
}*/
|
||||
//entry?.ReleaseRef();
|
||||
_textures[name].Handle = texture;
|
||||
_textures[name].groupTarget = groupTargetIndex;
|
||||
//texture?.AddRef();
|
||||
}
|
||||
else
|
||||
@@ -183,135 +196,41 @@ public class Material : Asset
|
||||
}
|
||||
}
|
||||
|
||||
private mixin RawPointer<T>(uint32 offset)
|
||||
private mixin SetVariable(String name, var value)
|
||||
{
|
||||
(T*)(&_rawVariables[offset])
|
||||
}
|
||||
|
||||
[Inline]
|
||||
private void SetVariable<T>(String name, T value) where T : struct
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<T>();
|
||||
|
||||
*RawPointer!<T>(entry.Offset) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
entry.SetData(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariable(String name, bool value) => SetVariable<bool>(name, value);
|
||||
public void SetVariable(String name, bool2 value) => SetVariable<bool2>(name, value);
|
||||
public void SetVariable(String name, bool3 value) => SetVariable<bool3>(name, value);
|
||||
public void SetVariable(String name, bool4 value) => SetVariable<bool4>(name, value);
|
||||
public void SetVariable(String name, bool value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, bool2 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, bool3 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, bool4 value) => SetVariable!(name, value);
|
||||
|
||||
public void SetVariable(String name, int32 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, int2 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, int3 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, int4 value) => SetVariable!(name, value);
|
||||
|
||||
public void SetVariable(String name, int32 value) => SetVariable<int32>(name, value);
|
||||
public void SetVariable(String name, int2 value) => SetVariable<int2>(name, value);
|
||||
public void SetVariable(String name, int3 value) => SetVariable<int3>(name, value);
|
||||
public void SetVariable(String name, int4 value) => SetVariable<int4>(name, value);
|
||||
public void SetVariable(String name, uint32 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, uint2 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, uint3 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, uint4 value) => SetVariable!(name, value);
|
||||
|
||||
public void SetVariable(String name, uint32 value) => SetVariable<uint32>(name, value);
|
||||
public void SetVariable(String name, uint2 value) => SetVariable<uint2>(name, value);
|
||||
public void SetVariable(String name, uint3 value) => SetVariable<uint3>(name, value);
|
||||
public void SetVariable(String name, uint4 value) => SetVariable<uint4>(name, value);
|
||||
public void SetVariable(String name, float value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, float2 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, float3 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, float4 value) => SetVariable!(name, value);
|
||||
|
||||
public void SetVariable(String name, float value) => SetVariable<float>(name, value);
|
||||
public void SetVariable(String name, float2 value) => SetVariable<float2>(name, value);
|
||||
public void SetVariable(String name, float3 value) => SetVariable<float3>(name, value);
|
||||
public void SetVariable(String name, float4 value) => SetVariable<float4>(name, value);
|
||||
public void SetVariable(String name, Color value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, ColorRGB value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, ColorRGBA value) => SetVariable!(name, value);
|
||||
|
||||
/*public void SetVariable(String name, float value) => SetVariable<double>(name, value);
|
||||
public void SetVariable(String name, float2 value) => SetVariable<float2>(name, value);
|
||||
public void SetVariable(String name, float3 value) => SetVariable<float3>(name, value);
|
||||
public void SetVariable(String name, float4 value) => SetVariable<float4>(name, value);*/
|
||||
|
||||
public void SetVariable(String name, Color value) => SetVariable<ColorRGBA>(name, (ColorRGBA)value);
|
||||
public void SetVariable(String name, ColorRGB value) => SetVariable<ColorRGB>(name, value);
|
||||
public void SetVariable(String name, ColorRGBA value) => SetVariable<ColorRGBA>(name, value);
|
||||
|
||||
public void SetVariable(String name, Matrix3x3 value)
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<Matrix3x3>();
|
||||
|
||||
// TODO: I'm not sure how to handle Matrix3x3
|
||||
// It seems to be 44 Bytes (11 Floats) large.
|
||||
Log.EngineLogger.AssertDebug(entry.Variable._sizeInBytes == 44, "Made wrong assumption about the size of float3x3 in a hlsl constant-buffer.");
|
||||
|
||||
#unwarn
|
||||
*RawPointer!<float[11]>(entry.Offset) = *(float[11]*)&Matrix4x3(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariable(String name, Matrix3x3[] values)
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<Matrix3x3>();
|
||||
|
||||
int count = Math.Min(values.Count, entry.Variable._arrayElements);
|
||||
|
||||
for(int i < count)
|
||||
{
|
||||
(RawPointer!<Matrix4x3>(entry.Offset))[i] = Matrix4x3(values[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetVariable(String name, Matrix4x3 value) => SetVariable<Matrix4x3>(name, value);
|
||||
public void SetVariable(String name, Matrix value) => SetVariable<Matrix>(name, value);
|
||||
|
||||
public void SetVariable(String name, Matrix[] values)
|
||||
{
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<Matrix>();
|
||||
|
||||
Internal.MemCpy(RawPointer!<Matrix>(entry.Offset), values.Ptr, sizeof(Matrix) * Math.Min(values.Count, entry.Variable._arrayElements));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.Assert(false, scope $"The effect doesn't contain a variable named \"{name}\"");
|
||||
}
|
||||
}
|
||||
|
||||
// Supporeted types
|
||||
// Bool, Bool2, Bool3, Bool4
|
||||
// Int, int2, int3, int4
|
||||
// UInt, UInt2, UInt3, UInt4
|
||||
// Color, ColorRGB, ColorRGBA
|
||||
// Float, Float2, Float3, Float4
|
||||
// Matrix3x3, Matrix4x3, Matrix
|
||||
|
||||
// TODO: Add missing variable types
|
||||
// Half, Half2, Half3, Half4
|
||||
// Byte, Byte2, Byte3, Byte4
|
||||
|
||||
/**
|
||||
* Sets the raw data of the variable.
|
||||
* @param rawData The pointer to the raw data. If rawData is null the raw data will be set to zero.
|
||||
*/
|
||||
internal void SetRawData(uint32 offset, void* rawData, uint32 byteCount)
|
||||
{
|
||||
if(rawData != null)
|
||||
Internal.MemCpy(&_rawVariables + offset, rawData, byteCount);
|
||||
else
|
||||
Internal.MemSet(&_rawVariables + offset, 0, byteCount);
|
||||
}
|
||||
public void SetVariable(String name, Matrix3x3 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, Matrix4x3 value) => SetVariable!(name, value);
|
||||
public void SetVariable(String name, Matrix value) => SetVariable!(name, value);
|
||||
|
||||
public void GetVariable<T>(String name, out T value) where T : struct
|
||||
{
|
||||
@@ -319,9 +238,10 @@ public class Material : Asset
|
||||
|
||||
if(_variables.TryGetValue(name, let entry))
|
||||
{
|
||||
entry.Variable.EnsureTypeMatch<T>();
|
||||
|
||||
value = *RawPointer!<T>(entry.Offset);
|
||||
entry.EnsureTypeMatch<T>();
|
||||
|
||||
// TODO: This obviously breaks for all cases where a custom SetData was necessary.
|
||||
value = *(T*)entry.firstByte;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
|
||||
namespace GlitchyEngine.Renderer;
|
||||
|
||||
using internal GlitchyEngine.Renderer;
|
||||
|
||||
class OverridingConstantBuffer : ConstantBuffer
|
||||
{
|
||||
protected ConstantBuffer _parent;
|
||||
|
||||
protected int _parentGeneration = 0;
|
||||
|
||||
public ConstantBuffer Parent => _parent;
|
||||
|
||||
public this(ConstantBuffer parent) : base(parent.Name, parent.RawData.Length)
|
||||
{
|
||||
Log.EngineLogger.AssertDebug(parent != null);
|
||||
_parent = parent;
|
||||
|
||||
InheritVariables();
|
||||
}
|
||||
|
||||
private void InheritVariables()
|
||||
{
|
||||
for (BufferVariable parentVariable in _parent.Variables)
|
||||
{
|
||||
BufferVariable newVariable = new BufferVariable(parentVariable.Name, this, parentVariable.ElementType, parentVariable.Columns,
|
||||
parentVariable.Rows, parentVariable.Offset, parentVariable._sizeInBytes, parentVariable.ArrayElements, parentVariable.IsUsed);
|
||||
|
||||
if (parentVariable.Flags.HasFlag(.Locked))
|
||||
{
|
||||
Enum.SetFlag(ref newVariable.[Friend]_flags, .Readonly | .Locked);
|
||||
}
|
||||
|
||||
// Default to using the value from the parent buffer.
|
||||
Enum.SetFlag(ref newVariable.[Friend]_flags, .Unset);
|
||||
|
||||
_variables.Add(newVariable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the date to the GPU.
|
||||
* @returns true if the GPU buffer was updated, false otherwise (i.e. it wasn't dirty).
|
||||
*/
|
||||
public override Result<void> Apply()
|
||||
{
|
||||
Result<void> parentChangedResult = _parent.Apply();
|
||||
|
||||
if (parentChangedResult case .Err)
|
||||
return .Err;
|
||||
|
||||
bool isDirty = false;
|
||||
|
||||
// If the parent got a newer generation then it was changed since our last apply.
|
||||
if (_parentGeneration != _parent._generation)
|
||||
{
|
||||
uint8[] newData = scope uint8[rawData.Count];
|
||||
|
||||
isDirty = true;
|
||||
_parent.RawData.CopyTo(newData);
|
||||
|
||||
for (BufferVariable variable in _variables)
|
||||
{
|
||||
Enum.ClearFlag(ref variable.[Friend]_flags, .Dirty);
|
||||
// TODO: Check if our variable is
|
||||
|
||||
if (!variable.Flags.HasFlag(.Unset))
|
||||
{
|
||||
Internal.MemCpy(newData.Ptr + variable.Offset, variable.firstByte, variable._sizeInBytes);
|
||||
}
|
||||
}
|
||||
|
||||
newData.CopyTo(rawData);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (BufferVariable variable in _variables)
|
||||
{
|
||||
if (variable.IsDirty)
|
||||
{
|
||||
isDirty = true;
|
||||
Enum.ClearFlag(ref variable.[Friend]_flags, .Dirty);
|
||||
|
||||
if (variable.Flags.HasFlag(.Unset))
|
||||
{
|
||||
// If it is unset, we copy the value from the parent buffer into ourselves.
|
||||
Internal.MemCpy(variable.firstByte, _parent.rawData.Ptr + variable.Offset, variable._sizeInBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isDirty)
|
||||
{
|
||||
Result<void> setDataResult = PlatformSetData(rawData.Ptr, (uint32)rawData.Count, 0, .WriteDiscard);
|
||||
|
||||
if (setDataResult case .Err)
|
||||
return .Err;
|
||||
|
||||
_generation++;
|
||||
}
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
}
|
||||
@@ -129,6 +129,11 @@ namespace GlitchyEngine.Renderer
|
||||
_rendererAPI.BindConstantBuffer(buffer, slot, stage);
|
||||
}
|
||||
|
||||
public static void BindConstantBuffers(BufferCollection constantBuffers, ShaderStage stage = .All)
|
||||
{
|
||||
_rendererAPI.BindConstantBuffers(constantBuffers, stage);
|
||||
}
|
||||
|
||||
public static void BindVertexShader(VertexShader vertexShader)
|
||||
{
|
||||
_rendererAPI.BindVertexShader(vertexShader);
|
||||
@@ -138,5 +143,10 @@ namespace GlitchyEngine.Renderer
|
||||
{
|
||||
_rendererAPI.BindPixelShader(pixelShader);
|
||||
}
|
||||
|
||||
public static void BindTexture(TextureViewBinding textureBinding, int slot, ShaderStage shaderStage)
|
||||
{
|
||||
_rendererAPI.BindTexture(textureBinding, slot, shaderStage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +132,7 @@ namespace GlitchyEngine.Renderer
|
||||
#endif
|
||||
|
||||
private static AssetHandle<Effect> s_quadBatchEffect;
|
||||
private static Material s_quadBatchMaterial ~ _?.ReleaseRef();
|
||||
private static AssetHandle<Effect> s_circleBatchEffect;
|
||||
private static AssetHandle<Effect> s_lineBatchEffect;
|
||||
|
||||
@@ -162,7 +163,7 @@ namespace GlitchyEngine.Renderer
|
||||
private static DrawOrder s_drawOrder;
|
||||
|
||||
/// The effect that is currently used to draw the sprites.
|
||||
private static AssetHandle<Effect> s_currentQuadEffect;
|
||||
//private static AssetHandle<Effect> s_currentQuadEffect;
|
||||
private static AssetHandle<Effect> s_currentCircleEffect;
|
||||
private static AssetHandle<Effect> s_currentLineEffect;
|
||||
|
||||
@@ -185,6 +186,7 @@ namespace GlitchyEngine.Renderer
|
||||
Debug.Profiler.ProfileFunction!();
|
||||
|
||||
s_quadBatchEffect = Content.LoadAsset("Resources/Shaders/spritebatch.hlsl", null, true);
|
||||
s_quadBatchMaterial = new Material(s_quadBatchEffect);
|
||||
s_circleBatchEffect = Content.LoadAsset("Resources/Shaders/circlebatch.hlsl", null, true);
|
||||
s_lineBatchEffect = Content.LoadAsset("Resources/Shaders/linebatch.hlsl", null, true);
|
||||
}
|
||||
@@ -455,7 +457,7 @@ namespace GlitchyEngine.Renderer
|
||||
}
|
||||
|
||||
// TODO: remove?
|
||||
public static void BeginScene(OldCamera camera, DrawOrder drawOrder = .SortByTexture, AssetHandle<Effect> effect = .Invalid, AssetHandle<Effect> circleEffect = .Invalid)
|
||||
public static void BeginScene(OldCamera camera, DrawOrder drawOrder = .SortByTexture)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
#if DEBUG
|
||||
@@ -463,28 +465,29 @@ namespace GlitchyEngine.Renderer
|
||||
Log.EngineLogger.AssertDebug(!s_sceneRunning, "You have to call EndScene before you can make another call to BeginScene.");
|
||||
#endif
|
||||
|
||||
if(effect != .Invalid)
|
||||
/*if(effect != .Invalid)
|
||||
{
|
||||
s_currentQuadEffect = effect;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_currentQuadEffect = s_quadBatchEffect;
|
||||
}
|
||||
}*/
|
||||
|
||||
if(circleEffect != .Invalid)
|
||||
/*if(circleEffect != .Invalid)
|
||||
{
|
||||
s_currentCircleEffect = circleEffect;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_currentCircleEffect = s_circleBatchEffect;
|
||||
}
|
||||
}*/
|
||||
|
||||
s_currentLineEffect = s_lineBatchEffect;
|
||||
|
||||
s_currentQuadEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
|
||||
s_currentCircleEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
|
||||
//s_currentQuadEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
|
||||
s_quadBatchMaterial.SetVariable("ViewProjection", camera.ViewProjection);
|
||||
//s_currentCircleEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
|
||||
|
||||
s_drawOrder = drawOrder;
|
||||
|
||||
@@ -493,7 +496,7 @@ namespace GlitchyEngine.Renderer
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void BeginScene(Camera camera, Matrix transform, DrawOrder drawOrder = .SortByTexture, AssetHandle<Effect> effect = .Invalid, AssetHandle<Effect> circleEffect = .Invalid)
|
||||
public static void BeginScene(Camera camera, Matrix transform, DrawOrder drawOrder = .SortByTexture)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
#if DEBUG
|
||||
@@ -501,29 +504,30 @@ namespace GlitchyEngine.Renderer
|
||||
Log.EngineLogger.AssertDebug(!s_sceneRunning, "You have to call EndScene before you can make another call to BeginScene.");
|
||||
#endif
|
||||
|
||||
if(effect != .Invalid)
|
||||
/*if(effect != .Invalid)
|
||||
{
|
||||
s_currentQuadEffect = effect;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_currentQuadEffect = s_quadBatchEffect;
|
||||
}
|
||||
}*/
|
||||
|
||||
if(circleEffect != .Invalid)
|
||||
/*if(circleEffect != .Invalid)
|
||||
{
|
||||
s_currentCircleEffect = circleEffect;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_currentCircleEffect = s_circleBatchEffect;
|
||||
}
|
||||
}*/
|
||||
|
||||
s_currentLineEffect = s_lineBatchEffect;
|
||||
|
||||
Matrix viewProjection = camera.Projection * Matrix.Invert(transform);
|
||||
|
||||
s_currentQuadEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
|
||||
|
||||
s_quadBatchMaterial.SetVariable("ViewProjection", viewProjection);
|
||||
//s_currentQuadEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentCircleEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentLineEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
|
||||
|
||||
@@ -534,7 +538,7 @@ namespace GlitchyEngine.Renderer
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void BeginScene(EditorCamera camera, DrawOrder drawOrder = .SortByTexture, AssetHandle<Effect> effect = .Invalid, AssetHandle<Effect> circleEffect = .Invalid)
|
||||
public static void BeginScene(EditorCamera camera, DrawOrder drawOrder = .SortByTexture)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
#if DEBUG
|
||||
@@ -542,7 +546,7 @@ namespace GlitchyEngine.Renderer
|
||||
Log.EngineLogger.AssertDebug(!s_sceneRunning, "You have to call EndScene before you can make another call to BeginScene.");
|
||||
#endif
|
||||
|
||||
if(effect != .Invalid)
|
||||
/*if(effect != .Invalid)
|
||||
{
|
||||
s_currentQuadEffect = effect;
|
||||
}
|
||||
@@ -558,13 +562,14 @@ namespace GlitchyEngine.Renderer
|
||||
else
|
||||
{
|
||||
s_currentCircleEffect = s_circleBatchEffect;
|
||||
}
|
||||
}*/
|
||||
|
||||
s_currentLineEffect = s_lineBatchEffect;
|
||||
|
||||
Matrix viewProjection = camera.Projection * camera.View;
|
||||
|
||||
s_currentQuadEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
|
||||
//s_currentQuadEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_quadBatchMaterial.SetVariable("ViewProjection", viewProjection);
|
||||
s_currentCircleEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
|
||||
s_currentLineEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
|
||||
|
||||
@@ -623,7 +628,7 @@ namespace GlitchyEngine.Renderer
|
||||
s_statistics.LineCount++;
|
||||
}
|
||||
|
||||
private static void FlushQuadInstances()
|
||||
private static void FlushQuadInstances(Texture texture)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
@@ -632,8 +637,24 @@ namespace GlitchyEngine.Renderer
|
||||
|
||||
s_quadInstanceBuffer.SetData<QuadBatchVertex>(s_rawQuadInstances.Ptr, s_setQuadInstances, 0, .WriteDiscard);
|
||||
|
||||
s_currentQuadEffect.ApplyChanges();
|
||||
s_currentQuadEffect.Bind();
|
||||
//s_currentQuadEffect.ApplyChanges();
|
||||
//s_currentQuadEffect.Bind();
|
||||
s_quadBatchMaterial.Bind();
|
||||
|
||||
using (TextureViewBinding tvb = texture.GetViewBinding())
|
||||
{
|
||||
if (s_quadBatchMaterial.Effect.Textures.TryGetValue("Texture", let textureEntry))
|
||||
{
|
||||
if (textureEntry.PsSlot != null)
|
||||
{
|
||||
RenderCommand.BindTexture(tvb, textureEntry.PsSlot.Index, .Pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//s_quadBatchMaterial.Effect.Textures["Texture"]
|
||||
//
|
||||
|
||||
s_quadBatchBinding.InstanceCount = s_setQuadInstances;
|
||||
s_quadBatchBinding.Bind();
|
||||
RenderCommand.DrawIndexedInstanced(s_quadBatchBinding);
|
||||
@@ -778,13 +799,13 @@ namespace GlitchyEngine.Renderer
|
||||
// TODO: per object blendstate
|
||||
RenderCommand.SetBlendState(s_transparentBlendState);
|
||||
|
||||
let quadEffect = s_currentQuadEffect.Get();
|
||||
let quadMaterial = s_quadBatchMaterial;//s_currentQuadEffect.Get();
|
||||
|
||||
if (quadEffect == null)
|
||||
if (quadMaterial == null)
|
||||
return;
|
||||
|
||||
Texture texture = s_QuadinstanceQueue[0].Texture;
|
||||
quadEffect.SetTexture("Texture", texture);
|
||||
//quadMaterial.SetTexture("Texture", .Invalid);
|
||||
|
||||
s_setQuadInstances = 0;
|
||||
|
||||
@@ -795,21 +816,21 @@ namespace GlitchyEngine.Renderer
|
||||
// flush every time the texture changes
|
||||
if(quad.Texture != texture)
|
||||
{
|
||||
FlushQuadInstances();
|
||||
FlushQuadInstances(texture);
|
||||
|
||||
texture = quad.Texture;
|
||||
quadEffect.SetTexture("Texture", texture);
|
||||
//quadMaterial.SetTexture("Texture", .Invalid);
|
||||
}
|
||||
|
||||
s_rawQuadInstances[s_setQuadInstances++] = .(quad.Transform, quad.Color, quad.uvTransform, quad.entityId);
|
||||
|
||||
if(s_setQuadInstances == s_rawQuadInstances.Count)
|
||||
{
|
||||
FlushQuadInstances();
|
||||
FlushQuadInstances(texture);
|
||||
}
|
||||
}
|
||||
|
||||
FlushQuadInstances();
|
||||
FlushQuadInstances(texture);
|
||||
|
||||
s_QuadinstanceQueue.Clear();
|
||||
}
|
||||
|
||||
@@ -68,5 +68,9 @@ namespace GlitchyEngine.Renderer
|
||||
public extern void BindVertexShader(VertexShader vertexShader);
|
||||
|
||||
public extern void BindPixelShader(PixelShader pixelShader);
|
||||
|
||||
public extern void BindConstantBuffers(BufferCollection bufferCollection, ShaderStage shaderStage);
|
||||
|
||||
public extern void BindTexture(TextureViewBinding textureBinding, int slot, ShaderStage shaderStage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,7 +560,7 @@ namespace GlitchyEngine.Renderer.Text
|
||||
|
||||
public static void DrawText(PreparedText text, Matrix transform, ColorRGBA fontColor = .White)
|
||||
{
|
||||
Debug.Profiler.ProfileRendererFunction!();
|
||||
/*Debug.Profiler.ProfileRendererFunction!();
|
||||
|
||||
text.AddRef();
|
||||
defer text.ReleaseRef();
|
||||
@@ -654,7 +654,7 @@ namespace GlitchyEngine.Renderer.Text
|
||||
for(int i < atlasses.Count)
|
||||
{
|
||||
atlasses[i].ReleaseRef();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user