[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.
This commit is contained in:
thefiddler 2014-05-09 00:13:23 +02:00
parent d430b462fe
commit 8195800ee7
2 changed files with 113 additions and 28 deletions

View file

@ -266,7 +266,14 @@ namespace OpenTK.Platform.X11
static string[] EntryPointNames = new string[] static string[] EntryPointNames = new string[]
{ {
"glXCreateContextAttribs", "glXCreateContextAttribs",
"glXSwapIntervalEXT",
"glXGetSwapIntervalEXT",
"glXSwapIntervalMESA",
"glXGetSwapIntervalMESA",
"glXSwapIntervalOML",
"glXGetSwapIntervalOML",
"glXSwapIntervalSGI", "glXSwapIntervalSGI",
"glXGetSwapIntervalSGI",
}; };
static IntPtr[] EntryPoints = new IntPtr[EntryPointNames.Length]; static IntPtr[] EntryPoints = new IntPtr[EntryPointNames.Length];
@ -405,6 +412,36 @@ namespace OpenTK.Platform.X11
#endregion #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 public partial class Sgi
{ {
[AutoGenerated(EntryPoint = "glXSwapIntervalSGI")] [AutoGenerated(EntryPoint = "glXSwapIntervalSGI")]
@ -412,6 +449,12 @@ namespace OpenTK.Platform.X11
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
[AutoGenerated(EntryPoint = "glXGetSwapIntervalSGI")]
public static int GetSwapInterval()
{
throw new NotImplementedException();
}
} }
[Slot(0)] [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); internal unsafe static extern IntPtr glXCreateContextAttribsARB(IntPtr display, IntPtr fbconfig, IntPtr share_context, bool direct, int* attribs);
[Slot(1)] [Slot(1)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] [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 #endregion
} }

View file

@ -29,10 +29,13 @@ namespace OpenTK.Platform.X11
// current on window originating from a different display. // current on window originating from a different display.
IntPtr display; IntPtr display;
X11WindowInfo currentWindow; X11WindowInfo currentWindow;
bool vsync_supported; bool vsync_ext_supported;
bool vsync_mesa_supported;
bool vsync_sgi_supported;
bool vsync_tear_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(); readonly X11GraphicsMode ModeSelector = new X11GraphicsMode();
string extensions = null;
#endregion #endregion
@ -232,7 +235,7 @@ namespace OpenTK.Platform.X11
return result; return result;
} }
static bool SupportsExtension(IntPtr display, X11WindowInfo window, string e) bool SupportsExtension(IntPtr display, X11WindowInfo window, string e)
{ {
if (window == null) if (window == null)
throw new ArgumentNullException("window"); throw new ArgumentNullException("window");
@ -241,15 +244,17 @@ namespace OpenTK.Platform.X11
if (window.Display != display) if (window.Display != display)
throw new InvalidOperationException(); throw new InvalidOperationException();
string extensions = null; if (String.IsNullOrEmpty(extensions))
{
using (new XLock(display)) using (new XLock(display))
{ {
extensions = Glx.QueryExtensionsString(display, window.Screen); extensions = Glx.QueryExtensionsString(display, window.Screen);
} }
}
return !String.IsNullOrEmpty(extensions) && extensions.Contains(e); return !String.IsNullOrEmpty(extensions) && extensions.Contains(e);
} }
static bool SupportsCreateContextAttribs(IntPtr display, X11WindowInfo window) bool SupportsCreateContextAttribs(IntPtr display, X11WindowInfo window)
{ {
return return
SupportsExtension(display, window, "GLX_ARB_create_context") && SupportsExtension(display, window, "GLX_ARB_create_context") &&
@ -354,14 +359,19 @@ namespace OpenTK.Platform.X11
{ {
get get
{ {
if (vsync_supported) using (new XLock(display))
return swap_interval; {
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 else
return 0; return 0;
} }
}
set set
{
if (vsync_supported)
{ {
if (value < 0 && !vsync_tear_supported) if (value < 0 && !vsync_tear_supported)
{ {
@ -370,15 +380,21 @@ namespace OpenTK.Platform.X11
ErrorCode error_code = 0; ErrorCode error_code = 0;
using (new XLock(Display)) 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); error_code = Glx.Sgi.SwapInterval(value);
}
if (error_code == X11.ErrorCode.NO_ERROR) if (error_code == X11.ErrorCode.NO_ERROR)
swap_interval = value; sgi_swap_interval = value;
else else
Debug.Print("VSync = {0} failed, error code: {1}.", value, error_code); Debug.Print("VSync = {0} failed, error code: {1}.", value, error_code);
} }
} }
}
#endregion #endregion
@ -386,12 +402,23 @@ namespace OpenTK.Platform.X11
public override void LoadAll() 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") && SupportsExtension(display, currentWindow, "GLX_SGI_swap_control") &&
Glx.SupportsFunction("glXSwapIntervalSGI"); Glx.SupportsFunction("glXSwapIntervalSGI");
Debug.Print("Context supports vsync: {0}.",
vsync_ext_supported || vsync_mesa_supported || vsync_ext_supported);
vsync_tear_supported = vsync_tear_supported =
SupportsExtension(display, currentWindow, "GLX_EXT_swap_control_tear"); 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(); base.LoadAll();
} }