[KMS] Added new Linux KMS driver
authorthefiddler <stapostol@gmail.com>
Tue, 24 Jun 2014 17:27:38 +0000 (19:27 +0200)
committerthefiddler <stapostol@gmail.com>
Wed, 16 Jul 2014 12:28:27 +0000 (14:28 +0200)
12 files changed:
Source/Examples/Main.cs
Source/OpenTK/OpenTK.csproj
Source/OpenTK/Platform/Factory.cs
Source/OpenTK/Platform/Linux/Bindings/Drm.cs
Source/OpenTK/Platform/Linux/Bindings/Libc.cs [moved from Source/OpenTK/Platform/Linux/Bindings/Linux.cs with 53% similarity]
Source/OpenTK/Platform/Linux/LinuxDisplayDriver.cs [new file with mode: 0644]
Source/OpenTK/Platform/Linux/LinuxFactory.cs
Source/OpenTK/Platform/Linux/LinuxJoystick.cs [moved from Source/OpenTK/Platform/X11/X11Joystick.cs with 75% similarity]
Source/OpenTK/Platform/Linux/LinuxNativeWindow.cs
Source/OpenTK/Platform/Linux/LinuxWindowInfo.cs [new file with mode: 0644]
Source/OpenTK/Platform/X11/X11Input.cs
Source/OpenTK/Platform/X11/XI2Input.cs

