diff --git a/engine/Definitions/tools/QtWidgets/DockManager.def b/engine/Definitions/tools/QtWidgets/DockManager.def index 9339beb7..66987393 100644 --- a/engine/Definitions/tools/QtWidgets/DockManager.def +++ b/engine/Definitions/tools/QtWidgets/DockManager.def @@ -25,12 +25,6 @@ native class ads::CDockManager as Native.CDockManager : QWidget ads::CDockManager::setConfigFlag( ads::CDockManager::OpaqueSplitterResize, true ); ads::CDockManager::setConfigFlag( ads::CDockManager::TabCloseButtonIsToolButton, true ); ads::CDockManager::setConfigFlag( ads::CDockManager::DisableStylesheet, true ); - - // Dock containers host native render widgets (swapchains). Making dock/area/floating - // windows native keeps the widget hierarchy natively parented, so floating and - // re-docking doesn't destroy and recreate the render widget's window out from - // under its swapchain. - ads::CDockManager::setConfigFlag( ads::CDockManager::UseNativeWindows, true ); } static CDockManager Create( QWidget parent ); [new] diff --git a/engine/Definitions/tools/QtWidgets/QWidget.def b/engine/Definitions/tools/QtWidgets/QWidget.def index 16322db7..7bdbd925 100644 --- a/engine/Definitions/tools/QtWidgets/QWidget.def +++ b/engine/Definitions/tools/QtWidgets/QWidget.def @@ -145,12 +145,6 @@ native class QWidget as Native.QWidget : QObject QWidget parentWidget(); QWidget window(); - inline void setTransientParent( QWidget parent ) - { - self->winId(); - parent->winId(); - self->windowHandle()->setTransientParent( parent->windowHandle() ); - } void AddClassName( QString name ); void Polish(); diff --git a/engine/Sandbox.Tools/Editor/FullScreenManager.cs b/engine/Sandbox.Tools/Editor/FullScreenManager.cs index e616e47f..dac526f0 100644 --- a/engine/Sandbox.Tools/Editor/FullScreenManager.cs +++ b/engine/Sandbox.Tools/Editor/FullScreenManager.cs @@ -27,24 +27,19 @@ internal partial class FullScreenManager /// public void Clear() { - if ( Widget is null ) + if ( !Widget.IsValid() ) return; - EditorWindow.DockManager.Visible = true; - if ( EditorWindow.Console.IsValid() ) { EditorWindow.Console.Input.FocusMode = FocusMode.TabOrClick; } - if ( Widget.IsValid() ) - { - Widget.Parent = PreviousParent; + Widget.Parent = PreviousParent; - if ( PreviousParent.IsValid() ) - { - PreviousParent.Layout?.Add( Widget ); - } + if ( PreviousParent.IsValid() ) + { + PreviousParent.Layout?.Add( Widget ); } Widget = null; @@ -54,15 +49,8 @@ internal partial class FullScreenManager [EditorEvent.Frame] public void OnFrame() { - if ( Widget is null ) - return; - - // If the widget died while fullscreen, restore the docks if ( !Widget.IsValid() ) - { - Clear(); return; - } if ( Widget.Size != GetTargetSize() || Widget.Position != GetTargetPosition() ) { @@ -113,10 +101,6 @@ internal partial class FullScreenManager // Set our target widget's parent to the editor's main window, so we can size it properly widget.Parent = EditorWindow; - // The docks are native windows, which always draw above sibling widget content, - // so the fullscreen widget can't simply cover them - hide them while it's active - EditorWindow.DockManager.Visible = false; - // Make sure we kill focus from the console if ( EditorWindow.Console.IsValid() ) { diff --git a/engine/Sandbox.Tools/Qt/SceneRenderingWidget.cs b/engine/Sandbox.Tools/Qt/SceneRenderingWidget.cs index 58bd15ed..060728fe 100644 --- a/engine/Sandbox.Tools/Qt/SceneRenderingWidget.cs +++ b/engine/Sandbox.Tools/Qt/SceneRenderingWidget.cs @@ -12,9 +12,6 @@ public class SceneRenderingWidget : Frame internal SwapChainHandle_t SwapChain; - // A released swapchain is destroyed at frame end and owns our window until then - private bool _destroyPending; - /// /// The active scene that we're rendering /// @@ -39,10 +36,6 @@ public class SceneRenderingWidget : Frame public SceneRenderingWidget( Widget parent = null ) : base( parent ) { - // Keep ancestors non-native, otherwise every dock splitter above us becomes a - // real HWND and resizes recurse through Win32 until stack overflow. Must be - // set before WA_NativeWindow. See qtoolscenewidget.cpp for the full story. - SetFlag( Flag.WA_DontCreateNativeAncestors, true ); SetFlag( Flag.WA_NativeWindow, true ); SetFlag( Flag.WA_PaintOnScreen, true ); SetFlag( Flag.WA_NoSystemBackground, true ); @@ -69,7 +62,10 @@ public class SceneRenderingWidget : Frame All.Remove( this ); RenderSettings.Instance.OnVideoSettingsChanged -= HandleVideoChanged; - ReleaseSwapChain(); + // The swapchain might still be in use by native, so defer its destruction until the end of the frame. + // Otherwise, a race condition could occur where render targets are accessed after destruction, causing a delayed crash. + EngineLoop.DisposeAtFrameEnd( new Sandbox.Utility.DisposeAction( () => g_pRenderDevice.DestroySwapChain( SwapChain ) ) ); + SwapChain = default; GizmoInstance?.Dispose(); GizmoInstance = default; @@ -162,43 +158,12 @@ public class SceneRenderingWidget : Frame UpdateGizmoInputs( ref GizmoInstance.Input, camera, hasMouseFocus ); } - // Qt destroys and recreates our native window when a dock reparents us into - // another window - release the swapchain and Render will rebuild it against - // the new handle. - internal override void OnWinIdChanged() - { - ReleaseSwapChain(); - } - - void ReleaseSwapChain() - { - if ( SwapChain == default ) return; - - // The swapchain might still be in use by native, so defer its destruction until the end of the frame. - // Otherwise, a race condition could occur where render targets are accessed after destruction, causing a delayed crash. - var swapChain = SwapChain; - _destroyPending = true; - EngineLoop.DisposeAtFrameEnd( new Sandbox.Utility.DisposeAction( () => - { - g_pRenderDevice.DestroySwapChain( swapChain ); - _destroyPending = false; - } ) ); - SwapChain = default; - } - void Render() { if ( !Scene.IsValid() ) return; if ( !Visible ) return; - if ( SwapChain == default ) - { - // The retired swapchain still owns our window until it's destroyed at - // frame end - creating a second one against it would fail, wait a frame. - if ( _destroyPending ) return; - - SwapChain = WidgetUtil.CreateSwapChain( _widget, RenderSettings.Instance.AntiAliasQuality.ToEngine() ); - } + if ( SwapChain == default ) return; using ( Scene.Push() ) { @@ -280,10 +245,15 @@ public class SceneRenderingWidget : Frame internal void HandleVideoChanged() { - // No swapchain right now - Render will create one with the current settings - if ( SwapChain == default ) return; + var msaaAmount = RenderSettings.Instance.AntiAliasQuality.ToEngine(); - WidgetUtil.UpdateSwapChainMSAA( SwapChain, RenderSettings.Instance.AntiAliasQuality.ToEngine() ); + if ( SwapChain == default ) + { + SwapChain = WidgetUtil.CreateSwapChain( _widget, msaaAmount ); + return; + } + + WidgetUtil.UpdateSwapChainMSAA( SwapChain, msaaAmount ); } internal static void RenderAll() diff --git a/engine/Sandbox.Tools/Qt/Widget.cs b/engine/Sandbox.Tools/Qt/Widget.cs index 99171707..ff95e600 100644 --- a/engine/Sandbox.Tools/Qt/Widget.cs +++ b/engine/Sandbox.Tools/Qt/Widget.cs @@ -1209,15 +1209,6 @@ namespace Editor { return QObject.FindOrCreate( _widget.window() ) as Widget; } - - /// - /// Keeps this window above its owner without making it globally topmost. - /// - public void SetTransientParent( Widget parent ) - { - ArgumentNullException.ThrowIfNull( parent ); - _widget.setTransientParent( parent._widget ); - } } diff --git a/game/addons/tools/Code/Scene/SceneView/SceneOverlayWidget.cs b/game/addons/tools/Code/Scene/SceneView/SceneOverlayWidget.cs index 42163cd6..b803bea7 100644 --- a/game/addons/tools/Code/Scene/SceneView/SceneOverlayWidget.cs +++ b/game/addons/tools/Code/Scene/SceneView/SceneOverlayWidget.cs @@ -12,7 +12,6 @@ public class SceneOverlayWidget : Widget NoSystemBackground = true; WindowFlags = WindowFlags.FramelessWindowHint | WindowFlags.Tool; - SetTransientParent( EditorWindow ); Active = this;