#region License
//
// The Open Toolkit Library License
//
// Copyright (c) 2006 - 2009 the Open Toolkit library.
//
// 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.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace OpenTK.Graphics
{
///
/// Provides a common foundation for all flat API classes.
///
public abstract class BindingsBase
{
#region Fields
///
/// A reflection handle to the nested type that contains the function delegates.
///
readonly protected Type DelegatesClass;
///
/// A refection handle to the nested type that contains core functions (i.e. not extensions).
///
readonly protected Type CoreClass;
///
/// A mapping of core function names to MethodInfo handles.
///
readonly protected SortedList CoreFunctionMap = new SortedList();
bool rebuildExtensionList = true;
#endregion
#region Constructors
///
/// Constructs a new BindingsBase instance.
///
public BindingsBase()
{
DelegatesClass = this.GetType().GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic);
CoreClass = this.GetType().GetNestedType("Core", BindingFlags.Static | BindingFlags.NonPublic);
MethodInfo[] methods = CoreClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
CoreFunctionMap = new SortedList(methods.Length);
foreach (MethodInfo m in methods)
{
CoreFunctionMap.Add(m.Name, m);
}
}
#endregion
#region Protected Members
///
/// Gets or sets a that indicates whether the list of supported extensions may have changed.
///
protected bool RebuildExtensionList
{
get { return rebuildExtensionList; }
set { rebuildExtensionList = value; }
}
#endregion
#region Internal Members
#region LoadAll
internal 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.
int supported = 0;
FieldInfo[] delegates = DelegatesClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (delegates == null)
throw new InvalidOperationException("The specified type does not have any loadable extensions.");
Debug.Write("Load extensions for " + this.GetType().FullName + "... ");
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);
}
rebuildExtensionList = true;
time.Stop();
Debug.Print("{0} extensions loaded in {1} ms.", supported, time.ElapsedMilliseconds);
time.Reset();
}
#endregion
#region Load
///
/// Loads all extension and core functions.
///
internal 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 = LoadDelegate(f.Name, f.FieldType);
if (old.Target != @new.Target)
{
f.SetValue(null, @new);
}
return @new != null;
}
#endregion
#endregion
#region Private Members
#region LoadDelegate
///
/// Tries to load the specified core or extension function.
///
/// The name of the function (i.e. glShaderSource)
/// True if the function was found and reloaded, false otherwise.
///
///
/// Use this function if you require greater granularity when loading entry points.
///
///
Delegate LoadDelegate(string name, Type signature)
{
MethodInfo m;
return
GetExtensionDelegate(name, signature) ??
(CoreFunctionMap.TryGetValue((name.Substring(2)), out m) ?
Delegate.CreateDelegate(signature, m) : null);
}
#endregion
#region GetExtensionDelegate
// Creates a System.Delegate that can be used to call a dynamically exported OpenGL function.
internal static Delegate GetExtensionDelegate(string name, Type signature)
{
IntPtr address = (GraphicsContext.CurrentContext as IGraphicsContextInternal).GetAddress(name);
if (address == IntPtr.Zero ||
address == new IntPtr(1) || // Workaround for buggy nvidia drivers which return
address == new IntPtr(2)) // 1 or 2 instead of IntPtr.Zero for some extensions.
{
return null;
}
else
{
return Marshal.GetDelegateForFunctionPointer(address, signature);
}
}
#endregion
#endregion
}
}