This commit is contained in:
2024-12-19 17:15:02 +03:00
parent 87abfde205
commit 3c66a65b40
27 changed files with 254 additions and 63 deletions

View File

@@ -19,6 +19,7 @@
<InternalsVisibleTo Include="PresenterConsole"/>
<InternalsVisibleTo Include="PresenterWpf"/>
<InternalsVisibleTo Include="PresenterNative"/>
<PackageReference Include="Evergine.Bindings.RenderDoc" Version="2024.10.7.18" />
<PackageReference Include="OpenTK" Version="4.8.2"/>
<PackageReference Include="Serilog" Version="4.1.0"/>

View File

@@ -7,6 +7,7 @@ using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using Serilog;
using Debug = Engine.Graphics.Debug;
namespace Engine;
@@ -69,8 +70,8 @@ public sealed class Engine
Profile = ContextProfile.Core
};
Window = new Window(this, new NativeWindow(settings), parHeadless);
Renderer = new Renderer(parWidth, parHeight);
Renderer = new Renderer(parWidth, parHeight, settings);
Window = new Window(this, Renderer.NativeWindow, parHeadless);
Log.Logger = parLogger;
_logger = Log.ForContext<Engine>();
@@ -92,18 +93,22 @@ public sealed class Engine
{
while (!Presenter?.IsExiting ?? false)
{
#if DEBUG
Debug.RenderDocStartFrame();
#endif
Renderer.StartFrame();
var view = Matrix4.Identity;
var projection = Matrix4.Identity;
var view = Matrix4.Identity;
lock (_sceneLock)
{
var camera = SceneManager.CurrentScene?.MainCamera;
if (camera != null)
{
camera.ScreenSize = new Vector2i(Renderer.ViewportWidth, Renderer.ViewportHeight);
view = camera.View;
projection = camera.Projection;
view = camera.View;
}
SceneManager.Render();
@@ -115,10 +120,15 @@ public sealed class Engine
Renderer.GlobalMeshRenderer.Render(projection, view);
Renderer.GlobalMeshRenderer.Reset();
Renderer.EndFrame();
Renderer.EndFrame(projection, view);
Presenter!.Present(Renderer.RenderTexture);
Presenter!.Render();
#if DEBUG
Debug.RenderDocEndFrame();
#endif
}
}

View File

@@ -52,12 +52,12 @@ public class IndexBuffer : OpenGlObject
GL.NamedBufferSubData(Handle, parOffset, parData.Length * sizeof(uint), parData);
}
public override void Bind()
internal override void Bind()
{
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
}
public override void Unbind()
internal override void Unbind()
{
GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
}

View File

@@ -22,7 +22,7 @@ public class VertexArray : OpenGlObject
{
GL.VertexArrayElementBuffer(Handle, parBuffer.Handle);
Log.Debug("Vertex array {Handle} bound to index buffer {Buffer}", Handle, parBuffer.Handle);
Log.Debug("Index buffer {Buffer} bound to vertex array {Handle}", parBuffer.Handle, Handle);
}
public void BindVertexBuffer<T>(VertexBuffer<T> parBuffer, int parBindingIndex = 0, int parDivisor = 0)
@@ -48,9 +48,8 @@ public class VertexArray : OpenGlObject
GL.VertexArrayBindingDivisor(Handle, parBindingIndex, parDivisor);
Log.Debug(
"Vertex array {Handle} bound to vertex buffer {Buffer} at {BindingIndex} binding with {Divisor} divisor",
Handle, parBuffer.Handle, parBindingIndex, parDivisor);
Log.Debug("Vertex buffer {Buffer} bound to vertex array {Handle} at {BindingIndex} binding with {Divisor} divisor",
parBuffer.Handle, Handle, parBindingIndex, parDivisor);
}
private void SetupAttribute(VertexAttribute parAttribute, int parBaseLocation, int parBaseOffset, int parBindingIndex)
@@ -70,12 +69,12 @@ public class VertexArray : OpenGlObject
}
}
public override void Bind()
internal override void Bind()
{
GL.BindVertexArray(Handle);
}
public override void Unbind()
internal override void Unbind()
{
GL.BindVertexArray(0);
}

