Subversion Repositories AndroidProjects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1452 chris 1
#region License
2
//
3
// The Open Toolkit Library License
4
//
5
// Copyright (c) 2006 - 2009 the Open Toolkit library.
6
//
7
// Permission is hereby granted, free of charge, to any person obtaining a copy
8
// of this software and associated documentation files (the "Software"), to deal
9
// in the Software without restriction, including without limitation the rights to 
10
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11
// the Software, and to permit persons to whom the Software is furnished to do
12
// so, subject to the following conditions:
13
//
14
// The above copyright notice and this permission notice shall be included in all
15
// copies or substantial portions of the Software.
16
//
17
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
// OTHER DEALINGS IN THE SOFTWARE.
25
//
26
#endregion
27
 
28
using System;
29
using System.Collections.Generic;
30
using System.Text;
31
using System.Reflection;
32
using System.Runtime.InteropServices;
33
using System.Diagnostics;
34
 
35
namespace OpenTK
36
{
37
    /// <summary>
38
    /// Provides a common foundation for all flat API bindings and implements the extension loading interface.
39
    /// </summary>
40
    public abstract class BindingsBase
41
    {
42
        #region Fields
43
 
44
        /// <summary>
45
        /// A reflection handle to the nested type that contains the function delegates.
46
        /// </summary>
47
        readonly protected Type DelegatesClass;
48
 
49
        /// <summary>
50
        /// A refection handle to the nested type that contains core functions (i.e. not extensions).
51
        /// </summary>
52
        readonly protected Type CoreClass;
53
 
54
        /// <summary>
55
        /// A mapping of core function names to MethodInfo handles.
56
        /// </summary>
57
        readonly protected SortedList<string, MethodInfo> CoreFunctionMap = new SortedList<string, MethodInfo>();
58
 
59
        bool rebuildExtensionList = true;
60
 
61
        #endregion
62
 
63
        #region Constructors
64
 
65
        /// <summary>
66
        /// Constructs a new BindingsBase instance.
67
        /// </summary>
68
        public BindingsBase()
69
        {
70
            DelegatesClass = this.GetType().GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic);
71
            CoreClass = this.GetType().GetNestedType("Core", BindingFlags.Static | BindingFlags.NonPublic);
72
 
73
            if (CoreClass != null)
74
            {
75
                MethodInfo[] methods = CoreClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
76
                CoreFunctionMap = new SortedList<string, MethodInfo>(methods.Length); // Avoid resizing
77
                foreach (MethodInfo m in methods)
78
                {
79
                    CoreFunctionMap.Add(m.Name, m);
80
                }
81
            }
82
        }
83
 
84
        #endregion
85
 
86
        #region Protected Members
87
 
88
        /// <summary>
89
        /// Gets or sets a <see cref="System.Boolean"/> that indicates whether the list of supported extensions may have changed.
90
        /// </summary>
91
        protected bool RebuildExtensionList
92
        {
93
            get { return rebuildExtensionList; }
94
            set { rebuildExtensionList = value; }
95
        }
96
 
97
        /// <summary>
98
        /// Retrieves an unmanaged function pointer to the specified function.
99
        /// </summary>
100
        /// <param name="funcname">
101
        /// A <see cref="System.String"/> that defines the name of the function.
102
        /// </param>
103
        /// <returns>
104
        /// A <see cref="IntPtr"/> that contains the address of funcname or IntPtr.Zero,
105
        /// if the function is not supported by the drivers.
106
        /// </returns>
107
        /// <remarks>
108
        /// Note: some drivers are known to return non-zero values for unsupported functions.
109
        /// Typical values include 1 and 2 - inheritors are advised to check for and ignore these
110
        /// values.
111
        /// </remarks>
112
        protected abstract IntPtr GetAddress(string funcname);
113
 
114
        /// <summary>
115
        /// Gets an object that can be used to synchronize access to the bindings implementation.
116
        /// </summary>
117
        /// <remarks>This object should be unique across bindings but consistent between bindings
118
        /// of the same type. For example, ES10.GL, OpenGL.GL and CL10.CL should all return 
119
        /// unique objects, but all instances of ES10.GL should return the same object.</remarks>
120
        protected abstract object SyncRoot { get; }
121
 
122
        #endregion
123
 
124
        #region Internal Members
125
 
126
        #region LoadEntryPoints
127
 
128
        internal void LoadEntryPoints()
129
        {
130
            // Using reflection is more than 3 times faster than directly loading delegates on the first
131
            // run, probably due to code generation overhead. Subsequent runs are faster with direct loading
132
            // than with reflection, but the first time is more significant.
133
 
134
            int supported = 0;
135
 
136
            FieldInfo[] delegates = DelegatesClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
137
            if (delegates == null)
138
                throw new InvalidOperationException("The specified type does not have any loadable extensions.");
139
 
140
            Debug.Write("Loading extensions for " + this.GetType().FullName + "... ");
141
 
142
            Stopwatch time = new Stopwatch();
143
            time.Reset();
144
            time.Start();
145
 
146
            foreach (FieldInfo f in delegates)
147
            {
148
                Delegate d = LoadDelegate(f.Name, f.FieldType);
149
                if (d != null)
150
                    ++supported;
151
 
152
                lock (SyncRoot)
153
                {
154
                    f.SetValue(null, d);
155
                }
156
            }
157
 
158
            rebuildExtensionList = true;
159
 
160
            time.Stop();
161
            Debug.Print("{0} extensions loaded in {1} ms.", supported, time.Elapsed.TotalMilliseconds);
162
            time.Reset();
163
        }
164
 
165
        #endregion
166
 
167
        #region LoadEntryPoint
168
 
169
        internal bool LoadEntryPoint(string function)
170
        {
171
            FieldInfo f = DelegatesClass.GetField(function, BindingFlags.Static | BindingFlags.NonPublic);
172
            if (f == null)
173
                return false;
174
 
175
            Delegate old = f.GetValue(null) as Delegate;
176
            Delegate @new = LoadDelegate(f.Name, f.FieldType);
177
            lock (SyncRoot)
178
            {
179
                if (old.Target != @new.Target)
180
                {
181
                    f.SetValue(null, @new);
182
                }
183
            }
184
            return @new != null;
185
        }
186
 
187
        #endregion
188
 
189
        #endregion
190
 
191
        #region Private Members
192
 
193
        #region LoadDelegate
194
 
195
        // Tries to load the specified core or extension function.
196
        Delegate LoadDelegate(string name, Type signature)
197
        {
198
            MethodInfo m;
199
            return
200
                GetExtensionDelegate(name, signature) ??
201
                (CoreFunctionMap.TryGetValue((name.Substring(2)), out m) ?
202
                Delegate.CreateDelegate(signature, m) : null);
203
        }
204
 
205
        #endregion
206
 
207
        #region GetExtensionDelegate
208
 
209
        // Creates a System.Delegate that can be used to call a dynamically exported OpenGL function.
210
        internal Delegate GetExtensionDelegate(string name, Type signature)
211
        {
212
            IntPtr address = GetAddress(name);
213
 
214
            if (address == IntPtr.Zero ||
215
                address == new IntPtr(1) ||     // Workaround for buggy nvidia drivers which return
216
                address == new IntPtr(2))       // 1 or 2 instead of IntPtr.Zero for some extensions.
217
            {
218
                return null;
219
            }
220
            else
221
            {
222
                return Marshal.GetDelegateForFunctionPointer(address, signature);
223
            }
224
        }
225
 
226
        #endregion
227
 
228
        #endregion
229
    }
230
}