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)
#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; } }
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()));
}
}
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),
}
}
}
readonly int FD;
- readonly GbmDevice Device;
readonly Dictionary<int, int> DisplayIds =
new Dictionary<int, int>();
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);
}
class LinuxFactory : PlatformFactoryBase
{
int fd;
- GbmDevice gbm_device;
+ IntPtr gbm_device;
IntPtr display;
IJoystickDriver2 JoystickDriver;
}
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");
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()
#endregion
using System;
+using System.Diagnostics;
using System.Drawing;
+using System.Runtime.InteropServices;
using OpenTK.Graphics;
using OpenTK.Platform.Egl;
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()
protected override void Dispose(bool disposing)
{
- // Todo
+ if (disposing)
+ {
+ window.Dispose();
+ Gbm.DestroySurface(window.Handle);
+ }
}
public override Icon Icon
{
get
{
- return window_info;
+ return window;
}
}
{
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.
}
}
}