From 128c3785633ffb754526462cadf8361aeb5e0e3f Mon Sep 17 00:00:00 2001 From: John Gietzen Date: Wed, 6 Mar 2024 20:26:43 -0800 Subject: [PATCH 1/4] Repaint on resize/drag. --- .../Interfaces/IView.cs | 5 +++ .../Internals/ViewImplementationBase.cs | 1 + .../netstandard2.0/PublicAPI.Shipped.txt | 1 + .../netstandard2.1/PublicAPI.Shipped.txt | 1 + .../WindowExtensions.cs | 36 +++++++++++-------- .../Silk.NET.Windowing.Glfw/GlfwWindow.cs | 10 ++++++ .../Silk.NET.Windowing.Sdl/SdlView.cs | 1 + 7 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/Windowing/Silk.NET.Windowing.Common/Interfaces/IView.cs b/src/Windowing/Silk.NET.Windowing.Common/Interfaces/IView.cs index d172f1b7a5..c7d95a6792 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Interfaces/IView.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/Interfaces/IView.cs @@ -47,6 +47,11 @@ public interface IView : IViewProperties, IGLContextSource, IVkSurfaceSource, ID /// event Action>? FramebufferResize; + /// + /// Raised when the window is being refreshed. + /// + event Action? Refresh; + /// /// Raised when the window is about to close. /// diff --git a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs index c9b108137a..471a0df878 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs @@ -79,6 +79,7 @@ protected ViewImplementationBase(ViewOptions opts) // Events public abstract event Action>? Resize; public abstract event Action>? FramebufferResize; + public abstract event Action? Refresh; public abstract event Action? Closing; public abstract event Action? FocusChanged; public event Action? Load; diff --git a/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt b/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt index 257c914b4b..dc93508072 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt +++ b/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt @@ -47,6 +47,7 @@ Silk.NET.Windowing.IView.DoUpdate() -> void Silk.NET.Windowing.IView.FocusChanged -> System.Action? Silk.NET.Windowing.IView.FramebufferResize -> System.Action>? Silk.NET.Windowing.IView.FramebufferSize.get -> Silk.NET.Maths.Vector2D +Silk.NET.Windowing.IView.Refresh -> System.Action? Silk.NET.Windowing.IView.Handle.get -> nint Silk.NET.Windowing.IView.Initialize() -> void Silk.NET.Windowing.IView.Invoke(System.Delegate! d, params object![]! args) -> object! diff --git a/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt b/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt index 257c914b4b..dc93508072 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt +++ b/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt @@ -47,6 +47,7 @@ Silk.NET.Windowing.IView.DoUpdate() -> void Silk.NET.Windowing.IView.FocusChanged -> System.Action? Silk.NET.Windowing.IView.FramebufferResize -> System.Action>? Silk.NET.Windowing.IView.FramebufferSize.get -> Silk.NET.Maths.Vector2D +Silk.NET.Windowing.IView.Refresh -> System.Action? Silk.NET.Windowing.IView.Handle.get -> nint Silk.NET.Windowing.IView.Initialize() -> void Silk.NET.Windowing.IView.Invoke(System.Delegate! d, params object![]! args) -> object! diff --git a/src/Windowing/Silk.NET.Windowing.Common/WindowExtensions.cs b/src/Windowing/Silk.NET.Windowing.Common/WindowExtensions.cs index 531bcfb7f8..dfa70caf8f 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/WindowExtensions.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/WindowExtensions.cs @@ -43,21 +43,29 @@ public static void Invoke(this IView view, Action t) public static void Run(this IView view) { view.Initialize(); - view.Run - ( - () => + + void OnFrame() + { + view.DoEvents(); + DoFrame(); + } + + void DoFrame() + { + if (!view.IsClosing) { - view.DoEvents(); - if (!view.IsClosing) - { - view.DoUpdate(); - } - if (!view.IsClosing) - { - view.DoRender(); - } + view.DoUpdate(); } - ); + + if (!view.IsClosing) + { + view.DoRender(); + } + } + + view.Refresh += DoFrame; + view.Run(OnFrame); + view.Refresh -= DoFrame; view.DoEvents(); view.Reset(); @@ -113,4 +121,4 @@ public static void SetWindowIcon(this IWindow window, ref RawImage icon) => wind (new[] { icon }); #endif } -} \ No newline at end of file +} diff --git a/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs b/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs index 15030d3772..1a8e690f2d 100644 --- a/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs +++ b/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs @@ -23,6 +23,7 @@ internal unsafe class GlfwWindow : WindowImplementationBase, IVkSurface private GlfwCallbacks.WindowPosCallback? _onMove; private GlfwCallbacks.WindowSizeCallback? _onResize; private GlfwCallbacks.FramebufferSizeCallback? _onFramebufferResize; + private GlfwCallbacks.WindowRefreshCallback? _onRefresh; private GlfwCallbacks.DropCallback? _onFileDrop; private GlfwCallbacks.WindowCloseCallback? _onClosing; private GlfwCallbacks.WindowFocusCallback? _onFocusChanged; @@ -658,6 +659,11 @@ protected override void RegisterCallbacks() FramebufferResize?.Invoke(new(width, height)); }; + _onRefresh = (window) => + { + Refresh?.Invoke(); + }; + _onClosing = window => Closing?.Invoke(); _onFocusChanged = (window, isFocused) => FocusChanged?.Invoke(isFocused); @@ -744,6 +750,7 @@ protected override void RegisterCallbacks() _glfw.SetWindowIconifyCallback(_glfwWindow, _onMinimized); _glfw.SetWindowMaximizeCallback(_glfwWindow, _onMaximized); _glfw.SetFramebufferSizeCallback(_glfwWindow, _onFramebufferResize); + _glfw.SetWindowRefreshCallback(_glfwWindow, _onRefresh); _glfw.SetDropCallback(_glfwWindow, _onFileDrop); GLFW.Glfw.ThrowExceptions(); } @@ -761,6 +768,7 @@ protected override void UnregisterCallbacks() _glfw.GcUtility.Unpin(_onMove); _glfw.GcUtility.Unpin(_onResize); _glfw.GcUtility.Unpin(_onFramebufferResize); + _glfw.GcUtility.Unpin(_onRefresh); _glfw.GcUtility.Unpin(_onFileDrop); _glfw.GcUtility.Unpin(_onFocusChanged); @@ -770,6 +778,7 @@ protected override void UnregisterCallbacks() _onMove = null; _onResize = null; _onFramebufferResize = null; + _onRefresh = null; _onFileDrop = null; _onFocusChanged = null; } @@ -789,6 +798,7 @@ protected override void UnregisterCallbacks() public override event Action>? Resize; public override event Action>? FramebufferResize; + public override event Action? Refresh; public override event Action? Closing; public override event Action? FocusChanged; diff --git a/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs b/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs index 41fcdeed4a..62ce998415 100644 --- a/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs +++ b/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs @@ -50,6 +50,7 @@ public SdlView(void* nativeHandle, IGLContext? ctx, SdlPlatform platform) : base // Events public override event System.Action>? Resize; public override event System.Action>? FramebufferResize; + public override event System.Action? Refresh; public override event System.Action? Closing; public override event System.Action? FocusChanged; From f659aa0af316554a06dc448aca7172439ac4809a Mon Sep 17 00:00:00 2001 From: John Gietzen Date: Thu, 7 Mar 2024 12:57:05 -0800 Subject: [PATCH 2/4] Remove API changes. --- .../Interfaces/IView.cs | 5 --- .../Internals/ViewImplementationBase.cs | 1 - .../netstandard2.0/PublicAPI.Shipped.txt | 1 - .../netstandard2.1/PublicAPI.Shipped.txt | 1 - .../WindowExtensions.cs | 36 ++++++++----------- .../Silk.NET.Windowing.Glfw/GlfwWindow.cs | 10 ++++-- .../Silk.NET.Windowing.Sdl/SdlView.cs | 1 - 7 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/Windowing/Silk.NET.Windowing.Common/Interfaces/IView.cs b/src/Windowing/Silk.NET.Windowing.Common/Interfaces/IView.cs index c7d95a6792..d172f1b7a5 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Interfaces/IView.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/Interfaces/IView.cs @@ -47,11 +47,6 @@ public interface IView : IViewProperties, IGLContextSource, IVkSurfaceSource, ID /// event Action>? FramebufferResize; - /// - /// Raised when the window is being refreshed. - /// - event Action? Refresh; - /// /// Raised when the window is about to close. /// diff --git a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs index 471a0df878..c9b108137a 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs @@ -79,7 +79,6 @@ protected ViewImplementationBase(ViewOptions opts) // Events public abstract event Action>? Resize; public abstract event Action>? FramebufferResize; - public abstract event Action? Refresh; public abstract event Action? Closing; public abstract event Action? FocusChanged; public event Action? Load; diff --git a/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt b/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt index dc93508072..257c914b4b 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt +++ b/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.0/PublicAPI.Shipped.txt @@ -47,7 +47,6 @@ Silk.NET.Windowing.IView.DoUpdate() -> void Silk.NET.Windowing.IView.FocusChanged -> System.Action? Silk.NET.Windowing.IView.FramebufferResize -> System.Action>? Silk.NET.Windowing.IView.FramebufferSize.get -> Silk.NET.Maths.Vector2D -Silk.NET.Windowing.IView.Refresh -> System.Action? Silk.NET.Windowing.IView.Handle.get -> nint Silk.NET.Windowing.IView.Initialize() -> void Silk.NET.Windowing.IView.Invoke(System.Delegate! d, params object![]! args) -> object! diff --git a/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt b/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt index dc93508072..257c914b4b 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt +++ b/src/Windowing/Silk.NET.Windowing.Common/PublicAPI/netstandard2.1/PublicAPI.Shipped.txt @@ -47,7 +47,6 @@ Silk.NET.Windowing.IView.DoUpdate() -> void Silk.NET.Windowing.IView.FocusChanged -> System.Action? Silk.NET.Windowing.IView.FramebufferResize -> System.Action>? Silk.NET.Windowing.IView.FramebufferSize.get -> Silk.NET.Maths.Vector2D -Silk.NET.Windowing.IView.Refresh -> System.Action? Silk.NET.Windowing.IView.Handle.get -> nint Silk.NET.Windowing.IView.Initialize() -> void Silk.NET.Windowing.IView.Invoke(System.Delegate! d, params object![]! args) -> object! diff --git a/src/Windowing/Silk.NET.Windowing.Common/WindowExtensions.cs b/src/Windowing/Silk.NET.Windowing.Common/WindowExtensions.cs index dfa70caf8f..531bcfb7f8 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/WindowExtensions.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/WindowExtensions.cs @@ -43,29 +43,21 @@ public static void Invoke(this IView view, Action t) public static void Run(this IView view) { view.Initialize(); - - void OnFrame() - { - view.DoEvents(); - DoFrame(); - } - - void DoFrame() - { - if (!view.IsClosing) - { - view.DoUpdate(); - } - - if (!view.IsClosing) + view.Run + ( + () => { - view.DoRender(); + view.DoEvents(); + if (!view.IsClosing) + { + view.DoUpdate(); + } + if (!view.IsClosing) + { + view.DoRender(); + } } - } - - view.Refresh += DoFrame; - view.Run(OnFrame); - view.Refresh -= DoFrame; + ); view.DoEvents(); view.Reset(); @@ -121,4 +113,4 @@ public static void SetWindowIcon(this IWindow window, ref RawImage icon) => wind (new[] { icon }); #endif } -} +} \ No newline at end of file diff --git a/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs b/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs index 1a8e690f2d..31b1f8b048 100644 --- a/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs +++ b/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs @@ -661,7 +661,14 @@ protected override void RegisterCallbacks() _onRefresh = (window) => { - Refresh?.Invoke(); + if (!IsClosing) + { + DoUpdate(); + } + if (!IsClosing) + { + DoRender(); + } }; _onClosing = window => Closing?.Invoke(); @@ -798,7 +805,6 @@ protected override void UnregisterCallbacks() public override event Action>? Resize; public override event Action>? FramebufferResize; - public override event Action? Refresh; public override event Action? Closing; public override event Action? FocusChanged; diff --git a/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs b/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs index 62ce998415..41fcdeed4a 100644 --- a/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs +++ b/src/Windowing/Silk.NET.Windowing.Sdl/SdlView.cs @@ -50,7 +50,6 @@ public SdlView(void* nativeHandle, IGLContext? ctx, SdlPlatform platform) : base // Events public override event System.Action>? Resize; public override event System.Action>? FramebufferResize; - public override event System.Action? Refresh; public override event System.Action? Closing; public override event System.Action? FocusChanged; From cc0140bd3545de00c19bcd1b69784ba34d06645a Mon Sep 17 00:00:00 2001 From: John Gietzen Date: Tue, 19 Mar 2024 16:22:51 -0700 Subject: [PATCH 3/4] Use the same `onRender` action for Glfw's refresh events, but prevent reentrancy into DoEvents. --- .../Internals/ViewImplementationBase.cs | 22 ++++++++++-- .../Silk.NET.Windowing.Glfw/GlfwWindow.cs | 36 ++++++++++--------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs index c9b108137a..1fd7351e35 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs @@ -76,6 +76,15 @@ protected ViewImplementationBase(ViewOptions opts) protected abstract void UnregisterCallbacks(); protected abstract INativeWindow GetNativeWindow(); + /// + /// The action passed to . + /// + /// + /// May be called on repaint from within . + /// For example, during modal operations such as resizing on Windows. + /// + protected Action? _onFrame; + // Events public abstract event Action>? Resize; public abstract event Action>? FramebufferResize; @@ -164,9 +173,18 @@ protected VideoMode CachedVideoMode // Game loop implementation public virtual void Run(Action onFrame) { - while (!IsClosing) + try + { + _onFrame = onFrame; + + while (!IsClosing) + { + onFrame(); + } + } + finally { - onFrame(); + _onFrame = null; } } diff --git a/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs b/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs index 31b1f8b048..d18cd5978a 100644 --- a/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs +++ b/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs @@ -38,6 +38,7 @@ internal unsafe class GlfwWindow : WindowImplementationBase, IVkSurface private string _localTitleCache; // glfw doesn't let us get the window title. private GlfwContext? _glContext; private string _windowClass; + private bool _inDoEvents; public GlfwWindow(WindowOptions optionsCache, GlfwWindow? parent, GlfwMonitor? monitor) : base(optionsCache) { @@ -599,13 +600,24 @@ public override Vector2D FramebufferSize public override void DoEvents() { - if (IsEventDriven) + if (!_inDoEvents) { - _glfw.WaitEvents(); - } - else - { - _glfw.PollEvents(); + try + { + _inDoEvents = true; + if (IsEventDriven) + { + _glfw.WaitEvents(); + } + else + { + _glfw.PollEvents(); + } + } + finally + { + _inDoEvents = false; + } } } @@ -659,17 +671,7 @@ protected override void RegisterCallbacks() FramebufferResize?.Invoke(new(width, height)); }; - _onRefresh = (window) => - { - if (!IsClosing) - { - DoUpdate(); - } - if (!IsClosing) - { - DoRender(); - } - }; + _onRefresh = (window) => _onFrame?.Invoke(); _onClosing = window => Closing?.Invoke(); From c6766184a4fbaf2be2880eb18414cb31aacc3767 Mon Sep 17 00:00:00 2001 From: John Gietzen Date: Tue, 19 Mar 2024 16:29:11 -0700 Subject: [PATCH 4/4] Move protected _onFrame field into the GlfwWindow class rather than the base ViewImplementationBase class. --- .../Internals/ViewImplementationBase.cs | 22 ++----------------- .../Silk.NET.Windowing.Glfw/GlfwWindow.cs | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs index 1fd7351e35..c9b108137a 100644 --- a/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs +++ b/src/Windowing/Silk.NET.Windowing.Common/Internals/ViewImplementationBase.cs @@ -76,15 +76,6 @@ protected ViewImplementationBase(ViewOptions opts) protected abstract void UnregisterCallbacks(); protected abstract INativeWindow GetNativeWindow(); - /// - /// The action passed to . - /// - /// - /// May be called on repaint from within . - /// For example, during modal operations such as resizing on Windows. - /// - protected Action? _onFrame; - // Events public abstract event Action>? Resize; public abstract event Action>? FramebufferResize; @@ -173,18 +164,9 @@ protected VideoMode CachedVideoMode // Game loop implementation public virtual void Run(Action onFrame) { - try - { - _onFrame = onFrame; - - while (!IsClosing) - { - onFrame(); - } - } - finally + while (!IsClosing) { - _onFrame = null; + onFrame(); } } diff --git a/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs b/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs index d18cd5978a..d6aca425df 100644 --- a/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs +++ b/src/Windowing/Silk.NET.Windowing.Glfw/GlfwWindow.cs @@ -40,6 +40,15 @@ internal unsafe class GlfwWindow : WindowImplementationBase, IVkSurface private string _windowClass; private bool _inDoEvents; + /// + /// The action passed to . + /// + /// + /// May be called on repaint from within . + /// For example, during modal operations such as resizing on Windows. + /// + protected Action? _onFrame; + public GlfwWindow(WindowOptions optionsCache, GlfwWindow? parent, GlfwMonitor? monitor) : base(optionsCache) { _glfw = GlfwProvider.GLFW.Value; @@ -69,6 +78,19 @@ protected override Rectangle CoreBorderSize protected override nint CoreHandle => (nint) _glfwWindow; + public override void Run(Action onFrame) + { + try + { + _onFrame = onFrame; + base.Run(onFrame); + } + finally + { + _onFrame = null; + } + } + protected override void CoreReset() { if (_glfwWindow == null)