mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-07-18 21:27:41 +00:00
[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:
parent
d430b462fe
commit
8195800ee7
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
|
||||||
{
|
{
|
||||||
extensions = Glx.QueryExtensionsString(display, window.Screen);
|
using (new XLock(display))
|
||||||
|
{
|
||||||
|
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,29 +359,40 @@ namespace OpenTK.Platform.X11
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (vsync_supported)
|
using (new XLock(display))
|
||||||
return swap_interval;
|
{
|
||||||
else
|
if (vsync_ext_supported)
|
||||||
return 0;
|
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
|
set
|
||||||
{
|
{
|
||||||
if (vsync_supported)
|
if (value < 0 && !vsync_tear_supported)
|
||||||
{
|
{
|
||||||
if (value < 0 && !vsync_tear_supported)
|
value = 1;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue