From 2a1924c62c3450628fc1182940839d418eb1702c Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Mon, 2 Nov 2009 20:50:16 +0000 Subject: [PATCH] Do not allow MakeCurrent() to change the display connection of the context. This would result in an X error and the change allows us to simplify shutdown/cleanup logic. --- Source/OpenTK/Platform/X11/X11GLContext.cs | 136 ++++++++++++++------- 1 file changed, 91 insertions(+), 45 deletions(-) diff --git a/Source/OpenTK/Platform/X11/X11GLContext.cs b/Source/OpenTK/Platform/X11/X11GLContext.cs index 312133a2..4f247fa8 100644 --- a/Source/OpenTK/Platform/X11/X11GLContext.cs +++ b/Source/OpenTK/Platform/X11/X11GLContext.cs @@ -1,4 +1,4 @@ -#region --- License --- +#region --- License --- /* Copyright (c) 2007 Stefanos Apostolopoulos * See license.txt for license info */ @@ -20,11 +20,20 @@ namespace OpenTK.Platform.X11 /// internal sealed class X11GLContext : DesktopGraphicsContext { + #region Fields + + // We assume that we cannot move a GL context to a different display connection. + // For this reason, we'll "lock" onto the display of the window used in the context + // constructor and we'll throw an exception if the user ever tries to make the context + // current on window originating from a different display. + IntPtr display; X11WindowInfo currentWindow; bool vsync_supported; int vsync_interval; bool glx_loaded; + #endregion + #region --- Constructors --- public X11GLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shared, bool direct, @@ -37,6 +46,10 @@ namespace OpenTK.Platform.X11 Mode = mode; + // Do not move this lower, as almost everything requires the Display + // property to be correctly set. + Display = ((X11WindowInfo)window).Display; + currentWindow = (X11WindowInfo)window; currentWindow.VisualInfo = SelectVisual(mode, currentWindow); @@ -54,19 +67,19 @@ namespace OpenTK.Platform.X11 // Create a temporary context to obtain the necessary function pointers. XVisualInfo visual = currentWindow.VisualInfo; - IntPtr ctx = Glx.CreateContext(currentWindow.Display, ref visual, IntPtr.Zero, true); + IntPtr ctx = Glx.CreateContext(Display, ref visual, IntPtr.Zero, true); if (ctx == IntPtr.Zero) - ctx = Glx.CreateContext(currentWindow.Display, ref visual, IntPtr.Zero, false); - + ctx = Glx.CreateContext(Display, ref visual, IntPtr.Zero, false); + if (ctx != IntPtr.Zero) { new Glx().LoadAll(); - Glx.MakeCurrent(currentWindow.Display, IntPtr.Zero, IntPtr.Zero); - //Glx.DestroyContext(currentWindow.Display, ctx); + Glx.MakeCurrent(Display, IntPtr.Zero, IntPtr.Zero); + //Glx.DestroyContext(Display, ctx); glx_loaded = true; } } - + // Try using the new context creation method. If it fails, fall back to the old one. // For each of these methods, we try two times to create a context: // one with the "direct" flag intact, the other with the flag inversed. @@ -76,14 +89,18 @@ namespace OpenTK.Platform.X11 if ((major * 10 + minor >= 30) && Glx.Delegates.glXCreateContextAttribsARB != null) { Debug.Write("Using GLX_ARB_create_context... "); - + unsafe { // We need the FB config for the current GraphicsMode. int count; - IntPtr* fbconfigs = Glx.ChooseFBConfig(currentWindow.Display, currentWindow.Screen, - new int[] { (int)GLXAttribute.VISUAL_ID, (int)mode.Index, 0 }, out count); - + IntPtr* fbconfigs = Glx.ChooseFBConfig(Display, currentWindow.Screen, + new int[] { + (int)GLXAttribute.VISUAL_ID, + (int)mode.Index, + 0 + }, out count); + if (count > 0) { List attributes = new List(); @@ -97,47 +114,48 @@ namespace OpenTK.Platform.X11 attributes.Add((int)flags); } attributes.Add(0); - - Handle = new ContextHandle(Glx.Arb.CreateContextAttribs(currentWindow.Display, *fbconfigs, + + Handle = new ContextHandle(Glx.Arb.CreateContextAttribs(Display, *fbconfigs, shareHandle.Handle, direct, attributes.ToArray())); - + if (Handle == ContextHandle.Zero) { Debug.Write(String.Format("failed. Trying direct: {0}... ", !direct)); - Handle = new ContextHandle(Glx.Arb.CreateContextAttribs(currentWindow.Display, *fbconfigs, + Handle = new ContextHandle(Glx.Arb.CreateContextAttribs(Display, *fbconfigs, shareHandle.Handle, !direct, attributes.ToArray())); } - + if (Handle == ContextHandle.Zero) Debug.WriteLine("failed."); else Debug.WriteLine("success!"); - + Functions.XFree((IntPtr)fbconfigs); } } } - + if (Handle == ContextHandle.Zero) { Debug.Write("Using legacy context creation... "); - - XVisualInfo info = currentWindow.VisualInfo; // Cannot pass a Property by reference. - Handle = new ContextHandle(Glx.CreateContext(currentWindow.Display, ref info, shareHandle.Handle, direct)); - + + XVisualInfo info = currentWindow.VisualInfo; + // Cannot pass a Property by reference. + Handle = new ContextHandle(Glx.CreateContext(Display, ref info, shareHandle.Handle, direct)); + if (Handle == ContextHandle.Zero) { Debug.WriteLine(String.Format("failed. Trying direct: {0}... ", !direct)); - Handle = new ContextHandle(Glx.CreateContext(currentWindow.Display, ref info, IntPtr.Zero, !direct)); + Handle = new ContextHandle(Glx.CreateContext(Display, ref info, IntPtr.Zero, !direct)); } } - + if (Handle != ContextHandle.Zero) Debug.Print("Context created (id: {0}).", Handle); else throw new GraphicsContextException("Failed to create OpenGL context. Glx.CreateContext call returned 0."); - - if (!Glx.IsDirect(currentWindow.Display, Handle.Handle)) + + if (!Glx.IsDirect(Display, Handle.Handle)) Debug.Print("Warning: Context is not direct."); } @@ -145,6 +163,19 @@ namespace OpenTK.Platform.X11 #region --- Private Methods --- + IntPtr Display + { + get { return display; } + set + { + if (value == IntPtr.Zero) + throw new ArgumentOutOfRangeException(); + if (display != IntPtr.Zero) + throw new InvalidOperationException("The display connection may not be changed after being set."); + display = value; + } + } + #region XVisualInfo SelectVisual(GraphicsMode mode, X11WindowInfo currentWindow) XVisualInfo SelectVisual(GraphicsMode mode, X11WindowInfo currentWindow) @@ -156,7 +187,7 @@ namespace OpenTK.Platform.X11 lock (API.Lock) { - IntPtr vs = Functions.XGetVisualInfo(currentWindow.Display, XVisualInfoMask.ID | XVisualInfoMask.Screen, ref info, out items); + IntPtr vs = Functions.XGetVisualInfo(Display, XVisualInfoMask.ID | XVisualInfoMask.Screen, ref info, out items); if (items == 0) throw new GraphicsModeException(String.Format("Invalid GraphicsMode specified ({0}).", mode)); @@ -171,7 +202,14 @@ namespace OpenTK.Platform.X11 bool SupportsExtension(X11WindowInfo window, string e) { - string extensions = Glx.QueryExtensionsString(window.Display, window.Screen); + if (window == null) + throw new ArgumentNullException("window"); + if (e == null) + throw new ArgumentNullException("e"); + if (window.Display != Display) + throw new InvalidOperationException(); + + string extensions = Glx.QueryExtensionsString(Display, window.Screen); return !String.IsNullOrEmpty(extensions) && extensions.Contains(e); } @@ -183,10 +221,10 @@ namespace OpenTK.Platform.X11 public override void SwapBuffers() { - if (currentWindow.Display == IntPtr.Zero || currentWindow.WindowHandle == IntPtr.Zero) + if (Display == IntPtr.Zero || currentWindow.WindowHandle == IntPtr.Zero) throw new InvalidOperationException( - String.Format("Window is invalid. Display ({0}), Handle ({1}).", currentWindow.Display, currentWindow.WindowHandle)); - Glx.SwapBuffers(currentWindow.Display, currentWindow.WindowHandle); + String.Format("Window is invalid. Display ({0}), Handle ({1}).", Display, currentWindow.WindowHandle)); + Glx.SwapBuffers(Display, currentWindow.WindowHandle); } #endregion @@ -195,28 +233,36 @@ namespace OpenTK.Platform.X11 public override void MakeCurrent(IWindowInfo window) { + if (window == currentWindow && IsCurrent) + return; + + if (window != null && ((X11WindowInfo)window).Display != Display) + throw new InvalidOperationException("MakeCurrent() may only be called on windows originating from the same display that spawned this GL context."); + if (window == null) { - Glx.MakeCurrent(currentWindow.Display, IntPtr.Zero, IntPtr.Zero); + Glx.MakeCurrent(Display, IntPtr.Zero, IntPtr.Zero); } else { X11WindowInfo w = (X11WindowInfo)window; bool result; - + Debug.Write(String.Format("Making context {0} current on thread {1} (Display: {2}, Screen: {3}, Window: {4})... ", - Handle, System.Threading.Thread.CurrentThread.ManagedThreadId, w.Display, w.Screen, w.WindowHandle)); - - if (w.Display == IntPtr.Zero || w.WindowHandle == IntPtr.Zero || Handle == ContextHandle.Zero) + Handle, System.Threading.Thread.CurrentThread.ManagedThreadId, Display, w.Screen, w.WindowHandle)); + + if (Display == IntPtr.Zero || w.WindowHandle == IntPtr.Zero || Handle == ContextHandle.Zero) throw new InvalidOperationException("Invalid display, window or context."); - - result = Glx.MakeCurrent(w.Display, w.WindowHandle, Handle); - + + result = Glx.MakeCurrent(Display, w.WindowHandle, Handle); + if (!result) throw new GraphicsContextException("Failed to make context current."); else Debug.WriteLine("done!"); } + + currentWindow = (X11WindowInfo)window; } #endregion @@ -225,7 +271,7 @@ namespace OpenTK.Platform.X11 public override bool IsCurrent { - get { return Glx.GetCurrentContext() == this.Handle.Handle; } + get { return Glx.GetCurrentContext() == Handle.Handle; } } #endregion @@ -300,11 +346,11 @@ namespace OpenTK.Platform.X11 { if (manuallyCalled) { - if (GraphicsContext.CurrentContext != null && - ((IGraphicsContextInternal)GraphicsContext.CurrentContext).Context == Handle) - GraphicsContext.CurrentContext.MakeCurrent(null); - - Glx.DestroyContext(currentWindow.Display, Handle); + IntPtr display = Display; + if (IsCurrent) + MakeCurrent(null); + + Glx.DestroyContext(display, Handle); } else {