Use more aggressive xlib locking following the advice of the multithreaded X manpages (needs work).
This commit is contained in:
parent
2a1924c62c
commit
974641086c
7 changed files with 158 additions and 99 deletions
|
@ -1,4 +1,4 @@
|
|||
#region --- License ---
|
||||
#region --- License ---
|
||||
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
|
||||
* Contributions from Erik Ylvisaker
|
||||
* See license.txt for license info
|
||||
|
@ -1589,6 +1589,23 @@ XF86VidModeGetGammaRampSize(
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
struct XLock : IDisposable
|
||||
{
|
||||
readonly IntPtr Display;
|
||||
|
||||
public XLock(IntPtr display)
|
||||
: this()
|
||||
{
|
||||
Functions.XLockDisplay(display);
|
||||
Display = display;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Functions.XUnlockDisplay(Display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 3019
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#region --- License ---
|
||||
#region --- License ---
|
||||
/* Licensed under the MIT/X11 license.
|
||||
* Copyright (c) 2006-2008 the OpenTK Team.
|
||||
* This notice may not be removed from any source distribution.
|
||||
|
@ -77,10 +77,18 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
internal static partial class Functions
|
||||
{
|
||||
public static readonly object Lock = new object();
|
||||
public static readonly object Lock = API.Lock;
|
||||
|
||||
[DllImport("libX11", EntryPoint = "XOpenDisplay")]
|
||||
public extern static IntPtr XOpenDisplay(IntPtr display);
|
||||
extern static IntPtr sys_XOpenDisplay(IntPtr display);
|
||||
public static IntPtr XOpenDisplay(IntPtr display)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
return sys_XOpenDisplay(display);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("libX11", EntryPoint = "XCloseDisplay")]
|
||||
public extern static int XCloseDisplay(IntPtr display);
|
||||
[DllImport("libX11", EntryPoint = "XSynchronize")]
|
||||
|
|
|
@ -49,18 +49,18 @@ namespace OpenTK.Platform.X11
|
|||
// Do not move this lower, as almost everything requires the Display
|
||||
// property to be correctly set.
|
||||
Display = ((X11WindowInfo)window).Display;
|
||||
|
||||
|
||||
currentWindow = (X11WindowInfo)window;
|
||||
currentWindow.VisualInfo = SelectVisual(mode, currentWindow);
|
||||
|
||||
|
||||
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));
|
||||
|
||||
|
||||
if (!glx_loaded)
|
||||
{
|
||||
Debug.WriteLine("Creating temporary context to load GLX extensions.");
|
||||
|
@ -130,7 +130,10 @@ namespace OpenTK.Platform.X11
|
|||
else
|
||||
Debug.WriteLine("success!");
|
||||
|
||||
Functions.XFree((IntPtr)fbconfigs);
|
||||
using (new XLock(Display))
|
||||
{
|
||||
Functions.XFree((IntPtr)fbconfigs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
Debug.Indent();
|
||||
|
||||
lock (API.Lock)
|
||||
using (new XLock(window.Display))
|
||||
{
|
||||
if (!mode.Index.HasValue)
|
||||
throw new GraphicsModeException("Invalid or unsupported GraphicsMode.");
|
||||
|
@ -164,7 +164,7 @@ namespace OpenTK.Platform.X11
|
|||
hints.base_width = width;
|
||||
hints.base_height = height;
|
||||
hints.flags = (IntPtr)(XSizeHintsFlags.PSize | XSizeHintsFlags.PPosition);
|
||||
lock (API.Lock)
|
||||
using (new XLock(window.Display))
|
||||
{
|
||||
Functions.XSetWMNormalHints(window.Display, window.WindowHandle, ref hints);
|
||||
|
||||
|
@ -194,21 +194,18 @@ namespace OpenTK.Platform.X11
|
|||
Debug.Indent();
|
||||
|
||||
// Open a display connection to the X server, and obtain the screen and root window.
|
||||
window.Display = API.DefaultDisplay;
|
||||
window.Display = Functions.XOpenDisplay(IntPtr.Zero);
|
||||
//window.Display = API.DefaultDisplay;
|
||||
if (window.Display == IntPtr.Zero)
|
||||
throw new Exception("Could not open connection to X");
|
||||
|
||||
try
|
||||
using (new XLock(window.Display))
|
||||
{
|
||||
Functions.XLockDisplay(window.Display);
|
||||
window.Screen = Functions.XDefaultScreen(window.Display); //API.DefaultScreen;
|
||||
window.RootWindow = Functions.XRootWindow(window.Display, window.Screen); // API.RootWindow;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Functions.XUnlockDisplay(window.Display);
|
||||
}
|
||||
|
||||
|
||||
Debug.Print("Display: {0}, Screen {1}, Root window: {2}", window.Display, window.Screen,
|
||||
window.RootWindow);
|
||||
|
||||
|
@ -232,28 +229,30 @@ namespace OpenTK.Platform.X11
|
|||
/// </summary>
|
||||
private void RegisterAtoms(X11WindowInfo window)
|
||||
{
|
||||
Debug.WriteLine("Registering atoms.");
|
||||
_atom_wm_destroy = Functions.XInternAtom(window.Display, "WM_DELETE_WINDOW", true);
|
||||
using (new XLock(window.Display))
|
||||
{
|
||||
Debug.WriteLine("Registering atoms.");
|
||||
_atom_wm_destroy = Functions.XInternAtom(window.Display, "WM_DELETE_WINDOW", true);
|
||||
|
||||
_atom_net_wm_state = Functions.XInternAtom(window.Display, "_NET_WM_STATE", false);
|
||||
_atom_net_wm_state_minimized = Functions.XInternAtom(window.Display, "_NET_WM_STATE_MINIMIZED", false);
|
||||
_atom_net_wm_state_fullscreen = Functions.XInternAtom(window.Display, "_NET_WM_STATE_FULLSCREEN", false);
|
||||
_atom_net_wm_state_maximized_horizontal =
|
||||
_atom_net_wm_state_minimized = Functions.XInternAtom(window.Display, "_NET_WM_STATE_MINIMIZED", false);
|
||||
_atom_net_wm_state_fullscreen = Functions.XInternAtom(window.Display, "_NET_WM_STATE_FULLSCREEN", false);
|
||||
_atom_net_wm_state_maximized_horizontal =
|
||||
Functions.XInternAtom(window.Display, "_NET_WM_STATE_MAXIMIZED_HORZ", false);
|
||||
_atom_net_wm_state_maximized_vertical =
|
||||
_atom_net_wm_state_maximized_vertical =
|
||||
Functions.XInternAtom(window.Display, "_NET_WM_STATE_MAXIMIZED_VERT", false);
|
||||
|
||||
_atom_net_wm_allowed_actions =
|
||||
Functions.XInternAtom(window.Display, "_NET_WM_ALLOWED_ACTIONS", false);
|
||||
_atom_net_wm_action_resize =
|
||||
_atom_net_wm_action_resize =
|
||||
Functions.XInternAtom(window.Display, "_NET_WM_ACTION_RESIZE", false);
|
||||
_atom_net_wm_action_maximize_horizontally =
|
||||
_atom_net_wm_action_maximize_horizontally =
|
||||
Functions.XInternAtom(window.Display, "_NET_WM_ACTION_MAXIMIZE_HORZ", false);
|
||||
_atom_net_wm_action_maximize_vertically =
|
||||
_atom_net_wm_action_maximize_vertically =
|
||||
Functions.XInternAtom(window.Display, "_NET_WM_ACTION_MAXIMIZE_VERT", false);
|
||||
|
||||
_atom_net_wm_icon =
|
||||
Functions.XInternAtom(window.Display,"_NEW_WM_ICON", false);
|
||||
Functions.XInternAtom(window.Display, "_NEW_WM_ICON", false);
|
||||
|
||||
// string[] atom_names = new string[]
|
||||
// {
|
||||
|
@ -266,6 +265,7 @@ namespace OpenTK.Platform.X11
|
|||
// int offset = 0;
|
||||
// //WMTitle = atoms[offset++];
|
||||
// //UTF8String = atoms[offset++];
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#region --- License ---
|
||||
#region --- License ---
|
||||
/* Licensed under the MIT/X11 license.
|
||||
* Copyright (c) 2006-2008 the OpenTK Team.
|
||||
* This notice may not be removed from any source distribution.
|
||||
|
@ -35,22 +35,23 @@ namespace OpenTK.Platform.X11
|
|||
public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum,
|
||||
int buffers, bool stereo)
|
||||
{
|
||||
GraphicsMode gfx; // The actual GraphicsMode that will be selected.
|
||||
GraphicsMode gfx;
|
||||
// The actual GraphicsMode that will be selected.
|
||||
IntPtr visual = IntPtr.Zero;
|
||||
IntPtr display = API.DefaultDisplay;
|
||||
|
||||
|
||||
// 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.
|
||||
visual = SelectVisualUsingFBConfig(color, depth, stencil, samples, accum, buffers, stereo);
|
||||
|
||||
if (visual == IntPtr.Zero)
|
||||
visual = SelectVisualUsingChooseVisual(color, depth, stencil, samples, accum, buffers, stereo);
|
||||
|
||||
|
||||
if (visual == IntPtr.Zero)
|
||||
throw new GraphicsContextException("Requested GraphicsMode not available.");
|
||||
|
||||
|
||||
XVisualInfo info = (XVisualInfo)Marshal.PtrToStructure(visual, typeof(XVisualInfo));
|
||||
|
||||
|
||||
// See what we *really* got:
|
||||
int r, g, b, a;
|
||||
Glx.GetConfig(display, ref info, GLXAttribute.ALPHA_SIZE, out a);
|
||||
|
@ -66,15 +67,19 @@ namespace OpenTK.Platform.X11
|
|||
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);
|
||||
++buffers; // the above lines returns 0 - false and 1 - true.
|
||||
++buffers;
|
||||
// the above lines returns 0 - false and 1 - true.
|
||||
int st;
|
||||
Glx.GetConfig(display, ref info, GLXAttribute.STEREO, out st);
|
||||
stereo = st != 0;
|
||||
|
||||
gfx = new GraphicsMode(info.VisualID, new ColorFormat(r, g, b, a), depth, stencil, samples,
|
||||
new ColorFormat(ar, ag, ab, aa), buffers, stereo);
|
||||
|
||||
Functions.XFree(visual);
|
||||
new ColorFormat(ar, ag, ab, aa), buffers, stereo);
|
||||
|
||||
using (new XLock(display))
|
||||
{
|
||||
Functions.XFree(visual);
|
||||
}
|
||||
|
||||
return gfx;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#region --- License ---
|
||||
#region --- License ---
|
||||
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
|
||||
* See license.txt for license info
|
||||
*/
|
||||
|
@ -53,38 +53,41 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
//window = new X11WindowInfo(attach);
|
||||
X11WindowInfo window = (X11WindowInfo)attach;
|
||||
|
||||
|
||||
// Init mouse
|
||||
mouse.Description = "Default X11 mouse";
|
||||
mouse.DeviceID = IntPtr.Zero;
|
||||
mouse.NumberOfButtons = 5;
|
||||
mouse.NumberOfWheels = 1;
|
||||
dummy_mice_list.Add(mouse);
|
||||
|
||||
// Init keyboard
|
||||
API.DisplayKeycodes(window.Display, ref firstKeyCode, ref lastKeyCode);
|
||||
Debug.Print("First keycode: {0}, last {1}", firstKeyCode, lastKeyCode);
|
||||
|
||||
IntPtr keysym_ptr = API.GetKeyboardMapping(window.Display, (byte)firstKeyCode,
|
||||
lastKeyCode - firstKeyCode + 1, ref keysyms_per_keycode);
|
||||
Debug.Print("{0} keysyms per keycode.", keysyms_per_keycode);
|
||||
|
||||
keysyms = new IntPtr[(lastKeyCode - firstKeyCode + 1) * keysyms_per_keycode];
|
||||
Marshal.PtrToStructure(keysym_ptr, keysyms);
|
||||
API.Free(keysym_ptr);
|
||||
|
||||
KeyboardDevice kb = new KeyboardDevice();
|
||||
keyboard.Description = "Default X11 keyboard";
|
||||
keyboard.NumberOfKeys = lastKeyCode - firstKeyCode + 1;
|
||||
keyboard.DeviceID = IntPtr.Zero;
|
||||
dummy_keyboard_list.Add(keyboard);
|
||||
|
||||
// Request that auto-repeat is only set on devices that support it physically.
|
||||
// This typically means that it's turned off for keyboards (which is what we want).
|
||||
// We prefer this method over XAutoRepeatOff/On, because the latter needs to
|
||||
// be reset before the program exits.
|
||||
bool supported;
|
||||
Functions.XkbSetDetectableAutoRepeat(window.Display, true, out supported);
|
||||
|
||||
using (new XLock(window.Display))
|
||||
{
|
||||
// Init keyboard
|
||||
API.DisplayKeycodes(window.Display, ref firstKeyCode, ref lastKeyCode);
|
||||
Debug.Print("First keycode: {0}, last {1}", firstKeyCode, lastKeyCode);
|
||||
|
||||
IntPtr keysym_ptr = API.GetKeyboardMapping(window.Display, (byte)firstKeyCode,
|
||||
lastKeyCode - firstKeyCode + 1, ref keysyms_per_keycode);
|
||||
Debug.Print("{0} keysyms per keycode.", keysyms_per_keycode);
|
||||
|
||||
keysyms = new IntPtr[(lastKeyCode - firstKeyCode + 1) * keysyms_per_keycode];
|
||||
Marshal.PtrToStructure(keysym_ptr, keysyms);
|
||||
API.Free(keysym_ptr);
|
||||
|
||||
KeyboardDevice kb = new KeyboardDevice();
|
||||
keyboard.Description = "Default X11 keyboard";
|
||||
keyboard.NumberOfKeys = lastKeyCode - firstKeyCode + 1;
|
||||
keyboard.DeviceID = IntPtr.Zero;
|
||||
dummy_keyboard_list.Add(keyboard);
|
||||
|
||||
// Request that auto-repeat is only set on devices that support it physically.
|
||||
// This typically means that it's turned off for keyboards (which is what we want).
|
||||
// We prefer this method over XAutoRepeatOff/On, because the latter needs to
|
||||
// be reset before the program exits.
|
||||
bool supported;
|
||||
Functions.XkbSetDetectableAutoRepeat(window.Display, true, out supported);
|
||||
}
|
||||
|
||||
Debug.Unindent();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#region --- License ---
|
||||
#region --- License ---
|
||||
/* Licensed under the MIT/X11 license.
|
||||
* Copyright (c) 2006-2008 the OpenTK Team.
|
||||
* This notice may not be removed from any source distribution.
|
||||
|
@ -42,16 +42,19 @@ namespace OpenTK.Platform.X11
|
|||
for (int screen = 0; screen < API.ScreenCount; screen++)
|
||||
{
|
||||
IntPtr timestamp_of_last_update;
|
||||
Functions.XRRTimes(API.DefaultDisplay, screen, out timestamp_of_last_update);
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
Functions.XRRTimes(API.DefaultDisplay, screen, out timestamp_of_last_update);
|
||||
}
|
||||
lastConfigUpdate.Add(timestamp_of_last_update);
|
||||
|
||||
|
||||
List<DisplayResolution> available_res = new List<DisplayResolution>();
|
||||
|
||||
|
||||
// Add info for a new screen.
|
||||
screenResolutionToIndex.Add(new Dictionary<DisplayResolution, int>());
|
||||
|
||||
|
||||
int[] depths = FindAvailableDepths(screen);
|
||||
|
||||
|
||||
int resolution_count = 0;
|
||||
foreach (XRRScreenSize size in FindAvailableResolutions(screen))
|
||||
{
|
||||
|
@ -60,7 +63,11 @@ namespace OpenTK.Platform.X11
|
|||
Debug.Print("[Warning] XRandR returned an invalid resolution ({0}) for display device {1}", size, screen);
|
||||
continue;
|
||||
}
|
||||
short[] rates = Functions.XRRRates(API.DefaultDisplay, screen, resolution_count);
|
||||
short[] rates = null;
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
rates = Functions.XRRRates(API.DefaultDisplay, screen, resolution_count);
|
||||
}
|
||||
|
||||
// It seems that XRRRates returns 0 for modes that are larger than the screen
|
||||
// can support, as well as for all supported modes. On Ubuntu 7.10 the tool
|
||||
|
@ -114,7 +121,10 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
static int[] FindAvailableDepths(int screen)
|
||||
{
|
||||
return Functions.XListDepths(API.DefaultDisplay, screen);
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
return Functions.XListDepths(API.DefaultDisplay, screen);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -123,7 +133,11 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
static XRRScreenSize[] FindAvailableResolutions(int screen)
|
||||
{
|
||||
XRRScreenSize[] resolutions = Functions.XRRSizes(API.DefaultDisplay, screen);
|
||||
XRRScreenSize[] resolutions = null;
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
resolutions = Functions.XRRSizes(API.DefaultDisplay, screen);
|
||||
}
|
||||
if (resolutions == null)
|
||||
throw new NotSupportedException("XRandR extensions not available.");
|
||||
return resolutions;
|
||||
|
@ -135,12 +149,15 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
static float FindCurrentRefreshRate(int screen)
|
||||
{
|
||||
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, Functions.XRootWindow(API.DefaultDisplay, screen));
|
||||
ushort rotation = 0;
|
||||
int size = Functions.XRRConfigCurrentConfiguration(screen_config, out rotation);
|
||||
short rate = Functions.XRRConfigCurrentRate(screen_config);
|
||||
Functions.XRRFreeScreenConfigInfo(screen_config);
|
||||
|
||||
short rate = 0;
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, Functions.XRootWindow(API.DefaultDisplay, screen));
|
||||
ushort rotation = 0;
|
||||
int size = Functions.XRRConfigCurrentConfiguration(screen_config, out rotation);
|
||||
rate = Functions.XRRConfigCurrentRate(screen_config);
|
||||
Functions.XRRFreeScreenConfigInfo(screen_config);
|
||||
}
|
||||
return (float)rate;
|
||||
}
|
||||
|
||||
|
@ -150,7 +167,10 @@ namespace OpenTK.Platform.X11
|
|||
|
||||
private static int FindCurrentDepth(int screen)
|
||||
{
|
||||
return (int)Functions.XDefaultDepth(API.DefaultDisplay, screen);
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
return (int)Functions.XDefaultDepth(API.DefaultDisplay, screen);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -163,24 +183,27 @@ namespace OpenTK.Platform.X11
|
|||
{
|
||||
// If resolution == null, restore to default resolution (new_resolution_index = 0).
|
||||
|
||||
int screen = deviceToScreen[device];
|
||||
IntPtr root = Functions.XRootWindow(API.DefaultDisplay, screen);
|
||||
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, root);
|
||||
|
||||
ushort current_rotation;
|
||||
int current_resolution_index = Functions.XRRConfigCurrentConfiguration(screen_config, out current_rotation);
|
||||
int new_resolution_index;
|
||||
if (resolution != null)
|
||||
new_resolution_index = screenResolutionToIndex[screen]
|
||||
[new DisplayResolution(0, 0, resolution.Width, resolution.Height, resolution.BitsPerPixel, 0)];
|
||||
else
|
||||
new_resolution_index = deviceToDefaultResolution[device];
|
||||
|
||||
Debug.Print("Changing size of screen {0} from {1} to {2}",
|
||||
screen, current_resolution_index, new_resolution_index);
|
||||
|
||||
return 0 == Functions.XRRSetScreenConfigAndRate(API.DefaultDisplay, screen_config, root, new_resolution_index,
|
||||
current_rotation, (short)(resolution != null ? resolution.RefreshRate : 0), lastConfigUpdate[screen]);
|
||||
using (new XLock(API.DefaultDisplay))
|
||||
{
|
||||
int screen = deviceToScreen[device];
|
||||
IntPtr root = Functions.XRootWindow(API.DefaultDisplay, screen);
|
||||
IntPtr screen_config = Functions.XRRGetScreenInfo(API.DefaultDisplay, root);
|
||||
|
||||
ushort current_rotation;
|
||||
int current_resolution_index = Functions.XRRConfigCurrentConfiguration(screen_config, out current_rotation);
|
||||
int new_resolution_index;
|
||||
if (resolution != null)
|
||||
new_resolution_index = screenResolutionToIndex[screen]
|
||||
[new DisplayResolution(0, 0, resolution.Width, resolution.Height, resolution.BitsPerPixel, 0)];
|
||||
else
|
||||
new_resolution_index = deviceToDefaultResolution[device];
|
||||
|
||||
Debug.Print("Changing size of screen {0} from {1} to {2}",
|
||||
screen, current_resolution_index, new_resolution_index);
|
||||
|
||||
return 0 == Functions.XRRSetScreenConfigAndRate(API.DefaultDisplay, screen_config, root, new_resolution_index,
|
||||
current_rotation, (short)(resolution != null ? resolution.RefreshRate : 0), lastConfigUpdate[screen]);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryRestoreResolution(DisplayDevice device)
|
||||
|
|
Loading…
Reference in a new issue