This commit is contained in:
Emmanuel 2020-09-09 15:47:45 +00:00
parent b999bbcfd5
commit 522678c94d
118 changed files with 24246 additions and 394 deletions

View file

@ -35,437 +35,535 @@ using System.ComponentModel;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform;
using Gtk;
using Cairo;
using GLib;
using Gdk;
using OpenGL;
using System.Diagnostics;
using OpenTK.Mathematics;
namespace OpenTK
{
[ToolboxItem(true)]
public class GLWidget : DrawingArea
{
private static bool xThreadInit;
[ToolboxItem(true)]
public class GLWidget : DrawingArea
{
/// <summary>
/// Get or set the OpenGL minimum color buffer bits.
/// </summary>
[Property("color-bits")]
public uint ColorBits
{
get { return (_ColorBits); }
set { _ColorBits = value; }
}
#region Static attrs.
/// <summary>
/// The OpenGL color buffer bits.
/// </summary>
private uint _ColorBits = 24;
private static int _graphicsContextCount;
private static bool _sharedContextInitialized;
/// <summary>
/// Get or set the OpenGL minimum depth buffer bits.
/// </summary>
[Property("depth-bits")]
public uint DepthBits
{
get { return (_DepthBits); }
set { _DepthBits = value; }
}
/// <summary>
/// The OpenGL color buffer bits.
/// </summary>
private uint _DepthBits;
/// <summary>
/// Get or set the OpenGL minimum stencil buffer bits.
/// </summary>
[Property("stencil-bits")]
public uint StencilBits
{
get { return (_StencilBits); }
set { _StencilBits = value; }
}
/// <summary>
/// The OpenGL color buffer bits.
/// </summary>
private uint _StencilBits;
/// <summary>
/// Get or set the OpenGL minimum multisample buffer "bits".
/// </summary>
[Property("multisample-bits")]
public uint MultisampleBits
{
get { return (_MultisampleBits); }
set { _MultisampleBits = value; }
}
/// <summary>
/// The OpenGL multisample buffer bits.
/// </summary>
private uint _MultisampleBits;
/// <summary>
/// Get or set the OpenGL swap buffers interval.
/// </summary>
[Property("swap-interval")]
public int SwapInterval
{
get { return (_SwapInterval); }
set { _SwapInterval = value; }
}
/// <summary>
/// The OpenGL swap buffers interval.
/// </summary>
private int _SwapInterval = 1;
/// <summary>
/// The <see cref="DevicePixelFormat"/> describing the minimum pixel format required by this control.
/// </summary>
private DevicePixelFormat ControlPixelFormat
{
get
{
DevicePixelFormat controlReqFormat = new DevicePixelFormat();
controlReqFormat.RgbaUnsigned = true;
controlReqFormat.RenderWindow = true;
controlReqFormat.ColorBits = (int)ColorBits;
controlReqFormat.DepthBits = (int)DepthBits;
controlReqFormat.StencilBits = (int)StencilBits;
controlReqFormat.MultisampleBits = (int)MultisampleBits;
controlReqFormat.DoubleBuffer = true;
return (controlReqFormat);
}
}
#region Static attrs.
public bool HandleRendering { get; set; } = false;
public bool IsRenderHandler { get; set; } = false;
#endregion
#region Attributes
private IGraphicsContext _graphicsContext;
private IWindowInfo _windowInfo;
private bool _initialized;
#endregion
#endregion
#region Properties
#region Properties
/// <summary>The major version of OpenGL to use.</summary>
public int GLVersionMajor { get; set; }
/// <summary>Use a single buffer versus a double buffer.</summary>
[Browsable(true)]
public bool SingleBuffer { get; set; }
/// <summary>The minor version of OpenGL to use.</summary>
public int GLVersionMinor { get; set; }
/// <summary>Color Buffer Bits-Per-Pixel</summary>
public int ColorBPP { get; set; }
private DeviceContext _deviceContext;
private IntPtr _graphicsContext;
private int _error;
/// <summary>Accumulation Buffer Bits-Per-Pixel</summary>
public int AccumulatorBPP { get; set; }
private IGraphicsContext _context;
private GLContext _gdkGlContext;
/// <summary>Depth Buffer Bits-Per-Pixel</summary>
public int DepthBPP { get; set; }
public bool ForwardCompatible { get; }
public DeviceContext DeviceContext { get => _deviceContext; set => _deviceContext = value; }
/// <summary>Stencil Buffer Bits-Per-Pixel</summary>
public int StencilBPP { get; set; }
/// <summary>Number of samples</summary>
public int Samples { get; set; }
/// <summary>Indicates if steropic renderering is enabled</summary>
public bool Stereo { get; set; }
/// <summary>The major version of OpenGL to use.</summary>
public int GLVersionMajor { get; set; }
/// <summary>The minor version of OpenGL to use.</summary>
public int GLVersionMinor { get; set; }
public GraphicsContextFlags GraphicsContextFlags
{
get;
set;
}
#endregion
#region Construction/Destruction
/// <summary>Constructs a new GLWidget</summary>
public GLWidget() : this(new Version(4, 0), true)
/// <summary>Constructs a new GLWidget.</summary>
public GLWidget()
: this(GraphicsMode.Default)
{
}
/// <summary>Constructs a new GLWidget using a given GraphicsMode</summary>
public GLWidget(GraphicsMode graphicsMode)
: this(graphicsMode, 1, 0, GraphicsContextFlags.Default)
{
/*this.ColorBits = 32;
this.DepthBits = 24;
this.StencilBits = 8;*/
}
/// <summary>Constructs a new GLWidget</summary>
public GLWidget(Version apiVersion, bool forwardCompatible)
{
GLVersionMajor = apiVersion.Major;
GLVersionMinor = apiVersion.Minor;
ForwardCompatible = forwardCompatible;
}
public GLWidget(GraphicsMode graphicsMode, int glVersionMajor, int glVersionMinor, GraphicsContextFlags graphicsContextFlags)
{
SingleBuffer = graphicsMode.Buffers == 1;
ColorBPP = graphicsMode.ColorFormat.BitsPerPixel;
AccumulatorBPP = graphicsMode.AccumulatorFormat.BitsPerPixel;
DepthBPP = graphicsMode.Depth;
StencilBPP = graphicsMode.Stencil;
Samples = graphicsMode.Samples;
Stereo = graphicsMode.Stereo;
~GLWidget()
{
Dispose(false);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
OnShuttingDown();
GLVersionMajor = glVersionMajor;
GLVersionMinor = glVersionMinor;
GraphicsContextFlags = graphicsContextFlags;
}
DeviceContext?.DeleteContext(_graphicsContext);
~GLWidget()
{
Dispose(false);
}
DeviceContext?.Dispose();
public void MakeCurrent()
{
GraphicsContext.MakeCurrent(_windowInfo);
}
_gdkGlContext?.Dispose();
public void ClearCurrent()
{
GraphicsContext.MakeCurrent(null);
}
public void Swapbuffers()
{
GraphicsContext.SwapBuffers();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
try
{
GraphicsContext.MakeCurrent(WindowInfo);
}
catch (Exception ex)
{
}
OnShuttingDown();
if (OpenTK.Graphics.GraphicsContext.ShareContexts && (Interlocked.Decrement(ref _graphicsContextCount) == 0))
{
OnGraphicsContextShuttingDown();
_sharedContextInitialized = false;
}
GraphicsContext.Dispose();
}
}
}
#endregion
#endregion
#region New Events
#region New Events
// Called when the first GraphicsContext is created in the case of GraphicsContext.ShareContexts == True;
public static event EventHandler GraphicsContextInitialized;
// Called when the first GraphicsContext is created in the case of GraphicsContext.ShareContexts == True;
public static event EventHandler GraphicsContextInitialized;
private static void OnGraphicsContextInitialized()
{
if (GraphicsContextInitialized != null)
{
GraphicsContextInitialized(null, EventArgs.Empty);
}
}
// Called when the first GraphicsContext is being destroyed in the case of GraphicsContext.ShareContexts == True;
public static event EventHandler GraphicsContextShuttingDown;
private static void OnGraphicsContextShuttingDown()
{
if (GraphicsContextShuttingDown != null)
{
GraphicsContextShuttingDown(null, EventArgs.Empty);
}
}
// Called when this GLWidget has a valid GraphicsContext
public event EventHandler Initialized;
protected virtual void OnInitialized()
{
if (Initialized != null)
{
Initialized(this, EventArgs.Empty);
}
}
// Called when this GLWidget needs to render a frame
public event EventHandler RenderFrame;
protected virtual void OnRenderFrame()
{
RenderFrame?.Invoke(this, EventArgs.Empty);
protected virtual void OnInitialized()
{
if (Initialized != null)
{
Initialized(this, EventArgs.Empty);
}
}
// Called when this GLWidget is being Disposed
public event EventHandler ShuttingDown;
// Called when this GLWidget needs to render a frame
public event EventHandler RenderFrame;
protected virtual void OnShuttingDown()
{
if (ShuttingDown != null)
{
ShuttingDown(this, EventArgs.Empty);
}
}
protected virtual void OnRenderFrame()
{
if (RenderFrame != null)
{
RenderFrame(this, EventArgs.Empty);
}
}
#endregion
// Called when this GLWidget is being Disposed
public event EventHandler ShuttingDown;
// Called when the widget needs to be (fully or partially) redrawn.
protected virtual void OnShuttingDown()
{
if (ShuttingDown != null)
{
ShuttingDown(this, EventArgs.Empty);
}
}
protected override bool OnDrawn(Cairo.Context cr)
{
if (!_initialized)
Initialize();
#endregion
ClearCurrent();
// Called when a widget is realized. (window handles and such are valid)
// protected override void OnRealized() { base.OnRealized(); }
// Called when the widget needs to be (fully or partially) redrawn.
protected override bool OnDrawn(Cairo.Context cr)
{
if (!_initialized)
Initialize();
else if (!IsRenderHandler)
GraphicsContext.MakeCurrent(WindowInfo);
return true;
}
public void Swapbuffers()
{
_context?.SwapBuffers();
}
public void MakeCurrent()
{
ClearCurrent();
_context?.MakeCurrent();
_error = Marshal.GetLastWin32Error();
}
public void ClearCurrent()
{
if (GTKBindingHelper.CurrentPlatform == OSPlatform.Windows)
{
DeviceContext?.MakeCurrent(IntPtr.Zero);
}
else
{
Gdk.GLContext.ClearCurrent();
}
}
private void CreateContext()
{
if (_graphicsContext != IntPtr.Zero)
throw new InvalidOperationException("context already created");
IntPtr sharingContext = IntPtr.Zero;
if (Gl.PlatformExtensions.CreateContext_ARB)
{
List<int> attributes = new List<int>();
uint contextProfile = 0, contextFlags = 0;
bool debuggerAttached = Debugger.IsAttached;
#region WGL_ARB_create_context|GLX_ARB_create_context
#endregion
#region WGL_ARB_create_context_profile|GLX_ARB_create_context_profile
if (Gl.PlatformExtensions.CreateContextProfile_ARB)
{
}
#endregion
#region WGL_ARB_create_context_robustness|GLX_ARB_create_context_robustness
if (Gl.PlatformExtensions.CreateContextRobustness_ARB)
{
}
#endregion
Debug.Assert(Wgl.CONTEXT_FLAGS_ARB == Glx.CONTEXT_FLAGS_ARB);
if (contextFlags != 0)
attributes.AddRange(new int[] { Wgl.CONTEXT_FLAGS_ARB, unchecked((int)contextFlags) });
Debug.Assert(Wgl.CONTEXT_PROFILE_MASK_ARB == Glx.CONTEXT_PROFILE_MASK_ARB);
Debug.Assert(contextProfile == 0 || Gl.PlatformExtensions.CreateContextProfile_ARB);
if (contextProfile != 0)
attributes.AddRange(new int[] { Wgl.CONTEXT_PROFILE_MASK_ARB, unchecked((int)contextProfile) });
attributes.Add(0);
if ((_graphicsContext = _deviceContext.CreateContextAttrib(sharingContext, attributes.ToArray())) == IntPtr.Zero)
throw new InvalidOperationException(String.Format("unable to create render context ({0})", Gl.GetError()));
}
else
{
// Create OpenGL context using compatibility profile
if ((_graphicsContext = _deviceContext.CreateContext(sharingContext)) == IntPtr.Zero)
throw new InvalidOperationException("unable to create render context");
}
}
private void CreateDeviceContext(DevicePixelFormat controlReqFormat)
{
#region Create device context
DeviceContext = DeviceContext.Create(GTKBindingHelper.GetDisplayHandle(Display.Handle), GTKBindingHelper.GetWindowHandle(Window.Handle));
DeviceContext.IncRef();
#endregion
#region Set pixel format
DevicePixelFormatCollection pixelFormats = DeviceContext.PixelsFormats;
List<DevicePixelFormat> matchingPixelFormats = pixelFormats.Choose(controlReqFormat);
if ((matchingPixelFormats.Count == 0) && controlReqFormat.MultisampleBits > 0)
{
// Try to select the maximum multisample configuration
int multisampleBits = 0;
pixelFormats.ForEach(delegate (DevicePixelFormat item) { multisampleBits = Math.Max(multisampleBits, item.MultisampleBits); });
controlReqFormat.MultisampleBits = multisampleBits;
matchingPixelFormats = pixelFormats.Choose(controlReqFormat);
}
if ((matchingPixelFormats.Count == 0) && controlReqFormat.DoubleBuffer)
{
// Try single buffered pixel formats
controlReqFormat.DoubleBuffer = false;
matchingPixelFormats = pixelFormats.Choose(controlReqFormat);
if (matchingPixelFormats.Count == 0)
throw new InvalidOperationException(String.Format("unable to find a suitable pixel format: {0}", pixelFormats.GuessChooseError(controlReqFormat)));
}
else if (matchingPixelFormats.Count == 0)
throw new InvalidOperationException(String.Format("unable to find a suitable pixel format: {0}", pixelFormats.GuessChooseError(controlReqFormat)));
DeviceContext.SetPixelFormat(matchingPixelFormats[0]);
#endregion
#region Set V-Sync
if (Gl.PlatformExtensions.SwapControl)
{
int swapInterval = SwapInterval;
// Mask value in case it is not supported
if (!Gl.PlatformExtensions.SwapControlTear && swapInterval == -1)
swapInterval = 1;
DeviceContext.SwapInterval(swapInterval);
}
#endregion
}
private void CreateGdkGlContext()
// Called on Resize
protected override bool OnConfigureEvent(Gdk.EventConfigure evnt)
{
_gdkGlContext = Window.CreateGlContext();
if (GraphicsContext != null)
{
GraphicsContext.Update(WindowInfo);
}
_gdkGlContext.SetRequiredVersion(GLVersionMajor, GLVersionMinor);
_gdkGlContext.ForwardCompatible = ForwardCompatible;
_gdkGlContext.SetUseEs(0);
_gdkGlContext.Realize();
_gdkGlContext.MakeCurrent();
return true;
}
private void Initialize()
{
ClearCurrent();
{
_initialized = true;
Khronos.KhronosApi.LogEnabled = true;
Window.EnsureNative();
if (GTKBindingHelper.CurrentPlatform == OSPlatform.Windows)
// If this looks uninitialized... initialize.
if (ColorBPP == 0)
{
CreateDeviceContext(ControlPixelFormat);
ColorBPP = 32;
CreateContext();
DeviceContext.MakeCurrent(_graphicsContext);
}
else {
GraphicsContext.Display = Display.Handle;
CreateGdkGlContext();
if (DepthBPP == 0)
{
DepthBPP = 16;
}
}
_context = GraphicsContext.GetCurrentContext(Window.Handle);
ColorFormat colorBufferColorFormat = new ColorFormat(ColorBPP);
MakeCurrent();
ColorFormat accumulationColorFormat = new ColorFormat(AccumulatorBPP);
GTKBindingHelper.InitializeGlBindings();
int buffers = 2;
if (SingleBuffer)
{
buffers--;
}
GraphicsMode graphicsMode = new GraphicsMode(colorBufferColorFormat, DepthBPP, StencilBPP, Samples, accumulationColorFormat, buffers, Stereo);
this.Window.EnsureNative();
// IWindowInfo
if (OpenTK.Configuration.RunningOnWindows)
{
WindowInfo = InitializeWindows();
}
else if (OpenTK.Configuration.RunningOnMacOS)
{
WindowInfo = InitializeOSX();
}
else
{
WindowInfo = InitializeX(graphicsMode);
}
// GraphicsContext
GraphicsContext = new GraphicsContext(graphicsMode, WindowInfo, GLVersionMajor, GLVersionMinor, GraphicsContextFlags);
GraphicsContext.MakeCurrent(WindowInfo);
if (OpenTK.Graphics.GraphicsContext.ShareContexts)
{
Interlocked.Increment(ref _graphicsContextCount);
if (!_sharedContextInitialized)
{
_sharedContextInitialized = true;
((IGraphicsContextInternal)GraphicsContext).LoadAll();
OnGraphicsContextInitialized();
}
}
else
{
((IGraphicsContextInternal)GraphicsContext).LoadAll();
OnGraphicsContextInitialized();
}
OnInitialized();
}
OpenTK.GraphicsContext.GetCurrentContext(Window.Handle).SwapInterval(1);
#region Windows Specific initalization
ClearCurrent();
IWindowInfo InitializeWindows()
{
IntPtr windowHandle = gdk_win32_window_get_handle(this.Window.Handle);
return Utilities.CreateWindowsWindowInfo(windowHandle);
}
_initialized = true;
[SuppressUnmanagedCodeSecurity, DllImport("libgdk-3-0.dll")]
public static extern IntPtr gdk_win32_window_get_handle(IntPtr d);
}
}
#endregion
#region OSX Specific Initialization
IWindowInfo InitializeOSX()
{
IntPtr windowHandle = gdk_quartz_window_get_nswindow(this.Window.Handle);
//IntPtr viewHandle = gdk_quartz_window_get_nsview(this.GdkWindow.Handle);
return Utilities.CreateMacOSWindowInfo(windowHandle);
}
[SuppressUnmanagedCodeSecurity, DllImport("libgdk-3.0.dylib")]
static extern IntPtr gdk_quartz_window_get_nswindow(IntPtr handle);
[SuppressUnmanagedCodeSecurity, DllImport("libgdk-3.0.dylib")]
static extern IntPtr gdk_quartz_window_get_nsview(IntPtr handle);
#endregion
#region X Specific Initialization
const string UnixLibGdkName = "libgdk-3.so.0";
const string UnixLibX11Name = "libX11.so.6";
const string UnixLibGLName = "libGL.so.1";
const int GLX_NONE = 0;
const int GLX_USE_GL = 1;
const int GLX_BUFFER_SIZE = 2;
const int GLX_LEVEL = 3;
const int GLX_RGBA = 4;
const int GLX_DOUBLEBUFFER = 5;
const int GLX_STEREO = 6;
const int GLX_AUX_BUFFERS = 7;
const int GLX_RED_SIZE = 8;
const int GLX_GREEN_SIZE = 9;
const int GLX_BLUE_SIZE = 10;
const int GLX_ALPHA_SIZE = 11;
const int GLX_DEPTH_SIZE = 12;
const int GLX_STENCIL_SIZE = 13;
const int GLX_ACCUM_RED_SIZE = 14;
const int GLX_ACCUM_GREEN_SIZE = 15;
const int GLX_ACCUM_BLUE_SIZE = 16;
const int GLX_ACCUM_ALPHA_SIZE = 17;
public enum XVisualClass
{
StaticGray = 0,
GrayScale = 1,
StaticColor = 2,
PseudoColor = 3,
TrueColor = 4,
DirectColor = 5,
}
[StructLayout(LayoutKind.Sequential)]
struct XVisualInfo
{
public IntPtr Visual;
public IntPtr VisualID;
public int Screen;
public int Depth;
public XVisualClass Class;
public long RedMask;
public long GreenMask;
public long blueMask;
public int ColormapSize;
public int BitsPerRgb;
public override string ToString()
{
return $"id ({VisualID}), screen ({Screen}), depth ({Depth}), class ({Class})";
}
}
[Flags]
internal enum XVisualInfoMask
{
No = 0x0,
ID = 0x1,
Screen = 0x2,
Depth = 0x4,
Class = 0x8,
Red = 0x10,
Green = 0x20,
Blue = 0x40,
ColormapSize = 0x80,
BitsPerRGB = 0x100,
All = 0x1FF,
}
private IWindowInfo InitializeX(GraphicsMode mode)
{
IntPtr display = gdk_x11_display_get_xdisplay(Display.Handle);
int screen = Screen.Number;
IntPtr windowHandle = gdk_x11_window_get_xid(Window.Handle);
IntPtr rootWindow = gdk_x11_window_get_xid(RootWindow.Handle);
IntPtr visualInfo;
if (mode.Index.HasValue)
{
XVisualInfo info = new XVisualInfo();
info.VisualID = mode.Index.Value;
int dummy;
visualInfo = XGetVisualInfo(display, XVisualInfoMask.ID, ref info, out dummy);
}
else
{
visualInfo = GetVisualInfo(display);
}
IWindowInfo retval = Utilities.CreateX11WindowInfo(display, screen, windowHandle, rootWindow, visualInfo);
XFree(visualInfo);
return retval;
}
private static IntPtr XGetVisualInfo(IntPtr display, XVisualInfoMask vinfo_mask, ref XVisualInfo template, out int nitems)
{
return XGetVisualInfoInternal(display, (IntPtr)(int)vinfo_mask, ref template, out nitems);
}
private IntPtr GetVisualInfo(IntPtr display)
{
try
{
int[] attributes = AttributeList.ToArray();
return glXChooseVisual(display, Screen.Number, attributes);
}
catch (DllNotFoundException e)
{
throw new DllNotFoundException("OpenGL dll not found!", e);
}
catch (EntryPointNotFoundException enf)
{
throw new EntryPointNotFoundException("Glx entry point not found!", enf);
}
}
private List<int> AttributeList
{
get
{
List<int> attributeList = new List<int>(24);
attributeList.Add(GLX_RGBA);
if (!SingleBuffer)
attributeList.Add(GLX_DOUBLEBUFFER);
if (Stereo)
attributeList.Add(GLX_STEREO);
attributeList.Add(GLX_RED_SIZE);
attributeList.Add(ColorBPP / 4); // TODO support 16-bit
attributeList.Add(GLX_GREEN_SIZE);
attributeList.Add(ColorBPP / 4); // TODO support 16-bit
attributeList.Add(GLX_BLUE_SIZE);
attributeList.Add(ColorBPP / 4); // TODO support 16-bit
attributeList.Add(GLX_ALPHA_SIZE);
attributeList.Add(ColorBPP / 4); // TODO support 16-bit
attributeList.Add(GLX_DEPTH_SIZE);
attributeList.Add(DepthBPP);
attributeList.Add(GLX_STENCIL_SIZE);
attributeList.Add(StencilBPP);
attributeList.Add(GLX_ACCUM_RED_SIZE);
attributeList.Add(AccumulatorBPP / 4);// TODO support 16-bit
attributeList.Add(GLX_ACCUM_GREEN_SIZE);
attributeList.Add(AccumulatorBPP / 4);// TODO support 16-bit
attributeList.Add(GLX_ACCUM_BLUE_SIZE);
attributeList.Add(AccumulatorBPP / 4);// TODO support 16-bit
attributeList.Add(GLX_ACCUM_ALPHA_SIZE);
attributeList.Add(AccumulatorBPP / 4);// TODO support 16-bit
attributeList.Add(GLX_NONE);
return attributeList;
}
}
public IGraphicsContext GraphicsContext { get => _graphicsContext; set => _graphicsContext = value; }
public IWindowInfo WindowInfo { get => _windowInfo; set => _windowInfo = value; }
[DllImport(UnixLibX11Name, EntryPoint = "XGetVisualInfo")]
private static extern IntPtr XGetVisualInfoInternal(IntPtr display, IntPtr vinfo_mask, ref XVisualInfo template, out int nitems);
[SuppressUnmanagedCodeSecurity, DllImport(UnixLibX11Name)]
private static extern void XFree(IntPtr handle);
/// <summary> Returns the X resource (window or pixmap) belonging to a GdkDrawable. </summary>
/// <remarks> XID gdk_x11_drawable_get_xid(GdkDrawable *drawable); </remarks>
/// <param name="gdkDisplay"> The GdkDrawable. </param>
/// <returns> The ID of drawable's X resource. </returns>
[SuppressUnmanagedCodeSecurity, DllImport(UnixLibGdkName)]
private static extern IntPtr gdk_x11_drawable_get_xid(IntPtr gdkDisplay);
/// <summary> Returns the X resource (window or pixmap) belonging to a GdkDrawable. </summary>
/// <remarks> XID gdk_x11_drawable_get_xid(GdkDrawable *drawable); </remarks>
/// <param name="gdkDisplay"> The GdkDrawable. </param>
/// <returns> The ID of drawable's X resource. </returns>
[SuppressUnmanagedCodeSecurity, DllImport(UnixLibGdkName)]
private static extern IntPtr gdk_x11_window_get_xid(IntPtr gdkDisplay);
/// <summary> Returns the X display of a GdkDisplay. </summary>
/// <remarks> Display* gdk_x11_display_get_xdisplay(GdkDisplay *display); </remarks>
/// <param name="gdkDisplay"> The GdkDrawable. </param>
/// <returns> The X Display of the GdkDisplay. </returns>
[SuppressUnmanagedCodeSecurity, DllImport(UnixLibGdkName)]
private static extern IntPtr gdk_x11_display_get_xdisplay(IntPtr gdkDisplay);
[SuppressUnmanagedCodeSecurity, DllImport(UnixLibGLName)]
private static extern IntPtr glXChooseVisual(IntPtr display, int screen, int[] attr);
#endregion
}
}

View file

@ -5,11 +5,13 @@
<Description>GLWigdet for GTKSharp, using Opentk.</Description>
<Version>1.0.3.2</Version>
<RepositoryUrl>https://github.com/Ryujinx/GLWidget</RepositoryUrl>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GtkSharp" Version="3.22.25.56" />
<PackageReference Include="OpenGL.Net" Version="0.8.4" />
<PackageReference Include="OpenTK.Graphics" Version="4.0.0-pre9.4" />
<PackageReference Include="OpenTK.Windowing.Common" Version="4.0.0-pre9.4" />
<PackageReference Include="GtkSharp" Version="3.22.25.56"/>
<PackageReference Include="OpenGL.Net" Version="0.8.4"/>
<PackageReference Include="OpenTK.Graphics" Version="4.0.0-pre9.4"/>
<PackageReference Include="OpenTK.Windowing.Common" Version="4.0.0-pre9.4"/>
<PackageReference Include="System.Drawing.Common" Version="4.7.0"/>
</ItemGroup>
</Project>

View file

@ -47,32 +47,16 @@ namespace OpenTK
{
if (CurrentPlatform == OSPlatform.Windows)
{
var addr = GetProcAddressWgl(procName);
if (addr == null || addr == IntPtr.Zero)
{
var library = UnsafeNativeMethods.LoadLibrary(WglLibrary);
addr = UnsafeNativeMethods.GetProcAddress(library, procName);
}
if (addr != IntPtr.Zero)
{
Loaded = true;
}
return addr;
IntPtr library = OpenTK.Platform.Windows.Functions.LoadLibrary(WglLibrary);
return OpenTK.Platform.Windows.Functions.GetProcAddress(library, procName);
}
else if (CurrentPlatform == OSPlatform.Linux)
{
return GetProcAddressGlx(procName);
return OpenTK.Platform.X11.Glx.GetProcAddress(procName);
}
else if(CurrentPlatform == OSPlatform.OSX)
{
var osxAddr = GetProcAddressOSX(procName);
if (osxAddr != IntPtr.Zero)
{
Loaded = true;
}
return osxAddr;
return OpenTK.Platform.MacOS.NS.GetAddress(procName);
}
else
{

View file

@ -6,7 +6,7 @@ using static OpenTK.GTKBindingHelper;
namespace OpenTK
{
public interface IGraphicsContext
public interface ILegacyGraphicsContext
{
void MakeCurrent();
void SwapBuffers();
@ -14,7 +14,7 @@ namespace OpenTK
void SwapInterval(int interval);
}
public abstract class GraphicsContext : IGraphicsContext
public abstract class LegacyGraphicsContext : ILegacyGraphicsContext
{
public static IntPtr Display{ get; set; }
@ -40,7 +40,7 @@ namespace OpenTK
}
}
public static IGraphicsContext GetCurrentContext(IntPtr handle)
public static ILegacyGraphicsContext GetCurrentContext(IntPtr handle)
{
var currentPlatform = CurrentPlatform;
@ -66,7 +66,7 @@ namespace OpenTK
public abstract void SwapInterval(int interval);
}
public class WglGraphicsContext : GraphicsContext
public class WglGraphicsContext : LegacyGraphicsContext
{
private delegate int wglSwapIntervalExtDelegate(int interval);
private static wglSwapIntervalExtDelegate wglSwapIntervalExt = null;
@ -120,7 +120,7 @@ namespace OpenTK
}
}
public class GlxGraphicsContext : GraphicsContext
public class GlxGraphicsContext : LegacyGraphicsContext
{
private IntPtr _windowHandle;
@ -162,7 +162,7 @@ namespace OpenTK
}
}
public class CglGraphicsContext : GraphicsContext
public class CglGraphicsContext : LegacyGraphicsContext
{
private IntPtr _windowHandle;

View file

@ -0,0 +1,210 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace OpenTK
{
/// <summary>
/// Provides a common foundation for all flat API bindings and implements the extension loading interface.
/// </summary>
public abstract class LegacyBindingsBase
{
/// <summary>
/// Constructs a new BindingsBase instance.
/// </summary>
public LegacyBindingsBase()
{
}
/// <summary>
/// Gets or sets a <see cref="System.Boolean"/> that indicates whether the list of supported extensions may have changed.
/// </summary>
protected bool RebuildExtensionList { get; set; } = true;
/// <summary>
/// Retrieves an unmanaged function pointer to the specified function.
/// </summary>
/// <param name="funcname">
/// A <see cref="System.String"/> that defines the name of the function.
/// </param>
/// <returns>
/// A <see cref="IntPtr"/> that contains the address of funcname or IntPtr.Zero,
/// if the function is not supported by the drivers.
/// </returns>
/// <remarks>
/// Note: some drivers are known to return non-zero values for unsupported functions.
/// Typical values include 1 and 2 - inheritors are advised to check for and ignore these
/// values.
/// </remarks>
public abstract IntPtr GetAddress(string funcname);
/// <summary>
/// Gets an object that can be used to synchronize access to the bindings implementation.
/// </summary>
/// <remarks>This object should be unique across bindings but consistent between bindings
/// of the same type. For example, ES10.GL, OpenGL.GL and CL10.CL should all return
/// unique objects, but all instances of ES10.GL should return the same object.</remarks>
protected abstract object SyncRoot { get; }
/// <summary>
/// Marshals a pointer to a null-terminated byte array to a new <c>System.String</c>.
/// This method supports OpenTK and is not intended to be called by user code.
/// </summary>
/// <param name="ptr">A pointer to a null-terminated byte array.</param>
/// <returns>
/// A <c>System.String</c> with the data from <paramref name="ptr"/>.
/// </returns>
protected static string MarshalPtrToString(IntPtr ptr)
{
if (ptr == IntPtr.Zero)
{
throw new ArgumentException("ptr");
}
unsafe
{
sbyte* str = (sbyte*)ptr;
int len = 0;
while (*str != 0)
{
++len;
++str;
}
return new string((sbyte*)ptr, 0, len, Encoding.UTF8);
}
}
/// <summary>
/// Marshal a <c>System.String</c> to unmanaged memory.
/// The resulting string is encoded in UTF8 and must be freed
/// with <c>FreeStringPtr</c>.
/// </summary>
/// <param name="str">The <c>System.String</c> to marshal.</param>
/// <returns>
/// An unmanaged pointer containing the marshalled string.
/// This pointer must be freed with <c>FreeStringPtr</c>
/// </returns>
protected static IntPtr MarshalStringToPtr(string str)
{
if (String.IsNullOrEmpty(str))
{
return IntPtr.Zero;
}
// Allocate a buffer big enough to hold the marshalled string.
// GetMaxByteCount() appears to allocate space for the final NUL
// character, but allocate an extra one just in case (who knows
// what old Mono version would do here.)
int max_count = Encoding.UTF8.GetMaxByteCount(str.Length) + 1;
IntPtr ptr = Marshal.AllocHGlobal(max_count);
if (ptr == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
// Pin the managed string and convert it to UTF8 using
// the pointer overload of System.Encoding.UTF8.GetBytes().
unsafe
{
fixed (char* pstr = str)
{
int actual_count = Encoding.UTF8.GetBytes(pstr, str.Length, (byte*)ptr, max_count);
Marshal.WriteByte(ptr, actual_count, 0); // Append '\0' at the end of the string
return ptr;
}
}
}
/// <summary>
/// Frees a marshalled string that allocated by <c>MarshalStringToPtr</c>.
/// </summary>
/// <param name="ptr">An unmanaged pointer allocated with <c>MarshalStringToPtr</c></param>
protected static void FreeStringPtr(IntPtr ptr)
{
Marshal.FreeHGlobal(ptr);
}
/// <summary>
/// Marshals a <c>System.String</c> array to unmanaged memory by calling
/// Marshal.AllocHGlobal for each element.
/// </summary>
/// <returns>An unmanaged pointer to an array of null-terminated strings</returns>
/// <param name="str_array">The string array to marshal.</param>
protected static IntPtr MarshalStringArrayToPtr(string[] str_array)
{
IntPtr ptr = IntPtr.Zero;
if (str_array != null && str_array.Length != 0)
{
ptr = Marshal.AllocHGlobal(str_array.Length * IntPtr.Size);
if (ptr == IntPtr.Zero)
{
throw new OutOfMemoryException();
}
int i = 0;
try
{
for (i = 0; i < str_array.Length; i++)
{
IntPtr str = MarshalStringToPtr(str_array[i]);
Marshal.WriteIntPtr(ptr, i * IntPtr.Size, str);
}
}
catch (OutOfMemoryException)
{
for (i = i - 1; i >= 0; --i)
{
Marshal.FreeHGlobal(Marshal.ReadIntPtr(ptr, i * IntPtr.Size));
}
Marshal.FreeHGlobal(ptr);
throw;
}
}
return ptr;
}
/// <summary>
/// Frees a marshalled string that allocated by <c>MarshalStringArrayToPtr</c>.
/// </summary>
/// <param name="ptr">An unmanaged pointer allocated with <c>MarshalStringArrayToPtr</c></param>
/// <param name="length">The length of the string array.</param>
protected static void FreeStringArrayPtr(IntPtr ptr, int length)
{
for (int i = 0; i < length; i++)
{
Marshal.FreeHGlobal(Marshal.ReadIntPtr(ptr, i * IntPtr.Size));
}
Marshal.FreeHGlobal(ptr);
}
internal abstract void LoadEntryPoints();
}
}

View file

@ -0,0 +1,197 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace OpenTK
{
/// <summary>
/// Provides information about the underlying OS and runtime.
/// You must call <c>Toolkit.Init</c> before accessing members
/// of this class.
/// </summary>
public sealed class Configuration
{
private static bool runningOnUnix, runningOnMacOS, runningOnLinux;
private volatile static bool initialized;
private readonly static object InitLock = new object();
private Configuration() { }
/// <summary>Gets a System.Boolean indicating whether OpenTK is running on a Windows platform.</summary>
public static bool RunningOnWindows { get; private set; }
/// <summary>Gets a System.Boolean indicating whether OpenTK is running on an X11 platform.</summary>
public static bool RunningOnX11 { get; private set; }
/// <summary>
/// Gets a <see cref="System.Boolean"/> indicating whether OpenTK is running on a Unix platform.
/// </summary>
public static bool RunningOnUnix
{
get { return runningOnUnix; }
}
/// <summary>Gets a System.Boolean indicating whether OpenTK is running on the Linux kernel.</summary>
public static bool RunningOnLinux { get { return runningOnLinux; } }
/// <summary>Gets a System.Boolean indicating whether OpenTK is running on a MacOS platform.</summary>
public static bool RunningOnMacOS { get { return runningOnMacOS; } }
/// <summary>
/// Gets a System.Boolean indicating whether OpenTK is running on the Mono runtime.
/// </summary>
public static bool RunningOnMono { get; private set; }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
private struct utsname
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string sysname;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string nodename;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string release;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string version;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string machine;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string extraJustInCase;
}
/// <summary>
/// Detects the unix kernel by p/invoking uname (libc).
/// </summary>
/// <returns></returns>
private static string DetectUnixKernel()
{
Debug.Print("Size: {0}", Marshal.SizeOf(typeof(utsname)).ToString());
Debug.Flush();
utsname uts = new utsname();
uname(out uts);
Debug.WriteLine("System:");
Debug.Indent();
Debug.WriteLine(uts.sysname);
Debug.WriteLine(uts.nodename);
Debug.WriteLine(uts.release);
Debug.WriteLine(uts.version);
Debug.WriteLine(uts.machine);
Debug.Unindent();
return uts.sysname.ToString();
}
[DllImport("libc")]
private static extern void uname(out utsname uname_struct);
private static bool DetectMono()
{
// Detect the Mono runtime (code taken from http://mono.wikia.com/wiki/Detecting_if_program_is_running_in_Mono).
Type t = Type.GetType("Mono.Runtime");
return t != null;
}
private static void DetectUnix(out bool unix, out bool linux, out bool macos)
{
unix = linux = macos = false;
string kernel_name = DetectUnixKernel();
switch (kernel_name)
{
case null:
case "":
throw new PlatformNotSupportedException(
"Unknown platform. Please file a bug report at https://github.com/opentk/opentk/issues");
case "Linux":
linux = unix = true;
break;
case "Darwin":
macos = unix = true;
break;
default:
unix = true;
break;
}
}
private static bool DetectWindows()
{
return
System.Environment.OSVersion.Platform == PlatformID.Win32NT ||
System.Environment.OSVersion.Platform == PlatformID.Win32S ||
System.Environment.OSVersion.Platform == PlatformID.Win32Windows ||
System.Environment.OSVersion.Platform == PlatformID.WinCE;
}
private static bool DetectX11()
{
// Detect whether X is present.
try { return OpenTK.Platform.X11.API.DefaultDisplay != IntPtr.Zero; }
catch { return false; }
}
// Detects the underlying OS and runtime.
internal static void Init(ToolkitOptions options)
{
lock (InitLock)
{
if (!initialized)
{
RunningOnMono = DetectMono();
RunningOnWindows = DetectWindows();
if (!RunningOnWindows)
{
DetectUnix(out runningOnUnix, out runningOnLinux, out runningOnMacOS);
}
if ((runningOnLinux) || options.Backend == PlatformBackend.PreferX11)
{
RunningOnX11 = DetectX11();
}
initialized = true;
Debug.Print("Detected configuration: {0} / {1}",
RunningOnWindows ? "Windows" : RunningOnLinux ? "Linux" : RunningOnMacOS ? "MacOS" :
runningOnUnix ? "Unix" : RunningOnX11 ? "X11" : "Unknown Platform",
RunningOnMono ? "Mono" : ".Net");
}
}
}
}
}

View file

@ -0,0 +1,127 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing detailed licensing details.
*/
using System;
namespace OpenTK
{
/// <summary>
/// Represents a handle to an OpenGL or OpenAL context.
/// </summary>
public struct ContextHandle : IComparable<ContextHandle>, IEquatable<ContextHandle>
{
private IntPtr handle;
/// <summary>
/// Gets a System.IntPtr that represents the handle of this ContextHandle.
/// </summary>
public IntPtr Handle { get { return handle; } }
/// <summary>A read-only field that represents a handle that has been initialized to zero.</summary>
public static readonly ContextHandle Zero = new ContextHandle(IntPtr.Zero);
/// <summary>
/// Constructs a new instance with the specified handle.
/// </summary>
/// <param name="h">A System.IntPtr containing the value for this instance.</param>
public ContextHandle(IntPtr h) { handle = h; }
/// <summary>
/// Converts this instance to its equivalent string representation.
/// </summary>
/// <returns>A System.String that contains the string representation of this instance.</returns>
public override string ToString()
{
return Handle.ToString();
}
/// <summary>
/// Compares this instance to the specified object.
/// </summary>
/// <param name="obj">The System.Object to compare to.</param>
/// <returns>True if obj is a ContextHandle that is equal to this instance; false otherwise.</returns>
public override bool Equals(object obj)
{
if (obj is ContextHandle)
{
return this.Equals((ContextHandle)obj);
}
return false;
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A System.Int32 with the hash code of this instance.</returns>
public override int GetHashCode()
{
return Handle.GetHashCode();
}
/// <summary>
/// Converts the specified ContextHandle to the equivalent IntPtr.
/// </summary>
/// <param name="c">The ContextHandle to convert.</param>
/// <returns>A System.IntPtr equivalent to the specified ContextHandle.</returns>
public static explicit operator IntPtr(ContextHandle c)
{
return c != ContextHandle.Zero ? c.handle : IntPtr.Zero;
}
/// <summary>
/// Converts the specified IntPtr to the equivalent ContextHandle.
/// </summary>
/// <param name="p">The System.IntPtr to convert.</param>
/// <returns>A ContextHandle equivalent to the specified IntPtr.</returns>
public static explicit operator ContextHandle(IntPtr p)
{
return new ContextHandle(p);
}
/// <summary>
/// Compares two ContextHandles for equality.
/// </summary>
/// <param name="left">The ContextHandle to compare.</param>
/// <param name="right">The ContextHandle to compare to.</param>
/// <returns>True if left is equal to right; false otherwise.</returns>
public static bool operator ==(ContextHandle left, ContextHandle right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two ContextHandles for inequality.
/// </summary>
/// <param name="left">The ContextHandle to compare.</param>
/// <param name="right">The ContextHandle to compare to.</param>
/// <returns>True if left is not equal to right; false otherwise.</returns>
public static bool operator !=(ContextHandle left, ContextHandle right)
{
return !left.Equals(right);
}
/// <summary>
/// Compares the numerical value of this instance to the specified ContextHandle and
/// returns a value indicating their relative order.
/// </summary>
/// <param name="other">The ContextHandle to compare to.</param>
/// <returns>Less than 0, if this instance is less than other; 0 if both are equal; Greater than 0 if other is greater than this instance.</returns>
public int CompareTo(ContextHandle other)
{
unsafe { return (int)((int*)other.handle.ToPointer() - (int*)this.handle.ToPointer()); }
}
/// <summary>
/// Compares this instance to the specified ContextHandle for equality.
/// </summary>
/// <param name="other">The ContextHandle to compare to.</param>
/// <returns>True if this instance is equal to other; false otherwise.</returns>
public bool Equals(ContextHandle other)
{
return Handle == other.Handle;
}
}
}

View file

@ -0,0 +1,445 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System;
using System.Collections.Generic;
using System.Drawing;
namespace OpenTK
{
/// <summary>
/// Defines a display device on the underlying system, and provides
/// methods to query and change its display parameters.
/// </summary>
public class DisplayDevice
{
// TODO: Add properties that describe the 'usable' size of the Display, i.e. the maximized size without the taskbar etc.
// TODO: Does not detect changes to primary device.
private bool primary;
private Rectangle bounds;
private DisplayResolution current_resolution = new DisplayResolution();
private List<DisplayResolution> available_resolutions = new List<DisplayResolution>();
private IList<DisplayResolution> available_resolutions_readonly;
internal object Id; // A platform-specific id for this monitor
private static readonly object display_lock = new object();
private static DisplayDevice primary_display;
private static Platform.IDisplayDeviceDriver implementation;
static DisplayDevice()
{
implementation = Platform.Factory.Default.CreateDisplayDeviceDriver();
}
internal DisplayDevice()
{
available_resolutions_readonly = available_resolutions.AsReadOnly();
}
internal DisplayDevice(DisplayResolution currentResolution, bool primary,
IEnumerable<DisplayResolution> availableResolutions, Rectangle bounds,
object id)
: this()
{
// Todo: Consolidate current resolution with bounds? Can they fall out of sync right now?
this.current_resolution = currentResolution;
IsPrimary = primary;
this.available_resolutions.AddRange(availableResolutions);
#pragma warning disable 612,618
this.bounds = bounds == Rectangle.Empty ? currentResolution.Bounds : bounds;
#pragma warning restore 612,618
this.Id = id;
}
/// <summary>
/// Gets the bounds of this instance in pixel coordinates..
/// </summary>
public Rectangle Bounds
{
get { return bounds; }
internal set
{
bounds = value;
current_resolution.Height = bounds.Height;
current_resolution.Width = bounds.Width;
}
}
/// <summary>Gets a System.Int32 that contains the width of this display in pixels.</summary>
public int Width { get { return current_resolution.Width; } }
/// <summary>Gets a System.Int32 that contains the height of this display in pixels.</summary>
public int Height { get { return current_resolution.Height; } }
/// <summary>Gets a System.Int32 that contains number of bits per pixel of this display. Typical values include 8, 16, 24 and 32.</summary>
public int BitsPerPixel
{
get { return current_resolution.BitsPerPixel; }
internal set { current_resolution.BitsPerPixel = value; }
}
/// <summary>
/// Gets a System.Single representing the vertical refresh rate of this display.
/// </summary>
public float RefreshRate
{
get { return current_resolution.RefreshRate; }
internal set { current_resolution.RefreshRate = value; }
}
/// <summary>Gets a System.Boolean that indicates whether this Display is the primary Display in systems with multiple Displays.</summary>
public bool IsPrimary
{
get { return primary; }
internal set
{
if (value && primary_display != null && primary_display != this)
{
primary_display.IsPrimary = false;
}
lock (display_lock)
{
primary = value;
if (value)
{
primary_display = this;
}
}
}
}
/// <summary>
/// Selects an available resolution that matches the specified parameters.
/// </summary>
/// <param name="width">The width of the requested resolution in pixels.</param>
/// <param name="height">The height of the requested resolution in pixels.</param>
/// <param name="bitsPerPixel">The bits per pixel of the requested resolution.</param>
/// <param name="refreshRate">The refresh rate of the requested resolution in hertz.</param>
/// <returns>The requested DisplayResolution or null if the parameters cannot be met.</returns>
/// <remarks>
/// <para>If a matching resolution is not found, this function will retry ignoring the specified refresh rate,
/// bits per pixel and resolution, in this order. If a matching resolution still doesn't exist, this function will
/// return the current resolution.</para>
/// <para>A parameter set to 0 or negative numbers will not be used in the search (e.g. if refreshRate is 0,
/// any refresh rate will be considered valid).</para>
/// <para>This function allocates memory.</para>
/// </remarks>
public DisplayResolution SelectResolution(int width, int height, int bitsPerPixel, float refreshRate)
{
DisplayResolution resolution = FindResolution(width, height, bitsPerPixel, refreshRate);
if (resolution == null)
{
resolution = FindResolution(width, height, bitsPerPixel, 0);
}
if (resolution == null)
{
resolution = FindResolution(width, height, 0, 0);
}
if (resolution == null)
{
return current_resolution;
}
return resolution;
}
/// <summary>
/// Gets the list of <see cref="DisplayResolution"/> objects available on this device.
/// </summary>
public IList<DisplayResolution> AvailableResolutions
{
get { return available_resolutions_readonly; }
internal set
{
available_resolutions = (List<DisplayResolution>)value;
available_resolutions_readonly = available_resolutions.AsReadOnly();
}
}
/// <summary>Changes the resolution of the DisplayDevice.</summary>
/// <param name="resolution">The resolution to set. <see cref="DisplayDevice.SelectResolution"/></param>
/// <exception cref="Graphics.GraphicsModeException">Thrown if the requested resolution could not be set.</exception>
/// <remarks>If the specified resolution is null, this function will restore the original DisplayResolution.</remarks>
public void ChangeResolution(DisplayResolution resolution)
{
if (resolution == null)
{
this.RestoreResolution();
}
if (resolution == current_resolution)
{
return;
}
//effect.FadeOut();
if (implementation.TryChangeResolution(this, resolution))
{
if (OriginalResolution == null)
{
OriginalResolution = current_resolution;
}
current_resolution = resolution;
}
else
{
throw new Graphics.GraphicsModeException(String.Format("Device {0}: Failed to change resolution to {1}.",
this, resolution));
}
//effect.FadeIn();
}
/// <summary>Changes the resolution of the DisplayDevice.</summary>
/// <param name="width">The new width of the DisplayDevice.</param>
/// <param name="height">The new height of the DisplayDevice.</param>
/// <param name="bitsPerPixel">The new bits per pixel of the DisplayDevice.</param>
/// <param name="refreshRate">The new refresh rate of the DisplayDevice.</param>
/// <exception cref="Graphics.GraphicsModeException">Thrown if the requested resolution could not be set.</exception>
public void ChangeResolution(int width, int height, int bitsPerPixel, float refreshRate)
{
this.ChangeResolution(this.SelectResolution(width, height, bitsPerPixel, refreshRate));
}
/// <summary>Restores the original resolution of the DisplayDevice.</summary>
/// <exception cref="Graphics.GraphicsModeException">Thrown if the original resolution could not be restored.</exception>
public void RestoreResolution()
{
if (OriginalResolution != null)
{
//effect.FadeOut();
if (implementation.TryRestoreResolution(this))
{
current_resolution = OriginalResolution;
OriginalResolution = null;
}
else
{
throw new Graphics.GraphicsModeException(String.Format("Device {0}: Failed to restore resolution.", this));
}
//effect.FadeIn();
}
}
/// <summary>Gets the default (primary) display of this system.</summary>
public static DisplayDevice Default
{
get { return implementation.GetDisplay(DisplayIndex.Primary); }
}
/// <summary>
/// Gets the <see cref="DisplayDevice"/> for the specified <see cref="DisplayIndex"/>.
/// </summary>
/// <param name="index">The <see cref="DisplayIndex"/> that defines the desired display.</param>
/// <returns>A <see cref="DisplayDevice"/> or null, if no device corresponds to the specified index.</returns>
public static DisplayDevice GetDisplay(DisplayIndex index)
{
return implementation.GetDisplay(index);
}
/// <summary>
/// Gets the original resolution of this instance.
/// </summary>
internal DisplayResolution OriginalResolution { get; set; }
internal static DisplayDevice FromPoint(int x, int y)
{
for (DisplayIndex i = DisplayIndex.First; i < DisplayIndex.Sixth; i++)
{
DisplayDevice display = DisplayDevice.GetDisplay(i);
if (display != null)
{
if (display.Bounds.Contains(x, y))
{
return display;
}
}
}
return null;
}
private DisplayResolution FindResolution(int width, int height, int bitsPerPixel, float refreshRate)
{
return available_resolutions.Find(delegate(DisplayResolution test)
{
return
((width > 0 && width == test.Width) || width == 0) &&
((height > 0 && height == test.Height) || height == 0) &&
((bitsPerPixel > 0 && bitsPerPixel == test.BitsPerPixel) || bitsPerPixel == 0) &&
((refreshRate > 0 && System.Math.Abs(refreshRate - test.RefreshRate) < 1.0) || refreshRate == 0);
});
}
/// <summary>
/// Returns a System.String representing this DisplayDevice.
/// </summary>
/// <returns>A System.String representing this DisplayDevice.</returns>
public override string ToString()
{
return String.Format("{0}: {1} ({2} modes available)", IsPrimary ? "Primary" : "Secondary",
Bounds.ToString(), available_resolutions.Count);
}
///// <summary>Determines whether the specified DisplayDevices are equal.</summary>
///// <param name="obj">The System.Object to check against.</param>
///// <returns>True if the System.Object is an equal DisplayDevice; false otherwise.</returns>
//public override bool Equals(object obj)
//{
// if (obj is DisplayDevice)
// {
// DisplayDevice dev = (DisplayDevice)obj;
// return
// IsPrimary == dev.IsPrimary &&
// current_resolution == dev.current_resolution &&
// available_resolutions.Count == dev.available_resolutions.Count;
// }
// return false;
//}
///// <summary>Returns a unique hash representing this DisplayDevice.</summary>
///// <returns>A System.Int32 that may serve as a hash code for this DisplayDevice.</returns>
////public override int GetHashCode()
//{
// return current_resolution.GetHashCode() ^ IsPrimary.GetHashCode() ^ available_resolutions.Count;
//}
}
#if false
class FadeEffect : IDisposable
{
List<Form> forms = new List<Form>();
double opacity_step = 0.04;
int sleep_step;
internal FadeEffect()
{
foreach (Screen s in Screen.AllScreens)
{
Form form = new Form();
form.ShowInTaskbar = false;
form.StartPosition = FormStartPosition.Manual;
form.WindowState = FormWindowState.Maximized;
form.FormBorderStyle = FormBorderStyle.None;
form.TopMost = true;
form.BackColor = System.Drawing.Color.Black;
forms.Add(form);
}
sleep_step = 10 / forms.Count;
MoveToStartPositions();
}
void MoveToStartPositions()
{
int count = 0;
foreach (Screen s in Screen.AllScreens)
{
// forms[count++].Location = new System.Drawing.Point(s.Bounds.X, s.Bounds.Y);
//forms[count].Size = new System.Drawing.Size(4096, 4096);
count++;
}
}
bool FadedOut
{
get
{
bool ready = true;
foreach (Form form in forms)
ready = ready && form.Opacity >= 1.0;
return ready;
}
}
bool FadedIn
{
get
{
bool ready = true;
foreach (Form form in forms)
ready = ready && form.Opacity <= 0.0;
return ready;
}
}
internal void FadeOut()
{
MoveToStartPositions();
foreach (Form form in forms)
{
form.Opacity = 0.0;
form.Visible = true;
}
while (!FadedOut)
{
foreach (Form form in forms)
{
form.Opacity += opacity_step;
form.Refresh();
}
Thread.Sleep(sleep_step);
}
}
internal void FadeIn()
{
MoveToStartPositions();
foreach (Form form in forms)
form.Opacity = 1.0;
while (!FadedIn)
{
foreach (Form form in forms)
{
form.Opacity -= opacity_step;
form.Refresh();
}
Thread.Sleep(sleep_step);
}
foreach (Form form in forms)
form.Visible = false;
}
public void Dispose()
{
foreach (Form form in forms)
form.Dispose();
}
}
#endif
}

View file

@ -0,0 +1,66 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
namespace OpenTK
{
/// <summary>
/// Defines <see cref="DisplayDevice"/> indices.
/// </summary>
public enum DisplayIndex
{
/// <summary>
/// The first DisplayDevice.
/// </summary>
First = 0,
/// <summary>
/// The second DisplayDevice.
/// </summary>
Second,
/// <summary>
/// The third DisplayDevice.
/// </summary>
Third,
/// <summary>
/// The fourth DisplayDevice.
/// </summary>
Fourth,
/// <summary>
/// The fifth DisplayDevice.
/// </summary>
Fifth,
/// <summary>
/// The sixth DisplayDevice.
/// </summary>
Sixth,
/// <summary>
/// The default (primary) DisplayDevice.
/// </summary>
Primary = -1,
/// <summary>
/// The default (primary) DisplayDevice.
/// </summary>
Default = Primary,
}
}

View file

@ -0,0 +1,179 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK team.
* This notice may not be removed.
* See license.txt for licensing detailed licensing details.
*/
using System;
using System.Drawing;
namespace OpenTK
{
/// <summary>Contains information regarding a monitor's display resolution.</summary>
public class DisplayResolution
{
private Rectangle bounds;
internal DisplayResolution() { }
// Creates a new DisplayResolution object for the primary DisplayDevice.
internal DisplayResolution(int x, int y, int width, int height, int bitsPerPixel, float refreshRate)
{
// Refresh rate may be zero, since this information may not be available on some platforms.
if (width <= 0)
{
throw new ArgumentOutOfRangeException("width", "Must be greater than zero.");
}
if (height <= 0)
{
throw new ArgumentOutOfRangeException("height", "Must be greater than zero.");
}
if (bitsPerPixel <= 0)
{
throw new ArgumentOutOfRangeException("bitsPerPixel", "Must be greater than zero.");
}
if (refreshRate < 0)
{
throw new ArgumentOutOfRangeException("refreshRate", "Must be greater than, or equal to zero.");
}
this.bounds = new Rectangle(x, y, width, height);
this.BitsPerPixel = bitsPerPixel;
this.RefreshRate = refreshRate;
}
#if false
/// <summary>
/// Creates a new DisplayResolution object for the specified DisplayDevice.
/// </summary>
/// <param name="width">The requested width in pixels.</param>
/// <param name="height">The requested height in pixels.</param>
/// <param name="bitsPerPixel">The requested bits per pixel in bits.</param>
/// <param name="refreshRate">The requested refresh rate in hertz.</param>
/// <remarks>OpenTK will select the closest match between all available resolutions on the specified DisplayDevice.</remarks>
///
public DisplayResolution(int width, int height, int bitsPerPixel, float refreshRate, DisplayDevice device)
{
// Refresh rate may be zero, since this information may not be available on some platforms.
if (width <= 0) throw new ArgumentOutOfRangeException("width", "Must be greater than zero.");
if (height <= 0) throw new ArgumentOutOfRangeException("height", "Must be greater than zero.");
if (bitsPerPixel <= 0) throw new ArgumentOutOfRangeException("bitsPerPixel", "Must be greater than zero.");
if (refreshRate < 0) throw new ArgumentOutOfRangeException("refreshRate", "Must be greater than, or equal to zero.");
if (device == null) throw new ArgumentNullException("DisplayDevice", "Must be a valid DisplayDevice");
DisplayResolution res = device.SelectResolution(width, height, bitsPerPixel, refreshRate);
this.width = res.width;
this.height = res.height;
this.bits_per_pixel = res.bits_per_pixel;
this.refresh_rate = res.refresh_rate;
}
#endif
/// <summary>
/// Gets a System.Drawing.Rectangle that contains the bounds of this display device.
/// </summary>
[Obsolete("This property will return invalid results if a monitor changes resolution. Use DisplayDevice.Bounds instead.")]
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public Rectangle Bounds
{
get { return bounds; }
}
/// <summary>Gets a System.Int32 that contains the width of this display in pixels.</summary>
public int Width
{
get { return bounds.Width; }
internal set { bounds.Width = value; }
}
/// <summary>Gets a System.Int32 that contains the height of this display in pixels.</summary>
public int Height
{
get { return bounds.Height; }
internal set { bounds.Height = value; }
}
/// <summary>Gets a System.Int32 that contains number of bits per pixel of this display. Typical values include 8, 16, 24 and 32.</summary>
public int BitsPerPixel { get; internal set; }
/// <summary>
/// Gets a System.Single representing the vertical refresh rate of this display.
/// </summary>
public float RefreshRate { get; internal set; }
/// <summary>
/// Returns a System.String representing this DisplayResolution.
/// </summary>
/// <returns>A System.String representing this DisplayResolution.</returns>
public override string ToString()
{
#pragma warning disable 612,618
return String.Format("{0}x{1}@{2}Hz", Bounds, BitsPerPixel, RefreshRate);
#pragma warning restore 612,618
}
/// <summary>Determines whether the specified resolutions are equal.</summary>
/// <param name="obj">The System.Object to check against.</param>
/// <returns>True if the System.Object is an equal DisplayResolution; false otherwise.</returns>
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (this.GetType() == obj.GetType())
{
DisplayResolution res = (DisplayResolution)obj;
return
Width == res.Width &&
Height == res.Height &&
BitsPerPixel == res.BitsPerPixel &&
RefreshRate == res.RefreshRate;
}
return false;
}
/// <summary>Returns a unique hash representing this resolution.</summary>
/// <returns>A System.Int32 that may serve as a hash code for this resolution.</returns>
public override int GetHashCode()
{
#pragma warning disable 612,618
return Bounds.GetHashCode() ^ BitsPerPixel ^ RefreshRate.GetHashCode();
#pragma warning restore 612,618
}
/// <summary>
/// Compares two instances for equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns>True, if left equals right; false otherwise.</returns>
public static bool operator== (DisplayResolution left, DisplayResolution right)
{
if (((object)left) == null && ((object)right) == null)
{
return true;
}
else if ((((object)left) == null && ((object)right) != null) ||
(((object)left) != null && ((object)right) == null))
{
return false;
}
return left.Equals(right);
}
/// <summary>
/// Compares two instances for inequality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns>True, if left does not equal right; false otherwise.</returns>
public static bool operator !=(DisplayResolution left, DisplayResolution right)
{
return !(left == right);
}
}
}

View file

@ -0,0 +1,50 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
namespace OpenTK
{
/// <summary>
/// This exception is thrown when a GraphicsContext property cannot be changed after creation.
/// </summary>
public class ContextExistsException : ApplicationException
{
/// <summary>
/// Constructs a new ContextExistsException instance.
/// </summary>
/// <param name="message">A System.String explaining the cause of this exception.</param>
public ContextExistsException(string message)
{
Message = message;
}
/// <summary>
/// Gets a System.String explaining the cause of this exception.
/// </summary>
public override string Message { get; }
}
}

View file

@ -0,0 +1,281 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System;
namespace OpenTK.Graphics
{
/// <summary>Defines the ColorFormat component of a GraphicsMode.</summary>
/// <remarks>
/// <para>A ColorFormat contains Red, Green, Blue and Alpha components that descibe
/// the allocated bits per pixel for the corresponding color.</para>
/// </remarks>
public struct ColorFormat : IComparable<ColorFormat>, IEquatable<ColorFormat>
{
private byte red, green, blue, alpha;
/// <summary>
/// Constructs a new ColorFormat with the specified aggregate bits per pixel.
/// </summary>
/// <param name="bpp">The bits per pixel sum for the Red, Green, Blue and Alpha color channels.</param>
public ColorFormat(int bpp)
{
if (bpp < 0)
{
throw new ArgumentOutOfRangeException("bpp", "Must be greater or equal to zero.");
}
red = green = blue = alpha = 0;
BitsPerPixel = bpp;
IsIndexed = false;
switch (bpp)
{
case 32:
Red = Green = Blue = Alpha = 8;
break;
case 24:
Red = Green = Blue = 8;
break;
case 16:
Red = Blue = 5;
Green = 6;
break;
case 15:
Red = Green = Blue = 5;
break;
case 8:
Red = Green = 3;
Blue = 2;
IsIndexed = true;
break;
case 4:
Red = Green = 2;
Blue = 1;
IsIndexed = true;
break;
case 1:
IsIndexed = true;
break;
default:
Red = Blue = Alpha = (byte)(bpp / 4);
Green = (byte)((bpp / 4) + (bpp % 4));
break;
}
}
/// <summary>
/// Constructs a new ColorFormat with the specified bits per pixel for
/// the Red, Green, Blue and Alpha color channels.
/// </summary>
/// <param name="red">Bits per pixel for the Red color channel.</param>
/// <param name="green">Bits per pixel for the Green color channel.</param>
/// <param name="blue">Bits per pixel for the Blue color channel.</param>
/// <param name="alpha">Bits per pixel for the Alpha color channel.</param>
public ColorFormat(int red, int green, int blue, int alpha)
{
if (red < 0 || green < 0 || blue < 0 || alpha < 0)
{
throw new ArgumentOutOfRangeException("Arguments must be greater or equal to zero.");
}
this.red = (byte)red;
this.green = (byte)green;
this.blue = (byte)blue;
this.alpha = (byte)alpha;
this.BitsPerPixel = red + green + blue + alpha;
this.IsIndexed = false;
if (this.BitsPerPixel < 15 && this.BitsPerPixel != 0)
{
this.IsIndexed = true;
}
}
/// <summary>Gets the bits per pixel for the Red channel.</summary>
public int Red { get { return red; } private set { red = (byte)value; } }
/// <summary>Gets the bits per pixel for the Green channel.</summary>
public int Green { get { return green; } private set { green = (byte)value; } }
/// <summary>Gets the bits per pixel for the Blue channel.</summary>
public int Blue { get { return blue; } private set { blue = (byte)value; } }
/// <summary>Gets the bits per pixel for the Alpha channel.</summary>
public int Alpha { get { return alpha; } private set { alpha = (byte)value; } }
/// <summary>Gets a System.Boolean indicating whether this ColorFormat is indexed.</summary>
public bool IsIndexed { get; private set; }
/// <summary>Gets the sum of Red, Green, Blue and Alpha bits per pixel.</summary>
public int BitsPerPixel { get; private set; }
/// <summary>
/// Defines an empty ColorFormat, where all properties are set to zero.
/// </summary>
public static readonly ColorFormat Empty = new ColorFormat(0);
/// <summary>
/// Converts the specified bpp into a new ColorFormat.
/// </summary>
/// <param name="bpp">The bits per pixel to convert.</param>
/// <returns>A ColorFormat with the specified bits per pixel.</returns>
public static implicit operator ColorFormat(int bpp)
{
return new ColorFormat(bpp);
}
//public static implicit operator int(ColorFormat mode)
//{
// return mode.BitsPerPixel;
//}
/// <summary>
/// Compares two instances.
/// </summary>
/// <param name="other">The other instance.</param>
/// <returns>
/// Zero if this instance is equal to other;
/// a positive value if this instance is greater than other;
/// a negative value otherwise.
/// </returns>
public int CompareTo(ColorFormat other)
{
int result = BitsPerPixel.CompareTo(other.BitsPerPixel);
if (result != 0)
{
return result;
}
result = IsIndexed.CompareTo(other.IsIndexed);
if (result != 0)
{
return result;
}
result = Alpha.CompareTo(other.Alpha);
return result;
}
/// <summary>
/// Compares whether this ColorFormat structure is equal to the specified ColorFormat.
/// </summary>
/// <param name="other">The ColorFormat structure to compare to.</param>
/// <returns>True if both ColorFormat structures contain the same components; false otherwise.</returns>
public bool Equals(ColorFormat other)
{
return
Red == other.Red &&
Green == other.Green &&
Blue == other.Blue &&
Alpha == other.Alpha;
}
/// <summary>
/// Indicates whether this instance and a specified object are equal.
/// </summary>
/// <param name="obj">Another object to compare to.</param>
/// <returns>True if this instance is equal to obj; false otherwise.</returns>
public override bool Equals(object obj)
{
return (obj is ColorFormat) ? this.Equals((ColorFormat)obj) : false;
}
/// <summary>
/// Compares two instances for equality.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>True if both instances are equal; false otherwise.</returns>
public static bool operator ==(ColorFormat left, ColorFormat right)
{
return left.Equals(right);
}
/// <summary>
/// Compares two instances for inequality.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>True if both instances are not equal; false otherwise.</returns>
public static bool operator !=(ColorFormat left, ColorFormat right)
{
return !(left == right);
}
/// <summary>
/// Compares two instances for inequality.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>True if left is greater than right; false otherwise.</returns>
public static bool operator >(ColorFormat left, ColorFormat right)
{
return left.CompareTo(right) > 0;
}
/// <summary>
/// Compares two instances for inequality.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>True if left is greater than or equal to right; false otherwise.</returns>
public static bool operator >=(ColorFormat left, ColorFormat right)
{
return left.CompareTo(right) >= 0;
}
/// <summary>
/// Compares two instances for inequality.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>True if left is less than right; false otherwise.</returns>
public static bool operator <(ColorFormat left, ColorFormat right)
{
return left.CompareTo(right) < 0;
}
/// <summary>
/// Compares two instances for inequality.
/// </summary>
/// <param name="left">The left operand.</param>
/// <param name="right">The right operand.</param>
/// <returns>True if left is less than or equal to right; false otherwise.</returns>
public static bool operator <=(ColorFormat left, ColorFormat right)
{
return left.CompareTo(right) <= 0;
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A System.Int32 with the hash code of this instance.</returns>
public override int GetHashCode()
{
return Red ^ Green ^ Blue ^ Alpha;
}
/// <summary>
/// Returns a <see cref="System.String"/> that describes this instance.
/// </summary>
/// <returns>A <see cref="System.String"/> that describes this instance.</returns>
public override string ToString()
{
return string.Format("{0} ({1})", BitsPerPixel, (IsIndexed ? " indexed" : Red.ToString() + Green.ToString() + Blue.ToString() + Alpha.ToString()));
}
}
}

View file

@ -0,0 +1,94 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using System.Diagnostics;
using OpenTK;
namespace OpenTK.Graphics
{
/// <summary>
/// Implements BindingsBase for the OpenTK.Graphics namespace (OpenGL and OpenGL|ES).
/// </summary>
public abstract class GraphicsBindingsBase : LegacyBindingsBase
{
internal IntPtr[] _EntryPointsInstance;
internal byte[] _EntryPointNamesInstance;
internal int[] _EntryPointNameOffsetsInstance;
/// <summary>
/// Retrieves an unmanaged function pointer to the specified function.
/// </summary>
/// <param name="funcname">
/// A <see cref="System.String"/> that defines the name of the function.
/// </param>
/// <returns>
/// A <see cref="IntPtr"/> that contains the address of funcname or IntPtr.Zero,
/// if the function is not supported by the drivers.
/// </returns>
/// <remarks>
/// Note: some drivers are known to return non-zero values for unsupported functions.
/// Typical values include 1 and 2 - inheritors are advised to check for and ignore these
/// values.
/// </remarks>
public override IntPtr GetAddress(string funcname)
{
var context = GraphicsContext.CurrentContext as IGraphicsContextInternal;
if (context == null)
{
throw new GraphicsContextMissingException();
}
return context != null ? context.GetAddress(funcname) : IntPtr.Zero;
}
// Loads all available entry points for the current API.
// Note: we prefer IGraphicsContextInternal.GetAddress over
// this.GetAddress to improve loading performance (less
// validation necessary.)
internal override void LoadEntryPoints()
{
Debug.Print("Loading entry points for {0}", GetType().FullName);
IGraphicsContext context = GraphicsContext.CurrentContext;
if (context == null)
{
throw new GraphicsContextMissingException();
}
IGraphicsContextInternal context_internal = context as IGraphicsContextInternal;
unsafe
{
fixed (byte* name = _EntryPointNamesInstance)
{
for (int i = 0; i < _EntryPointsInstance.Length; i++)
{
_EntryPointsInstance[i] = context_internal.GetAddress(
new IntPtr(name + _EntryPointNameOffsetsInstance[i]));
}
}
}
}
}
}

View file

@ -0,0 +1,620 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2013 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.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenTK.Platform;
namespace OpenTK.Graphics
{
/// <summary>
/// Represents and provides methods to manipulate an OpenGL render context.
/// </summary>
public sealed class GraphicsContext : IGraphicsContext, IGraphicsContextInternal
{
/// <summary>
/// Used to retrive function pointers by name.
/// </summary>
/// <param name="function">The function name.</param>
/// <returns>A function pointer to <paramref name="function"/>, or <c>IntPtr.Zero</c></returns>
public delegate IntPtr GetAddressDelegate(string function);
/// <summary>
/// Used to return the handel of the current OpenGL context.
/// </summary>
/// <returns>The current OpenGL context, or <c>IntPtr.Zero</c> if no context is on the calling thread.</returns>
public delegate ContextHandle GetCurrentContextDelegate();
private IGraphicsContext implementation; // The actual render context implementation for the underlying platform.
private bool disposed;
// Cache for the context handle. We need this for RemoveContext()
// in case the user does not call Dispose(). When this happens,
// RemoveContext() is called by the finalizer, in which case
// the IGraphicsContext implementation may already be null
// (hence we cannot call implementation.Context to retrieve
// the handle.)
private ContextHandle handle_cached;
private readonly static object SyncRoot = new object();
// Maps OS-specific context handles to GraphicsContext instances.
private readonly static Dictionary<ContextHandle, IGraphicsContext> available_contexts =
new Dictionary<ContextHandle, IGraphicsContext>();
/// <summary>
/// Constructs a new GraphicsContext with the specified GraphicsMode and attaches it to the specified window.
/// </summary>
/// <param name="mode">The OpenTK.Graphics.GraphicsMode of the GraphicsContext.</param>
/// <param name="window">The OpenTK.Platform.IWindowInfo to attach the GraphicsContext to.</param>
public GraphicsContext(GraphicsMode mode, IWindowInfo window)
: this(mode, window, 1, 0, GraphicsContextFlags.Default)
{ }
/// <summary>
/// Constructs a new GraphicsContext with the specified GraphicsMode, version and flags, and attaches it to the specified window.
/// </summary>
/// <param name="mode">The OpenTK.Graphics.GraphicsMode of the GraphicsContext.</param>
/// <param name="window">The OpenTK.Platform.IWindowInfo to attach the GraphicsContext to.</param>
/// <param name="major">The major version of the new GraphicsContext.</param>
/// <param name="minor">The minor version of the new GraphicsContext.</param>
/// <param name="flags">The GraphicsContextFlags for the GraphicsContext.</param>
/// <remarks>
/// Different hardware supports different flags, major and minor versions. Invalid parameters will be silently ignored.
/// </remarks>
public GraphicsContext(GraphicsMode mode, IWindowInfo window, int major, int minor, GraphicsContextFlags flags)
: this(mode, window, FindSharedContext(), major, minor, flags)
{
}
/// <summary>
/// Constructs a new GraphicsContext with the specified GraphicsMode, version and flags, and attaches it to the specified window. A dummy context will be created if both
/// the handle and the window are null.
/// </summary>
/// <param name="mode">The OpenTK.Graphics.GraphicsMode of the GraphicsContext.</param>
/// <param name="window">The OpenTK.Platform.IWindowInfo to attach the GraphicsContext to.</param>
/// <param name="shareContext">The GraphicsContext to share resources with, or null for explicit non-sharing.</param>
/// <param name="major">The major version of the new GraphicsContext.</param>
/// <param name="minor">The minor version of the new GraphicsContext.</param>
/// <param name="flags">The GraphicsContextFlags for the GraphicsContext.</param>
/// <remarks>
/// Different hardware supports different flags, major and minor versions. Invalid parameters will be silently ignored.
/// </remarks>
public GraphicsContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags)
{
lock (SyncRoot)
{
bool designMode = false;
if (mode == null && window == null)
{
designMode = true;
}
else if (mode == null)
{
throw new ArgumentNullException("mode", "Must be a valid GraphicsMode.");
}
else if (window == null)
{
throw new ArgumentNullException("window", "Must point to a valid window.");
}
// Silently ignore invalid major and minor versions.
if (major <= 0)
{
major = 1;
}
if (minor < 0)
{
minor = 0;
}
// Angle needs an embedded context
const GraphicsContextFlags useAngleFlag = GraphicsContextFlags.Angle
| GraphicsContextFlags.AngleD3D9
| GraphicsContextFlags.AngleD3D11
| GraphicsContextFlags.AngleOpenGL;
var useAngle = false;
if ((flags & useAngleFlag) != 0)
{
flags |= GraphicsContextFlags.Embedded;
useAngle = true;
}
Debug.Print("Creating GraphicsContext.");
try
{
Debug.Indent();
Debug.Print("GraphicsMode: {0}", mode);
Debug.Print("IWindowInfo: {0}", window);
Debug.Print("GraphicsContextFlags: {0}", flags);
Debug.Print("Requested version: {0}.{1}", major, minor);
// Todo: Add a DummyFactory implementing IPlatformFactory.
if (designMode)
{
implementation = new Platform.Dummy.DummyGLContext();
}
else
{
IPlatformFactory factory = null;
switch ((flags & GraphicsContextFlags.Embedded) == GraphicsContextFlags.Embedded)
{
case false:
factory = Factory.Default;
break;
case true:
factory = useAngle ? Factory.Angle : Factory.Embedded;
break;
}
// Note: this approach does not allow us to mix native and EGL contexts in the same process.
// This should not be a problem, as this use-case is not interesting for regular applications.
// Note 2: some platforms may not support a direct way of getting the current context
// (this happens e.g. with DummyGLContext). In that case, we use a slow fallback which
// iterates through all known contexts and checks if any is current (check GetCurrentContext
// declaration).
if (GetCurrentContext == null)
{
GetCurrentContext = factory.CreateGetCurrentGraphicsContext();
}
implementation = factory.CreateGLContext(mode, window, shareContext, DirectRendering, major, minor, flags);
handle_cached = ((IGraphicsContextInternal)implementation).Context;
factory.RegisterResource(this);
}
AddContext(this);
}
finally
{
Debug.Unindent();
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="OpenTK.Graphics.GraphicsContext"/> class using
/// an external context handle that was created by a third-party library.
/// </summary>
/// <param name="handle">
/// A valid, unique handle for an external OpenGL context, or <c>ContextHandle.Zero</c> to use the current context.
/// It is an error to specify a handle that has been created through OpenTK or that has been passed to OpenTK before.
/// </param>
/// <param name="getAddress">
/// A <c>GetAddressDelegate</c> instance that accepts the name of an OpenGL function and returns
/// a valid function pointer, or <c>IntPtr.Zero</c> if that function is not supported. This delegate should be
/// implemented using the same toolkit that created the OpenGL context (i.e. if the context was created with
/// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetProcAddress() to retrieve function
/// pointers.)
/// </param>
/// <param name="getCurrent">
/// A <c>GetCurrentContextDelegate</c> instance that returns the handle of the current OpenGL context,
/// or <c>IntPtr.Zero</c> if no context is current on the calling thread. This delegate should be implemented
/// using the same toolkit that created the OpenGL context (i.e. if the context was created with
/// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetCurrentContext() to retrieve
/// the current context.)
/// </param>
public GraphicsContext(ContextHandle handle, GetAddressDelegate getAddress, GetCurrentContextDelegate getCurrent)
{
if (getAddress == null || getCurrent == null)
{
throw new ArgumentNullException();
}
lock (SyncRoot)
{
// Replace a zero-handle by the current context, if any
if (handle == ContextHandle.Zero)
{
handle = getCurrent();
}
// Make sure this handle corresponds to a valid, unique OpenGL context
if (handle == ContextHandle.Zero)
{
throw new GraphicsContextMissingException();
}
else if (available_contexts.ContainsKey(handle))
{
throw new InvalidOperationException("Context handle has already been added");
}
// We have a valid handle for an external OpenGL context, wrap it into a
// DummyGLContext instance.
implementation = new Platform.Dummy.DummyGLContext(handle, getAddress);
GetCurrentContext = getCurrent ?? GetCurrentContext;
AddContext(this);
}
implementation.LoadAll();
}
/// <summary>
/// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. A dummy context will be created if both
/// the handle and the window are null.
/// </summary>
/// <param name="handle">The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK.</param>
/// <param name="window">This parameter is reserved.</param>
public GraphicsContext(ContextHandle handle, IWindowInfo window)
: this(handle, window, null, 1, 0, GraphicsContextFlags.Default)
{ }
/// <summary>
/// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK.
/// </summary>
/// <param name="handle">The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK.</param>
/// <param name="window">This parameter is reserved.</param>
/// <param name="shareContext">This parameter is reserved.</param>
/// <param name="major">This parameter is reserved.</param>
/// <param name="minor">This parameter is reserved.</param>
/// <param name="flags">This parameter is reserved..</param>
public GraphicsContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags)
: this(handle, Platform.Utilities.CreateGetAddress(), Factory.Default.CreateGetCurrentGraphicsContext())
{ }
/// <summary>
/// Returns a <see cref="System.String"/> representing this instance.
/// </summary>
/// <returns>A <see cref="System.String"/> that contains a string representation of this instance.</returns>
public override string ToString()
{
return (this as IGraphicsContextInternal).Context.ToString();
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A System.Int32 with the hash code of this instance.</returns>
public override int GetHashCode()
{
return (this as IGraphicsContextInternal).Context.GetHashCode();
}
/// <summary>
/// Compares two instances.
/// </summary>
/// <param name="obj">The instance to compare to.</param>
/// <returns>True, if obj is equal to this instance; false otherwise.</returns>
public override bool Equals(object obj)
{
return (obj is GraphicsContext) &&
(this as IGraphicsContextInternal).Context == (obj as IGraphicsContextInternal).Context;
}
private static void AddContext(IGraphicsContextInternal context)
{
ContextHandle ctx = context.Context;
if (!available_contexts.ContainsKey(ctx))
{
available_contexts.Add(ctx, (IGraphicsContext)context);
}
else
{
Debug.Print("A GraphicsContext with handle {0} already exists.", ctx);
Debug.Print("Did you forget to call Dispose()?");
available_contexts[ctx] = (IGraphicsContext)context;
}
}
private static void RemoveContext(IGraphicsContextInternal context)
{
ContextHandle ctx = context.Context;
if (available_contexts.ContainsKey(ctx))
{
available_contexts.Remove(ctx);
}
else
{
Debug.Print("Tried to remove non-existent GraphicsContext handle {0}. Call Dispose() to avoid this error.", ctx);
}
}
private static IGraphicsContext FindSharedContext()
{
if (GraphicsContext.ShareContexts)
{
// A small hack to create a shared context with the first available context.
foreach (IGraphicsContext target in GraphicsContext.available_contexts.Values)
{
// Fix for bug 1874: if a GraphicsContext gets finalized
// (but not disposed), it won't be removed from available_contexts
// making this return null even if another valid context exists.
// The workaround is to simply ignore null targets.
if (target != null)
{
return target;
}
}
}
return null;
}
/// <summary>
/// Checks if a GraphicsContext exists in the calling thread and throws a GraphicsContextMissingException if it doesn't.
/// </summary>
/// <exception cref="GraphicsContextMissingException">Generated when no GraphicsContext is current in the calling thread.</exception>
public static void Assert()
{
if (GraphicsContext.CurrentContext == null)
{
throw new GraphicsContextMissingException();
}
}
internal static GetCurrentContextDelegate GetCurrentContext;
/// <summary>
/// Gets the handle of the current GraphicsContext in the calling thread.
/// </summary>
public static ContextHandle CurrentContextHandle
{
get { return GetCurrentContext(); }
}
/// <summary>
/// Gets the GraphicsContext that is current in the calling thread.
/// </summary>
/// <remarks>
/// Note: this property will not function correctly when both desktop and EGL contexts are
/// available in the same process. This scenario is very unlikely to appear in practice.
/// </remarks>
public static IGraphicsContext CurrentContext
{
get
{
lock (SyncRoot)
{
if (available_contexts.Count > 0)
{
ContextHandle handle = CurrentContextHandle;
if (handle.Handle != IntPtr.Zero)
{
return (IGraphicsContext)available_contexts[handle];
}
}
return null;
}
}
}
/// <summary>Gets or sets a System.Boolean, indicating whether GraphicsContext resources are shared</summary>
/// <remarks>
/// <para>If ShareContexts is true, new GLContexts will share resources. If this value is
/// false, new GLContexts will not share resources.</para>
/// <para>Changing this value will not affect already created GLContexts.</para>
/// </remarks>
public static bool ShareContexts { get; set; } = true;
/// <summary>Gets or sets a System.Boolean, indicating whether GraphicsContexts will perform direct rendering.</summary>
/// <remarks>
/// <para>
/// If DirectRendering is true, new contexts will be constructed with direct rendering capabilities, if possible.
/// If DirectRendering is false, new contexts will be constructed with indirect rendering capabilities.
/// </para>
/// <para>This property does not affect existing GraphicsContexts, unless they are recreated.</para>
/// <para>
/// This property is ignored on Operating Systems without support for indirect rendering, like Windows and OS X.
/// </para>
/// </remarks>
public static bool DirectRendering { get; set; } = true;
/// <summary>
/// Gets or sets a System.Boolean, indicating whether automatic error checking should be performed.
/// Influences the debug version of OpenTK.dll, only.
/// </summary>
/// <remarks>Automatic error checking will clear the OpenGL error state. Set CheckErrors to false if you use
/// the OpenGL error state in your code flow (e.g. for checking supported texture formats).</remarks>
public bool ErrorChecking { get; set; } = true;
/// <summary>
/// Swaps buffers on a context. This presents the rendered scene to the user.
/// </summary>
public void SwapBuffers()
{
implementation.SwapBuffers();
}
/// <summary>
/// Makes the GraphicsContext the current rendering target.
/// </summary>
/// <param name="window">A valid <see cref="OpenTK.Platform.IWindowInfo" /> structure.</param>
/// <remarks>
/// You can use this method to bind the GraphicsContext to a different window than the one it was created from.
/// </remarks>
public void MakeCurrent(IWindowInfo window)
{
implementation.MakeCurrent(window);
}
/// <summary>
/// Gets a <see cref="System.Boolean"/> indicating whether this instance is current in the calling thread.
/// </summary>
public bool IsCurrent
{
get { return implementation.IsCurrent; }
}
/// <summary>
/// Gets a <see cref="System.Boolean"/> indicating whether this instance has been disposed.
/// It is an error to access any instance methods if this property returns true.
/// </summary>
public bool IsDisposed
{
get { return disposed && implementation.IsDisposed; }
private set { disposed = value; }
}
/// <summary>
/// Gets or sets a positive integer in the range [1, n), indicating the number of
/// <see cref="DisplayDevice"/> refreshes between consecutive
/// <see cref="SwapBuffers()"/> calls. The maximum value for n is
/// implementation-dependent. The default value is 1.
/// Invalid values will be clamped to the valid range.
/// </summary>
public int SwapInterval
{
get { return implementation.SwapInterval; }
set { implementation.SwapInterval = value; }
}
/// <summary>
/// Updates the graphics context. This must be called when the render target
/// is resized for proper behavior on Mac OS X.
/// </summary>
/// <param name="window"></param>
public void Update(IWindowInfo window)
{
implementation.Update(window);
}
/// <summary>
/// Loads all OpenGL entry points.
/// </summary>
/// <exception cref="OpenTK.Graphics.GraphicsContextException">
/// Occurs when this instance is not current on the calling thread.
/// </exception>
public void LoadAll()
{
if (GraphicsContext.CurrentContext != this)
{
throw new GraphicsContextException();
}
implementation.LoadAll();
}
/// <summary>
/// Gets the platform-specific implementation of this IGraphicsContext.
/// </summary>
IGraphicsContext IGraphicsContextInternal.Implementation
{
get { return implementation; }
}
/// <summary>
/// Gets a handle to the OpenGL rendering context.
/// </summary>
ContextHandle IGraphicsContextInternal.Context
{
get
{
if (implementation != null)
{
handle_cached = ((IGraphicsContextInternal)implementation).Context;
}
return handle_cached;
}
}
/// <summary>
/// Gets the GraphicsMode of the context.
/// </summary>
public GraphicsMode GraphicsMode
{
get { return (implementation as IGraphicsContext).GraphicsMode; }
}
/// <summary>
/// Retrieves the implementation-defined address of an OpenGL function.
/// </summary>
/// <param name="function">The name of the OpenGL function (e.g. "glGetString")</param>
/// <returns>
/// A pointer to the specified function or an invalid pointer if the function is not
/// available in the current OpenGL context. The return value and calling convention
/// depends on the underlying platform.
/// </returns>
IntPtr IGraphicsContextInternal.GetAddress(string function)
{
IntPtr name = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(function);
IntPtr address = (implementation as IGraphicsContextInternal).GetAddress(name);
System.Runtime.InteropServices.Marshal.FreeHGlobal(name);
return address;
}
/// <summary>
/// Retrieves the implementation-defined address of an OpenGL function.
/// </summary>
/// <param name="function">
/// A pointer to a null-terminated buffer
/// containing the name of the OpenGL function.
/// </param>
/// <returns>
/// A pointer to the specified function or an invalid pointer if the function is not
/// available in the current OpenGL context. The return value and calling convention
/// depends on the underlying platform.
/// </returns>
IntPtr IGraphicsContextInternal.GetAddress(IntPtr function)
{
return (implementation as IGraphicsContextInternal).GetAddress(function);
}
/// <summary>
/// Disposes of the GraphicsContext.
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool manual)
{
if (!IsDisposed)
{
lock (SyncRoot)
{
RemoveContext(this);
}
// Note: we cannot dispose the implementation
// from a different thread. See wglDeleteContext.
// This is also known to crash GLX implementations.
if (manual)
{
Debug.Print("Disposing context {0}.", (this as IGraphicsContextInternal).Context.ToString());
if (implementation != null)
{
implementation.Dispose();
}
}
else
{
Debug.WriteLine("GraphicsContext leaked, did you forget to call Dispose()?");
}
IsDisposed = true;
}
}
/// <summary>
/// Marks this context as deleted, but does not actually release unmanaged resources
/// due to the threading requirements of OpenGL. Use <see cref="GraphicsContext.Dispose()"/>
/// instead.
/// </summary>
~GraphicsContext()
{
Dispose(false);
}
}
}

View file

@ -0,0 +1,132 @@
//
// GraphicsContextBase.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.
//
using System;
using System.Diagnostics;
using OpenTK.Platform;
namespace OpenTK.Graphics
{
// Provides the foundation for all IGraphicsContext implementations.
internal abstract class GraphicsContextBase : IGraphicsContext, IGraphicsContextInternal, IEquatable<IGraphicsContextInternal>
{
protected ContextHandle Handle;
protected GraphicsMode Mode;
public abstract void SwapBuffers();
public abstract void MakeCurrent(IWindowInfo window);
public abstract bool IsCurrent { get; }
public bool IsDisposed { get; protected set; }
public bool VSync
{
get { return SwapInterval > 0; }
set
{
if (value && SwapInterval <= 0)
{
SwapInterval = 1;
}
else if (!value && SwapInterval > 0)
{
SwapInterval = 0;
}
}
}
public abstract int SwapInterval { get; set; }
public virtual void Update(IWindowInfo window) { }
public GraphicsMode GraphicsMode { get { return Mode; } }
public bool ErrorChecking
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public IGraphicsContext Implementation { get { return this; } }
public abstract void LoadAll();
public ContextHandle Context { get { return Handle; } }
// This function is no longer used.
// The GraphicsContext facade will
// always call the IntPtr overload.
public IntPtr GetAddress(string function)
{
throw new NotImplementedException();
}
public abstract IntPtr GetAddress(IntPtr function);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected abstract void Dispose(bool disposing);
#if DEBUG
~GraphicsContextBase()
{
Dispose(false);
Debug.Print("[Warning] {0}:{1} leaked. Did you forget to call Dispose()?",
GetType().FullName, Handle);
}
#endif
public bool Equals(IGraphicsContextInternal other)
{
return Context.Equals(other.Context);
}
public override string ToString()
{
return string.Format("[{0}: IsCurrent={1}, IsDisposed={2}, VSync={3}, SwapInterval={4}, GraphicsMode={5}, Context={6}]",
GetType().Name, IsCurrent, IsDisposed, VSync, SwapInterval, GraphicsMode, Context);
}
public override int GetHashCode()
{
return Handle.GetHashCode();
}
public override bool Equals(object obj)
{
return
obj is IGraphicsContextInternal &&
Equals((IGraphicsContextInternal)obj);
}
}
}

View file

@ -0,0 +1,19 @@
using System;
namespace OpenTK.Graphics
{
/// <summary>
/// Represents errors related to a GraphicsContext.
/// </summary>
public class GraphicsContextException : Exception
{
/// <summary>
/// Constructs a new GraphicsContextException.
/// </summary>
public GraphicsContextException() : base() { }
/// <summary>
/// Constructs a new GraphicsContextException with the given error message.
/// </summary>
public GraphicsContextException(string message) : base(message) { }
}
}

View file

@ -0,0 +1,81 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted.
//
// 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.
//
using System;
namespace OpenTK.Graphics
{
/// <summary>
/// Enumerates various flags that affect the creation of new GraphicsContexts.
/// </summary>
[Flags]
public enum GraphicsContextFlags
{
/// <summary>
/// The default value of the GraphicsContextFlags enumeration.
/// </summary>
Default = 0x0000,
/// <summary>
/// Indicates that this is a debug GraphicsContext. Debug contexts may provide
/// additional debugging information at the cost of performance.
/// </summary>
/// <remarks></remarks>
Debug = 0x0001,
/// <summary>
/// Indicates that this is a forward compatible GraphicsContext. Forward-compatible contexts
/// do not support functionality marked as deprecated in the current GraphicsContextVersion.
/// </summary>
/// <remarks>Forward-compatible contexts are defined only for OpenGL versions 3.0 and later.</remarks>
ForwardCompatible = 0x0002,
/// <summary>
/// Indicates that this GraphicsContext is targeting OpenGL|ES.
/// </summary>
Embedded = 0x0004,
/// <summary>
/// Indicates that this GraphicsContext is intended for offscreen rendering.
/// </summary>
Offscreen = 0x0008,
/// <summary>
/// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle
/// and that angle-specific extensions are available.
/// </summary>
Angle = 0x0010,
/// <summary>
/// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle
/// and uses Direct3D9 as rendering backend.
/// </summary>
AngleD3D9 = 0x0020,
/// <summary>
/// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle
/// and uses Direct3D11 as rendering backend.
/// </summary>
AngleD3D11 = 0x0040,
/// <summary>
/// Indicates that this GraphicsContext is targeting OpenGL|ES via Angle
/// and uses OpenGL as rendering backend.
/// </summary>
AngleOpenGL = 0x0080,
}
}

View file

@ -0,0 +1,20 @@
using System;
namespace OpenTK.Graphics
{
/// <summary>
/// Thrown when an operation that required GraphicsContext is performed, when no
/// GraphicsContext is current in the calling thread.
/// </summary>
public class GraphicsContextMissingException : GraphicsContextException
{
/// <summary>
/// Constructs a new GraphicsContextMissingException.
/// </summary>
public GraphicsContextMissingException()
: base(String.Format(
"No context is current in the calling thread (ThreadId: {0}).",
System.Threading.Thread.CurrentThread.ManagedThreadId))
{ }
}
}

View file

@ -0,0 +1,63 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted.
//
// 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.
//
using System;
namespace OpenTK.Graphics
{
/// <summary>
/// Defines the version information of a GraphicsContext.
/// </summary>
public sealed class GraphicsContextVersion
{
internal GraphicsContextVersion(int minor, int major, string vendor, string renderer)
{
Minor = minor;
Major = major;
Vendor = vendor;
Renderer = renderer;
}
/// <summary>
/// Gets a System.Int32 indicating the minor version of a GraphicsContext instance.
/// </summary>
public int Minor { get; private set; }
/// <summary>
/// Gets a System.Int32 indicating the major version of a GraphicsContext instance.
/// </summary>
public int Major { get; private set; }
/// <summary>
/// Gets a System.String indicating the vendor of a GraphicsContext instance.
/// </summary>
public string Vendor { get; private set; } = String.Empty;
/// <summary>
/// Gets a System.String indicating the renderer of a GraphicsContext instance.
/// </summary>
public string Renderer { get; private set; } = String.Empty;
}
}

View file

@ -0,0 +1,17 @@
namespace OpenTK.Graphics
{
/// <summary>
/// Identifies a specific OpenGL or OpenGL|ES error. Such exceptions are only thrown
/// when OpenGL or OpenGL|ES automatic error checking is enabled -
/// <see cref="GraphicsContext.ErrorChecking"/> property.
/// Important: Do *not* catch this exception. Rather, fix the underlying issue that caused the error.
/// </summary>
public class GraphicsErrorException : GraphicsException
{
/// <summary>
/// Constructs a new GraphicsErrorException instance with the specified error message.
/// </summary>
/// <param name="message"></param>
public GraphicsErrorException(string message) : base(message) { }
}
}

View file

@ -0,0 +1,20 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK team.
* This notice may not be removed.
* See license.txt for licensing detailed licensing details.
*/
using System;
namespace OpenTK
{
/// <summary>Represents errors related to Graphics operations.</summary>
public class GraphicsException : Exception
{
/// <summary>Constructs a new GraphicsException.</summary>
public GraphicsException() : base() { }
/// <summary>Constructs a new GraphicsException with the specified excpetion message.</summary>
/// <param name="message"></param>
public GraphicsException(string message) : base(message) { }
}
}

View file

@ -0,0 +1,239 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing detailed licensing details.
*/
using System;
using System.Diagnostics;
using OpenTK.Core;
namespace OpenTK.Graphics
{
/// <summary>Defines the format for graphics operations.</summary>
public class GraphicsMode : IEquatable<GraphicsMode>
{
private int samples;
private static GraphicsMode defaultMode;
private static readonly object SyncRoot = new object();
// Disable BeforeFieldInit
static GraphicsMode() { }
internal GraphicsMode(GraphicsMode mode)
: this(mode.ColorFormat, mode.Depth, mode.Stencil, mode.Samples, mode.AccumulatorFormat, mode.Buffers, mode.Stereo) { }
internal GraphicsMode(IntPtr? index, ColorFormat color, int depth, int stencil, int samples, ColorFormat accum,
int buffers, bool stereo)
{
if (depth < 0)
{
throw new ArgumentOutOfRangeException("depth", "Must be greater than, or equal to zero.");
}
if (stencil < 0)
{
throw new ArgumentOutOfRangeException("stencil", "Must be greater than, or equal to zero.");
}
if (buffers < 0)
{
throw new ArgumentOutOfRangeException("buffers", "Must be greater than, or equal to zero.");
}
if (samples < 0)
{
throw new ArgumentOutOfRangeException("samples", "Must be greater than, or equal to zero.");
}
this.Index = index;
this.ColorFormat = color;
this.Depth = depth;
this.Stencil = stencil;
this.Samples = samples;
this.AccumulatorFormat = accum;
this.Buffers = buffers;
this.Stereo = stereo;
}
/// <summary>Constructs a new GraphicsMode with sensible default parameters.</summary>
public GraphicsMode()
: this(Default)
{ }
/// <summary>Constructs a new GraphicsMode with the specified parameters.</summary>
/// <param name="color">The ColorFormat of the color buffer.</param>
public GraphicsMode(ColorFormat color)
: this(color, Default.Depth, Default.Stencil, Default.Samples, Default.AccumulatorFormat, Default.Buffers, Default.Stereo)
{ }
/// <summary>Constructs a new GraphicsMode with the specified parameters.</summary>
/// <param name="color">The ColorFormat of the color buffer.</param>
/// <param name="depth">The number of bits in the depth buffer.</param>
public GraphicsMode(ColorFormat color, int depth)
: this(color, depth, Default.Stencil, Default.Samples, Default.AccumulatorFormat, Default.Buffers, Default.Stereo)
{ }
/// <summary>Constructs a new GraphicsMode with the specified parameters.</summary>
/// <param name="color">The ColorFormat of the color buffer.</param>
/// <param name="depth">The number of bits in the depth buffer.</param>
/// <param name="stencil">The number of bits in the stencil buffer.</param>
public GraphicsMode(ColorFormat color, int depth, int stencil)
: this(color, depth, stencil, Default.Samples, Default.AccumulatorFormat, Default.Buffers, Default.Stereo)
{ }
/// <summary>Constructs a new GraphicsMode with the specified parameters.</summary>
/// <param name="color">The ColorFormat of the color buffer.</param>
/// <param name="depth">The number of bits in the depth buffer.</param>
/// <param name="stencil">The number of bits in the stencil buffer.</param>
/// <param name="samples">The number of samples for FSAA.</param>
public GraphicsMode(ColorFormat color, int depth, int stencil, int samples)
: this(color, depth, stencil, samples, Default.AccumulatorFormat, Default.Buffers, Default.Stereo)
{ }
/// <summary>Constructs a new GraphicsMode with the specified parameters.</summary>
/// <param name="color">The ColorFormat of the color buffer.</param>
/// <param name="depth">The number of bits in the depth buffer.</param>
/// <param name="stencil">The number of bits in the stencil buffer.</param>
/// <param name="samples">The number of samples for FSAA.</param>
/// <param name="accum">The ColorFormat of the accumilliary buffer.</param>
public GraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum)
: this(color, depth, stencil, samples, accum, Default.Buffers, Default.Stereo)
{ }
/// <summary>Constructs a new GraphicsMode with the specified parameters.</summary>
/// <param name="color">The ColorFormat of the color buffer.</param>
/// <param name="depth">The number of bits in the depth buffer.</param>
/// <param name="stencil">The number of bits in the stencil buffer.</param>
/// <param name="samples">The number of samples for FSAA.</param>
/// <param name="accum">The ColorFormat of the accumilliary buffer.</param>
/// <param name="buffers">The number of render buffers. Typical values include one (single-), two (double-) or three (triple-buffering).</param>
public GraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers)
: this(color, depth, stencil, samples, accum, buffers, Default.Stereo)
{ }
/// <summary>Constructs a new GraphicsMode with the specified parameters.</summary>
/// <param name="color">The ColorFormat of the color buffer.</param>
/// <param name="depth">The number of bits in the depth buffer.</param>
/// <param name="stencil">The number of bits in the stencil buffer.</param>
/// <param name="samples">The number of samples for FSAA.</param>
/// <param name="accum">The ColorFormat of the accumilliary buffer.</param>
/// <param name="stereo">Set to true for a GraphicsMode with stereographic capabilities.</param>
/// <param name="buffers">The number of render buffers. Typical values include one (single-), two (double-) or three (triple-buffering).</param>
public GraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers, bool stereo)
: this(null, color, depth, stencil, samples, accum, buffers, stereo) { }
/// <summary>
/// Gets a nullable <see cref="System.IntPtr"/> value, indicating the platform-specific index for this GraphicsMode.
/// </summary>
public IntPtr? Index { get; set; } = null;
/// <summary>
/// Gets an OpenTK.Graphics.ColorFormat that describes the color format for this GraphicsFormat.
/// </summary>
public ColorFormat ColorFormat { get; private set; }
/// <summary>
/// Gets an OpenTK.Graphics.ColorFormat that describes the accumulator format for this GraphicsFormat.
/// </summary>
public ColorFormat AccumulatorFormat { get; private set; }
/// <summary>
/// Gets a System.Int32 that contains the bits per pixel for the depth buffer
/// for this GraphicsFormat.
/// </summary>
public int Depth { get; private set; }
/// <summary>
/// Gets a System.Int32 that contains the bits per pixel for the stencil buffer
/// of this GraphicsFormat.
/// </summary>
public int Stencil { get; private set; }
/// <summary>
/// Gets a System.Int32 that contains the number of FSAA samples per pixel for this GraphicsFormat.
/// </summary>
public int Samples
{
get
{
return samples;
}
private set
{
// Clamp antialiasing samples to max 64x
// This protects against a potential DOS during
// mode selection, when the user requests an
// abnormally high AA level.
samples = Math.Clamp(value, 0, 64);
}
}
/// <summary>
/// Gets a System.Boolean indicating whether this DisplayMode is stereoscopic.
/// </summary>
public bool Stereo { get; private set; }
/// <summary>
/// Gets a System.Int32 containing the number of buffers associated with this
/// DisplayMode.
/// </summary>
public int Buffers { get; private set; }
/// <summary>Returns an OpenTK.GraphicsFormat compatible with the underlying platform.</summary>
public static GraphicsMode Default
{
get
{
lock (SyncRoot)
{
if (defaultMode == null)
{
defaultMode = new GraphicsMode(null, 32, 16, 0, 0, 0, 2, false);
Debug.Print("GraphicsMode.Default = {0}", defaultMode.ToString());
}
return defaultMode;
}
}
}
/// <summary>Returns a System.String describing the current GraphicsFormat.</summary>
/// <returns>! System.String describing the current GraphicsFormat.</returns>
public override string ToString()
{
return String.Format("Index: {0}, Color: {1}, Depth: {2}, Stencil: {3}, Samples: {4}, Accum: {5}, Buffers: {6}, Stereo: {7}",
Index, ColorFormat, Depth, Stencil, Samples, AccumulatorFormat, Buffers, Stereo);
}
/// <summary>
/// Returns the hashcode for this instance.
/// </summary>
/// <returns>A <see cref="System.Int32"/> hashcode for this instance.</returns>
public override int GetHashCode()
{
return Index.GetHashCode();
}
/// <summary>
/// Indicates whether obj is equal to this instance.
/// </summary>
/// <param name="obj">An object instance to compare for equality.</param>
/// <returns>True, if obj equals this instance; false otherwise.</returns>
public override bool Equals(object obj)
{
if (obj is GraphicsMode)
{
return Equals((GraphicsMode)obj);
}
return false;
}
/// <summary>
/// Indicates whether other represents the same mode as this instance.
/// </summary>
/// <param name="other">The GraphicsMode to compare to.</param>
/// <returns>True, if other is equal to this instance; false otherwise.</returns>
public bool Equals(GraphicsMode other)
{
return Index.HasValue && Index == other.Index;
}
}
}

View file

@ -0,0 +1,67 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System.Collections.Generic;
namespace OpenTK.Graphics
{
internal sealed class GraphicsModeComparer : IComparer<GraphicsMode>
{
public int Compare(GraphicsMode x, GraphicsMode y)
{
int result = x.ColorFormat.CompareTo(y.ColorFormat);
if (result != 0)
{
return result;
}
result = x.Depth.CompareTo(y.Depth);
if (result != 0)
{
return result;
}
result = x.Stencil.CompareTo(y.Stencil);
if (result != 0)
{
return result;
}
result = x.Samples.CompareTo(y.Samples);
if (result != 0)
{
return result;
}
result = x.Stereo.CompareTo(y.Stereo);
if (result != 0)
{
return result;
}
result = x.Buffers.CompareTo(y.Buffers);
if (result != 0)
{
return result;
}
return x.AccumulatorFormat.CompareTo(y.AccumulatorFormat);
}
}
}

View file

@ -0,0 +1,19 @@
using System;
namespace OpenTK.Graphics
{
/// <summary>
/// Represents errors related to unavailable graphics parameters.
/// </summary>
public class GraphicsModeException : Exception
{
/// <summary>
/// Constructs a new GraphicsModeException.
/// </summary>
public GraphicsModeException() : base() { }
/// <summary>
/// Constructs a new GraphicsModeException with the given error message.
/// </summary>
public GraphicsModeException(string message) : base(message) { }
}
}

View file

@ -0,0 +1,122 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing detailed licensing details.
*/
using System;
using OpenTK.Platform;
namespace OpenTK.Graphics
{
/// <summary>
/// Provides methods for creating and interacting with an OpenGL context.
/// </summary>
public interface IGraphicsContext : IDisposable
{
/// <summary>Swaps buffers, presenting the rendered scene to the user.</summary>
void SwapBuffers();
/// <summary>Makes the GraphicsContext current in the calling thread.</summary>
/// <param name="window">An OpenTK.Platform.IWindowInfo structure that points to a valid window.</param>
/// <remarks>
/// <para>OpenGL commands in one thread, affect the GraphicsContext which is current in that thread.</para>
/// <para>It is an error to issue an OpenGL command in a thread without a current GraphicsContext.</para>
/// </remarks>
void MakeCurrent(IWindowInfo window);
/// <summary>
/// Gets a <see cref="System.Boolean"/> indicating whether this instance is current in the calling thread.
/// </summary>
bool IsCurrent { get; }
/// <summary>
/// Gets a <see cref="System.Boolean"/> indicating whether this instance has been disposed.
/// It is an error to access any instance methods if this property returns true.
/// </summary>
bool IsDisposed { get; }
/// <summary>
/// Gets or sets a positive integer in the range [1, n), indicating the number of
/// <see cref="DisplayDevice"/> refreshes between consecutive
/// <see cref="SwapBuffers()"/> calls. The maximum value for n is
/// implementation-dependent. The default value is 1.
/// Invalid values will be clamped to the valid range.
/// </summary>
int SwapInterval { get; set; }
/// <summary>
/// Updates the graphics context. This must be called when the region the graphics context
/// is drawn to is resized.
/// </summary>
/// <param name="window"></param>
void Update(IWindowInfo window);
/// <summary>Gets the GraphicsMode of this instance.</summary>
GraphicsMode GraphicsMode { get; }
/// <summary>
/// Gets or sets a System.Boolean, indicating whether automatic error checking should be performed.
/// </summary>
/// <remarks>
/// <para>It is an error to enable error checking inside a Begin()-End() region.</para>
/// <para>This method only affects the debug version of OpenTK.dll.</para>
/// </remarks>
bool ErrorChecking { get; set; }
/// <summary>
/// Loads all OpenGL entry points. Requires this instance to be current on the calling thread.
/// </summary>
void LoadAll();
}
// Functions for internal use by OpenTK.
// TODO: RegisterForDisposal/DisposeResources for 0.3.15 (GC & OpenGL)
// TODO: Remove or move GetDisplayModes to another class.
/// <summary>
/// Provides methods to create new GraphicsContexts. Should only be used for extending OpenTK.
/// </summary>
public interface IGraphicsContextInternal
{
/// <summary>
/// Gets the internal implementation of the current instance.
/// </summary>
IGraphicsContext Implementation { get; }
/// <summary>
/// Loads all OpenGL entry points. Requires this instance to be current on the calling thread.
/// </summary>
void LoadAll();
/// <summary>
/// Gets a handle to the OpenGL rendering context.
/// </summary>
ContextHandle Context { get; }
/// <summary>
/// Retrieves the implementation-defined address of an OpenGL function.
/// </summary>
/// <param name="function">The name of the OpenGL function (e.g. "glGetString")</param>
/// <returns>
/// A pointer to the specified function or an invalid pointer if the function is not
/// available in the current OpenGL context. The return value and calling convention
/// depends on the underlying platform.
/// </returns>
IntPtr GetAddress(string function);
/// <summary>
/// Retrieves the implementation-defined address of an OpenGL function.
/// </summary>
/// <param name="function">
/// A pointer to a null-terminated buffer
/// containing the name of the OpenGL function.
/// </param>
/// <returns>
/// A pointer to the specified function or an invalid pointer if the function is not
/// available in the current OpenGL context. The return value and calling convention
/// depends on the underlying platform.
/// </returns>
/// <remarks><seealso cref="GetAddress(string)"/></remarks>
IntPtr GetAddress(IntPtr function);
}
}

View file

@ -0,0 +1,16 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing detailed licensing details.
*/
namespace OpenTK.Graphics
{
internal interface IGraphicsMode
{
// Creates a temporary OpenGL context (if necessary) and finds the mode which closest matches
// the specified parameters.
GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers,
bool stereo);
}
}

View file

@ -0,0 +1,80 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System.Diagnostics;
using System.Reflection;
using OpenTK.Graphics;
namespace OpenTK.Platform
{
// Provides the foundation for all desktop IGraphicsContext implementations.
internal abstract class DesktopGraphicsContext : GraphicsContextBase
{
public override void LoadAll()
{
// Modern unices can use EGL to create
// both GL and ES contexts, so we need
// to load all entry points. This is
// especially true on KMS, Wayland and Mir.
Stopwatch time = Stopwatch.StartNew();
Assembly assembly;
try
{
assembly = Assembly.Load("OpenTK.Graphics");
}
catch
{
// Failed to load graphics, oh well.
// Up to the user I guess?
// TODO: Should we expose this load failure to the user better?
return;
}
var provider = new GTKBindingHelper();
void LoadBindings(string typeNamespace)
{
var type = assembly.GetType($"OpenTK.Graphics.{typeNamespace}.GL");
if (type == null)
{
return;
}
var load = type.GetMethod("LoadBindings");
load.Invoke(null, new object[] { provider });
}
LoadBindings("ES11");
LoadBindings("ES20");
LoadBindings("ES30");
LoadBindings("OpenGL");
LoadBindings("OpenGL4");
Debug.Print("Bindings loaded in {0} ms.", time.Elapsed.TotalMilliseconds);
}
}
}

View file

@ -0,0 +1,227 @@
//
// DeviceCollection.cs
//
// Author:
// Stefanos A. <stapostol@gmail.com>
//
// Copyright (c) 2006-2014
//
// 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.
//
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenTK.Platform
{
// Holds a collection of hardware devices with an associated id.
// Note: 'id' refers to a unique hardware-specific device identifier.
// Note: 'index' refers to the offset of the device in the Devices array.
// Indices are allocated sequentially as devices are added to the system.
// If a device is removed, its index will be reused for the next device
// that is added.
internal class DeviceCollection<T> : IEnumerable<T>
{
internal struct Enumerator : IEnumerator<T>
{
private int Index;
private DeviceCollection<T> Collection;
internal Enumerator(DeviceCollection<T> collection)
{
Collection = collection;
Index = -1;
Current = default(T);
}
public T Current { get; private set; }
object IEnumerator.Current
{
get
{
return Current;
}
}
public void Dispose()
{
}
public bool MoveNext()
{
do
{
++Index;
if (Index < Collection.Devices.Count)
{
Current = Collection.Devices[Index];
}
} while (Index < Collection.Devices.Count && Collection.Devices[Index] == null);
return Index < Collection.Devices.Count;
}
public void Reset()
{
Index = -1;
Current = default(T);
}
}
private readonly Dictionary<long, int> Map = new Dictionary<long, int>();
private readonly List<T> Devices = new List<T>();
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new Enumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator(this);
}
// This avoids boxing when using foreach loops
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
public T this[int index]
{
get { return FromIndex(index); }
}
/// \internal
/// <summary>
/// Adds or replaces a device based on its hardware id.
/// A zero-based device index will be generated automatically
/// for the first available device slot.
/// </summary>
/// <param name="id">The hardware id for the device.</param>
/// <param name="device">The device instance.</param>
public void Add(long id, T device)
{
if (!Map.ContainsKey(id))
{
int index = GetIndex();
Map.Add(id, index);
}
Devices[Map[id]] = device;
}
public void Remove(long id)
{
if (!TryRemove(id))
{
Debug.Print("Invalid DeviceCollection<{0}> id: {1}", typeof(T).FullName, id);
}
}
public bool TryRemove(long id)
{
if (!Map.ContainsKey(id))
{
return false;
}
Devices[Map[id]] = default(T);
Map.Remove(id);
return true;
}
public T FromIndex(int index)
{
if (index >= 0 && index < Devices.Count)
{
return Devices[index];
}
else
{
return default(T);
}
}
public bool FromIndex(int index, out T device)
{
if (index >= 0 && index < Devices.Count)
{
device = Devices[index];
return true;
}
else
{
device = default(T);
return false;
}
}
public T FromHardwareId(long id)
{
if (Map.ContainsKey(id))
{
return FromIndex(Map[id]);
}
else
{
return default(T);
}
}
public bool FromHardwareId(long id, out T device)
{
if (Map.ContainsKey(id))
{
device = FromIndex(Map[id]);
return true;
}
else
{
device = default(T);
return false;
}
}
public int Count
{
get { return Map.Count; }
}
// Return the index of the first empty slot in Devices.
// If no empty slot exists, append a new one and return
// that index.
private int GetIndex()
{
for (int i = 0; i < Devices.Count; i++)
{
if (Devices[i] == null)
{
return i;
}
}
Devices.Add(default(T));
return Devices.Count - 1;
}
}
}

View file

@ -0,0 +1,61 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System;
using System.Collections.Generic;
namespace OpenTK.Platform
{
internal abstract class DisplayDeviceBase : IDisplayDeviceDriver
{
internal sealed class SystemEvents
{
public static event EventHandler DisplaySettingsChanged;
}
protected readonly List<DisplayDevice> AvailableDevices = new List<DisplayDevice>();
protected DisplayDevice Primary;
public abstract bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution);
public abstract bool TryRestoreResolution(DisplayDevice device);
// Gets the DisplayDevice that corresponds to the specified index.
public virtual DisplayDevice GetDisplay(DisplayIndex index)
{
if (index == DisplayIndex.Primary)
{
return Primary;
}
else if ((int)index >= 0 && (int)index < AvailableDevices.Count)
{
return AvailableDevices[(int)index];
}
else
{
return null;
}
}
}
}

View file

@ -0,0 +1,97 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing detailed licensing details.
*/
using System;
using System.Threading;
using OpenTK.Graphics;
namespace OpenTK.Platform.Dummy
{
/// \internal
/// <summary>
/// An empty IGraphicsContext implementation to be used inside the Visual Studio designer.
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
/// </summary>
internal sealed class DummyGLContext : GraphicsContextBase
{
private readonly GraphicsContext.GetAddressDelegate Loader;
private static int handle_count;
private Thread current_thread;
public DummyGLContext()
{
Handle = new ContextHandle(
new IntPtr(Interlocked.Increment(
ref handle_count)));
}
public DummyGLContext(ContextHandle handle, GraphicsContext.GetAddressDelegate loader)
: this()
{
if (handle != ContextHandle.Zero)
{
Handle = handle;
}
Loader = loader;
Mode = new GraphicsMode(new IntPtr(2), 32, 16, 0, 0, 0, 2, false);
}
public override void SwapBuffers() { }
public override void MakeCurrent(IWindowInfo info)
{
Thread new_thread = Thread.CurrentThread;
// A context may be current only on one thread at a time.
if (current_thread != null && new_thread != current_thread)
{
throw new GraphicsContextException(
"Cannot make context current on two threads at the same time");
}
if (info != null)
{
current_thread = Thread.CurrentThread;
}
else
{
current_thread = null;
}
}
public override bool IsCurrent
{
get { return current_thread != null && current_thread == Thread.CurrentThread; }
}
public override IntPtr GetAddress(IntPtr function)
{
string str = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(function);
return Loader(str);
}
public override int SwapInterval { get; set; }
public override void Update(IWindowInfo window)
{ }
public override void LoadAll()
{
#if OPENGL
new OpenTK.Graphics.OpenGL.GL().LoadEntryPoints();
new OpenTK.Graphics.OpenGL4.GL().LoadEntryPoints();
#endif
#if OPENGLES
new OpenTK.Graphics.ES11.GL().LoadEntryPoints();
new OpenTK.Graphics.ES20.GL().LoadEntryPoints();
new OpenTK.Graphics.ES30.GL().LoadEntryPoints();
#endif
}
protected override void Dispose(bool disposing) { IsDisposed = true; }
}
}

View file

@ -0,0 +1,16 @@
using System;
namespace OpenTK.Platform.Dummy
{
internal class DummyWindowInfo : IWindowInfo
{
public void Dispose()
{
}
public IntPtr Handle
{
get { return IntPtr.Zero; }
}
}
}

View file

@ -0,0 +1,179 @@
using System;
using OpenTK.Graphics;
using OpenTK.Platform.Windows;
namespace OpenTK.Platform.Egl
{
using EGLSurface = IntPtr;
/// <summary>
/// A window info for angle.
/// </summary>
public interface IAngleWindowInfo : IWindowInfo
{
/// <summary>
/// Query the underlying platform pointer / handle for this window's
/// default surface or IntPtr.Zero
/// </summary>
IntPtr QuerySurfacePointer();
/// <summary>
/// Create an additional rendering surface that shares the display
/// of this window.
/// </summary>
/// <param name="width">width in pixels</param>
/// <param name="height">height in pixels</param>
/// <returns>A reference to the new surface</returns>
EGLSurface CreateSurface(int width, int height);
/// <summary>
/// Destroy a surface created with CreateSurface and clears the passed reference.
/// </summary>
/// <param name="surface">Reference to the surface.</param>
void DestroySurface(ref EGLSurface surface);
/// <summary>
/// MakeCurrent the custom surface created with CreateSurface.
/// </summary>
/// <param name="surface">Reference to the surface.</param>
void MakeCurrent(EGLSurface surface);
/// <summary>
/// Query the underlying platform pointer / handle for an EGLSurface
/// created with CreateSurface.
/// </summary>
/// <param name="surface"></param>
IntPtr QuerySurfacePointer(EGLSurface surface);
}
internal interface IAngleWindowInfoInternal : IAngleWindowInfo
{
IWindowInfo PlatformWindow { get; }
IntPtr Display { get; }
IntPtr Surface { get; }
EglContext EglContext { get; set; }
EglWindowInfo EglWindowInfo { get; set; }
IntPtr DeviceContext { get; }
}
internal class AngleWindowInfo : IAngleWindowInfoInternal
{
private bool _disposed;
public AngleWindowInfo(IWindowInfo platform_window)
{
PlatformWindow = platform_window;
}
public IWindowInfo PlatformWindow { get; }
public IWindowInfo WindowInfo
{
get { return EglWindowInfo; }
}
public IntPtr DeviceContext
{
get
{
var win_win = PlatformWindow as WinWindowInfo;
if (win_win != null)
{
return win_win.DeviceContext;
}
return IntPtr.Zero;
}
}
public EglContext EglContext { get; set; }
public EglWindowInfo EglWindowInfo { get; set; }
public IntPtr Display
{
get { return EglWindowInfo.Display; }
}
public IntPtr Surface
{
get { return EglWindowInfo.Surface; }
}
public void Dispose()
{
Dispose(false);
}
public IntPtr Handle
{
get { return PlatformWindow.Handle; }
}
~AngleWindowInfo()
{
Dispose(true);
}
private void Dispose(bool called_from_finalizer)
{
if (_disposed)
{
return;
}
if (!called_from_finalizer)
{
PlatformWindow.Dispose();
}
// dispose unmanaged
_disposed = true;
GC.SuppressFinalize(this);
}
public IntPtr QuerySurfacePointer()
{
return QuerySurfacePointer(Surface);
}
public EGLSurface CreateSurface(int width, int height)
{
IntPtr surface;
EglWindowInfo.CreatePbufferSurface(
EglContext.GraphicsMode.Index.Value,
width, height,
out surface);
return surface;
}
public void DestroySurface(ref EGLSurface surface)
{
EglWindowInfo.DestroySurface(ref surface);
}
public void MakeCurrent(EGLSurface surface)
{
Egl.MakeCurrent(Display, surface, surface, EglContext.HandleAsEGLContext);
}
public IntPtr QuerySurfacePointer(IntPtr surface)
{
if (UsesDirect3DBackend())
{
return QuerySurfacePointer(surface,
Egl.EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE);
}
return IntPtr.Zero;
}
private IntPtr QuerySurfacePointer(IntPtr surface, int attrib)
{
IntPtr surface_pointer;
if (Egl.QuerySurfacePointerANGLE(
Display, surface, attrib, out surface_pointer))
{
return surface_pointer;
}
return IntPtr.Zero;
}
private bool UsesDirect3DBackend()
{
var d3d_flags = GraphicsContextFlags.AngleD3D9 | GraphicsContextFlags.AngleD3D11;
return ((EglContext.GraphicsContextFlags & d3d_flags) != 0);
}
}
}

View file

@ -0,0 +1,403 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2011 the Open Toolkit library.
//
// 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.
//
using System;
using System.Runtime.InteropServices;
using OpenTK.Graphics;
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedMember.Global
#pragma warning disable 1591 // Missing XML comments
namespace OpenTK.Platform.Egl
{
using EGLNativeDisplayType = IntPtr;
using EGLNativeWindowType = IntPtr;
using EGLNativePixmapType = IntPtr;
using EGLConfig = IntPtr;
using EGLContext = IntPtr;
using EGLDisplay = IntPtr;
using EGLSurface = IntPtr;
using EGLClientBuffer = IntPtr;
internal enum RenderApi
{
ES = Egl.OPENGL_ES_API,
GL = Egl.OPENGL_API,
VG = Egl.OPENVG_API
}
[Flags]
internal enum RenderableFlags
{
ES = Egl.OPENGL_ES_BIT,
ES2 = Egl.OPENGL_ES2_BIT,
ES3 = Egl.OPENGL_ES3_BIT,
GL = Egl.OPENGL_BIT,
VG = Egl.OPENVG_BIT,
}
public enum ErrorCode
{
SUCCESS = 12288,
NOT_INITIALIZED = 12289,
BAD_ACCESS = 12290,
BAD_ALLOC = 12291,
BAD_ATTRIBUTE = 12292,
BAD_CONFIG = 12293,
BAD_CONTEXT = 12294,
BAD_CURRENT_SURFACE = 12295,
BAD_DISPLAY = 12296,
BAD_MATCH = 12297,
BAD_NATIVE_PIXMAP = 12298,
BAD_NATIVE_WINDOW = 12299,
BAD_PARAMETER = 12300,
BAD_SURFACE = 12301,
CONTEXT_LOST = 12302,
}
internal enum SurfaceType
{
PBUFFER_BIT = 0x0001,
PIXMAP_BIT = 0x0002,
WINDOW_BIT = 0x0004,
VG_COLORSPACE_LINEAR_BIT = 0x0020,
VG_ALPHA_FORMAT_PRE_BIT = 0x0040,
MULTISAMPLE_RESOLVE_BOX_BIT = 0x0200,
SWAP_BEHAVIOR_PRESERVED_BIT = 0x0400,
}
internal static partial class Egl
{
public const int VERSION_1_0 = 1;
public const int VERSION_1_1 = 1;
public const int VERSION_1_2 = 1;
public const int VERSION_1_3 = 1;
public const int VERSION_1_4 = 1;
public const int FALSE = 0;
public const int TRUE = 1;
public const int DONT_CARE = -1;
public const int CONTEXT_LOST = 12302;
public const int BUFFER_SIZE = 12320;
public const int ALPHA_SIZE = 12321;
public const int BLUE_SIZE = 12322;
public const int GREEN_SIZE = 12323;
public const int RED_SIZE = 12324;
public const int DEPTH_SIZE = 12325;
public const int STENCIL_SIZE = 12326;
public const int CONFIG_CAVEAT = 12327;
public const int CONFIG_ID = 12328;
public const int LEVEL = 12329;
public const int MAX_PBUFFER_HEIGHT = 12330;
public const int MAX_PBUFFER_PIXELS = 12331;
public const int MAX_PBUFFER_WIDTH = 12332;
public const int NATIVE_RENDERABLE = 12333;
public const int NATIVE_VISUAL_ID = 12334;
public const int NATIVE_VISUAL_TYPE = 12335;
public const int PRESERVED_RESOURCES = 12336;
public const int SAMPLES = 12337;
public const int SAMPLE_BUFFERS = 12338;
public const int SURFACE_TYPE = 12339;
public const int TRANSPARENT_TYPE = 12340;
public const int TRANSPARENT_BLUE_VALUE = 12341;
public const int TRANSPARENT_GREEN_VALUE = 12342;
public const int TRANSPARENT_RED_VALUE = 12343;
public const int NONE = 12344;
public const int BIND_TO_TEXTURE_RGB = 12345;
public const int BIND_TO_TEXTURE_RGBA = 12346;
public const int MIN_SWAP_INTERVAL = 12347;
public const int MAX_SWAP_INTERVAL = 12348;
public const int LUMINANCE_SIZE = 12349;
public const int ALPHA_MASK_SIZE = 12350;
public const int COLOR_BUFFER_TYPE = 12351;
public const int RENDERABLE_TYPE = 12352;
public const int MATCH_NATIVE_PIXMAP = 12353;
public const int CONFORMANT = 12354;
public const int SLOW_CONFIG = 12368;
public const int NON_CONFORMANT_CONFIG = 12369;
public const int TRANSPARENT_RGB = 12370;
public const int RGB_BUFFER = 12430;
public const int LUMINANCE_BUFFER = 12431;
public const int NO_TEXTURE = 12380;
public const int TEXTURE_RGB = 12381;
public const int TEXTURE_RGBA = 12382;
public const int TEXTURE_2D = 12383;
public const int PBUFFER_BIT = 1;
public const int PIXMAP_BIT = 2;
public const int WINDOW_BIT = 4;
public const int VG_COLORSPACE_LINEAR_BIT = 32;
public const int VG_ALPHA_FORMAT_PRE_BIT = 64;
public const int MULTISAMPLE_RESOLVE_BOX_BIT = 512;
public const int SWAP_BEHAVIOR_PRESERVED_BIT = 1024;
public const int OPENGL_ES_BIT = 1;
public const int OPENVG_BIT = 2;
public const int OPENGL_ES2_BIT = 4;
public const int OPENGL_BIT = 8;
public const int OPENGL_ES3_BIT = 64;
public const int VENDOR = 12371;
public const int VERSION = 12372;
public const int EXTENSIONS = 12373;
public const int CLIENT_APIS = 12429;
public const int HEIGHT = 12374;
public const int WIDTH = 12375;
public const int LARGEST_PBUFFER = 12376;
public const int TEXTURE_FORMAT = 12416;
public const int TEXTURE_TARGET = 12417;
public const int MIPMAP_TEXTURE = 12418;
public const int MIPMAP_LEVEL = 12419;
public const int RENDER_BUFFER = 12422;
public const int VG_COLORSPACE = 12423;
public const int VG_ALPHA_FORMAT = 12424;
public const int HORIZONTAL_RESOLUTION = 12432;
public const int VERTICAL_RESOLUTION = 12433;
public const int PIXEL_ASPECT_RATIO = 12434;
public const int SWAP_BEHAVIOR = 12435;
public const int MULTISAMPLE_RESOLVE = 12441;
public const int BACK_BUFFER = 12420;
public const int SINGLE_BUFFER = 12421;
public const int VG_COLORSPACE_sRGB = 12425;
public const int VG_COLORSPACE_LINEAR = 12426;
public const int VG_ALPHA_FORMAT_NONPRE = 12427;
public const int VG_ALPHA_FORMAT_PRE = 12428;
public const int DISPLAY_SCALING = 10000;
public const int UNKNOWN = -1;
public const int BUFFER_PRESERVED = 12436;
public const int BUFFER_DESTROYED = 12437;
public const int OPENVG_IMAGE = 12438;
public const int CONTEXT_CLIENT_TYPE = 12439;
public const int CONTEXT_CLIENT_VERSION = 12440;
public const int MULTISAMPLE_RESOLVE_DEFAULT = 12442;
public const int MULTISAMPLE_RESOLVE_BOX = 12443;
public const int OPENGL_ES_API = 12448;
public const int OPENVG_API = 12449;
public const int OPENGL_API = 12450;
public const int DRAW = 12377;
public const int READ = 12378;
public const int CORE_NATIVE_ENGINE = 12379;
public const int COLORSPACE = VG_COLORSPACE;
public const int ALPHA_FORMAT = VG_ALPHA_FORMAT;
public const int COLORSPACE_sRGB = VG_COLORSPACE_sRGB;
public const int COLORSPACE_LINEAR = VG_COLORSPACE_LINEAR;
public const int ALPHA_FORMAT_NONPRE = VG_ALPHA_FORMAT_NONPRE;
public const int ALPHA_FORMAT_PRE = VG_ALPHA_FORMAT_PRE;
// EGL_ANGLE_d3d_share_handle_client_buffer
public const int D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
// EGL_ANGLE_window_fixed_size
public const int FIXED_SIZE_ANGLE = 0x3201;
// EGL_ANGLE_query_surface_pointer
[DllImport("libEGL.dll", EntryPoint = "eglQuerySurfacePointerANGLE")]
public static extern bool QuerySurfacePointerANGLE(EGLDisplay display, EGLSurface surface, int attribute, out IntPtr value);
[DllImport("libEGL.dll", EntryPoint = "eglGetPlatformDisplayEXT")]
public static extern EGLDisplay GetPlatformDisplay(int platform, EGLNativeDisplayType displayId, int[] attribList);
// EGL_ANGLE_software_display
public static readonly EGLNativeDisplayType SOFTWARE_DISPLAY_ANGLE = new EGLNativeDisplayType(-1);
// EGL_ANGLE_direct3d_display
public static readonly EGLNativeDisplayType D3D11_ELSE_D3D9_DISPLAY_ANGLE = new EGLNativeDisplayType(-2);
public static readonly EGLNativeDisplayType D3D11_ONLY_DISPLAY_ANGLE = new EGLNativeDisplayType(-3);
// EGL_ANGLE_device_d3d
public const int D3D9_DEVICE_ANGLE = 0x33A0;
public const int D3D11_DEVICE_ANGLE = 0x33A1;
// EGL_ANGLE_platform_angle
public const int PLATFORM_ANGLE_ANGLE = 0x3202;
public const int PLATFORM_ANGLE_TYPE_ANGLE = 0x3203;
public const int PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE = 0x3204;
public const int PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE = 0x3205;
public const int PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE = 0x3206;
// EGL_ANGLE_platform_angle_d3d
public const int PLATFORM_ANGLE_TYPE_D3D9_ANGLE = 0x3207;
public const int PLATFORM_ANGLE_TYPE_D3D11_ANGLE = 0x3208;
public const int PLATFORM_ANGLE_DEVICE_TYPE_ANGLE = 0x3209;
public const int PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE = 0x320A;
public const int PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE = 0x320B;
public const int PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE = 0x320C;
public const int PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE = 0x320F;
// EGL_ANGLE_platform_angle_opengl
public const int PLATFORM_ANGLE_TYPE_OPENGL_ANGLE = 0x320D;
public const int PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE = 0x320E;
// See EGL_ANGLE_surface_d3d_texture_2d_share_handle
public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200;
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetError")]
public static extern ErrorCode GetError();
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetDisplay")]
public static extern EGLDisplay GetDisplay(EGLNativeDisplayType display_id);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglInitialize")]
//[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool Initialize(EGLDisplay dpy, out int major, out int minor);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglTerminate")]
//[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool Terminate(EGLDisplay dpy);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryString")]
public static extern IntPtr QueryString(EGLDisplay dpy, int name);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetConfigs")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool GetConfigs(EGLDisplay dpy, EGLConfig[] configs, int config_size, out int num_config);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglChooseConfig")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool ChooseConfig(EGLDisplay dpy, int[] attrib_list, [In, Out] EGLConfig[] configs, int config_size, out int num_config);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetConfigAttrib")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool GetConfigAttrib(EGLDisplay dpy, EGLConfig config, int attribute, out int value);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglCreateWindowSurface")]
public static extern EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, IntPtr win, IntPtr attrib_list);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePbufferSurface")]
public static extern EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, int[] attrib_list);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePixmapSurface")]
public static extern EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, int[] attrib_list);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglDestroySurface")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool DestroySurface(EGLDisplay dpy, EGLSurface surface);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglQuerySurface")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool QuerySurface(EGLDisplay dpy, EGLSurface surface, int attribute, out int value);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglBindAPI")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool BindAPI(RenderApi api);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryAPI")]
public static extern int QueryAPI();
[DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitClient")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool WaitClient();
[DllImportAttribute("libEGL.dll", EntryPoint = "eglReleaseThread")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool ReleaseThread();
[DllImportAttribute("libEGL.dll", EntryPoint = "eglCreatePbufferFromClientBuffer")]
public static extern EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, int buftype, EGLClientBuffer buffer, EGLConfig config, int[] attrib_list);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglSurfaceAttrib")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, int attribute, int value);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglBindTexImage")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool BindTexImage(EGLDisplay dpy, EGLSurface surface, int buffer);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglReleaseTexImage")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, int buffer);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglSwapInterval")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool SwapInterval(EGLDisplay dpy, int interval);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglCreateContext")]
private static extern IntPtr eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list);
public static EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, int[] attrib_list)
{
IntPtr ptr = eglCreateContext(dpy, config, share_context, attrib_list);
if (ptr == IntPtr.Zero)
{
throw new GraphicsContextException(String.Format("Failed to create EGL context, error: {0}.", Egl.GetError()));
}
return ptr;
}
[DllImportAttribute("libEGL.dll", EntryPoint = "eglDestroyContext")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool DestroyContext(EGLDisplay dpy, EGLContext ctx);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglMakeCurrent")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentContext")]
public static extern EGLContext GetCurrentContext();
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentSurface")]
public static extern EGLSurface GetCurrentSurface(int readdraw);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetCurrentDisplay")]
public static extern EGLDisplay GetCurrentDisplay();
[DllImportAttribute("libEGL.dll", EntryPoint = "eglQueryContext")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool QueryContext(EGLDisplay dpy, EGLContext ctx, int attribute, out int value);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitGL")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool WaitGL();
[DllImportAttribute("libEGL.dll", EntryPoint = "eglWaitNative")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool WaitNative(int engine);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglSwapBuffers")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool SwapBuffers(EGLDisplay dpy, EGLSurface surface);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglCopyBuffers")]
[return: MarshalAsAttribute(UnmanagedType.I1)]
public static extern bool CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetProcAddress")]
public static extern IntPtr GetProcAddress(string funcname);
[DllImportAttribute("libEGL.dll", EntryPoint = "eglGetProcAddress")]
public static extern IntPtr GetProcAddress(IntPtr funcname);
// EGL_EXT_platform_base
[DllImport("libEGL.dll", EntryPoint = "eglGetPlatformDisplayEXT")]
public static extern EGLDisplay GetPlatformDisplayEXT(int platform, EGLNativeDisplayType native_display, int[] attrib_list);
[DllImport("libEGL.dll", EntryPoint = "eglCreatePlatformWindowSurfaceEXT")]
public static extern EGLSurface CreatePlatformWindowSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType native_window, int[] attrib_list);
[DllImport("libEGL.dll", EntryPoint = "eglCreatePlatformPixmapSurfaceEXT")]
public static extern EGLSurface CreatePlatformPixmapSurfaceEXT(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType native_pixmap, int[] attrib_list);
// Returns true if Egl drivers exist on the system.
public static bool IsSupported
{
get
{
try { GetCurrentContext(); }
catch (Exception) { return false; }
return true;
}
}
}
}

View file

@ -0,0 +1,138 @@

//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2015 the Open Toolkit library.
//
// 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.
//
using System;
using OpenTK.Graphics;
namespace OpenTK.Platform.Egl
{
internal class EglAnglePlatformFactory : PlatformFactoryBase
{
private readonly IPlatformFactory _platform_factory;
public EglAnglePlatformFactory(IPlatformFactory platform_factory)
{
_platform_factory = platform_factory;
}
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return _platform_factory.CreateDisplayDeviceDriver();
}
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window,
IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
var angle_window = (IAngleWindowInfoInternal)window;
var egl_window = CreateWindowInfo(angle_window, major, flags);
var egl_context = new EglWinContext(mode, egl_window, shareContext, major, minor, flags);
angle_window.EglContext = egl_context;
return egl_context;
}
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window,
IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
var angle_window = (IAngleWindowInfoInternal)window;
var egl_window = CreateWindowInfo(angle_window, major, flags);
var egl_context = new EglWinContext(handle, egl_window, shareContext, major, minor, flags);
angle_window.EglContext = egl_context;
return egl_context;
}
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
return new ContextHandle(Platform.Egl.Egl.GetCurrentContext());
};
}
private static bool FlagEnabled(GraphicsContextFlags flags, GraphicsContextFlags flag)
{
return (flags & flag) != 0;
}
private EglWindowInfo CreateWindowInfo(IAngleWindowInfoInternal window_info,
int major, GraphicsContextFlags flags)
{
var egl_display = GetAngleDisplay(window_info.DeviceContext, flags, major);
var egl_window = new EglWindowInfo(window_info.Handle, egl_display);
window_info.EglWindowInfo = egl_window;
return egl_window;
}
private IntPtr GetAngleDisplay(IntPtr dc, GraphicsContextFlags flags, int major)
{
// default to D3D9 for ES2, but use D3D11 for ES3 as required by Angle.
var platform_type = major == 2
? Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9_ANGLE
: Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
if (FlagEnabled(flags, GraphicsContextFlags.AngleD3D11))
{
platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
}
else if (FlagEnabled(flags, GraphicsContextFlags.AngleD3D9))
{
platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
}
else if (FlagEnabled(flags, GraphicsContextFlags.AngleOpenGL))
{
platform_type = Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
}
else
{
// make sure the correct flag is set.
switch (platform_type)
{
case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D9_ANGLE:
flags |= GraphicsContextFlags.AngleD3D9;
break;
case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_D3D11_ANGLE:
flags |= GraphicsContextFlags.AngleD3D11;
break;
case Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_OPENGL_ANGLE:
flags |= GraphicsContextFlags.AngleOpenGL;
break;
}
}
var attribs = new[]
{
Platform.Egl.Egl.PLATFORM_ANGLE_TYPE_ANGLE, platform_type,
Platform.Egl.Egl.PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, Platform.Egl.Egl.DONT_CARE,
Platform.Egl.Egl.PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, Platform.Egl.Egl.DONT_CARE,
Platform.Egl.Egl.PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, Platform.Egl.Egl.PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
Platform.Egl.Egl.NONE
};
return Platform.Egl.Egl.GetPlatformDisplay(
Platform.Egl.Egl.PLATFORM_ANGLE_ANGLE,
dc,
attribs
);
}
}
}

View file

@ -0,0 +1,268 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using System.Diagnostics;
using OpenTK.Graphics;
namespace OpenTK.Platform.Egl
{
internal abstract class EglContext : EmbeddedGraphicsContext
{
protected readonly RenderableFlags Renderable;
internal EglWindowInfo WindowInfo;
internal GraphicsContextFlags GraphicsContextFlags { get; set; }
internal IntPtr HandleAsEGLContext { get { return Handle.Handle; } set { Handle = new ContextHandle(value); } }
private int swap_interval = 1; // Default interval is defined as 1 in EGL.
public EglContext(GraphicsMode mode, EglWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
{
if (mode == null)
{
throw new ArgumentNullException("mode");
}
if (window == null)
{
throw new ArgumentNullException("window");
}
EglContext shared = GetSharedEglContext(sharedContext);
WindowInfo = window;
// Select an EGLConfig that matches the desired mode. We cannot use the 'mode'
// parameter directly, since it may have originated on a different system (e.g. GLX)
// and it may not support the desired renderer.
Renderable = RenderableFlags.GL;
if ((flags & GraphicsContextFlags.Embedded) != 0)
{
switch (major)
{
case 3:
Renderable = RenderableFlags.ES3;
break;
case 2:
Renderable = RenderableFlags.ES2;
break;
default:
Renderable = RenderableFlags.ES;
break;
}
}
RenderApi api = (Renderable & RenderableFlags.GL) != 0 ? RenderApi.GL : RenderApi.ES;
Debug.Print("[EGL] Binding {0} rendering API.", api);
if (!Egl.BindAPI(api))
{
Debug.Print("[EGL] Failed to bind rendering API. Error: {0}", Egl.GetError());
}
bool offscreen = (flags & GraphicsContextFlags.Offscreen) != 0;
SurfaceType surfaceType = offscreen
? SurfaceType.PBUFFER_BIT
: SurfaceType.WINDOW_BIT;
Mode = new EglGraphicsMode().SelectGraphicsMode(surfaceType,
window.Display, mode.ColorFormat, mode.Depth, mode.Stencil,
mode.Samples, mode.AccumulatorFormat, mode.Buffers, mode.Stereo,
Renderable);
if (!Mode.Index.HasValue)
{
throw new GraphicsModeException("Invalid or unsupported GraphicsMode.");
}
IntPtr config = Mode.Index.Value;
if (window.Surface == IntPtr.Zero)
{
if (!offscreen)
{
window.CreateWindowSurface(config);
}
else
{
window.CreatePbufferSurface(config);
}
}
int[] attribList = { Egl.CONTEXT_CLIENT_VERSION, major, Egl.NONE };
var shareContext = shared?.HandleAsEGLContext ?? IntPtr.Zero;
HandleAsEGLContext = Egl.CreateContext(window.Display, config, shareContext, attribList);
GraphicsContextFlags = flags;
}
public EglContext(ContextHandle handle, EglWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
{
if (handle == ContextHandle.Zero)
{
throw new ArgumentException("handle");
}
if (window == null)
{
throw new ArgumentNullException("window");
}
Handle = handle;
}
public override void SwapBuffers()
{
if (!Egl.SwapBuffers(WindowInfo.Display, WindowInfo.Surface))
{
throw new GraphicsContextException(string.Format("Failed to swap buffers for context {0} current. Error: {1}", Handle, Egl.GetError()));
}
}
public override void MakeCurrent(IWindowInfo window)
{
// Ignore 'window', unless it actually is an EGL window. In other words,
// trying to make the EglContext current on a non-EGL window will do,
// nothing (the EglContext will remain current on the previous EGL window
// or the window it was constructed on (which may not be EGL)).
if (window != null)
{
if (window is EglWindowInfo)
{
WindowInfo = (EglWindowInfo)window;
}
else if (window is IAngleWindowInfoInternal)
{
WindowInfo = ((IAngleWindowInfoInternal)window).EglWindowInfo;
}
if (!Egl.MakeCurrent(WindowInfo.Display, WindowInfo.Surface, WindowInfo.Surface, HandleAsEGLContext))
{
throw new GraphicsContextException(string.Format("Failed to make context {0} current. Error: {1}", Handle, Egl.GetError()));
}
}
else
{
Egl.MakeCurrent(WindowInfo.Display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}
}
public override bool IsCurrent
{
get { return Egl.GetCurrentContext() == HandleAsEGLContext; }
}
public override int SwapInterval
{
get
{
// Egl.GetSwapInterval does not exist, so store and return the current interval.
// The default interval is defined as 1 (true).
return swap_interval;
}
set
{
if (value < 0)
{
// EGL does not offer EXT_swap_control_tear yet
value = 1;
}
if (Egl.SwapInterval(WindowInfo.Display, value))
{
swap_interval = value;
}
else
{
Debug.Print("[Warning] Egl.SwapInterval({0}, {1}) failed. Error: {2}",
WindowInfo.Display, value, Egl.GetError());
}
}
}
public override void Update(IWindowInfo window)
{
MakeCurrent(window);
// ANGLE updates the width and height of the back buffer surfaces in the WaitClient function.
// So without this calling this function, the surface won't match the size of the window after it
// was resized.
// https://bugs.chromium.org/p/angleproject/issues/detail?id=1438
if (!Egl.WaitClient())
{
Debug.Print("[Warning] Egl.WaitClient() failed. Error: {0}", Egl.GetError());
}
}
public override IntPtr GetAddress(IntPtr function)
{
// Try loading a static export from ES1 or ES2
IntPtr address = GetStaticAddress(function, Renderable);
// If a static export is not available, try retrieving an extension
// function pointer with eglGetProcAddress
if (address == IntPtr.Zero)
{
address = Egl.GetProcAddress(function);
}
return address;
}
protected abstract IntPtr GetStaticAddress(IntPtr function, RenderableFlags renderable);
// Todo: cross-reference the specs. What should happen if the context is destroyed from a different
// thread?
protected override void Dispose(bool manual)
{
if (!IsDisposed)
{
if (manual)
{
if (IsCurrent)
{
Egl.MakeCurrent(WindowInfo.Display, WindowInfo.Surface, WindowInfo.Surface, IntPtr.Zero);
}
Egl.DestroyContext(WindowInfo.Display, HandleAsEGLContext);
}
IsDisposed = true;
}
}
private EglContext GetSharedEglContext(IGraphicsContext sharedContext)
{
if (sharedContext == null)
{
return null;
}
var internalContext = sharedContext as IGraphicsContextInternal;
if (internalContext != null)
{
return (EglContext)internalContext.Implementation;
}
return (EglContext)sharedContext;
}
}
}

View file

@ -0,0 +1,23 @@
// Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
// This file is distributed under GPL v3. See LICENSE.md for details.
using OpenTK.Graphics;
namespace OpenTK.Platform.Egl
{
/// <summary>
/// Represents an Egl exception.
/// </summary>
public class EglException : GraphicsContextException
{
/// <summary>
/// Gets the EGL error code.
/// </summary>
public ErrorCode ErrorCode { get; private set; }
internal EglException(string message, ErrorCode errorCode) : base(message)
{
ErrorCode = errorCode;
}
}
}

View file

@ -0,0 +1,101 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using OpenTK.Graphics;
namespace OpenTK.Platform.Egl
{
internal 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 renderableFlags)
{
return SelectGraphicsMode(
SurfaceType.WINDOW_BIT,
window.Display,
color, depth, stencil, samples, accum, buffers, stereo, renderableFlags);
}
public GraphicsMode SelectGraphicsMode(SurfaceType surfaceType,
IntPtr display, ColorFormat color, int depth, int stencil,
int samples, ColorFormat accum, int buffers, bool stereo,
RenderableFlags renderableFlags)
{
IntPtr[] configs = new IntPtr[1];
int[] attribList = new int[]
{
Egl.SURFACE_TYPE, (int)surfaceType,
Egl.RENDERABLE_TYPE, (int)renderableFlags,
Egl.RED_SIZE, color.Red,
Egl.GREEN_SIZE, color.Green,
Egl.BLUE_SIZE, color.Blue,
Egl.ALPHA_SIZE, color.Alpha,
Egl.DEPTH_SIZE, depth > 0 ? depth : 0,
Egl.STENCIL_SIZE, stencil > 0 ? stencil : 0,
Egl.SAMPLE_BUFFERS, samples > 0 ? 1 : 0,
Egl.SAMPLES, samples > 0 ? samples : 0,
Egl.NONE,
};
int numConfigs;
if (!Egl.ChooseConfig(display, attribList, configs, configs.Length, out numConfigs) || numConfigs == 0)
{
throw new GraphicsModeException(String.Format("Failed to retrieve GraphicsMode, error {0}", Egl.GetError()));
}
// See what we really got
IntPtr activeConfig = configs[0];
int r, g, b, a;
Egl.GetConfigAttrib(display, activeConfig, Egl.RED_SIZE, out r);
Egl.GetConfigAttrib(display, activeConfig, Egl.GREEN_SIZE, out g);
Egl.GetConfigAttrib(display, activeConfig, Egl.BLUE_SIZE, out b);
Egl.GetConfigAttrib(display, activeConfig, Egl.ALPHA_SIZE, out a);
int d, s;
Egl.GetConfigAttrib(display, activeConfig, Egl.DEPTH_SIZE, out d);
Egl.GetConfigAttrib(display, activeConfig, Egl.STENCIL_SIZE, out s);
int sampleBuffers;
Egl.GetConfigAttrib(display, activeConfig, Egl.SAMPLES, out sampleBuffers);
Egl.GetConfigAttrib(display, activeConfig, Egl.SAMPLES, out samples);
return new GraphicsMode(activeConfig, new ColorFormat(r, g, b, a), d, s, sampleBuffers > 0 ? samples : 0, 0, 2, false);
}
}
}

View file

@ -0,0 +1,44 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using OpenTK.Graphics;
using OpenTK.Platform.MacOS;
namespace OpenTK.Platform.Egl
{
internal class EglMacPlatformFactory : MacOSFactory
{
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new NotImplementedException();
}
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new NotImplementedException();
}
}
}

View file

@ -0,0 +1,135 @@
//
// EglUnixContext.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.
//
using System;
using System.Diagnostics;
using System.Reflection;
using OpenTK.Graphics;
namespace OpenTK.Platform.Egl
{
internal class EglUnixContext : EglContext
{
private IntPtr ES1 = OpenTK.Platform.X11.DL.Open("libGLESv1_CM", X11.DLOpenFlags.Lazy);
private IntPtr ES2 = OpenTK.Platform.X11.DL.Open("libGLESv2", X11.DLOpenFlags.Lazy);
private IntPtr GL = OpenTK.Platform.X11.DL.Open("libGL", X11.DLOpenFlags.Lazy);
public EglUnixContext(GraphicsMode mode, EglWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
: base(mode, window, sharedContext, major, minor, flags)
{
}
public EglUnixContext(ContextHandle handle, EglWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
: base(handle, window, sharedContext, major, minor, flags)
{
}
protected override IntPtr GetStaticAddress(IntPtr function, RenderableFlags renderable)
{
if ((renderable & (RenderableFlags.ES2 | RenderableFlags.ES3)) != 0 && ES2 != IntPtr.Zero)
{
return X11.DL.Symbol(ES2, function);
}
else if ((renderable & RenderableFlags.ES) != 0 && ES1 != IntPtr.Zero)
{
return X11.DL.Symbol(ES1, function);
}
else if ((renderable & RenderableFlags.GL) != 0 && GL != IntPtr.Zero)
{
return X11.DL.Symbol(GL, function);
}
return IntPtr.Zero;
}
protected override void Dispose(bool manual)
{
if (ES1 != IntPtr.Zero)
{
X11.DL.Close(ES1);
}
if (ES2 != IntPtr.Zero)
{
X11.DL.Close(ES2);
}
if (GL != IntPtr.Zero)
{
X11.DL.Close(GL);
}
GL = ES1 = ES2 = IntPtr.Zero;
base.Dispose(manual);
}
public override void LoadAll()
{
// Modern unices can use EGL to create
// both GL and ES contexts, so we need
// to load all entry points. This is
// especially true on KMS, Wayland and Mir.
Stopwatch time = Stopwatch.StartNew();
Assembly assembly;
try
{
assembly = Assembly.Load("OpenTK.Graphics");
}
catch
{
// Failed to load graphics, oh well.
// Up to the user I guess?
// TODO: Should we expose this load failure to the user better?
return;
}
var provider = new GTKBindingHelper();
void LoadBindings(string typeNamespace)
{
var type = assembly.GetType($"OpenTK.Graphics.{typeNamespace}.GL");
if (type == null)
{
return;
}
var load = type.GetMethod("LoadBindings");
load.Invoke(null, new object[] { provider });
}
LoadBindings("ES11");
LoadBindings("ES20");
LoadBindings("ES30");
LoadBindings("OpenGL");
LoadBindings("OpenGL4");
Debug.Print("Bindings loaded in {0} ms.", time.Elapsed.TotalMilliseconds);
}
}
}

View file

@ -0,0 +1,79 @@
//
// EglWinContext.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.
//
using System;
using OpenTK.Graphics;
namespace OpenTK.Platform.Egl
{
internal class EglWinContext : EglContext
{
private IntPtr ES1 = OpenTK.Platform.Windows.Functions.LoadLibrary("libGLESv1_CM");
private IntPtr ES2 = OpenTK.Platform.Windows.Functions.LoadLibrary("libGLESv2");
public EglWinContext(GraphicsMode mode, EglWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
: base(mode, window, sharedContext, major, minor, flags)
{
}
public EglWinContext(ContextHandle handle, EglWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
: base(handle, window, sharedContext, major, minor, flags)
{
}
protected override IntPtr GetStaticAddress(IntPtr function, RenderableFlags renderable)
{
if ((renderable & (RenderableFlags.ES2 | RenderableFlags.ES3)) != 0 && ES2 != IntPtr.Zero)
{
return Windows.Functions.GetProcAddress(ES2, function);
}
else if ((renderable & RenderableFlags.ES) != 0 && ES1 != IntPtr.Zero)
{
return Windows.Functions.GetProcAddress(ES1, function);
}
return IntPtr.Zero;
}
protected override void Dispose(bool manual)
{
if (ES1 != IntPtr.Zero)
{
Windows.Functions.FreeLibrary(ES1);
}
if (ES2 != IntPtr.Zero)
{
Windows.Functions.FreeLibrary(ES2);
}
ES1 = ES2 = IntPtr.Zero;
base.Dispose(manual);
}
}
}

View file

@ -0,0 +1,70 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using OpenTK.Graphics;
using OpenTK.Platform.Windows;
namespace OpenTK.Platform.Egl
{
// EGL factory for the Windows platform.
internal class EglWinPlatformFactory : WinFactory
{
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
WinWindowInfo win_win = (WinWindowInfo)window;
IntPtr egl_display = GetDisplay(win_win.DeviceContext);
EglWindowInfo egl_win = new OpenTK.Platform.Egl.EglWindowInfo(win_win.Handle, egl_display);
return new EglWinContext(mode, egl_win, shareContext, major, minor, flags);
}
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
WinWindowInfo win_win = (WinWindowInfo)window;
IntPtr egl_display = GetDisplay(win_win.DeviceContext);
EglWindowInfo egl_win = new OpenTK.Platform.Egl.EglWindowInfo(win_win.Handle, egl_display);
return new EglWinContext(handle, egl_win, shareContext, major, minor, flags);
}
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
return new ContextHandle(Egl.GetCurrentContext());
};
}
private IntPtr GetDisplay(IntPtr dc)
{
IntPtr display = Egl.GetDisplay(dc);
if (display == IntPtr.Zero)
{
display = Egl.GetDisplay(IntPtr.Zero);
}
return display;
}
}
}

View file

@ -0,0 +1,186 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using System.Diagnostics;
using OpenTK.Graphics;
namespace OpenTK.Platform.Egl
{
// Holds information about an EGL window.
internal class EglWindowInfo : IWindowInfo
{
private IntPtr surface;
private bool disposed;
public EglWindowInfo(IntPtr handle, IntPtr display)
: this(handle, display, IntPtr.Zero)
{
}
public EglWindowInfo(IntPtr handle, IntPtr display, IntPtr surface)
{
Handle = handle;
Surface = surface;
if (display == IntPtr.Zero)
{
display = Egl.GetDisplay(IntPtr.Zero);
}
Display = display;
int dummyMajor, dummyMinor;
if (!Egl.Initialize(Display, out dummyMajor, out dummyMinor))
{
throw new GraphicsContextException(String.Format("Failed to initialize EGL, error {0}.", Egl.GetError()));
}
}
public IntPtr Handle { get; set; }
public IntPtr Display { get; private set; }
public IntPtr Surface { get { return surface; } private set { surface = value; } }
public void CreateWindowSurface(IntPtr config)
{
Surface = Egl.CreateWindowSurface(Display, config, Handle, IntPtr.Zero);
if (Surface == IntPtr.Zero)
{
throw new GraphicsContextException(String.Format(
"[EGL] Failed to create window surface, error {0}.", Egl.GetError()));
}
}
//public void CreatePixmapSurface(EGLConfig config)
//{
// Surface = Egl.CreatePixmapSurface(Display, config, Handle, null);
//}
public void CreatePbufferSurface(IntPtr config)
{
int[] attribs = new int[]{Egl.NONE};
Surface = Egl.CreatePbufferSurface(Display, config, attribs);
if (Surface == IntPtr.Zero)
{
throw new GraphicsContextException(String.Format(
"[EGL] Failed to create pbuffer surface, error {0}.", Egl.GetError()));
}
}
public void CreatePbufferSurface(IntPtr config, int width, int height)
{
if (surface != IntPtr.Zero)
{
DestroySurface();
}
CreatePbufferSurface(config, width, height, out surface);
}
public void CreatePbufferSurface(IntPtr config, int width, int height, out IntPtr bufferSurface)
{
int[] attribs = new int[]
{
Egl.WIDTH, width,
Egl.HEIGHT, height,
Egl.TEXTURE_TARGET, Egl.TEXTURE_2D,
Egl.TEXTURE_FORMAT, Egl.TEXTURE_RGBA,
Egl.NONE
};
bufferSurface = Egl.CreatePbufferSurface(Display, config, attribs);
if (bufferSurface == IntPtr.Zero)
{
throw new GraphicsContextException(String.Format(
"[EGL] Failed to create pbuffer surface, error {0}.", Egl.GetError()));
}
}
public void DestroySurface()
{
DestroySurface(ref surface);
}
public void DestroySurface(ref IntPtr bufferSurface)
{
if (bufferSurface == IntPtr.Zero)
{
return;
}
if (Egl.GetCurrentSurface(Egl.DRAW) == Surface)
{
Egl.MakeCurrent(Display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
}
if (Egl.DestroySurface(Display, bufferSurface))
{
bufferSurface = IntPtr.Zero;
return;
}
Debug.Print("[Warning] Failed to destroy {0}:{1}.", Surface.GetType().Name, Surface);
Surface = IntPtr.Zero;
}
public void TerminateDisplay()
{
if (Display != IntPtr.Zero)
{
if (!Egl.Terminate(Display))
{
Debug.Print("[Warning] Failed to terminate display {0}.", Display);
}
Display = IntPtr.Zero;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool manual)
{
if (!disposed)
{
if (manual)
{
DestroySurface();
disposed = true;
}
else
{
Debug.Print("[Warning] Failed to destroy {0}:{1}.", this.GetType().Name, Handle);
}
}
}
~EglWindowInfo()
{
Dispose(false);
}
}
}

View file

@ -0,0 +1,55 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using OpenTK.Graphics;
using OpenTK.Platform.X11;
namespace OpenTK.Platform.Egl
{
internal class EglX11PlatformFactory : X11Factory
{
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
X11WindowInfo x11_win = (X11WindowInfo)window;
EglWindowInfo egl_win = new OpenTK.Platform.Egl.EglWindowInfo(x11_win.Handle, Egl.GetDisplay(x11_win.Display));
return new EglUnixContext(mode, egl_win, shareContext, major, minor, flags);
}
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
X11WindowInfo x11_win = (X11WindowInfo)window;
EglWindowInfo egl_win = new OpenTK.Platform.Egl.EglWindowInfo(x11_win.Handle, Egl.GetDisplay(x11_win.Display));
return new EglUnixContext(handle, egl_win, shareContext, major, minor, flags);
}
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
return new ContextHandle(Egl.GetCurrentContext());
};
}
}
}

View file

@ -0,0 +1,78 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System.Diagnostics;
using System.Reflection;
using OpenTK.Graphics;
namespace OpenTK.Platform
{
// Provides the foundation for all desktop IGraphicsContext implementations.
internal abstract class EmbeddedGraphicsContext : GraphicsContextBase
{
public override void LoadAll()
{
// Modern unices can use EGL to create
// both GL and ES contexts, so we need
// to load all entry points. This is
// especially true on KMS, Wayland and Mir.
Stopwatch time = Stopwatch.StartNew();
Assembly assembly;
try
{
assembly = Assembly.Load("OpenTK.Graphics");
}
catch
{
// Failed to load graphics, oh well.
// Up to the user I guess?
// TODO: Should we expose this load failure to the user better?
return;
}
var provider = new GTKBindingHelper();
void LoadBindings(string typeNamespace)
{
var type = assembly.GetType($"OpenTK.Graphics.{typeNamespace}.GL");
if (type == null)
{
return;
}
var load = type.GetMethod("LoadBindings");
load.Invoke(null, new object[] { provider });
}
LoadBindings("ES11");
LoadBindings("ES20");
LoadBindings("ES30");
Debug.Print("Bindings loaded in {0} ms.", time.Elapsed.TotalMilliseconds);
}
}
}

View file

@ -0,0 +1,192 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using System.Diagnostics;
namespace OpenTK.Platform
{
using Graphics;
internal sealed class Factory : IPlatformFactory
{
private bool disposed;
static Factory()
{
Toolkit.Init();
}
public Factory()
{
// Ensure we are correctly initialized.
Toolkit.Init();
// Create regular platform backend
if (Configuration.RunningOnWindows)
{
Default = new Windows.WinFactory();
}
else if (Configuration.RunningOnMacOS)
{
Default = new MacOS.MacOSFactory();
}
else if (Configuration.RunningOnX11)
{
Default = new X11.X11Factory();
}
else if (Configuration.RunningOnLinux)
{
Default = new Linux.LinuxFactory();
}
if (Default == null)
{
Default = new UnsupportedPlatform();
}
if (Egl.Egl.IsSupported)
{
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();
}
Angle = new Egl.EglAnglePlatformFactory(Embedded);
}
else
{
Embedded = new UnsupportedPlatform();
Angle = Embedded;
}
if (Default is UnsupportedPlatform && !(Embedded is UnsupportedPlatform))
{
Default = Embedded;
}
}
public static IPlatformFactory Default { get; private set; }
public static IPlatformFactory Embedded { get; private set; }
public static IPlatformFactory Angle { get; private set; }
public IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return Default.CreateDisplayDeviceDriver();
}
public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return Default.CreateGLContext(mode, window, shareContext, directRendering, major, minor, flags);
}
public IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return Default.CreateGLContext(handle, window, shareContext, directRendering, major, minor, flags);
}
public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return Default.CreateGetCurrentGraphicsContext();
}
public void RegisterResource(IDisposable resource)
{
Default.RegisterResource(resource);
}
private class UnsupportedPlatform : PlatformFactoryBase
{
private static readonly string error_string = "Please, refer to http://www.opentk.com for more information.";
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
throw new PlatformNotSupportedException(error_string);
}
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new PlatformNotSupportedException(error_string);
}
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new PlatformNotSupportedException(error_string);
}
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
throw new PlatformNotSupportedException(error_string);
}
}
private void Dispose(bool manual)
{
if (!disposed)
{
if (manual)
{
Default.Dispose();
if (Embedded != Default)
{
Embedded.Dispose();
}
}
else
{
Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Factory()
{
Dispose(false);
}
}
}

View file

@ -0,0 +1,34 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
namespace OpenTK.Platform
{
internal interface IDisplayDeviceDriver
{
bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution);
bool TryRestoreResolution(DisplayDevice device);
DisplayDevice GetDisplay(DisplayIndex displayIndex);
}
}

View file

@ -0,0 +1,43 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using OpenTK.Graphics;
namespace OpenTK.Platform
{
internal interface IPlatformFactory : IDisposable
{
IDisplayDeviceDriver CreateDisplayDeviceDriver();
IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags);
IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags);
GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext();
void RegisterResource(IDisposable resource);
}
}

View file

@ -0,0 +1,19 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing detailed licensing details.
*/
using System;
namespace OpenTK.Platform
{
/// <summary>Describes an OS window.</summary>
public interface IWindowInfo : IDisposable
{
/// <summary>
/// Retrieves a platform-specific handle to this window.
/// </summary>
IntPtr Handle { get; }
}
}

View file

@ -0,0 +1,209 @@
//
// Drm.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.
//
using System;
using System.Runtime.InteropServices;
#pragma warning disable 0649 // field is never assigned
namespace OpenTK.Platform.Linux
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void VBlankCallback(int fd,
int sequence,
int tv_sec,
int tv_usec,
IntPtr user_data);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void PageFlipCallback(int fd,
int sequence,
int tv_sec,
int tv_usec,
IntPtr user_data);
internal class Drm
{
private const string lib = "libdrm";
[DllImport(lib, EntryPoint = "drmHandleEvent", CallingConvention = CallingConvention.Cdecl)]
public static extern int HandleEvent(int fd, ref EventContext evctx);
[DllImport(lib, EntryPoint = "drmModeAddFB", CallingConvention = CallingConvention.Cdecl)]
public static extern int ModeAddFB(int fd, int width, int height, byte depth,
byte bpp, int pitch, int bo_handle,
out int buf_id);
[DllImport(lib, EntryPoint = "drmModeRmFB", CallingConvention = CallingConvention.Cdecl)]
public static extern int ModeRmFB(int fd, int bufferId);
[DllImport(lib, EntryPoint = "drmModeFreeCrtc", CallingConvention = CallingConvention.Cdecl)]
public static extern void ModeFreeCrtc(IntPtr ptr);
[DllImport(lib, EntryPoint = "drmModeGetCrtc", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ModeGetCrtc(int fd, int 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, int connector_id);
[DllImport(lib, EntryPoint = "drmModeGetEncoder", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ModeGetEncoder(int fd, int encoder_id);
[DllImport(lib, EntryPoint = "drmModeGetResources", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ModeGetResources(int fd);
[DllImport(lib, EntryPoint = "drmModePageFlip", CallingConvention = CallingConvention.Cdecl)]
public static extern int ModePageFlip(int fd, int crtc_id, int fb_id,
PageFlipFlags flags, IntPtr user_data);
[DllImport(lib, EntryPoint = "drmModeSetCrtc", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern int ModeSetCrtc(int fd, int crtcId, int bufferId,
int x, int y, int* connectors, int count, ModeInfo* mode);
[DllImport(lib, EntryPoint = "drmModeSetCursor2", CallingConvention = CallingConvention.Cdecl)]
public static extern int SetCursor(int fd, int crtcId, int bo_handle, int width, int height, int hot_x, int hot_y);
[DllImport(lib, EntryPoint = "drmModeMoveCursor", CallingConvention = CallingConvention.Cdecl)]
public static extern int MoveCursor(int fd, int crtcId, int x, int y);
}
internal enum ModeConnection
{
Connected = 1,
Disconnected = 2,
Unknown = 3
}
internal enum ModeSubPixel
{
Unknown = 1,
HorizontalRgb = 2,
HorizontalBgr = 3,
VerticalRgb = 4,
VerticalBgr = 5,
None = 6
}
[Flags]
internal enum PageFlipFlags
{
FlipEvent = 0x01,
FlipAsync = 0x02,
FlipFlags = FlipEvent | FlipAsync
}
[StructLayout(LayoutKind.Sequential)]
internal struct EventContext
{
public int version;
public IntPtr vblank_handler;
public IntPtr page_flip_handler;
public static readonly int Version = 2;
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct ModeConnector
{
public int connector_id;
public int encoder_id;
public int connector_type;
public int connector_type_id;
public ModeConnection connection;
public int mmWidth, mmHeight;
public ModeSubPixel subpixel;
public int count_modes;
public ModeInfo* modes;
public int count_props;
public int *props;
public long *prop_values;
public int count_encoders;
public int *encoders;
}
internal struct ModeCrtc
{
public int crtc_id;
public int buffer_id;
public int x, y;
public int width, height;
public int mode_valid;
public ModeInfo mode;
public int gamma_size;
}
internal struct ModeEncoder
{
public int encoder_id;
public int encoder_type;
public int crtc_id;
public int possible_crtcs;
public int possible_clones;
}
[StructLayout(LayoutKind.Sequential)]
internal 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 int vrefresh; // refresh rate * 1000
public uint flags;
public uint type;
public fixed sbyte name[32];
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct ModeRes
{
public int count_fbs;
public int* fbs;
public int count_crtcs;
public int* crtcs;
public int count_connectors;
public int* connectors;
public int count_encoders;
public int* encoders;
public int min_width, max_width;
public int min_height, max_height;
}
}

View file

@ -0,0 +1,272 @@
//
// Gbm.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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.Linux
{
using Device = IntPtr; // struct gbm_device*
using Surface = IntPtr;
using BufferObjectHandle = IntPtr;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate void DestroyUserDataCallback(BufferObject bo, IntPtr data);
internal class Gbm
{
private const string lib = "gbm";
[DllImport(lib, EntryPoint = "gbm_bo_create", CallingConvention = CallingConvention.Cdecl)]
public static extern BufferObject CreateBuffer(Device gbm, int width, int height, SurfaceFormat format, SurfaceFlags flags);
[DllImport(lib, EntryPoint = "gbm_bo_destroy", CallingConvention = CallingConvention.Cdecl)]
public static extern void DestroyBuffer(BufferObject bo);
[DllImport(lib, EntryPoint = "gbm_bo_write", CallingConvention = CallingConvention.Cdecl)]
public static extern int BOWrite(IntPtr bo, IntPtr buf, IntPtr count);
[DllImport(lib, EntryPoint = "gbm_bo_get_device", CallingConvention = CallingConvention.Cdecl)]
public static extern Device BOGetDevice(IntPtr bo);
[DllImport(lib, EntryPoint = "gbm_bo_get_handle", CallingConvention = CallingConvention.Cdecl)]
public static extern BufferObjectHandle BOGetHandle(IntPtr bo);
[DllImport(lib, EntryPoint = "gbm_bo_get_height", CallingConvention = CallingConvention.Cdecl)]
public static extern int BOGetHeight(IntPtr bo);
[DllImport(lib, EntryPoint = "gbm_bo_get_width", CallingConvention = CallingConvention.Cdecl)]
public static extern int BOGetWidth(IntPtr bo);
[DllImport(lib, EntryPoint = "gbm_bo_get_stride", CallingConvention = CallingConvention.Cdecl)]
public static extern int BOGetStride(IntPtr bo);
[DllImport(lib, EntryPoint = "gbm_bo_set_user_data", CallingConvention = CallingConvention.Cdecl)]
public static extern void BOSetUserData(IntPtr bo, IntPtr data, DestroyUserDataCallback callback);
[DllImport(lib, EntryPoint = "gbm_create_device", CallingConvention = CallingConvention.Cdecl)]
public static extern Device CreateDevice(int fd);
[DllImport(lib, EntryPoint = "gbm_device_destroy", CallingConvention = CallingConvention.Cdecl)]
public static extern void DestroyDevice(Device gbm);
[DllImport(lib, EntryPoint = "gbm_device_get_fd", CallingConvention = CallingConvention.Cdecl)]
public static extern int DeviceGetFD(IntPtr gbm);
[DllImport(lib, EntryPoint = "gbm_surface_create", CallingConvention = CallingConvention.Cdecl)]
public static extern Surface CreateSurface(Device 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(Device gbm, SurfaceFormat format, SurfaceFlags usage);
[DllImport(lib, EntryPoint = "gbm_surface_lock_front_buffer", CallingConvention = CallingConvention.Cdecl)]
public static extern BufferObject LockFrontBuffer(Surface surface);
[DllImport(lib, EntryPoint = "gbm_surface_release_buffer", CallingConvention = CallingConvention.Cdecl)]
public static extern void ReleaseBuffer(Surface surface, BufferObject buffer);
}
internal 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)),
}
[Flags]
internal enum SurfaceFlags
{
Scanout = (1 << 0),
Cursor64x64 = (1 << 1),
Rendering = (1 << 2),
Write = (1 << 3),
}
[StructLayout(LayoutKind.Sequential)]
internal struct BufferObject : IEquatable<BufferObject>
{
private IntPtr buffer;
public static readonly BufferObject Zero =
default(BufferObject);
public int Write(byte[] data)
{
unsafe
{
fixed (byte* pdata = data)
{
return Gbm.BOWrite(buffer, (IntPtr)pdata, (IntPtr)data.Length);
}
}
}
public void SetUserData(IntPtr data, DestroyUserDataCallback destroyFB)
{
Gbm.BOSetUserData(buffer, data, destroyFB);
}
public Device Device
{
get { return Gbm.BOGetDevice(buffer); }
}
public int Handle
{
get { return Gbm.BOGetHandle(buffer).ToInt32(); }
}
public int Width
{
get { return Gbm.BOGetWidth(buffer); }
}
public int Height
{
get { return Gbm.BOGetHeight(buffer); }
}
public int Stride
{
get { return Gbm.BOGetStride(buffer); }
}
public void Dispose()
{
Gbm.DestroyBuffer(this);
buffer = IntPtr.Zero;
}
public static bool operator ==(BufferObject left, BufferObject right)
{
return left.Equals(right);
}
public static bool operator !=(BufferObject left, BufferObject right)
{
return !left.Equals(right);
}
public override bool Equals(object obj)
{
return
obj is BufferObject &&
this.Equals((BufferObject)obj);
}
public override int GetHashCode()
{
return buffer.GetHashCode();
}
public override string ToString()
{
return string.Format("[BufferObject: {0}]", buffer);
}
public bool Equals(BufferObject other)
{
return buffer == other.buffer;
}
}
}

View file

@ -0,0 +1,44 @@
//
// Kms.cs
//
// Author:
// Stefanos A. <stapostol@gmail.com>
//
// Copyright (c) 2006-2014
//
// 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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.Linux
{
internal class Kms
{
private const string lib = "libkms";
[DllImport(lib, EntryPoint = "kms_bo_map", CallingConvention = CallingConvention.Cdecl)]
public static extern int MapBuffer(IntPtr bo, out IntPtr @out);
[DllImport(lib, EntryPoint = "kms_bo_unmap", CallingConvention = CallingConvention.Cdecl)]
public static extern int UnmapBuffer(IntPtr bo);
}
}

View file

@ -0,0 +1,181 @@
//
// Linux.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.
//
using System;
using System.Runtime.InteropServices;
using System.Text;
#pragma warning disable 0649 // field is never assigned
namespace OpenTK.Platform.Linux
{
internal partial class Libc
{
private const string lib = "libc";
[DllImport(lib)]
public static extern int dup(int file);
[DllImport(lib)]
public static extern int dup2(int file1, int file2);
[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, uint request, [Out] IntPtr data);
[DllImport(lib)]
public static extern int ioctl(int d, KeyboardIoctlCode request, ref IntPtr data);
[DllImport(lib)]
public static extern int ioctl(int d, KeyboardIoctlCode request, int data);
[DllImport(lib)]
public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags);
[DllImport(lib)]
public static extern int open(IntPtr 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);
public static int read(int fd, out byte b)
{
unsafe
{
fixed (byte* pb = &b)
{
return read(fd, pb, (UIntPtr)1).ToInt32();
}
}
}
public static int read(int fd, out short s)
{
unsafe
{
fixed (short* ps = &s)
{
return read(fd, ps, (UIntPtr)2).ToInt32();
}
}
}
[DllImport(lib)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool isatty(int fd);
}
internal enum ErrorNumber
{
Interrupted = 4,
Again = 11,
InvalidValue = 22,
}
[Flags]
internal enum DirectionFlags
{
None = 0,
Write = 1,
Read = 2
}
[Flags]
internal enum OpenFlags
{
ReadOnly = 0x0000,
WriteOnly = 0x0001,
ReadWrite = 0x0002,
NonBlock = 0x0800,
CloseOnExec = 0x0080000
}
[Flags]
internal enum JoystickEventType : byte
{
Button = 0x01, // button pressed/released
Axis = 0x02, // joystick moved
Init = 0x80 // initial state of device
}
internal 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)
}
internal enum KeyboardIoctlCode
{
GetMode = 0x4b44,
SetMode = 0x4b45,
}
[StructLayout(LayoutKind.Sequential)]
internal struct Stat
{
public IntPtr dev; /* ID of device containing file */
public IntPtr ino; /* inode number */
public IntPtr mode; /* protection */
public IntPtr nlink; /* number of hard links */
public IntPtr uid; /* user ID of owner */
public IntPtr gid; /* group ID of owner */
public IntPtr rdev; /* device ID (if special file) */
public IntPtr size; /* total size, in bytes */
public IntPtr blksize; /* blocksize for file system I/O */
public IntPtr blocks; /* number of 512B blocks allocated */
public IntPtr atime; /* time of last access */
public IntPtr mtime; /* time of last modification */
public IntPtr ctime; /* time of last status change */
}
internal struct EvdevInputId
{
public ushort BusType;
public ushort Vendor;
public ushort Product;
public ushort Version;
}
internal 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
}
}

View file

@ -0,0 +1,63 @@
//
// Poll.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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.Linux
{
internal partial class Libc
{
[DllImport("libc", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern int poll(ref PollFD fd, IntPtr fd_count, int timeout);
public static int poll(ref PollFD fd, int fd_count, int timeout)
{
return poll(ref fd, (IntPtr)fd_count, timeout);
}
}
[Flags]
internal enum PollFlags : short
{
In = 0x01,
Pri = 0x02,
Out = 0x04,
Error = 0x08,
Hup = 0x10,
Invalid = 0x20,
}
[StructLayout(LayoutKind.Sequential)]
internal struct PollFD
{
public int fd;
public PollFlags events;
public PollFlags revents;
}
}

View file

@ -0,0 +1,168 @@
//
// Terminal.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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.Linux
{
internal class Terminal
{
private const string lib = "libc";
[DllImport(lib, EntryPoint = "isatty", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern bool IsTerminal(int fd);
[DllImport(lib, EntryPoint = "tcgetattr", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetAttributes(int fd, out TerminalState state);
[DllImport(lib, EntryPoint = "tcsetattr", CallingConvention = CallingConvention.Cdecl)]
public static extern int SetAttributes(int fd, OptionalActions actions, ref TerminalState state);
}
[Flags]
internal enum InputFlags
{
IGNBRK = 1 << 0,
BRKINT = 1 << 1,
IGNPAR = 1 << 2,
PARMRK = 1 << 3,
INPCK = 1 << 4,
ISTRIP = 1 << 5,
INLCR = 1 << 6,
IGNCR = 1 << 7,
ICRNL = 1 << 8,
IUCLC = 1 << 9,
IXON = 1 << 10,
IXANY = 1 << 11,
IXOFF = 1 << 12,
IMAXBEL = 1 << 13,
IUTF8 = 1 << 14,
}
[Flags]
internal enum OutputFlags
{
OPOST = 1 << 1,
OLCUC = 1 << 2,
ONLCR = 1 << 3,
OCRNL = 1 << 4,
ONOCR = 1 << 5,
ONLRET = 1 << 6,
OFILL = 1 << 7,
OFDEL = 1 << 8,
}
[Flags]
internal enum ControlFlags
{
B0 = 0, // hang up
B50,
B75,
B110,
B134,
B150,
B200,
B300,
B600,
B1200,
B1800,
B2400,
B4800,
B9600,
B19200,
B38400,
}
[Flags]
internal enum LocalFlags
{
ISIG = 0x01,
ICANON = 0x02,
ECHO = 0x08,
}
internal enum OptionalActions
{
NOW = 0,
DRAIN = 1,
FLUSH = 2
}
[StructLayout(LayoutKind.Sequential)]
internal struct TerminalState
{
public InputFlags InputMode;
public OutputFlags OutputMode;
public ControlFlags ControlMode;
public LocalFlags LocalMode;
public byte LineDiscipline;
public ControlCharacters ControlCharacters;
public int InputSpeed;
public int OutputSpeed;
}
[StructLayout(LayoutKind.Sequential)]
internal struct ControlCharacters
{
public byte VINTR;
public byte VQUIT;
public byte VERASE;
public byte VKILL;
public byte VEOF;
public byte VTIME;
public byte VMIN;
public byte VSWTC;
public byte VSTART;
public byte VSTOP;
public byte VSUSP;
public byte VEOL;
public byte VREPRINT;
public byte VDISCARD;
public byte VWERASE;
public byte VLNEXT;
public byte VEOL2;
public byte C17;
public byte C18;
public byte C19;
public byte C20;
public byte C21;
public byte C22;
public byte C23;
public byte C24;
public byte C25;
public byte C26;
public byte C27;
public byte C28;
public byte C29;
public byte C30;
public byte C31;
}
}

View file

@ -0,0 +1,44 @@
//
// Udev.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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.Linux
{
internal class Udev
{
private const string lib = "libudev";
[DllImport(lib, EntryPoint = "udev_new", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr New();
[DllImport(lib, EntryPoint = "udev_destroy", CallingConvention = CallingConvention.Cdecl)]
public static extern void Destroy(IntPtr Udev);
}
}

View file

@ -0,0 +1,413 @@
//
// 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.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
namespace OpenTK.Platform.Linux
{
// Stores platform-specific information about a display
internal class LinuxDisplay
{
public int FD;
public IntPtr Connector;
public IntPtr Crtc;
public IntPtr Encoder;
unsafe public ModeConnector* pConnector { get { return (ModeConnector*)Connector; } }
unsafe public ModeCrtc* pCrtc { get { return (ModeCrtc*)Crtc; } }
unsafe public ModeEncoder* pEncoder { get { return (ModeEncoder*)Encoder; } }
/*
public ModeInfo Mode
{
get
{
if (Crtc == IntPtr.Zero)
throw new InvalidOperationException();
unsafe
{
return pCrtc->mode;
}
}
}
*/
public ModeInfo OriginalMode;
public int Id
{
get
{
if (Crtc == IntPtr.Zero)
{
throw new InvalidOperationException();
}
unsafe
{
return (int)pCrtc->crtc_id;
}
}
}
public LinuxDisplay(int fd, IntPtr c, IntPtr e, IntPtr r)
{
FD = fd;
Connector = c;
Encoder = e;
Crtc = r;
unsafe
{
OriginalMode = pCrtc->mode; // in case we change resolution later on
}
}
}
internal class LinuxDisplayDriver : DisplayDeviceBase
{
private readonly int FD;
private readonly Dictionary<int, int> DisplayIds =
new Dictionary<int, int>();
public LinuxDisplayDriver(int fd)
{
Debug.Print("[KMS] Creating LinuxDisplayDriver for fd:{0}", fd);
Debug.Indent();
try
{
FD = fd;
UpdateDisplays(fd);
}
finally
{
Debug.Unindent();
}
}
/// \internal
/// <summary>
/// Queries the specified GPU for connected displays and, optionally,
/// returns the list of displays.
/// </summary>
/// <returns><c>true</c>, if at least one display is connected, <c>false</c> otherwise.</returns>
/// <param name="fd">The fd for the GPU to query, obtained through open("/dev/dri/card0").</param>
/// <param name="displays">
/// If not null, this will contain a list <see cref="LinuxDisplay"/> instances,
/// one for each connected display.
/// </param>
internal static bool QueryDisplays(int fd, List<LinuxDisplay> displays)
{
unsafe
{
bool has_displays = false;
if (displays != null)
{
displays.Clear();
}
ModeRes* resources = (ModeRes*)Drm.ModeGetResources(fd);
if (resources == null)
{
Debug.Print("[KMS] Drm.ModeGetResources failed.");
return false;
}
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)
{
bool success = false;
LinuxDisplay display = null;
try
{
if (connector->connection == ModeConnection.Connected &&
connector->count_modes > 0)
{
success = QueryDisplay(fd, connector, out display);
has_displays |= success;
}
}
catch (Exception e)
{
Debug.Print("[KMS] Failed to add display. Error: {0}", e);
}
if (success && displays != null)
{
displays.Add(display);
}
else
{
Drm.ModeFreeConnector((IntPtr)connector);
connector = null;
}
}
}
return has_displays;
}
}
private void UpdateDisplays(int fd)
{
unsafe
{
lock (this)
{
AvailableDevices.Clear();
DisplayIds.Clear();
List<LinuxDisplay> displays = new List<LinuxDisplay>();
if (QueryDisplays(fd, displays))
{
foreach (LinuxDisplay display in displays)
{
AddDisplay(display);
}
}
if (AvailableDevices.Count == 0)
{
Debug.Print("[KMS] Failed to find any active displays");
}
}
}
}
private unsafe static ModeEncoder* GetEncoder(int fd, ModeConnector* c)
{
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 encoder;
}
private unsafe static ModeCrtc* GetCrtc(int fd, ModeEncoder* encoder)
{
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 crtc;
}
private unsafe static void GetModes(LinuxDisplay display, DisplayResolution[] modes, out DisplayResolution current)
{
int mode_count = display.pConnector->count_modes;
Debug.Print("[KMS] Display supports {0} mode(s)", mode_count);
for (int i = 0; i < mode_count; i++)
{
ModeInfo* mode = display.pConnector->modes + i;
if (mode != null)
{
Debug.Print("Mode {0}: {1}x{2} @{3}", i,
mode->hdisplay, mode->vdisplay, mode->vrefresh);
DisplayResolution res = GetDisplayResolution(mode);
modes[i] = res;
}
}
if (display.pCrtc->mode_valid != 0)
{
ModeInfo cmode = display.pCrtc->mode;
current = GetDisplayResolution(&cmode);
}
else
{
current = GetDisplayResolution(display.pConnector->modes);
}
Debug.Print("Current mode: {0}", current.ToString());
}
private Rectangle GetBounds(DisplayResolution current)
{
// 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.
int x = AvailableDevices.Count == 0 ?
0 : AvailableDevices[AvailableDevices.Count - 1].Bounds.Right;
int y = 0;
return new Rectangle(
x, y, current.Width, current.Height);
}
private void UpdateDisplayIndices(LinuxDisplay display, DisplayDevice device)
{
if (!DisplayIds.ContainsKey(display.Id))
{
Debug.Print("[KMS] Adding display {0} as {1}", display.Id, AvailableDevices.Count);
DisplayIds.Add(display.Id, AvailableDevices.Count);
}
int index = DisplayIds[display.Id];
if (index >= AvailableDevices.Count)
{
AvailableDevices.Add(device);
}
else
{
AvailableDevices[index] = device;
}
}
private unsafe static bool QueryDisplay(int fd, ModeConnector* c, out LinuxDisplay display)
{
display = null;
// Find corresponding encoder
ModeEncoder* encoder = GetEncoder(fd, c);
if (encoder == null)
{
return false;
}
ModeCrtc* crtc = GetCrtc(fd, encoder);
if (crtc == null)
{
return false;
}
display = new LinuxDisplay(fd, (IntPtr)c, (IntPtr)encoder, (IntPtr)crtc);
return true;
}
private unsafe void AddDisplay(LinuxDisplay display)
{
DisplayResolution[] modes = new DisplayResolution[display.pConnector->count_modes];
DisplayResolution current;
GetModes(display, modes, out current);
bool is_primary = AvailableDevices.Count == 0;
DisplayDevice device = new DisplayDevice(current, is_primary,
modes, GetBounds(current), display);
if (is_primary)
{
Primary = device;
}
UpdateDisplayIndices(display, device);
Debug.Print("[KMS] Added DisplayDevice {0}", device);
}
private unsafe static DisplayResolution GetDisplayResolution(ModeInfo* mode)
{
return new DisplayResolution(
0, 0,
mode->hdisplay, mode->vdisplay,
32, // This is actually part of the framebuffer, not the DisplayResolution
mode->vrefresh);
}
private unsafe static ModeInfo* GetModeInfo(LinuxDisplay display, DisplayResolution resolution)
{
for (int i = 0; i < display.pConnector->count_modes; i++)
{
ModeInfo* mode = display.pConnector->modes + i;
if (mode != null &&
mode->hdisplay == resolution.Width &&
mode->vdisplay == resolution.Height)
{
return mode;
}
}
return null;
}
public override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
{
unsafe
{
LinuxDisplay display = (LinuxDisplay)device.Id;
ModeInfo* mode = GetModeInfo(display, resolution);
int connector_id = display.pConnector->connector_id;
if (mode != null)
{
return Drm.ModeSetCrtc(FD, display.Id, 0, 0, 0,
&connector_id, 1, mode) == 0;
}
return false;
}
}
public override bool TryRestoreResolution(DisplayDevice device)
{
unsafe
{
LinuxDisplay display = (LinuxDisplay)device.Id;
ModeInfo mode = display.OriginalMode;
int connector_id = display.pConnector->connector_id;
return Drm.ModeSetCrtc(FD, display.Id, 0, 0, 0,
&connector_id, 1, &mode) == 0;
}
}
}
}

View file

@ -0,0 +1,197 @@
//
// LinuxFactory.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.
//
using System;
using System.Diagnostics;
using System.IO;
using OpenTK.Graphics;
using OpenTK.Platform.Egl;
namespace OpenTK.Platform.Linux
{
using Egl = OpenTK.Platform.Egl.Egl;
// Linux KMS platform
internal class LinuxFactory : PlatformFactoryBase
{
private int _fd;
private IntPtr gbm_device;
private IntPtr egl_display;
private const string gpu_path = "/dev/dri"; // card0, card1, ...
public LinuxFactory()
{
Debug.Print("[KMS] Using Linux/KMS backend.");
}
private int gpu_fd
{
get
{
lock (this)
{
if (_fd == 0)
{
_fd = CreateDisplay(out gbm_device, out egl_display);
}
return _fd;
}
}
}
private static int CreateDisplay(out IntPtr gbm_device, out IntPtr egl_display)
{
// Query all GPUs until we find one that has a connected display.
// This is necessary in multi-gpu systems, where only one GPU
// can output a signal.
// Todo: allow OpenTK to drive multiple GPUs
// Todo: allow OpenTK to run on an offscreen GPU
// Todo: allow the user to pick a GPU
int fd = 0;
gbm_device = IntPtr.Zero;
egl_display = IntPtr.Zero;
var files = Directory.GetFiles(gpu_path);
foreach (var gpu in files)
{
if (Path.GetFileName(gpu).StartsWith("card"))
{
int test_fd = SetupDisplay(gpu, out gbm_device, out egl_display);
if (test_fd >= 0)
{
try
{
if (LinuxDisplayDriver.QueryDisplays(test_fd, null))
{
fd = test_fd;
break;
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
Debug.Print("[KMS] GPU '{0}' is not connected, skipping.", gpu);
Libc.close(test_fd);
}
}
}
if (fd == 0)
{
Debug.Print("[Error] No valid GPU found, bailing out.");
throw new PlatformNotSupportedException();
}
return fd;
}
private static int SetupDisplay(string gpu, out IntPtr gbm_device, out IntPtr egl_display)
{
Debug.Print("[KMS] Attempting to use gpu '{0}'.", gpu);
gbm_device = IntPtr.Zero;
egl_display = IntPtr.Zero;
int fd = Libc.open(gpu, OpenFlags.ReadWrite | OpenFlags.CloseOnExec);
if (fd < 0)
{
Debug.Print("[KMS] Failed to open gpu");
return fd;
}
Debug.Print("[KMS] GPU '{0}' opened as fd:{1}", gpu, fd);
gbm_device = Gbm.CreateDevice(fd);
if (gbm_device == IntPtr.Zero)
{
throw new NotSupportedException("[KMS] Failed to create GBM device");
}
Debug.Print("[KMS] GBM {0:x} created successfully; ", gbm_device);
egl_display = Egl.GetDisplay(gbm_device);
if (egl_display == IntPtr.Zero)
{
throw new NotSupportedException("[KMS] Failed to create EGL display");
}
Debug.Print("[KMS] EGL display {0:x} created successfully", egl_display);
int major, minor;
if (!Egl.Initialize(egl_display, out major, out minor))
{
ErrorCode error = Egl.GetError();
throw new NotSupportedException("[KMS] Failed to initialize EGL display. Error code: " + error);
}
Debug.Print("[KMS] EGL {0}.{1} initialized successfully on display {2:x}", major, minor, egl_display);
return fd;
}
protected override void Dispose(bool manual)
{
if (egl_display != IntPtr.Zero)
{
Debug.Print("[KMS] Terminating EGL.");
Egl.Terminate(egl_display);
egl_display = IntPtr.Zero;
}
if (gbm_device != IntPtr.Zero)
{
Debug.Print("[KMS] Destroying GBM device.");
Gbm.DestroyDevice(gbm_device);
gbm_device = IntPtr.Zero;
}
if (_fd >= 0)
{
Debug.Print("[KMS] Closing GPU fd.");
Libc.close(_fd);
}
base.Dispose(manual);
}
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new LinuxDisplayDriver(gpu_fd);
}
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new LinuxGraphicsContext(mode, (LinuxWindowInfo)window, shareContext, major, minor, flags);
}
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
return new ContextHandle(Egl.GetCurrentContext());
};
}
}
}

View file

@ -0,0 +1,318 @@
//
// LinuxGraphicsContext.cs
//
// Author:
// thefiddler <stapostol@gmail.com>
//
// Copyright (c) 2006-2014
//
// 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.
//
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using OpenTK.Graphics;
namespace OpenTK.Platform.Linux
{
/// \internal
/// <summary>
/// Defines an IGraphicsContext implementation for the Linux KMS framebuffer.
/// For Linux/X11 and other Unix operating systems, use the more generic
/// <see cref="OpenTK.Platform.Egl.EglUnixContext"/> instead.
/// </summary>
/// <remarks>
/// Note: to display our results, we need to allocate a GBM framebuffer
/// and point the scanout address to that via Drm.ModeSetCrtc.
/// </remarks>
internal class LinuxGraphicsContext : Egl.EglUnixContext
{
private BufferObject bo, bo_next;
private int fd;
private bool is_flip_queued;
private int swap_interval;
public LinuxGraphicsContext(GraphicsMode mode, LinuxWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
: base(mode, window, sharedContext, major, minor, flags)
{
if (mode.Buffers < 1)
{
throw new ArgumentException();
}
fd = window.FD;
PageFlip = HandlePageFlip;
PageFlipPtr = Marshal.GetFunctionPointerForDelegate(PageFlip);
}
public override void SwapBuffers()
{
base.SwapBuffers();
if (is_flip_queued)
{
// Todo: if we don't wait for the page flip,
// we drop all rendering buffers and get a crash
// in Egl.SwapBuffers(). We need to fix that
// before we can disable vsync.
WaitFlip(true); // WaitFlip(SwapInterval > 0)
if (is_flip_queued)
{
Debug.Print("[KMS] Dropping frame");
return;
}
}
bo_next = LockSurface();
int fb = GetFramebuffer(bo_next);
QueueFlip(fb);
}
public override void Update(IWindowInfo window)
{
WaitFlip(true);
base.SwapBuffers();
bo = LockSurface();
int fb = GetFramebuffer(bo);
SetScanoutRegion(fb);
}
public override int SwapInterval
{
get
{
return swap_interval;
}
set
{
// We only support a SwapInterval of 0 (immediate)
// or 1 (vsynced).
// Todo: add support for SwapInterval of -1 (adaptive).
// This requires a small change in WaitFlip().
swap_interval = Math.Clamp(value, 0, 1);
}
}
private void WaitFlip(bool block)
{
PollFD fds = new PollFD();
fds.fd = fd;
fds.events = PollFlags.In;
EventContext evctx = new EventContext();
evctx.version = EventContext.Version;
evctx.page_flip_handler = PageFlipPtr;
int timeout = block ? -1 : 0;
while (is_flip_queued)
{
fds.revents = 0;
if (Libc.poll(ref fds, 1, timeout) < 0)
{
break;
}
if ((fds.revents & (PollFlags.Hup | PollFlags.Error)) != 0)
{
break;
}
if ((fds.revents & PollFlags.In) != 0)
{
Drm.HandleEvent(fd, ref evctx);
}
else
{
break;
}
}
// Page flip has taken place, update buffer objects
if (!is_flip_queued)
{
IntPtr gbm_surface = WindowInfo.Handle;
Gbm.ReleaseBuffer(gbm_surface, bo);
bo = bo_next;
}
}
private void QueueFlip(int buffer)
{
LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo;
if (wnd == null)
{
throw new InvalidOperationException();
}
unsafe
{
int ret = Drm.ModePageFlip(fd, wnd.DisplayDevice.Id, buffer,
PageFlipFlags.FlipEvent, IntPtr.Zero);
if (ret < 0)
{
Debug.Print("[KMS] Failed to enqueue framebuffer flip. Error: {0}", ret);
}
is_flip_queued = true;
}
}
private void SetScanoutRegion(int buffer)
{
LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo;
if (wnd == null)
{
throw new InvalidOperationException();
}
unsafe
{
ModeInfo* mode = wnd.DisplayDevice.pConnector->modes;
int connector_id = wnd.DisplayDevice.pConnector->connector_id;
int crtc_id = wnd.DisplayDevice.Id;
int x = 0;
int y = 0;
int connector_count = 1;
int ret = Drm.ModeSetCrtc(fd, crtc_id, buffer, x, y,
&connector_id, connector_count, mode);
if (ret != 0)
{
Debug.Print("[KMS] Drm.ModeSetCrtc{0}, {1}, {2}, {3}, {4:x}, {5}, {6:x}) failed. Error: {7}",
fd, crtc_id, buffer, x, y, (IntPtr)connector_id, connector_count, (IntPtr)mode, ret);
}
}
}
private BufferObject LockSurface()
{
IntPtr gbm_surface = WindowInfo.Handle;
return Gbm.LockFrontBuffer(gbm_surface);
}
private int GetFramebuffer(BufferObject bo)
{
if (bo == BufferObject.Zero)
{
goto fail;
}
int bo_handle = bo.Handle;
if (bo_handle == 0)
{
Debug.Print("[KMS] Gbm.BOGetHandle({0:x}) failed.", bo);
goto fail;
}
int width = bo.Width;
int height = bo.Height;
int bpp = Mode.ColorFormat.BitsPerPixel;
int depth = Mode.Depth;
int stride = bo.Stride;
if (width == 0 || height == 0 || bpp == 0)
{
Debug.Print("[KMS] Invalid framebuffer format: {0}x{1} {2} {3} {4}",
width, height, stride, bpp, depth);
goto fail;
}
int buffer;
int ret = Drm.ModeAddFB(
fd, width, height,
(byte)depth, (byte)bpp, stride, bo_handle,
out buffer);
if (ret != 0)
{
Debug.Print("[KMS] Drm.ModeAddFB({0}, {1}, {2}, {3}, {4}, {5}, {6}) failed. Error: {7}",
fd, width, height, depth, bpp, stride, bo_handle, ret);
goto fail;
}
bo.SetUserData((IntPtr)buffer, DestroyFB);
return buffer;
fail:
Debug.Print("[Error] Failed to create framebuffer.");
return -1;
}
private readonly IntPtr PageFlipPtr;
private readonly PageFlipCallback PageFlip;
private void HandlePageFlip(int fd,
int sequence,
int tv_sec,
int tv_usec,
IntPtr user_data)
{
is_flip_queued = false;
}
private static readonly DestroyUserDataCallback DestroyFB = HandleDestroyFB;
private static void HandleDestroyFB(BufferObject bo, IntPtr data)
{
IntPtr gbm = bo.Device;
int fb = data.ToInt32();
Debug.Print("[KMS] Destroying framebuffer {0}", fb);
if (fb != 0)
{
Drm.ModeRmFB(Gbm.DeviceGetFD(gbm), fb);
}
}
protected override void Dispose(bool manual)
{
if (manual)
{
// Reset the scanout region
LinuxWindowInfo wnd = WindowInfo as LinuxWindowInfo;
if (wnd != null)
{
unsafe
{
int connector_id = wnd.DisplayDevice.pConnector->connector_id;
ModeInfo mode = wnd.DisplayDevice.OriginalMode;
Drm.ModeSetCrtc(fd,
wnd.DisplayDevice.pCrtc->crtc_id,
wnd.DisplayDevice.pCrtc->buffer_id,
wnd.DisplayDevice.pCrtc->x,
wnd.DisplayDevice.pCrtc->y,
&connector_id,
1,
&mode);
}
}
}
base.Dispose(manual);
}
}
}

View file

@ -0,0 +1,55 @@
//
// 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.
//
using System;
using OpenTK.Platform.Egl;
namespace OpenTK.Platform.Linux
{
internal class LinuxWindowInfo : EglWindowInfo
{
public int FD { get; private set; }
public LinuxDisplay DisplayDevice { get; private set; }
public IntPtr BufferManager { get; private set; }
public LinuxWindowInfo(IntPtr display, int fd, IntPtr gbm, LinuxDisplay display_device)
: base(IntPtr.Zero, display, IntPtr.Zero)
{
if (display_device == null)
{
throw new ArgumentNullException();
}
FD = fd;
BufferManager = gbm;
DisplayDevice = display_device;
// The window handle and surface handle must
// be filled in manually once they are known.
}
}
}

View file

@ -0,0 +1,141 @@
//
// Cgl.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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
using CGLPixelFormat = IntPtr;
using CGLContext = IntPtr;
internal static class Cgl
{
internal enum PixelFormatBool
{
None = 0,
AllRenderers = 1,
Doublebuffer = 5,
Stereo = 6,
AuxBuffers = 7,
MinimumPolicy = 51,
MaximumPolicy = 52,
Offscreen = 53,
AuxDepthStencil = 57,
ColorFloat = 58,
Multisample = 59,
Supersample = 60,
SampleALpha = 61,
SingleRenderer = 71,
NoRecovery = 72,
Accelerated = 73,
ClosestPolicy = 74,
BackingStore = 76,
Window = 80,
Compliant = 83,
PBuffer = 90,
RemotePBuffer = 91,
}
internal enum PixelFormatInt
{
ColorSize = 8,
AlphaSize = 11,
DepthSize = 12,
StencilSize = 13,
AccumSize = 14,
SampleBuffers = 55,
Samples = 56,
RendererID = 70,
DisplayMask = 84,
OpenGLProfile = 99,
VScreenCount = 128,
}
internal enum OpenGLProfileVersion
{
Legacy = 0x100,
Core3_2 = 0x3200,
}
internal enum ParameterNames
{
SwapInterval = 222,
}
internal enum Error
{
None = 0x000,
}
private const string cgl = "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL";
private const string cgs = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon";
[DllImport(cgl, EntryPoint = "CGLGetError")]
internal static extern Error GetError();
[DllImport(cgl, EntryPoint = "CGLErrorString")]
private static extern IntPtr CGLErrorString(Error code);
internal static string ErrorString(Error code)
{
return Marshal.PtrToStringAnsi(CGLErrorString(code));
}
[DllImport(cgl, EntryPoint = "CGLChoosePixelFormat")]
internal static extern Error ChoosePixelFormat(int []attribs, ref CGLPixelFormat format, ref int numPixelFormats);
[DllImport(cgl, EntryPoint = "CGLDescribePixelFormat")]
internal static extern Error DescribePixelFormat(CGLPixelFormat pix, int pix_num, PixelFormatInt attrib, out int value);
[DllImport(cgl, EntryPoint = "CGLDescribePixelFormat")]
internal static extern Error DescribePixelFormat(CGLPixelFormat pix, int pix_num, PixelFormatBool attrib, out bool value);
[DllImport(cgl, EntryPoint = "CGLGetPixelFormat")]
internal static extern CGLPixelFormat GetPixelFormat(CGLContext context);
[DllImport(cgl, EntryPoint = "CGLCreateContext")]
internal static extern Error CreateContext(CGLPixelFormat format, CGLContext share, ref CGLContext context);
[DllImport(cgl, EntryPoint = "CGLDestroyPixelFormat")]
internal static extern Error DestroyPixelFormat(CGLPixelFormat format);
[DllImport(cgl, EntryPoint = "CGLGetCurrentContext")]
internal static extern CGLContext GetCurrentContext();
[DllImport(cgl, EntryPoint = "CGLSetCurrentContext")]
internal static extern Error SetCurrentContext(CGLContext context);
[DllImport(cgl, EntryPoint = "CGLDestroyContext")]
internal static extern Error DestroyContext(CGLContext context);
[DllImport(cgl, EntryPoint = "CGLSetParameter")]
internal static extern Error SetParameter(CGLContext context, int parameter, ref int value);
[DllImport(cgl, EntryPoint = "CGLFlushDrawable")]
internal static extern Error FlushDrawable(CGLContext context);
[DllImport(cgl, EntryPoint = "CGLSetSurface")]
internal static extern Error SetSurface(CGLContext context, int conId, int winId, int surfId);
[DllImport(cgl, EntryPoint = "CGLUpdateContext")]
internal static extern Error UpdateContext(CGLContext context);
[DllImport(cgs, EntryPoint = "CGSMainConnectionID")]
internal static extern int MainConnectionID();
[DllImport(cgs, EntryPoint = "CGSGetSurfaceCount")]
internal static extern Error GetSurfaceCount(int conId, int winId, ref int count);
[DllImport(cgs, EntryPoint = "CGSGetSurfaceList")]
internal static extern Error GetSurfaceList(int conId, int winId, int count, ref int ids, ref int filled);
}
}

View file

@ -0,0 +1,158 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System;
namespace OpenTK.Platform.MacOS
{
//
// http://web.archive.org/web/20100501161453/http://www.classicteck.com/rbarticles/mackeyboard.php
internal enum MacOSKeyCode
{
A = 0,
B = 11,
C = 8,
D = 2,
E = 14,
F = 3,
G = 5,
H = 4,
I = 34,
J = 38,
K = 40,
L = 37,
M = 46,
N = 45,
O = 31,
P = 35,
Q = 12,
R = 15,
S = 1,
T = 17,
U = 32,
V = 9,
W = 13,
X = 7,
Y = 16,
Z = 6,
Key_1 = 18,
Key_2 = 19,
Key_3 = 20,
Key_4 = 21,
Key_5 = 23,
Key_6 = 22,
Key_7 = 26,
Key_8 = 28,
Key_9 = 25,
Key_0 = 29,
Space = 49,
Tilde = 50,
Minus = 27,
Equals = 24,
BracketLeft = 33,
BracketRight = 30,
Backslash = 42,
Semicolon = 41,
Quote = 39,
Comma = 43,
Period = 47,
Slash = 44,
Enter = 36,
Tab = 48,
Backspace = 51,
Return = 52,
Esc = 53,
Command = 55,
Shift = 56,
CapsLock = 57,
OptionAlt = 58,
Control = 59,
KeyPad_Decimal = 65,
KeyPad_Multiply = 67,
KeyPad_Add = 69,
KeyPad_Divide = 75,
KeyPad_Enter = 76,
KeyPad_Subtract = 78,
KeyPad_Equal = 81,
KeyPad_0 = 82,
KeyPad_1 = 83,
KeyPad_2 = 84,
KeyPad_3 = 85,
KeyPad_4 = 86,
KeyPad_5 = 87,
KeyPad_6 = 88,
KeyPad_7 = 89,
KeyPad_8 = 91,
KeyPad_9 = 92,
F1 = 122,
F2 = 120,
F3 = 99,
F4 = 118,
F5 = 96,
F6 = 97,
F7 = 98,
F8 = 100,
F9 = 101,
F10 = 109,
F11 = 103,
F12 = 111,
F13 = 105,
F14 = 107,
F15 = 113,
Menu = 110,
Insert = 114,
Home = 115,
Pageup = 116,
Del = 117,
End = 119,
Pagedown = 121,
Up = 126,
Down = 125,
Left = 123,
Right = 124,
}
[Flags]
internal enum MacOSKeyModifiers
{
None = 0,
Shift = 0x0200,
CapsLock = 0x0400,
Control = 0x1000, //
Command = 0x0100, // Open-Apple - Windows key
Option = 0x0800, // Option key is same position as the alt key on non-mac keyboards.
}
}

View file

@ -0,0 +1,119 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
namespace OpenTK.Platform.MacOS
{
/// \internal
/// <summary>
/// Describes a Carbon window.
/// </summary>
internal sealed class CarbonWindowInfo : IWindowInfo
{
private bool ownHandle = false;
private bool disposed = false;
/// <summary>
/// Constructs a new instance with the specified parameters.
/// </summary>
/// <param name="windowRef">A valid Carbon window reference.</param>
/// <param name="ownHandle"></param>
/// <param name="isControl"></param>
public CarbonWindowInfo(IntPtr windowRef, bool ownHandle, bool isControl)
{
this.Handle = windowRef;
this.ownHandle = ownHandle;
this.IsControl = isControl;
}
public CarbonWindowInfo(IntPtr windowRef, bool ownHandle, bool isControl, GetInt getX, GetInt getY) : this(windowRef, ownHandle, isControl)
{
this.XOffset = getX;
this.YOffset = getY;
}
/// <summary>
/// Gets the window reference for this instance.
/// </summary>
public IntPtr Handle { get; set; }
internal bool GoFullScreenHack { get; set; } = false;
internal bool GoWindowedHack { get; set; } = false;
/// <summary>
/// Gets a value indicating whether this instance refers to a System.Windows.Forms.Control.
/// </summary>
public bool IsControl { get; } = true;
/// <summary>Returns a System.String that represents the current window.</summary>
/// <returns>A System.String that represents the current window.</returns>
public override string ToString()
{
return String.Format("MacOS.CarbonWindowInfo: Handle {0}", this.Handle);
}
// For compatibility with whoever thought it would be
// a good idea to access internal APIs through reflection
// (e.g. MonoGame)
public IntPtr WindowHandle { get { return Handle; } set { Handle = value; } }
public GetInt XOffset { get; set; }
public GetInt YOffset { get; set; }
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
}
if (ownHandle)
{
Handle = IntPtr.Zero;
}
disposed = true;
}
~CarbonWindowInfo()
{
Dispose(false);
}
}
}

View file

@ -0,0 +1,97 @@
//
// Class.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System.Runtime.InteropServices;
using System;
namespace OpenTK.Platform.MacOS
{
internal static class Class
{
public static readonly IntPtr NSAutoreleasePool = Get("NSAutoreleasePool");
public static readonly IntPtr NSDictionary = Get("NSDictionary");
public static readonly IntPtr NSNumber = Get("NSNumber");
public static readonly IntPtr NSUserDefaults = Get("NSUserDefaults");
[DllImport (Cocoa.LibObjC)]
private extern static IntPtr class_getName(IntPtr handle);
[DllImport (Cocoa.LibObjC)]
private extern static bool class_addMethod(IntPtr classHandle, IntPtr selector, IntPtr method, string types);
[DllImport (Cocoa.LibObjC)]
private extern static IntPtr objc_getClass(string name);
[DllImport (Cocoa.LibObjC)]
private extern static IntPtr objc_allocateClassPair(IntPtr parentClass, string name, int extraBytes);
[DllImport (Cocoa.LibObjC)]
private extern static void objc_registerClassPair(IntPtr classToRegister);
[DllImport (Cocoa.LibObjC)]
private extern static void objc_disposeClassPair(IntPtr cls);
public static IntPtr Get(string name)
{
var id = objc_getClass(name);
if (id == IntPtr.Zero)
{
throw new ArgumentException("Unknown class: " + name);
}
return id;
}
public static IntPtr AllocateClass(string className, string parentClass)
{
return objc_allocateClassPair(Get(parentClass), className, 0);
}
public static void RegisterClass(IntPtr handle)
{
objc_registerClassPair(handle);
}
public static void DisposeClass(IntPtr handle)
{
objc_disposeClassPair(handle);
}
public static void RegisterMethod(IntPtr handle, Delegate d, string selector, string typeString)
{
// TypeString info:
// https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
IntPtr p = Marshal.GetFunctionPointerForDelegate(d);
bool r = class_addMethod(handle, Selector.Get(selector), p, typeString);
if (!r)
{
throw new ArgumentException("Could not register method " + d + " in class + " + class_getName(handle));
}
}
}
}

View file

@ -0,0 +1,284 @@
//
// Cocoa.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System.Runtime.InteropServices;
using System;
using System.Drawing;
using System.Drawing.Imaging;
namespace OpenTK.Platform.MacOS
{
internal static class Cocoa
{
private static readonly IntPtr selUTF8String = Selector.Get("UTF8String");
internal const string LibObjC = "/usr/lib/libobjc.dylib";
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, ulong ulong1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSSize size);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, int int1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2, IntPtr intPtr3);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2, IntPtr intPtr3, IntPtr intPtr4, IntPtr intPtr5);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr p1, NSPoint p2);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, bool p1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSPoint p1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSRect rectangle1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSRect rectangle1, int int1, int int2, bool bool1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, uint uint1, IntPtr intPtr1, IntPtr intPtr2, bool bool1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, NSRect rectangle1, int int1, IntPtr intPtr1, IntPtr intPtr2);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr p1, int p2, int p3, int p4, int p5, int p6, int p7, IntPtr p8, NSBitmapFormat p9, int p10, int p11);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static bool SendBool(IntPtr receiver, IntPtr selector);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static bool SendBool(IntPtr receiver, IntPtr selector, int int1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, uint uint1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, uint uint1, IntPtr intPtr1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, IntPtr intPtr1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, IntPtr intPtr1, int int1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, int int1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, bool bool1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, NSPoint point1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, NSRect rect1, bool bool1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static void SendVoid(IntPtr receiver, IntPtr selector, NSRect rect1, IntPtr intPtr1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static int SendInt(IntPtr receiver, IntPtr selector);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static uint SendUint(IntPtr receiver, IntPtr selector);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static ushort SendUshort(IntPtr receiver, IntPtr selector);
[DllImport(LibObjC, EntryPoint="objc_msgSend_fpret")]
private extern static float SendFloat_i386(IntPtr receiver, IntPtr selector);
// On x64 using selector that return CGFloat give you 64 bit == double
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
private extern static double SendFloat_x64(IntPtr receiver, IntPtr selector);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
private extern static float SendFloat_ios(IntPtr receiver, IntPtr selector);
public static float SendFloat(IntPtr receiver, IntPtr selector)
{
if (IntPtr.Size == 4)
{
return SendFloat_i386(receiver, selector);
}
else
{
return (float)SendFloat_x64(receiver, selector);
}
}
// Not the _stret version, perhaps because a NSPoint fits in one register?
// thefiddler: gcc is indeed using objc_msgSend for NSPoint on i386
[DllImport (LibObjC, EntryPoint="objc_msgSend")]
public extern static NSPointF SendPointF(IntPtr receiver, IntPtr selector);
[DllImport (LibObjC, EntryPoint="objc_msgSend")]
public extern static NSPointD SendPointD(IntPtr receiver, IntPtr selector);
public static NSPoint SendPoint(IntPtr receiver, IntPtr selector)
{
NSPoint r = new NSPoint();
unsafe
{
if (IntPtr.Size == 4)
{
NSPointF pf = SendPointF(receiver, selector);
r.X.Value = *(IntPtr *)&pf.X;
r.Y.Value = *(IntPtr *)&pf.Y;
}
else
{
NSPointD pd = SendPointD(receiver, selector);
r.X.Value = *(IntPtr *)&pd.X;
r.Y.Value = *(IntPtr *)&pd.Y;
}
}
return r;
}
[DllImport (LibObjC, EntryPoint="objc_msgSend_stret")]
private extern static void SendRect(out NSRect retval, IntPtr receiver, IntPtr selector);
[DllImport (LibObjC, EntryPoint="objc_msgSend_stret")]
private extern static void SendRect(out NSRect retval, IntPtr receiver, IntPtr selector, NSRect rect1);
public static NSRect SendRect(IntPtr receiver, IntPtr selector)
{
NSRect r;
SendRect(out r, receiver, selector);
return r;
}
public static NSRect SendRect(IntPtr receiver, IntPtr selector, NSRect rect1)
{
NSRect r;
SendRect(out r, receiver, selector, rect1);
return r;
}
public static IntPtr ToNSString(string str)
{
if (str == null)
{
return IntPtr.Zero;
}
unsafe
{
fixed (char* ptrFirstChar = str)
{
var handle = Cocoa.SendIntPtr(Class.Get("NSString"), Selector.Alloc);
handle = Cocoa.SendIntPtr(handle, Selector.Get("initWithCharacters:length:"), (IntPtr)ptrFirstChar, str.Length);
return handle;
}
}
}
public static string FromNSString(IntPtr handle)
{
return Marshal.PtrToStringAuto(SendIntPtr(handle, selUTF8String));
}
public static unsafe IntPtr ToNSImage(Image img)
{
using (System.IO.MemoryStream s = new System.IO.MemoryStream())
{
img.Save(s, ImageFormat.Png);
byte[] b = s.ToArray();
fixed (byte* pBytes = b)
{
IntPtr nsData = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSData"), Selector.Alloc),
Selector.Get("initWithBytes:length:"), (IntPtr)pBytes, b.Length);
IntPtr nsImage = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSImage"), Selector.Alloc),
Selector.Get("initWithData:"), nsData);
Cocoa.SendVoid(nsData, Selector.Release);
return nsImage;
}
}
}
public static IntPtr GetStringConstant(IntPtr handle, string symbol)
{
var indirect = NS.GetSymbol(handle, symbol);
if (indirect == IntPtr.Zero)
{
return IntPtr.Zero;
}
var actual = Marshal.ReadIntPtr(indirect);
if (actual == IntPtr.Zero)
{
return IntPtr.Zero;
}
return actual;
}
public static IntPtr AppKitLibrary;
public static IntPtr FoundationLibrary;
public static void Initialize()
{
if (AppKitLibrary != IntPtr.Zero)
{
return;
}
AppKitLibrary = NS.LoadLibrary("/System/Library/Frameworks/AppKit.framework/AppKit");
FoundationLibrary = NS.LoadLibrary("/System/Library/Frameworks/Foundation.framework/Foundation");
}
}
}

View file

@ -0,0 +1,138 @@
//
// NSApplication.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace OpenTK.Platform.MacOS
{
internal static class NSApplication
{
internal static IntPtr Handle;
private static readonly IntPtr selQuit = Selector.Get("quit");
private static readonly int ThreadId =
System.Threading.Thread.CurrentThread.ManagedThreadId;
internal static void Initialize() { }
static NSApplication()
{
Cocoa.Initialize();
// Register a Quit method to be called on cmd-q
IntPtr nsapp = Class.Get("NSApplication");
Class.RegisterMethod(nsapp, OnQuitHandler, "quit", "v@:");
// Fetch the application handle
Handle = Cocoa.SendIntPtr(nsapp, Selector.Get("sharedApplication"));
// Setup the application
Cocoa.SendBool(Handle, Selector.Get("setActivationPolicy:"), (int)NSApplicationActivationPolicy.Regular);
Cocoa.SendVoid(Handle, Selector.Get("discardEventsMatchingMask:beforeEvent:"), uint.MaxValue, IntPtr.Zero);
Cocoa.SendVoid(Handle, Selector.Get("activateIgnoringOtherApps:"), true);
if (Cocoa.SendIntPtr(Handle, Selector.Get("mainMenu")) == IntPtr.Zero)
{
// Create the menu bar
var menubar = Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc);
var menuItem = Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc);
// Add menu item to bar, and bar to application
Cocoa.SendIntPtr(menubar, Selector.Get("addItem:"), menuItem);
Cocoa.SendIntPtr(Handle, Selector.Get("setMainMenu:"), menubar);
// Add a "Quit" menu item and bind the button.
var appMenu = Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc);
var quitMenuItem = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc),
Selector.Get("initWithTitle:action:keyEquivalent:"), Cocoa.ToNSString("Quit"), selQuit, Cocoa.ToNSString("q"));
Cocoa.SendIntPtr(appMenu, Selector.Get("addItem:"), quitMenuItem);
Cocoa.SendIntPtr(menuItem, Selector.Get("setSubmenu:"), appMenu);
// Tell cocoa we're ready to run the application (usually called by [NSApp run]).
// Note: if a main menu exists, then this method has already been called and
// calling it again will result in a crash. For this reason, we only call it
// when we create our own main menu.
Cocoa.SendVoid(Handle, Selector.Get("finishLaunching"));
}
// Disable momentum scrolling and long-press key pop-ups
IntPtr settings = Cocoa.SendIntPtr(Class.NSDictionary, Selector.Alloc);
//IntPtr momentum_scrolling = Cocoa.SendIntPtr(Class.NSNumber, Selector.Get("numberWithBool:"), false);
IntPtr press_and_hold = Cocoa.SendIntPtr(Class.NSNumber, Selector.Get("numberWithBool:"), false);
// Initialize and register the settings dictionary
settings =
Cocoa.SendIntPtr(settings, Selector.Get("initWithObjectsAndKeys:"),
//momentum_scrolling, Cocoa.ToNSString("AppleMomentumScrollSupported"),
press_and_hold, Cocoa.ToNSString("ApplePressAndHoldEnabled"),
IntPtr.Zero);
Cocoa.SendVoid(
Cocoa.SendIntPtr(Class.NSUserDefaults, Selector.Get("standardUserDefaults")),
Selector.Get("registerDefaults:"),
settings);
Cocoa.SendVoid(settings, Selector.Release);
}
internal static bool IsUIThread
{
get
{
int thread_id = Thread.CurrentThread.ManagedThreadId;
bool is_ui_thread = thread_id == NSApplication.ThreadId;
if (!is_ui_thread)
{
Debug.Print("[Warning] UI resources must be disposed in the UI thread #{0}, not #{1}.",
NSApplication.ThreadId, thread_id);
}
return is_ui_thread;
}
}
internal static event EventHandler<CancelEventArgs> Quit = delegate { };
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate void OnQuitDelegate(IntPtr self, IntPtr cmd);
private static OnQuitDelegate OnQuitHandler = OnQuit;
private static void OnQuit(IntPtr self, IntPtr cmd)
{
var e = new CancelEventArgs();
Quit(null, e);
if (!e.Cancel)
{
Cocoa.SendVoid(Handle, Selector.Get("terminate:"), Handle);
}
}
}
}

View file

@ -0,0 +1,36 @@
//
// NSApplicationActivationPolicy.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
namespace OpenTK.Platform.MacOS
{
internal enum NSApplicationActivationPolicy
{
Regular,
Accessory,
Prohibited,
}
}

View file

@ -0,0 +1,46 @@
//
// NSApplicationPresentationOptions.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
namespace OpenTK.Platform.MacOS
{
internal enum NSApplicationPresentationOptions
{
Default = 0,
AutoHideDock = 1,
HideDock = 2,
AutoHideMenuBar = 4,
HideMenuBar = 8,
DisableAppleMenu = 16,
DisableProcessSwitching = 32,
DisableForceQuit = 64,
DisableSessionTermination = 128,
DisableHideApplication = 256,
DisableMenuBarTransparency = 512,
FullScreen = 1024,
AutoHideToolbar = 2048,
}
}

View file

@ -0,0 +1,34 @@
using System;
namespace OpenTK.Platform.MacOS
{
/// <summary>
/// The <see cref="NSAutoreleasePool"/> class is a wrapper around the native objective-C NSAutoreleasePool.
/// In particular, this construct mimics the usage of an @autorelease block and can be used in much the same way,
/// only with a C# using block instead.
/// </summary>
public sealed class NSAutoreleasePool : IDisposable
{
private readonly IntPtr _autoreleasePool;
/// <summary>
/// Allocates and initializes a new <see cref="NSAutoreleasePool"/>.
/// </summary>
public NSAutoreleasePool()
{
var uninitializedPool = Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Alloc);
_autoreleasePool = Cocoa.SendIntPtr(uninitializedPool, Selector.Init);
}
/// <summary>
/// Disposes of the <see cref="NSAutoreleasePool"/> instance, draining it.
/// </summary>
public void Dispose()
{
if (_autoreleasePool != IntPtr.Zero)
{
Cocoa.SendVoid(_autoreleasePool, Selector.Get("drain"));
}
}
}
}

View file

@ -0,0 +1,36 @@
//
// NSBackingStore.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
namespace OpenTK.Platform.MacOS
{
internal enum NSBackingStore
{
Retained,
Nonretained,
Buffered,
}
}

View file

@ -0,0 +1,40 @@
//
// NSBitmapFormat.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.
//
using System;
namespace OpenTK.Platform.MacOS
{
[Flags]
internal enum NSBitmapFormat
{
AlphaFirst = 1 << 0,
AlphaNonpremultiplied = 1 << 1,
FloatingPointSamples = 1 << 2
}
}

View file

@ -0,0 +1,23 @@
using System;
namespace OpenTK.Platform.MacOS
{
/// <summary>
/// Used by draggingSourceOperationMask() <see cref="CocoaNativeWindow.DraggingEntered"/> to get permission for dropped object
/// also used for respones to drag source
/// Values for enum can be found here https://developer.apple.com/documentation/appkit/nsdragoperation?language=objc
/// or for Mac users /System/Library/Frameworks/AppKit.framework/Headers
/// </summary>
internal enum NSDragOperation : int
{
None = 0,
Copy = 1,
Link = 2,
Generic = 4,
Private = 8,
AllObsolete = 15,
Move = 16,
Delete = 32,
Every = Int32.MaxValue,
}
}

View file

@ -0,0 +1,45 @@
//
// NSEventModifierMask.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
namespace OpenTK.Platform.MacOS
{
[Flags]
internal enum NSEventModifierMask : uint
{
AlphaShiftKeyMask = 65536U,
ShiftKeyMask = 131072U,
ControlKeyMask = 262144U,
AlternateKeyMask = 524288U,
CommandKeyMask = 1048576U,
NumericPadKeyMask = 2097152U,
HelpKeyMask = 4194304U,
FunctionKeyMask = 8388608U,
DeviceIndependentModifierFlagsMask = 4294901760U,
}
}

View file

@ -0,0 +1,64 @@
//
// NSEventType.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
namespace OpenTK.Platform.MacOS
{
internal enum NSEventType
{
LeftMouseDown = 1,
LeftMouseUp = 2,
RightMouseDown = 3,
RightMouseUp = 4,
MouseMoved = 5,
LeftMouseDragged = 6,
RightMouseDragged = 7,
MouseEntered = 8,
MouseExited = 9,
KeyDown = 10,
KeyUp = 11,
FlagsChanged = 12,
AppKitDefined = 13,
SystemDefined = 14,
ApplicationDefined = 15,
Periodic = 16,
CursorUpdate = 17,
Rotate = 18,
BeginGesture = 19,
EndGesture = 20,
ScrollWheel = 22,
TabletPoint = 23,
TabletProximity = 24,
OtherMouseDown = 25,
OtherMouseUp = 26,
OtherMouseDragged = 27,
Gesture = 29,
Magnify = 30,
Swipe = 31,
SmartMagnify = 32,
QuickLook = 33,
}
}

View file

@ -0,0 +1,201 @@
//
// NSFloat.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.
//
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
// NSFloat is defined as float on 32bit systems and double on 64bit.
// We have to account for this peculiarity in order to run OpenTK on
// 64bit Mac platforms.
// We do this by adding implicit conversions between IntPtr and float/double.
// Note that this conversion is against C# best practices, as it can lose information.
// However, NSFloat is used internally in places where this precision loss does not matter.
internal struct NSFloat
{
private IntPtr _value;
public IntPtr Value
{
get { return _value; }
set { _value = value; }
}
public static implicit operator NSFloat(float v)
{
NSFloat f = new NSFloat();
unsafe
{
if (IntPtr.Size == 4)
{
f.Value = *(IntPtr*)&v;
}
else
{
double d = v;
f.Value = *(IntPtr*)&d;
}
}
return f;
}
public static implicit operator NSFloat(double v)
{
NSFloat f = new NSFloat();
unsafe
{
if (IntPtr.Size == 4)
{
float fv = (float)v;
f.Value = *(IntPtr*)&fv;
}
else
{
f.Value = *(IntPtr*)&v;
}
}
return f;
}
public static implicit operator float(NSFloat f)
{
unsafe
{
if (IntPtr.Size == 4)
{
return *(float*)&f._value;
}
else
{
return (float)*(double*)&f._value;
}
}
}
public static implicit operator double(NSFloat f)
{
unsafe
{
if (IntPtr.Size == 4)
{
return (double)*(float*)&f._value;
}
else
{
return *(double*)&f._value;
}
}
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct NSPoint
{
public NSFloat X;
public NSFloat Y;
public static implicit operator NSPoint(PointF p)
{
return new NSPoint
{
X = p.X,
Y = p.Y
};
}
public static implicit operator PointF(NSPoint s)
{
return new PointF(s.X, s.Y);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct NSSize
{
public NSFloat Width;
public NSFloat Height;
public static implicit operator NSSize(SizeF s)
{
return new NSSize
{
Width = s.Width,
Height = s.Height
};
}
public static implicit operator SizeF(NSSize s)
{
return new SizeF(s.Width, s.Height);
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct NSRect
{
public NSPoint Location;
public NSSize Size;
public NSFloat Width { get { return Size.Width; } }
public NSFloat Height { get { return Size.Height; } }
public NSFloat X { get { return Location.X; } }
public NSFloat Y { get { return Location.Y; } }
public static implicit operator NSRect(RectangleF s)
{
return new NSRect
{
Location = s.Location,
Size = s.Size
};
}
public static implicit operator RectangleF(NSRect s)
{
return new RectangleF(s.Location, s.Size);
}
}
// Using IntPtr in NSFloat cause that if imported function
// return struct that consist of them you will get wrong data
// This types are used for such function.
[StructLayout(LayoutKind.Sequential)]
internal struct NSPointF
{
public float X;
public float Y;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NSPointD
{
public double X;
public double Y;
}
}

View file

@ -0,0 +1,50 @@
//
// NSOpenGLContextParameter.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
namespace OpenTK.Platform.MacOS
{
internal enum NSOpenGLContextParameter
{
[Obsolete] SwapRectangle = 200,
[Obsolete] SwapRectangleEnable = 201,
[Obsolete] RasterizationEnable = 221,
SwapInterval = 222,
SurfaceOrder = 235,
SurfaceOpacity = 236,
[Obsolete] StateValidation = 301,
SurfaceBackingSize = 304, // Lion
[Obsolete] SurfaceSurfaceVolatile = 306,
ReclaimResources = 308, // Lion
CurrentRendererID = 309, // Lion
GpuVertexProcessing = 310, // Lion
GpuFragmentProcessing = 311, // Lion
HasDrawable = 314, // Lion
MpsSwapsInFlight = 315, // Lion
}
}

View file

@ -0,0 +1,74 @@
//
// NSOpenGLPixelFormatAttribute.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
namespace OpenTK.Platform.MacOS
{
internal enum NSOpenGLPixelFormatAttribute
{
AllRenderers = 1,
TrippleBuffer = 3, // Lion
DoubleBuffer = 5,
Stereo = 6,
AuxBuffers = 7,
ColorSize = 8,
AlphaSize = 11,
DepthSize = 12,
StencilSize = 13,
AccumSize = 14,
MinimumPolicy = 51,
MaximumPolicy = 52,
OffScreen = 53,
FullScreen = 54,
SampleBuffers = 55,
Samples = 56,
AuxDepthStencil = 57,
ColorFloat = 58,
Multisample = 59,
Supersample = 60,
SampleAlpha = 61,
RendererID = 70,
SingleRenderer = 71,
NoRecovery = 72,
Accelerated = 73,
ClosestPolicy = 74,
[Obsolete] Robust = 75,
BackingStore = 76,
[Obsolete] MPSafe = 78,
Window = 80,
[Obsolete] MultiScreen = 81,
Compliant = 83,
ScreenMask = 84,
PixelBuffer = 90,
RemotePixelBuffer = 91,
AllowOfflineRenderers = 96,
AcceleratedCompute = 97,
OpenGLProfile = 99, // Lion
VirtualScreenCount = 128,
}
}

View file

@ -0,0 +1,35 @@
//
// NSOpenGLProfile.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
namespace OpenTK.Platform.MacOS
{
internal enum NSOpenGLProfile
{
VersionLegacy = 4096,
Version3_2Core = 12800,
}
}

View file

@ -0,0 +1,46 @@
//
// NSTrackingAreaOptions.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
namespace OpenTK.Platform.MacOS
{
[Flags]
internal enum NSTrackingAreaOptions
{
MouseEnteredAndExited = 1,
MouseMoved = 2,
CursorUpdate = 4,
ActiveWhenFirstResponder = 16,
ActiveInKeyWindow = 32,
ActiveInActiveApp = 64,
ActiveAlways = 128,
AssumeInside = 256,
InVisibleRect = 512,
EnabledDuringMouseDrag = 1024,
}
}

View file

@ -0,0 +1,49 @@
//
// NSWindowStyle.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
namespace OpenTK.Platform.MacOS
{
[Flags]
internal enum NSWindowStyle
{
Borderless = 0,
Titled = 1,
Closable = 2,
Miniaturizable = 4,
Resizable = 8,
Utility = 16,
DocModal = 64,
NonactivatingPanel = 128,
TexturedBackground = 256,
Unscaled = 2048,
UnifiedTitleAndToolbar = 4096,
Hud = 8192,
FullScreenWindow = 16384,
}
}

View file

@ -0,0 +1,46 @@
//
// Selector.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
internal static class Selector
{
// Frequently used selectors
public static readonly IntPtr Init = Selector.Get("init");
public static readonly IntPtr InitWithCoder = Selector.Get("initWithCoder:");
public static readonly IntPtr Alloc = Selector.Get("alloc");
public static readonly IntPtr Retain = Selector.Get("retain");
public static readonly IntPtr Release = Selector.Get("release");
public static readonly IntPtr Autorelease = Selector.Get("autorelease");
[DllImport ("/usr/lib/libobjc.dylib", EntryPoint="sel_registerName")]
public extern static IntPtr Get(string name);
}
}

View file

@ -0,0 +1,410 @@
//
// CocoaContext.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
using OpenTK.Platform;
using OpenTK.Graphics;
using OpenTK.Platform.MacOS;
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace OpenTK
{
internal class CocoaContext : DesktopGraphicsContext
{
private CocoaWindowInfo cocoaWindow;
private IntPtr shareContextRef;
private static readonly IntPtr NSOpenGLContext = Class.Get("NSOpenGLContext");
private static readonly IntPtr selCurrentContext = Selector.Get("currentContext");
private static readonly IntPtr selFlushBuffer = Selector.Get("flushBuffer");
private static readonly IntPtr selMakeCurrentContext = Selector.Get("makeCurrentContext");
private static readonly IntPtr selUpdate = Selector.Get("update");
private static readonly IntPtr opengl = NS.AddImage(
"/System/Library/Frameworks/OpenGL.framework/OpenGL",
AddImageFlags.ReturnOnError);
private static readonly IntPtr opengles = NS.AddImage(
"/System/Library/Frameworks/OpenGL.framework/OpenGLES",
AddImageFlags.ReturnOnError);
static CocoaContext()
{
Cocoa.Initialize();
}
public CocoaContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, int majorVersion, int minorVersion)
{
Debug.Print("Context Type: {0}", shareContext);
Debug.Print("Window info: {0}", window);
cocoaWindow = (CocoaWindowInfo)window;
if (shareContext is CocoaContext)
{
shareContextRef = ((CocoaContext)shareContext).Handle.Handle;
}
if (shareContext is GraphicsContext)
{
ContextHandle shareHandle = shareContext != null ? (shareContext as IGraphicsContextInternal).Context : (ContextHandle)IntPtr.Zero;
shareContextRef = shareHandle.Handle;
}
if (shareContextRef == IntPtr.Zero)
{
Debug.Print("No context sharing will take place.");
}
CreateContext(mode, cocoaWindow, shareContextRef, majorVersion, minorVersion, true);
}
public CocoaContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int majorVersion, int minorVersion)
{
if (handle == ContextHandle.Zero)
{
throw new ArgumentException("handle");
}
if (window == null)
{
throw new ArgumentNullException("window");
}
Handle = handle;
cocoaWindow = (CocoaWindowInfo)window;
}
private void AddPixelAttrib(List<NSOpenGLPixelFormatAttribute> attributes, NSOpenGLPixelFormatAttribute attribute)
{
Debug.Print(attribute.ToString());
attributes.Add(attribute);
}
private void AddPixelAttrib(List<NSOpenGLPixelFormatAttribute> attributes, NSOpenGLPixelFormatAttribute attribute, int value)
{
Debug.Print("{0} : {1}", attribute, value);
attributes.Add(attribute);
attributes.Add((NSOpenGLPixelFormatAttribute)value);
}
private void CreateContext(GraphicsMode mode, CocoaWindowInfo cocoaWindow, IntPtr shareContextRef, int majorVersion, int minorVersion, bool fullscreen)
{
// Prepare attributes
IntPtr pixelFormat = SelectPixelFormat(mode, majorVersion, minorVersion);
if (pixelFormat == IntPtr.Zero)
{
throw new GraphicsException(String.Format(
"Failed to contruct NSOpenGLPixelFormat for GraphicsMode '{0}'",
mode));
}
// Create context
var context = Cocoa.SendIntPtr(NSOpenGLContext, Selector.Alloc);
context = Cocoa.SendIntPtr(context, Selector.Get("initWithFormat:shareContext:"), pixelFormat, shareContextRef);
if (context == IntPtr.Zero)
{
throw new GraphicsException(String.Format(
"Failed to construct NSOpenGLContext",
mode));
}
// Release pixel format
Cocoa.SendVoid(pixelFormat, Selector.Release);
pixelFormat = IntPtr.Zero;
// Attach the view
Cocoa.SendVoid(context, Selector.Get("setView:"), cocoaWindow.ViewHandle);
Cocoa.SendVoid(cocoaWindow.ViewHandle, Selector.Get("setWantsBestResolutionOpenGLSurface:"), true);
// Finalize
Handle = new ContextHandle(context);
Mode = GetGraphicsMode(context);
Update(cocoaWindow);
}
private IntPtr SelectPixelFormat(GraphicsMode mode, int majorVersion, int minorVersion)
{
List<NSOpenGLPixelFormatAttribute> attributes = new List<NSOpenGLPixelFormatAttribute>();
var profile = NSOpenGLProfile.VersionLegacy;
if (majorVersion > 3 || (majorVersion == 3 && minorVersion >= 2))
{
profile = NSOpenGLProfile.Version3_2Core;
Debug.Print("Running the OpenGL core profile.");
}
else
{
Debug.Print("Running the legacy OpenGL profile. Start with version major=3, minor=2 or later for the 3.2 profile.");
}
Debug.Print("NSGL pixel format attributes:");
Debug.Indent();
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.OpenGLProfile, (int)profile);
if (mode.ColorFormat.BitsPerPixel > 0)
{
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.ColorSize, mode.ColorFormat.BitsPerPixel);
}
if (mode.Depth > 0)
{
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.DepthSize, mode.Depth);
}
if (mode.Stencil > 0)
{
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.StencilSize, mode.Stencil);
}
if (mode.AccumulatorFormat.BitsPerPixel > 0)
{
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.AccumSize, mode.AccumulatorFormat.BitsPerPixel);
}
if (mode.Samples > 1)
{
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.SampleBuffers, 1);
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.Samples, mode.Samples);
}
if (mode.Buffers > 1)
{
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.DoubleBuffer);
}
// If at least a single accelerated pixel format is available,
// then use that. If no accelerated formats are available, fall
// back to software rendering.
if (IsAccelerationSupported())
{
AddPixelAttrib(attributes, NSOpenGLPixelFormatAttribute.Accelerated);
}
AddPixelAttrib(attributes, (NSOpenGLPixelFormatAttribute)0);
Debug.Unindent();
Debug.Write("Attribute array: ");
for (int i = 0; i < attributes.Count; i++)
{
Debug.Write(attributes[i].ToString() + " ");
}
Debug.WriteLine("");
// Create pixel format
var pixelFormat = Cocoa.SendIntPtr(Class.Get("NSOpenGLPixelFormat"), Selector.Alloc);
unsafe
{
fixed (NSOpenGLPixelFormatAttribute* ptr = attributes.ToArray())
{
pixelFormat = Cocoa.SendIntPtr(pixelFormat, Selector.Get("initWithAttributes:"), (IntPtr)ptr);
}
}
return pixelFormat;
}
private bool IsAccelerationSupported()
{
IntPtr pf = IntPtr.Zero;
int count = 0;
Cgl.ChoosePixelFormat(new int[] { (int)Cgl.PixelFormatBool.Accelerated, 0 },
ref pf, ref count);
if (pf != IntPtr.Zero)
{
Cgl.DestroyPixelFormat(pf);
}
return pf != IntPtr.Zero;
}
private GraphicsMode GetGraphicsMode(IntPtr context)
{
IntPtr cgl_context = Cocoa.SendIntPtr(context, Selector.Get("CGLContextObj"));
IntPtr cgl_format = Cgl.GetPixelFormat(cgl_context);
int id = 0; // CGL does not support the concept of a pixel format id
int color, depth, stencil, samples, accum;
bool doublebuffer, stereo;
Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.ColorSize, out color);
Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.DepthSize, out depth);
Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.StencilSize, out stencil);
Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.Samples, out samples);
Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatInt.AccumSize, out accum);
Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatBool.Doublebuffer, out doublebuffer);
Cgl.DescribePixelFormat(cgl_format, 0, Cgl.PixelFormatBool.Stereo, out stereo);
return new GraphicsMode((IntPtr)id, color, depth, stencil, samples, accum, doublebuffer ? 2 : 1, stereo);
}
public override void SwapBuffers()
{
Cocoa.SendVoid(Handle.Handle, selFlushBuffer);
}
public override void MakeCurrent(IWindowInfo window)
{
Cocoa.SendVoid(Handle.Handle, selMakeCurrentContext);
}
public override bool IsCurrent
{
get
{
return Handle.Handle == CurrentContext;
}
}
public static IntPtr CurrentContext
{
get
{
return Cocoa.SendIntPtr(NSOpenGLContext, selCurrentContext);
}
}
private unsafe void SetContextValue (int val, NSOpenGLContextParameter par)
{
int* p = &val;
Cocoa.SendVoid(Handle.Handle, Selector.Get("setValues:forParameter:"), (IntPtr)p, (int)par);
}
private unsafe int GetContextValue (NSOpenGLContextParameter par)
{
int ret;
int* p = &ret;
Cocoa.SendVoid(Handle.Handle, Selector.Get("getValues:forParameter:"), (IntPtr)p, (int)par);
return ret;
}
public override int SwapInterval
{
get
{
return GetContextValue(NSOpenGLContextParameter.SwapInterval);
}
set
{
if (value < 0)
{
// NSOpenGL does not offer EXT_swap_control_tear yet
value = 1;
}
SetContextValue(value, NSOpenGLContextParameter.SwapInterval);
}
}
public override void Update(IWindowInfo window)
{
Cocoa.SendVoid(Handle.Handle, selUpdate);
}
protected override void Dispose(bool disposing)
{
if (IsDisposed || Handle.Handle == IntPtr.Zero)
{
return;
}
Debug.Print("Disposing of Cocoa context.");
if (!NSApplication.IsUIThread)
{
return;
}
using (var pool = new NSAutoreleasePool())
{
if (IsCurrent)
{
Cocoa.SendVoid(NSOpenGLContext, Selector.Get("clearCurrentContext"));
}
Cocoa.SendVoid(Handle.Handle, Selector.Get("clearDrawable"));
Cocoa.SendVoid(Handle.Handle, Selector.Get("release"));
}
Handle = ContextHandle.Zero;
IsDisposed = true;
}
public override IntPtr GetAddress(IntPtr function)
{
unsafe
{
// Add a leading underscore to the function name
// As of OpenGL 4.4, all functions are < 64 bytes
// in length. Double that just to be sure.
const int max = 128;
byte* fun = stackalloc byte[max];
byte* ptr = fun;
byte* cur = (byte*)function.ToPointer();
int i = 0;
*ptr++ = (byte)'_';
while (*cur != 0 && ++i < max)
{
*ptr++ = *cur++;
}
if (i >= max - 1)
{
Debug.Print("Function {0} too long. Loading will fail.",
Marshal.PtrToStringAnsi(function));
}
IntPtr address = IntPtr.Zero;
IntPtr symbol = IntPtr.Zero;
if (opengl != IntPtr.Zero)
{
symbol = NS.LookupSymbolInImage(opengl, new IntPtr(fun),
SymbolLookupFlags.Bind | SymbolLookupFlags.ReturnOnError);
}
if (symbol == IntPtr.Zero && opengles != IntPtr.Zero)
{
symbol = NS.LookupSymbolInImage(opengles, new IntPtr(fun),
SymbolLookupFlags.Bind | SymbolLookupFlags.ReturnOnError);
}
if (symbol != IntPtr.Zero)
{
address = NS.AddressOfSymbol(symbol);
}
return address;
}
}
}
}

View file

@ -0,0 +1,113 @@
//
// CocoaWindowInfo.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// 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.
//
using System;
using System.Diagnostics;
namespace OpenTK.Platform.MacOS
{
/// \internal
/// <summary>
/// Describes a Cocoa window.
/// </summary>
internal sealed class CocoaWindowInfo : IWindowInfo
{
private static readonly IntPtr selContentView = Selector.Get("contentView");
private bool disposed = false;
/// <summary>
/// Constructs a new instance with the specified parameters.
/// </summary>
/// <remarks>This constructor assumes that the NSWindow's contentView is the NSView we want to attach to our context.</remarks>
/// <param name="nsWindowRef">A valid NSWindow reference.</param>
public CocoaWindowInfo(IntPtr nsWindowRef) : this(nsWindowRef, Cocoa.SendIntPtr(nsWindowRef, selContentView))
{
}
/// <summary>
/// Constructs a new instance with the specified parameters.
/// </summary>
/// <param name="nsWindowRef">A valid NSWindow reference.</param>
/// <param name="nsViewRef">A valid NSView reference.</param>
public CocoaWindowInfo(IntPtr nsWindowRef, IntPtr nsViewRef)
{
this.Handle = nsWindowRef;
this.ViewHandle = nsViewRef;
Cocoa.SendVoid(nsWindowRef, Selector.Retain);
}
/// <summary>
/// Gets the window reference for this instance.
/// </summary>
public IntPtr Handle { get; }
/// <summary>
/// Gets the view reference for this instance.
/// </summary>
public IntPtr ViewHandle { get; }
/// <summary>Returns a System.String that represents the current window.</summary>
/// <returns>A System.String that represents the current window.</returns>
public override string ToString()
{
return String.Format("MacOS.CocoaWindowInfo: NSWindow {0}, NSView {1}", Handle, ViewHandle);
}
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
Cocoa.SendVoid(Handle, Selector.Release);
}
else
{
Debug.Print("CocoaWindowInfo:{0} leaked, did you forget to call Dispose()?", Handle);
}
disposed = true;
}
#if DEBUG
~CocoaWindowInfo()
{
Dispose(false);
}
#endif
}
}

View file

@ -0,0 +1,34 @@
// See License.txt file for copyright details
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
[StructLayout(LayoutKind.Sequential)]
internal struct CVTime
{
public Int64 timeValue;
public Int32 timeScale;
public Int32 flags;
}
internal class CV
{
private const string LibPath = "/System/Library/Frameworks/CoreVideo.framework/Versions/Current/CoreVideo";
internal enum TimeFlags : Int32
{
TimeIsIndefinite = 1 << 0
}
[DllImport(LibPath, EntryPoint = "CVDisplayLinkCreateWithCGDisplay")]
public extern static IntPtr DisplayLinkCreateWithCGDisplay(IntPtr currentDisplay, out IntPtr displayLink);
[DllImport(LibPath, EntryPoint = "CVDisplayLinkGetNominalOutputVideoRefreshPeriod")]
public extern static CVTime DisplayLinkGetNominalOutputVideoRefreshPeriod(IntPtr displayLink);
[DllImport(LibPath, EntryPoint = "CVDisplayLinkRelease")]
public extern static void DisplayLinkRelease(IntPtr displayLink);
}
}

View file

@ -0,0 +1,117 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
// Created by Erik Ylvisaker on 3/17/08.
using System;
namespace OpenTK.Platform.MacOS
{
internal class MacOSException : Exception
{
public MacOSException()
{}
public MacOSException(OSStatus errorCode)
: base("Error Code " + ((int)errorCode).ToString() + ": " + errorCode.ToString())
{
this.ErrorCode = errorCode;
}
public MacOSException(OSStatus errorCode, string message)
: base(message)
{
this.ErrorCode = errorCode;
}
internal MacOSException(int errorCode, string message)
: base(message)
{
this.ErrorCode = (OSStatus)errorCode;
}
public OSStatus ErrorCode { get; }
}
internal enum OSStatus
{
NoError = 0,
ParameterError = -50, /*error in user parameter list*/
NoHardwareError = -200, /*Sound Manager Error Returns*/
NotEnoughHardwareError = -201, /*Sound Manager Error Returns*/
UserCanceledError = -128,
QueueError = -1, /*queue element not found during deletion*/
VTypErr = -2, /*invalid queue element*/
CorErr = -3, /*core routine number out of range*/
UnimpErr = -4, /*unimplemented core routine*/
SlpTypeErr = -5, /*invalid queue element*/
SeNoDB = -8, /*no debugger installed to handle debugger command*/
ControlErr = -17, /*I/O System Errors*/
StatusErr = -18, /*I/O System Errors*/
ReadErr = -19, /*I/O System Errors*/
WritErr = -20, /*I/O System Errors*/
BadUnitErr = -21, /*I/O System Errors*/
UnitEmptyErr = -22, /*I/O System Errors*/
OpenErr = -23, /*I/O System Errors*/
ClosErr = -24, /*I/O System Errors*/
DRemovErr = -25, /*tried to remove an open driver*/
DInstErr = -26, /*DrvrInstall couldn't find driver in resources*/
// Window Manager result codes.
InvalidWindowPtr = -5600,
UnsupportedWindowAttributesForClass = -5601,
WindowDoesNotHaveProxy = -5602,
WindowPropertyNotFound = -5604,
UnrecognizedWindowClass = -5605,
CorruptWindowDescription = -5606,
UserWantsToDragWindow = -5607,
WindowsAlreadyInitialized = -5608,
FloatingWindowsNotInitialized = -5609,
WindowNotFound = -5610,
WindowDoesNotFitOnscreen = -5611,
WindowAttributeImmutable = -5612,
WindowAttributesConflict = -5613,
WindowManagerInternalError = -5614,
WindowWrongState = -5615,
WindowGroupInvalid = -5616,
WindowAppModalStateAlreadyExists = -5617,
WindowNoAppModalState = -5618,
WindowDoesntSupportFocus = -30583,
WindowRegionCodeInvalid = -30593,
// Event Manager result codes
EventAlreadyPosted = -9860,
EventTargetBusy = -9861,
EventDeferAccessibilityEvent = -9865,
EventInternalError = -9868,
EventParameterNotFound = -9870,
EventNotHandled = -9874,
EventLoopTimedOut = -9875,
EventLoopQuit = -9876,
EventNotInQueue = -9877,
HotKeyExists = -9878,
EventPassToNextTarget = -9880
}
}

View file

@ -0,0 +1,74 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
namespace OpenTK.Platform.MacOS
{
using Graphics;
internal class MacOSFactory : PlatformFactoryBase
{
// Todo: we can query the exact amount via
// CGEventSourceGetPixelsPerLine. This is
// approximately 0.1f
internal const float ScrollFactor = 0.1f;
internal static bool ExclusiveFullscreen = false;
public MacOSFactory()
{
NSApplication.Initialize();
}
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new QuartzDisplayDeviceDriver();
}
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new CocoaContext(mode, window, shareContext, major, minor);
}
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new CocoaContext(handle, window, shareContext, major, minor);
}
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
return new ContextHandle(CocoaContext.CurrentContext);
};
}
protected override void Dispose(bool manual)
{
if (!IsDisposed)
{
base.Dispose(manual);
}
}
}
}

View file

@ -0,0 +1,170 @@
//
// NS.cs
//
// Author:
// Stefanos A. <stapostol@gmail.com>
//
// Copyright (c) 2006-2013 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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
[Flags]
internal enum AddImageFlags
{
ReturnOnError = 1,
WithSearching = 2,
ReturnOnlyIfLoaded = 4
}
[Flags]
internal enum SymbolLookupFlags
{
Bind = 0,
BindNow = 1,
BindFully = 2,
ReturnOnError = 4
}
internal class NS
{
private const string Library = "libdl.dylib";
[DllImport(Library, EntryPoint = "NSAddImage")]
internal static extern IntPtr AddImage(string s, AddImageFlags flags);
[DllImport(Library, EntryPoint = "NSAddressOfSymbol")]
internal static extern IntPtr AddressOfSymbol(IntPtr symbol);
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
internal static extern bool IsSymbolNameDefined(string s);
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
internal static extern bool IsSymbolNameDefined(IntPtr s);
[DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
internal static extern IntPtr LookupAndBindSymbol(string s);
[DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
internal static extern IntPtr LookupAndBindSymbol(IntPtr s);
[DllImport(Library, EntryPoint = "NSLookupSymbolInImage")]
internal static extern IntPtr LookupSymbolInImage(IntPtr image, IntPtr symbolName, SymbolLookupFlags options);
// Unfortunately, these are slower even if they are more
// portable and simpler to use.
[DllImport(Library)]
internal static extern IntPtr dlopen(String fileName, int flags);
[DllImport(Library)]
internal static extern int dlclose(IntPtr handle);
[DllImport (Library)]
internal static extern IntPtr dlsym (IntPtr handle, string symbol);
[DllImport (Library)]
internal static extern IntPtr dlsym (IntPtr handle, IntPtr symbol);
public static IntPtr GetAddress(string function)
{
// Instead of allocating and combining strings in managed memory
// we do that directly in unmanaged memory. This way, we avoid
// 2 string allocations every time this function is called.
// must add a '_' prefix and null-terminate the function name,
// hence we allocate +2 bytes
IntPtr ptr = Marshal.AllocHGlobal(function.Length + 2);
try
{
Marshal.WriteByte(ptr, (byte)'_');
for (int i = 0; i < function.Length; i++)
{
Marshal.WriteByte(ptr, i + 1, (byte)function[i]);
}
Marshal.WriteByte(ptr, function.Length + 1, 0); // null-terminate
IntPtr symbol = GetAddressInternal(ptr);
return symbol;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
public static IntPtr GetAddress(IntPtr function)
{
unsafe
{
const int max = 64;
byte* symbol = stackalloc byte[max];
byte* ptr = symbol;
byte* cur = (byte*)function.ToPointer();
int i = 0;
*ptr++ = (byte)'_';
while (*cur != 0 && ++i < max)
{
*ptr++ = *cur++;
}
if (i >= max - 1)
{
throw new NotSupportedException(String.Format(
"Function {0} is too long. Please report a bug at https://github.com/opentk/issues/issues",
Marshal.PtrToStringAnsi(function)));
}
return GetAddressInternal(new IntPtr(symbol));
}
}
private static IntPtr GetAddressInternal(IntPtr function)
{
IntPtr symbol = IntPtr.Zero;
if (IsSymbolNameDefined(function))
{
symbol = LookupAndBindSymbol(function);
if (symbol != IntPtr.Zero)
{
symbol = AddressOfSymbol(symbol);
}
}
return symbol;
}
public static IntPtr GetSymbol(IntPtr handle, string symbol)
{
return dlsym(handle, symbol);
}
public static IntPtr GetSymbol(IntPtr handle, IntPtr symbol)
{
return dlsym(handle, symbol);
}
public static IntPtr LoadLibrary(string fileName)
{
const int RTLD_NOW = 2;
return dlopen(fileName, RTLD_NOW);
}
public static void FreeLibrary(IntPtr handle)
{
dlclose(handle);
}
}
}

View file

@ -0,0 +1,244 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace OpenTK.Platform.MacOS.Carbon
{
using CFAllocatorRef = IntPtr;
using CFIndex = System.IntPtr;
using CFRunLoop = System.IntPtr;
using CFRunLoopRef = IntPtr;
using CFRunLoopSourceRef = IntPtr;
using CFStringRef = System.IntPtr;
using CFTypeRef = System.IntPtr;
using CFMachPortRef = IntPtr;
internal struct CFArray
{
public IntPtr Ref { get; set; }
public CFArray(IntPtr reference)
{
Ref = reference;
}
public int Count
{
get { return CF.CFArrayGetCount(Ref); }
}
public IntPtr this[int index]
{
get
{
if (index >= Count || index < 0)
{
throw new IndexOutOfRangeException();
}
return CF.CFArrayGetValueAtIndex(Ref, index);
}
}
}
internal struct CFDictionary
{
public CFDictionary(IntPtr reference)
{
Ref = reference;
}
public IntPtr Ref { get; set; }
public int Count
{
get
{
return CF.CFDictionaryGetCount(Ref);
}
}
public double GetNumberValue(string key)
{
double retval;
IntPtr cfnum = CF.CFDictionaryGetValue(Ref,
CF.CFSTR(key));
CF.CFNumberGetValue(cfnum, CF.CFNumberType.kCFNumberDoubleType, out retval);
return retval;
}
}
internal class CF
{
private const string appServices = "/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/ApplicationServices";
[DllImport(appServices)]
internal static extern int CFArrayGetCount(IntPtr theArray);
[DllImport(appServices)]
internal static extern IntPtr CFArrayGetValueAtIndex(IntPtr theArray, int idx);
[DllImport(appServices)]
internal static extern int CFDictionaryGetCount(IntPtr theDictionary);
[DllImport(appServices)]
internal static extern IntPtr CFDictionaryGetValue(IntPtr theDictionary, IntPtr theKey);
[DllImport(appServices)]
internal static extern IntPtr CFGetTypeID(IntPtr v);
[DllImport(appServices)]
internal static extern IntPtr CFRetain(CFTypeRef cf);
[DllImport(appServices)]
internal static extern void CFRelease(CFTypeRef cf);
// this mirrors the definition in CFString.h.
// I don't know why, but __CFStringMakeConstantString is marked as "private and should not be used directly"
// even though the CFSTR macro just calls it.
[DllImport(appServices)]
private static extern IntPtr __CFStringMakeConstantString(string cStr);
internal static IntPtr CFSTR(string cStr)
{
return __CFStringMakeConstantString(cStr);
}
[DllImport(appServices)]
internal static extern Boolean CFStringGetCString(
CFStringRef theString,
byte[] buffer,
CFIndex bufferSize,
CFStringEncoding encoding
);
internal static string CFStringGetCString(IntPtr cfstr)
{
CFIndex length = CFStringGetLength(cfstr);
if (length != IntPtr.Zero)
{
byte[] utf8_chars = new byte[length.ToInt32() + 1];
if (CFStringGetCString(cfstr, utf8_chars, new IntPtr(utf8_chars.Length), CFStringEncoding.UTF8))
{
return Encoding.UTF8.GetString(utf8_chars);
}
}
return String.Empty;
}
[DllImport(appServices)]
internal static extern CFIndex CFStringGetLength(
CFStringRef theString
);
[DllImport(appServices)]
internal static extern bool CFNumberGetValue (IntPtr number, CFNumberType theType, out int valuePtr);
[DllImport(appServices)]
internal static extern bool CFNumberGetValue (IntPtr number, CFNumberType theType, out long valuePtr);
[DllImport(appServices)]
internal static extern bool CFNumberGetValue(IntPtr number, CFNumberType theType, out double valuePtr);
internal enum CFNumberType
{
kCFNumberSInt8Type = 1,
kCFNumberSInt16Type = 2,
kCFNumberSInt32Type = 3,
kCFNumberSInt64Type = 4,
kCFNumberFloat32Type = 5,
kCFNumberFloat64Type = 6,
kCFNumberCharType = 7,
kCFNumberShortType = 8,
kCFNumberIntType = 9,
kCFNumberLongType = 10,
kCFNumberLongLongType = 11,
kCFNumberFloatType = 12,
kCFNumberDoubleType = 13,
kCFNumberCFIndexType = 14,
kCFNumberNSIntegerType = 15,
kCFNumberCGFloatType = 16,
kCFNumberMaxType = 16
};
public enum CFRunLoopExitReason
{
Finished = 1,
Stopped = 2,
TimedOut = 3,
HandledSource = 4
}
public enum CFStringEncoding
{
MacRoman = 0,
WindowsLatin1 = 0x0500,
ISOLatin1 = 0x0201,
NextStepLatin = 0x0B01,
ASCII = 0x0600,
Unicode = 0x0100,
UTF8 = 0x08000100,
NonLossyASCII = 0x0BFF,
UTF16 = 0x0100,
UTF16BE = 0x10000100,
UTF16LE = 0x14000100,
UTF32 = 0x0c000100,
UTF32BE = 0x18000100,
UTF32LE = 0x1c000100
}
public static readonly IntPtr RunLoopModeDefault = CF.CFSTR("kCFRunLoopDefaultMode");
[DllImport(appServices)]
internal static extern CFRunLoop CFRunLoopGetCurrent();
[DllImport(appServices)]
internal static extern CFRunLoop CFRunLoopGetMain();
[DllImport(appServices)]
internal static extern CFRunLoopExitReason CFRunLoopRunInMode(
IntPtr cfstrMode, double interval, bool returnAfterSourceHandled);
[DllImport(appServices, EntryPoint = "CFMachPortCreateRunLoopSource")]
internal static extern CFRunLoopSourceRef MachPortCreateRunLoopSource(
CFAllocatorRef allocator,
CFMachPortRef port,
CFIndex order);
[DllImport(appServices, EntryPoint = "CFRunLoopAddSource")]
internal static extern void RunLoopAddSource(
CFRunLoopRef rl,
CFRunLoopSourceRef source,
CFStringRef mode);
[DllImport(appServices, EntryPoint = "CFRunLoopRemoveSource")]
internal static extern void RunLoopRemoveSource(
CFRunLoopRef rl,
CFRunLoopSourceRef source,
CFStringRef mode);
}
}

View file

@ -0,0 +1,132 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
using CGDirectDisplayID = System.IntPtr;
// Quartz Display services used here are available in MacOS X 10.3 and later.
internal enum CGDisplayErr
{
}
internal enum CGError
{
Success = 0,
Failure = 1000,
IllegalArgument = 1001,
InvalidConnection = 1002,
InvalidContext = 1003,
CannotComplete = 1004,
NotImplemented = 1006,
RangeCheck = 1007,
TypeCheck = 1008,
InvalidOperation = 1010,
NoneAvailable = 1011,
}
internal partial class CG
{
private const string lib = "/System/Library/Frameworks/ApplicationServices.framework/Versions/Current/ApplicationServices";
// CGPoint -> NSPoint
// CGSize -> NSSize
// CGRect -> NSRect
[DllImport(lib, EntryPoint="CGGetActiveDisplayList")]
internal unsafe static extern CGDisplayErr GetActiveDisplayList(int maxDisplays, IntPtr* activeDspys, out int dspyCnt);
[DllImport(lib, EntryPoint="CGMainDisplayID")]
internal static extern IntPtr MainDisplayID();
// Note: sizeof(HIRect) == 16, which is larger than 8 bytes.
// The x86 and x64 Mac ABIs pass such structs as pointers in the
// first parameter slot. This is normally handled automatically
// by gcc/clang, but here we have to do it ourselves.
// See "Listing 4" on https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW3
internal unsafe static NSRect DisplayBounds(IntPtr display)
{
NSRect rect;
DisplayBounds(out rect, display);
return rect;
}
[DllImport(lib, EntryPoint = "CGDisplayBounds")]
private unsafe static extern void DisplayBounds(out NSRect rect, IntPtr display);
[DllImport(lib, EntryPoint="CGDisplayPixelsWide")]
internal static extern int DisplayPixelsWide(IntPtr display);
[DllImport(lib, EntryPoint="CGDisplayPixelsHigh")]
internal static extern int DisplayPixelsHigh(IntPtr display);
[DllImport(lib, EntryPoint="CGDisplayCurrentMode")]
internal static extern IntPtr DisplayCurrentMode(IntPtr display);
[DllImport(lib, EntryPoint="CGDisplayCapture")]
internal static extern CGDisplayErr DisplayCapture(IntPtr display);
[DllImport(lib, EntryPoint="CGCaptureAllDisplays")]
internal static extern CGDisplayErr CaptureAllDisplays();
[DllImport(lib, EntryPoint="CGShieldingWindowLevel")]
internal static extern uint ShieldingWindowLevel();
[DllImport(lib, EntryPoint="CGDisplayRelease")]
internal static extern CGDisplayErr DisplayRelease(IntPtr display);
[DllImport(lib, EntryPoint="CGReleaseAllDisplays")]
internal static extern CGDisplayErr DisplayReleaseAll();
[DllImport(lib, EntryPoint = "CGDisplayAvailableModes")]
internal static extern IntPtr DisplayAvailableModes(IntPtr display);
[DllImport(lib, EntryPoint = "CGDisplaySwitchToMode")]
internal static extern IntPtr DisplaySwitchToMode(IntPtr display, IntPtr displayMode);
[DllImport(lib, EntryPoint = "CGWarpMouseCursorPosition")]
internal static extern CGError WarpMouseCursorPosition(NSPoint newCursorPosition);
[DllImport(lib, EntryPoint = "CGCursorIsVisible")]
internal static extern bool CursorIsVisible();
[DllImport(lib, EntryPoint = "CGDisplayShowCursor")]
internal static extern CGError DisplayShowCursor(CGDirectDisplayID display);
[DllImport(lib, EntryPoint = "CGDisplayHideCursor")]
internal static extern CGError DisplayHideCursor(CGDirectDisplayID display);
[DllImport(lib, EntryPoint = "CGAssociateMouseAndMouseCursorPosition")]
internal static extern CGError AssociateMouseAndMouseCursorPosition(bool connected);
[DllImport(lib, EntryPoint="CGSetLocalEventsSuppressionInterval")]
internal static extern CGError SetLocalEventsSuppressionInterval(double seconds);
}
}

View file

@ -0,0 +1,221 @@
//
// EventServices.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.
//
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
using CGEventTapProxy = IntPtr;
using CGEventRef = IntPtr;
using CFMachPortRef = IntPtr;
internal partial class CG
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate CGEventRef EventTapCallBack(
CGEventTapProxy proxy,
CGEventType type,
CGEventRef @event,
IntPtr refcon);
[DllImport(lib, EntryPoint = "CGEventTapCreate")]
public static extern CFMachPortRef EventTapCreate(
CGEventTapLocation tap,
CGEventTapPlacement place,
CGEventTapOptions options,
CGEventMask eventsOfInterest,
[MarshalAs(UnmanagedType.FunctionPtr)]
EventTapCallBack callback,
IntPtr refcon);
[DllImport(lib, EntryPoint = "CGEventGetDoubleValueField")]
internal static extern double EventGetDoubleValueField(
CGEventRef @event,
CGEventField field);
[DllImport(lib, EntryPoint = "CGEventGetIntegerValueField")]
internal static extern int EventGetIntegerValueField(
CGEventRef @event,
CGEventField field);
[DllImport(lib, EntryPoint = "CGEventGetLocation")]
internal static extern NSPointF EventGetLocationF(CGEventRef @event);
[DllImport(lib, EntryPoint = "CGEventGetLocation")]
internal static extern NSPointD EventGetLocationD(CGEventRef @event);
internal static NSPoint EventGetLocation(CGEventRef @event)
{
NSPoint r = new NSPoint();
unsafe {
if (IntPtr.Size == 4)
{
NSPointF pf = EventGetLocationF(@event);
r.X.Value = *(IntPtr *)&pf.X;
r.Y.Value = *(IntPtr *)&pf.Y;
}
else
{
NSPointD pd = EventGetLocationD(@event);
r.X.Value = *(IntPtr *)&pd.X;
r.Y.Value = *(IntPtr *)&pd.Y;
}
}
return r;
}
}
internal enum CGEventTapLocation
{
HIDEventTap = 0,
SessionEventTap,
AnnotatedSessionEventTap
}
internal enum CGEventTapPlacement
{
HeadInsert = 0,
TailAppend
}
internal enum CGEventTapOptions
{
Default = 0x00000000,
ListenOnly = 0x00000001
}
[Flags]
internal enum CGEventMask : long
{
LeftMouseDown = 1 << CGEventType.LeftMouseDown,
LeftMouseUp = 1 << CGEventType.LeftMouseUp,
RightMouseDown = 1 << CGEventType.RightMouseDown,
RightMouseUp = 1 << CGEventType.RightMouseUp,
MouseMoved = 1 << CGEventType.MouseMoved,
LeftMouseDragged = 1 << CGEventType.LeftMouseDown,
RightMouseDragged = 1 << CGEventType.RightMouseDown,
KeyDown = 1 << CGEventType.KeyDown,
KeyUp = 1 << CGEventType.KeyUp,
FlagsChanged = 1 << CGEventType.FlagsChanged,
ScrollWheel = 1 << CGEventType.ScrollWheel,
TabletPointer = 1 << CGEventType.TabletPointer,
TabletProximity = 1 << CGEventType.TabletProximity,
OtherMouseDown = 1 << CGEventType.OtherMouseDown,
OtherMouseUp = 1 << CGEventType.OtherMouseUp,
OtherMouseDragged = 1 << CGEventType.OtherMouseDragged,
All = -1,
AllMouse =
LeftMouseDown | LeftMouseUp | LeftMouseDragged |
RightMouseDown | RightMouseUp | RightMouseDragged |
OtherMouseDown | OtherMouseUp | OtherMouseDragged |
ScrollWheel | MouseMoved
}
internal enum CGEventType
{
Null = 0,
LeftMouseDown = 1,
LeftMouseUp = 2,
RightMouseDown = 3,
RightMouseUp = 4,
MouseMoved = 5,
LeftMouseDragged = 6,
RightMouseDragged = 7,
KeyDown = 10,
KeyUp = 11,
FlagsChanged = 12,
ScrollWheel = 22,
TabletPointer = 23,
TabletProximity = 24,
OtherMouseDown = 25,
OtherMouseUp = 26,
OtherMouseDragged = 27,
TapDisabledByTimeout = -2,
TapDisabledByUserInput = -1
}
internal enum CGEventField
{
MouseEventNumber = 0,
MouseEventClickState = 1,
MouseEventPressure = 2,
MouseEventButtonNumber = 3,
MouseEventDeltaX = 4,
MouseEventDeltaY = 5,
MouseEventInstantMouser = 6,
MouseEventSubtype = 7,
KeyboardEventAutorepeat = 8,
KeyboardEventKeycode = 9,
KeyboardEventKeyboardType = 10,
ScrollWheelEventDeltaAxis1 = 11,
ScrollWheelEventDeltaAxis2 = 12,
ScrollWheelEventDeltaAxis3 = 13,
ScrollWheelEventFixedPtDeltaAxis1 = 93,
ScrollWheelEventFixedPtDeltaAxis2 = 94,
ScrollWheelEventFixedPtDeltaAxis3 = 95,
ScrollWheelEventPointDeltaAxis1 = 96,
ScrollWheelEventPointDeltaAxis2 = 97,
ScrollWheelEventPointDeltaAxis3 = 98,
ScrollWheelEventInstantMouser = 14,
TabletEventPointX = 15,
TabletEventPointY = 16,
TabletEventPointZ = 17,
TabletEventPointButtons = 18,
TabletEventPointPressure = 19,
TabletEventTiltX = 20,
TabletEventTiltY = 21,
TabletEventRotation = 22,
TabletEventTangentialPressure = 23,
TabletEventDeviceID = 24,
TabletEventVendor1 = 25,
TabletEventVendor2 = 26,
TabletEventVendor3 = 27,
TabletProximityEventVendorID = 28,
TabletProximityEventTabletID = 29,
TabletProximityEventPointerID = 30,
TabletProximityEventDeviceID = 31,
TabletProximityEventSystemTabletID = 32,
TabletProximityEventVendorPointerType = 33,
TabletProximityEventVendorPointerSerialNumber = 34,
TabletProximityEventVendorUniqueID = 35,
TabletProximityEventCapabilityMask = 36,
TabletProximityEventPointerType = 37,
TabletProximityEventEnterProximity = 38,
EventTargetProcessSerialNumber = 39,
EventTargetUnixProcessID = 40,
EventSourceUnixProcessID = 41,
EventSourceUserData = 42,
EventSourceUserID = 43,
EventSourceGroupID = 44,
EventSourceStateID = 45,
ScrollWheelEventIsContinuous = 88
}
}

View file

@ -0,0 +1,209 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using OpenTK.Platform.MacOS.Carbon;
namespace OpenTK.Platform.MacOS
{
internal sealed class QuartzDisplayDeviceDriver : DisplayDeviceBase
{
private static object display_lock = new object();
public QuartzDisplayDeviceDriver()
{
lock (display_lock)
{
// To minimize the need to add static methods to OpenTK.Graphics.DisplayDevice
// we only allow settings to be set through its constructor.
// Thus, we save all necessary parameters in temporary variables
// and construct the device when every needed detail is available.
// The main DisplayDevice constructor adds the newly constructed device
// to the list of available devices.
const int maxDisplayCount = 20;
IntPtr[] displays = new IntPtr[maxDisplayCount];
int displayCount;
unsafe
{
fixed (IntPtr* displayPtr = displays)
{
CG.GetActiveDisplayList(maxDisplayCount, displayPtr, out displayCount);
}
}
Debug.Print("CoreGraphics reported {0} display(s).", displayCount);
Debug.Indent();
for (int i = 0; i < displayCount; i++)
{
IntPtr currentDisplay = displays[i];
// according to docs, first element in the array is always the
// main display.
bool primary = (i == 0);
// gets current settings
int currentWidth = CG.DisplayPixelsWide(currentDisplay);
int currentHeight = CG.DisplayPixelsHigh(currentDisplay);
Debug.Print("Display {0} is at {1}x{2}", i, currentWidth, currentHeight);
IntPtr displayModesPtr = CG.DisplayAvailableModes(currentDisplay);
CFArray displayModes = new CFArray(displayModesPtr);
Debug.Print("Supports {0} display modes.", displayModes.Count);
DisplayResolution opentk_dev_current_res = null;
List<DisplayResolution> opentk_dev_available_res = new List<DisplayResolution>();
IntPtr currentModePtr = CG.DisplayCurrentMode(currentDisplay);
CFDictionary currentMode = new CFDictionary(currentModePtr);
for (int j = 0; j < displayModes.Count; j++)
{
CFDictionary dict = new CFDictionary(displayModes[j]);
int width = (int)dict.GetNumberValue("Width");
int height = (int)dict.GetNumberValue("Height");
int bpp = (int)dict.GetNumberValue("BitsPerPixel");
double freq = dict.GetNumberValue("RefreshRate");
bool current = currentMode.Ref == dict.Ref;
if (freq <= 0)
{
IntPtr displayLink;
CV.DisplayLinkCreateWithCGDisplay(currentDisplay, out displayLink);
CVTime t = CV.DisplayLinkGetNominalOutputVideoRefreshPeriod(displayLink);
if ((t.flags & (Int32)CV.TimeFlags.TimeIsIndefinite) != (Int32)CV.TimeFlags.TimeIsIndefinite)
{
freq = (double)t.timeScale / t.timeValue;
}
CV.DisplayLinkRelease(displayLink);
}
//if (current) Debug.Write(" * ");
//else Debug.Write(" ");
//Debug.Print("Mode {0} is {1}x{2}x{3} @ {4}.", j, width, height, bpp, freq);
DisplayResolution thisRes = new DisplayResolution(0, 0, width, height, bpp, (float)freq);
opentk_dev_available_res.Add(thisRes);
if (current)
{
opentk_dev_current_res = thisRes;
}
}
NSRect bounds = CG.DisplayBounds(currentDisplay);
Rectangle newRect = new Rectangle((int)bounds.Location.X, (int)bounds.Location.Y, (int)bounds.Size.Width, (int)bounds.Size.Height);
Debug.Print("Display {0} bounds: {1}", i, newRect);
DisplayDevice opentk_dev = new DisplayDevice(opentk_dev_current_res,
primary, opentk_dev_available_res, newRect, currentDisplay);
AvailableDevices.Add(opentk_dev);
if (primary)
{
Primary = opentk_dev;
}
}
Debug.Unindent();
}
}
static internal IntPtr HandleTo(DisplayDevice displayDevice)
{
return (IntPtr)displayDevice.Id;
}
private Dictionary<IntPtr, IntPtr> storedModes = new Dictionary<IntPtr, IntPtr>();
private List<IntPtr> displaysCaptured = new List<IntPtr>();
public sealed override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
{
IntPtr display = HandleTo(device);
IntPtr currentModePtr = CG.DisplayCurrentMode(display);
if (storedModes.ContainsKey(display) == false)
{
storedModes.Add(display, currentModePtr);
}
IntPtr displayModesPtr = CG.DisplayAvailableModes(display);
CFArray displayModes = new CFArray(displayModesPtr);
for (int j = 0; j < displayModes.Count; j++)
{
CFDictionary dict = new CFDictionary(displayModes[j]);
int width = (int)dict.GetNumberValue("Width");
int height = (int)dict.GetNumberValue("Height");
int bpp = (int)dict.GetNumberValue("BitsPerPixel");
double freq = dict.GetNumberValue("RefreshRate");
if (width == resolution.Width && height == resolution.Height && bpp == resolution.BitsPerPixel && System.Math.Abs(freq - resolution.RefreshRate) < 1e-6)
{
// if (displaysCaptured.Contains(display) == false)
// {
// CG.DisplayCapture(display);
// }
Debug.Print("Changing resolution to {0}x{1}x{2}@{3}.", width, height, bpp, freq);
CG.DisplaySwitchToMode(display, displayModes[j]);
return true;
}
}
return false;
}
public sealed override bool TryRestoreResolution(DisplayDevice device)
{
IntPtr display = HandleTo(device);
if (storedModes.ContainsKey(display))
{
Debug.Print("Restoring resolution.");
CG.DisplaySwitchToMode(display, storedModes[display]);
//CG.DisplayRelease(display);
displaysCaptured.Remove(display);
return true;
}
return false;
}
}
}

View file

@ -0,0 +1,29 @@
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing detailed licensing details.
*/
using System;
namespace OpenTK
{
/// <summary>
/// Defines a plaftorm-specific exception.
/// </summary>
public class PlatformException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="OpenTK.PlatformException"/> class.
/// </summary>
public PlatformException()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="OpenTK.PlatformException"/> class.
/// </summary>
/// <param name="message">A message explaining the cause for this exception.</param>
public PlatformException(string message) : base(message) { }
}
}

View file

@ -0,0 +1,106 @@
//
// PlatformFactoryBase.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.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenTK.Graphics;
namespace OpenTK.Platform
{
/// \internal
/// <summary>
/// Implements IPlatformFactory functionality that is common
/// for all platform backends. IPlatformFactory implementations
/// should inherit from this class.
/// </summary>
internal abstract class PlatformFactoryBase : IPlatformFactory
{
private static readonly object sync = new object();
private readonly List<IDisposable> Resources = new List<IDisposable>();
protected bool IsDisposed;
public PlatformFactoryBase()
{
}
public abstract IDisplayDeviceDriver CreateDisplayDeviceDriver();
public abstract IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags);
public virtual IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new NotImplementedException();
}
public abstract GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext();
public void RegisterResource(IDisposable resource)
{
lock (sync)
{
Resources.Add(resource);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool manual)
{
if (!IsDisposed)
{
if (manual)
{
lock (sync)
{
foreach (var resource in Resources)
{
resource.Dispose();
}
Resources.Clear();
}
}
else
{
Debug.Print("[OpenTK] {0} leaked with {1} live resources, did you forget to call Dispose()?",
GetType().FullName, Resources.Count);
}
IsDisposed = true;
}
}
~PlatformFactoryBase()
{
Dispose(false);
}
}
}

View file

@ -0,0 +1,401 @@
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* See license.txt for license info
*/
using System;
using System.Reflection;
using System.Diagnostics;
using OpenTK.Graphics;
namespace OpenTK.Platform
{
namespace MacOS
{
/// <summary>
/// This delegate represents any method that takes no arguments and returns an int.
/// I would have used Func but that requires .NET 4
/// </summary>
/// <returns>The int value that your method returns</returns>
public delegate int GetInt();
}
/// <summary>
/// Provides cross-platform utilities to help interact with the underlying platform.
/// </summary>
public static class Utilities
{
private static bool throw_on_error;
internal static bool ThrowOnX11Error
{
get { return throw_on_error; }
set
{
if (value && !throw_on_error)
{
Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms")
.GetField("ErrorExceptions", System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.NonPublic)
.SetValue(null, true);
throw_on_error = true;
}
else if (!value && throw_on_error)
{
Type.GetType("System.Windows.Forms.XplatUIX11, System.Windows.Forms")
.GetField("ErrorExceptions", System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.NonPublic)
.SetValue(null, false);
throw_on_error = false;
}
}
}
private delegate Delegate LoadDelegateFunction(string name, Type signature);
/// <internal />
/// <summary>Loads all extensions for the specified class. This function is intended
/// for OpenGL, Wgl, Glx, OpenAL etc.</summary>
/// <param name="type">The class to load extensions for.</param>
/// <remarks>
/// <para>The Type must contain a nested class called "Delegates".</para>
/// <para>
/// The Type must also implement a static function called LoadDelegate with the
/// following signature:
/// <code>static Delegate LoadDelegate(string name, Type signature)</code>
/// </para>
/// <para>This function allocates memory.</para>
/// </remarks>
internal static void LoadExtensions(Type type)
{
// Using reflection is more than 3 times faster than directly loading delegates on the first
// run, probably due to code generation overhead. Subsequent runs are faster with direct loading
// than with reflection, but the first time is more significant.
int supported = 0;
Type extensions_class = type.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (extensions_class == null)
{
throw new InvalidOperationException("The specified type does not have any loadable extensions.");
}
FieldInfo[] delegates = extensions_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (delegates == null)
{
throw new InvalidOperationException("The specified type does not have any loadable extensions.");
}
MethodInfo load_delegate_method_info = type.GetMethod("LoadDelegate", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (load_delegate_method_info == null)
{
throw new InvalidOperationException(type.ToString() + " does not contain a static LoadDelegate method.");
}
LoadDelegateFunction LoadDelegate = (LoadDelegateFunction)Delegate.CreateDelegate(
typeof(LoadDelegateFunction), load_delegate_method_info);
Debug.Write("Load extensions for " + type.ToString() + "... ");
System.Diagnostics.Stopwatch time = new System.Diagnostics.Stopwatch();
time.Reset();
time.Start();
foreach (FieldInfo f in delegates)
{
Delegate d = LoadDelegate(f.Name, f.FieldType);
if (d != null)
{
++supported;
}
f.SetValue(null, d);
}
FieldInfo rebuildExtensionList = type.GetField("rebuildExtensionList", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (rebuildExtensionList != null)
{
rebuildExtensionList.SetValue(null, true);
}
time.Stop();
Debug.Print("{0} extensions loaded in {1} ms.", supported, time.ElapsedMilliseconds);
time.Reset();
}
/// <internal />
/// <summary>Loads the specified extension for the specified class. This function is intended
/// for OpenGL, Wgl, Glx, OpenAL etc.</summary>
/// <param name="type">The class to load extensions for.</param>
/// <param name="extension">The extension to load.</param>
/// <remarks>
/// <para>The Type must contain a nested class called "Delegates".</para>
/// <para>
/// The Type must also implement a static function called LoadDelegate with the
/// following signature:
/// <code>static Delegate LoadDelegate(string name, Type signature)</code>
/// </para>
/// <para>This function allocates memory.</para>
/// </remarks>
internal static bool TryLoadExtension(Type type, string extension)
{
Type extensions_class = type.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (extensions_class == null)
{
Debug.Print(type.ToString(), " does not contain extensions.");
return false;
}
LoadDelegateFunction LoadDelegate = (LoadDelegateFunction)Delegate.CreateDelegate(typeof(LoadDelegateFunction),
type.GetMethod("LoadDelegate", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public));
if (LoadDelegate == null)
{
Debug.Print(type.ToString(), " does not contain a static LoadDelegate method.");
return false;
}
FieldInfo f = extensions_class.GetField(extension, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (f == null)
{
Debug.Print("Extension \"", extension, "\" not found in ", type.ToString());
return false;
}
Delegate old = f.GetValue(null) as Delegate;
Delegate @new = LoadDelegate(f.Name, f.FieldType);
if ((old != null ? old.Target : null) != (@new != null ? @new.Target : null))
{
f.SetValue(null, @new);
FieldInfo rebuildExtensionList = type.GetField("rebuildExtensionList", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (rebuildExtensionList != null)
{
rebuildExtensionList.SetValue(null, true);
}
}
return @new != null;
}
internal static GraphicsContext.GetAddressDelegate CreateGetAddress()
{
if (Configuration.RunningOnWindows)
{
return Platform.Windows.Wgl.GetAddress;
}
if (Configuration.RunningOnX11)
{
return Platform.X11.Glx.GetProcAddress;
}
if (Configuration.RunningOnMacOS)
{
return Platform.MacOS.NS.GetAddress;
}
// Other platforms: still allow dummy contexts to be created (if no Loader is required)
return EmptyGetAddress;
}
private static IntPtr EmptyGetAddress(string function)
{
return IntPtr.Zero;
}
/// <summary>
/// Constructs a new IWindowInfo instance for the X11 platform.
/// </summary>
/// <param name="display">The display connection.</param>
/// <param name="screen">The screen.</param>
/// <param name="windowHandle">The handle for the window.</param>
/// <param name="rootWindow">The root window for screen.</param>
/// <param name="visualInfo">A pointer to a XVisualInfo structure obtained through XGetVisualInfo.</param>
/// <returns>A new IWindowInfo instance.</returns>
public static IWindowInfo CreateX11WindowInfo(IntPtr display, int screen, IntPtr windowHandle, IntPtr rootWindow, IntPtr visualInfo)
{
Platform.X11.X11WindowInfo window = new OpenTK.Platform.X11.X11WindowInfo();
window.Display = display;
window.Screen = screen;
window.Handle = windowHandle;
window.RootWindow = rootWindow;
window.Visual = visualInfo;
return window;
}
/// <summary>
/// Creates an IWindowInfo instance for the windows platform.
/// </summary>
/// <param name="windowHandle">The handle of the window.</param>
/// <returns>A new IWindowInfo instance.</returns>
public static IWindowInfo CreateWindowsWindowInfo(IntPtr windowHandle)
{
return new OpenTK.Platform.Windows.WinWindowInfo(windowHandle, null);
}
/// <summary>
/// Creates an IWindowInfo instance for the Mac OS X platform.
/// </summary>
/// <param name="windowHandle">The handle of the window.</param>
/// <param name="ownHandle">Ignored. This is reserved for future use.</param>
/// <param name="isControl">Set to true if windowHandle corresponds to a System.Windows.Forms control.</param>
/// <returns>A new IWindowInfo instance.</returns>
public static IWindowInfo CreateMacOSCarbonWindowInfo(IntPtr windowHandle, bool ownHandle, bool isControl)
{
return CreateMacOSCarbonWindowInfo(windowHandle, ownHandle, isControl, null, null);
}
/// <summary>
/// Creates an IWindowInfo instance for the Mac OS X platform with an X and Y offset for the GL viewport location.
/// </summary>
/// <param name="windowHandle">The handle of the window.</param>
/// <param name="ownHandle">Ignored. This is reserved for future use.</param>
/// <param name="isControl">Set to true if windowHandle corresponds to a System.Windows.Forms control.</param>
/// <param name="xOffset">The X offset for the GL viewport</param>
/// <param name="yOffset">The Y offset for the GL viewport</param>
/// <returns>A new IWindowInfo instance.</returns>
public static IWindowInfo CreateMacOSCarbonWindowInfo(IntPtr windowHandle, bool ownHandle, bool isControl,
OpenTK.Platform.MacOS.GetInt xOffset, OpenTK.Platform.MacOS.GetInt yOffset)
{
return new OpenTK.Platform.MacOS.CarbonWindowInfo(windowHandle, false, isControl, xOffset, yOffset);
}
/// <summary>
/// Creates an IWindowInfo instance for the Mac OS X platform.
/// </summary>
/// <param name="windowHandle">The handle of the NSWindow.</param>
/// <remarks>Assumes that the NSWindow's contentView is the NSView we want to attach to our context.</remarks>
/// <returns>A new IWindowInfo instance.</returns>
public static IWindowInfo CreateMacOSWindowInfo(IntPtr windowHandle)
{
return new OpenTK.Platform.MacOS.CocoaWindowInfo(windowHandle);
}
/// <summary>
/// Creates an IWindowInfo instance for the Mac OS X platform.
/// </summary>
/// <param name="windowHandle">The handle of the NSWindow.</param>
/// <param name="viewHandle">The handle of the NSView.</param>
/// <returns>A new IWindowInfo instance.</returns>
public static IWindowInfo CreateMacOSWindowInfo(IntPtr windowHandle, IntPtr viewHandle)
{
return new OpenTK.Platform.MacOS.CocoaWindowInfo(windowHandle, viewHandle);
}
/// <summary>
/// Creates an IWindowInfo instance for the dummy platform.
/// </summary>
/// <returns>A new IWindowInfo instance.</returns>
public static IWindowInfo CreateDummyWindowInfo()
{
return new Dummy.DummyWindowInfo();
}
/// <summary>
/// Creates an IWindowInfo instance for Angle rendering, based on
/// supplied platform window (e.g. a window created with
/// CreateWindowsWindowInfo, or CreateDummyWindowInfo).
/// </summary>
/// <param name="platformWindow"></param>
/// <returns></returns>
public static Egl.IAngleWindowInfo CreateAngleWindowInfo(IWindowInfo platformWindow)
{
return new Egl.AngleWindowInfo(platformWindow);
}
internal static bool RelaxGraphicsMode(ref GraphicsMode mode)
{
ColorFormat color = mode.ColorFormat;
int depth = mode.Depth;
int stencil = mode.Stencil;
int samples = mode.Samples;
ColorFormat accum = mode.AccumulatorFormat;
int buffers = mode.Buffers;
bool stereo = mode.Stereo;
bool success = RelaxGraphicsMode(
ref color, ref depth, ref stencil, ref samples,
ref accum, ref buffers, ref stereo);
mode = new GraphicsMode(
color, depth, stencil, samples,
accum, buffers, stereo);
return success;
}
/// \internal
/// <summary>
/// Relaxes graphics mode parameters. Use this function to increase compatibility
/// on systems that do not directly support a requested GraphicsMode. For example:
/// - user requested stereoscopic rendering, but GPU does not support stereo
/// - user requseted 16x antialiasing, but GPU only supports 4x
/// </summary>
/// <returns><c>true</c>, if a graphics mode parameter was relaxed, <c>false</c> otherwise.</returns>
/// <param name="color">Color bits.</param>
/// <param name="depth">Depth bits.</param>
/// <param name="stencil">Stencil bits.</param>
/// <param name="samples">Number of antialiasing samples.</param>
/// <param name="accum">Accumulator buffer bits.</param>
/// <param name="buffers">Number of rendering buffers (1 for single buffering, 2+ for double buffering, 0 for don't care).</param>
/// <param name="stereo">Stereoscopic rendering enabled/disabled.</param>
internal static bool RelaxGraphicsMode(ref ColorFormat color, ref int depth, ref int stencil, ref int samples, ref ColorFormat accum, ref int buffers, ref bool stereo)
{
// Parameters are relaxed in order of importance.
// - Accumulator buffers are way outdated as a concept,
// so they go first.
// - Triple+ buffering is generally not supported by the
// core WGL/GLX/AGL/CGL/EGL specs, so we clamp
// to double-buffering as a second step. (If this doesn't help
// we will also fall back to undefined single/double buffering
// as a last resort).
// - AA samples are an easy way to increase compatibility
// so they go next.
// - Stereoscopic is only supported on very few GPUs
// (Quadro/FirePro series) so it goes next.
// - The rest of the parameters then follow.
if (accum != 0)
{
accum = 0;
return true;
}
if (buffers > 2)
{
buffers = 2;
return true;
}
if (samples > 0)
{
samples = Math.Max(samples - 1, 0);
return true;
}
if (stereo)
{
stereo = false;
return true;
}
if (stencil != 0)
{
stencil = 0;
return true;
}
if (depth != 0)
{
depth = 0;
return true;
}
if (color != 24)
{
color = 24;
return true;
}
if (buffers != 0)
{
buffers = 0;
return true;
}
// no parameters left to relax, fail
return false;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,159 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2013 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.
//
using System;
using System.Runtime.InteropServices;
using System.Security;
using OpenTK.Core.Native;
namespace OpenTK.Platform.Windows
{
#pragma warning disable 3019
#pragma warning disable 1591
internal partial class Wgl
{
static Wgl()
{
EntryPointNames = new string[]
{
"wglCreateContextAttribsARB",
"wglGetExtensionsStringARB",
"wglGetPixelFormatAttribivARB",
"wglGetPixelFormatAttribfvARB",
"wglChoosePixelFormatARB",
"wglMakeContextCurrentARB",
"wglGetCurrentReadDCARB",
"wglCreatePbufferARB",
"wglGetPbufferDCARB",
"wglReleasePbufferDCARB",
"wglDestroyPbufferARB",
"wglQueryPbufferARB",
"wglBindTexImageARB",
"wglReleaseTexImageARB",
"wglSetPbufferAttribARB",
"wglGetExtensionsStringEXT",
"wglSwapIntervalEXT",
"wglGetSwapIntervalEXT",
};
EntryPoints = new IntPtr[EntryPointNames.Length];
}
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglCreateContext", ExactSpelling = true, SetLastError = true)]
internal extern static IntPtr CreateContext(IntPtr hDc);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglDeleteContext", ExactSpelling = true, SetLastError = true)]
internal extern static Boolean DeleteContext(IntPtr oldContext);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglGetCurrentContext", ExactSpelling = true, SetLastError = true)]
internal extern static IntPtr GetCurrentContext();
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglMakeCurrent", ExactSpelling = true, SetLastError = true)]
internal extern static Boolean MakeCurrent(IntPtr hDc, IntPtr newContext);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglChoosePixelFormat", ExactSpelling = true, SetLastError = true)]
internal extern static unsafe int ChoosePixelFormat(IntPtr hDc, ref PixelFormatDescriptor pPfd);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglDescribePixelFormat", ExactSpelling = true, SetLastError = true)]
internal extern static unsafe int DescribePixelFormat(IntPtr hdc, int ipfd, int cjpfd, ref PixelFormatDescriptor ppfd);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglGetCurrentDC", ExactSpelling = true, SetLastError = true)]
internal extern static IntPtr GetCurrentDC();
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglGetProcAddress", ExactSpelling = true, SetLastError = true)]
internal extern static IntPtr GetProcAddress(String lpszProc);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglGetProcAddress", ExactSpelling = true, SetLastError = true)]
internal extern static IntPtr GetProcAddress(IntPtr lpszProc);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglGetPixelFormat", ExactSpelling = true, SetLastError = true)]
internal extern static int GetPixelFormat(IntPtr hdc);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglSetPixelFormat", ExactSpelling = true, SetLastError = true)]
internal extern static Boolean SetPixelFormat(IntPtr hdc, int ipfd, ref PixelFormatDescriptor ppfd);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglSwapBuffers", ExactSpelling = true, SetLastError = true)]
internal extern static Boolean SwapBuffers(IntPtr hdc);
[SuppressUnmanagedCodeSecurity]
[DllImport(Wgl.Library, EntryPoint = "wglShareLists", ExactSpelling = true, SetLastError = true)]
internal extern static Boolean ShareLists(IntPtr hrcSrvShare, IntPtr hrcSrvSource);
[Slot(0)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal unsafe static extern IntPtr wglCreateContextAttribsARB(IntPtr hDC, IntPtr hShareContext, int* attribList);
[Slot(1)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern IntPtr wglGetExtensionsStringARB(IntPtr hdc);
[Slot(2)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal unsafe static extern Boolean wglGetPixelFormatAttribivARB(IntPtr hdc, int iPixelFormat, int iLayerPlane, UInt32 nAttributes, int* piAttributes, [Out] int* piValues);
[Slot(3)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal unsafe static extern Boolean wglGetPixelFormatAttribfvARB(IntPtr hdc, int iPixelFormat, int iLayerPlane, UInt32 nAttributes, int* piAttributes, [Out] Single* pfValues);
[Slot(4)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal unsafe static extern Boolean wglChoosePixelFormatARB(IntPtr hdc, int* piAttribIList, Single* pfAttribFList, UInt32 nMaxFormats, [Out] int* piFormats, [Out] UInt32* nNumFormats);
[Slot(5)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern Boolean wglMakeContextCurrentARB(IntPtr hDrawDC, IntPtr hReadDC, IntPtr hglrc);
[Slot(6)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern IntPtr wglGetCurrentReadDCARB();
[Slot(7)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal unsafe static extern IntPtr wglCreatePbufferARB(IntPtr hDC, int iPixelFormat, int iWidth, int iHeight, int* piAttribList);
[Slot(8)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern IntPtr wglGetPbufferDCARB(IntPtr hPbuffer);
[Slot(9)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern int wglReleasePbufferDCARB(IntPtr hPbuffer, IntPtr hDC);
[Slot(10)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern Boolean wglDestroyPbufferARB(IntPtr hPbuffer);
[Slot(11)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal unsafe static extern Boolean wglQueryPbufferARB(IntPtr hPbuffer, int iAttribute, [Out] int* piValue);
[Slot(12)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern Boolean wglBindTexImageARB(IntPtr hPbuffer, int iBuffer);
[Slot(13)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern Boolean wglReleaseTexImageARB(IntPtr hPbuffer, int iBuffer);
[Slot(14)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal unsafe static extern Boolean wglSetPbufferAttribARB(IntPtr hPbuffer, int* piAttribList);
[Slot(15)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern IntPtr wglGetExtensionsStringEXT();
[Slot(16)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern Boolean wglSwapIntervalEXT(int interval);
[Slot(17)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern int wglGetSwapIntervalEXT();
}
}

View file

@ -0,0 +1,521 @@
namespace OpenTK.Platform.Windows
{
#pragma warning disable 3019
#pragma warning disable 1591
public enum ArbCreateContext
{
CoreProfileBit = 0x0001,
CompatibilityProfileBit = 0x0002,
DebugBit = 0x0001,
ForwardCompatibleBit = 0x0002,
MajorVersion = 0x2091,
MinorVersion = 0x2092,
LayerPlane = 0x2093,
ContextFlags = 0x2094,
ErrorInvalidVersion = 0x2095,
ProfileMask = 0x9126
}
public enum WGL_ARB_buffer_region
{
BackColorBufferBitArb = ((int)0x00000002),
StencilBufferBitArb = ((int)0x00000008),
FrontColorBufferBitArb = ((int)0x00000001),
DepthBufferBitArb = ((int)0x00000004),
}
public enum WGL_EXT_pixel_format
{
SupportGdiExt = ((int)0x200f),
TypeColorindexExt = ((int)0x202c),
AccelerationExt = ((int)0x2003),
GreenBitsExt = ((int)0x2017),
DrawToWindowExt = ((int)0x2001),
SwapCopyExt = ((int)0x2029),
DrawToBitmapExt = ((int)0x2002),
TransparentExt = ((int)0x200a),
SwapMethodExt = ((int)0x2007),
SwapLayerBuffersExt = ((int)0x2006),
PixelTypeExt = ((int)0x2013),
AlphaShiftExt = ((int)0x201c),
AccumRedBitsExt = ((int)0x201e),
FullAccelerationExt = ((int)0x2027),
SupportOpenglExt = ((int)0x2010),
BlueShiftExt = ((int)0x201a),
RedBitsExt = ((int)0x2015),
NoAccelerationExt = ((int)0x2025),
StereoExt = ((int)0x2012),
GreenShiftExt = ((int)0x2018),
BlueBitsExt = ((int)0x2019),
AlphaBitsExt = ((int)0x201b),
RedShiftExt = ((int)0x2016),
DepthBitsExt = ((int)0x2022),
TypeRgbaExt = ((int)0x202b),
GenericAccelerationExt = ((int)0x2026),
AccumAlphaBitsExt = ((int)0x2021),
AccumGreenBitsExt = ((int)0x201f),
TransparentValueExt = ((int)0x200b),
AccumBlueBitsExt = ((int)0x2020),
ShareDepthExt = ((int)0x200c),
ShareAccumExt = ((int)0x200e),
SwapExchangeExt = ((int)0x2028),
AccumBitsExt = ((int)0x201d),
NumberUnderlaysExt = ((int)0x2009),
StencilBitsExt = ((int)0x2023),
DoubleBufferExt = ((int)0x2011),
NeedPaletteExt = ((int)0x2004),
ColorBitsExt = ((int)0x2014),
SwapUndefinedExt = ((int)0x202a),
NeedSystemPaletteExt = ((int)0x2005),
NumberOverlaysExt = ((int)0x2008),
AuxBuffersExt = ((int)0x2024),
NumberPixelFormatsExt = ((int)0x2000),
ShareStencilExt = ((int)0x200d),
}
public enum WGL_ARB_pixel_format
{
ShareStencilArb = ((int)0x200d),
AccumBitsArb = ((int)0x201d),
NumberUnderlaysArb = ((int)0x2009),
StereoArb = ((int)0x2012),
MaxPbufferHeightArb = ((int)0x2030),
TypeRgbaArb = ((int)0x202b),
SupportGdiArb = ((int)0x200f),
NeedSystemPaletteArb = ((int)0x2005),
AlphaBitsArb = ((int)0x201b),
ShareDepthArb = ((int)0x200c),
SupportOpenglArb = ((int)0x2010),
ColorBitsArb = ((int)0x2014),
AccumRedBitsArb = ((int)0x201e),
MaxPbufferWidthArb = ((int)0x202f),
NumberOverlaysArb = ((int)0x2008),
MaxPbufferPixelsArb = ((int)0x202e),
NeedPaletteArb = ((int)0x2004),
RedShiftArb = ((int)0x2016),
AccelerationArb = ((int)0x2003),
GreenBitsArb = ((int)0x2017),
TransparentGreenValueArb = ((int)0x2038),
PixelTypeArb = ((int)0x2013),
AuxBuffersArb = ((int)0x2024),
DrawToWindowArb = ((int)0x2001),
RedBitsArb = ((int)0x2015),
NumberPixelFormatsArb = ((int)0x2000),
GenericAccelerationArb = ((int)0x2026),
BlueBitsArb = ((int)0x2019),
PbufferLargestArb = ((int)0x2033),
AccumAlphaBitsArb = ((int)0x2021),
TransparentArb = ((int)0x200a),
FullAccelerationArb = ((int)0x2027),
ShareAccumArb = ((int)0x200e),
SwapExchangeArb = ((int)0x2028),
SwapUndefinedArb = ((int)0x202a),
TransparentAlphaValueArb = ((int)0x203a),
PbufferHeightArb = ((int)0x2035),
TransparentBlueValueArb = ((int)0x2039),
SwapMethodArb = ((int)0x2007),
StencilBitsArb = ((int)0x2023),
DepthBitsArb = ((int)0x2022),
GreenShiftArb = ((int)0x2018),
TransparentRedValueArb = ((int)0x2037),
DoubleBufferArb = ((int)0x2011),
NoAccelerationArb = ((int)0x2025),
TypeColorindexArb = ((int)0x202c),
SwapLayerBuffersArb = ((int)0x2006),
AccumBlueBitsArb = ((int)0x2020),
DrawToPbufferArb = ((int)0x202d),
AccumGreenBitsArb = ((int)0x201f),
PbufferWidthArb = ((int)0x2034),
TransparentIndexValueArb = ((int)0x203b),
AlphaShiftArb = ((int)0x201c),
DrawToBitmapArb = ((int)0x2002),
BlueShiftArb = ((int)0x201a),
SwapCopyArb = ((int)0x2029),
}
public enum WGL_EXT_pbuffer
{
DrawToPbufferExt = ((int)0x202d),
PbufferLargestExt = ((int)0x2033),
OptimalPbufferWidthExt = ((int)0x2031),
MaxPbufferPixelsExt = ((int)0x202e),
MaxPbufferHeightExt = ((int)0x2030),
PbufferWidthExt = ((int)0x2034),
MaxPbufferWidthExt = ((int)0x202f),
OptimalPbufferHeightExt = ((int)0x2032),
PbufferHeightExt = ((int)0x2035),
}
public enum WGL_ARB_pbuffer
{
PbufferWidthArb = ((int)0x2034),
TransparentGreenValueArb = ((int)0x2038),
PbufferHeightArb = ((int)0x2035),
PbufferLostArb = ((int)0x2036),
DrawToPbufferArb = ((int)0x202d),
TransparentIndexValueArb = ((int)0x203b),
TransparentRedValueArb = ((int)0x2037),
MaxPbufferPixelsArb = ((int)0x202e),
TransparentAlphaValueArb = ((int)0x203a),
MaxPbufferWidthArb = ((int)0x202f),
MaxPbufferHeightArb = ((int)0x2030),
TransparentBlueValueArb = ((int)0x2039),
PbufferLargestArb = ((int)0x2033),
}
public enum WGL_EXT_depth_float
{
DepthFloatExt = ((int)0x2040),
}
public enum WGL_EXT_multisample
{
SampleBuffersExt = ((int)0x2041),
SamplesExt = ((int)0x2042),
}
public enum WGL_ARB_multisample
{
SampleBuffersArb = ((int)0x2041),
SamplesArb = ((int)0x2042),
}
public enum WGL_EXT_make_current_read
{
ErrorInvalidPixelTypeExt = ((int)0x2043),
}
public enum WGL_ARB_make_current_read
{
ErrorInvalidPixelTypeArb = ((int)0x2043),
ErrorIncompatibleDeviceContextsArb = ((int)0x2054),
}
public enum WGL_I3D_genlock
{
GenlockSourceMultiviewI3d = ((int)0x2044),
GenlockSourceEdgeBothI3d = ((int)0x204c),
GenlockSourceEdgeRisingI3d = ((int)0x204b),
GenlockSourceDigitalSyncI3d = ((int)0x2048),
GenlockSourceExtenalFieldI3d = ((int)0x2046),
GenlockSourceDigitalFieldI3d = ((int)0x2049),
GenlockSourceExtenalSyncI3d = ((int)0x2045),
GenlockSourceEdgeFallingI3d = ((int)0x204a),
GenlockSourceExtenalTtlI3d = ((int)0x2047),
}
public enum WGL_I3D_gamma
{
GammaExcludeDesktopI3d = ((int)0x204f),
GammaTableSizeI3d = ((int)0x204e),
}
public enum WGL_I3D_digital_video_control
{
DigitalVideoCursorAlphaFramebufferI3d = ((int)0x2050),
DigitalVideoGammaCorrectedI3d = ((int)0x2053),
DigitalVideoCursorAlphaValueI3d = ((int)0x2051),
DigitalVideoCursorIncludedI3d = ((int)0x2052),
}
public enum WGL_3DFX_multisample
{
SampleBuffers3dfx = ((int)0x2060),
Samples3dfx = ((int)0x2061),
}
public enum WGL_ARB_render_texture
{
TextureCubeMapPositiveXArb = ((int)0x207d),
TextureCubeMapPositiveYArb = ((int)0x207f),
Aux0Arb = ((int)0x2087),
Texture1dArb = ((int)0x2079),
Aux6Arb = ((int)0x208d),
TextureCubeMapArb = ((int)0x2078),
TextureFormatArb = ((int)0x2072),
BackRightArb = ((int)0x2086),
BindToTextureRgbArb = ((int)0x2070),
MipmapLevelArb = ((int)0x207b),
CubeMapFaceArb = ((int)0x207c),
TextureCubeMapNegativeXArb = ((int)0x207e),
Aux7Arb = ((int)0x208e),
Aux8Arb = ((int)0x208f),
MipmapTextureArb = ((int)0x2074),
NoTextureArb = ((int)0x2077),
Aux3Arb = ((int)0x208a),
Texture2DArb = ((int)0x207a),
Aux1Arb = ((int)0x2088),
TextureCubeMapPositiveZArb = ((int)0x2081),
BindToTextureRgbaArb = ((int)0x2071),
TextureCubeMapNegativeYArb = ((int)0x2080),
TextureRgbaArb = ((int)0x2076),
FrontRightArb = ((int)0x2084),
Aux5Arb = ((int)0x208c),
Aux4Arb = ((int)0x208b),
TextureTargetArb = ((int)0x2073),
FrontLeftArb = ((int)0x2083),
Aux9Arb = ((int)0x2090),
TextureRgbArb = ((int)0x2075),
BackLeftArb = ((int)0x2085),
TextureCubeMapNegativeZArb = ((int)0x2082),
Aux2Arb = ((int)0x2089),
}
public enum WGL_NV_render_texture_rectangle
{
BindToTextureRectangleRgbNv = ((int)0x20a0),
BindToTextureRectangleRgbaNv = ((int)0x20a1),
TextureRectangleNv = ((int)0x20a2),
}
public enum WGL_NV_render_depth_texture
{
DepthTextureFormatNv = ((int)0x20a5),
TextureDepthComponentNv = ((int)0x20a6),
BindToTextureDepthNv = ((int)0x20a3),
DepthComponentNv = ((int)0x20a7),
BindToTextureRectangleDepthNv = ((int)0x20a4),
}
public enum WGL_NV_float_buffer
{
BindToTextureRectangleFloatRNv = ((int)0x20b1),
TextureFloatRNv = ((int)0x20b5),
TextureFloatRgbNv = ((int)0x20b7),
TextureFloatRgNv = ((int)0x20b6),
TextureFloatRgbaNv = ((int)0x20b8),
BindToTextureRectangleFloatRgbaNv = ((int)0x20b4),
FloatComponentsNv = ((int)0x20b0),
BindToTextureRectangleFloatRgNv = ((int)0x20b2),
BindToTextureRectangleFloatRgbNv = ((int)0x20b3),
}
public enum WGL_ARB_pixel_format_float
{
TypeRgbaFloatArb = ((int)0x21a0),
}
public enum WGL_ATI_pixel_format_float
{
TypeRgbaFloatAti = ((int)0x21a0),
}
public enum WGL_font_type
{
FontLines = ((int)0),
}
public enum All
{
SwapCopyExt = ((int)0x2029),
BackColorBufferBitArb = ((int)0x00000002),
FullAccelerationArb = ((int)0x2027),
AccelerationExt = ((int)0x2003),
GenlockSourceMultiviewI3d = ((int)0x2044),
Aux3Arb = ((int)0x208a),
TextureCubeMapNegativeYArb = ((int)0x2080),
DoubleBufferArb = ((int)0x2011),
SwapUndefinedExt = ((int)0x202a),
SupportGdiArb = ((int)0x200f),
Aux2Arb = ((int)0x2089),
TextureCubeMapArb = ((int)0x2078),
SwapLayerBuffersExt = ((int)0x2006),
SwapCopyArb = ((int)0x2029),
ErrorIncompatibleDeviceContextsArb = ((int)0x2054),
TypeColorindexArb = ((int)0x202c),
DigitalVideoCursorIncludedI3d = ((int)0x2052),
NeedPaletteExt = ((int)0x2004),
RedBitsArb = ((int)0x2015),
TextureCubeMapNegativeXArb = ((int)0x207e),
SampleBuffersExt = ((int)0x2041),
GenericAccelerationExt = ((int)0x2026),
BindToTextureRectangleRgbaNv = ((int)0x20a1),
NoTextureArb = ((int)0x2077),
FrontColorBufferBitArb = ((int)0x00000001),
TransparentValueExt = ((int)0x200b),
AlphaBitsArb = ((int)0x201b),
RedBitsExt = ((int)0x2015),
PbufferHeightArb = ((int)0x2035),
BindToTextureRectangleFloatRgbaNv = ((int)0x20b4),
SampleBuffersArb = ((int)0x2041),
MipmapLevelArb = ((int)0x207b),
NeedSystemPaletteExt = ((int)0x2005),
Aux4Arb = ((int)0x208b),
TextureFormatArb = ((int)0x2072),
AccumBitsExt = ((int)0x201d),
AccumBlueBitsExt = ((int)0x2020),
BackLeftArb = ((int)0x2085),
AlphaBitsExt = ((int)0x201b),
StencilBitsArb = ((int)0x2023),
DrawToPbufferExt = ((int)0x202d),
FullAccelerationExt = ((int)0x2027),
ColorBitsExt = ((int)0x2014),
BindToTextureRectangleFloatRgNv = ((int)0x20b2),
DepthBufferBitArb = ((int)0x00000004),
BindToTextureRgbaArb = ((int)0x2071),
AccumGreenBitsArb = ((int)0x201f),
AccumBitsArb = ((int)0x201d),
TypeRgbaFloatArb = ((int)0x21a0),
NeedPaletteArb = ((int)0x2004),
ShareAccumArb = ((int)0x200e),
TransparentArb = ((int)0x200a),
ShareStencilArb = ((int)0x200d),
Aux5Arb = ((int)0x208c),
ImageBufferLockI3d = ((int)0x00000002),
TextureFloatRNv = ((int)0x20b5),
DepthComponentNv = ((int)0x20a7),
FloatComponentsNv = ((int)0x20b0),
TransparentGreenValueArb = ((int)0x2038),
GenlockSourceExtenalTtlI3d = ((int)0x2047),
NeedSystemPaletteArb = ((int)0x2005),
BlueBitsExt = ((int)0x2019),
GreenShiftExt = ((int)0x2018),
OptimalPbufferWidthExt = ((int)0x2031),
AuxBuffersExt = ((int)0x2024),
TypeRgbaFloatAti = ((int)0x21a0),
FrontRightArb = ((int)0x2084),
DepthBitsExt = ((int)0x2022),
GammaTableSizeI3d = ((int)0x204e),
AccumAlphaBitsArb = ((int)0x2021),
Aux0Arb = ((int)0x2087),
TransparentIndexValueArb = ((int)0x203b),
AccumGreenBitsExt = ((int)0x201f),
TransparentBlueValueArb = ((int)0x2039),
NoAccelerationArb = ((int)0x2025),
MaxPbufferPixelsArb = ((int)0x202e),
GammaExcludeDesktopI3d = ((int)0x204f),
MaxPbufferPixelsExt = ((int)0x202e),
AccumBlueBitsArb = ((int)0x2020),
SwapUndefinedArb = ((int)0x202a),
ShareDepthExt = ((int)0x200c),
GenlockSourceEdgeBothI3d = ((int)0x204c),
Samples3dfx = ((int)0x2061),
DoubleBufferExt = ((int)0x2011),
BindToTextureRectangleFloatRgbNv = ((int)0x20b3),
SwapMethodExt = ((int)0x2007),
ErrorInvalidPixelTypeArb = ((int)0x2043),
GreenShiftArb = ((int)0x2018),
TextureFloatRgbaNv = ((int)0x20b8),
Aux1Arb = ((int)0x2088),
GreenBitsArb = ((int)0x2017),
NumberPixelFormatsExt = ((int)0x2000),
NumberOverlaysExt = ((int)0x2008),
PixelTypeArb = ((int)0x2013),
SwapLayerBuffersArb = ((int)0x2006),
DrawToBitmapArb = ((int)0x2002),
NumberPixelFormatsArb = ((int)0x2000),
PbufferLostArb = ((int)0x2036),
Aux9Arb = ((int)0x2090),
TextureCubeMapPositiveZArb = ((int)0x2081),
MaxPbufferHeightArb = ((int)0x2030),
TransparentExt = ((int)0x200a),
PbufferLargestArb = ((int)0x2033),
SwapMethodArb = ((int)0x2007),
TextureRgbaArb = ((int)0x2076),
PbufferWidthExt = ((int)0x2034),
OptimalPbufferHeightExt = ((int)0x2032),
StencilBitsExt = ((int)0x2023),
ShareStencilExt = ((int)0x200d),
DepthFloatExt = ((int)0x2040),
BindToTextureRgbArb = ((int)0x2070),
BindToTextureRectangleRgbNv = ((int)0x20a0),
GenlockSourceDigitalSyncI3d = ((int)0x2048),
AccumAlphaBitsExt = ((int)0x2021),
GenlockSourceExtenalSyncI3d = ((int)0x2045),
RedShiftExt = ((int)0x2016),
GenlockSourceDigitalFieldI3d = ((int)0x2049),
FrontLeftArb = ((int)0x2083),
BlueShiftArb = ((int)0x201a),
PbufferWidthArb = ((int)0x2034),
CubeMapFaceArb = ((int)0x207c),
StencilBufferBitArb = ((int)0x00000008),
NumberOverlaysArb = ((int)0x2008),
SwapExchangeExt = ((int)0x2028),
BackRightArb = ((int)0x2086),
DepthTextureFormatNv = ((int)0x20a5),
TextureFloatRgNv = ((int)0x20b6),
Texture1dArb = ((int)0x2079),
DepthBitsArb = ((int)0x2022),
BindToTextureDepthNv = ((int)0x20a3),
DrawToWindowArb = ((int)0x2001),
TypeRgbaExt = ((int)0x202b),
DigitalVideoCursorAlphaValueI3d = ((int)0x2051),
ErrorInvalidPixelTypeExt = ((int)0x2043),
AccumRedBitsExt = ((int)0x201e),
GreenBitsExt = ((int)0x2017),
TypeRgbaArb = ((int)0x202b),
DigitalVideoCursorAlphaFramebufferI3d = ((int)0x2050),
AuxBuffersArb = ((int)0x2024),
AccumRedBitsArb = ((int)0x201e),
TextureFloatRgbNv = ((int)0x20b7),
TypeColorindexExt = ((int)0x202c),
TransparentAlphaValueArb = ((int)0x203a),
BlueShiftExt = ((int)0x201a),
RedShiftArb = ((int)0x2016),
PbufferHeightExt = ((int)0x2035),
GenlockSourceEdgeRisingI3d = ((int)0x204b),
Texture2DArb = ((int)0x207a),
NumberUnderlaysArb = ((int)0x2009),
NumberUnderlaysExt = ((int)0x2009),
DrawToBitmapExt = ((int)0x2002),
ShareDepthArb = ((int)0x200c),
TextureDepthComponentNv = ((int)0x20a6),
NoAccelerationExt = ((int)0x2025),
PixelTypeExt = ((int)0x2013),
SupportOpenglArb = ((int)0x2010),
TextureCubeMapPositiveYArb = ((int)0x207f),
DrawToWindowExt = ((int)0x2001),
PbufferLargestExt = ((int)0x2033),
DrawToPbufferArb = ((int)0x202d),
SupportOpenglExt = ((int)0x2010),
SampleBuffers3dfx = ((int)0x2060),
GenlockSourceExtenalFieldI3d = ((int)0x2046),
MaxPbufferHeightExt = ((int)0x2030),
SupportGdiExt = ((int)0x200f),
Aux7Arb = ((int)0x208e),
DigitalVideoGammaCorrectedI3d = ((int)0x2053),
ColorBitsArb = ((int)0x2014),
Aux6Arb = ((int)0x208d),
ShareAccumExt = ((int)0x200e),
StereoArb = ((int)0x2012),
TextureRgbArb = ((int)0x2075),
AccelerationArb = ((int)0x2003),
TextureCubeMapPositiveXArb = ((int)0x207d),
TransparentRedValueArb = ((int)0x2037),
BlueBitsArb = ((int)0x2019),
SwapExchangeArb = ((int)0x2028),
SamplesExt = ((int)0x2042),
AlphaShiftExt = ((int)0x201c),
SamplesArb = ((int)0x2042),
TextureTargetArb = ((int)0x2073),
BindToTextureRectangleDepthNv = ((int)0x20a4),
AlphaShiftArb = ((int)0x201c),
Aux8Arb = ((int)0x208f),
MaxPbufferWidthExt = ((int)0x202f),
GenlockSourceEdgeFallingI3d = ((int)0x204a),
StereoExt = ((int)0x2012),
MaxPbufferWidthArb = ((int)0x202f),
TextureRectangleNv = ((int)0x20a2),
ImageBufferMinAccessI3d = ((int)0x00000001),
TextureCubeMapNegativeZArb = ((int)0x2082),
MipmapTextureArb = ((int)0x2074),
GenericAccelerationArb = ((int)0x2026),
BindToTextureRectangleFloatRNv = ((int)0x20b1),
FontLines = ((int)0),
}
public enum WGL_ARB_extensions_string
{
}
public enum WGL_I3D_image_buffer
{
ImageBufferMinAccessI3d = ((int)0x00000001),
ImageBufferLockI3d = ((int)0x00000002),
}
public enum WGL_I3D_swap_frame_lock
{
}
}

View file

@ -0,0 +1,130 @@
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* See license.txt for license info
*
* Date: 12/8/2007
* Time: 6:43 <EFBFBD><EFBFBD>
*/
using System;
using System.Collections.Generic;
namespace OpenTK.Platform.Windows
{
internal partial class Wgl
{
private static IntPtr[] EntryPoints;
private static string[] EntryPointNames;
internal const string Library = "OPENGL32.DLL";
private readonly static Dictionary<string, bool> extensions =
new Dictionary<string, bool>();
private static readonly object sync = new object();
public Wgl()
{
}
public static bool SupportsExtension(string name)
{
return SupportsExtension(Wgl.GetCurrentDC(), name);
}
/// <summary>
/// Checks if a Wgl extension is supported by the given context.
/// </summary>
/// <param name="dc">The device context.</param>
/// <param name="name">The extension to check.</param>
/// <returns>True if the extension is supported by the given context, false otherwise</returns>
public static bool SupportsExtension(IntPtr dc, string name)
{
lock (sync)
{
if (extensions.Count == 0)
{
// We cache this locally, as another thread might create a context which doesn't support this method.
// The design is far from ideal, but there's no good solution to this issue as long as we are using
// static WGL/GL classes. Fortunately, this issue is extremely unlikely to arise in practice, as you'd
// have to create one accelerated and one non-accelerated context in the same application, with the
// non-accelerated context coming second.
bool get_arb = SupportsFunction("wglGetExtensionsStringARB");
bool get_ext = SupportsFunction("wglGetExtensionsStringEXT");
string str =
get_arb ? OpenGL.Wgl.GetExtensionsStringARB(dc) :
get_ext ? OpenGL.Wgl.GetExtensionsStringEXT():
String.Empty;
if (!String.IsNullOrEmpty(str))
{
foreach (string ext in str.Split(' '))
{
extensions.Add(ext, true);
}
}
}
}
if (extensions.Count > 0)
{
return extensions.ContainsKey(name);
}
return false;
}
/// <summary>
/// Checks whether an extension function is supported.
/// Do not use with core WGL functions, as this function
/// will incorrectly return false.
/// </summary>
/// <param name="name">The extension function to check (e.g. "wglGetExtensionsStringARB"</param>
/// <returns>True if the extension function is supported; otherwise, false.</returns>
public static bool SupportsFunction(string name)
{
int index = Array.IndexOf(EntryPointNames, name);
if (index >= 0)
{
return EntryPoints[index] != IntPtr.Zero;
}
return false;
}
private object SyncRoot
{
get { return sync; }
}
internal static IntPtr GetAddress(string function_string)
{
IntPtr address = Wgl.GetProcAddress(function_string);
if (!IsValid(address))
{
address = Functions.GetProcAddress(WinFactory.OpenGLHandle, function_string);
}
return address;
}
private static bool IsValid(IntPtr address)
{
// See https://www.opengl.org/wiki/Load_OpenGL_Functions
long a = address.ToInt64();
bool is_valid = (a < -1) || (a > 3);
return is_valid;
}
internal void LoadEntryPoints()
{
lock (SyncRoot)
{
if (Wgl.GetCurrentContext() != IntPtr.Zero)
{
for (int i = 0; i < EntryPointNames.Length; i++)
{
EntryPoints[i] = GetAddress(EntryPointNames[i]);
}
extensions.Clear();
}
}
}
}
}

View file

@ -0,0 +1,200 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2010 the Open Toolkit library.
//
// 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.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Win32;
namespace OpenTK.Platform.Windows
{
internal sealed class WinDisplayDeviceDriver : DisplayDeviceBase
{
private readonly object display_lock = new object();
public WinDisplayDeviceDriver()
{
RefreshDisplayDevices();
SystemEvents.DisplaySettingsChanged +=
HandleDisplaySettingsChanged;
}
public sealed override bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
{
DeviceMode mode = null;
if (resolution != null)
{
mode = new DeviceMode();
mode.PelsWidth = resolution.Width;
mode.PelsHeight = resolution.Height;
mode.BitsPerPel = resolution.BitsPerPixel;
mode.DisplayFrequency = (int)resolution.RefreshRate;
mode.Fields = Constants.DM_BITSPERPEL
| Constants.DM_PELSWIDTH
| Constants.DM_PELSHEIGHT
| Constants.DM_DISPLAYFREQUENCY;
}
return Constants.DISP_CHANGE_SUCCESSFUL ==
Functions.ChangeDisplaySettingsEx((string)device.Id, mode, IntPtr.Zero,
ChangeDisplaySettingsEnum.Fullscreen, IntPtr.Zero);
}
public sealed override bool TryRestoreResolution(DisplayDevice device)
{
return TryChangeResolution(device, null);
}
public void RefreshDisplayDevices()
{
lock (display_lock)
{
// Store an array of the current available DisplayDevice objects.
// This is needed to preserve the original resolution.
DisplayDevice[] previousDevices = AvailableDevices.ToArray();
AvailableDevices.Clear();
// We save all necessary parameters in temporary variables
// and construct the device when every needed detail is available.
// The main DisplayDevice constructor adds the newly constructed device
// to the list of available devices.
DisplayDevice opentk_dev;
DisplayResolution opentk_dev_current_res = null;
List<DisplayResolution> opentk_dev_available_res = new List<DisplayResolution>();
bool opentk_dev_primary = false;
int device_count = 0, mode_count = 0;
// Get available video adapters and enumerate all monitors
WindowsDisplayDevice dev1 = new WindowsDisplayDevice();
while (Functions.EnumDisplayDevices(null, device_count++, dev1, 0))
{
if ((dev1.StateFlags & DisplayDeviceStateFlags.AttachedToDesktop) == DisplayDeviceStateFlags.None)
{
continue;
}
DeviceMode monitor_mode = new DeviceMode();
// The second function should only be executed when the first one fails
// (e.g. when the monitor is disabled)
if (Functions.EnumDisplaySettingsEx(dev1.DeviceName.ToString(), DisplayModeSettingsEnum.CurrentSettings, monitor_mode, 0) ||
Functions.EnumDisplaySettingsEx(dev1.DeviceName.ToString(), DisplayModeSettingsEnum.RegistrySettings, monitor_mode, 0))
{
VerifyMode(dev1, monitor_mode);
float scale = GetScale(ref monitor_mode);
opentk_dev_current_res = new DisplayResolution(
(int)(monitor_mode.Position.X / scale), (int)(monitor_mode.Position.Y / scale),
(int)(monitor_mode.PelsWidth / scale), (int)(monitor_mode.PelsHeight / scale),
monitor_mode.BitsPerPel, monitor_mode.DisplayFrequency);
opentk_dev_primary =
(dev1.StateFlags & DisplayDeviceStateFlags.PrimaryDevice) != DisplayDeviceStateFlags.None;
}
opentk_dev_available_res.Clear();
mode_count = 0;
while (Functions.EnumDisplaySettingsEx(dev1.DeviceName.ToString(), mode_count++, monitor_mode, 0))
{
VerifyMode(dev1, monitor_mode);
float scale = GetScale(ref monitor_mode);
DisplayResolution res = new DisplayResolution(
(int)(monitor_mode.Position.X / scale), (int)(monitor_mode.Position.Y / scale),
(int)(monitor_mode.PelsWidth / scale), (int)(monitor_mode.PelsHeight / scale),
monitor_mode.BitsPerPel, monitor_mode.DisplayFrequency);
opentk_dev_available_res.Add(res);
}
// Construct the OpenTK DisplayDevice through the accumulated parameters.
// The constructor will automatically add the DisplayDevice to the list
// of available devices.
#pragma warning disable 612,618
opentk_dev = new DisplayDevice(
opentk_dev_current_res,
opentk_dev_primary,
opentk_dev_available_res,
opentk_dev_current_res.Bounds,
dev1.DeviceName);
#pragma warning restore 612,618
// Set the original resolution if the DisplayDevice was previously available.
foreach (DisplayDevice existingDevice in previousDevices)
{
if ((string)existingDevice.Id == (string)opentk_dev.Id)
{
opentk_dev.OriginalResolution = existingDevice.OriginalResolution;
}
}
AvailableDevices.Add(opentk_dev);
if (opentk_dev_primary)
{
Primary = opentk_dev;
}
Debug.Print("DisplayDevice {0} ({1}) supports {2} resolutions.",
device_count, opentk_dev.IsPrimary ? "primary" : "secondary", opentk_dev.AvailableResolutions.Count);
}
}
}
private float GetScale(ref DeviceMode monitor_mode)
{
float scale = 1.0f;
if ((monitor_mode.Fields & Constants.DM_LOGPIXELS) != 0)
{
scale = monitor_mode.LogPixels / 96.0f;
}
return scale;
}
private static void VerifyMode(WindowsDisplayDevice device, DeviceMode mode)
{
if (mode.BitsPerPel == 0)
{
Debug.Print(
"[Warning] DisplayDevice '{0}' reported a mode with 0 bpp. Please create a bug report at https://github.com/opentk/opentk/issues",
device.DeviceName.ToString());
mode.BitsPerPel = 32;
}
}
private void HandleDisplaySettingsChanged(object sender, EventArgs e)
{
RefreshDisplayDevices();
}
~WinDisplayDeviceDriver()
{
SystemEvents.DisplaySettingsChanged -=
HandleDisplaySettingsChanged;
}
}
}

View file

@ -0,0 +1,109 @@
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.
//
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using OpenTK.Graphics;
namespace OpenTK.Platform.Windows
{
internal class WinFactory : PlatformFactoryBase
{
private readonly object SyncRoot = new object();
// The input drivers must be constructed lazily, *after* the
// WinFactory constructor has finished running. The reason is
// that they call WinFactory methods internally.
internal static IntPtr OpenGLHandle { get; private set; }
private const string OpenGLName = "OPENGL32.DLL";
public WinFactory()
{
if (System.Environment.OSVersion.Version.Major <= 4)
{
throw new PlatformNotSupportedException("OpenTK requires Windows XP or higher");
}
// Dynamically load opengl32.dll in order to use the extension loading capabilities of Wgl.
// Note: opengl32.dll must be loaded before gdi32.dll, otherwise strange failures may occur
// (such as "error: 2000" when calling wglSetPixelFormat or slowness/lag on specific GPUs).
LoadOpenGL();
if (System.Environment.OSVersion.Version.Major >= 6)
{
if (Toolkit.Options.EnableHighResolution)
{
// Enable high-dpi support
// Only available on Windows Vista and higher
bool result = Functions.SetProcessDPIAware();
Debug.Print("SetProcessDPIAware() returned {0}", result);
}
}
}
private static void LoadOpenGL()
{
OpenGLHandle = Functions.LoadLibrary(OpenGLName);
if (OpenGLHandle == IntPtr.Zero)
{
throw new ApplicationException(String.Format("LoadLibrary(\"{0}\") call failed with code {1}",
OpenGLName, Marshal.GetLastWin32Error()));
}
Debug.WriteLine(String.Format("Loaded opengl32.dll: {0}", OpenGLHandle));
}
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new WinDisplayDeviceDriver();
}
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new WinGLContext(mode, (WinWindowInfo)window, shareContext, major, minor, flags);
}
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new WinGLContext(handle, (WinWindowInfo)window, shareContext, major, minor, flags);
}
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
return new ContextHandle(Wgl.GetCurrentContext());
};
}
protected override void Dispose(bool manual)
{
if (!IsDisposed)
{
base.Dispose(manual);
}
}
}
}

View file

@ -0,0 +1,455 @@
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* Contributions from Erik Ylvisaker
* See license.txt for license info
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using OpenTK.Graphics;
namespace OpenTK.Platform.Windows
{
/// \internal
/// <summary>
/// Provides methods to create and control an opengl context on the Windows platform.
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
/// </summary>
internal sealed class WinGLContext : DesktopGraphicsContext
{
private static readonly object LoadLock = new object();
private bool vsync_supported;
private bool vsync_tear_supported;
private readonly WinGraphicsMode ModeSelector;
// We need to create a temp context in order to load
// wgl extensions (e.g. for multisampling or GL3).
// We cannot rely on any WGL extensions before
// we load them with the temporary context.
private class TemporaryContext : IDisposable
{
public ContextHandle Context;
public TemporaryContext(IntPtr native)
{
Debug.WriteLine("[WGL] Creating temporary context to load extensions");
if (native == null)
{
throw new ArgumentNullException();
}
// Create temporary context and load WGL entry points
// First, set a compatible pixel format to the device context
// of the temp window
WinWindowInfo window = new WinWindowInfo
{
Handle = native
};
WinGraphicsMode selector = new WinGraphicsMode(window.DeviceContext);
WinGLContext.SetGraphicsModePFD(selector, GraphicsMode.Default, window);
bool success = false;
// Then, construct a temporary context and load all wgl extensions
Context = new ContextHandle(Wgl.CreateContext(window.DeviceContext));
if (Context != ContextHandle.Zero)
{
// Make the context current.
// Note: on some video cards and on some virtual machines, wglMakeCurrent
// may fail with an errorcode of 6 (INVALID_HANDLE). The suggested workaround
// is to call wglMakeCurrent in a loop until it succeeds.
// See https://www.opengl.org/discussion_boards/showthread.php/171058-nVidia-wglMakeCurrent()-multiple-threads
// Sigh...
for (int retry = 0; retry < 5 && !success; retry++)
{
success = Wgl.MakeCurrent(window.DeviceContext, Context.Handle);
if (!success)
{
Debug.Print("wglMakeCurrent failed with error: {0}. Retrying", Marshal.GetLastWin32Error());
System.Threading.Thread.Sleep(10);
}
}
}
else
{
Debug.Print("[WGL] CreateContext failed with error: {0}", Marshal.GetLastWin32Error());
}
if (!success)
{
Debug.WriteLine("[WGL] Failed to create temporary context");
}
}
public void Dispose()
{
if (Context != ContextHandle.Zero)
{
Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
Wgl.DeleteContext(Context.Handle);
}
}
}
public WinGLContext(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
{
// There are many ways this code can break when accessed by multiple threads. The biggest offender is
// the sharedContext stuff, which will only become valid *after* this constructor returns.
// The easiest solution is to serialize all context construction - hence the big lock, below.
lock (LoadLock)
{
if (window == null)
{
throw new ArgumentNullException("window", "Must point to a valid window.");
}
if (window.Handle == IntPtr.Zero)
{
throw new ArgumentException("window", "Must be a valid window.");
}
IntPtr current_context = Wgl.GetCurrentContext();
TemporaryContext temp_context = null;
try
{
if (current_context == IntPtr.Zero)
{
// Create temporary context to load WGL extensions
temp_context = new TemporaryContext(window.Handle);
current_context = Wgl.GetCurrentContext();
if (current_context != IntPtr.Zero && current_context == temp_context.Context.Handle)
{
new Wgl().LoadEntryPoints();
}
}
Debug.Print("OpenGL will be bound to window:{0} on thread:{1}", window.Handle,
System.Threading.Thread.CurrentThread.ManagedThreadId);
ModeSelector = new WinGraphicsMode(window.DeviceContext);
Mode = SetGraphicsModePFD(ModeSelector, format, (WinWindowInfo)window);
if (Wgl.SupportsFunction("wglCreateContextAttribsARB"))
{
try
{
Debug.Write("Using WGL_ARB_create_context... ");
List<int> attributes = new List<int>();
attributes.Add((int)ArbCreateContext.MajorVersion);
attributes.Add(major);
attributes.Add((int)ArbCreateContext.MinorVersion);
attributes.Add(minor);
if (flags != 0)
{
attributes.Add((int)ArbCreateContext.ContextFlags);
attributes.Add((int)GetARBContextFlags(flags));
attributes.Add((int)ArbCreateContext.ProfileMask);
attributes.Add((int)GetARBContextProfile(flags));
}
// According to the docs, " <attribList> specifies a list of attributes for the context.
// The list consists of a sequence of <name,value> pairs terminated by the
// value 0. [...]"
// Is this a single 0, or a <0, 0> pair? (Defensive coding: add two zeroes just in case).
attributes.Add(0);
attributes.Add(0);
Handle = new ContextHandle(
OpenGL.Wgl.CreateContextAttribsARB(
window.DeviceContext,
sharedContext != null ? (sharedContext as IGraphicsContextInternal).Context.Handle : IntPtr.Zero,
attributes.ToArray()));
if (Handle == ContextHandle.Zero)
{
Debug.Print("failed. (Error: {0})", Marshal.GetLastWin32Error());
}
}
catch (Exception e) { Debug.Print(e.ToString()); }
}
if (Handle == ContextHandle.Zero)
{
// Failed to create GL3-level context, fall back to GL2.
Debug.Write("Falling back to GL2... ");
Handle = new ContextHandle(Wgl.CreateContext(window.DeviceContext));
if (Handle == ContextHandle.Zero)
{
Handle = new ContextHandle(Wgl.CreateContext(window.DeviceContext));
}
if (Handle == ContextHandle.Zero)
{
throw new GraphicsContextException(
String.Format("Context creation failed. Wgl.CreateContext() error: {0}.",
Marshal.GetLastWin32Error()));
}
}
Debug.WriteLine(String.Format("success! (id: {0})", Handle));
}
finally
{
if (temp_context != null)
{
temp_context.Dispose();
temp_context = null;
}
}
}
// Todo: is this comment still true?
// On intel drivers, wgl entry points appear to change
// when creating multiple contexts. As a workaround,
// we reload Wgl entry points every time we create a
// new context - this solves the issue without any apparent
// side-effects (i.e. the old contexts can still be handled
// using the new entry points.)
// Sigh...
MakeCurrent(window);
new Wgl().LoadEntryPoints();
if (sharedContext != null)
{
Marshal.GetLastWin32Error();
Debug.Write(String.Format("Sharing state with context {0}: ", sharedContext));
bool result = Wgl.ShareLists((sharedContext as IGraphicsContextInternal).Context.Handle, Handle.Handle);
Debug.WriteLine(result ? "success!" : "failed with win32 error " + Marshal.GetLastWin32Error());
}
}
private static ArbCreateContext GetARBContextFlags(GraphicsContextFlags flags)
{
ArbCreateContext result = 0;
result |= (flags & GraphicsContextFlags.ForwardCompatible) != 0 ?
ArbCreateContext.CoreProfileBit : ArbCreateContext.CompatibilityProfileBit;
return result;
}
private static ArbCreateContext GetARBContextProfile(GraphicsContextFlags flags)
{
ArbCreateContext result = 0;
result |= (flags & GraphicsContextFlags.Debug) != 0 ? ArbCreateContext.DebugBit : 0;
return result;
}
public WinGLContext(ContextHandle handle, WinWindowInfo window, IGraphicsContext sharedContext,
int major, int minor, GraphicsContextFlags flags)
{
if (handle == ContextHandle.Zero)
{
throw new ArgumentException("handle");
}
if (window == null)
{
throw new ArgumentNullException("window");
}
Handle = handle;
}
public override void SwapBuffers()
{
if (!Functions.SwapBuffers(DeviceContext))
{
throw new GraphicsContextException(String.Format(
"Failed to swap buffers for context {0} current. Error: {1}", this, Marshal.GetLastWin32Error()));
}
}
public override void MakeCurrent(IWindowInfo window)
{
lock (LoadLock)
{
bool success;
WinWindowInfo wnd = window as WinWindowInfo;
if (wnd != null)
{
if (wnd.Handle == IntPtr.Zero)
{
throw new ArgumentException("window", "Must point to a valid window.");
}
success = Wgl.MakeCurrent(wnd.DeviceContext, Handle.Handle);
DeviceContext = wnd.DeviceContext;
}
else
{
success = Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero);
DeviceContext = IntPtr.Zero;
}
if (!success)
{
throw new GraphicsContextException(String.Format(
"Failed to make context {0} current. Error: {1}", this, Marshal.GetLastWin32Error()));
}
}
}
public override bool IsCurrent
{
get { return Wgl.GetCurrentContext() == Handle.Handle; }
}
public override int SwapInterval
{
get
{
lock (LoadLock)
{
if (vsync_supported)
{
return OpenGL.Wgl.GetSwapIntervalEXT();
}
else
{
return 0;
}
}
}
set
{
lock (LoadLock)
{
if (vsync_supported)
{
if (value < 0 && !vsync_tear_supported)
{
value = 1;
}
if (!OpenGL.Wgl.SwapIntervalEXT(value))
{
Debug.Print("wglSwapIntervalEXT call failed.");
}
}
}
}
}
public override void LoadAll()
{
lock (LoadLock)
{
new Wgl().LoadEntryPoints();
vsync_supported =
Wgl.SupportsExtension(DeviceContext, "WGL_EXT_swap_control") &&
Wgl.SupportsFunction("wglGetSwapIntervalEXT") &&
Wgl.SupportsFunction("wglSwapIntervalEXT");
vsync_tear_supported =
Wgl.SupportsExtension(DeviceContext, "WGL_EXT_swap_control_tear");
}
base.LoadAll();
}
/*
IWindowInfo IGraphicsContextInternal.Info
{
get { return (IWindowInfo)windowInfo; }
}
*/
public override IntPtr GetAddress(IntPtr function_string)
{
IntPtr address = Wgl.GetProcAddress(function_string);
if (!IsValid(address))
{
address = Functions.GetProcAddress(WinFactory.OpenGLHandle, function_string);
}
return address;
}
private static bool IsValid(IntPtr address)
{
// See https://www.opengl.org/wiki/Load_OpenGL_Functions
long a = address.ToInt64();
bool is_valid = (a < -1) || (a > 3);
return is_valid;
}
// Note: there is no relevant ARB function.
internal static GraphicsMode SetGraphicsModePFD(WinGraphicsMode mode_selector,
GraphicsMode mode, WinWindowInfo window)
{
Debug.Write("Setting pixel format... ");
if (window == null)
{
throw new ArgumentNullException("window", "Must point to a valid window.");
}
if (!mode.Index.HasValue)
{
mode = mode_selector.SelectGraphicsMode(
mode.ColorFormat, mode.Depth, mode.Stencil,
mode.Samples, mode.AccumulatorFormat,
mode.Buffers, mode.Stereo);
}
PixelFormatDescriptor pfd = new PixelFormatDescriptor();
Functions.DescribePixelFormat(
window.DeviceContext, (int)mode.Index.Value,
API.PixelFormatDescriptorSize, ref pfd);
Debug.WriteLine(mode.Index.ToString());
if (!Functions.SetPixelFormat(window.DeviceContext, (int)mode.Index.Value, ref pfd))
{
throw new GraphicsContextException(String.Format(
"Requested GraphicsMode not available. SetPixelFormat error: {0}",
Marshal.GetLastWin32Error()));
}
return mode;
}
internal IntPtr DeviceContext { get; private set; }
/// <summary>Returns a System.String describing this OpenGL context.</summary>
/// <returns>A System.String describing this OpenGL context.</returns>
public override string ToString()
{
return (this as IGraphicsContextInternal).Context.ToString();
}
protected override void Dispose(bool calledManually)
{
if (!IsDisposed)
{
if (calledManually)
{
DestroyContext();
}
IsDisposed = true;
}
}
private void DestroyContext()
{
if (Handle != ContextHandle.Zero)
{
try
{
// This will fail if the user calls Dispose() on thread X when the context is current on thread Y.
if (!Wgl.DeleteContext(Handle.Handle))
{
Debug.Print("Failed to destroy OpenGL context {0}. Error: {1}",
Handle.ToString(), Marshal.GetLastWin32Error());
}
}
catch (AccessViolationException e)
{
Debug.WriteLine("An access violation occured while destroying the OpenGL context. Please report at https://github.com/opentk/opentk/issues");
Debug.Indent();
Debug.Print("Marshal.GetLastWin32Error(): {0}", Marshal.GetLastWin32Error().ToString());
Debug.WriteLine(e.ToString());
Debug.Unindent();
}
Handle = ContextHandle.Zero;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more