Merge branch 'external' into develop

This commit is contained in:
thefiddler 2013-12-28 01:27:49 +01:00
commit dc12128679
10 changed files with 303 additions and 121 deletions

View file

@ -565,6 +565,7 @@
<None Include="..\..\Dependencies\x64\libSDL2.dylib"> <None Include="..\..\Dependencies\x64\libSDL2.dylib">
<Link>Dependencies\x64\libSDL2.dylib</Link> <Link>Dependencies\x64\libSDL2.dylib</Link>
</None> </None>
<Compile Include="OpenTK\Test\ExternalContext.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5"> <BootstrapperPackage Include="Microsoft.Net.Client.3.5">

View file

@ -0,0 +1,81 @@
// This code was written for the OpenTK library and has been released
// to the Public Domain.
// It is provided "as is" without express or implied warranty of any kind.
using System;
using System.Runtime.InteropServices;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
namespace Examples.Tests
{
[Example("External Context Test", ExampleCategory.OpenTK, "OpenGL")]
class ExternalContext
{
public static void Main()
{
using (Toolkit.Init(new ToolkitOptions { Backend = PlatformBackend.PreferNative }))
{
var window = Sdl2.CreateWindow("Test", 0, 0, 640, 480, WindowFlags.AllowHighDpi | WindowFlags.OpenGL);
var context = Sdl2.CreateContext(window);
Sdl2.MakeCurrent(window, context);
using (var dummy = new GraphicsContext(new ContextHandle(context), OpenTK.Platform.Utilities.CreateDummyWindowInfo()))
{
for (int i = 0; i < 100; i++)
{
Sdl2.PumpEvents();
GL.ClearColor(i / 100.0f, i / 100.0f, i / 100.0f, i / 100.0f);
GL.Clear(ClearBufferMask.ColorBufferBit);
Sdl2.SwapWindow(window);
}
Sdl2.DestroyWindow(window);
}
}
}
}
#region SDL2 bindings
public enum WindowFlags
{
Default = 0,
OpenGL = 0x00000002,
AllowHighDpi = 0x00002000,
}
static class Sdl2
{
const string lib = "SDL2.dll";
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_CreateWindow", ExactSpelling = true)]
public static extern IntPtr CreateWindow(string title, int x, int y, int w, int h, WindowFlags flags);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_CreateContext", ExactSpelling = true)]
public static extern IntPtr CreateContext(IntPtr window);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_DestroyWindow", ExactSpelling = true)]
public static extern void DestroyWindow(IntPtr window);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_GetCurrentContext", ExactSpelling = true)]
public static extern IntPtr GetCurrentContext();
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_GetProcAddress", ExactSpelling = true)]
public static extern IntPtr GetAddress(string name);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_MakeCurrent", ExactSpelling = true)]
public static extern int MakeCurrent(IntPtr window, IntPtr context);
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_PumpEvents", ExactSpelling = true)]
public static extern void PumpEvents();
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_SwapWindow", ExactSpelling = true)]
public static extern void SwapWindow(IntPtr window);
}
#endregion
}

View file

