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
@@ -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 internal GlitchyEngine.Renderer;
using internal GlitchyEngine.Platform.DX11;
using System;
using GlitchyEngine.Renderer;
using DirectX.D3D11;
using DirectX.D3DCompiler;
using GlitchyEngine.Platform.DX11;
using GlitchyEngine.Content;
using DirectX.Common;
using internal GlitchyEngine.Renderer;
using internal GlitchyEngine.Platform.DX11;
namespace GlitchyEngine.Renderer
{
@@ -115,6 +127,40 @@ namespace GlitchyEngine.Renderer
*/
internal ID3DBlob* nativeCode ~ _?.Release();
protected override Result<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 |
#if DEBUG
.Debug;
@@ -29,5 +29,7 @@ namespace GlitchyEngine.Renderer
_nativeShaderResourceView?.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);
}
/// This should happen during shader compilation!
/// Validates or gets the validated input layout for the given vertexshader.
internal ID3D11InputLayout* GetNativeVertexLayout(ID3DBlob* vertexShaderCode)
{
+2 -1
View File
@@ -38,8 +38,9 @@ namespace GlitchyEngine.Renderer
[Inline]
internal uint8* firstByte => _constantBuffer.rawData.CArray() + _offset;
public this(ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 elements, bool isUsed)
public this(StringView name, ConstantBuffer constantBuffer, ShaderVariableType type, uint32 columns, uint32 rows, uint32 offset, uint32 sizeInBytes, uint32 elements, bool isUsed)
{
_name = new String(name);
_constantBuffer = constantBuffer..AddRef();
_type = type;
_columns = columns;
+17 -2
View File
@@ -74,13 +74,28 @@ namespace GlitchyEngine.Renderer
public BufferVariableCollection Variables => _variables;
/// Gets a span to the rawData held on the CPU.
public Span<uint8> RawData => rawData;
protected this() {}
public this(StringView name, int64 size)
{
_name = new String(name);
rawData = new uint8[size];
ConstructBuffer();
}
protected internal void AddVariable(BufferVariable ownVariable)
{
_variables.Add(ownVariable);
}
public void AddVariable(StringView name, uint64 offset, uint64 sizeInBytes, bool isUsed, ShaderVariableType type, uint8 rows, uint8 columns, uint64 arraySize)
{
_variables.Add(new BufferVariable(name, this, type, columns, rows, (uint32)offset, (uint32)sizeInBytes, (uint32)arraySize, isUsed));
}
/**
* Construct the buffer description.
*/
@@ -96,9 +111,9 @@ namespace GlitchyEngine.Renderer
/**
* Uploads the date to the GPU.
*/
public void Update()
public Result<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;
@@ -99,7 +99,8 @@ public class Effect : Asset
MergeResources();
}
[Obsolete("", false)]
public this(Stream data, StringView assetIdentifier, IContentManager contentManager)
{
Debug.Profiler.ProfileResourceFunction!();
@@ -115,6 +116,13 @@ public class Effect : Asset
MergeResources();
}
public this()
{
_bufferCollection = new BufferCollection();
_variables = new BufferVariableCollection(false);
_textures = new Dictionary<String, TextureEntry>();
}
public ~this()
{
Debug.Profiler.ProfileResourceFunction!();
@@ -668,7 +676,7 @@ public class Effect : Asset
}
// save entry
_textures[shaderEntry.Name] = entry;
_textures[new String(shaderEntry.Name)] = entry;
}
}
}
@@ -8,5 +8,7 @@ namespace GlitchyEngine.Renderer
[AllowAppend]
public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null)
: base(code, fileName, entryPoint, contentManager, macros) { }
public this() : base() { }
}
}
+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 ShaderTextureCollection _textures ~ delete _;
protected ShaderType _shaderType;
public BufferCollection Buffers => _buffers;
public ShaderTextureCollection Textures => _textures;
public ShaderType ShaderType => _shaderType;
[AllowAppend]
public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager, ShaderDefine[] macros = null)
{
@@ -43,24 +56,49 @@ namespace GlitchyEngine.Renderer
CompileFromSource(code, fileName, entryPoint, contentManager);
}
public this()
{
_buffers = new BufferCollection();
_textures = new ShaderTextureCollection();
}
public static Result<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()
{
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);
protected abstract Result<void> InternalCreateFromBlob(Span<uint8> blob);
}
}
@@ -38,6 +38,8 @@ namespace GlitchyEngine.Renderer
}
// TODO: finish implementation (like BufferCollection)
public ResourceEntry* this[int idx] => _idxToBuf[idx];
public ResourceEntry* this[String name] => _strToBuf[name];
public void Add(String name, uint32 index, TextureViewBinding texture, TextureDimension dimension)
{
@@ -2,6 +2,7 @@ using System;
namespace GlitchyEngine.Renderer
{
// TODO: I hate this. It is a reference counting struct?!
/// Represents a reference to a texture that can be used as shader input resource.
public struct TextureViewBinding : IRefCounted, IDisposable
{
@@ -11,6 +12,8 @@ namespace GlitchyEngine.Renderer
public extern void AddRef();
public extern void Release();
public static extern TextureViewBinding CreateDefault();
public void Dispose() => Release();
}
}
@@ -8,5 +8,7 @@ namespace GlitchyEngine.Renderer
[AllowAppend]
public this(StringView code, StringView? fileName, String entryPoint, IContentManager contentManager = null, ShaderDefine[] macros = null)
: base(code, fileName, entryPoint, contentManager, macros) { }
public this() : base() { }
}
}