Opentk/Source/OpenTK/Platform/Linux/LinuxNativeWindow.cs

320 lines
8.8 KiB
C#
Raw Normal View History

2014-06-23 20:22:04 +00:00
#region License
//
// LinuxNativeWindow.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;
2014-06-25 07:01:35 +00:00
using System.Diagnostics;
2014-06-24 17:27:38 +00:00
using System.Drawing;
2014-06-25 07:01:35 +00:00
using System.Runtime.InteropServices;
2014-06-24 17:27:38 +00:00
using OpenTK.Graphics;
using OpenTK.Platform.Egl;
2014-06-23 20:22:04 +00:00
namespace OpenTK.Platform.Linux
{
2014-06-24 17:27:38 +00:00
using Egl = OpenTK.Platform.Egl.Egl;
2014-06-23 20:22:04 +00:00
class LinuxNativeWindow : NativeWindowBase
{
2014-06-25 07:01:35 +00:00
LinuxWindowInfo window;
2014-06-24 17:27:38 +00:00
string title;
Icon icon;
bool exists;
Rectangle bounds;
Size client_size;
public LinuxNativeWindow(IntPtr display, IntPtr gbm, int fd,
2014-06-25 07:01:35 +00:00
int x, int y, int width, int height, string title,
GraphicsMode mode, GameWindowFlags options,
2014-06-24 17:27:38 +00:00
DisplayDevice display_device)
{
2014-06-25 07:01:35 +00:00
Debug.Print("[KMS] Creating window on display {0:x}", display);
2014-06-24 17:27:38 +00:00
Title = title;
display_device = display_device ?? DisplayDevice.Default;
if (display_device == null)
{
throw new NotSupportedException("[KMS] Driver does not currently support headless systems");
}
2014-06-24 17:27:38 +00:00
window = new LinuxWindowInfo(display, fd, display_device.Id as LinuxDisplay);
// Note: we only support fullscreen windows on KMS.
// We implicitly override the requested width and height
// by the width and height of the DisplayDevice, if any.
width = display_device.Width;
height = display_device.Height;
bounds = new Rectangle(0, 0, width, height);
client_size = bounds.Size;
2014-06-25 07:01:35 +00:00
if (!mode.Index.HasValue)
{
mode = new EglGraphicsMode().SelectGraphicsMode(window, mode, 0);
}
Debug.Print("[KMS] Selected EGL mode {0}", mode);
SurfaceFormat format = GetSurfaceFormat(display, mode);
SurfaceFlags usage = SurfaceFlags.Rendering | SurfaceFlags.Scanout;
if (!Gbm.IsFormatSupported(gbm, format, usage))
2014-06-25 07:01:35 +00:00
{
Debug.Print("[KMS] Failed to find suitable surface format, using XRGB8888");
format = SurfaceFormat.XRGB8888;
}
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");
}
2014-06-24 17:27:38 +00:00
window.Handle = gbm_surface;
2014-06-25 07:01:35 +00:00
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
2014-06-24 17:27:38 +00:00
exists = true;
}
SurfaceFormat GetSurfaceFormat(IntPtr display, GraphicsMode mode)
2014-06-25 07:01:35 +00:00
{
// Use EGL 1.4 EGL_NATIVE_VISUAL_ID to retrieve
// the corresponding surface format. If that fails
// fall back to a manual algorithm.
int format;
Egl.GetConfigAttrib(display, mode.Index.Value,
Egl.NATIVE_VISUAL_ID, out format);
if ((SurfaceFormat)format != 0)
return (SurfaceFormat)format;
Debug.Print("[KMS] Failed to retrieve EGL visual from GBM surface. Error: {0}",
Egl.GetError());
Debug.Print("[KMS] Falling back to hardcoded formats.");
2014-06-25 07:01:35 +00:00
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;
}
2014-06-23 20:22:04 +00:00
#region INativeWindow Members
public override void ProcessEvents()
{
base.ProcessEvents();
}
2014-06-23 20:22:04 +00:00
public override void Close()
{
2014-06-24 17:27:38 +00:00
exists = false;
2014-06-23 20:22:04 +00:00
}
2014-06-24 17:27:38 +00:00
public override Point PointToClient(Point point)
2014-06-23 20:22:04 +00:00
{
2014-06-24 17:27:38 +00:00
// Todo
return point;
2014-06-23 20:22:04 +00:00
}
2014-06-24 17:27:38 +00:00
public override Point PointToScreen(Point point)
2014-06-23 20:22:04 +00:00
{
2014-06-24 17:27:38 +00:00
// Todo
return point;
2014-06-23 20:22:04 +00:00
}
protected override void Dispose(bool disposing)
{
2014-06-25 07:01:35 +00:00
if (disposing)
{
window.Dispose();
Gbm.DestroySurface(window.Handle);
}
2014-06-23 20:22:04 +00:00
}
2014-06-24 17:27:38 +00:00
public override Icon Icon
2014-06-23 20:22:04 +00:00
{
get
{
2014-06-24 17:27:38 +00:00
return icon;
2014-06-23 20:22:04 +00:00
}
set
{
2014-06-24 17:27:38 +00:00
if (icon != value)
{
icon = value;
OnIconChanged(EventArgs.Empty);
}
2014-06-23 20:22:04 +00:00
}
}
public override string Title
{
get
{
2014-06-24 17:27:38 +00:00
return title;
2014-06-23 20:22:04 +00:00
}
set
{
2014-06-24 17:27:38 +00:00
if (title != value)
{
title = value;
OnTitleChanged(EventArgs.Empty);
}
2014-06-23 20:22:04 +00:00
}
}
public override bool Focused
{
get
{
2014-06-24 17:27:38 +00:00
return true;
2014-06-23 20:22:04 +00:00
}
}
public override bool Visible
{
get
{
2014-06-24 17:27:38 +00:00
return true;
2014-06-23 20:22:04 +00:00
}
set
{
}
}
public override bool Exists
{
get
{
2014-06-24 17:27:38 +00:00
return exists;
2014-06-23 20:22:04 +00:00
}
}
public override IWindowInfo WindowInfo
{
get
{
2014-06-25 07:01:35 +00:00
return window;
2014-06-23 20:22:04 +00:00
}
}
public override WindowState WindowState
{
get
{
2014-06-24 17:27:38 +00:00
return WindowState.Fullscreen;
2014-06-23 20:22:04 +00:00
}
set
{
}
}
public override WindowBorder WindowBorder
{
get
{
2014-06-24 17:27:38 +00:00
return WindowBorder.Hidden;
2014-06-23 20:22:04 +00:00
}
set
{
}
}
2014-06-24 17:27:38 +00:00
public override Rectangle Bounds
2014-06-23 20:22:04 +00:00
{
get
{
2014-06-24 17:27:38 +00:00
return bounds;
2014-06-23 20:22:04 +00:00
}
set
{
}
}
2014-06-24 17:27:38 +00:00
public override Size ClientSize
2014-06-23 20:22:04 +00:00
{
get
{
2014-06-24 17:27:38 +00:00
return client_size;
2014-06-23 20:22:04 +00:00
}
set
{
}
}
public override bool CursorVisible
{
get
{
2014-06-24 17:27:38 +00:00
return false;
2014-06-23 20:22:04 +00:00
}
set
{
}
}
public override MouseCursor Cursor
{
get
{
2014-06-24 17:27:38 +00:00
return MouseCursor.Empty;
2014-06-23 20:22:04 +00:00
}
set
{
}
}
#endregion
}
}