[KMS] Create window surface
authorthefiddler <stapostol@gmail.com>
Wed, 25 Jun 2014 07:01:35 +0000 (09:01 +0200)
committerthefiddler <stapostol@gmail.com>
Wed, 16 Jul 2014 12:28:27 +0000 (14:28 +0200)
Source/OpenTK/Platform/Egl/EglGraphicsMode.cs
Source/OpenTK/Platform/Egl/EglWindowInfo.cs
Source/OpenTK/Platform/Linux/Bindings/Gbm.cs
Source/OpenTK/Platform/Linux/LinuxDisplayDriver.cs
Source/OpenTK/Platform/Linux/LinuxFactory.cs
Source/OpenTK/Platform/Linux/LinuxNativeWindow.cs
Source/OpenTK/Platform/Linux/LinuxWindowInfo.cs

index bc78bc8..779e8ff 100644 (file)
@@ -35,6 +35,15 @@ namespace OpenTK.Platform.Egl
     class EglGraphicsMode
     {
         public GraphicsMode SelectGraphicsMode(EglWindowInfo window,
+            GraphicsMode mode, RenderableFlags flags)
+        {
+            return SelectGraphicsMode(window,
+                mode.ColorFormat, mode.Depth, mode.Stencil,
+                mode.Samples, mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
+                flags);
+        }
+
+        public GraphicsMode SelectGraphicsMode(EglWindowInfo window,
             ColorFormat color, int depth, int stencil,
             int samples, ColorFormat accum, int buffers, bool stereo,
             RenderableFlags renderable_flags)
index db9acb4..4d0e194 100644 (file)
@@ -75,7 +75,7 @@ namespace OpenTK.Platform.Egl
 
         #region Public Members
 
-        public IntPtr Handle { get { return handle; } private set { handle = value; } }
+        public IntPtr Handle { get { return handle; } set { handle = value; } }
 
         public IntPtr Display { get { return display; } private set { display = value; } }
 
@@ -87,7 +87,7 @@ namespace OpenTK.Platform.Egl
                        if (Surface==IntPtr.Zero)
                        {
                 throw new GraphicsContextException(String.Format(
-                                       "[Error] Failed to create EGL window surface, error {0}.", Egl.GetError()));
+                    "[EGL] Failed to create window surface, error {0}.", Egl.GetError()));
                        }
         }
 
