From 8195800ee7d4c96b06583f76f9ee857e15009955 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 9 May 2014 00:13:23 +0200 Subject: [PATCH] [X11] Improved vsync support OpenTK will now check for GLX_EXT_swap_control, GLX_MESA_swap_control and GLX_SGI_swap_control. This allows us to control vsync on more systems. --- Source/OpenTK/Platform/X11/Bindings/Glx.cs | 60 +++++++++++++++- Source/OpenTK/Platform/X11/X11GLContext.cs | 81 ++++++++++++++-------- 2 files changed, 113 insertions(+), 28 deletions(-) diff --git a/Source/OpenTK/Platform/X11/Bindings/Glx.cs b/Source/OpenTK/Platform/X11/Bindings/Glx.cs index 4a312b9d..27c83695 100644 --- a/Source/OpenTK/Platform/X11/Bindings/Glx.cs +++ b/Source/OpenTK/Platform/X11/Bindings/Glx.cs @@ -266,7 +266,14 @@ namespace OpenTK.Platform.X11 static string[] EntryPointNames = new string[] { "glXCreateContextAttribs", + "glXSwapIntervalEXT", + "glXGetSwapIntervalEXT", + "glXSwapIntervalMESA", + "glXGetSwapIntervalMESA", + "glXSwapIntervalOML", + "glXGetSwapIntervalOML", "glXSwapIntervalSGI", + "glXGetSwapIntervalSGI", }; static IntPtr[] EntryPoints = new IntPtr[EntryPointNames.Length]; @@ -405,6 +412,36 @@ namespace OpenTK.Platform.X11 #endregion } + public partial class Ext + { + [AutoGenerated(EntryPoint = "glXSwapIntervalEXT")] + public static ErrorCode SwapInterval(int interval) + { + throw new NotImplementedException(); + } + + [AutoGenerated(EntryPoint = "glXGetSwapIntervalEXT")] + public static int GetSwapInterval() + { + throw new NotImplementedException(); + } + } + + public partial class Mesa + { + [AutoGenerated(EntryPoint = "glXSwapIntervalMESA")] + public static ErrorCode SwapInterval(int interval) + { + throw new NotImplementedException(); + } + + [AutoGenerated(EntryPoint = "glXGetSwapIntervalMESA")] + public static int GetSwapInterval() + { + throw new NotImplementedException(); + } + } + public partial class Sgi { [AutoGenerated(EntryPoint = "glXSwapIntervalSGI")] @@ -412,6 +449,12 @@ namespace OpenTK.Platform.X11 { throw new NotImplementedException(); } + + [AutoGenerated(EntryPoint = "glXGetSwapIntervalSGI")] + public static int GetSwapInterval() + { + throw new NotImplementedException(); + } } [Slot(0)] @@ -419,7 +462,22 @@ namespace OpenTK.Platform.X11 internal unsafe static extern IntPtr glXCreateContextAttribsARB(IntPtr display, IntPtr fbconfig, IntPtr share_context, bool direct, int* attribs); [Slot(1)] [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] - internal static extern IntPtr glXSwapIntervalSGI(int interval); + internal static extern ErrorCode glXSwapIntervalEXT(int interval); + [Slot(2)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern int glXGetSwapIntervalEXT(); + [Slot(3)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern ErrorCode glXSwapIntervalMESA(int interval); + [Slot(4)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern int glXGetSwapIntervalMESA(); + [Slot(5)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern ErrorCode glXSwapIntervalSGI(int interval); + [Slot(6)] + [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + internal static extern int glXGetSwapIntervalSGI(); #endregion } diff --git a/Source/OpenTK/Platform/X11/X11GLContext.cs b/Source/OpenTK/Platform/X11/X11GLContext.cs index e67c1514..9596f0e3 100644 --- a/Source/OpenTK/Platform/X11/X11GLContext.cs +++ b/Source/OpenTK/Platform/X11/X11GLContext.cs @@ -29,10 +29,13 @@ namespace OpenTK.Platform.X11 // current on window originating from a different display. IntPtr display; X11WindowInfo currentWindow; - bool vsync_supported; + bool vsync_ext_supported; + bool vsync_mesa_supported; + bool vsync_sgi_supported; bool vsync_tear_supported; - int swap_interval = 1; // As defined in GLX_SGI_swap_control + int sgi_swap_interval = 1; // As defined in GLX_SGI_swap_control readonly X11GraphicsMode ModeSelector = new X11GraphicsMode(); + string extensions = null; #endregion @@ -232,7 +235,7 @@ namespace OpenTK.Platform.X11 return result; } - static bool SupportsExtension(IntPtr display, X11WindowInfo window, string e) + bool SupportsExtension(IntPtr display, X11WindowInfo window, string e) { if (window == null) throw new ArgumentNullException("window"); @@ -241,15 +244,17 @@ namespace OpenTK.Platform.X11 if (window.Display != display) throw new InvalidOperationException(); - string extensions = null; - using (new XLock(display)) + if (String.IsNullOrEmpty(extensions)) { - extensions = Glx.QueryExtensionsString(display, window.Screen); + using (new XLock(display)) + { + extensions = Glx.QueryExtensionsString(display, window.Screen); + } } return !String.IsNullOrEmpty(extensions) && extensions.Contains(e); } - static bool SupportsCreateContextAttribs(IntPtr display, X11WindowInfo window) + bool SupportsCreateContextAttribs(IntPtr display, X11WindowInfo window) { return SupportsExtension(display, window, "GLX_ARB_create_context") && @@ -354,29 +359,40 @@ namespace OpenTK.Platform.X11 { get { - if (vsync_supported) - return swap_interval; - else - return 0; + using (new XLock(display)) + { + if (vsync_ext_supported) + return Glx.Ext.GetSwapInterval(); + else if (vsync_mesa_supported) + return Glx.Mesa.GetSwapInterval(); + else if (vsync_sgi_supported) + return sgi_swap_interval; + else + return 0; + } } set { - if (vsync_supported) + if (value < 0 && !vsync_tear_supported) { - if (value < 0 && !vsync_tear_supported) - { - value = 1; - } - - ErrorCode error_code = 0; - using (new XLock(Display)) - error_code = Glx.Sgi.SwapInterval(value); - - if (error_code == X11.ErrorCode.NO_ERROR) - swap_interval = value; - else - Debug.Print("VSync = {0} failed, error code: {1}.", value, error_code); + value = 1; } + + ErrorCode error_code = 0; + using (new XLock(Display)) + { + if (vsync_ext_supported) + error_code = Glx.Ext.SwapInterval(value); + else if (vsync_mesa_supported) + error_code = Glx.Mesa.SwapInterval(value); + else if (vsync_sgi_supported) + error_code = Glx.Sgi.SwapInterval(value); + } + + if (error_code == X11.ErrorCode.NO_ERROR) + sgi_swap_interval = value; + else + Debug.Print("VSync = {0} failed, error code: {1}.", value, error_code); } } @@ -386,12 +402,23 @@ namespace OpenTK.Platform.X11 public override void LoadAll() { - vsync_supported = + vsync_ext_supported = + SupportsExtension(display, currentWindow, "GLX_EXT_swap_control") && + Glx.SupportsFunction("glXSwapIntervalEXT") && + Glx.SupportsFunction("glXGetSwapIntervalEXT"); + vsync_mesa_supported = + SupportsExtension(display, currentWindow, "GLX_MESA_swap_control") && + Glx.SupportsFunction("glXSwapIntervalMESA") && + Glx.SupportsFunction("glXGetSwapIntervalMESA"); + vsync_sgi_supported = SupportsExtension(display, currentWindow, "GLX_SGI_swap_control") && Glx.SupportsFunction("glXSwapIntervalSGI"); + Debug.Print("Context supports vsync: {0}.", + vsync_ext_supported || vsync_mesa_supported || vsync_ext_supported); + vsync_tear_supported = SupportsExtension(display, currentWindow, "GLX_EXT_swap_control_tear"); - Debug.Print("Context supports vsync: {0}.", vsync_supported); + Debug.Print("Context supports vsync tear: {0}.", vsync_tear_supported); base.LoadAll(); }