Refactored extension loading to remove duplicate code. The logic is now contained in OpenTK/Platform/Utilities.cs

This commit is contained in:
the_fiddler 2008-01-22 23:58:50 +00:00
parent 2864c0235b
commit 448e3a476f
5 changed files with 152 additions and 99 deletions

View file

@ -105,7 +105,7 @@ namespace OpenTK.OpenGL
#endregion #endregion
#region --- Methods --- #region --- Public Methods ---
#region public static bool SupportsExtension(string name) #region public static bool SupportsExtension(string name)
@ -193,43 +193,11 @@ namespace OpenTK.OpenGL
/// </remarks> /// </remarks>
public static void LoadAll() public static void LoadAll()
{ {
// Using reflection is more than 3 times faster than directly loading delegates on the first //TODO: Route GameWindow context creation through GLContext.
// run, probably due to code generation overhead. Subsequent runs are faster with direct loading //if (GLContext.CurrentContext == null)
// than with reflection, but the first time is more significant. // throw new InvalidOperationException("You must create an OpenGL context before using the GL class.");
int supported = 0; OpenTK.Platform.Utilities.LoadExtensions(glClass);
if (delegates == null)
{
delegates = delegatesClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
}
Trace.Write("GL.LoadAll(): ");
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);
}
time.Stop();
Trace.WriteLine(String.Format("{0} OpenGL extensions loaded in {1} milliseconds.", supported, time.ElapsedMilliseconds));
time.Reset();
rebuildExtensionList = true;
}
static void set(object d, Delegate value)
{
d = value;
} }
#endregion #endregion

View file

@ -25,20 +25,20 @@ namespace OpenTK.OpenGL
private static Dictionary<string, bool> AvailableExtensions = new Dictionary<string, bool>(); private static Dictionary<string, bool> AvailableExtensions = new Dictionary<string, bool>();
private static bool rebuildExtensionList = true; private static bool rebuildExtensionList = true;
private static Assembly assembly; //private static Assembly assembly;
private static Type glClass; //private static Type glClass;
private static Type delegatesClass; //private static Type delegatesClass;
private static Type importsClass; private static Type importsClass = typeof(Imports);
static Glu() static Glu()
{ {
assembly = Assembly.GetExecutingAssembly();//Assembly.Load("OpenTK.OpenGL"); //assembly = Assembly.GetExecutingAssembly();//Assembly.Load("OpenTK.OpenGL");
glClass = assembly.GetType("OpenTK.OpenGL.Glu"); //glClass = assembly.GetType("OpenTK.OpenGL.Glu");
delegatesClass = glClass.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic); //delegatesClass = glClass.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic);
importsClass = glClass.GetNestedType("Imports", BindingFlags.Static | BindingFlags.NonPublic); //importsClass = glClass.GetNestedType("Imports", BindingFlags.Static | BindingFlags.NonPublic);
} }
#region private static Delegate GetDelegate(string name, Type signature) #region private static Delegate LoadDelegate(string name, Type signature)
/// <summary> /// <summary>
/// Creates a System.Delegate that can be used to call a GLU function, core or extension. /// Creates a System.Delegate that can be used to call a GLU function, core or extension.
@ -49,7 +49,7 @@ namespace OpenTK.OpenGL
/// A System.Delegate that can be used to call this GLU function, or null if the specified /// A System.Delegate that can be used to call this GLU function, or null if the specified
/// function name did not correspond to an GLU function. /// function name did not correspond to an GLU function.
/// </returns> /// </returns>
private static Delegate GetDelegate(string name, Type signature) private static Delegate LoadDelegate(string name, Type signature)
{ {
MethodInfo m = importsClass.GetMethod(name.Substring(3), BindingFlags.Static | BindingFlags.NonPublic); MethodInfo m = importsClass.GetMethod(name.Substring(3), BindingFlags.Static | BindingFlags.NonPublic);
return return
@ -72,14 +72,7 @@ namespace OpenTK.OpenGL
/// </remarks> /// </remarks>
public static void LoadAll() public static void LoadAll()
{ {
FieldInfo[] v = delegatesClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic); OpenTK.Platform.Utilities.LoadExtensions(typeof(Glu));
foreach (FieldInfo f in v)
{
f.SetValue(null, GetDelegate(f.Name, f.FieldType));
}
AvailableExtensions.Clear();
rebuildExtensionList = true;
} }
#endregion #endregion
@ -107,14 +100,7 @@ namespace OpenTK.OpenGL
/// </remarks> /// </remarks>
public static bool Load(string function) public static bool Load(string function)
{ {
FieldInfo f = delegatesClass.GetField(function); return OpenTK.Platform.Utilities.TryLoadExtension(typeof(Glu), function);
if (f == null)
return false;
f.SetValue(null, GetDelegate(f.Name, f.FieldType));
rebuildExtensionList = true;
return f.GetValue(null) != null;
} }
#endregion #endregion

View file

@ -117,7 +117,7 @@ namespace OpenTK.Platform
/// A pointer to the specified function or IntPtr.Zero if the function isn't /// A pointer to the specified function or IntPtr.Zero if the function isn't
/// available in the current opengl context. /// available in the current opengl context.
/// </returns> /// </returns>
/// <see cref="Marshal.GetDelegateForFunctionPointer"/> // /// <see cref="Marshal.GetDelegateForFunctionPointer"/>
IntPtr GetAddress(string function); IntPtr GetAddress(string function);
} }
} }