index 6ca1e6b..9225e44 100644 (file)
@@ -32,21 +32,111 @@ using System.Runtime.InteropServices;
 
 namespace OpenTK.Platform.Linux
 {
+    using GbmDevice = IntPtr; // opaque pointer "struct gbm_device*"
+
     class Gbm
     {
         const string lib = "gbm";
 
         [DllImport(lib, EntryPoint = "gbm_create_device", CallingConvention = CallingConvention.Cdecl)]
-        public static extern IntPtr CreateDevice(int fd);
+        public static extern GbmDevice CreateDevice(int fd);
+
+        [DllImport(lib, EntryPoint = "gbm_surface_create", CallingConvention = CallingConvention.Cdecl)]
+        public static extern IntPtr CreateSurface(GbmDevice gbm, int width, int height, SurfaceFormat format, SurfaceFlags flags);
+
+        [DllImport(lib, EntryPoint = "gbm_surface_destroy", CallingConvention = CallingConvention.Cdecl)]
+        public static extern void DestroySurface(IntPtr surface);
+
+        [DllImport(lib, EntryPoint = "gbm_device_is_format_supported", CallingConvention = CallingConvention.Cdecl)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool IsFormatSupported(GbmDevice gbm, SurfaceFormat format, SurfaceFlags usage);
+    }
+
+    enum SurfaceFormat
+    {
+        BigEndian = 1 << 31,
+        C8 = ((int)('C') | ((int)('8') << 8) | ((int)(' ') << 16) | ((int)(' ') << 24)),
+
+        RGB332 = ((int)('R') | ((int)('G') << 8) | ((int)('B') << 16) | ((int)('8') << 24)),
+        BGR233 = ((int)('B') | ((int)('G') << 8) | ((int)('R') << 16) | ((int)('8') << 24)),
+
+        XRGB4444 = ((int)('X') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        XBGR4444 = ((int)('X') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        RGBX4444 = ((int)('R') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        BGRX4444 = ((int)('B') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+
+        ARGB4444 = ((int)('A') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        ABGR4444 = ((int)('A') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        RGBA4444 = ((int)('R') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        BGRA4444 = ((int)('B') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+
+        XRGB1555 = ((int)('X') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
+        XBGR1555 = ((int)('X') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
+        RGBX5551 = ((int)('R') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
+        BGRX5551 = ((int)('B') | ((int)('X') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
+
+        ARGB1555 = ((int)('A') | ((int)('R') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
+        ABGR1555 = ((int)('A') | ((int)('B') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
+        RGBA5551 = ((int)('R') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
+        BGRA5551 = ((int)('B') | ((int)('A') << 8) | ((int)('1') << 16) | ((int)('5') << 24)),
+
+        RGB565 = ((int)('R') | ((int)('G') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
+        BGR565 = ((int)('B') | ((int)('G') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
+
+        RGB888 = ((int)('R') | ((int)('G') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+        BGR888 = ((int)('B') | ((int)('G') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+
+        XRGB8888 = ((int)('X') | ((int)('R') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+        XBGR8888 = ((int)('X') | ((int)('B') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+        RGBX8888 = ((int)('R') | ((int)('X') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+        BGRX8888 = ((int)('B') | ((int)('X') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+
+        ARGB8888 = ((int)('A') | ((int)('R') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+        ABGR8888 = ((int)('A') | ((int)('B') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+        RGBA8888 = ((int)('R') | ((int)('A') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+        BGRA8888 = ((int)('B') | ((int)('A') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+
+        XRGB2101010 = ((int)('X') | ((int)('R') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
+        XBGR2101010 = ((int)('X') | ((int)('B') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
+        RGBX1010102 = ((int)('R') | ((int)('X') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
+        BGRX1010102 = ((int)('B') | ((int)('X') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
+
+        ARGB2101010 = ((int)('A') | ((int)('R') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
+        ABGR2101010 = ((int)('A') | ((int)('B') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
+        RGBA1010102 = ((int)('R') | ((int)('A') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
+        BGRA1010102 = ((int)('B') | ((int)('A') << 8) | ((int)('3') << 16) | ((int)('0') << 24)),
+
+        YUYV = ((int)('Y') | ((int)('U') << 8) | ((int)('Y') << 16) | ((int)('V') << 24)),
+        YVYU = ((int)('Y') | ((int)('V') << 8) | ((int)('Y') << 16) | ((int)('U') << 24)),
+        UYVY = ((int)('U') | ((int)('Y') << 8) | ((int)('V') << 16) | ((int)('Y') << 24)),
+        VYUY = ((int)('V') | ((int)('Y') << 8) | ((int)('U') << 16) | ((int)('Y') << 24)),
+
+        AYUV = ((int)('A') | ((int)('Y') << 8) | ((int)('U') << 16) | ((int)('V') << 24)),
+
+        NV12 = ((int)('N') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        NV21 = ((int)('N') | ((int)('V') << 8) | ((int)('2') << 16) | ((int)('1') << 24)),
+        NV16 = ((int)('N') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
+        NV61 = ((int)('N') | ((int)('V') << 8) | ((int)('6') << 16) | ((int)('1') << 24)),
+
+        YUV410 = ((int)('Y') | ((int)('U') << 8) | ((int)('V') << 16) | ((int)('9') << 24)),
+        YVU410 = ((int)('Y') | ((int)('V') << 8) | ((int)('U') << 16) | ((int)('9') << 24)),
+        YUV411 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('1') << 24)),
+        YVU411 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('1') << 24)),
+        YUV420 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        YVU420 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('2') << 24)),
+        YUV422 = ((int)('Y') | ((int)('U') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
+        YVU422 = ((int)('Y') | ((int)('V') << 8) | ((int)('1') << 16) | ((int)('6') << 24)),
+        YUV444 = ((int)('Y') | ((int)('U') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
+        YVU444 = ((int)('Y') | ((int)('V') << 8) | ((int)('2') << 16) | ((int)('4') << 24)),
     }
 
-    struct GbmDevice
+    [Flags]
+    enum SurfaceFlags
     {
-        public int id;
-        public int fd;
-        public IntPtr name;
-        public int refcount;
-        public Stat stat;
+        Scanout = (1 << 0),
+        Cursor64x64 = (1 << 1),
+        Rendering = (1 << 2),
+        Write = (1 << 3),
     }
 }
 
index 8feefe4..a12fd06 100644 (file)
@@ -75,7 +75,6 @@ namespace OpenTK.Platform.Linux
         }
 
         readonly int FD;
-        readonly GbmDevice Device;
         readonly Dictionary<int, int> DisplayIds =
             new Dictionary<int, int>();
 
@@ -203,19 +202,16 @@ namespace OpenTK.Platform.Linux
                     0,
                     current.Width,
                     current.Height);
-
-            DisplayDevice device = new DisplayDevice(
-                current,
-                AvailableDevices.Count == 0,
-                modes,
-                bounds,
-                display);
+            bool is_primary = AvailableDevices.Count == 0;
+            DisplayDevice device = new DisplayDevice(current, is_primary,
+                modes, bounds, display);
 
             if (AvailableDevices.Count == 0)
             {
                 Primary = device;
             }
 
+            Debug.Print("[KMS] Detected display {0}", device);
             AvailableDevices.Add(device);
         }
 
index f8b1096..2c962ed 100644 (file)
@@ -42,7 +42,7 @@ namespace OpenTK.Platform.Linux
     class LinuxFactory : PlatformFactoryBase
     {
         int fd;
-        GbmDevice gbm_device;
+        IntPtr gbm_device;
         IntPtr display;
 
         IJoystickDriver2 JoystickDriver;
@@ -66,15 +66,14 @@ namespace OpenTK.Platform.Linux
             }
             Debug.Print("[KMS] GPU '{0}' opened as fd:{1}", gpu, fd);
 
-            IntPtr dev = Gbm.CreateDevice(fd);
-            if (dev == IntPtr.Zero)
+            gbm_device = Gbm.CreateDevice(fd);
+            if (gbm_device == IntPtr.Zero)
             {
                 throw new NotSupportedException("[KMS] Failed to create GBM device");
             }
-            gbm_device = (GbmDevice)Marshal.PtrToStructure(dev, typeof(GbmDevice));
-            Debug.Print("[KMS] GBM {0:x} created successfully", dev);
+            Debug.Print("[KMS] GBM {0:x} created successfully; ", gbm_device);
 
-            display = Egl.GetDisplay(dev);
+            display = Egl.GetDisplay(gbm_device);
             if (display == IntPtr.Zero)
             {
                 throw new NotSupportedException("[KMS] Failed to create EGL display");
@@ -96,7 +95,7 @@ namespace OpenTK.Platform.Linux
 
         public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice display_device)
         {
-            return new LinuxNativeWindow(display, gbm_device, width, height, title, mode, options, display_device);
+            return new LinuxNativeWindow(display, gbm_device, x, y, width, height, title, mode, options, display_device);
         }
 
         public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
index 6d92692..5c0da51 100644 (file)
@@ -28,7 +28,9 @@
 #endregion
 
 using System;
+using System.Diagnostics;
 using System.Drawing;
+using System.Runtime.InteropServices;
 using OpenTK.Graphics;
 using OpenTK.Platform.Egl;
 
@@ -38,27 +40,89 @@ namespace OpenTK.Platform.Linux
 
     class LinuxNativeWindow : NativeWindowBase
     {
-        LinuxWindowInfo window_info;
+        LinuxWindowInfo window;
         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,
+        public LinuxNativeWindow(IntPtr display, IntPtr gbm,
+            int x, int y, int width, int height, string title,
+            GraphicsMode mode, GameWindowFlags options,
             DisplayDevice display_device)
         {
+            Debug.Print("[KMS] Creating window on display {0:x}", display);
+
             Title = title;
             bounds = new Rectangle(0, 0, width, height);
             client_size = bounds.Size;
 
-            //window_info = new LinuxWindowInfo(
-                //    Egl.CreateWindowSurface(
+            window = new LinuxWindowInfo(display);
+            if (!mode.Index.HasValue)
+            {
+                mode = new EglGraphicsMode().SelectGraphicsMode(window, mode, 0);
+            }
+            Debug.Print("[KMS] Selected EGL mode {0}", mode);
 
+            unsafe
+            {
+                SurfaceFormat format = GetSurfaceFormat(mode);
+                SurfaceFlags usage = SurfaceFlags.Rendering | SurfaceFlags.Scanout;
+                if (!Gbm.IsFormatSupported(gbm, format, usage))
+                {
+                    format = SurfaceFormat.XBGR8888;
+                }
+
+                Debug.Print("[KMS] Creating GBM surface on {0:x} with {1}x{2} {3} {4}",
+                    gbm, width, height, format, usage);
+                IntPtr gbm_surface =  Gbm.CreateSurface(gbm,
+                        width, height, format, usage);
+                if (gbm_surface == IntPtr.Zero)
+                {
+                    throw new NotSupportedException("[KMS] Failed to create GBM surface for rendering");
+                }
+
+                window.Handle = gbm_surface;
+                Debug.Print("[KMS] Created GBM surface {0:x}", window.Handle);
+            }
+
+            window.CreateWindowSurface(mode.Index.Value);
+            Debug.Print("[KMS] Created EGL surface {0:x}", window.Surface);
+
+            // Todo: create mouse cursor
             exists = true;
         }
 
+        SurfaceFormat GetSurfaceFormat(GraphicsMode mode)
+        {
+            int r = mode.ColorFormat.Red;
+            int g = mode.ColorFormat.Green;
+            int b = mode.ColorFormat.Blue;
+            int a = mode.ColorFormat.Alpha;
+
+            if (mode.ColorFormat.IsIndexed)
+                return SurfaceFormat.C8;
+            if (r == 3 && g == 3 && b == 2 && a == 0)
+                return SurfaceFormat.RGB332;
+            if (r == 5 && g == 6 && b == 5 && a == 0)
+                return SurfaceFormat.RGB565;
+            if (r == 5 && g == 6 && b == 5 && a == 0)
+                return SurfaceFormat.RGB565;
+            if (r == 8 && g == 8 && b == 8 && a == 0)
+                return SurfaceFormat.RGB888;
+            if (r == 5 && g == 5 && b == 5 && a == 1)
+                return SurfaceFormat.RGBA5551;
+            if (r == 10 && g == 10 && b == 10 && a == 2)
+                return SurfaceFormat.RGBA1010102;
+            if (r == 4 && g == 4 && b == 4 && a == 4)
+                return SurfaceFormat.RGBA4444;
+            if (r == 8 && g == 8 && b == 8 && a == 8)
+                return SurfaceFormat.RGBA8888;
+
+            return SurfaceFormat.RGBA8888;
+        }
+
         #region INativeWindow Members
 
         public override void Close()
@@ -80,7 +144,11 @@ namespace OpenTK.Platform.Linux
 
         protected override void Dispose(bool disposing)
         {
-            // Todo
+            if (disposing)
+            {
+                window.Dispose();
+                Gbm.DestroySurface(window.Handle);
+            }
         }
 
         public override Icon Icon
@@ -146,7 +214,7 @@ namespace OpenTK.Platform.Linux
         {
             get
             {
-                return window_info;
+                return window;
             }
         }
 
index df56428..0a1f093 100644 (file)
@@ -34,9 +34,11 @@ namespace OpenTK.Platform.Linux
 {
     class LinuxWindowInfo : EglWindowInfo
     {
-        public LinuxWindowInfo(IntPtr handle, IntPtr display, IntPtr surface)
-            : base(handle, display, surface)
+        public LinuxWindowInfo(IntPtr display)
+            : base(IntPtr.Zero, display, IntPtr.Zero)
         {
+            // The window handle and surface handle must
+            // be filled in manually once they are known.
         }
     }
 }