I'm having some trouble to have a rendering system working on both Windows and Linux platforms.
On Windows platform it works like a sharm, while on Linux my application terminates with the following exception:
System.InvalidOperationException: context cannot be current ---> System.ComponentModel.Win32Exception: BadMatch (invalid parameter attributes) X error details: X event name: '' (0) Display: 0x8f17328 Resource ID: 4000011 Error code: 8 Major code: '' (135) Minor code: 5
at Derm.Render.RenderContext.MakeCurrent (IDeviceContext deviceContext, Boolean flag) at Derm.Render.RenderContext.CreateRenderContext (IDeviceContext deviceContext, Derm.Render.RenderContext hSharedContext, GLVersion version) Stacktrace:
at (wrapper managed-to-native) System.Windows.Forms.XplatUIX11.XFlush (intptr) at System.Windows.Forms.XplatUIX11.PostQuitMessage (int)
...
at System.Windows.Forms.Control.CreateHandle () at System.Windows.Forms.Control.CreateControl()
I'm able to create a "simple" rendering context, using the following routine:
private static IntPtr CreateX11SimpleContext(IDeviceContext rDevice)
{
XServerDeviceContext x11DeviceCtx = (XServerDeviceContext)rDevice;
using (new Glx.XLock(x11DeviceCtx.Display)) {
int[] attributes = new int[] {
Glx.RENDER_TYPE, (int)Glx.RGBA_BIT,
0
};
// Get basic visual
unsafe {
int[] choosenConfigCount = new int[1];
IntPtr *choosenConfigs = Glx.ChooseFBConfig(x11DeviceCtx.Display, x11DeviceCtx.Screen, attributes, ref choosenConfigCount);
if (choosenConfigCount[0] == 0)
throw new InvalidOperationException("unable to find basic visual");
IntPtr choosenConfig = *choosenConfigs;
IntPtr visual = Glx.GetVisualFromFBConfig(x11DeviceCtx.Display, choosenConfig);
x11DeviceCtx.XVisualInfo = (Glx.XVisualInfo)Marshal.PtrToStructure(visual, typeof(Glx.XVisualInfo));
x11DeviceCtx.FBConfig = choosenConfig;
Glx.XFree((IntPtr)choosenConfigs);
}
// Create direct context
IntPtr rContext = Glx.CreateContext(x11DeviceCtx.Display, x11DeviceCtx.XVisualInfo, IntPtr.Zero, true);
if (rContext == IntPtr.Zero) {
// Fallback to not direct context
rContext = Glx.CreateContext(x11DeviceCtx.Display, x11DeviceCtx.XVisualInfo, IntPtr.Zero, false);
}
if (rContext == IntPtr.Zero)
throw new InvalidOperationException("unable to create context");
return (rContext);
}
}
The problem I'm facing is that the above context is used for fetching the OpenGL informations (extensions, renderer, ...), and then is destroyed. Successively, I create a context using attributes:
XServerDeviceContext x11DeviceContext = (XServerDeviceContext)deviceContext;
using (Glx.XLock displayLock = new Glx.XLock(x11DeviceContext.Display)) {
return (Glx.CreateContextAttribsARB(x11DeviceContext.Display, x11DeviceContext.FBConfig, sharedContext, true, attribsList));
}
The context is created, but at the next glXMakeCurrent
the X server send me the error in question (BadMatch).
I've suspected about the CreateContextAttribsARB
arguments: x11DeviceContext.Display
and x11DeviceContext.FBConfig
. Infact, the "drawable" I'm using is actually a System.Windows.Forms
control, provided by Mono implementation.
Here is some snippets showing how I initialize those variables:
How do I initialize x11DeviceContext.Display
?
Type xplatui = Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms");
Type xplatui = Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms");
if (xplatui == null)
throw new PlatformNotSupportedException("mono runtime version no supported");
// Get System.Windows.Forms display
mDisplay = (IntPtr)xplatui.GetField("DisplayHandle", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic).GetValue(null);
if (mDisplay == IntPtr.Zero)
throw new InvalidOperationException("unable to connect to X server");
How do I initialize x11DeviceContext.FBConfig
?
IntPtr* configs = Glx.GetFBConfigs(x11DeviceContext.Display, x11DeviceContext.Screen, out configsCount);
// Then, a value is selected using a custom seletcion algo, using GetFBConfigAttrib
Sorry because I'm not able to give you a short example program, but the code base is very large and complex.
Do you have any idea to what it's going on?
EDIT:
Further investigations revealed that I can correctly render using specific visuals, otherwise I get a BadMatch
. I can't say why, but I see my lines and triangles (but I need to swap even if the visual is not double buffered...).
Previously I got the BadMatch
error because I was not aware of "not conformant" visual, indeed I selected one of them; however, most of the visual give me the error.
I've checked the XplatUIX11
class of the Mono implementation, and actually open the display with XOpenDisplay
.
I found the solution.
I wrote an unit test, creating OpenGL contextes for each visual, and I found the variable that discriminate the visuals that cause the BadMatch
error: the depth of the visual used for creating the window.
Visuals having a 32 bit depth cause the BadMatch
error. Fortunately the driver offers equivalent visuals having 24 bit depth, which works perfectly.
Using the System.Windows.Forms.XPlatUIX11 implementation of Mono, the window is created by the framework (in my case a UserControl). Since it uses the CopyFromParent
constant, my Control inherit the visual depth, limiting the possible visual to select.