View file

@ -11,6 +11,8 @@ using System.Collections.Generic;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
#endregion #endregion
@ -21,6 +23,8 @@ namespace OpenTK.Platform
/// </summary> /// </summary>
public static class Utilities public static class Utilities
{ {
#region internal static bool ThrowOnX11Error
static bool throw_on_error; static bool throw_on_error;
internal static bool ThrowOnX11Error internal static bool ThrowOnX11Error
{ {
@ -46,6 +50,127 @@ namespace OpenTK.Platform
} }
} }
#endregion
#region internal static void LoadExtensions(Type type)
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);
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);
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);
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);
if (rebuildExtensionList != null)
rebuildExtensionList.SetValue(null, true);
time.Stop();
Debug.Print("{0} extensions loaded in {1} ms.", supported, time.ElapsedMilliseconds);
time.Reset();
}
#endregion
#region internal static void LoadExtension()
/// <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);
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));
if (LoadDelegate == null)
{
Debug.Print(type.ToString(), " does not contain a static LoadDelegate method.");
return false;
}
FieldInfo f = type.GetField(extension, BindingFlags.Static | BindingFlags.NonPublic);
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.Target != @new.Target)
{
f.SetValue(null, @new);
FieldInfo rebuildExtensionList = type.GetField("rebuildExtensionList", BindingFlags.Static | BindingFlags.NonPublic);
if (rebuildExtensionList != null)
rebuildExtensionList.SetValue(null, true);
}
return @new != null;
}
#endregion
#region public bool IsIdle #region public bool IsIdle
interface IIsIdle { bool IsIdle { get; } } interface IIsIdle { bool IsIdle { get; } }

View file