index 84dba6d..eb86bd0 100644 (file)
@@ -101,6 +101,15 @@ namespace Examples
         public static void Main(string[] args)
         {
             Trace.Listeners.Add(new ConsoleTraceListener());
+            Tests.GameWindowStates.Main();
+            return;
+
+            using (var gw = new GameWindow())
+            {
+                gw.KeyDown += (sender, e) => gw.Exit();
+                gw.Run(60);
+            }
+            return;
 
             if (args.Length > 0)
             {
index d931c24..794abfa 100644 (file)
     <Compile Include="Platform\X11\X11WindowInfo.cs">
       <SubType>Code</SubType>
     </Compile>
-    <Compile Include="Platform\X11\X11Joystick.cs">
-      <SubType>Code</SubType>
-    </Compile>
     <Compile Include="Platform\X11\Functions.cs">
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="Platform\Linux\Bindings\Drm.cs" />
     <Compile Include="Platform\Linux\LinuxFactory.cs" />
     <Compile Include="Platform\Linux\LinuxNativeWindow.cs" />
-    <Compile Include="Platform\Linux\Bindings\Linux.cs" />
     <Compile Include="Platform\Linux\Bindings\Gbm.cs" />
+    <Compile Include="Platform\Linux\LinuxDisplayDriver.cs" />
+    <Compile Include="Platform\Linux\LinuxJoystick.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Platform\Linux\Bindings\Libc.cs" />
+    <Compile Include="Platform\Linux\LinuxWindowInfo.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
index 9a70184..5cc0bfe 100644 (file)
@@ -53,6 +53,7 @@ namespace OpenTK.Platform
 
             // Create regular platform backend
             if (Configuration.RunningOnSdl2) Default = new SDL2.Sdl2Factory();
+            else if (Configuration.RunningOnLinux) Default = new Linux.LinuxFactory();
             else if (Configuration.RunningOnX11) Default = new X11.X11Factory();
             else if (Configuration.RunningOnWindows) Default = new Windows.WinFactory();
             else if (Configuration.RunningOnMacOS) Default = new MacOS.MacOSFactory();
@@ -70,7 +71,8 @@ namespace OpenTK.Platform
             }
             else if (Egl.Egl.IsSupported)
             {
-                if (Configuration.RunningOnX11) Embedded = new Egl.EglX11PlatformFactory();
+                if (Configuration.RunningOnLinux) Embedded = Default;
+                else if (Configuration.RunningOnX11) Embedded = new Egl.EglX11PlatformFactory();
                 else if (Configuration.RunningOnWindows) Embedded = new Egl.EglWinPlatformFactory();
                 else if (Configuration.RunningOnMacOS) Embedded = new Egl.EglMacPlatformFactory();
                 else Embedded = new UnsupportedPlatform();
index 3f4bddb..7f2bf59 100644 (file)
@@ -36,20 +36,115 @@ namespace OpenTK.Platform.Linux
     {
         const string lib = "libdrm";
 
+        [DllImport(lib, EntryPoint = "drmModeGetCrtc", CallingConvention = CallingConvention.Cdecl)]
+        public static extern IntPtr ModeGetCrtc(int fd, uint crtcId);
+
+        [DllImport(lib, EntryPoint = "drmModeFreeConnector", CallingConvention = CallingConvention.Cdecl)]
+        public static extern void ModeFreeConnector(IntPtr ptr);
+
+        [DllImport(lib, EntryPoint = "drmModeFreeEncoder", CallingConvention = CallingConvention.Cdecl)]
+        public static extern void ModeFreeEncoder(IntPtr ptr);
+
+        [DllImport(lib, EntryPoint = "drmModeGetConnector", CallingConvention = CallingConvention.Cdecl)]
+        public static extern IntPtr ModeGetConnector(int fd, uint connector_id);
+
+        [DllImport(lib, EntryPoint = "drmModeGetEncoder", CallingConvention = CallingConvention.Cdecl)]
+        public static extern IntPtr ModeGetEncoder(int fd, uint encoder_id);
+
         [DllImport(lib, EntryPoint = "drmModeGetResources", CallingConvention = CallingConvention.Cdecl)]
-        static extern IntPtr ModeGetResources(int fd);
+        public static extern IntPtr ModeGetResources(int fd);
+
+        [DllImport(lib, EntryPoint = "drmModeSetCrtc", CallingConvention = CallingConvention.Cdecl)]
+        unsafe public static extern int ModeSetCrtc(int fd, uint crtcId, uint bufferId,
+            uint x, uint y, uint* connectors, int count, ModeInfo* mode);
+    }
+
+    enum ModeConnection : byte
+    {
+        Connected = 1,
+        Disconnected = 2,
+        Unknown = 3
+    }
+
+    enum ModeSubPixel : byte
+    {
+        Unknown = 1,
+        HorizontalRgb = 2,
+        HorizontalBgr = 3,
+        VerticalRgb = 4,
+        VerticalBgr = 5,
+        None = 6
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    unsafe struct ModeConnector
+    {
+        public uint connector_id;
+        public uint encoder_id;
+        public uint connector_type;
+        public uint connector_type_id;
+        public ModeConnection connection;
+        public uint mmWidth, mmHeight;
+        public ModeSubPixel subpixel;
+
+        public int count_modes;
+        public ModeInfo* modes;
+
+        public int count_props;
+        public uint *props;
+        public ulong *prop_values;
+
+        public int count_encoders;
+        public uint *encoders;
+    }
+
+    struct ModeCrtc
+    {
+        public uint crtc_id;
+        public uint buffer_id;
+
+        public uint x, y;
+        public uint width, height;
+        public int mode_valid;
+        public ModeInfo mode;
+
+        public int gamma_size;
+    }
+
+    struct ModeEncoder
+    {
+        public uint encoder_id;
+        public uint encoder_type;
+        public uint crtc_id;
+        public uint possible_crtcs;
+        public uint possible_clones;
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    unsafe struct ModeInfo
+    {
+        public uint clock;
+        public ushort hdisplay, hsync_start, hsync_end, htotal, hskew;
+        public ushort vdisplay, vsync_start, vsync_end, vtotal, vscan;
+
+        public uint vrefresh; // refresh rate * 1000
+
+        public uint flags;
+        public uint type;
+        public fixed sbyte name[32];
     }
 
-    struct ModeRes
+    [StructLayout(LayoutKind.Sequential)]
+    unsafe struct ModeRes
     {
         public int count_fbs;
-        public IntPtr fbs; //uint*
+        public uint* fbs;
         public int count_crtcs;
-        public IntPtr crtcs; //uint*
+        public uint* crtcs;
         public int count_connectors;
-        public IntPtr connectors; //uint*
+        public uint* connectors;
         public int count_encoders;
-        public IntPtr encoders; //uint*
+        public uint* encoders;
         public int min_width, max_width;
         public int min_height, max_height;
     }
 
 using System;
 using System.Runtime.InteropServices;
+using System.Text;
 
 namespace OpenTK.Platform.Linux
 {
-    class Linux
+    class Libc
     {
-        [DllImport("glib", EntryPoint = "open", CallingConvention = CallingConvention.Cdecl)]
-        public static extern int Open(string pathname, OpenFlags flags);
+        const string lib = "libc";
+
+        [DllImport(lib)]
+        public static extern int ioctl(int d, JoystickIoctlCode request, ref int data);
+
+        [DllImport(lib)]
+        public static extern int ioctl(int d, JoystickIoctlCode request, StringBuilder data);
+
+        [DllImport(lib)]
+        public static extern int ioctl(int d, EvdevIoctlCode request, out EvdevInputId data);
+
+        [DllImport(lib)]
+        public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags);
+
+        [DllImport(lib)]
+        public static extern int close(int fd);
+
+        [DllImport(lib)]
+        unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count);
     }
 
     [Flags]
     enum OpenFlags
     {
-        ReadOnly = 0,
-        WriteOnly = 1,
-        ReadWrite = 2,
-        CloseOnExec = 4096
+        ReadOnly = 0x0000,
+        WriteOnly = 0x0001,
+        ReadWrite = 0x0002,
+        NonBlock = 0x0800,
+        CloseOnExec = 0x0080000
+    }
+
+    enum EvdevIoctlCode : uint
+    {
+        Id = ((byte)'E' << 8) | (0x02 << 0) //EVIOCGID, which is _IOR('E', 0x02, struct input_id)
+    }
+
+    [Flags]
+    enum JoystickEventType : byte
+    {
+        Button = 0x01,    // button pressed/released
+        Axis = 0x02,      // joystick moved
+        Init = 0x80       // initial state of device
+    }
+
+    enum JoystickIoctlCode : uint
+    {
+        Version = 0x80046a01,
+        Axes = 0x80016a11,
+        Buttons = 0x80016a12,
+        Name128 = (2u << 30) | (0x6A << 8) | (0x13 << 0) | (128 << 16) //JSIOCGNAME(128), which is _IOC(_IO_READ, 'j', 0x13, len)
     }
 
     [StructLayout(LayoutKind.Sequential)]
@@ -64,5 +104,21 @@ namespace OpenTK.Platform.Linux
         public IntPtr mtime;   /* time of last modification */
         public IntPtr ctime;   /* time of last status change */
     }
+
+    struct EvdevInputId
+    {
+        public ushort BusType;
+        public ushort Vendor;
+        public ushort Product;
+        public ushort Version;
+    }
+
+    struct JoystickEvent
+    {
+        public uint Time;    // (u32) event timestamp in milliseconds
+        public short Value;  // (s16) value
+        public JoystickEventType Type;    // (u8)  event type
+        public byte Number;  // (u8)  axis/button number
+    }
 }
 
diff --git a/Source/OpenTK/Platform/Linux/LinuxDisplayDriver.cs b/Source/OpenTK/Platform/Linux/LinuxDisplayDriver.cs
new file mode 100644 (file)
index 0000000..8feefe4
--- /dev/null
@@ -0,0 +1,282 @@
+#region License
+//
+// LinuxDisplayDriver.cs
+//
+// Author:
+//       Stefanos A. <stapostol@gmail.com>
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using OpenTK;
+using OpenTK.Graphics;
+
+namespace OpenTK.Platform.Linux
+{
+    class LinuxDisplayDriver : DisplayDeviceBase
+    {
+        unsafe class LinuxDisplay
+        {
+            public ModeConnector* Connector;
+            public ModeEncoder* Encoder;
+            public ModeCrtc* Crtc;
+            public ModeInfo Mode
+            {
+                get
+                {
+                    if (Crtc == null)
+                        throw new InvalidOperationException();
+
+                    return Crtc->mode;
+                }
+            }
+            public ModeInfo OriginalMode;
+
+            public int Id
+            {
+                get
+                {
+                    if (Crtc == null)
+                        throw new InvalidOperationException();
+
+                    return (int)Crtc->crtc_id;
+                }
+            }
+
+            public LinuxDisplay(ModeConnector* c, ModeEncoder* e, ModeCrtc* r)
+            {
+                Connector = c;
+                Encoder = e;
+                Crtc = r;
+                OriginalMode = Crtc->mode; // in case we change resolution later on
+            }
+        }
+
+        readonly int FD;
+        readonly GbmDevice Device;
+        readonly Dictionary<int, int> DisplayIds =
+            new Dictionary<int, int>();
+
+        public LinuxDisplayDriver(int fd)
+        {
+            FD = fd;
+            QueryDisplays();
+        }
+
+        void QueryDisplays()
+        {
+            unsafe
+            {
+                lock (this)
+                {
+                    AvailableDevices.Clear();
+                    DisplayIds.Clear();
+
+                    ModeRes* resources = (ModeRes*)Drm.ModeGetResources(FD);
+                    if (resources == null)
+                    {
+                        throw new NotSupportedException("[KMS] DRM ModeGetResources failed");
+                    }
+                    Debug.Print("[KMS] DRM found {0} connectors", resources->count_connectors);
+
+                    // Search for a valid connector
+                    ModeConnector* connector = null;
+                    for (int i = 0; i < resources->count_connectors; i++)
+                    {
+                        connector = (ModeConnector*)Drm.ModeGetConnector(FD,
+                            *(resources->connectors + i));
+                        if (connector != null)
+                        {
+                            if (connector->connection == ModeConnection.Connected &&
+                            connector->count_modes > 0)
+                            {
+                                // Connector found!
+                                AddDisplay(connector);
+                            }
+                            else
+                            {
+                                // This is not the display we are looking for
+                                Drm.ModeFreeConnector((IntPtr)connector);
+                                connector = null;
+                            }
+                        }
+                    }
+
+                    if (AvailableDevices.Count == 0)
+                    {
+                        Debug.Print("[KMS] Failed to find any active displays");
+                    }
+                }
+            }
+        }
+
+        unsafe void AddDisplay(ModeConnector* c)
+        {
+            // Find corresponding encoder
+            ModeEncoder* encoder = null;
+            for (int i = 0; i < c->count_encoders && encoder == null; i++)
+            {
+                ModeEncoder* e = (ModeEncoder*)Drm.ModeGetEncoder(
+                    FD, *(c->encoders + i));
+                if (e != null)
+                {
+                    if (e->encoder_id == c->encoder_id)
+                    {
+                        encoder = e;
+                    }
+                    else
+                    {
+                        Drm.ModeFreeEncoder((IntPtr)e);
+                    }
+                }
+            }
+
+            if (encoder != null)
+            {
+                Debug.Print("[KMS] Encoder {0} found for connector {1}",
+                    encoder->encoder_id, c->connector_id);
+            }
+            else
+            {
+                Debug.Print("[KMS] Failed to find encoder for connector {0}", c->connector_id);
+                return;
+            }
+
+            ModeCrtc* crtc = (ModeCrtc*)Drm.ModeGetCrtc(FD, encoder->crtc_id);
+            if (crtc != null)
+            {
+                Debug.Print("[KMS] CRTC {0} found for encoder {1}",
+                    encoder->crtc_id, encoder->encoder_id);
+            }
+            else
+            {
+                Debug.Print("[KMS] Failed to find crtc {0} for encoder {1}",
+                    encoder->crtc_id, encoder->encoder_id);
+                return;
+            }
+
+            LinuxDisplay display = new LinuxDisplay(c, encoder, crtc);
+            if (!DisplayIds.ContainsKey(display.Id))
+            {
+                DisplayIds.Add(display.Id, AvailableDevices.Count);
+            }
+
+            List<DisplayResolution> modes = new List<DisplayResolution>();
+            for (int i = 0; i < display.Connector->count_modes; i++)
+            {
+                ModeInfo* mode = display.Connector->modes + i;
+                DisplayResolution res = GetDisplayResolution(mode);
+                modes.Add(res);
+            }
+            ModeInfo current_mode = display.Mode;
+            DisplayResolution current = GetDisplayResolution(&current_mode);
+
+            // Note: since we are not running a display manager, we are free
+            // to choose the display layout for multiple displays ourselves.
+            // We choose the simplest layout: displays are laid out side-by-side
+            // from left to right. Primary display is the first display we encounter.
+            System.Drawing.Rectangle bounds =
+                new System.Drawing.Rectangle(
+                    AvailableDevices.Count == 0 ? 0 : AvailableDevices[0].Bounds.Right,
+                    0,
+                    current.Width,
+                    current.Height);
+
+            DisplayDevice device = new DisplayDevice(
+                current,
+                AvailableDevices.Count == 0,
+                modes,
+                bounds,
+                display);
+
+            if (AvailableDevices.Count == 0)
+            {
+                Primary = device;
+            }
+
+            AvailableDevices.Add(device);
+        }
+
+        unsafe static DisplayResolution GetDisplayResolution(ModeInfo* mode)
+        {
+            if (mode == null)
+                throw new ArgumentNullException();
+
+            return new DisplayResolution(
+                0, 0,
+                mode->htotal, mode->vtotal,
+                32, // This is actually part of the framebuffer, not the DisplayResolution
+                mode->vrefresh / 1000.0f);
+        }
+
+        unsafe static ModeInfo* GetModeInfo(LinuxDisplay display, DisplayResolution resolution)
+        {
+            for (int i = 0; i < display.Connector->count_modes; i++)
+            {
+                ModeInfo* mode = display.Connector->modes + i;
+                if (mode != null &&
+                    mode->htotal == resolution.Width &&
+                    mode->vtotal == resolution.Height)
+                {
+                    return mode;
+                }
+            }
+            return null;
+        }
+
+        #region IDisplayDeviceDriver
+
+        public override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
+        {
+            unsafe
+            {
+                LinuxDisplay display = (LinuxDisplay)device.Id;
+                ModeInfo* mode = GetModeInfo(display, resolution);
+                uint connector_id = display.Connector->connector_id;
+                if (mode != null)
+                {
+                    return Drm.ModeSetCrtc(FD, (uint)display.Id, 0, 0, 0,
+                        &connector_id, 1, mode) == 0;
+                }
+                return false;
+            }
+        }
+
+        public override bool TryRestoreResolution(DisplayDevice device)
+        {
+            unsafe
+            {
+                LinuxDisplay display = (LinuxDisplay)device.Id;
+                uint connector_id = display.Connector->connector_id;
+                ModeInfo mode = display.OriginalMode;
+                return Drm.ModeSetCrtc(FD, (uint)display.Id, 0, 0, 0,
+                    &connector_id, 1, &mode) == 0;
+            }
+        }
+
+        #endregion
+    }
+}
+
index f998a07..f8b1096 100644 (file)
@@ -32,70 +32,93 @@ using System.Diagnostics;
 using System.Runtime.InteropServices;
 using OpenTK.Graphics;
 using OpenTK.Input;
+using OpenTK.Platform.Egl;
 
 namespace OpenTK.Platform.Linux
 {
+    using Egl = OpenTK.Platform.Egl.Egl;
+
     // Linux KMS platform
     class LinuxFactory : PlatformFactoryBase
     {
         int fd;
-        GbmDevice device;
+        GbmDevice gbm_device;
         IntPtr display;
 
+        IJoystickDriver2 JoystickDriver;
+        IDisplayDeviceDriver DisplayDriver;
+
         public LinuxFactory()
         {
+            SetupEgl();
+        }
+
+        #region Private Members
+
+        void SetupEgl()
+        {
             // Todo: support multi-GPU systems
             string gpu = "/dev/dri/card0";
-            fd = Linux.Open(gpu, OpenFlags.ReadOnly | OpenFlags.CloseOnExec);
+            fd = Libc.open(gpu, OpenFlags.ReadWrite | OpenFlags.CloseOnExec);
             if (fd < 0)
             {
-                throw new NotSupportedException("No KMS-capable GPU available");
+                throw new NotSupportedException("[KMS] No KMS-capable GPU available");
             }
-            Debug.Print("GPU {0} opened as fd:{1}", gpu, fd);
+            Debug.Print("[KMS] GPU '{0}' opened as fd:{1}", gpu, fd);
 
             IntPtr dev = Gbm.CreateDevice(fd);
             if (dev == IntPtr.Zero)
             {
-                throw new NotSupportedException("Failed to create GBM device");
+                throw new NotSupportedException("[KMS] Failed to create GBM device");
             }
-            device = (GbmDevice)Marshal.PtrToStructure(dev, typeof(GbmDevice));
-            Debug.Print("GBM {0:x} '{1}' created successfully",
-                dev, Marshal.PtrToStringAnsi(device.name));
+            gbm_device = (GbmDevice)Marshal.PtrToStructure(dev, typeof(GbmDevice));
+            Debug.Print("[KMS] GBM {0:x} created successfully", dev);
 
-            display = Egl.Egl.GetDisplay(dev);
+            display = Egl.GetDisplay(dev);
             if (display == IntPtr.Zero)
             {
-                throw new NotSupportedException("Failed to create EGL display");
+                throw new NotSupportedException("[KMS] Failed to create EGL display");
             }
-            Debug.Print("EGL display {0:x} created successfully", display);
+            Debug.Print("[KMS] EGL display {0:x} created successfully", display);
 
             int major, minor;
-            if (!Egl.Egl.Initialize(display, out major, out minor))
+            if (!Egl.Initialize(display, out major, out minor))
             {
-                int error = Egl.Egl.GetError();
-                throw new NotSupportedException("Failed to initialize EGL display. Error code: " + error);
+                int error = Egl.GetError();
+                throw new NotSupportedException("[KMS] Failed to initialize EGL display. Error code: " + error);
             }
-            Debug.Print("EGL {0}.{1} initialized successfully on display {2:x}", major, minor, display);
+            Debug.Print("[KMS] EGL {0}.{1} initialized successfully on display {2:x}", major, minor, display);
         }
 
-        public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
+        #endregion
+
+        #region IPlatformFactory Members
+
+        public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice display_device)
         {
-            return new LinuxNativeWindow(x, y, width, height, title, mode, options, device);
+            return new LinuxNativeWindow(display, gbm_device, width, height, title, mode, options, display_device);
         }
 
         public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
         {
-            throw new NotImplementedException();
+            lock (this)
+            {
+                DisplayDriver = DisplayDriver ?? new LinuxDisplayDriver(fd);
+                return DisplayDriver;
+            }
         }
 
         public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
         {
-            throw new NotImplementedException();
+            return new EglUnixContext(mode, (EglWindowInfo)window, shareContext, major, minor, flags);
         }
 
         public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
         {
-            throw new NotImplementedException();
+            return (GraphicsContext.GetCurrentContextDelegate)delegate
+            {
+                return new ContextHandle(Egl.GetCurrentContext());
+            };
         }
 
         public override IKeyboardDriver2 CreateKeyboardDriver()
@@ -110,8 +133,14 @@ namespace OpenTK.Platform.Linux
 
         public override IJoystickDriver2 CreateJoystickDriver()
         {
-            throw new NotImplementedException();
+            lock (this)
+            {
+                JoystickDriver = JoystickDriver ?? new LinuxJoystick();
+                return JoystickDriver;
+            }
         }
+
+        #endregion
     }
 }
 