View File

@@ -91,12 +91,12 @@ public class VertexBuffer<T> : OpenGlObject
GL.NamedBufferSubData(Handle, parOffset * _stride, parCount * _stride, parData);
}
public override void Bind()
internal override void Bind()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, Handle);
}
public override void Unbind()
internal override void Unbind()
{
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
}

View File

@@ -4,7 +4,7 @@ namespace Engine.Graphics.Camera;
public interface ICamera
{
public Matrix4 View { get; }
public Matrix4 Projection { get; }
public Vector2i ScreenSize { get; internal set; }
Matrix4 View { get; }
Matrix4 Projection { get; }
Vector2i ScreenSize { get; internal set; }
}

View File

@@ -2,17 +2,35 @@
using OpenTK.Graphics.OpenGL;
using Serilog;
using Serilog.Events;
using Evergine.Bindings.RenderDoc;
namespace Engine.Graphics;
internal static class Debug
{
private static RenderDoc _renderDocApi;
public static void Setup()
{
GL.Enable(EnableCap.DebugOutput);
GL.DebugMessageCallback(DebugCallback, IntPtr.Zero);
}
public static void InitializeRenderDoc()
{
RenderDoc.Load(out _renderDocApi);
}
public static void RenderDocStartFrame()
{
// _renderDocApi.API.StartFrameCapture(IntPtr.Zero, IntPtr.Zero);
}
public static void RenderDocEndFrame()
{
// _renderDocApi.API.EndFrameCapture(IntPtr.Zero, IntPtr.Zero);
}
private static void DebugCallback(DebugSource parSource, DebugType parType, int parId, DebugSeverity parSeverity,
int parLength,
IntPtr parMessage, IntPtr parUserParam)

View File

@@ -35,7 +35,7 @@ public class Framebuffer : OpenGlObject
private int _width;
private int _height;
public Framebuffer(int parWidth, int parHeight,
internal Framebuffer(int parWidth, int parHeight,
IDictionary<FramebufferAttachment, IFramebufferAttachment> parAttachments)
{
Width = parWidth;
@@ -62,7 +62,7 @@ public class Framebuffer : OpenGlObject
return new FramebufferBuilder(parWidth, parHeight);
}
public T? GetAttachment<T>(FramebufferAttachment parAttachment) where T : IFramebufferAttachment
internal T? GetAttachment<T>(FramebufferAttachment parAttachment) where T : IFramebufferAttachment
{
if (!_attachments.TryGetValue(parAttachment, out var attachmentValue))
{
@@ -95,12 +95,12 @@ public class Framebuffer : OpenGlObject
Log.Debug("Framebuffer {Handle} resized to {Width}x{Height}", Handle, parWidth, parHeight);
}
public override void Bind()
internal override void Bind()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, Handle);
}
public override void Unbind()
internal override void Unbind()
{
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
}

View File

@@ -2,11 +2,11 @@
namespace Engine.Graphics.Framebuffer;
public interface IFramebufferAttachment
internal interface IFramebufferAttachment
{
internal int Handle { get; }
int Handle { get; }
public void Resize(int parWidth, int parHeight);
void Resize(int parWidth, int parHeight);
internal void Attach(Framebuffer parFramebuffer, FramebufferAttachment parAttachment);
void Attach(Framebuffer parFramebuffer, FramebufferAttachment parAttachment);
}

View File

@@ -39,12 +39,12 @@ public class Renderbuffer : OpenGlObject, IFramebufferAttachment
GL.NamedFramebufferRenderbuffer(parFramebuffer.Handle, parAttachment, RenderbufferTarget.Renderbuffer, Handle);
}
public override void Bind()
internal override void Bind()
{
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, Handle);
}
public override void Unbind()
internal override void Unbind()
{
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);
}

