From b40af1200adf492739b7778abfbabbf575b2bc27 Mon Sep 17 00:00:00 2001 From: dnesov Date: Sun, 18 Aug 2024 19:53:31 +0200 Subject: [PATCH] Initialize WebGPU --- TestGame/TestGame.cs | 43 ++-- Voile/Source/Audio/FmodAudioBackend.cs | 2 +- Voile/Source/Rendering/StandardRenderer.cs | 254 +++++++++++++++------ Voile/Voile.csproj | 4 +- 4 files changed, 208 insertions(+), 95 deletions(-) diff --git a/TestGame/TestGame.cs b/TestGame/TestGame.cs index 31a4fa0..dace329 100644 --- a/TestGame/TestGame.cs +++ b/TestGame/TestGame.cs @@ -14,9 +14,9 @@ public class TestGame : Game public override void Initialize() { - _renderer = new RaylibRenderer(); + _renderer = new StandardRenderer(); _audioBackend = new FmodAudioBackend(); - _inputHandler = new RaylibInputHandler(); + // _inputHandler = new RaylibInputHandler(); _resourceManager.AddResourceSaverAssociation(new SerializedSceneSaver()); @@ -27,7 +27,7 @@ public class TestGame : Game }, new RendererSettings() { UseVSync = true, - Fullscreen = true + Fullscreen = false }); _audioBackend.Initialize(); @@ -70,33 +70,36 @@ public class TestGame : Game protected override void Ready() { - _inputHandler!.AddInputMapping("play", new InputAction[] { new KeyInputAction(KeyboardKey.Spacebar) }); - _inputHandler.AddInputMapping("sprint", new InputAction[] { new KeyInputAction(KeyboardKey.LeftShift) }); - _inputHandler.AddInputMapping("toggle_fullscreen", new InputAction[] { new KeyInputAction(KeyboardKey.F11) }); + // _inputHandler!.AddInputMapping("play", new InputAction[] { new KeyInputAction(KeyboardKey.Spacebar) }); + // _inputHandler.AddInputMapping("sprint", new InputAction[] { new KeyInputAction(KeyboardKey.LeftShift) }); + // _inputHandler.AddInputMapping("toggle_fullscreen", new InputAction[] { new KeyInputAction(KeyboardKey.F11) }); - _scene!.AddLayer("World", _worldLayer!); + // _scene!.AddLayer("World", _worldLayer!); - _worldLayer!.AddEntity(new World()); - _worldLayer.AddEntity(new TestPlayer()); + // _worldLayer!.AddEntity(new World()); + // _worldLayer.AddEntity(new TestPlayer()); - _scene.AddLayer("UI", _uiLayer!); - _scene.Start(); + // _scene.AddLayer("UI", _uiLayer!); + // _scene.Start(); } protected override void Run() { - while (_scene!.ShouldRun) + while (_renderer.ShouldRun) { - _scene.Update(); + // _scene.Update(); - if (_inputHandler!.IsActionPressed("toggle_fullscreen")) - { - _renderer!.Fullscreen = !_renderer.Fullscreen; - _logger.Info($"Fullscreen: {_renderer.Fullscreen}"); - } + // if (_inputHandler!.IsActionPressed("toggle_fullscreen")) + // { + // _renderer!.Fullscreen = !_renderer.Fullscreen; + // _logger.Info($"Fullscreen: {_renderer.Fullscreen}"); + // } - _scene.BeginDraw(); - _scene.EndDraw(); + // _scene.BeginDraw(); + // _scene.EndDraw(); + _renderer.BeginFrame(); + // _renderer.ClearBackground(Color.White); + _renderer.EndFrame(); } } diff --git a/Voile/Source/Audio/FmodAudioBackend.cs b/Voile/Source/Audio/FmodAudioBackend.cs index bdfa673..3674042 100644 --- a/Voile/Source/Audio/FmodAudioBackend.cs +++ b/Voile/Source/Audio/FmodAudioBackend.cs @@ -124,7 +124,7 @@ namespace Voile.Audio public override void Shutdown() { - throw new NotImplementedException(); + } private FMOD.System _system; diff --git a/Voile/Source/Rendering/StandardRenderer.cs b/Voile/Source/Rendering/StandardRenderer.cs index 879107a..d9de609 100644 --- a/Voile/Source/Rendering/StandardRenderer.cs +++ b/Voile/Source/Rendering/StandardRenderer.cs @@ -1,20 +1,22 @@ -using System.Drawing; using System.Numerics; -using Silk.NET.GLFW; -using Silk.NET.OpenGL; +using Silk.NET.Windowing; +using Silk.NET.WebGPU; +using Silk.NET.Maths; +using Voile.Utils; +using System.Runtime.InteropServices; namespace Voile.Rendering { /// - /// A standard, OpenGL-based renderer. + /// A standard, WebGPU-based renderer. /// public class StandardRenderer : Renderer { /// public override Vector2 WindowSize { get; set; } /// - public override bool ShouldRun => throw new NotImplementedException(); + public override bool ShouldRun => !_window?.IsClosing ?? false; public override Vector2 MonitorSize => throw new NotImplementedException(); @@ -23,13 +25,20 @@ namespace Voile.Rendering public override string WindowTitle { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public override bool Fullscreen { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - - - /// public override void Initialize(RendererSettings settings) { + _logger.Info("Initializing WebGPU..."); + CreateApi(); + CreateInstance(); + CreateSurface(); + CreateAdapter(); + CreateDevice(); + + ConfigureDebugCallback(); + + ConfigureSurface(); } /// @@ -39,31 +48,51 @@ namespace Voile.Rendering Initialize(renderSettings); } - public override void BeginFrame() - { - _glfw.PollEvents(); - _gl.Viewport(new Size((int)_windowSize.X, (int)_windowSize.Y)); - } - - /// - public override void EndFrame() + public override void CreateWindow(WindowSettings windowSettings) { // throw new NotImplementedException(); - EndFrameUnsafe(); + _logger.Info("Creating window..."); + + WindowOptions windowOptions = WindowOptions.Default; + windowOptions.Size = new Vector2D((int)windowSettings.Size.X, (int)windowSettings.Size.Y); + windowOptions.Title = windowSettings.Title; + windowOptions.API = GraphicsAPI.None; + + _window = Window.Create(windowOptions); + _window.Initialize(); + } + + public override void BeginFrame() + { + _window!.DoEvents(); + _window.DoUpdate(); + _window.DoRender(); } /// public override void ClearBackground(Color color) { - _gl.ClearColor(color.ToSystemColor()); - _gl.Clear((uint)ClearBufferMask.ColorBufferBit); + throw new NotImplementedException(); } - /// - public override void Shutdown() + public override void DrawText(Font font, string text, Color color) { - CloseWindowUnsafe(); - _glfw.Terminate(); + throw new NotImplementedException(); + } + + public override void DrawSdfText(string text, int fontSize, Color color) + { + throw new NotImplementedException(); + } + + public override void BeginCamera2d(Vector2 offset, Vector2 target, float rotation, float zoom) + { + throw new NotImplementedException(); + } + + public override void EndCamera2d() + { + throw new NotImplementedException(); } /// @@ -90,6 +119,22 @@ namespace Voile.Rendering throw new NotImplementedException(); } + /// + public override void EndFrame() + { + + } + + /// + public override void Shutdown() + { + _window!.DoEvents(); + _window.Reset(); + _window.Dispose(); + + ShutdownUnsafe(); + } + /// protected override double GetFrameTime() { @@ -111,7 +156,7 @@ namespace Voile.Rendering /// protected override void SetWindowTitle(string title) { - SetWindowTitleUnsafe(title); + throw new NotImplementedException(); } /// @@ -121,50 +166,7 @@ namespace Voile.Rendering } /// - protected override bool WindowShouldClose() => WindowShouldCloseUnsafe(); - - private unsafe void CreateWindowUnsafe(string title, Vector2 size) - { - _glfw = GlfwProvider.GLFW.Value; - _glfw.Init(); - - _glfw.WindowHint(WindowHintInt.ContextVersionMajor, 4); - _glfw.WindowHint(WindowHintInt.ContextVersionMinor, 6); - _windowHandle = _glfw.CreateWindow((int)size.X, (int)size.Y, title, null, null); - - _glfw.MakeContextCurrent(_windowHandle); - _gl = GL.GetApi(_glfw.GetProcAddress); - _glfw.SwapInterval(1); - - _windowSize = size; - } - private unsafe void CloseWindowUnsafe() => _glfw.DestroyWindow(_windowHandle); - private unsafe bool WindowShouldCloseUnsafe() => _glfw.WindowShouldClose(_windowHandle); - private unsafe void SetWindowTitleUnsafe(string title) => _glfw.SetWindowTitle(_windowHandle, title); - private unsafe void EndFrameUnsafe() - { - _glfw.SwapBuffers(_windowHandle); - } - - public override void DrawSdfText(string text, int fontSize, Color color) - { - throw new NotImplementedException(); - } - - public override void BeginCamera2d(Vector2 offset, Vector2 target, float rotation, float zoom) - { - throw new NotImplementedException(); - } - - public override void EndCamera2d() - { - throw new NotImplementedException(); - } - - public override void CreateWindow(WindowSettings windowSettings) - { - throw new NotImplementedException(); - } + protected override bool WindowShouldClose() => throw new NotImplementedException(); protected override int GetMonitorWidth(int monitorId) { @@ -181,14 +183,120 @@ namespace Voile.Rendering throw new NotImplementedException(); } - public override void DrawText(Font font, string text, Color color) + private unsafe void CreateApi() { - throw new NotImplementedException(); + _wgpu = WebGPU.GetApi(); + } + + private unsafe void CreateInstance() + { + InstanceDescriptor descriptor = new(); + _instance = _wgpu!.CreateInstance(descriptor); + } + + private unsafe void CreateSurface() + { + _surface = _window.CreateWebGPUSurface(_wgpu, _instance); + } + + private unsafe void CreateAdapter() + { + RequestAdapterOptions adapterOptions = new() + { + CompatibleSurface = _surface, + // TODO: do not force Vulkan, let user choose their own API. + BackendType = BackendType.Vulkan, + PowerPreference = PowerPreference.HighPerformance + }; + + PfnRequestAdapterCallback callback = PfnRequestAdapterCallback.From( + (status, adapter, msgPtr, userDataPtr) => + { + if (status == RequestAdapterStatus.Success) + { + _adapter = adapter; + + AdapterProperties adapterProperties = new(); + + _wgpu.AdapterGetProperties(_adapter, &adapterProperties); + + string deviceName = Marshal.PtrToStringAnsi((IntPtr)adapterProperties.Name); + + _logger.Info($"Retrieved WebGPU Adapter ({deviceName})"); + } + else + { + string msg = Marshal.PtrToStringAnsi((IntPtr)msgPtr); + _logger.Error($"Error while retrieving WebGPU Adapter: {msg}"); + } + }); + + _wgpu.InstanceRequestAdapter(_instance, adapterOptions, callback, null); + } + + private unsafe void CreateDevice() + { + DeviceDescriptor deviceDescriptor = new(); + + PfnRequestDeviceCallback callback = PfnRequestDeviceCallback.From( + (status, device, msgPtr, userDataPtr) => + { + if (status == RequestDeviceStatus.Success) + { + _device = device; + _logger.Info($"Retrieved WebGPU Device."); + } + else + { + string msg = Marshal.PtrToStringAnsi((IntPtr)msgPtr); + _logger.Error($"Error while retrieving WebGPU Device: {msg}"); + } + }); + + _wgpu.AdapterRequestDevice(_adapter, deviceDescriptor, callback, null); + } + + private unsafe void ConfigureSurface() + { + SurfaceConfiguration configuration = new SurfaceConfiguration(); + configuration.Device = _device; + configuration.Width = (uint)_window!.Size.X; + configuration.Height = (uint)_window.Size.Y; + configuration.Format = Silk.NET.WebGPU.TextureFormat.Bgra8Unorm; + configuration.PresentMode = PresentMode.Fifo; + + _wgpu!.SurfaceConfigure(_surface, configuration); + } + + private unsafe void ConfigureDebugCallback() + { + PfnErrorCallback callback = PfnErrorCallback.From((type, msgPtr, userDataPtr) => + { + string msg = Marshal.PtrToStringAnsi((IntPtr)msgPtr); + _logger.Error($"WebGPU Error: {msg}"); + }); + + _wgpu.DeviceSetUncapturedErrorCallback(_device, callback, null); + _logger.Info("WGPU Debug Callback Configured."); + } + + private unsafe void ShutdownUnsafe() + { + _wgpu.DeviceDestroy(_device); + _wgpu.InstanceRelease(_instance); + _wgpu.SurfaceRelease(_surface); + _wgpu.AdapterRelease(_adapter); } - private GL _gl; - private Glfw _glfw; - private unsafe WindowHandle* _windowHandle; private Vector2 _windowSize; + private IWindow? _window; + + private WebGPU? _wgpu; + private unsafe Instance* _instance; + private unsafe Surface* _surface; + private unsafe Adapter* _adapter; + private unsafe Device* _device; + + private Logger _logger = new(nameof(StandardRenderer)); } } \ No newline at end of file diff --git a/Voile/Voile.csproj b/Voile/Voile.csproj index 93e3b7a..9f98fa8 100644 --- a/Voile/Voile.csproj +++ b/Voile/Voile.csproj @@ -9,11 +9,13 @@ + + + -