@ -39,14 +39,13 @@ namespace OpenTK.Graphics
/// </summary> /// </summary>
public sealed class GraphicsContext : IGraphicsContext, IGraphicsContextInternal public sealed class GraphicsContext : IGraphicsContext, IGraphicsContextInternal
{ {
public delegate IntPtr GetAddressDelegate(string function);
public delegate ContextHandle GetCurrentContextDelegate();
#region --- Fields --- #region --- Fields ---
IGraphicsContext implementation; // The actual render context implementation for the underlying platform. IGraphicsContext implementation; // The actual render context implementation for the underlying platform.
bool disposed; bool disposed;
// Indicates that this context was created through external means, e.g. Tao.Sdl or GLWidget#.
// In this case, We'll assume that the external program will manage the lifetime of this
// context - we'll not destroy it manually.
readonly bool IsExternal;
bool check_errors = true; bool check_errors = true;
// Cache for the context handle. We need this for RemoveContext() // Cache for the context handle. We need this for RemoveContext()
// in case the user does not call Dispose(). When this happens, // in case the user does not call Dispose(). When this happens,
@ -67,17 +66,6 @@ namespace OpenTK.Graphics
#region --- Constructors --- #region --- Constructors ---
// Necessary to allow creation of dummy GraphicsContexts (see CreateDummyContext static method).
GraphicsContext(ContextHandle handle)
{
implementation = new OpenTK.Platform.Dummy.DummyGLContext(handle);
lock (SyncRoot)
{
AddContext(this);
}
}
/// <summary> /// <summary>
/// Constructs a new GraphicsContext with the specified GraphicsMode and attaches it to the specified window. /// Constructs a new GraphicsContext with the specified GraphicsMode and attaches it to the specified window.
/// </summary> /// </summary>
@ -163,12 +151,65 @@ namespace OpenTK.Graphics
} }
} }
/// <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> /// <summary>
/// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK.
/// </summary> /// </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="handle">The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK.</param>
/// <param name="window">The window this context is bound to. This must be a valid window obtained through Utilities.CreateWindowInfo.</param> /// <param name="window">This parameter is reserved.</param>
/// <exception cref="GraphicsContextException">Occurs if handle is identical to a context already registered with OpenTK.</exception>
public GraphicsContext(ContextHandle handle, IWindowInfo window) public GraphicsContext(ContextHandle handle, IWindowInfo window)
: this(handle, window, null, 1, 0, GraphicsContextFlags.Default) : this(handle, window, null, 1, 0, GraphicsContextFlags.Default)
{ } { }
@ -177,40 +218,14 @@ namespace OpenTK.Graphics
/// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK. /// Constructs a new GraphicsContext from a pre-existing context created outside of OpenTK.
/// </summary> /// </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="handle">The handle of the existing context. This must be a valid, unique handle that is not known to OpenTK.</param>
/// <param name="window">The window this context is bound to. This must be a valid window obtained through Utilities.CreateWindowInfo.</param> /// <param name="window">This parameter is reserved.</param>
/// <param name="shareContext">A different context that shares resources with this instance, if any. /// <param name="shareContext">This parameter is reserved.</param>
/// Pass null if the context is not shared or if this is the first GraphicsContext instruct you construct.</param> /// <param name="major">This parameter is reserved.</param>
/// <param name="major">The major version of the context (e.g. "2" for "2.1").</param> /// <param name="minor">This parameter is reserved.</param>
/// <param name="minor">The minor version of the context (e.g. "1" for "2.1").</param> /// <param name="flags">This parameter is reserved..</param>
/// <param name="flags">A bitwise combination of <see cref="GraphicsContextFlags"/> that describe this context.</param>
/// <exception cref="GraphicsContextException">Occurs if handle is identical to a context already registered with OpenTK.</exception>
public GraphicsContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags) public GraphicsContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags)
: this(handle) : this(handle, Platform.Utilities.CreateGetAddress(), Factory.Default.CreateGetCurrentGraphicsContext())
{ { }
lock (SyncRoot)
{
IsExternal = true;
if (handle == ContextHandle.Zero)
{
implementation = new OpenTK.Platform.Dummy.DummyGLContext(handle);
}
else if (available_contexts.ContainsKey(handle))
{
throw new GraphicsContextException("Context already exists.");
}
else
{
switch ((flags & GraphicsContextFlags.Embedded) == GraphicsContextFlags.Embedded)
{
case false: implementation = Factory.Default.CreateGLContext(handle, window, shareContext, direct_rendering, major, minor, flags); break;
case true: implementation = Factory.Embedded.CreateGLContext(handle, window, shareContext, direct_rendering, major, minor, flags); break;
}
}
(this as IGraphicsContextInternal).LoadAll();
}
}
#endregion #endregion
@ -309,6 +324,7 @@ namespace OpenTK.Graphics
/// <para>Instances created by this method will not be functional. Instance methods will have no effect.</para> /// <para>Instances created by this method will not be functional. Instance methods will have no effect.</para>
/// <para>This method requires that a context is current on the calling thread.</para> /// <para>This method requires that a context is current on the calling thread.</para>
/// </remarks> /// </remarks>
[Obsolete("Use GraphicsContext(ContextHandle, IWindowInfo) constructor instead")]
public static GraphicsContext CreateDummyContext() public static GraphicsContext CreateDummyContext()
{ {
ContextHandle handle = GetCurrentContext(); ContextHandle handle = GetCurrentContext();
@ -326,12 +342,13 @@ namespace OpenTK.Graphics
/// <remarks> /// <remarks>
/// <para>Instances created by this method will not be functional. Instance methods will have no effect.</para> /// <para>Instances created by this method will not be functional. Instance methods will have no effect.</para>
/// </remarks> /// </remarks>
[Obsolete("Use GraphicsContext(ContextHandle, IWindowInfo) constructor instead")]
public static GraphicsContext CreateDummyContext(ContextHandle handle) public static GraphicsContext CreateDummyContext(ContextHandle handle)
{ {
if (handle == ContextHandle.Zero) if (handle == ContextHandle.Zero)
throw new ArgumentOutOfRangeException("handle"); throw new ArgumentOutOfRangeException("handle");
return new GraphicsContext(handle); return new GraphicsContext(handle, (IWindowInfo)null);
} }
#endregion #endregion
@ -352,7 +369,6 @@ namespace OpenTK.Graphics
#region public static IGraphicsContext CurrentContext #region public static IGraphicsContext CurrentContext
internal delegate ContextHandle GetCurrentContextDelegate();
internal static GetCurrentContextDelegate GetCurrentContext; internal static GetCurrentContextDelegate GetCurrentContext;
/// <summary> /// <summary>

View file

@ -777,6 +777,7 @@
<Compile Include="SlotAttribute.cs" /> <Compile Include="SlotAttribute.cs" />
<Compile Include="RewrittenAttribute.cs" /> <Compile Include="RewrittenAttribute.cs" />
<Compile Include="Graphics\OpenGL\GLObsolete.cs" /> <Compile Include="Graphics\OpenGL\GLObsolete.cs" />
<Compile Include="Platform\MacOS\NS.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>

View file

@ -22,7 +22,8 @@ namespace OpenTK.Platform.Dummy
/// </summary> /// </summary>
internal sealed class DummyGLContext : DesktopGraphicsContext internal sealed class DummyGLContext : DesktopGraphicsContext
{ {
// This mode is not real. To receive a real mode we'd have to create a temporary context, which is not desirable! readonly GraphicsContext.GetAddressDelegate Loader;
bool vsync; bool vsync;
int swap_interval; int swap_interval;
static int handle_count; static int handle_count;
@ -31,13 +32,20 @@ namespace OpenTK.Platform.Dummy
#region --- Constructors --- #region --- Constructors ---
public DummyGLContext() public DummyGLContext()
: this(new ContextHandle(new IntPtr(++handle_count)))
{ {
Handle = new ContextHandle(
new IntPtr(Interlocked.Increment(
ref handle_count)));
} }
public DummyGLContext(ContextHandle handle) public DummyGLContext(ContextHandle handle, GraphicsContext.GetAddressDelegate loader)
: this()
{ {
Handle = handle; if (handle != ContextHandle.Zero)
{
Handle = handle;
}
Loader = loader;
Mode = new GraphicsMode(new IntPtr(2), 32, 16, 0, 0, 0, 2, false); Mode = new GraphicsMode(new IntPtr(2), 32, 16, 0, 0, 0, 2, false);
} }
@ -45,15 +53,6 @@ namespace OpenTK.Platform.Dummy
#region --- IGraphicsContext Members --- #region --- IGraphicsContext Members ---
public void CreateContext(bool direct, IGraphicsContext source)
{
if (Handle == ContextHandle.Zero)
{
++handle_count;
Handle = new ContextHandle((IntPtr)handle_count);
}
}
public override void SwapBuffers() { } public override void SwapBuffers() { }
public override void MakeCurrent(IWindowInfo info) public override void MakeCurrent(IWindowInfo info)
@ -81,9 +80,15 @@ namespace OpenTK.Platform.Dummy
get { return current_thread != null && current_thread == Thread.CurrentThread; } get { return current_thread != null && current_thread == Thread.CurrentThread; }
} }
public override IntPtr GetAddress(string function) { return IntPtr.Zero; } public override IntPtr GetAddress(string function)
{
return Loader(function);
}
public override IntPtr GetAddress(IntPtr function) { return IntPtr.Zero; } public override IntPtr GetAddress(IntPtr function)
{
return IntPtr.Zero;
}
public override int SwapInterval public override int SwapInterval
{ {
@ -101,7 +106,14 @@ namespace OpenTK.Platform.Dummy
{ } { }
public override void LoadAll() public override void LoadAll()
{ } {
new OpenTK.Graphics.OpenGL.GL().LoadEntryPoints();
new OpenTK.Graphics.OpenGL4.GL().LoadEntryPoints();
new OpenTK.Graphics.ES10.GL().LoadEntryPoints();
new OpenTK.Graphics.ES11.GL().LoadEntryPoints();
new OpenTK.Graphics.ES20.GL().LoadEntryPoints();
new OpenTK.Graphics.ES30.GL().LoadEntryPoints();
}
#endregion #endregion

View file

@ -464,64 +464,16 @@ namespace OpenTK.Platform.MacOS
#region IGraphicsContextInternal Members #region IGraphicsContextInternal Members
private const string Library = "libdl.dylib";
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
private static extern bool NSIsSymbolNameDefined(string s);
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
private static extern bool NSIsSymbolNameDefined(IntPtr s);
[DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
private static extern IntPtr NSLookupAndBindSymbol(string s);
[DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
private static extern IntPtr NSLookupAndBindSymbol(IntPtr s);
[DllImport(Library, EntryPoint = "NSAddressOfSymbol")]
private static extern IntPtr NSAddressOfSymbol(IntPtr symbol);
public override IntPtr GetAddress(string function) public override IntPtr GetAddress(string function)
{ {
// Instead of allocating and combining strings in managed memory return NS.GetAddress(function);
// 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 = IntPtr.Zero;
if (NSIsSymbolNameDefined(ptr))
{
symbol = NSLookupAndBindSymbol(ptr);
if (symbol != IntPtr.Zero)
symbol = NSAddressOfSymbol(symbol);
}
return symbol;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
} }
public override IntPtr GetAddress(IntPtr function) public override IntPtr GetAddress(IntPtr function)
{ {
if (!NSIsSymbolNameDefined(function)) return NS.GetAddress(function);
return IntPtr.Zero;
IntPtr symbol = NSLookupAndBindSymbol(function);
if (symbol != IntPtr.Zero)
symbol = NSAddressOfSymbol(symbol);
return symbol;
} }
#endregion #endregion
} }
} }

View file

@ -70,7 +70,7 @@ namespace OpenTK.Platform.MacOS
{ {
return (GraphicsContext.GetCurrentContextDelegate)delegate return (GraphicsContext.GetCurrentContextDelegate)delegate
{ {
return new ContextHandle(Agl.aglGetCurrentContext()); return new ContextHandle(Cgl.GetCurrentContext());
}; };
} }

View file

@ -0,0 +1,92 @@
#region License
//
// 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.
//
#endregion
using System;
using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS
{
internal class NS
{
const string Library = "libdl.dylib";
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
static extern bool NSIsSymbolNameDefined(string s);
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")]
static extern bool NSIsSymbolNameDefined(IntPtr s);
[DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
static extern IntPtr NSLookupAndBindSymbol(string s);
[DllImport(Library, EntryPoint = "NSLookupAndBindSymbol")]
static extern IntPtr NSLookupAndBindSymbol(IntPtr s);
[DllImport(Library, EntryPoint = "NSAddressOfSymbol")]
static extern IntPtr NSAddressOfSymbol(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 = GetAddress(ptr);
return symbol;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
public static IntPtr GetAddress(IntPtr function)
{
IntPtr symbol = IntPtr.Zero;
if (NSIsSymbolNameDefined(function))
{
symbol = NSLookupAndBindSymbol(function);
if (symbol != IntPtr.Zero)
symbol = NSAddressOfSymbol(symbol);
}
return symbol;
}
}
}

View file

@ -334,6 +334,7 @@ namespace OpenTK.Platform.SDL2
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_GetAttribute", ExactSpelling = true)] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_GetAttribute", ExactSpelling = true)]
public static extern int GetAttribute(ContextAttribute attr, out int value); public static extern int GetAttribute(ContextAttribute attr, out int value);
[SuppressUnmanagedCodeSecurity]
[DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_GetCurrentContext", ExactSpelling = true)] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GL_GetCurrentContext", ExactSpelling = true)]
public static extern IntPtr GetCurrentContext(); public static extern IntPtr GetCurrentContext();

View file

@ -170,6 +170,32 @@ namespace OpenTK.Platform
#endregion #endregion
#region CreateGetAddress
internal static GraphicsContext.GetAddressDelegate CreateGetAddress()
{
GraphicsContext.GetAddressDelegate loader = null;
if (Configuration.RunningOnWindows)
{
loader = Platform.Windows.Wgl.GetProcAddress;
}
else if (Configuration.RunningOnX11)
{
loader = Platform.X11.Glx.GetProcAddress;
}
else if (Configuration.RunningOnMacOS)
{
loader = Platform.MacOS.NS.GetAddress;
}
else
{
throw new PlatformNotSupportedException();
}
return loader;
}
#endregion
#region --- Creating a Graphics Context --- #region --- Creating a Graphics Context ---
/// <summary> /// <summary>