@ -41,12 +41,11 @@ namespace OpenTK.Platform.Windows
private static Type delegatesClass; private static Type delegatesClass;
private static Type importsClass; private static Type importsClass;
private static bool reload_ext_extension_strings = true; private static bool rebuildExtensionList = true;
private static bool reload_arb_extension_strings = true;
#endregion #endregion
#region public static Delegate GetDelegate(string name, Type signature) #region static Delegate LoadDelegate(string name, Type signature)
/// <summary> /// <summary>
/// Creates a System.Delegate that can be used to call an OpenGL function, core or extension. /// Creates a System.Delegate that can be used to call an OpenGL function, core or extension.
@ -57,21 +56,17 @@ namespace OpenTK.Platform.Windows
/// A System.Delegate that can be used to call this OpenGL function, or null if the specified /// A System.Delegate that can be used to call this OpenGL function, or null if the specified
/// function name did not correspond to an OpenGL function. /// function name did not correspond to an OpenGL function.
/// </returns> /// </returns>
public static Delegate GetDelegate(string name, Type signature) static Delegate LoadDelegate(string name, Type signature)
{ {
Delegate d; Delegate d;
string realName = name.StartsWith("wgl") ? name.Substring(3) : name; string realName = name.StartsWith("wgl") ? name.Substring(3) : name;
if (importsClass.GetMethod(realName, if (importsClass.GetMethod(realName,
BindingFlags.NonPublic | BindingFlags.Static) != null) BindingFlags.NonPublic | BindingFlags.Static) != null)
{
d = GetExtensionDelegate(name, signature) ?? d = GetExtensionDelegate(name, signature) ??
Delegate.CreateDelegate(signature, typeof(Imports), realName); Delegate.CreateDelegate(signature, typeof(Imports), realName);
}
else else
{
d = GetExtensionDelegate(name, signature); d = GetExtensionDelegate(name, signature);
}
return d; return d;
} }
@ -114,13 +109,7 @@ namespace OpenTK.Platform.Windows
/// </summary> /// </summary>
public static void LoadAll() public static void LoadAll()
{ {
FieldInfo[] v = delegatesClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic); OpenTK.Platform.Utilities.LoadExtensions(typeof(Wgl));
foreach (FieldInfo f in v)
{
f.SetValue(null, GetDelegate(f.Name, f.FieldType));
}
reload_ext_extension_strings = true;
reload_arb_extension_strings = true;
} }
#endregion #endregion
@ -134,22 +123,7 @@ namespace OpenTK.Platform.Windows
/// <returns></returns> /// <returns></returns>
public static bool Load(string function) public static bool Load(string function)
{ {
FieldInfo f = delegatesClass.GetField(function, BindingFlags.Static | BindingFlags.NonPublic); return OpenTK.Platform.Utilities.TryLoadExtension(typeof(Wgl), function);
if (f == null)
return false;
Delegate old = f.GetValue(null) as Delegate;
Delegate @new = GetDelegate(f.Name, f.FieldType);
if (old.Target != @new.Target)
{
f.SetValue(null, @new);
if (function.EndsWith("EXT"))
reload_ext_extension_strings = true;
else if (function.EndsWith("ARB"))
reload_arb_extension_strings = true;
}
return @new != null;
} }
#endregion #endregion
@ -200,11 +174,11 @@ namespace OpenTK.Platform.Windows
{ {
if (Wgl.Delegates.wglGetExtensionsStringARB != null) if (Wgl.Delegates.wglGetExtensionsStringARB != null)
{ {
if (extensions == null || reload_arb_extension_strings) if (extensions == null || rebuildExtensionList)
{ {
extensions = Wgl.Arb.GetExtensionsString(deviceContext).Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); extensions = Wgl.Arb.GetExtensionsString(deviceContext).Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
Array.Sort(extensions); Array.Sort(extensions);
reload_arb_extension_strings = false; rebuildExtensionList = false;
} }
return Array.BinarySearch(extensions, ext) != -1; return Array.BinarySearch(extensions, ext) != -1;
@ -227,11 +201,11 @@ namespace OpenTK.Platform.Windows
{ {
if (Wgl.Delegates.wglGetExtensionsStringEXT != null) if (Wgl.Delegates.wglGetExtensionsStringEXT != null)
{ {
if (extensions == null || reload_ext_extension_strings) if (extensions == null || rebuildExtensionList)
{ {
extensions = Wgl.Ext.GetExtensionsString().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); extensions = Wgl.Ext.GetExtensionsString().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
Array.Sort(extensions); Array.Sort(extensions);
reload_ext_extension_strings = false; rebuildExtensionList = false;
} }
return Array.BinarySearch(extensions, ext) != -1; return Array.BinarySearch(extensions, ext) != -1;