View File

@@ -0,0 +1,59 @@
using Engine.Graphics.Pixel;
using Engine.Graphics.Render.Mesh;
using Engine.Graphics.Render.Quad;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
namespace Engine.Graphics;
public class GenericRenderer : IRenderer
{
public QuadRenderer QuadRenderer => _quadRenderer ??= new QuadRenderer(1024 * 8);
public GlobalMeshRenderer GlobalMeshRenderer => _globalMeshRenderer ??= new GlobalMeshRenderer(1024);
private QuadRenderer? _quadRenderer;
private GlobalMeshRenderer? _globalMeshRenderer;
internal readonly Framebuffer.Framebuffer _framebuffer;
private bool _frameStarted;
public GenericRenderer(int parWidth, int parHeight)
{
_framebuffer = Framebuffer.Framebuffer.Builder(parWidth, parHeight)
.AddColorAttachment<Rgba8>()
.AddDepthAttachment()
.Build();
}
public void StartFrame()
{
_frameStarted = true;
}
public void EndFrame(in Matrix4 parProjectionMatrix, in Matrix4 parViewMatrix)
{
if (!_frameStarted)
throw new InvalidOperationException("Frame not started");
_framebuffer.Bind();
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
QuadRenderer.Render(parProjectionMatrix, parViewMatrix);
QuadRenderer.Reset();
GlobalMeshRenderer.Render(parProjectionMatrix, parViewMatrix);
GlobalMeshRenderer.Reset();
_framebuffer.Unbind();
_frameStarted = false;
}
public void Resize(int parWidth, int parHeight)
{
_framebuffer.Resize(parWidth, parHeight);
}
}

View File

@@ -6,11 +6,11 @@ namespace Engine.Graphics;
public interface IPresenter : IUpdate, IRender
{
public bool IsExiting { get; }
public int Width { get; }
public int Height { get; }
bool IsExiting { get; }
int Width { get; }
int Height { get; }
public event Action<ResizeEventArgs> Resize;
event Action<ResizeEventArgs> Resize;
public void Present(IConstTexture parTexture);
void Present(IConstTexture parTexture);
}

View File

@@ -0,0 +1,11 @@
using OpenTK.Mathematics;
namespace Engine.Graphics;
internal interface IRenderer
{
public void StartFrame();
public void EndFrame(in Matrix4 parProjectionMatrix, in Matrix4 parViewMatrix);
public void Resize(int parWidth, int parHeight);
}

View File

