private 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); Glx.GetConfig(display, ref info, GLXAttribute.RED_SIZE, out r); Glx.GetConfig(display, ref info, GLXAttribute.GREEN_SIZE, out g); Glx.GetConfig(display, ref info, GLXAttribute.BLUE_SIZE, out b); int ar, ag, ab, aa; Glx.GetConfig(display, ref info, GLXAttribute.ACCUM_ALPHA_SIZE, out aa); 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); int st; Glx.GetConfig(display, ref info, GLXAttribute.STEREO, out st); // Note: Glx.GetConfig return buffers = 0 (false) or 1 (true). // osuTK 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)); }
public override IntPtr GetAddress(IntPtr function) { using (new XLock(Display)) { return(Glx.GetProcAddress(function)); } }
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() { return((GraphicsContext.GetCurrentContextDelegate) delegate { return new ContextHandle(Glx.GetCurrentContext()); }); }
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) { Debug.Write(String.Format("Releasing context {0} from thread {1} (Display: {2})... ", Handle, System.Threading.Thread.CurrentThread.ManagedThreadId, Display)); bool result; result = Glx.MakeCurrent(Display, IntPtr.Zero, IntPtr.Zero); if (result) { currentWindow = null; } Debug.Print("{0}", result ? "done!" : "failed."); } 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, Display, w.Screen, w.Handle)); if (Display == IntPtr.Zero || w.Handle == IntPtr.Zero || Handle == ContextHandle.Zero) { throw new InvalidOperationException("Invalid display, window or context."); } result = Glx.MakeCurrent(Display, w.Handle, Handle); if (result) { currentWindow = w; } if (!result) { throw new GraphicsContextException("Failed to make context current."); } else { Debug.WriteLine("done!"); } } currentWindow = (X11WindowInfo)window; }
public override void SwapBuffers() { if (Display == IntPtr.Zero || currentWindow.Handle == IntPtr.Zero) { throw new InvalidOperationException( String.Format("Window is invalid. Display ({0}), Handle ({1}).", Display, currentWindow.Handle)); } using (new XLock(Display)) { Glx.SwapBuffers(Display, currentWindow.Handle); } }
private static ContextHandle CreateContextLegacy(IntPtr display, IntPtr info, bool direct, ContextHandle shareContext) { Debug.Write("Using legacy context creation... "); IntPtr context; using (new XLock(display)) { 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, info, shareContext.Handle, !direct); } } return(new ContextHandle(context)); }
public GraphicsMode SelectGraphicsMode(GraphicsMode desired_mode, out IntPtr visual, out IntPtr fbconfig) { GraphicsMode gfx; 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. fbconfig = SelectFBConfig(mode); if (fbconfig != IntPtr.Zero) { visual = Glx.GetVisualFromFBConfig(display, fbconfig); } if (visual == IntPtr.Zero) { visual = SelectVisual(mode); } if (visual == IntPtr.Zero) { // Relax parameters and retry 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); }
protected override void Dispose(bool manuallyCalled) { if (!IsDisposed) { if (manuallyCalled) { IntPtr display = Display; if (IsCurrent) { Glx.MakeCurrent(display, IntPtr.Zero, IntPtr.Zero); } using (new XLock(display)) { Glx.DestroyContext(display, Handle); } } } else { Debug.Print("[Warning] {0} leaked.", this.GetType().Name); } IsDisposed = true; }
private bool SupportsExtension(IntPtr display, X11WindowInfo window, string e) { if (window == null) { throw new ArgumentNullException("window"); } if (e == null) { throw new ArgumentNullException("e"); } if (window.Display != display) { throw new InvalidOperationException(); } if (String.IsNullOrEmpty(extensions)) { using (new XLock(display)) { extensions = Glx.QueryExtensionsString(display, window.Screen); } } return(!String.IsNullOrEmpty(extensions) && extensions.Contains(e)); }
public X11GLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shared, bool direct, int major, int minor, GraphicsContextFlags flags) { if (mode == null) { throw new ArgumentNullException("mode"); } if (window == null) { throw new ArgumentNullException("window"); } // Do not move this lower, as almost everything requires the Display // property to be correctly set. Display = ((X11WindowInfo)window).Display; // Check that GLX is supported. We cannot proceed to create // an OpenGL context without the GLX extension. int error_base; int event_base; int glx_major; int glx_minor; using (new XLock(Display)) { bool supported = Glx.QueryExtension(Display, out error_base, out event_base); supported &= Glx.QueryVersion(Display, out glx_major, out glx_minor); if (supported) { Debug.Print("[X11] GLX supported. Version is {0}.{1}", glx_major, glx_minor); } else { throw new NotSupportedException("[X11] GLX extension is not supported."); } } 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; if (currentWindow.Visual != IntPtr.Zero) { visual = currentWindow.Visual; fbconfig = currentWindow.FBConfig; Mode = currentWindow.GraphicsMode; } if (Mode == null || !Mode.Index.HasValue) { Mode = ModeSelector.SelectGraphicsMode(mode, out visual, out fbconfig); } ContextHandle shareHandle = shared != null ? (shared as IGraphicsContextInternal).Context : (ContextHandle)IntPtr.Zero; Debug.Write("Creating X11GLContext context: "); Debug.Write(direct ? "direct, " : "indirect, "); Debug.WriteLine(shareHandle.Handle == IntPtr.Zero ? "not shared... " : String.Format("shared with ({0})... ", shareHandle)); // 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. // 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 (fbconfig != IntPtr.Zero && (major * 10 + minor >= 30) && SupportsCreateContextAttribs(Display, currentWindow)) { Handle = CreateContextAttribs(Display, currentWindow.Screen, fbconfig, direct, major, minor, flags, shareHandle); } if (Handle == ContextHandle.Zero) { Handle = CreateContextLegacy(Display, visual, direct, shareHandle); } 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."); } using (new XLock(Display)) { if (!Glx.IsDirect(Display, Handle.Handle)) { Debug.Print("Warning: Context is not direct."); } } }
private IntPtr SelectFBConfig(GraphicsMode mode) { Debug.Print("Selecting FB config for {0}", mode); List <int> visualAttributes = new List <int>(); if (mode.ColorFormat.BitsPerPixel > 0) { if (!mode.ColorFormat.IsIndexed) { visualAttributes.Add((int)GLXAttribute.RENDER_TYPE); visualAttributes.Add((int)GLXRenderTypeMask.RGBA_BIT); } visualAttributes.Add((int)GLXAttribute.RED_SIZE); visualAttributes.Add(mode.ColorFormat.Red); visualAttributes.Add((int)GLXAttribute.GREEN_SIZE); visualAttributes.Add(mode.ColorFormat.Green); visualAttributes.Add((int)GLXAttribute.BLUE_SIZE); visualAttributes.Add(mode.ColorFormat.Blue); visualAttributes.Add((int)GLXAttribute.ALPHA_SIZE); visualAttributes.Add(mode.ColorFormat.Alpha); } if (mode.Depth > 0) { visualAttributes.Add((int)GLXAttribute.DEPTH_SIZE); visualAttributes.Add(mode.Depth); } if (mode.Buffers > 1) { visualAttributes.Add((int)GLXAttribute.DOUBLEBUFFER); visualAttributes.Add(1); } if (mode.Stereo) { visualAttributes.Add((int)GLXAttribute.STENCIL_SIZE); visualAttributes.Add(mode.Stereo ? 1 : 0); } if (mode.AccumulatorFormat.BitsPerPixel > 0) { visualAttributes.Add((int)GLXAttribute.ACCUM_ALPHA_SIZE); visualAttributes.Add(mode.AccumulatorFormat.Alpha); visualAttributes.Add((int)GLXAttribute.ACCUM_BLUE_SIZE); visualAttributes.Add(mode.AccumulatorFormat.Blue); visualAttributes.Add((int)GLXAttribute.ACCUM_GREEN_SIZE); visualAttributes.Add(mode.AccumulatorFormat.Green); visualAttributes.Add((int)GLXAttribute.ACCUM_RED_SIZE); visualAttributes.Add(mode.AccumulatorFormat.Red); } if (mode.Samples > 0) { visualAttributes.Add((int)GLXAttribute.SAMPLE_BUFFERS); visualAttributes.Add(1); visualAttributes.Add((int)GLXAttribute.SAMPLES); visualAttributes.Add(mode.Samples); } if (mode.Stereo) { visualAttributes.Add((int)GLXAttribute.STEREO); visualAttributes.Add(1); } visualAttributes.Add(0); // Select a visual that matches the parameters set by the user. IntPtr display = API.DefaultDisplay; IntPtr result = IntPtr.Zero; using (new XLock(display)) { try { 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."); int fbcount; // Note that ChooseFBConfig returns an array of GLXFBConfig opaque structures (i.e. mapped to IntPtrs). IntPtr *fbconfigs = Glx.ChooseFBConfig(display, screen, visualAttributes.ToArray(), out fbcount); if (fbcount > 0 && fbconfigs != null) { // We want to use the first GLXFBConfig from the fbconfigs array (the first one is the best match). 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(result); }
private IntPtr SelectVisual(GraphicsMode mode) { Debug.Print("Selecting FB config for {0}", mode); List <int> visualAttributes = new List <int>(); if (mode.ColorFormat.BitsPerPixel > 0) { if (!mode.ColorFormat.IsIndexed) { visualAttributes.Add((int)GLXAttribute.RGBA); } visualAttributes.Add((int)GLXAttribute.RED_SIZE); visualAttributes.Add(mode.ColorFormat.Red); visualAttributes.Add((int)GLXAttribute.GREEN_SIZE); visualAttributes.Add(mode.ColorFormat.Green); visualAttributes.Add((int)GLXAttribute.BLUE_SIZE); visualAttributes.Add(mode.ColorFormat.Blue); visualAttributes.Add((int)GLXAttribute.ALPHA_SIZE); visualAttributes.Add(mode.ColorFormat.Alpha); } if (mode.Depth > 0) { visualAttributes.Add((int)GLXAttribute.DEPTH_SIZE); visualAttributes.Add(mode.Depth); } if (mode.Buffers > 1) { visualAttributes.Add((int)GLXAttribute.DOUBLEBUFFER); } if (mode.Stencil > 1) { visualAttributes.Add((int)GLXAttribute.STENCIL_SIZE); visualAttributes.Add(mode.Stencil); } if (mode.AccumulatorFormat.BitsPerPixel > 0) { visualAttributes.Add((int)GLXAttribute.ACCUM_ALPHA_SIZE); visualAttributes.Add(mode.AccumulatorFormat.Alpha); visualAttributes.Add((int)GLXAttribute.ACCUM_BLUE_SIZE); visualAttributes.Add(mode.AccumulatorFormat.Blue); visualAttributes.Add((int)GLXAttribute.ACCUM_GREEN_SIZE); visualAttributes.Add(mode.AccumulatorFormat.Green); visualAttributes.Add((int)GLXAttribute.ACCUM_RED_SIZE); visualAttributes.Add(mode.AccumulatorFormat.Red); } if (mode.Samples > 0) { visualAttributes.Add((int)GLXAttribute.SAMPLE_BUFFERS); visualAttributes.Add(1); visualAttributes.Add((int)GLXAttribute.SAMPLES); visualAttributes.Add(mode.Samples); } if (mode.Stereo) { visualAttributes.Add((int)GLXAttribute.STEREO); } visualAttributes.Add(0); Debug.Print("Falling back to glXChooseVisual."); IntPtr display = API.DefaultDisplay; using (new XLock(display)) { return(Glx.ChooseVisual(display, Functions.XDefaultScreen(display), visualAttributes.ToArray())); } }