similarity index 75%
rename from Source/OpenTK/Platform/X11/X11Joystick.cs
rename to Source/OpenTK/Platform/Linux/LinuxJoystick.cs
index 4b3fdc8..5199279 100644 (file)
@@ -33,9 +33,9 @@ using System.Runtime.InteropServices;
 using System.Text;
 using OpenTK.Input;
 
-namespace OpenTK.Platform.X11
+namespace OpenTK.Platform.Linux
 {
-    struct X11JoyDetails
+    struct LinuxJoyDetails
     {
         public Guid Guid;
         public int FileDescriptor;
@@ -43,7 +43,7 @@ namespace OpenTK.Platform.X11
     }
 
     // Note: despite what the name says, this class is Linux-specific.
-    sealed class X11Joystick : IJoystickDriver2
+    sealed class LinuxJoystick : IJoystickDriver2
     {
         #region Fields
 
@@ -52,7 +52,7 @@ namespace OpenTK.Platform.X11
         readonly FileSystemWatcher watcher = new FileSystemWatcher();
 
         readonly Dictionary<int, int> index_to_stick = new Dictionary<int, int>();
-        List<JoystickDevice<X11JoyDetails>> sticks = new List<JoystickDevice<X11JoyDetails>>();
+        List<JoystickDevice<LinuxJoyDetails>> sticks = new List<JoystickDevice<LinuxJoyDetails>>();
 
         bool disposed;
 
@@ -60,7 +60,7 @@ namespace OpenTK.Platform.X11
 
         #region Constructors
 
-        public X11Joystick()
+        public LinuxJoystick()
         {
             string path =
                 Directory.Exists(JoystickPath) ? JoystickPath :
@@ -89,7 +89,7 @@ namespace OpenTK.Platform.X11
             {
                 foreach (string file in Directory.GetFiles(path))
                 {
-                    JoystickDevice<X11JoyDetails> stick = OpenJoystick(file);
+                    JoystickDevice<LinuxJoyDetails> stick = OpenJoystick(file);
                     if (stick != null)
                     {
                         //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
@@ -155,7 +155,7 @@ namespace OpenTK.Platform.X11
 
         #region Private Members
 
-        Guid CreateGuid(JoystickDevice<X11JoyDetails> js, string path, int number)
+        Guid CreateGuid(JoystickDevice<LinuxJoyDetails> js, string path, int number)
         {
             byte[] bytes = new byte[16];
             for (int i = 0; i < Math.Min(bytes.Length, js.Description.Length); i++)
@@ -221,9 +221,9 @@ namespace OpenTK.Platform.X11
 #endif
         }
         
-        JoystickDevice<X11JoyDetails> OpenJoystick(string path)
+        JoystickDevice<LinuxJoyDetails> OpenJoystick(string path)
         {
-            JoystickDevice<X11JoyDetails> stick = null;
+            JoystickDevice<LinuxJoyDetails> stick = null;
 
             int number = GetJoystickNumber(Path.GetFileName(path));
             if (number >= 0)
@@ -231,28 +231,28 @@ namespace OpenTK.Platform.X11
                 int fd = -1;
                 try
                 {
-                    fd = UnsafeNativeMethods.open(path, OpenFlags.NonBlock);
+                    fd = Libc.open(path, OpenFlags.NonBlock);
                     if (fd == -1)
                         return null;
 
                     // Check joystick driver version (must be 1.0+)
                     int driver_version = 0x00000800;
-                    UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Version, ref driver_version);
+                    Libc.ioctl(fd, JoystickIoctlCode.Version, ref driver_version);
                     if (driver_version < 0x00010000)
                         return null;
 
                     // Get number of joystick axes
                     int axes = 0;
-                    UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Axes, ref axes);
+                    Libc.ioctl(fd, JoystickIoctlCode.Axes, ref axes);
 
                     // Get number of joystick buttons
                     int buttons = 0;
-                    UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
+                    Libc.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
 
-                    stick = new JoystickDevice<X11JoyDetails>(number, axes, buttons);
+                    stick = new JoystickDevice<LinuxJoyDetails>(number, axes, buttons);
 
                     StringBuilder sb = new StringBuilder(128);
-                    UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Name128, sb);
+                    Libc.ioctl(fd, JoystickIoctlCode.Name128, sb);
                     stick.Description = sb.ToString();
 
                     stick.Details.FileDescriptor = fd;
@@ -287,16 +287,16 @@ namespace OpenTK.Platform.X11
                 finally
                 {
                     if (stick == null && fd != -1)
-                        UnsafeNativeMethods.close(fd);
+                        Libc.close(fd);
                 }
             }
 
             return stick;
         }
 
-        void CloseJoystick(JoystickDevice<X11JoyDetails> js)
+        void CloseJoystick(JoystickDevice<LinuxJoyDetails> js)
         {
-            UnsafeNativeMethods.close(js.Details.FileDescriptor);
+            Libc.close(js.Details.FileDescriptor);
             js.Details.State = new JoystickState(); // clear joystick state
             js.Details.FileDescriptor = -1;
             
@@ -317,13 +317,13 @@ namespace OpenTK.Platform.X11
             }
         }
 
-        void PollJoystick(JoystickDevice<X11JoyDetails> js)
+        void PollJoystick(JoystickDevice<LinuxJoyDetails> js)
         {
             JoystickEvent e;
 
             unsafe
             {
-                while ((long)UnsafeNativeMethods.read(js.Details.FileDescriptor, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
+                while ((long)Libc.read(js.Details.FileDescriptor, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
                 {
                     e.Type &= ~JoystickEventType.Init;
 
@@ -352,78 +352,9 @@ namespace OpenTK.Platform.X11
             return index_to_stick.ContainsKey(index);
         }
 
-        #region UnsafeNativeMethods
-
-        struct EvdevInputId
-        {
-            public ushort BusType;
-            public ushort Vendor;
-            public ushort Product;
-            public ushort Version;
-        }
-
-        enum EvdevIoctlCode : uint
-        {
-            Id = ((byte)'E' << 8) | (0x02 << 0) //EVIOCGID, which is _IOR('E', 0x02, struct input_id)
-        }
-
-        struct JoystickEvent
-        {
-            public uint Time;    // (u32) event timestamp in milliseconds
-            public short Value;  // (s16) value
-            public JoystickEventType Type;    // (u8)  event type
-            public byte Number;  // (u8)  axis/button number
-        }
-
-        [Flags]
-        enum JoystickEventType : byte
-        {
-            Button = 0x01,    // button pressed/released
-            Axis = 0x02,      // joystick moved
-            Init = 0x80       // initial state of device
-        }
-
-        enum JoystickIoctlCode : uint
-        {
-            Version = 0x80046a01,
-            Axes = 0x80016a11,
-            Buttons = 0x80016a12,
-            Name128 = (2u << 30) | (0x6A << 8) | (0x13 << 0) | (128 << 16) //JSIOCGNAME(128), which is _IOC(_IO_READ, 'j', 0x13, len)
-        }
-
         static readonly string JoystickPath = "/dev/input";
         static readonly string JoystickPathLegacy = "/dev";
 
-        [Flags]
-        enum OpenFlags
-        {
-            NonBlock = 0x00000800
-        }
-
-        static class UnsafeNativeMethods
-        {
-            [DllImport("libc", SetLastError = true)]
-            public static extern int ioctl(int d, JoystickIoctlCode request, ref int data);
-
-            [DllImport("libc", SetLastError = true)]
-            public static extern int ioctl(int d, JoystickIoctlCode request, StringBuilder data);
-
-            [DllImport("libc", SetLastError = true)]
-            public static extern int ioctl(int d, EvdevIoctlCode request, out EvdevInputId data);
-
-            [DllImport("libc", SetLastError = true)]
-            public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags);
-
-            [DllImport("libc", SetLastError = true)]
-            public static extern int close(int fd);
-
-            [DllImport("libc", SetLastError = true)]
-            unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count);
-        }
-
-        #endregion
-
         #endregion
 
         #region IDisposable Members
@@ -443,7 +374,7 @@ namespace OpenTK.Platform.X11
                 }
 
                 watcher.Dispose();
-                foreach (JoystickDevice<X11JoyDetails> js in sticks)
+                foreach (JoystickDevice<LinuxJoyDetails> js in sticks)
                 {
                     CloseJoystick(js);
                 }
@@ -452,7 +383,7 @@ namespace OpenTK.Platform.X11
             }
         }
 
-        ~X11Joystick()
+        ~LinuxJoystick()
         {
             Dispose(false);
         }
@@ -465,7 +396,7 @@ namespace OpenTK.Platform.X11
         {
             if (IsValid(index))
             {
-                JoystickDevice<X11JoyDetails> js = 
+                JoystickDevice<LinuxJoyDetails> js = 
                     sticks[index_to_stick[index]];
                 PollJoystick(js);
                 return js.Details.State;
@@ -478,7 +409,7 @@ namespace OpenTK.Platform.X11
             JoystickCapabilities caps = new JoystickCapabilities();
             if (IsValid(index))
             {
-                JoystickDevice<X11JoyDetails> js = sticks[index_to_stick[index]];
+                JoystickDevice<LinuxJoyDetails> js = sticks[index_to_stick[index]];
                 caps = new JoystickCapabilities(
                     js.Axis.Count,
                     js.Button.Count,
@@ -492,7 +423,7 @@ namespace OpenTK.Platform.X11
         {
             if (IsValid(index))
             {
-                JoystickDevice<X11JoyDetails> js = sticks[index_to_stick[index]];
+                JoystickDevice<LinuxJoyDetails> js = sticks[index_to_stick[index]];
                 return js.Details.Guid; 
             }
             return new Guid();
index a44cb9b..6d92692 100644 (file)
 #endregion
 
 using System;
+using System.Drawing;
+using OpenTK.Graphics;
+using OpenTK.Platform.Egl;
 
 namespace OpenTK.Platform.Linux
 {
+    using Egl = OpenTK.Platform.Egl.Egl;
+
     class LinuxNativeWindow : NativeWindowBase
     {
+        LinuxWindowInfo window_info;
+        string title;
+        Icon icon;
+        bool exists;
+        Rectangle bounds;
+        Size client_size;
+
+        public LinuxNativeWindow(IntPtr display, GbmDevice device,
+            int width, int height, string title, GraphicsMode mode, GameWindowFlags options,
+            DisplayDevice display_device)
+        {
+            Title = title;
+            bounds = new Rectangle(0, 0, width, height);
+            client_size = bounds.Size;
+
+            //window_info = new LinuxWindowInfo(
+                //    Egl.CreateWindowSurface(
+
+            exists = true;
+        }
+
         #region INativeWindow Members
 
         public override void Close()
         {
-            throw new NotImplementedException();
+            exists = false;
         }
 
-        public override System.Drawing.Point PointToClient(System.Drawing.Point point)
+        public override Point PointToClient(Point point)
         {
-            throw new NotImplementedException();
+            // Todo
+            return point;
         }
 
-        public override System.Drawing.Point PointToScreen(System.Drawing.Point point)
+        public override Point PointToScreen(Point point)
         {
-            throw new NotImplementedException();
+            // Todo
+            return point;
         }
 
         protected override void Dispose(bool disposing)
         {
-            throw new NotImplementedException();
+            // Todo
         }
 
-        public override System.Drawing.Icon Icon
+        public override Icon Icon
         {
             get
             {
-                throw new NotImplementedException();
+                return icon;
             }
             set
             {
-                throw new NotImplementedException();
+                if (icon != value)
+                {
+                    icon = value;
+                    OnIconChanged(EventArgs.Empty);
+                }
             }
         }
 
@@ -71,11 +103,15 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return title;
             }
             set
             {
-                throw new NotImplementedException();
+                if (title != value)
+                {
+                    title = value;
+                    OnTitleChanged(EventArgs.Empty);
+                }
             }
         }
 
@@ -83,7 +119,7 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return true;
             }
         }
 
@@ -91,11 +127,10 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return true;
             }
             set
             {
-                throw new NotImplementedException();
             }
         }
 
@@ -103,7 +138,7 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return exists;
             }
         }
 
@@ -111,7 +146,7 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return window_info;
             }
         }
 
