From 0a5c346c525831f095e92f547ba76d678cc08ddf Mon Sep 17 00:00:00 2001 From: iRon Date: Mon, 8 Jan 2018 22:31:45 +0100 Subject: [PATCH] =?utf8?q?Fix=20to=20able=20to=20recover=20from=20Graphics?= =?utf8?q?ModeException=20in=20the=20override=20OnH=E2=80=A6=20(#658)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit * Fix to able to recover from GraphicsModeException in the override OnHandleCreated. * Changes according to comments: - m_implementation and m_context is now always set. To DummyGLControl if CreateContext fails - Changed FailedCreateContext -> HasValidContext - Changed all if{} to short style with braces. - Added null propagation when applicable - Renamed member variables to have 'm_' infront. - and more ... * Changed 'm_' prefix into '_' Added braces to be using Allman Style * Fixed: 2) SA1003: GLControl.cs(226,47): Operator '(IGraphicsContextInternal)' must not be followed by whitespace. 3) SA1003: GLControl.cs(412,49): Operator '(float)' must not be followed by whitespace. * Removed Paket.Restore.targets from sourcecontrol Added *.Restore.targets to .gitignore * Fixed comments Added *.DotSettings to .gitignore * Removed *.DotSettings from GitIgnore Moved *.Restore.targets to Paket section --- .gitignore | 1 + src/OpenTK.GLControl/GLControl.cs | 169 +++++++++++++++++++++----------------- 2 files changed, 93 insertions(+), 77 deletions(-) diff --git a/.gitignore b/.gitignore index 8597c63..2c1e804 100644 --- a/.gitignore +++ b/.gitignore @@ -317,6 +317,7 @@ _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ +*.Restore.targets # FAKE - F# Make .fake/ diff --git a/src/OpenTK.GLControl/GLControl.cs b/src/OpenTK.GLControl/GLControl.cs index 69e58bf..d5c2096 100644 --- a/src/OpenTK.GLControl/GLControl.cs +++ b/src/OpenTK.GLControl/GLControl.cs @@ -41,22 +41,24 @@ namespace OpenTK /// public partial class GLControl : UserControl { - private IGraphicsContext context; - private IGLControl implementation; - private GraphicsMode format; - private int major, minor; - private GraphicsContextFlags flags; + private IGraphicsContext _context; + private IGLControl _implementation; + private readonly GraphicsMode _format; + private readonly int _major; + private readonly int _minor; + private readonly GraphicsContextFlags _flags; + private bool? _initialVsyncValue; - private bool? initial_vsync_value; // Indicates that OnResize was called before OnHandleCreated. // To avoid issues with missing OpenGL contexts, we suppress // the premature Resize event and raise it as soon as the handle // is ready. - private bool resize_event_suppressed; + private bool _resizeEventSuppressed; + // Indicates whether the control is in design mode. Due to issues - // wiith the DesignMode property and nested controls,we need to + // with the DesignMode property and nested controls,we need to // evaluate this in the constructor. - private readonly bool design_mode; + private readonly bool _designMode; /// /// Constructs a new instance. @@ -84,7 +86,7 @@ namespace OpenTK { if (mode == null) { - throw new ArgumentNullException("mode"); + throw new ArgumentNullException(nameof(mode)); } // SDL does not currently support embedding @@ -104,28 +106,37 @@ namespace OpenTK SetStyle(ControlStyles.AllPaintingInWmPaint, true); DoubleBuffered = false; - this.format = mode; - this.major = major; - this.minor = minor; - this.flags = flags; + _format = mode; + _major = major; + _minor = minor; + _flags = flags; // Note: the DesignMode property may be incorrect when nesting controls. // We use LicenseManager.UsageMode as a workaround (this only works in // the constructor). - design_mode = + _designMode = DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; InitializeComponent(); } + /// + /// Gets a value indicating whether [failed to create OpenGL context]. + /// So that the application stays running and is able to recover. + /// + /// + /// true if [failed create context]; otherwise, false. + /// + public bool HasValidContext { get; private set; } + private IGLControl Implementation { get { ValidateState(); - return implementation; + return _implementation; } } @@ -150,7 +161,7 @@ namespace OpenTK CreateControl(); } - if (implementation == null || context == null || context.IsDisposed) + if (_implementation == null || _context == null || _context.IsDisposed) { RecreateHandle(); } @@ -167,7 +178,7 @@ namespace OpenTK const int CS_HREDRAW = 0x2; const int CS_OWNDC = 0x20; - CreateParams cp = base.CreateParams; + var cp = base.CreateParams; if (Configuration.RunningOnWindows) { // Setup necessary class style for OpenGL on windows @@ -181,46 +192,54 @@ namespace OpenTK /// Not used. protected override void OnHandleCreated(EventArgs e) { - if (context != null) - { - context.Dispose(); - } + if (!(_implementation is DummyGLControl)) + { // No need to recreate our DummyGLControl + _context?.Dispose(); + _implementation?.WindowInfo.Dispose(); - if (implementation != null) - { - implementation.WindowInfo.Dispose(); - } - - if (design_mode) - { - implementation = new DummyGLControl(); - } - else - { - implementation = new GLControlFactory().CreateGLControl(format, this); - } + if (_designMode) + { + _implementation = new DummyGLControl(); + _context = _implementation.CreateContext(_major, _minor, _flags); + HasValidContext = false; + } + else + { + try + { + _implementation = new GLControlFactory().CreateGLControl(_format, this); + _context = _implementation.CreateContext(_major, _minor, _flags); + HasValidContext = true; + } + catch (GraphicsModeException) + { + _implementation = new DummyGLControl(); + _context = _implementation.CreateContext(_major, _minor, _flags); + HasValidContext = false; + } + } - context = implementation.CreateContext(major, minor, flags); - MakeCurrent(); + MakeCurrent(); - if (!design_mode) - { - ((IGraphicsContextInternal)Context).LoadAll(); - } + if (HasValidContext) + { + ((IGraphicsContextInternal)_context).LoadAll(); + } - // Deferred setting of vsync mode. See VSync property for more information. - if (initial_vsync_value.HasValue) - { - Context.SwapInterval = initial_vsync_value.Value ? 1 : 0; - initial_vsync_value = null; + // Deferred setting of vsync mode. See VSync property for more information. + if (_initialVsyncValue.HasValue) + { + _context.SwapInterval = _initialVsyncValue.Value ? 1 : 0; + _initialVsyncValue = null; + } } base.OnHandleCreated(e); - if (resize_event_suppressed) + if (_resizeEventSuppressed) { OnResize(EventArgs.Empty); - resize_event_suppressed = false; + _resizeEventSuppressed = false; } } @@ -232,18 +251,23 @@ namespace OpenTK // => This allows to perform cleanup operations in OnHandleDestroyed handlers base.OnHandleDestroyed(e); - if (context != null) + if (_implementation is DummyGLControl) { - context.Dispose(); - context = null; + // No need to destroy our DummyGLControl + return; } - if (implementation != null) + if (_context != null) { - implementation.WindowInfo.Dispose(); - implementation = null; + _context.Dispose(); + _context = null; } + if (_implementation != null) + { + _implementation.WindowInfo.Dispose(); + _implementation = null; + } } /// @@ -254,7 +278,7 @@ namespace OpenTK { ValidateState(); - if (design_mode) + if (_designMode) { e.Graphics.Clear(BackColor); } @@ -273,7 +297,7 @@ namespace OpenTK // Do not raise OnResize event before the handle and context are created. if (!IsHandleCreated) { - resize_event_suppressed = true; + _resizeEventSuppressed = true; return; } @@ -282,9 +306,9 @@ namespace OpenTK DelayUpdate delay = PerformContextUpdate; BeginInvoke(delay); //Need the native window to resize first otherwise our control will be in the wrong place. } - else if (context != null) + else { - context.Update (Implementation.WindowInfo); + _context?.Update(Implementation.WindowInfo); } base.OnResize(e); @@ -294,15 +318,13 @@ namespace OpenTK /// Needed to delay the invoke on OS X. Also needed because OpenTK is .NET 2, otherwise I'd use an inline Action. /// public delegate void DelayUpdate(); + /// /// Execute the delayed context update /// public void PerformContextUpdate() { - if (context != null) - { - context.Update (Implementation.WindowInfo); - } + _context?.Update(Implementation.WindowInfo); } /// @@ -311,10 +333,7 @@ namespace OpenTK /// A System.EventArgs that contains the event data. protected override void OnParentChanged(EventArgs e) { - if (context != null) - { - context.Update(Implementation.WindowInfo); - } + _context?.Update(Implementation.WindowInfo); base.OnParentChanged(e); } @@ -377,9 +396,8 @@ namespace OpenTK get { ValidateState(); - return context; + return _context; } - private set { context = value; } } /// @@ -409,12 +427,12 @@ namespace OpenTK { if (!IsHandleCreated) { - return initial_vsync_value.HasValue ? - initial_vsync_value.Value : true; + return !_initialVsyncValue.HasValue || _initialVsyncValue.Value; } ValidateState(); - ValidateContext("VSync"); + ValidateContext(@"VSync"); + return Context.SwapInterval != 0; } set @@ -425,12 +443,12 @@ namespace OpenTK // Work around this issue by deferring VSync mode setting to the HandleCreated event. if (!IsHandleCreated) { - initial_vsync_value = value; + _initialVsyncValue = value; return; } ValidateState(); - ValidateContext("VSync"); + ValidateContext(@"VSync"); Context.SwapInterval = value ? 1 : 0; } } @@ -452,9 +470,6 @@ namespace OpenTK /// /// Gets the for this instance. /// - public IWindowInfo WindowInfo - { - get { return implementation.WindowInfo; } - } + public IWindowInfo WindowInfo => _implementation.WindowInfo; } } -- 2.7.4