[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:
thefiddler 2014-04-26 14:21:26 +02:00
parent 433fa35f7e
commit b732e377c9
2 changed files with 121 additions and 23 deletions

View file

@ -47,6 +47,12 @@ namespace OpenTK
static readonly IntPtr selFlushBuffer = Selector.Get("flushBuffer"); static readonly IntPtr selFlushBuffer = Selector.Get("flushBuffer");
static readonly IntPtr selMakeCurrentContext = Selector.Get("makeCurrentContext"); static readonly IntPtr selMakeCurrentContext = Selector.Get("makeCurrentContext");
static readonly IntPtr selUpdate = Selector.Get("update"); 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() static CocoaContext()
{ {
@ -292,14 +298,49 @@ namespace OpenTK
#region IGraphicsContextInternal Members #region IGraphicsContextInternal Members
public override IntPtr GetAddress(string function)
{
return NS.GetAddress(function);
}
public override IntPtr GetAddress(IntPtr 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 #endregion

View file

@ -33,27 +33,52 @@ using System.Runtime.InteropServices;
namespace OpenTK.Platform.MacOS 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 internal class NS
{ {
const string Library = "libdl.dylib"; const string Library = "libdl.dylib";
[DllImport(Library, EntryPoint = "NSIsSymbolNameDefined")] [DllImport(Library, EntryPoint = "NSAddImage")]
static extern bool NSIsSymbolNameDefined(string s); internal static extern IntPtr AddImage(string s, AddImageFlags flags);
[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")] [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)] [DllImport(Library)]
private static extern IntPtr dlopen(String fileName, int flags); internal static extern IntPtr dlopen(String fileName, int flags);
[DllImport(Library)] [DllImport(Library)]
private static extern int dlclose(IntPtr handle); internal static extern int dlclose(IntPtr handle);
[DllImport (Library)] [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) public static IntPtr GetAddress(string function)
{ {
@ -73,7 +98,7 @@ namespace OpenTK.Platform.MacOS
} }
Marshal.WriteByte(ptr, function.Length + 1, 0); // null-terminate Marshal.WriteByte(ptr, function.Length + 1, 0); // null-terminate
IntPtr symbol = GetAddress(ptr); IntPtr symbol = GetAddressInternal(ptr);
return symbol; return symbol;
} }
finally finally
@ -84,12 +109,39 @@ namespace OpenTK.Platform.MacOS
public static IntPtr GetAddress(IntPtr function) public static IntPtr GetAddress(IntPtr function)
{ {
IntPtr symbol = IntPtr.Zero; unsafe
if (NSIsSymbolNameDefined(function))
{ {
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) if (symbol != IntPtr.Zero)
symbol = NSAddressOfSymbol(symbol); symbol = AddressOfSymbol(symbol);
} }
return symbol; return symbol;
} }
@ -99,6 +151,11 @@ namespace OpenTK.Platform.MacOS
return dlsym(handle, symbol); return dlsym(handle, symbol);
} }
public static IntPtr GetSymbol(IntPtr handle, IntPtr symbol)
{
return dlsym(handle, symbol);
}
public static IntPtr LoadLibrary(string fileName) public static IntPtr LoadLibrary(string fileName)
{ {
const int RTLD_NOW = 2; const int RTLD_NOW = 2;