[Mac] Sped up extension loading
From ~200ms down to ~65ms on a rMBP with Nvidia 650M and Mac OS X 10.9.2.
This commit is contained in:
parent
433fa35f7e
commit
b732e377c9
2 changed files with 121 additions and 23 deletions
|
@ -47,6 +47,12 @@ namespace OpenTK
|
|||
static readonly IntPtr selFlushBuffer = Selector.Get("flushBuffer");
|
||||
static readonly IntPtr selMakeCurrentContext = Selector.Get("makeCurrentContext");
|
||||
static readonly IntPtr selUpdate = Selector.Get("update");
|
||||
static readonly IntPtr opengl = NS.AddImage(
|
||||
"/System/Library/Frameworks/OpenGL.framework/OpenGL",
|
||||
AddImageFlags.ReturnOnError);
|
||||
static readonly IntPtr opengles = NS.AddImage(
|
||||
"/System/Library/Frameworks/OpenGL.framework/OpenGLES",
|
||||
AddImageFlags.ReturnOnError);
|
||||
|
||||
static CocoaContext()
|
||||
{
|
||||
|
@ -292,14 +298,49 @@ namespace OpenTK
|
|||
|
||||
#region IGraphicsContextInternal Members
|
||||
|
||||
public override IntPtr GetAddress(string function)
|
||||
{
|
||||
return NS.GetAddress(function);
|
||||
}
|
||||
|
||||
public override IntPtr GetAddress(IntPtr function)
|
||||
{
|
||||
return NS.GetAddress(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;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -33,27 +33,52 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace OpenTK.Platform.MacOS
|
||||
{
|
||||
[Flags]
|
||||
enum AddImageFlags
|
||||
{
|
||||
ReturnOnError = 1,
|
||||
WithSearching = 2,
|
||||
ReturnOnlyIfLoaded = 4
|
||||
}
|
||||
|
||||
[Flags]
|
||||
enum SymbolLookupFlags
|
||||
{
|
||||
Bind = 0,
|
||||
BindNow = 1,
|
||||
BindFully = 2,
|
||||
ReturnOnError = 4
|
||||
}
|
||||
|
||||
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 = "NSAddImage")]
|
||||
internal static extern IntPtr AddImage(string s, AddImageFlags flags);
|
||||
[DllImport(Library, EntryPoint = "NSAddressOfSymbol")]
|
||||
static extern IntPtr NSAddressOfSymbol(IntPtr symbol);
|
||||
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)]
|
||||
private static extern IntPtr dlopen(String fileName, int flags);
|
||||
internal static extern IntPtr dlopen(String fileName, int flags);
|
||||
[DllImport(Library)]
|
||||
private static extern int dlclose(IntPtr handle);
|
||||
internal static extern int dlclose(IntPtr handle);
|
||||
[DllImport (Library)]
|
||||
private static extern IntPtr dlsym (IntPtr handle, string symbol);
|
||||
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)
|
||||
{
|
||||
|
@ -73,7 +98,7 @@ namespace OpenTK.Platform.MacOS
|
|||
}
|
||||
Marshal.WriteByte(ptr, function.Length + 1, 0); // null-terminate
|
||||
|
||||
IntPtr symbol = GetAddress(ptr);
|
||||
IntPtr symbol = GetAddressInternal(ptr);
|
||||
return symbol;
|
||||
}
|
||||
finally
|
||||
|
@ -84,12 +109,39 @@ namespace OpenTK.Platform.MacOS
|
|||
|
||||
public static IntPtr GetAddress(IntPtr function)
|
||||
{
|
||||
IntPtr symbol = IntPtr.Zero;
|
||||
if (NSIsSymbolNameDefined(function))
|
||||
unsafe
|
||||
{
|
||||
symbol = NSLookupAndBindSymbol(function);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
static IntPtr GetAddressInternal(IntPtr function)
|
||||
{
|
||||
IntPtr symbol = IntPtr.Zero;
|
||||
if (IsSymbolNameDefined(function))
|
||||
{
|
||||
symbol = LookupAndBindSymbol(function);
|
||||
if (symbol != IntPtr.Zero)
|
||||
symbol = NSAddressOfSymbol(symbol);
|
||||
symbol = AddressOfSymbol(symbol);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
@ -99,6 +151,11 @@ namespace OpenTK.Platform.MacOS
|
|||
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;
|
||||
|
|
Loading…
Reference in a new issue