[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[]
{
"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
}

View file

@ -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();
}