Use more aggressive xlib locking following the advice of the multithreaded X manpages (needs work).

This commit is contained in:
the_fiddler 2009-11-02 22:37:13 +00:00
parent 0bfb7897b0
commit 74bae3e196
7 changed files with 158 additions and 99 deletions

View file

@ -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

View file

@ -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")]

View file

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

View file

@ -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

View file

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

View file

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

View file

@ -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)