Materials kind of working and used in some places

- Also Texture viewer fixes
This commit is contained in:
Simon Lübeß
2025-02-09 01:39:35 +01:00
parent acfb052137
commit 76087d6ba4
21 changed files with 572 additions and 322 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
FileVersion = 1 FileVersion = 1
Projects = {GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}, box2d-beef = {Path = "GlitchyEngine/vendor/box2D"}, "Beef.Linq" = {Path = "GlitchyEngine/vendor/Beef.Linq/src"}, ScriptCore = {Path = "ScriptCore"}} Projects = {GlitchyEngine = {Path = "GlitchyEngine"}, GlitchLog = {Path = "GlitchLog"}, DirectX = {Path = "GlitchyEngine/vendor/directx/DirectX"}, LodePng = {Path = "vendor/lodepng-beef/lodepng-beef"}, FreeType = {Path = "GlitchyEngine/vendor/freetype"}, cgltf-beef = {Path = "GlitchyEngine/vendor/gltf/cgltf-beef"}, GlitchyEditor = {Path = "GlitchyEditor"}, msdfgen-beef = {Path = "GlitchyEngine/vendor/msdfgen/msdfgen-beef"}, ImGui = {Path = "GlitchyEngine/vendor/imgui/ImGui"}, ImGuiImplDX11 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplDX11"}, ImGuiImplWin32 = {Path = "GlitchyEngine/vendor/imgui/ImGuiImplWin32"}, ImGuizmo = {Path = "GlitchyEngine/vendor/imgui/ImGuizmo"}, GlitchyEngineHelper = {Path = "GlitchyEngineHelper"}, bon = {Path = "GlitchyEngine/vendor/bon"}, box2d-beef = {Path = "GlitchyEngine/vendor/box2D"}, "Beef.Linq" = {Path = "GlitchyEngine/vendor/Beef.Linq/src"}, ScriptCore = {Path = "ScriptCore"}}
WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper", "ScriptCore"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"]} WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngineHelper", "ScriptCore"], "GlitchyEngine/Dependencies" = ["cgltf-beef", "DirectX", "FreeType", "ImGui", "ImGuiImplDX11", "ImGuiImplWin32", "ImGuizmo", "LodePng", "msdfgen-beef", "bon", "box2d-beef", "Beef.Linq"], Beef = ["Beefy2D", "corlib", "MiniZ"]}
[Workspace] [Workspace]
StartupProject = "GlitchyEditor" StartupProject = "GlitchyEditor"
+3
View File
@@ -7,6 +7,9 @@ TargetType = "BeefGUIApplication"
StartupObject = "GlitchyEngine.Program" StartupObject = "GlitchyEngine.Program"
ProcessorMacros = ["GE_EDITOR_IMGUI_DEMO"] ProcessorMacros = ["GE_EDITOR_IMGUI_DEMO"]
[Platform.Windows]
IconFile = "$(ProjectDir)/Resources/Textures/GlitchyEngineIcon.ico"
[Configs.Debug.Win64] [Configs.Debug.Win64]
PostBuildCmds = ["CopyFilesIfNewer(\"$(WorkspaceDir)/bin/vswhere.exe\", \"$(TargetDir)\")"] PostBuildCmds = ["CopyFilesIfNewer(\"$(WorkspaceDir)/bin/vswhere.exe\", \"$(TargetDir)\")"]
DebugCommandArguments = "\"D:\\Development\\Git\\SingleStateToOrbit\"" DebugCommandArguments = "\"D:\\Development\\Git\\SingleStateToOrbit\""
@@ -84,7 +84,7 @@ class MaterialProcessor : IAssetProcessor
{ {
Log.EngineLogger.Error("The buffers of a material must be ConstantBuffers."); Log.EngineLogger.Error("The buffers of a material must be ConstantBuffers.");
continue; continue;
// TODO: Why even allow any kind of Buffer for Materials? Will this make sense later if we can create and bind Buffers from C#? // TODO: Why even allow any other kind of Buffer for Materials? Will this make sense later if we can create and bind Buffers from C#?
} }
Span<uint8> data = processedMaterial.CloneBuffer(buffer.Name, cBuffer); Span<uint8> data = processedMaterial.CloneBuffer(buffer.Name, cBuffer);
+83 -52
View File
@@ -14,7 +14,7 @@ class AssetViewer : EditorWindow
private AssetHandle _selectedAsset; private AssetHandle _selectedAsset;
append TexturererViewerer _textureViewer = .(); append TextureViewer _textureViewer = .();
public this(EditorContentManager contentManager) public this(EditorContentManager contentManager)
{ {
@@ -133,7 +133,7 @@ class AssetViewer : EditorWindow
} }
} }
class TexturererViewerer class TextureViewer
{ {
enum BackgroundMode : int32 enum BackgroundMode : int32
{ {
@@ -160,7 +160,8 @@ class TexturererViewerer
} }
AssetHandle<Effect> _effect; AssetHandle<Effect> _effect;
AssetHandle<Effect> _renderTargetEffect; //AssetHandle<Effect> _renderTargetEffect;
Material _renderTargetMaterial ~ _.ReleaseRef();
float _zoom = 1.0f; float _zoom = 1.0f;
@@ -169,14 +170,28 @@ class TexturererViewerer
SampleMode _sampleMode = .Linear; SampleMode _sampleMode = .Linear;
RenderTarget2D _target ~ _?.ReleaseRef(); RenderTargetGroup _targets ~ _?.ReleaseRef();
/*RenderTarget2D _target ~ _?.ReleaseRef();
RenderTarget2D _idTarget ~ _?.ReleaseRef();
// TODO: we don't need depth! // TODO: we don't need depth!
DepthStencilTarget _depth ~ _?.ReleaseRef(); DepthStencilTarget _depth ~ _?.ReleaseRef();*/
public this() public this()
{ {
_effect = Content.LoadAsset("Resources/Shaders/textureViewerShader.hlsl", null, true); _effect = Content.LoadAsset("Resources/Shaders/textureViewerShader.hlsl", null, true);
_renderTargetEffect = Content.LoadAsset("Resources/Shaders/RenderTargetGroupViewer.hlsl", null, true); AssetHandle<Effect> effect = Content.LoadAsset("Resources/Shaders/RenderTargetGroupViewer.hlsl", null, true);
_renderTargetMaterial = new Material(effect);
_targets = new RenderTargetGroup(.(){
Width = 100,
Height = 100,
ColorTargetDescriptions = TargetDescription[](
.(.R8G8B8A8_UNorm, clearColor: .Color(ColorRGBA.Pink)),
.(.R32_UInt)
),
DepthTargetDescription = .(.D24_UNorm_S8_UInt)
});
} }
float2 _position; float2 _position;
@@ -215,7 +230,8 @@ class TexturererViewerer
if (_backgroundMode == .CustomColor) if (_backgroundMode == .CustomColor)
{ {
ImGui.ColorPicker4("Color", ref _backgroundColor); ImGui.ColorPicker3("Color", ref _backgroundColor);
_backgroundColor.A = 1.0f;
} }
} }
@@ -366,20 +382,16 @@ class TexturererViewerer
viewportSize.x = Math.Max(viewportSize.x, 1); viewportSize.x = Math.Max(viewportSize.x, 1);
viewportSize.y = Math.Max(viewportSize.y, 1); viewportSize.y = Math.Max(viewportSize.y, 1);
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height) if (_targets.Width != viewportSize.x || _targets.Height != viewportSize.y)
{ {
_target?.ReleaseRef(); _targets.Resize((.)viewportSize.x, (.)viewportSize.y);
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm_SRGB, (.)viewportSize.x, (.)viewportSize.y));
_target.SamplerState = SamplerStateManager.PointClamp;
_depth?.ReleaseRef();
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
} }
RenderBackground(); RenderBackground();
RenderTexture(texture); RenderTexture(texture);
ImGui.Image(_target, viewportSize); ImGui.Image(_targets.GetViewBinding(0), viewportSize);
ImGui.EndChild(); ImGui.EndChild();
} }
@@ -398,20 +410,19 @@ class TexturererViewerer
viewportSize.x = Math.Max(viewportSize.x, 1); viewportSize.x = Math.Max(viewportSize.x, 1);
viewportSize.y = Math.Max(viewportSize.y, 1); viewportSize.y = Math.Max(viewportSize.y, 1);
if(_target == null || viewportSize.x != _target.Width || viewportSize.y != _target.Height) if (_targets.Width != viewportSize.x || _targets.Height != viewportSize.y)
{ {
_target?.ReleaseRef(); _targets.Resize((.)viewportSize.x, (.)viewportSize.y);
_target = new RenderTarget2D(.(.R8G8B8A8_UNorm_SRGB, (.)viewportSize.x, (.)viewportSize.y));
_target.SamplerState = SamplerStateManager.PointClamp;
_depth?.ReleaseRef();
_depth = new DepthStencilTarget((.)viewportSize.x, (.)viewportSize.y, .D16_UNorm);
} }
RenderBackground(); RenderBackground();
RenderTexture(texture); RenderTexture(texture);
ImGui.Image(_target, viewportSize); using (let vb = _targets.GetViewBinding(0))
{
ImGui.Image(vb, viewportSize);
}
ImGui.EndChild(); ImGui.EndChild();
} }
@@ -468,19 +479,21 @@ class TexturererViewerer
private void RenderBackground() private void RenderBackground()
{ {
Viewport vp = .(0, 0, _target.Width, _target.Height); Viewport vp = .(0, 0, _targets.Width, _targets.Height);
RenderCommand.SetViewport(vp); RenderCommand.SetViewport(vp);
RenderCommand.Clear(_targets, .ColorDepth);
// TODO: don't clear pink! // TODO: don't clear pink!
RenderCommand.Clear(_target, .Pink); //RenderCommand.Clear(_target, .Pink);
RenderCommand.Clear(_depth, .Depth, 1.0f, 0); //RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
//_target.Bind(); //_target.Bind();
RenderCommand.SetRenderTarget(_target); RenderCommand.SetRenderTargetGroup(_targets);
RenderCommand.SetDepthStencilTarget(_depth); //RenderCommand.SetRenderTarget(_idTarget, 1);
//RenderCommand.SetDepthStencilTarget(_depth);
RenderCommand.BindRenderTargets(); RenderCommand.BindRenderTargets();
float2 targetSize = float2(_target.Width, _target.Height); float2 targetSize = float2(_targets.Width, _targets.Height);
_camera.Left = 0; _camera.Left = 0;
_camera.Top = 0; _camera.Top = 0;
@@ -520,7 +533,7 @@ class TexturererViewerer
Renderer2D.EndScene(); Renderer2D.EndScene();
} }
private void RenderTexture(TextureViewBinding viewedTexture, float2 textureSize, Format format) private void RenderTexture(Asset textureAsset, float2 textureSize, Format format, int32? groupTargetIndex = null)
{ {
float2 mippedTextureSize = float2((int)textureSize.X >> _mipLevel, (int)textureSize.X >> _mipLevel); float2 mippedTextureSize = float2((int)textureSize.X >> _mipLevel, (int)textureSize.X >> _mipLevel);
@@ -544,52 +557,70 @@ class TexturererViewerer
//Renderer2D.BeginScene(_camera, .SortByTexture, _effect); //Renderer2D.BeginScene(_camera, .SortByTexture, _effect);
// float3(_position * .(1, -1), 0) // float3(_position * .(1, -1), 0)
RenderCommand.Clear(_depth, .Depth, 1.0f, 0); //RenderCommand.Clear(_depth, .Depth, 1.0f, 0);
RenderCommand.Clear(_targets, .Depth);
Matrix matrix = .Translation(float3(_position * .(1, -1), 0)) * .Scaling(float3(zoomedTextureSize, 1)); Matrix matrix = .Translation(float3(_position * .(1, -1), 0)) * .Scaling(float3(zoomedTextureSize, 1));
// TODO: ViewProjection kommt nicht korrekt an? // TODO: ViewProjection kommt nicht korrekt an?
_renderTargetEffect.Variables["WorldViewProjection"].SetData(_camera.ViewProjection * matrix); _renderTargetMaterial.SetVariable("WorldViewProjection", _camera.ViewProjection * matrix);
_renderTargetMaterial.SetVariable("ColorOffset", _colorOffset);
_renderTargetMaterial.SetVariable("ColorScale", _colorScale);
_renderTargetMaterial.SetVariable("AlphaOffset", _alphaOffset);
_renderTargetMaterial.SetVariable("AlphaScale", _alphaScale);
/*_renderTargetEffect.Variables["WorldViewProjection"].SetData(_camera.ViewProjection * matrix);
_renderTargetEffect.Variables["ColorOffset"].SetData(_colorOffset); _renderTargetEffect.Variables["ColorOffset"].SetData(_colorOffset);
_renderTargetEffect.Variables["ColorScale"].SetData(_colorScale); _renderTargetEffect.Variables["ColorScale"].SetData(_colorScale);
_renderTargetEffect.Variables["AlphaOffset"].SetData(_alphaOffset); _renderTargetEffect.Variables["AlphaOffset"].SetData(_alphaOffset);
_renderTargetEffect.Variables["AlphaScale"].SetData(_alphaScale); _renderTargetEffect.Variables["AlphaScale"].SetData(_alphaScale);*/
_renderTargetEffect.Variables["Texels"].SetData(mippedTextureSize); //_renderTargetEffect.Variables["Texels"].SetData(mippedTextureSize);
_renderTargetMaterial.SetVariable("Texels", mippedTextureSize);
_renderTargetEffect.Variables["MipLevel"].SetData((float)_mipLevel); //_renderTargetEffect.Variables["MipLevel"].SetData((float)_mipLevel);
_renderTargetMaterial.SetVariable("MipLevel", (float)_mipLevel);
_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA)); //_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
_renderTargetMaterial.SetVariable("Swizzle", int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
if (((DirectX.DXGI.Format)format).IsInt()) int textureSlot = -1;
if (format.IsInt())
{ {
// Int Texture // Int Texture
_renderTargetEffect.Variables["Mode"].SetData(1); _renderTargetMaterial.SetVariable("Mode", 1);
_renderTargetEffect.SetTexture("IntTexture", viewedTexture); textureSlot = _renderTargetMaterial.Effect.Textures["IntTexture"].PsSlot.Index;
_renderTargetEffect.SetTexture("UIntTexture", (Texture)null);
_renderTargetEffect.SetTexture("Texture", (Texture)null);
} }
else if (format.IsUInt()) else if (format.IsUInt())
{ {
// UInt Texture // UInt Texture
_renderTargetEffect.Variables["Mode"].SetData(2); _renderTargetMaterial.SetVariable("Mode", 2);
_renderTargetEffect.SetTexture("IntTexture", (Texture)null); textureSlot = _renderTargetMaterial.Effect.Textures["UIntTexture"].PsSlot.Index;
_renderTargetEffect.SetTexture("UIntTexture", viewedTexture);
_renderTargetEffect.SetTexture("Texture", (Texture)null);
} }
else else
{ {
// Float Texture // Float Texture
_renderTargetEffect.Variables["Mode"].SetData(0); _renderTargetMaterial.SetVariable("Mode", 0);
_renderTargetEffect.SetTexture("IntTexture", (Texture)null); textureSlot = _renderTargetMaterial.Effect.Textures["Texture"].PsSlot.Index;
_renderTargetEffect.SetTexture("UIntTexture", (Texture)null);
_renderTargetEffect.SetTexture("Texture", viewedTexture);
} }
_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA)); //_renderTargetMaterial.ApplyChanges();
_renderTargetMaterial.Bind();
_renderTargetEffect.ApplyChanges(); if (let renderTargetGroup = textureAsset as RenderTargetGroup)
_renderTargetEffect.Bind(); {
using (let viewBinding = renderTargetGroup.GetViewBinding((.)groupTargetIndex))
{
RenderCommand.BindTexture(viewBinding, textureSlot, .Pixel);
}
}
else if (let texture = textureAsset as Texture)
{
using (let viewBinding = texture.GetViewBinding())
{
RenderCommand.BindTexture(viewBinding, textureSlot, .Pixel);
}
}
Quad.Draw(); Quad.Draw();
} }
@@ -598,11 +629,11 @@ class TexturererViewerer
{ {
var desc = _groupIndex >= 0 ? viewedTexture.[Friend]_colorTargetDescriptions[_groupIndex] : viewedTexture.[Friend]_depthTargetDescription; var desc = _groupIndex >= 0 ? viewedTexture.[Friend]_colorTargetDescriptions[_groupIndex] : viewedTexture.[Friend]_depthTargetDescription;
RenderTexture(viewedTexture.GetViewBinding(_groupIndex), float2(viewedTexture.Width, viewedTexture.Height), (.)desc.Format.GetShaderViewFormat()); RenderTexture(viewedTexture, float2(viewedTexture.Width, viewedTexture.Height), (.)desc.Format.GetShaderViewFormat(), _groupIndex);
} }
private void RenderTexture(Texture viewedTexture) private void RenderTexture(Texture viewedTexture)
{ {
RenderTexture(viewedTexture.GetViewBinding(), float2(viewedTexture.Width, viewedTexture.Height), viewedTexture.Format); RenderTexture(viewedTexture, float2(viewedTexture.Width, viewedTexture.Height), viewedTexture.Format, -1);
} }
} }
@@ -133,7 +133,7 @@ class ShaderLoader : IProcessedAssetLoader
} }
Try!(stream.TryRead(buffer.RawData)); Try!(stream.TryRead(buffer.RawData));
Try!(buffer.Update()); Try!(buffer.Apply());
if (vertexShaderBindPoint != -1) if (vertexShaderBindPoint != -1)
effect.VertexShader.Buffers.Add(vertexShaderBindPoint, buffer.Name, buffer); effect.VertexShader.Buffers.Add(vertexShaderBindPoint, buffer.Name, buffer);
+2
View File
@@ -233,6 +233,8 @@ namespace GlitchyEngine.ImGui
ImGui.Render(); ImGui.Render();
RenderCommand.SetDepthStencilTarget(null); RenderCommand.SetDepthStencilTarget(null);
// TODO: This is dirty
RenderCommand.UnbindRenderTargets();
RenderCommand.SetRenderTarget(null); RenderCommand.SetRenderTarget(null);
RenderCommand.BindRenderTargets(); RenderCommand.BindRenderTargets();
@@ -12,7 +12,7 @@ namespace GlitchyEngine.Renderer
internal ID3D11Buffer*[DirectX.D3D11.D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] nativeBuffers; internal ID3D11Buffer*[DirectX.D3D11.D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] nativeBuffers;
internal void PlatformFetchNativeBuffers() protected internal override void PlatformFetchNativeBuffers()
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
@@ -210,11 +210,19 @@ namespace GlitchyEngine.Renderer
BindInputLayout(); BindInputLayout();
if (_hasVs) if (_hasVs)
{
NativeContext.VertexShader.SetShaderResources(0, _vsShaderResources.Count, &_vsShaderResources);
NativeContext.VertexShader.SetSamplers(0, _vsSamplers.Count, &_vsSamplers);
NativeContext.VertexShader.SetConstantBuffers(0, _vsBuffers.Count, &_vsBuffers); NativeContext.VertexShader.SetConstantBuffers(0, _vsBuffers.Count, &_vsBuffers);
}
if (_hasPs) if (_hasPs)
{
NativeContext.PixelShader.SetShaderResources(0, _psShaderResources.Count, &_psShaderResources);
NativeContext.PixelShader.SetSamplers(0, _psSamplers.Count, &_psSamplers);
NativeContext.PixelShader.SetConstantBuffers(0, _psBuffers.Count, &_psBuffers); NativeContext.PixelShader.SetConstantBuffers(0, _psBuffers.Count, &_psBuffers);
} }
}
public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0) public override void Draw(uint32 vertexCount, uint32 startVertexIndex = 0)
{ {
@@ -291,6 +299,11 @@ namespace GlitchyEngine.Renderer
private ID3D11Buffer*[DirectX.D3D11.D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] _vsBuffers; private ID3D11Buffer*[DirectX.D3D11.D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] _vsBuffers;
private ID3D11Buffer*[DirectX.D3D11.D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] _psBuffers; private ID3D11Buffer*[DirectX.D3D11.D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] _psBuffers;
private ID3D11ShaderResourceView*[DirectX.D3D11.D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] _vsShaderResources;
private ID3D11SamplerState*[DirectX.D3D11.D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] _vsSamplers;
private ID3D11ShaderResourceView*[DirectX.D3D11.D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] _psShaderResources;
private ID3D11SamplerState*[DirectX.D3D11.D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] _psSamplers;
/** /**
* Binds the given shader to the corresponding shader stage. * Binds the given shader to the corresponding shader stage.
* @param shader The shader that will be bound to the graphics context. * @param shader The shader that will be bound to the graphics context.
@@ -299,24 +312,25 @@ namespace GlitchyEngine.Renderer
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
uint32 _firstTexture = D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; //uint32 _firstTexture = D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT;
uint32 _textureCount = 0; //uint32 _textureCount = 0;
ID3D11ShaderResourceView*[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] shaderResources = .();
ID3D11SamplerState*[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] samplers = .();
ID3D11ShaderResourceView*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] _textures = .();
ID3D11SamplerState*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] _samplers = .();
for (let entry in shader?.Textures) for (let entry in shader?.Textures)
{ {
_textures[entry.Index] = entry.BoundTexture._nativeShaderResourceView; shaderResources[entry.Index] = entry.BoundTexture._nativeShaderResourceView;
_samplers[entry.Index] = entry.BoundTexture._nativeSamplerState; samplers[entry.Index] = entry.BoundTexture._nativeSamplerState;
if(entry.Index >= _textureCount) /*if(entry.Index >= _textureCount)
_textureCount = entry.Index + 1; _textureCount = entry.Index + 1;
if(entry.Index < _firstTexture) if(entry.Index < _firstTexture)
_firstTexture = entry.Index; _firstTexture = entry.Index;*/
} }
shader.Buffers.PlatformFetchNativeBuffers(); //constantBuffers.PlatformFetchNativeBuffers();
switch (typeof(TShader)) switch (typeof(TShader))
{ {
@@ -325,38 +339,44 @@ namespace GlitchyEngine.Renderer
_hasPs = shader != null; _hasPs = shader != null;
// TODO: bind uavs // TODO: bind uavs
if (_textureCount > 0) /*if (_textureCount > 0)
{ {
NativeContext.PixelShader.SetShaderResources(_firstTexture, _textureCount, &_textures[_firstTexture]); //NativeContext.PixelShader.SetShaderResources(_firstTexture, _textureCount, &_textures[_firstTexture]);
NativeContext.PixelShader.SetSamplers(_firstTexture, _textureCount, &_samplers[_firstTexture]); //NativeContext.PixelShader.SetSamplers(_firstTexture, _textureCount, &_samplers[_firstTexture]);
} }*/
_ps_FirstTexture = _firstTexture; /*_ps_FirstTexture = _firstTexture;
_ps_BoundTextures = _textureCount; _ps_BoundTextures = _textureCount;*/
_psBuffers = shader.Buffers.nativeBuffers; //_psBuffers = constantBuffers.nativeBuffers;
//NativeContext.PixelShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers); //NativeContext.PixelShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers);
_psShaderResources = shaderResources;
_psSamplers = samplers;
NativeContext.PixelShader.SetShader((ID3D11PixelShader*)shader?.nativeShader); NativeContext.PixelShader.SetShader((ID3D11PixelShader*)shader?.nativeShader);
case typeof(VertexShader): case typeof(VertexShader):
_hasVs = shader != null; _hasVs = shader != null;
if (_textureCount > 0) /*if (_textureCount > 0)
{ {
NativeContext.VertexShader.SetShaderResources(_firstTexture, _textureCount, &_textures[_firstTexture]); NativeContext.VertexShader.SetShaderResources(_firstTexture, _textureCount, &_textures[_firstTexture]);
NativeContext.VertexShader.SetSamplers(_firstTexture, _textureCount, &_samplers[_firstTexture]); NativeContext.VertexShader.SetSamplers(_firstTexture, _textureCount, &_samplers[_firstTexture]);
} }*/
_vsBuffers = shader.Buffers.nativeBuffers; //_vsBuffers = constantBuffers.nativeBuffers;
//NativeContext.VertexShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers); //NativeContext.VertexShader.SetConstantBuffers(0, shader.Buffers.nativeBuffers.Count, &shader.Buffers.nativeBuffers);
_vsShaderResources = shaderResources;
_vsSamplers = samplers;
NativeContext.VertexShader.SetShader((ID3D11VertexShader*)shader?.nativeShader); NativeContext.VertexShader.SetShader((ID3D11VertexShader*)shader?.nativeShader);
_vs_FirstTexture = _firstTexture; /*_vs_FirstTexture = _firstTexture;
_vs_BoundTextures = _textureCount; _vs_BoundTextures = _textureCount;*/
//if (VertexShader vs = shader as VertexShader) //if (VertexShader vs = shader as VertexShader)
[ConstSkip] [ConstSkip]
@@ -372,12 +392,14 @@ namespace GlitchyEngine.Renderer
public override void UnbindTextures() public override void UnbindTextures()
{ {
void** voidArray = scope void*[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]*; _vsShaderResources = .();
_psShaderResources = .();
using (ContextMonitor.Enter()) using (ContextMonitor.Enter())
{ {
NativeContext.PixelShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray); // Do we need to set here, or is it enough to do it in BindState?
NativeContext.VertexShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, (.)voidArray); NativeContext.PixelShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, &_vsShaderResources);
NativeContext.VertexShader.SetShaderResources(0, D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, &_psShaderResources);
} }
} }
@@ -411,6 +433,34 @@ namespace GlitchyEngine.Renderer
_psBuffers[slot] = buffer.nativeBuffer; _psBuffers[slot] = buffer.nativeBuffer;
} }
} }
public override void BindTexture(TextureViewBinding textureBinding, int slot, ShaderStage shaderStage)
{
Debug.Assert((slot >= 0) && (slot < DirectX.D3D11.D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT));
if (shaderStage.HasFlag(.Vertex))
{
_vsShaderResources[slot] = textureBinding._nativeShaderResourceView;
_vsSamplers[slot] = textureBinding._nativeSamplerState;
}
if (shaderStage.HasFlag(.Pixel))
{
_psShaderResources[slot] = textureBinding._nativeShaderResourceView;
_psSamplers[slot] = textureBinding._nativeSamplerState;
}
}
public override void BindConstantBuffers(BufferCollection bufferCollection, ShaderStage shaderStage)
{
bufferCollection.PlatformFetchNativeBuffers();
if (shaderStage.HasFlag(.Vertex))
_vsBuffers = bufferCollection.nativeBuffers;
if (shaderStage.HasFlag(.Pixel))
_psBuffers = bufferCollection.nativeBuffers;
}
} }
} }
@@ -291,6 +291,16 @@ namespace GlitchyEngine.Renderer
{ {
_context.BindPixelShader(pixelShader); _context.BindPixelShader(pixelShader);
} }
public override void BindConstantBuffers(BufferCollection bufferCollection, ShaderStage shaderStage)
{
_context.BindConstantBuffers(bufferCollection, shaderStage);
}
public override void BindTexture(TextureViewBinding textureBinding, int slot, ShaderStage shaderStage)
{
_context.BindTexture(textureBinding, slot, shaderStage);
}
} }
} }
@@ -176,5 +176,7 @@ namespace GlitchyEngine.Renderer
{ {
return _buffers.GetEnumerator(); return _buffers.GetEnumerator();
} }
protected internal extern void PlatformFetchNativeBuffers();
} }
} }
+65 -6
View File
@@ -4,6 +4,21 @@ namespace GlitchyEngine.Renderer
{ {
using internal 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 public class BufferVariable
{ {
private ConstantBuffer _constantBuffer; private ConstantBuffer _constantBuffer;
@@ -19,7 +34,7 @@ namespace GlitchyEngine.Renderer
// Number of elements in the array // Number of elements in the array
internal uint32 _arrayElements; internal uint32 _arrayElements;
private bool _isUsed; private VariableFlags _flags;
public ConstantBuffer ConstantBuffer => _constantBuffer; public ConstantBuffer ConstantBuffer => _constantBuffer;
@@ -27,7 +42,7 @@ namespace GlitchyEngine.Renderer
public String Name => _name; public String Name => _name;
public bool IsUsed => _isUsed; public bool IsUsed => _flags.HasFlag(.Used);
public uint32 Columns => _columns; public uint32 Columns => _columns;
public uint32 Rows => _rows; public uint32 Rows => _rows;
@@ -35,6 +50,20 @@ namespace GlitchyEngine.Renderer
public uint32 Offset => _offset; 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. * Gets a pointer to the start of the variable in the constant buffers backing data.
*/ */
@@ -51,7 +80,12 @@ namespace GlitchyEngine.Renderer
_offset = offset; _offset = offset;
_sizeInBytes = sizeInBytes; _sizeInBytes = sizeInBytes;
_arrayElements = arrayElements; _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) public void EnsureTypeMatch(int rows, int cols, ShaderVariableType type)
@@ -131,11 +165,20 @@ namespace GlitchyEngine.Renderer
} }
} }
enum SetDataError
{
VariableNotFound,
TypeMismatch
}
[Inline] [Inline]
private void SetData<T>(T value) private void SetData<T>(T value)
{ {
EnsureTypeMatch<T>(); EnsureTypeMatch<T>();
_flags |= .Dirty;
Enum.ClearFlag(ref _flags, .Unset);
*(T*)firstByte = value; *(T*)firstByte = value;
} }
@@ -175,6 +218,9 @@ namespace GlitchyEngine.Renderer
{ {
EnsureTypeMatch<Matrix4x3>(); EnsureTypeMatch<Matrix4x3>();
_flags |= .Dirty;
Enum.ClearFlag(ref _flags, .Unset);
// TODO: assert length // TODO: assert length
Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix4x3) * Math.Min(value.Count, _arrayElements)); Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix4x3) * Math.Min(value.Count, _arrayElements));
@@ -184,15 +230,22 @@ namespace GlitchyEngine.Renderer
{ {
EnsureTypeMatch<Matrix3x3>(); EnsureTypeMatch<Matrix3x3>();
*(Matrix4x3*)firstByte = Matrix4x3(value); _flags |= .Dirty;
Enum.ClearFlag(ref _flags, .Unset);
// Todo: maybe manual copy // 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);
} }
public void SetData(Matrix3x3[] value) public void SetData(Matrix3x3[] value)
{ {
EnsureTypeMatch<Matrix3x3>(); EnsureTypeMatch<Matrix3x3>();
_flags |= .Dirty;
Enum.ClearFlag(ref _flags, .Unset);
// TODO: assert length // TODO: assert length
for(int i < Math.Min(value.Count, _arrayElements)) for(int i < Math.Min(value.Count, _arrayElements))
@@ -207,6 +260,9 @@ namespace GlitchyEngine.Renderer
{ {
EnsureTypeMatch<Matrix>(); EnsureTypeMatch<Matrix>();
_flags |= .Dirty;
Enum.ClearFlag(ref _flags, .Unset);
// TODO: assert length // TODO: assert length
Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix) * Math.Min(value.Count, _arrayElements)); Internal.MemCpy(firstByte, value.Ptr, sizeof(Matrix) * Math.Min(value.Count, _arrayElements));
@@ -223,12 +279,15 @@ namespace GlitchyEngine.Renderer
#if GE_SHADER_UNUSED_VARIABLE_IS_ERROR #if GE_SHADER_UNUSED_VARIABLE_IS_ERROR
Log.EngineLogger.Assert(_isUsed, scope $"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\"."); Log.EngineLogger.Assert(_isUsed, scope $"Setting data for unused Variable \"{_name}\" of constant buffer \"{_constantBuffer.Name}\".");
#elif GE_SHADER_UNUSED_VARIABLE_IS_WARNING #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}\"."); 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) if(rawData != null)
Internal.MemCpy(firstByte, rawData, _sizeInBytes); Internal.MemCpy(firstByte, rawData, _sizeInBytes);
else else
+29 -3
View File
@@ -17,8 +17,12 @@ namespace GlitchyEngine.Renderer
protected BufferVariableCollection _variables = new BufferVariableCollection() ~ delete _; protected BufferVariableCollection _variables = new BufferVariableCollection() ~ delete _;
protected bool _isDirty = true;
protected internal int _generation = 0;
/// Gets the name of the constant buffer. /// Gets the name of the constant buffer.
public String Name => _name; public StringView Name => _name;
public BufferVariableCollection Variables => _variables; public BufferVariableCollection Variables => _variables;
@@ -58,10 +62,32 @@ namespace GlitchyEngine.Renderer
/** /**
* Uploads the date to the GPU. * 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;
} }
} }
+1 -1
View File
@@ -123,7 +123,7 @@ public class Effect : Asset
{ {
if(let cbuffer = buffer.Buffer as ConstantBuffer) 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 UnbindTextures();
public extern void BindConstantBuffer(Buffer buffer, int slot, ShaderStage stage); 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);
} }
} }
+109 -189
View File
@@ -12,11 +12,11 @@ public class Material : Asset
{ {
private Effect _effect ~ _?.ReleaseRef(); 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 public Effect Effect
{ {
@@ -28,36 +28,7 @@ public class Material : Asset
if (_effect == null) if (_effect == null)
return; return;
// TODO: get variables from effect Init();
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();
} }
} }
@@ -71,51 +42,81 @@ public class Material : Asset
Effect = effect; Effect = effect;
} }
private void Init()
/** @brief Initializes the raw data array for the variables.
*/
private void InitRawData()
{ {
uint32 bufferSize = 0; decltype(_textures) newTextures = new .();
decltype(_variables) newVariables = new Dictionary<String, (uint32 Offset, BufferVariable Variable)>(); // Get texture slots from effect
for(let (name, effectTexture) in _effect.Textures)
for(let variable in _effect.Variables)
{ {
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;
} }
uint8[] newData = new uint8[bufferSize]; if (textureHandle.IsValid)
for (let (newKey, newValue) in newVariables)
{ {
if (_variables.TryGetValue(newKey, let oldEntry)) if (textureHandle.Dimension != effectTexture.TextureDimension)
{ textureHandle = .Invalid;
if (oldEntry.Variable.ElementType == newValue.Variable.ElementType)
{
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);
} }
newTextures[new String(name)] = (textureHandle, effectTexture.TextureDimension, groupTarget);
} }
// TODO: we could try to convert e.g. Int <-> Float
DeleteDictionaryAndKeys!(_textures);
_textures = newTextures;
//InitRawData();
InitBuffers();
}
private void InitBuffers()
{
_variables.Clear();
_bufferCollection?.ReleaseRef();
_bufferCollection = new BufferCollection();
void InitVariables(ConstantBuffer buffer)
{
for (BufferVariable variable in buffer.Variables)
{
if (_variables.ContainsKey(variable.Name))
{
// TODO: Handle overlapping variable names?
Log.EngineLogger.Error("Variable with same name already added to Material, skipping...");
continue;
}
_variables.Add(variable.Name, variable);
} }
} }
delete _rawVariables; for (let (bufferName, buffer) in _effect.Buffers)
_rawVariables = newData; {
if (buffer == null)
continue;
DeleteDictionaryAndKeys!(_variables); if (ConstantBuffer parentConstBuffer = buffer as ConstantBuffer)
_variables = newVariables; {
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.");
}
}
} }
/** /**
@@ -125,6 +126,7 @@ public class Material : Asset
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
// TODO: Bind textures, don't go through effect for that
for(let (name, texture) in _textures) for(let (name, texture) in _textures)
{ {
switch (texture.Dimension) 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(); _effect.Bind();
RenderCommand.BindConstantBuffers(_bufferCollection);
} }
/** @brief Sets a texture of the material. /** @brief Sets a texture of the material.
* @param name The name of the texture to set. * @param name The name of the texture to set.
* @param texture The texture to bind to the effect. * @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)) if(_textures.TryGetValue(name, var entry))
{ {
@@ -174,6 +186,7 @@ public class Material : Asset
}*/ }*/
//entry?.ReleaseRef(); //entry?.ReleaseRef();
_textures[name].Handle = texture; _textures[name].Handle = texture;
_textures[name].groupTarget = groupTargetIndex;
//texture?.AddRef(); //texture?.AddRef();
} }
else 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}\"");
}
}
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, 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<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<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, 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)) if(_variables.TryGetValue(name, let entry))
{ {
entry.Variable.EnsureTypeMatch<Matrix3x3>(); entry.SetData(value);
// 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) public void SetVariable(String name, bool value) => SetVariable!(name, value);
{ public void SetVariable(String name, bool2 value) => SetVariable!(name, value);
if(_variables.TryGetValue(name, let entry)) public void SetVariable(String name, bool3 value) => SetVariable!(name, value);
{ public void SetVariable(String name, bool4 value) => SetVariable!(name, value);
entry.Variable.EnsureTypeMatch<Matrix3x3>();
int count = Math.Min(values.Count, entry.Variable._arrayElements); 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);
for(int i < count) public void SetVariable(String name, uint32 value) => SetVariable!(name, value);
{ public void SetVariable(String name, uint2 value) => SetVariable!(name, value);
(RawPointer!<Matrix4x3>(entry.Offset))[i] = Matrix4x3(values[i]); public void SetVariable(String name, uint3 value) => SetVariable!(name, value);
} public void SetVariable(String name, uint4 value) => SetVariable!(name, value);
}
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, float value) => SetVariable!(name, value);
public void SetVariable(String name, Matrix value) => SetVariable<Matrix>(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, Matrix[] values) public void SetVariable(String name, Color value) => SetVariable!(name, value);
{ public void SetVariable(String name, ColorRGB value) => SetVariable!(name, value);
if(_variables.TryGetValue(name, let entry)) public void SetVariable(String name, ColorRGBA value) => SetVariable!(name, value);
{
entry.Variable.EnsureTypeMatch<Matrix>();
Internal.MemCpy(RawPointer!<Matrix>(entry.Offset), values.Ptr, sizeof(Matrix) * Math.Min(values.Count, entry.Variable._arrayElements)); public void SetVariable(String name, Matrix3x3 value) => SetVariable!(name, value);
} public void SetVariable(String name, Matrix4x3 value) => SetVariable!(name, value);
else public void SetVariable(String name, Matrix value) => SetVariable!(name, value);
{
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 GetVariable<T>(String name, out T value) where T : struct 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)) if(_variables.TryGetValue(name, let entry))
{ {
entry.Variable.EnsureTypeMatch<T>(); entry.EnsureTypeMatch<T>();
value = *RawPointer!<T>(entry.Offset); // TODO: This obviously breaks for all cases where a custom SetData was necessary.
value = *(T*)entry.firstByte;
} }
else 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); _rendererAPI.BindConstantBuffer(buffer, slot, stage);
} }
public static void BindConstantBuffers(BufferCollection constantBuffers, ShaderStage stage = .All)
{
_rendererAPI.BindConstantBuffers(constantBuffers, stage);
}
public static void BindVertexShader(VertexShader vertexShader) public static void BindVertexShader(VertexShader vertexShader)
{ {
_rendererAPI.BindVertexShader(vertexShader); _rendererAPI.BindVertexShader(vertexShader);
@@ -138,5 +143,10 @@ namespace GlitchyEngine.Renderer
{ {
_rendererAPI.BindPixelShader(pixelShader); _rendererAPI.BindPixelShader(pixelShader);
} }
public static void BindTexture(TextureViewBinding textureBinding, int slot, ShaderStage shaderStage)
{
_rendererAPI.BindTexture(textureBinding, slot, shaderStage);
}
} }
} }
+49 -28
View File
@@ -132,6 +132,7 @@ namespace GlitchyEngine.Renderer
#endif #endif
private static AssetHandle<Effect> s_quadBatchEffect; private static AssetHandle<Effect> s_quadBatchEffect;
private static Material s_quadBatchMaterial ~ _?.ReleaseRef();
private static AssetHandle<Effect> s_circleBatchEffect; private static AssetHandle<Effect> s_circleBatchEffect;
private static AssetHandle<Effect> s_lineBatchEffect; private static AssetHandle<Effect> s_lineBatchEffect;
@@ -162,7 +163,7 @@ namespace GlitchyEngine.Renderer
private static DrawOrder s_drawOrder; private static DrawOrder s_drawOrder;
/// The effect that is currently used to draw the sprites. /// 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_currentCircleEffect;
private static AssetHandle<Effect> s_currentLineEffect; private static AssetHandle<Effect> s_currentLineEffect;
@@ -185,6 +186,7 @@ namespace GlitchyEngine.Renderer
Debug.Profiler.ProfileFunction!(); Debug.Profiler.ProfileFunction!();
s_quadBatchEffect = Content.LoadAsset("Resources/Shaders/spritebatch.hlsl", null, true); 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_circleBatchEffect = Content.LoadAsset("Resources/Shaders/circlebatch.hlsl", null, true);
s_lineBatchEffect = Content.LoadAsset("Resources/Shaders/linebatch.hlsl", null, true); s_lineBatchEffect = Content.LoadAsset("Resources/Shaders/linebatch.hlsl", null, true);
} }
@@ -455,7 +457,7 @@ namespace GlitchyEngine.Renderer
} }
// TODO: remove? // 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!(); Debug.Profiler.ProfileRendererFunction!();
#if DEBUG #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."); Log.EngineLogger.AssertDebug(!s_sceneRunning, "You have to call EndScene before you can make another call to BeginScene.");
#endif #endif
if(effect != .Invalid) /*if(effect != .Invalid)
{ {
s_currentQuadEffect = effect; s_currentQuadEffect = effect;
} }
else else
{ {
s_currentQuadEffect = s_quadBatchEffect; s_currentQuadEffect = s_quadBatchEffect;
} }*/
if(circleEffect != .Invalid) /*if(circleEffect != .Invalid)
{ {
s_currentCircleEffect = circleEffect; s_currentCircleEffect = circleEffect;
} }
else else
{ {
s_currentCircleEffect = s_circleBatchEffect; s_currentCircleEffect = s_circleBatchEffect;
} }*/
s_currentLineEffect = s_lineBatchEffect; s_currentLineEffect = s_lineBatchEffect;
s_currentQuadEffect.Variables["ViewProjection"].SetData(camera.ViewProjection); //s_currentQuadEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
s_currentCircleEffect.Variables["ViewProjection"].SetData(camera.ViewProjection); s_quadBatchMaterial.SetVariable("ViewProjection", camera.ViewProjection);
//s_currentCircleEffect.Variables["ViewProjection"].SetData(camera.ViewProjection);
s_drawOrder = drawOrder; s_drawOrder = drawOrder;
@@ -493,7 +496,7 @@ namespace GlitchyEngine.Renderer
#endif #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!(); Debug.Profiler.ProfileRendererFunction!();
#if DEBUG #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."); Log.EngineLogger.AssertDebug(!s_sceneRunning, "You have to call EndScene before you can make another call to BeginScene.");
#endif #endif
if(effect != .Invalid) /*if(effect != .Invalid)
{ {
s_currentQuadEffect = effect; s_currentQuadEffect = effect;
} }
else else
{ {
s_currentQuadEffect = s_quadBatchEffect; s_currentQuadEffect = s_quadBatchEffect;
} }*/
if(circleEffect != .Invalid) /*if(circleEffect != .Invalid)
{ {
s_currentCircleEffect = circleEffect; s_currentCircleEffect = circleEffect;
} }
else else
{ {
s_currentCircleEffect = s_circleBatchEffect; s_currentCircleEffect = s_circleBatchEffect;
} }*/
s_currentLineEffect = s_lineBatchEffect; s_currentLineEffect = s_lineBatchEffect;
Matrix viewProjection = camera.Projection * Matrix.Invert(transform); 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_currentCircleEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
s_currentLineEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection); s_currentLineEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
@@ -534,7 +538,7 @@ namespace GlitchyEngine.Renderer
#endif #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!(); Debug.Profiler.ProfileRendererFunction!();
#if DEBUG #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."); Log.EngineLogger.AssertDebug(!s_sceneRunning, "You have to call EndScene before you can make another call to BeginScene.");
#endif #endif
if(effect != .Invalid) /*if(effect != .Invalid)
{ {
s_currentQuadEffect = effect; s_currentQuadEffect = effect;
} }
@@ -558,13 +562,14 @@ namespace GlitchyEngine.Renderer
else else
{ {
s_currentCircleEffect = s_circleBatchEffect; s_currentCircleEffect = s_circleBatchEffect;
} }*/
s_currentLineEffect = s_lineBatchEffect; s_currentLineEffect = s_lineBatchEffect;
Matrix viewProjection = camera.Projection * camera.View; 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_currentCircleEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
s_currentLineEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection); s_currentLineEffect.Get()?.Variables["ViewProjection"].SetData(viewProjection);
@@ -623,7 +628,7 @@ namespace GlitchyEngine.Renderer
s_statistics.LineCount++; s_statistics.LineCount++;
} }
private static void FlushQuadInstances() private static void FlushQuadInstances(Texture texture)
{ {
Debug.Profiler.ProfileRendererFunction!(); Debug.Profiler.ProfileRendererFunction!();
@@ -632,8 +637,24 @@ namespace GlitchyEngine.Renderer
s_quadInstanceBuffer.SetData<QuadBatchVertex>(s_rawQuadInstances.Ptr, s_setQuadInstances, 0, .WriteDiscard); s_quadInstanceBuffer.SetData<QuadBatchVertex>(s_rawQuadInstances.Ptr, s_setQuadInstances, 0, .WriteDiscard);
s_currentQuadEffect.ApplyChanges(); //s_currentQuadEffect.ApplyChanges();
s_currentQuadEffect.Bind(); //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.InstanceCount = s_setQuadInstances;
s_quadBatchBinding.Bind(); s_quadBatchBinding.Bind();
RenderCommand.DrawIndexedInstanced(s_quadBatchBinding); RenderCommand.DrawIndexedInstanced(s_quadBatchBinding);
@@ -778,13 +799,13 @@ namespace GlitchyEngine.Renderer
// TODO: per object blendstate // TODO: per object blendstate
RenderCommand.SetBlendState(s_transparentBlendState); RenderCommand.SetBlendState(s_transparentBlendState);
let quadEffect = s_currentQuadEffect.Get(); let quadMaterial = s_quadBatchMaterial;//s_currentQuadEffect.Get();
if (quadEffect == null) if (quadMaterial == null)
return; return;
Texture texture = s_QuadinstanceQueue[0].Texture; Texture texture = s_QuadinstanceQueue[0].Texture;
quadEffect.SetTexture("Texture", texture); //quadMaterial.SetTexture("Texture", .Invalid);
s_setQuadInstances = 0; s_setQuadInstances = 0;
@@ -795,21 +816,21 @@ namespace GlitchyEngine.Renderer
// flush every time the texture changes // flush every time the texture changes
if(quad.Texture != texture) if(quad.Texture != texture)
{ {
FlushQuadInstances(); FlushQuadInstances(texture);
texture = quad.Texture; texture = quad.Texture;
quadEffect.SetTexture("Texture", texture); //quadMaterial.SetTexture("Texture", .Invalid);
} }
s_rawQuadInstances[s_setQuadInstances++] = .(quad.Transform, quad.Color, quad.uvTransform, quad.entityId); s_rawQuadInstances[s_setQuadInstances++] = .(quad.Transform, quad.Color, quad.uvTransform, quad.entityId);
if(s_setQuadInstances == s_rawQuadInstances.Count) if(s_setQuadInstances == s_rawQuadInstances.Count)
{ {
FlushQuadInstances(); FlushQuadInstances(texture);
} }
} }
FlushQuadInstances(); FlushQuadInstances(texture);
s_QuadinstanceQueue.Clear(); s_QuadinstanceQueue.Clear();
} }
@@ -68,5 +68,9 @@ namespace GlitchyEngine.Renderer
public extern void BindVertexShader(VertexShader vertexShader); public extern void BindVertexShader(VertexShader vertexShader);
public extern void BindPixelShader(PixelShader pixelShader); 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) public static void DrawText(PreparedText text, Matrix transform, ColorRGBA fontColor = .White)
{ {
Debug.Profiler.ProfileRendererFunction!(); /*Debug.Profiler.ProfileRendererFunction!();
text.AddRef(); text.AddRef();
defer text.ReleaseRef(); defer text.ReleaseRef();
@@ -654,7 +654,7 @@ namespace GlitchyEngine.Renderer.Text
for(int i < atlasses.Count) for(int i < atlasses.Count)
{ {
atlasses[i].ReleaseRef(); atlasses[i].ReleaseRef();
} }*/
} }
} }
} }
+2
View File
@@ -172,6 +172,8 @@ class SceneRenderer
viewportTarget.AddRef(); viewportTarget.AddRef();
RenderCommand.Clear(_compositeTarget, .ColorDepth);
// 3D render // 3D render
Renderer.BeginScene(camera, _compositeTarget); Renderer.BeginScene(camera, _compositeTarget);