From 786273dd19bd7407ec7a030aaabedd74aa0bdcc9 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 18 Jul 2014 17:02:47 +0200 Subject: [PATCH 1/5] [X11] Fixed OnMouseMove being called without mouse movement --- Source/OpenTK/Platform/X11/X11GLNative.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/X11/X11GLNative.cs b/Source/OpenTK/Platform/X11/X11GLNative.cs index 1971501e..c1de141e 100644 --- a/Source/OpenTK/Platform/X11/X11GLNative.cs +++ b/Source/OpenTK/Platform/X11/X11GLNative.cs @@ -892,7 +892,7 @@ namespace OpenTK.Platform.X11 int x = e.MotionEvent.x; int y = e.MotionEvent.y; - if (x != 0 || y != 0) + if (x != MouseState.X || y != MouseState.Y) { OnMouseMove( MathHelper.Clamp(x, 0, Width), From a13a2f8e666d583872d3d814f404578e6ef4aa74 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 18 Jul 2014 17:16:27 +0200 Subject: [PATCH 2/5] [X11] Workaround for issue #146 Windows are now unmapped before being destroyed. --- Source/OpenTK/Platform/X11/X11GLNative.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/OpenTK/Platform/X11/X11GLNative.cs b/Source/OpenTK/Platform/X11/X11GLNative.cs index c1de141e..9ae0784c 100644 --- a/Source/OpenTK/Platform/X11/X11GLNative.cs +++ b/Source/OpenTK/Platform/X11/X11GLNative.cs @@ -825,7 +825,7 @@ namespace OpenTK.Platform.X11 case XEventName.ClientMessage: if (!isExiting && e.ClientMessageEvent.ptr1 == _atom_wm_destroy) { - Debug.WriteLine("Exit message received."); + Debug.Print("[X11] Exit message received for window {0:X} on display {1:X}", window.Handle, window.Display); CancelEventArgs ce = new CancelEventArgs(); OnClosing(ce); @@ -1624,6 +1624,8 @@ namespace OpenTK.Platform.X11 public void Exit() { + Debug.Print("[X11] Sending exit message window {0:X} on display {1:X}", window.Handle, window.Display); + XEvent ev = new XEvent(); ev.type = XEventName.ClientMessage; ev.ClientMessageEvent.format = 32; @@ -1644,10 +1646,12 @@ namespace OpenTK.Platform.X11 public void DestroyWindow() { - Debug.WriteLine("X11GLNative shutdown sequence initiated."); + Debug.Print("[X11] Destroying window {0:X} on display {1:X}", window.Handle, window.Display); + using (new XLock(window.Display)) { - Functions.XSync(window.Display, true); + Functions.XUnmapWindow(window.Display, window.Handle); + Functions.XSync(window.Display, false); Functions.XDestroyWindow(window.Display, window.Handle); exists = false; } From d75a2ce43909d62a258c7a8af08a589a2225e334 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sat, 19 Jul 2014 20:39:17 +0200 Subject: [PATCH 3/5] [X11] Fix for issue #143 OpenTK will now use the same GLXFBConfig to create the INativeWindow and IGraphicsContext on Linux/X11. This resolves an issue where OpenGL 3.x contexts could not be created on some graphics drivers (e.g. nvidia binary.) --- Source/OpenTK/Platform/Utilities.cs | 6 +- Source/OpenTK/Platform/X11/X11GLContext.cs | 196 ++++++++---------- Source/OpenTK/Platform/X11/X11GLNative.cs | 18 +- Source/OpenTK/Platform/X11/X11GraphicsMode.cs | 168 ++++++++------- Source/OpenTK/Platform/X11/X11WindowInfo.cs | 17 +- 5 files changed, 199 insertions(+), 206 deletions(-) diff --git a/Source/OpenTK/Platform/Utilities.cs b/Source/OpenTK/Platform/Utilities.cs index a7b801eb..cae7ba50 100644 --- a/Source/OpenTK/Platform/Utilities.cs +++ b/Source/OpenTK/Platform/Utilities.cs @@ -248,11 +248,7 @@ namespace OpenTK.Platform window.Screen = screen; window.Handle = windowHandle; window.RootWindow = rootWindow; - if (visualInfo != IntPtr.Zero) - { - window.VisualInfo = (X11.XVisualInfo)Marshal.PtrToStructure(visualInfo, typeof(X11.XVisualInfo)); - } - + window.Visual = visualInfo; return window; } diff --git a/Source/OpenTK/Platform/X11/X11GLContext.cs b/Source/OpenTK/Platform/X11/X11GLContext.cs index a600b8be..a1c95a39 100644 --- a/Source/OpenTK/Platform/X11/X11GLContext.cs +++ b/Source/OpenTK/Platform/X11/X11GLContext.cs @@ -78,13 +78,26 @@ namespace OpenTK.Platform.X11 } } - Mode = ModeSelector.SelectGraphicsMode( - mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples, - mode.AccumulatorFormat, mode.Buffers, mode.Stereo); + IntPtr visual = IntPtr.Zero; + IntPtr fbconfig = IntPtr.Zero; + // Once a window has a visual, we cannot use a different + // visual on the OpenGL context, or glXMakeCurrent might fail. + // Note: we should only check X11WindowInfo.Visual, as that + // is the only property that can be set by Utilities.CreateX11WindowInfo. currentWindow = (X11WindowInfo)window; - currentWindow.VisualInfo = SelectVisual(Mode, currentWindow); - + if (currentWindow.Visual != IntPtr.Zero) + { + visual = currentWindow.Visual; + fbconfig = currentWindow.FBConfig; + Mode = currentWindow.GraphicsMode; + } + + if (!Mode.Index.HasValue) + { + Mode = ModeSelector.SelectGraphicsMode(mode, out visual, out fbconfig); + } + ContextHandle shareHandle = shared != null ? (shared as IGraphicsContextInternal).Context : (ContextHandle)IntPtr.Zero; @@ -99,84 +112,15 @@ namespace OpenTK.Platform.X11 // HACK: It seems that Catalyst 9.1 - 9.4 on Linux have problems with contexts created through // GLX_ARB_create_context, including hideous input lag, no vsync and other madness. // Use legacy context creation if the user doesn't request a 3.0+ context. - if ((major * 10 + minor >= 30) && SupportsCreateContextAttribs(Display, currentWindow)) + if (fbconfig != IntPtr.Zero && (major * 10 + minor >= 30) && SupportsCreateContextAttribs(Display, currentWindow)) { - Debug.Write("Using GLX_ARB_create_context... "); - - unsafe - { - // We need the FB config for the current GraphicsMode. - int 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(); - attributes.Add((int)ArbCreateContext.MajorVersion); - attributes.Add(major); - attributes.Add((int)ArbCreateContext.MinorVersion); - attributes.Add(minor); - if (flags != 0) - { - attributes.Add((int)ArbCreateContext.Flags); - attributes.Add((int)GetARBContextFlags(flags)); - attributes.Add((int)ArbCreateContext.ProfileMask); - attributes.Add((int)GetARBProfileFlags(flags)); - } - // According to the docs, " specifies a list of attributes for the context. - // The list consists of a sequence of pairs terminated by the - // value 0. [...]" - // Is this a single 0, or a <0, 0> pair? (Defensive coding: add two zeroes just in case). - attributes.Add(0); - attributes.Add(0); - - using (new XLock(Display)) - { - 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(Display, *fbconfigs, - shareHandle.Handle, !direct, attributes.ToArray())); - } - } - - if (Handle == ContextHandle.Zero) - Debug.WriteLine("failed."); - else - Debug.WriteLine("success!"); - - using (new XLock(Display)) - { - Functions.XFree((IntPtr)fbconfigs); - } - } - } + Handle = CreateContextAttribs(Display, currentWindow.Screen, + fbconfig, direct, major, minor, flags, shareHandle); } if (Handle == ContextHandle.Zero) { - Debug.Write("Using legacy context creation... "); - - XVisualInfo info = currentWindow.VisualInfo; - using (new XLock(Display)) - { - // 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(Display, ref info, IntPtr.Zero, !direct)); - } - } + Handle = CreateContextLegacy(Display, currentWindow.VisualInfo, direct, shareHandle); } if (Handle != ContextHandle.Zero) @@ -208,6 +152,74 @@ namespace OpenTK.Platform.X11 #region --- Private Methods --- + static ContextHandle CreateContextAttribs( + IntPtr display, int screen, IntPtr fbconfig, + bool direct, int major, int minor, + GraphicsContextFlags flags, ContextHandle shareContext) + { + Debug.Write("Using GLX_ARB_create_context... "); + IntPtr context = IntPtr.Zero; + + { + // We need the FB config for the current GraphicsMode. + List attributes = new List(); + attributes.Add((int)ArbCreateContext.MajorVersion); + attributes.Add(major); + attributes.Add((int)ArbCreateContext.MinorVersion); + attributes.Add(minor); + if (flags != 0) + { + attributes.Add((int)ArbCreateContext.Flags); + attributes.Add((int)GetARBContextFlags(flags)); + attributes.Add((int)ArbCreateContext.ProfileMask); + attributes.Add((int)GetARBProfileFlags(flags)); + } + // According to the docs, " specifies a list of attributes for the context. + // The list consists of a sequence of pairs terminated by the + // value 0. [...]" + // Is this a single 0, or a <0, 0> pair? (Defensive coding: add two zeroes just in case). + attributes.Add(0); + attributes.Add(0); + + using (new XLock(display)) + { + context = Glx.Arb.CreateContextAttribs(display, fbconfig, shareContext.Handle, direct, attributes.ToArray()); + if (context == IntPtr.Zero) + { + Debug.Write(String.Format("failed. Trying direct: {0}... ", !direct)); + context = Glx.Arb.CreateContextAttribs(display, fbconfig, shareContext.Handle, !direct, attributes.ToArray()); + } + } + + if (context == IntPtr.Zero) + Debug.WriteLine("failed."); + else + Debug.WriteLine("success!"); + } + + return new ContextHandle(context); + } + + static ContextHandle CreateContextLegacy(IntPtr display, + XVisualInfo info, bool direct, ContextHandle shareContext) + { + Debug.Write("Using legacy context creation... "); + IntPtr context; + + using (new XLock(display)) + { + // Cannot pass a Property by reference. + context = Glx.CreateContext(display, ref info, shareContext.Handle, direct); + if (context == IntPtr.Zero) + { + Debug.WriteLine(String.Format("failed. Trying direct: {0}... ", !direct)); + context = Glx.CreateContext(display, ref info, IntPtr.Zero, !direct); + } + } + + return new ContextHandle(context); + } + IntPtr Display { get { return display; } @@ -221,38 +233,14 @@ namespace OpenTK.Platform.X11 } } - #region XVisualInfo SelectVisual(GraphicsMode mode, X11WindowInfo currentWindow) - - XVisualInfo SelectVisual(GraphicsMode mode, X11WindowInfo currentWindow) - { - XVisualInfo info = new XVisualInfo(); - info.VisualID = (IntPtr)mode.Index; - info.Screen = currentWindow.Screen; - int items; - - lock (API.Lock) - { - 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)); - - info = (XVisualInfo)Marshal.PtrToStructure(vs, typeof(XVisualInfo)); - Functions.XFree(vs); - } - - return info; - } - - #endregion - - ArbCreateContext GetARBContextFlags(GraphicsContextFlags flags) + static ArbCreateContext GetARBContextFlags(GraphicsContextFlags flags) { ArbCreateContext result = 0; result |= (flags & GraphicsContextFlags.Debug) != 0 ? ArbCreateContext.DebugBit : 0; return result; } - ArbCreateContext GetARBProfileFlags(GraphicsContextFlags flags) + static ArbCreateContext GetARBProfileFlags(GraphicsContextFlags flags) { ArbCreateContext result = 0; result |= (flags & GraphicsContextFlags.ForwardCompatible) != 0 ? diff --git a/Source/OpenTK/Platform/X11/X11GLNative.cs b/Source/OpenTK/Platform/X11/X11GLNative.cs index 9ae0784c..388c45a5 100644 --- a/Source/OpenTK/Platform/X11/X11GLNative.cs +++ b/Source/OpenTK/Platform/X11/X11GLNative.cs @@ -140,7 +140,7 @@ namespace OpenTK.Platform.X11 #region Constructors public X11GLNative(int x, int y, int width, int height, string title, - GraphicsMode mode,GameWindowFlags options, DisplayDevice device) + GraphicsMode mode, GameWindowFlags options, DisplayDevice device) : this() { if (width <= 0) @@ -154,17 +154,13 @@ namespace OpenTK.Platform.X11 using (new XLock(window.Display)) { - if (!mode.Index.HasValue) - { - mode = new X11GraphicsMode().SelectGraphicsMode( - mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples, - mode.AccumulatorFormat, mode.Buffers, mode.Stereo); - } + IntPtr visual; + IntPtr fbconfig; + window.GraphicsMode = new X11GraphicsMode() + .SelectGraphicsMode(mode, out visual, out fbconfig); - info.VisualID = mode.Index.Value; - int dummy; - window.VisualInfo = (XVisualInfo)Marshal.PtrToStructure( - Functions.XGetVisualInfo(window.Display, XVisualInfoMask.ID, ref info, out dummy), typeof(XVisualInfo)); + window.Visual = visual; + window.FBConfig = fbconfig; // Create a window on this display using the visual above Debug.Write("Opening render window... "); diff --git a/Source/OpenTK/Platform/X11/X11GraphicsMode.cs b/Source/OpenTK/Platform/X11/X11GraphicsMode.cs index 000f45ee..9a76447e 100644 --- a/Source/OpenTK/Platform/X11/X11GraphicsMode.cs +++ b/Source/OpenTK/Platform/X11/X11GraphicsMode.cs @@ -16,7 +16,7 @@ using OpenTK.Graphics; namespace OpenTK.Platform.X11 { - class X11GraphicsMode : IGraphicsMode + class X11GraphicsMode { // Todo: Add custom visual selection algorithm, instead of ChooseFBConfig/ChooseVisual. // It seems the Choose* methods do not take multisampling into account (at least on some @@ -32,34 +32,45 @@ namespace OpenTK.Platform.X11 #region IGraphicsMode Members - public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, - int buffers, bool stereo) + public GraphicsMode SelectGraphicsMode(GraphicsMode desired_mode, out IntPtr visual, out IntPtr fbconfig) { GraphicsMode gfx; - // The actual GraphicsMode that will be selected. - IntPtr visual = IntPtr.Zero; + GraphicsMode mode = new GraphicsMode(desired_mode); + visual = IntPtr.Zero; + fbconfig = IntPtr.Zero; IntPtr display = API.DefaultDisplay; do { // Try to select a visual using Glx.ChooseFBConfig and Glx.GetVisualFromFBConfig. // This is only supported on GLX 1.3 - if it fails, fall back to Glx.ChooseVisual. - visual = SelectVisualUsingFBConfig(color, depth, stencil, samples, accum, buffers, stereo); + fbconfig = SelectFBConfig(mode); + if (fbconfig != IntPtr.Zero) + visual = Glx.GetVisualFromFBConfig(display, fbconfig); if (visual == IntPtr.Zero) - visual = SelectVisualUsingChooseVisual(color, depth, stencil, samples, accum, buffers, stereo); + visual = SelectVisual(mode); if (visual == IntPtr.Zero) { // Relax parameters and retry - if (!Utilities.RelaxGraphicsMode(ref color, ref depth, ref stencil, ref samples, ref accum, ref buffers, ref stereo)) + if (!Utilities.RelaxGraphicsMode(ref mode)) throw new GraphicsModeException("Requested GraphicsMode not available."); } } while (visual == IntPtr.Zero); XVisualInfo info = (XVisualInfo)Marshal.PtrToStructure(visual, typeof(XVisualInfo)); + gfx = CreateGraphicsMode(display, ref info); + return gfx; + } + #endregion + + #region Private Members + + static GraphicsMode CreateGraphicsMode(IntPtr display, ref XVisualInfo info) + { // See what we *really* got: int r, g, b, a; Glx.GetConfig(display, ref info, GLXAttribute.ALPHA_SIZE, out a); @@ -71,99 +82,84 @@ namespace OpenTK.Platform.X11 Glx.GetConfig(display, ref info, GLXAttribute.ACCUM_RED_SIZE, out ar); Glx.GetConfig(display, ref info, GLXAttribute.ACCUM_GREEN_SIZE, out ag); Glx.GetConfig(display, ref info, GLXAttribute.ACCUM_BLUE_SIZE, out ab); + int depth, stencil, samples, buffers; Glx.GetConfig(display, ref info, GLXAttribute.DEPTH_SIZE, out depth); Glx.GetConfig(display, ref info, GLXAttribute.STENCIL_SIZE, out stencil); Glx.GetConfig(display, ref info, GLXAttribute.SAMPLES, out samples); Glx.GetConfig(display, ref info, GLXAttribute.DOUBLEBUFFER, out buffers); - ++buffers; - // the above lines returns 0 - false and 1 - true. int st; Glx.GetConfig(display, ref info, GLXAttribute.STEREO, out st); - stereo = st != 0; - - gfx = new GraphicsMode(info.VisualID, new ColorFormat(r, g, b, a), depth, stencil, samples, - new ColorFormat(ar, ag, ab, aa), buffers, stereo); - - using (new XLock(display)) - { - Functions.XFree(visual); - } - - return gfx; + + // Note: Glx.GetConfig return buffers = 0 (false) or 1 (true). + // OpenTK expects buffers = 1 (single-) or 2 (double-buffering), + // so increase the GLX value by one. + return new GraphicsMode(info.VisualID, new ColorFormat(r, g, b, a), depth, stencil, samples, + new ColorFormat(ar, ag, ab, aa), buffers + 1, st != 0); } - #endregion - - #region Private Members - - // See http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.opengl/doc/openglrf/glXChooseFBConfig.htm - // for the attribute declarations. Note that the attributes are different than those used in Glx.ChooseVisual. - IntPtr SelectVisualUsingFBConfig(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, - int buffers, bool stereo) + IntPtr SelectFBConfig(GraphicsMode mode) { + Debug.Print("Selecting FB config for {0}", mode); + List visualAttributes = new List(); IntPtr visual = IntPtr.Zero; - Debug.Print("Bits per pixel: {0}", color.BitsPerPixel); - - if (color.BitsPerPixel > 0) + if (mode.ColorFormat.BitsPerPixel > 0) { - if (!color.IsIndexed) + if (!mode.ColorFormat.IsIndexed) { - visualAttributes.Add((int)GLXAttribute.RGBA); - visualAttributes.Add(1); + visualAttributes.Add((int)GLXAttribute.RENDER_TYPE); + visualAttributes.Add((int)GLXRenderTypeMask.RGBA_BIT); } visualAttributes.Add((int)GLXAttribute.RED_SIZE); - visualAttributes.Add(color.Red); + visualAttributes.Add(mode.ColorFormat.Red); visualAttributes.Add((int)GLXAttribute.GREEN_SIZE); - visualAttributes.Add(color.Green); + visualAttributes.Add(mode.ColorFormat.Green); visualAttributes.Add((int)GLXAttribute.BLUE_SIZE); - visualAttributes.Add(color.Blue); + visualAttributes.Add(mode.ColorFormat.Blue); visualAttributes.Add((int)GLXAttribute.ALPHA_SIZE); - visualAttributes.Add(color.Alpha); + visualAttributes.Add(mode.ColorFormat.Alpha); } - Debug.Print("Depth: {0}", depth); - - if (depth > 0) + if (mode.Depth > 0) { visualAttributes.Add((int)GLXAttribute.DEPTH_SIZE); - visualAttributes.Add(depth); + visualAttributes.Add(mode.Depth); } - if (buffers > 1) + if (mode.Buffers > 1) { visualAttributes.Add((int)GLXAttribute.DOUBLEBUFFER); visualAttributes.Add(1); } - if (stencil > 1) + if (mode.Stereo) { visualAttributes.Add((int)GLXAttribute.STENCIL_SIZE); - visualAttributes.Add(stencil); + visualAttributes.Add(mode.Stereo ? 1 : 0); } - if (accum.BitsPerPixel > 0) + if (mode.AccumulatorFormat.BitsPerPixel > 0) { visualAttributes.Add((int)GLXAttribute.ACCUM_ALPHA_SIZE); - visualAttributes.Add(accum.Alpha); + visualAttributes.Add(mode.AccumulatorFormat.Alpha); visualAttributes.Add((int)GLXAttribute.ACCUM_BLUE_SIZE); - visualAttributes.Add(accum.Blue); + visualAttributes.Add(mode.AccumulatorFormat.Blue); visualAttributes.Add((int)GLXAttribute.ACCUM_GREEN_SIZE); - visualAttributes.Add(accum.Green); + visualAttributes.Add(mode.AccumulatorFormat.Green); visualAttributes.Add((int)GLXAttribute.ACCUM_RED_SIZE); - visualAttributes.Add(accum.Red); + visualAttributes.Add(mode.AccumulatorFormat.Red); } - - if (samples > 0) + + if (mode.Samples > 0) { visualAttributes.Add((int)GLXAttribute.SAMPLE_BUFFERS); visualAttributes.Add(1); visualAttributes.Add((int)GLXAttribute.SAMPLES); - visualAttributes.Add(samples); + visualAttributes.Add(mode.Samples); } - if (stereo) + if (mode.Stereo) { visualAttributes.Add((int)GLXAttribute.STEREO); visualAttributes.Add(1); @@ -173,6 +169,7 @@ namespace OpenTK.Platform.X11 // Select a visual that matches the parameters set by the user. IntPtr display = API.DefaultDisplay; + IntPtr result = IntPtr.Zero; using (new XLock(display)) { try @@ -180,7 +177,7 @@ namespace OpenTK.Platform.X11 int screen = Functions.XDefaultScreen(display); IntPtr root = Functions.XRootWindow(display, screen); Debug.Print("Display: {0}, Screen: {1}, RootWindow: {2}", display, screen, root); - + unsafe { Debug.Print("Getting FB config."); @@ -190,81 +187,82 @@ namespace OpenTK.Platform.X11 if (fbcount > 0 && fbconfigs != null) { // We want to use the first GLXFBConfig from the fbconfigs array (the first one is the best match). - visual = Glx.GetVisualFromFBConfig(display, *fbconfigs); + Debug.Print("Selected FB config: {0}", *fbconfigs); + result = *fbconfigs; Functions.XFree((IntPtr)fbconfigs); } + else + { + Debug.Print("No matching FB config found."); + } } } catch (EntryPointNotFoundException) { Debug.Print("Function glXChooseFBConfig not supported."); - return IntPtr.Zero; } } - return visual; + return result; } - // See http://publib.boulder.ibm.com/infocenter/systems/index.jsp?topic=/com.ibm.aix.opengl/doc/openglrf/glXChooseVisual.htm - IntPtr SelectVisualUsingChooseVisual(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, - int buffers, bool stereo) + IntPtr SelectVisual(GraphicsMode mode) { + Debug.Print("Selecting FB config for {0}", mode); + List visualAttributes = new List(); - Debug.Print("Bits per pixel: {0}", color.BitsPerPixel); - - if (color.BitsPerPixel > 0) + if (mode.ColorFormat.BitsPerPixel > 0) { - if (!color.IsIndexed) + if (!mode.ColorFormat.IsIndexed) visualAttributes.Add((int)GLXAttribute.RGBA); visualAttributes.Add((int)GLXAttribute.RED_SIZE); - visualAttributes.Add(color.Red); + visualAttributes.Add(mode.ColorFormat.Red); visualAttributes.Add((int)GLXAttribute.GREEN_SIZE); - visualAttributes.Add(color.Green); + visualAttributes.Add(mode.ColorFormat.Green); visualAttributes.Add((int)GLXAttribute.BLUE_SIZE); - visualAttributes.Add(color.Blue); + visualAttributes.Add(mode.ColorFormat.Blue); visualAttributes.Add((int)GLXAttribute.ALPHA_SIZE); - visualAttributes.Add(color.Alpha); + visualAttributes.Add(mode.ColorFormat.Alpha); } - Debug.Print("Depth: {0}", depth); - if (depth > 0) + if (mode.Depth > 0) { visualAttributes.Add((int)GLXAttribute.DEPTH_SIZE); - visualAttributes.Add(depth); + visualAttributes.Add(mode.Depth); } - if (buffers > 1) + if (mode.Buffers > 1) visualAttributes.Add((int)GLXAttribute.DOUBLEBUFFER); - if (stencil > 1) + if (mode.Stencil > 1) { visualAttributes.Add((int)GLXAttribute.STENCIL_SIZE); - visualAttributes.Add(stencil); + visualAttributes.Add(mode.Stencil); } - if (accum.BitsPerPixel > 0) + if (mode.AccumulatorFormat.BitsPerPixel > 0) { visualAttributes.Add((int)GLXAttribute.ACCUM_ALPHA_SIZE); - visualAttributes.Add(accum.Alpha); + visualAttributes.Add(mode.AccumulatorFormat.Alpha); visualAttributes.Add((int)GLXAttribute.ACCUM_BLUE_SIZE); - visualAttributes.Add(accum.Blue); + visualAttributes.Add(mode.AccumulatorFormat.Blue); visualAttributes.Add((int)GLXAttribute.ACCUM_GREEN_SIZE); - visualAttributes.Add(accum.Green); + visualAttributes.Add(mode.AccumulatorFormat.Green); visualAttributes.Add((int)GLXAttribute.ACCUM_RED_SIZE); - visualAttributes.Add(accum.Red); + visualAttributes.Add(mode.AccumulatorFormat.Red); } - - if (samples > 0) + + if (mode.Samples > 0) { visualAttributes.Add((int)GLXAttribute.SAMPLE_BUFFERS); visualAttributes.Add(1); visualAttributes.Add((int)GLXAttribute.SAMPLES); - visualAttributes.Add(samples); + visualAttributes.Add(mode.Samples); } - if (stereo) + if (mode.Stereo) visualAttributes.Add((int)GLXAttribute.STEREO); visualAttributes.Add(0); diff --git a/Source/OpenTK/Platform/X11/X11WindowInfo.cs b/Source/OpenTK/Platform/X11/X11WindowInfo.cs index 740e51d2..2b5b19ab 100644 --- a/Source/OpenTK/Platform/X11/X11WindowInfo.cs +++ b/Source/OpenTK/Platform/X11/X11WindowInfo.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.Runtime.InteropServices; using System.Text; namespace OpenTK.Platform.X11 @@ -87,7 +88,17 @@ namespace OpenTK.Platform.X11 /// Gets or sets the X11 screen. public int Screen { get { return screen; } set { screen = value; } } /// Gets or sets the X11 VisualInfo. - public XVisualInfo VisualInfo { get { return visualInfo; } set { visualInfo = value; } } + public XVisualInfo VisualInfo + { + get + { + if (Visual != IntPtr.Zero) + { + return (XVisualInfo)Marshal.PtrToStructure(Visual, typeof(XVisualInfo)); + } + return default(XVisualInfo); + } + } /// Gets or sets the X11 EventMask. public EventMask EventMask { get { return eventMask; } set { eventMask = value; } } @@ -96,6 +107,10 @@ namespace OpenTK.Platform.X11 // (e.g. MonoGame) public IntPtr WindowHandle { get { return Handle; } set { Handle = value; } } + public IntPtr Visual { get; set; } + public IntPtr FBConfig { get; set; } + public Graphics.GraphicsMode GraphicsMode { get; set; } + #endregion #region --- IDisposable Members --- From 6fa70263cb27e2be1e23776fcf37e71d124c3865 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 20 Jul 2014 11:28:43 +0200 Subject: [PATCH 4/5] [X11] Fixed GLControl on nvidia binary drivers Nvidia drivers fail in Glx.MakeCurrent() when using a 32bpp visual on a window created with a 24bpp visual. Since we do not know the actual visual until after the context is constructed, the solution is to implicitly use 24bpp when 32bpp is requested. The loss of the alpha channel does not have a user-visible effect, since WinForms do not support translucent windows on X11. --- Source/GLControl/X11GLControl.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Source/GLControl/X11GLControl.cs b/Source/GLControl/X11GLControl.cs index 19d036b7..6d70fbfb 100644 --- a/Source/GLControl/X11GLControl.cs +++ b/Source/GLControl/X11GLControl.cs @@ -77,7 +77,22 @@ namespace OpenTK if (control == null) throw new ArgumentNullException("control"); - this.mode = mode; + // Note: the X11 window is created with a default XVisualInfo, + // that is not necessarily compatible with the desired GraphicsMode. + // This manifests in Nvidia binary drivers that fail in Glx.MakeCurrent() + // when GraphicsMode has a 32bpp color format. + // To work around this issue, we implicitly select a 24bpp color format when 32bpp is + // requested - this appears to work correctly in all cases. + // (The loss of the alpha channel does not matter, since WinForms do not support + // translucent windows on X11 in the first place.) + this.mode = new GraphicsMode( + new ColorFormat(mode.ColorFormat.Red, mode.ColorFormat.Green, mode.ColorFormat.Blue, 0), + mode.Depth, + mode.Stencil, + mode.Samples, + mode.AccumulatorFormat, + mode.Buffers, + mode.Stereo); if (xplatui == null) throw new PlatformNotSupportedException( "System.Windows.Forms.XplatUIX11 missing. Unsupported platform or Mono runtime version, aborting."); @@ -105,6 +120,8 @@ namespace OpenTK info = (XVisualInfo)Marshal.PtrToStructure(infoPtr, typeof(XVisualInfo)); // set the X11 colormap. + // Note: this only affects windows created in the future + // (do we even need this here?) SetStaticFieldValue(xplatui, "CustomVisual", info.Visual); SetStaticFieldValue(xplatui, "CustomColormap", XCreateColormap(display, rootWindow, info.Visual, 0)); From 0f1776bdd0ed9501deb994cc5fef00d662d86ac2 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 20 Jul 2014 11:31:02 +0200 Subject: [PATCH 5/5] [X11] Use the correct visual info for the context This also fixes a potential NRE. --- Source/OpenTK/Platform/X11/X11GLContext.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Source/OpenTK/Platform/X11/X11GLContext.cs b/Source/OpenTK/Platform/X11/X11GLContext.cs index a1c95a39..d86a3481 100644 --- a/Source/OpenTK/Platform/X11/X11GLContext.cs +++ b/Source/OpenTK/Platform/X11/X11GLContext.cs @@ -93,7 +93,7 @@ namespace OpenTK.Platform.X11 Mode = currentWindow.GraphicsMode; } - if (!Mode.Index.HasValue) + if (Mode == null || !Mode.Index.HasValue) { Mode = ModeSelector.SelectGraphicsMode(mode, out visual, out fbconfig); } @@ -120,7 +120,7 @@ namespace OpenTK.Platform.X11 if (Handle == ContextHandle.Zero) { - Handle = CreateContextLegacy(Display, currentWindow.VisualInfo, direct, shareHandle); + Handle = CreateContextLegacy(Display, visual, direct, shareHandle); } if (Handle != ContextHandle.Zero) @@ -201,19 +201,18 @@ namespace OpenTK.Platform.X11 } static ContextHandle CreateContextLegacy(IntPtr display, - XVisualInfo info, bool direct, ContextHandle shareContext) + IntPtr info, bool direct, ContextHandle shareContext) { Debug.Write("Using legacy context creation... "); IntPtr context; using (new XLock(display)) { - // Cannot pass a Property by reference. - context = Glx.CreateContext(display, ref info, shareContext.Handle, direct); + context = Glx.CreateContext(display, info, shareContext.Handle, direct); if (context == IntPtr.Zero) { Debug.WriteLine(String.Format("failed. Trying direct: {0}... ", !direct)); - context = Glx.CreateContext(display, ref info, IntPtr.Zero, !direct); + context = Glx.CreateContext(display, info, shareContext.Handle, !direct); } }