jdomnitz's picture

Display detection fails when Nvidia twinview is enabled under linux

Project:The Open Toolkit library
Category:bug report

I have been getting this reported by a few users and have narrowed the issue down to this. When nvidia twinview is enabled, the displaydevices array is empty even though there are 2 valid monitors available. When disabled (and no other changes) everything works fine.

I have attached a diff of the config file showing the changed options that could be effecting things.

config changes.txt1.19 KB


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture


Status:open» need info

Right now, OpenTK requires XRandR to detect available modes through Xinerama and XRandR. Unfortunately, XRandR doesn't work very well when Nvidia/TwinView is enabled. We probably need to fall back to the deprecated XF86VMextension when XRandR fails.

Which OpenTK version are you using? I recall an "empty DisplayDevice array" being fixed on a recent OpenTK version. If possible, try running your program with the debug version of OpenTK.dll and log the output from System.Diagnostics.Debug, which should point to the exact point of failure.

jdomnitz's picture


This is using the latest openTK code (not more the a couple days old). I run the ubuntu 10.10 branch and can't repro the issue so I assume its fixed in the lastest nvidia drivers. Not all of my users will be using the latest branch though, so if theres a way to restore compatibility that would be great. If any users can repro the issue with a debugger and post that would be even better but I could look into implementing xf86 support. Are there any plans or existing code in that department or am I starting from scratch?

the Fiddler's picture


Status:need info» confirmed

The relevant code is in OpenTK/Platform/X11/X11DisplayDevice.cs. We'd need to implement QueryXF86() in a similar fashion to QueryXRandR() (see lines 76, 122 and 199).

The necessary DllImports are already in place as "API.XF86VidMode*" (man 3 xf86vm) so it's mainly a matter of piecing together out how they work.

jdomnitz's picture


Alright I implemented queryxf86...just have to do some testing and then i'll send it your way.

I think I found the actual problem though...it wasn't just an issue with twinview, its an issue with xinerama and twinview. Xinerama query screens returns 0 screens....and the QueryXinerama function still returns true. Can we change the final line from return true to return (devices.Count>0)?

the Fiddler's picture


Aha, yes, please do that.

jdomnitz's picture


Done tested and working:

static bool QueryXF86(List<DisplayDevice> devices)
            int major;
            int minor;
            if (!API.XF86VidModeQueryVersion(API.DefaultDisplay, out major, out minor))
                return false;
				return false;
            int currentScreen = 0;
            Debug.Print("Using XF86 v" + major.ToString() + "." + minor.ToString());
            foreach(DisplayDevice dev in devices)
                int count;
                IntPtr srcArray;
                API.XF86VidModeGetAllModeLines(API.DefaultDisplay, currentScreen, out count, out srcArray);
                Debug.Print(count.ToString()+" modes detected on screen "+currentScreen.ToString());
                IntPtr[] array=new IntPtr[count];
                Marshal.Copy(srcArray, array, 0, count);
                API.XF86VidModeModeInfo Mode = new API.XF86VidModeModeInfo();
                int x;
                int y;
                API.XF86VidModeGetViewPort(API.DefaultDisplay,currentScreen,out x,out y);
				List<OpenMobile.DisplayResolution> resolutions=new List<OpenMobile.DisplayResolution>();
                for(int i=0;i<count;i++)
                    resolutions.Add(new DisplayResolution(x,y,Mode.hdisplay,Mode.vdisplay,24,(Mode.dotclock*1000F)/(Mode.vtotal*Mode.htotal)));
                int pixelClock;
                API.XF86VidModeModeLine currentMode;
                API.XF86VidModeGetModeLine(API.DefaultDisplay,currentScreen,out pixelClock,out currentMode);
                dev.Bounds = new Rectangle(x, y, currentMode.hdisplay, (currentMode.vdisplay==0) ? currentMode.vsyncstart : currentMode.vdisplay);
                dev.BitsPerPixel = FindCurrentDepth(currentScreen);
                dev.RefreshRate = (pixelClock*1000F)/(currentMode.vtotal*currentMode.htotal);
            return true;

Only thing I couldn't get was bit depth for each of the supported resolutions (only was able to get current bit depth).
A few changes were needed to the APIs also... the main one being the dll path was wrong. I changed it to
private const string _dll_name_vid = "libXxf86vm.so.1
but it could be left as is and a DllMap used - its up to you.

and lastly a few new P/Invokes for the API class:

        extern public static bool XF86VidModeGetViewPort(
            Display display,
            int screen,
            out int x_return,
            out int y_return);
        extern public static bool XF86VidModeGetModeLine(
            Display display,
            int screen,
            out int dotclock_return,
            out XF86VidModeModeLine modeline);
jdomnitz's picture


Sorry about the formatting...it looked right when I pasted it in but got screwed up after posting.

the Fiddler's picture


Status:confirmed» in progress (commit)

Thanks, looking good!

the Fiddler's picture


Version:all versions» 1.x-dev
Status:in progress (commit)» fixed

Commited to r2784. Many thanks!

the Fiddler's picture


Version:1.x-dev» 1.1-2014-01-02
Status:fixed» closed

Closing issues fixed in OpenTK 1.1.

If this is still an issue please file a new bug report at https://github.com/opentk/opentk/issues