@@ -6,8 +6,8 @@ public abstract class OpenGlObject
{
public int Handle { get; protected set; } = -1;
public abstract void Bind();
public abstract void Unbind();
internal abstract void Bind();
internal abstract void Unbind();
protected abstract void Destroy();

View File

@@ -0,0 +1,27 @@
namespace Engine.Graphics.Pipeline;
public class RenderLayer
{
public static readonly RenderLayer DEFAULT = new("default");
public static readonly RenderLayer HUD = new("hud");
public static readonly RenderLayer OVERLAY = new("overlay");
public static readonly IReadOnlyList<RenderLayer> ALL = new List<RenderLayer> { DEFAULT, HUD, OVERLAY }.AsReadOnly();
public string Name { get; }
private RenderLayer(string parName)
{
Name = parName;
}
public override string ToString()
{
return Name;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}

View File

@@ -0,0 +1,6 @@
namespace Engine.Graphics.Pipeline;
public class RenderPipeline
{
}

View File

@@ -4,9 +4,9 @@ namespace Engine.Graphics.Pixel;
public interface IPixel
{
public PixelFormat Format { get; }
public PixelType Type { get; }
PixelFormat Format { get; }
PixelType Type { get; }
public PixelInternalFormat InternalFormat { get; }
public SizedInternalFormat SizedInternalFormat { get; }
PixelInternalFormat InternalFormat { get; }
SizedInternalFormat SizedInternalFormat { get; }
}

View File

@@ -0,0 +1,21 @@
using System.Runtime.InteropServices;
using OpenTK.Graphics.OpenGL;
namespace Engine.Graphics.Pixel;
[StructLayout(LayoutKind.Sequential)]
public struct Rgba8 : IPixel
{
public PixelFormat Format => PixelFormat.Rgba;
public PixelType Type => PixelType.UnsignedByte;
public PixelInternalFormat InternalFormat => PixelInternalFormat.Rgba8;
public SizedInternalFormat SizedInternalFormat => SizedInternalFormat.Rgba8;
public byte R;
public byte G;
public byte B;
public byte A;
public override string ToString() => $"{R}, {G}, {B}, {A}";
}

View File

@@ -10,8 +10,6 @@ public abstract class InstancedRenderer<C, I>
where C : struct, IVertex
where I : struct, IVertex
{
protected readonly Renderer _renderer;
private readonly IndexBuffer _indexBuffer;
private readonly VertexBuffer<C> _commonVertexBuffer;
private readonly VertexBuffer<I> _instanceVertexBuffer;
@@ -24,12 +22,11 @@ public abstract class InstancedRenderer<C, I>
private readonly PrimitiveType _primitiveType;
private readonly Program _program;
protected InstancedRenderer(Renderer parRenderer, PrimitiveType parPrimitiveType, int parInstanceCount,
protected InstancedRenderer(PrimitiveType parPrimitiveType, int parInstanceCount,
uint[] parIndexBuffer, C[] parInstanceBuffer,
Program parProgram)
{
_program = parProgram;
_renderer = parRenderer;
_instanceCount = parInstanceCount;
_queuedInstanceCount = 0;
_instanceVertices = new I[parInstanceCount];
@@ -53,8 +50,6 @@ public abstract class InstancedRenderer<C, I>
return;
}
_renderer.EnsureRenderThread();
_instanceVertexBuffer.UploadData(_instanceVertices, _queuedInstanceCount);
_vertexArray.Bind();

View File

@@ -3,7 +3,7 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Mesh;
public class GlobalMeshRenderer(Renderer parRenderer, int parMaxInstanceCount)
public class GlobalMeshRenderer(int parMaxInstanceCount)
{
private readonly Dictionary<Asset.Mesh.Mesh, MeshRenderer> _meshRenderers = new();
private readonly HashSet<Asset.Mesh.Mesh> _frameMeshes = [];
@@ -18,7 +18,7 @@ public class GlobalMeshRenderer(Renderer parRenderer, int parMaxInstanceCount)
}
else
{
var newMeshRenderer = new MeshRenderer(parRenderer, parMesh, parMaxInstanceCount, _program);
var newMeshRenderer = new MeshRenderer(parMesh, parMaxInstanceCount, _program);
newMeshRenderer.Commit(parModelMatrix);
_meshRenderers.Add(parMesh, newMeshRenderer);

View File

@@ -5,9 +5,9 @@ using OpenTK.Mathematics;
namespace Engine.Graphics.Render.Mesh;
public class MeshRenderer(Renderer parRenderer, Asset.Mesh.Mesh parMesh, int parInstanceCount, Program parProgram)
public class MeshRenderer(Asset.Mesh.Mesh parMesh, int parInstanceCount, Program parProgram)
: InstancedRenderer<Asset.Mesh.Mesh.Vertex, MeshInstanceVertex>(
parRenderer, PrimitiveType.Triangles,
PrimitiveType.Triangles,
parInstanceCount,
parMesh.Indices.ToArray(),
parMesh.Vertices.ToArray(),

View File

@@ -10,8 +10,8 @@ public class QuadRenderer : InstancedRenderer<QuadCommonVertex, QuadInstanceVert
private readonly TextureUnitMap _textureUnitMap = new(16);
private readonly int[] _textureUnitIndices = new int[16];
public QuadRenderer(Renderer parRenderer, int parInstanceCount)
: base(parRenderer, PrimitiveType.Triangles, parInstanceCount, [0, 1, 2, 2, 3, 0], [
public QuadRenderer(int parInstanceCount)
: base(PrimitiveType.Triangles, parInstanceCount, [0, 1, 2, 2, 3, 0], [
new QuadCommonVertex { _position = new Vector3(-0.5f, -0.5f, 0), _uv = new Vector2(0, 1) },
new QuadCommonVertex { _position = new Vector3(0.5f, -0.5f, 0), _uv = new Vector2(1, 1) },
new QuadCommonVertex { _position = new Vector3(0.5f, 0.5f, 0), _uv = new Vector2(1, 0) },

View File

@@ -1,7 +1,10 @@
using Engine.Graphics.Pixel;
using Engine.Graphics.Pipeline;
using Engine.Graphics.Pixel;
using Engine.Graphics.Render.Mesh;
using Engine.Graphics.Render.Quad;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop;
namespace Engine.Graphics;
@@ -15,15 +18,25 @@ public class Renderer
public int ViewportWidth => _framebuffer.Width;
public int ViewportHeight => _framebuffer.Height;
private readonly Dictionary<RenderLayer, GenericRenderer> _renderers = new();
internal NativeWindow NativeWindow { get; }
private readonly Framebuffer.Framebuffer _framebuffer;
private readonly Thread _renderThread;
private readonly Queue<Action> _scheduleActions = new();
public Renderer(int parWidth, int parHeight)
public Renderer(int parWidth, int parHeight, NativeWindowSettings parSettings)
{
Thread.CurrentThread.Name = "RendererThread";
#if DEBUG
Debug.InitializeRenderDoc();
#endif
NativeWindow = new NativeWindow(parSettings);
InitializeOpenGl(parWidth, parHeight);
_renderThread = Thread.CurrentThread;
@@ -33,8 +46,8 @@ public class Renderer
.AddDepthAttachment()
.Build();
QuadRenderer = new QuadRenderer(this, 1024 * 8);
GlobalMeshRenderer = new GlobalMeshRenderer(this, 1024);
QuadRenderer = new QuadRenderer(1024 * 8);
GlobalMeshRenderer = new GlobalMeshRenderer(1024);
}
private void InitializeOpenGl(int parWidth, int parHeight)
@@ -77,13 +90,31 @@ public class Renderer
_framebuffer.Bind();
GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Clear(ClearBufferMask.ColorBufferBit);
// foreach (var renderer in _renderers.Values)
// {
// renderer.StartFrame();
// }
}
internal void EndFrame()
internal void EndFrame(in Matrix4 parViewMatrix, in Matrix4 parProjectionMatrix)
{
EnsureRenderThread();
// foreach (var renderer in _renderers.Values)
// {
// renderer.EndFrame(in parViewMatrix, in parProjectionMatrix);
// }
//
// foreach (var renderer in _renderers.Values)
// {
// QuadRenderer.Commit(Matrix4.CreateScale(2f), Vector4.One, renderer._framebuffer.TextureInternal);
// }
//
// QuadRenderer.Render(in parProjectionMatrix, in parViewMatrix);
// QuadRenderer.Reset();
_framebuffer.Unbind();
}

View File

@@ -62,12 +62,12 @@ public class Program : OpenGlObject
}
}
public override void Bind()
internal override void Bind()
{
GL.UseProgram(Handle);
}
public override void Unbind()
internal override void Unbind()
{
GL.UseProgram(0);
}

View File

@@ -127,12 +127,12 @@ public abstract class Texture : OpenGlObject, ITexture
GL.BindTextureUnit(parUnit, Handle);
}
public override void Bind()
internal override void Bind()
{
GL.BindTexture(TextureTarget.Texture2D, Handle);
}
public override void Unbind()
internal override void Unbind()
{
GL.BindTexture(TextureTarget.Texture2D, 0);
}