@@ -119,11 +154,10 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return WindowState.Fullscreen;
             }
             set
             {
-                throw new NotImplementedException();
             }
         }
 
@@ -131,35 +165,32 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return WindowBorder.Hidden;
             }
             set
             {
-                throw new NotImplementedException();
             }
         }
 
-        public override System.Drawing.Rectangle Bounds
+        public override Rectangle Bounds
         {
             get
             {
-                throw new NotImplementedException();
+                return bounds;
             }
             set
             {
-                throw new NotImplementedException();
             }
         }
 
-        public override System.Drawing.Size ClientSize
+        public override Size ClientSize
         {
             get
             {
-                throw new NotImplementedException();
+                return client_size;
             }
             set
             {
-                throw new NotImplementedException();
             }
         }
 
@@ -167,11 +198,10 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return false;
             }
             set
             {
-                throw new NotImplementedException();
             }
         }
 
@@ -179,18 +209,14 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                throw new NotImplementedException();
+                return MouseCursor.Empty;
             }
             set
             {
-                throw new NotImplementedException();
             }
         }
 
         #endregion
-
-
-
     }
 }
 
diff --git a/Source/OpenTK/Platform/Linux/LinuxWindowInfo.cs b/Source/OpenTK/Platform/Linux/LinuxWindowInfo.cs
new file mode 100644 (file)
index 0000000..df56428
--- /dev/null
@@ -0,0 +1,43 @@
+#region License
+//
+// LinuxWindowInfo.cs
+//
+// Author:
+//       Stefanos A. <stapostol@gmail.com>
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+#endregion
+
+using System;
+using OpenTK.Platform.Egl;
+
+namespace OpenTK.Platform.Linux
+{
+    class LinuxWindowInfo : EglWindowInfo
+    {
+        public LinuxWindowInfo(IntPtr handle, IntPtr display, IntPtr surface)
+            : base(handle, display, surface)
+        {
+        }
+    }
+}
+
index 50bdf4a..246501c 100644 (file)
@@ -37,7 +37,7 @@ namespace OpenTK.Platform.X11
     {
         readonly X11Mouse mouse = new X11Mouse();
         readonly X11Keyboard keyboard = new X11Keyboard();
-        readonly X11Joystick joystick = new X11Joystick();
+        readonly Linux.LinuxJoystick joystick = new Linux.LinuxJoystick();
         readonly IGamePadDriver gamepad = new MappedGamePadDriver();
 
         internal X11Input()
index c2e8528..d91d2c0 100644 (file)
@@ -36,7 +36,7 @@ namespace OpenTK.Platform.X11
     class XI2Input : IInputDriver2
     {
         readonly XI2MouseKeyboard mouse_keyboard = new XI2MouseKeyboard();
-        readonly X11Joystick joystick = new X11Joystick();
+        readonly Linux.LinuxJoystick joystick = new Linux.LinuxJoystick();
         readonly IGamePadDriver gamepad = new MappedGamePadDriver();
 
         internal XI2Input()