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 394cc1f769
commit 5598019f01
5 changed files with 152 additions and 99 deletions

View file

@ -105,7 +105,7 @@ namespace OpenTK.OpenGL
#endregion
#region --- Methods ---
#region --- Public Methods ---
#region public static bool SupportsExtension(string name)
@ -193,43 +193,11 @@ namespace OpenTK.OpenGL
/// </remarks>
public static void LoadAll()
{
// 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.
//TODO: Route GameWindow context creation through GLContext.
//if (GLContext.CurrentContext == null)
// throw new InvalidOperationException("You must create an OpenGL context before using the GL class.");
int supported = 0;
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;
OpenTK.Platform.Utilities.LoadExtensions(glClass);
}
#endregion

View file

@ -25,20 +25,20 @@ namespace OpenTK.OpenGL
private static Dictionary<string, bool> AvailableExtensions = new Dictionary<string, bool>();
private static bool rebuildExtensionList = true;
private static Assembly assembly;
private static Type glClass;
private static Type delegatesClass;
private static Type importsClass;
//private static Assembly assembly;
//private static Type glClass;
//private static Type delegatesClass;
private static Type importsClass = typeof(Imports);
static Glu()
{
assembly = Assembly.GetExecutingAssembly();//Assembly.Load("OpenTK.OpenGL");
glClass = assembly.GetType("OpenTK.OpenGL.Glu");
delegatesClass = glClass.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic);
importsClass = glClass.GetNestedType("Imports", BindingFlags.Static | BindingFlags.NonPublic);
//assembly = Assembly.GetExecutingAssembly();//Assembly.Load("OpenTK.OpenGL");
//glClass = assembly.GetType("OpenTK.OpenGL.Glu");
//delegatesClass = glClass.GetNestedType("Delegates", 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>
/// 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
/// function name did not correspond to an GLU function.
/// </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);
return
@ -72,14 +72,7 @@ namespace OpenTK.OpenGL
/// </remarks>
public static void LoadAll()
{
FieldInfo[] v = delegatesClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
foreach (FieldInfo f in v)
{
f.SetValue(null, GetDelegate(f.Name, f.FieldType));
}
AvailableExtensions.Clear();
rebuildExtensionList = true;
OpenTK.Platform.Utilities.LoadExtensions(typeof(Glu));
}
#endregion
@ -107,14 +100,7 @@ namespace OpenTK.OpenGL
/// </remarks>
public static bool Load(string function)
{
FieldInfo f = delegatesClass.GetField(function);
if (f == null)
return false;
f.SetValue(null, GetDelegate(f.Name, f.FieldType));
rebuildExtensionList = true;
return f.GetValue(null) != null;
return OpenTK.Platform.Utilities.TryLoadExtension(typeof(Glu), function);
}
#endregion

View file

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

View file

@ -11,6 +11,8 @@ using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
#endregion
@ -21,6 +23,8 @@ namespace OpenTK.Platform
/// </summary>
public static class Utilities
{
#region internal static bool ThrowOnX11Error
static bool throw_on_error;
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
interface IIsIdle { bool IsIdle { get; } }

View file

@ -41,12 +41,11 @@ namespace OpenTK.Platform.Windows
private static Type delegatesClass;
private static Type importsClass;
private static bool reload_ext_extension_strings = true;
private static bool reload_arb_extension_strings = true;
private static bool rebuildExtensionList = true;
#endregion
#region public static Delegate GetDelegate(string name, Type signature)
#region static Delegate LoadDelegate(string name, Type signature)
/// <summary>
/// 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
/// function name did not correspond to an OpenGL function.
/// </returns>
public static Delegate GetDelegate(string name, Type signature)
static Delegate LoadDelegate(string name, Type signature)
{
Delegate d;
string realName = name.StartsWith("wgl") ? name.Substring(3) : name;
if (importsClass.GetMethod(realName,
BindingFlags.NonPublic | BindingFlags.Static) != null)
{
d = GetExtensionDelegate(name, signature) ??
Delegate.CreateDelegate(signature, typeof(Imports), realName);
}
else
{
d = GetExtensionDelegate(name, signature);
}
return d;
}
@ -114,13 +109,7 @@ namespace OpenTK.Platform.Windows
/// </summary>
public static void LoadAll()
{
FieldInfo[] v = delegatesClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
foreach (FieldInfo f in v)
{
f.SetValue(null, GetDelegate(f.Name, f.FieldType));
}
reload_ext_extension_strings = true;
reload_arb_extension_strings = true;
OpenTK.Platform.Utilities.LoadExtensions(typeof(Wgl));
}
#endregion
@ -134,22 +123,7 @@ namespace OpenTK.Platform.Windows
/// <returns></returns>
public static bool Load(string function)
{
FieldInfo f = delegatesClass.GetField(function, BindingFlags.Static | BindingFlags.NonPublic);
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;
return OpenTK.Platform.Utilities.TryLoadExtension(typeof(Wgl), function);
}
#endregion
@ -200,11 +174,11 @@ namespace OpenTK.Platform.Windows
{
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);
Array.Sort(extensions);
reload_arb_extension_strings = false;
rebuildExtensionList = false;
}
return Array.BinarySearch(extensions, ext) != -1;
@ -227,11 +201,11 @@ namespace OpenTK.Platform.Windows
{
if (Wgl.Delegates.wglGetExtensionsStringEXT != null)
{
if (extensions == null || reload_ext_extension_strings)
if (extensions == null || rebuildExtensionList)
{
extensions = Wgl.Ext.GetExtensionsString().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
Array.Sort(extensions);
reload_ext_extension_strings = false;
rebuildExtensionList = false;
}
return Array.BinarySearch(extensions, ext) != -1;