Пример #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OpenTK.Graphics.GraphicsContext"/> class using
        /// an external context handle that was created by a third-party library.
        /// </summary>
        /// <param name="handle">
        /// A valid, unique handle for an external OpenGL context, or <c>ContextHandle.Zero</c> to use the current context.
        /// It is an error to specify a handle that has been created through OpenTK or that has been passed to OpenTK before.
        /// </param>
        /// <param name="getAddress">
        /// A <c>GetAddressDelegate</c> instance that accepts the name of an OpenGL function and returns
        /// a valid function pointer, or <c>IntPtr.Zero</c> if that function is not supported. This delegate should be
        /// implemented using the same toolkit that created the OpenGL context (i.e. if the context was created with
        /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetProcAddress() to retrieve function
        /// pointers.)
        /// </param>
        /// <param name="getCurrent">
        /// A <c>GetCurrentContextDelegate</c> instance that returns the handle of the current OpenGL context,
        /// or <c>IntPtr.Zero</c> if no context is current on the calling thread. This delegate should be implemented
        /// using the same toolkit that created the OpenGL context (i.e. if the context was created with
        /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetCurrentContext() to retrieve
        /// the current context.)
        /// </param>
        public GraphicsContext(ContextHandle handle, GetAddressDelegate getAddress, GetCurrentContextDelegate getCurrent)
        {
            if (getAddress == null || getCurrent == null)
            {
                throw new ArgumentNullException();
            }

            lock (SyncRoot)
            {
                // Replace a zero-handle by the current context, if any
                if (handle == ContextHandle.Zero)
                {
                    handle = getCurrent();
                }

                // Make sure this handle corresponds to a valid, unique OpenGL context
                if (handle == ContextHandle.Zero)
                {
                    throw new GraphicsContextMissingException();
                }
                else if (available_contexts.ContainsKey(handle))
                {
                    throw new InvalidOperationException("Context handle has already been added");
                }

                // We have a valid handle for an external OpenGL context, wrap it into a
                // DummyGLContext instance.
                implementation    = new Platform.Dummy.DummyGLContext(handle, getAddress);
                GetCurrentContext = getCurrent ?? GetCurrentContext;
                AddContext(this);
            }
            implementation.LoadAll();
        }
Пример #2
0
        public void GetAddressAsync(string name)
        {
            GetAddressDelegate dc = new GetAddressDelegate(this.GetAddress);

            AsyncCallback cb = new AsyncCallback(this.GetResultsOnCallback);
            IAsyncResult  ar = dc.BeginInvoke(name, cb, null);
        }
Пример #3
0
        /// <summary>
        /// Link delegates field using import declaration, using platform specific method for determining procedures address.
        /// </summary>
        internal static void BindAPIFunction <T>(string path, string functionName, GetAddressDelegate getProcAddress, KhronosVersion version, ExtensionsCollection extensions)
        {
            FunctionContext functionContext = GetFunctionContext(typeof(T));

            Debug.Assert(functionContext != null);

            BindAPIFunction(path, getProcAddress, functionContext.GetFunction(functionName), version, extensions);
        }
Пример #4
0
        /// <summary>
        /// Link delegates field using import declaration, using platform specific method for determining procedures address.
        /// </summary>
        internal static void BindAPIFunction <T>(string path, string functionName, GetAddressDelegate getProcAddress, KhronosVersion version, ExtensionsCollection extensions)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            if (functionName == null)
            {
                throw new ArgumentNullException("function");
            }
            if (getProcAddress == null)
            {
                throw new ArgumentNullException("getAddress");
            }

            FunctionContext functionContext = GetFunctionContext(typeof(T));

            Debug.Assert(functionContext != null);
            if (functionContext == null)
            {
                throw new InvalidOperationException("unrecognized API type");
            }

#if NETSTANDARD1_1 || NETSTANDARD1_4
            TypeInfo delegatesClass = typeof(T).GetTypeInfo().GetDeclaredNestedType("Delegates");
            Debug.Assert(delegatesClass != null);
            if (delegatesClass == null)
            {
                throw new NotImplementedException("missing Delegates class");
            }

            FieldInfo functionField = delegatesClass.GetDeclaredField("p" + functionName);
            Debug.Assert(functionField != null);
            if (functionField == null)
            {
                throw new NotImplementedException(String.Format("unable to find function named {0}", functionName));
            }
#else
            Type delegatesClass = typeof(T).GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic);
            Debug.Assert(delegatesClass != null);
            if (delegatesClass == null)
            {
                throw new NotImplementedException("missing Delegates class");
            }

            FieldInfo functionField = delegatesClass.GetField("p" + functionName, BindingFlags.Static | BindingFlags.NonPublic);
            Debug.Assert(functionField != null);
            if (functionField == null)
            {
                throw new NotImplementedException(String.Format("unable to find function named {0}", functionName));
            }
#endif

            BindAPIFunction(path, getProcAddress, functionContext, functionField, version, extensions);
        }
Пример #5
0
        static UnsafeObject()
        {
            var getAddressMethod = CreateDynamicMethod <object, IntPtr>(nameof(GetAddressFromIL));
            var getObjectMethod  = CreateDynamicMethod <IntPtr, object>(nameof(GetObjectFromIL));

            BuildIL(getAddressMethod);
            BuildIL(getObjectMethod);

            _getAddress = getAddressMethod.CreateDelegate(typeof(GetAddressDelegate)) as GetAddressDelegate;
            _getObject  = getObjectMethod.CreateDelegate(typeof(GetObjectDelegate)) as GetObjectDelegate;
        }
Пример #6
0
 public void GetAddressSync(string name)
 {
     try
     {
         GetAddressDelegate dc     = new GetAddressDelegate(this.GetAddress);
         string             result = dc(name);
         Console.WriteLine("\nSync: " + result);
     }
     catch (Exception ex)
     {
         Console.WriteLine("\nSync: a problem occurred: " + ex.Message);
     }
 }
Пример #7
0
        /// <summary>
        /// Link delegates fields using import declarations.
        /// </summary>
        /// <param name="path">
        /// A <see cref="System.String"/> that specifies the assembly file path containing the import functions.
        /// </param>
        /// <param name="type">
        /// A <see cref="System.Type"/> that specifies the type used for detecting import declarations and delegates fields.
        /// </param>
        /// <param name="getAddress">
        /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform.
        /// </param>
        /// <param name="sImportMap">
        /// A <see cref="T:SortedList{String, MethodIndo}"/> mapping a <see cref="MethodInfo"/> with the relative function name.
        /// </param>
        /// <param name="sDelegates">
        /// A <see cref="T:List{FieldInfo}"/> listing <see cref="FieldInfo"/> related to function delegates.
        /// </param>
        /// <remarks>
        /// <para>
        /// The type <paramref name="type"/> shall have defined a nested class named "UnsafeNativeMethods" specifying the import declarations and a nested
        /// class named "Delagates" specifying the delegate fields.
        /// </para>
        /// </remarks>
        private static void LinkProcAddressImports(string path, Type type, GetAddressDelegate getAddress, out SortedList <string, MethodInfo> sImportMap, out List <FieldInfo> sDelegates)
        {
            Type impClass = type.GetNestedType("UnsafeNativeMethods", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);

            Debug.Assert(impClass != null);

            Type delClass = type.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic);

            Debug.Assert(delClass != null);

            // Query imports declarations
            MethodInfo[] iMethods = impClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);

            sImportMap = new SortedList <string, MethodInfo>(iMethods.Length);
            foreach (MethodInfo m in iMethods)
            {
                sImportMap.Add(m.Name, m);
            }

            // Query delegates declarations
            sDelegates = new List <FieldInfo>(delClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic));

            foreach (FieldInfo fi in sDelegates)
            {
                Delegate pDelegate   = null;
                string   pImportName = fi.Name.Substring(1);
                IntPtr   mAddr       = getAddress(path, pImportName);

                if (mAddr != IntPtr.Zero)
                {
                    // Try to load external symbol
                    if ((pDelegate = Marshal.GetDelegateForFunctionPointer(mAddr, fi.FieldType)) == null)
                    {
                        MethodInfo mInfo;

                        if (sImportMap.TryGetValue(pImportName, out mInfo) == true)
                        {
                            pDelegate = Delegate.CreateDelegate(fi.FieldType, mInfo);
                        }
                    }

                    if (pDelegate != null)
                    {
                        fi.SetValue(null, pDelegate);
                    }
                }
            }
        }
Пример #8
0
        public void GetResultsOnCallback(IAsyncResult ar)
        {
            GetAddressDelegate del = (GetAddressDelegate)
                                     ((AsyncResult)ar).AsyncDelegate;

            try
            {
                string result;
                result = del.EndInvoke(ar);
                Console.WriteLine("\nOn CallBack: result is " + result);
            }
            catch (Exception ex)
            {
                Console.WriteLine("\nOn CallBack, problem occurred: " + ex.Message);
            }
        }
Пример #9
0
        public void GetAddressAsyncWait(string name)
        {
            GetAddressDelegate dc = new GetAddressDelegate(this.GetAddress);

            IAsyncResult ar = dc.BeginInvoke(name, null, null);

            // Main thread can in principle do other work now
            try
            {
                string result = dc.EndInvoke(ar);
                Console.WriteLine("\nAsync waiting : " + result);
            }
            catch (Exception ex)
            {
                Console.WriteLine("\nAsync waiting, a problem occurred : " +
                                  ex.Message);
            }
        }
Пример #10
0
        /// <summary>
        /// Link delegates fields using import declarations.
        /// </summary>
        /// <param name="path">
        /// A <see cref="string"/> that specifies the assembly file path containing the import functions.
        /// </param>
        /// <param name="getAddress">
        /// A <see cref="GetAddressDelegate"/> used for getting function pointers.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="path"/> or <paramref name="getAddress"/> is null.
        /// </exception>
        internal static void BindAPI <T>(string path, GetAddressDelegate getAddress, KhronosVersion version, ExtensionsCollection extensions)
        {
            if (path == null)
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (getAddress == null)
            {
                throw new ArgumentNullException(nameof(getAddress));
            }

            FunctionContext functionContext = GetFunctionContext(typeof(T));

            Debug.Assert(functionContext != null);

            foreach (FieldInfo fi in functionContext.Delegates)
            {
                BindAPIFunction(path, getAddress, fi, version, extensions);
            }
        }
Пример #11
0
        public void GetResultsOnCallback(IAsyncResult ar)
        {
            GetAddressDelegate del = (GetAddressDelegate)((AsyncResult)ar).AsyncDelegate;

            try
            {
                string result;
                result = del.EndInvoke(ar);
                lock (this)
                {
                    this.address = result;
                    this.status  = ResultStatus.Done;
                }
            }
            catch (Exception ex)
            {
                lock (this)
                {
                    this.address = ex.Message;
                    this.status  = ResultStatus.Failed;
                }
            }
        }
Пример #12
0
        /// <summary>
        /// Link delegates fields using import declarations.
        /// </summary>
        /// <param name="path">
        /// A <see cref="String"/> that specifies the assembly file path containing the import functions.
        /// </param>
        /// <param name="imports">
        /// A <see cref="ImportMap"/> mapping a <see cref="MethodInfo"/> with the relative function name.
        /// </param>
        /// <param name="delegates">
        /// A <see cref="DelegateList"/> listing <see cref="FieldInfo"/> related to function delegates.
        /// </param>
        /// <param name="getAddress">
        /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="path"/>, <paramref name="imports"/>, <paramref name="delegates"/> or <paramref name="getAddress"/> is null.
        /// </exception>
        private static void BindAPI <T>(string path, GetAddressDelegate getAddress)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            if (getAddress == null)
            {
                throw new ArgumentNullException("getAddress");
            }

            FunctionContext functionContext = GetFunctionContext(typeof(T));

            Debug.Assert(functionContext != null);
            if (functionContext == null)
            {
                throw new InvalidOperationException("unrecognized API type");
            }

            foreach (FieldInfo fi in functionContext.Delegates)
            {
                BindAPIFunction(path, functionContext, fi, getAddress);
            }
        }
Пример #13
0
		/// <summary>
		/// Link delegates fields using import declarations.
		/// </summary>
		/// <param name="path">
		/// A <see cref="System.String"/> that specifies the assembly file path containing the import functions.
		/// </param>
		/// <param name="type">
		/// A <see cref="System.Type"/> that specifies the type used for detecting import declarations and delegates fields.
		/// </param>
		/// <param name="getAddress">
		/// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform.
		/// </param>
		/// <param name="sImportMap">
		/// A <see cref="T:SortedList{String, MethodIndo}"/> mapping a <see cref="MethodInfo"/> with the relative function name.
		/// </param>
		/// <param name="sDelegates">
		/// A <see cref="T:List{FieldInfo}"/> listing <see cref="FieldInfo"/> related to function delegates.
		/// </param>
		/// <remarks>
		/// <para>
		/// The type <paramref name="type"/> shall have defined a nested class named "UnsafeNativeMethods" specifying the import declarations and a nested
		/// class named "Delagates" specifying the delegate fields.
		/// </para>
		/// </remarks>
		private static void LinkProcAddressImports(string path, Type type, GetAddressDelegate getAddress, out SortedList<string, MethodInfo> sImportMap, out List<FieldInfo> sDelegates)
		{
			Type impClass = type.GetNestedType("UnsafeNativeMethods", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
			Debug.Assert(impClass != null);

			Type delClass = type.GetNestedType("Delegates", BindingFlags.Static | BindingFlags.NonPublic);
			Debug.Assert(delClass != null);

			// Query imports declarations
			MethodInfo[] iMethods = impClass.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);

			sImportMap = new SortedList<string, MethodInfo>(iMethods.Length);
			foreach (MethodInfo m in iMethods)
				sImportMap.Add(m.Name, m);

			// Query delegates declarations
			sDelegates = new List<FieldInfo>(delClass.GetFields(BindingFlags.Static | BindingFlags.NonPublic));

			foreach (FieldInfo fi in sDelegates) {
				Delegate pDelegate = null;
				string pImportName = fi.Name.Substring(1);
				IntPtr mAddr = getAddress(path, pImportName);

				if (mAddr != IntPtr.Zero) {
					// Try to load external symbol
					if ((pDelegate = Marshal.GetDelegateForFunctionPointer(mAddr, fi.FieldType)) == null) {
						MethodInfo mInfo;

						if (sImportMap.TryGetValue(pImportName, out mInfo) == true)
							pDelegate = Delegate.CreateDelegate(fi.FieldType, mInfo);
					}

					if (pDelegate != null)
						fi.SetValue(null, pDelegate);
				}
			}
		}
Пример #14
0
        /// <summary>
        /// Link delegates fields using import declarations.
        /// </summary>
        /// <param name="path">
        /// A <see cref="String"/> that specifies the assembly file path containing the import functions.
        /// </param>
        /// <param name="imports">
        /// A <see cref="ImportMap"/> mapping a <see cref="MethodInfo"/> with the relative function name.
        /// </param>
        /// <param name="delegates">
        /// A <see cref="DelegateList"/> listing <see cref="FieldInfo"/> related to function delegates.
        /// </param>
        /// <param name="getAddress">
        /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="path"/>, <paramref name="imports"/>, <paramref name="delegates"/> or <paramref name="getAddress"/> is null.
        /// </exception>
        private static void LoadProcDelegates(string path, ImportMap imports, DelegateList delegates, GetAddressDelegate getAddress)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            if (imports == null)
            {
                throw new ArgumentNullException("importMap");
            }
            if (delegates == null)
            {
                throw new ArgumentNullException("delegates");
            }
            if (getAddress == null)
            {
                throw new ArgumentNullException("getAddress");
            }

            foreach (FieldInfo fi in delegates)
            {
                Attribute[] aliasOfAttributes = Attribute.GetCustomAttributes(fi, typeof(AliasOfAttribute));
                string      importName        = fi.Name.Substring(1);               // Delegate name always prefixes with 'p'
                IntPtr      importAddress     = IntPtr.Zero;

                if (aliasOfAttributes.Length > 0)
                {
                    for (int i = 0; i < aliasOfAttributes.Length; i++)
                    {
                        if ((importAddress = getAddress(path, ((AliasOfAttribute)aliasOfAttributes[i]).SymbolName)) != IntPtr.Zero)
                        {
                            break;
                        }
                    }
                }
                else
                {
                    importAddress = getAddress(path, importName);
                }

                // Is function implemented?
                if (importAddress == IntPtr.Zero)
                {
                    fi.SetValue(null, null);
                    continue;
                }

                Delegate delegatePtr;

                // Try to load external symbol
                if ((delegatePtr = Marshal.GetDelegateForFunctionPointer(importAddress, fi.FieldType)) == null)
                {
                    MethodInfo methodInfo;

                    if (imports.TryGetValue(importName, out methodInfo) == true)
                    {
                        delegatePtr = Delegate.CreateDelegate(fi.FieldType, methodInfo);
                    }
                }

                if (delegatePtr != null)
                {
                    fi.SetValue(null, delegatePtr);
                }
            }
        }
Пример #15
0
        /// <summary>
        /// Link delegates fields using import declarations.
        /// </summary>
        /// <param name="path">
        /// A <see cref="String"/> that specifies the assembly file path containing the import functions.
        /// </param>
        /// <param name="getAddress">
        /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform.
        /// </param>
        /// <param name="functionContext">
        /// A <see cref="FunctionContext"/> mapping a <see cref="MethodInfo"/> with the relative function name.
        /// </param>
        /// <param name="function">
        /// A <see cref="FieldInfo"/> that specifies the underlying function field to be updated.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="path"/>, <paramref name="function"/> or <paramref name="getAddress"/> is null.
        /// </exception>
        private static void BindAPIFunction(string path, GetAddressDelegate getAddress, FunctionContext functionContext, FieldInfo function, KhronosVersion version, ExtensionsCollection extensions)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            if (functionContext == null)
            {
                throw new ArgumentNullException("functionContext");
            }
            if (function == null)
            {
                throw new ArgumentNullException("function");
            }
            if (getAddress == null)
            {
                throw new ArgumentNullException("getAddress");
            }

            if (version != null || extensions != null)
            {
                if (IsCompatibleField(function, version, extensions) == false)
                {
                    function.SetValue(null, null);                                              // Function not supported: reset
                    return;
                }
            }

            string importName    = function.Name.Substring(1);                    // Delegate name always prefixes with 'p'
            IntPtr importAddress = IntPtr.Zero;

            // Load command address
            importAddress = getAddress(path, importName);

            // Manages aliases (load external symbol)
            if (importAddress == IntPtr.Zero)
            {
#if !NETCORE
                Attribute[] aliasOfAttributes = Attribute.GetCustomAttributes(function, typeof(AliasOfAttribute));
#else
                Attribute[] aliasOfAttributes = new List <Attribute>(function.GetCustomAttributes(typeof(AliasOfAttribute))).ToArray();
#endif

                for (int i = 1 /* Skip base name */; i < aliasOfAttributes.Length; i++)
                {
                    AliasOfAttribute aliasOfAttribute = (AliasOfAttribute)aliasOfAttributes[i];
                    if ((importAddress = getAddress(path, aliasOfAttribute.SymbolName)) != IntPtr.Zero)
                    {
                        break;
                    }
                }
            }

            if (importAddress != IntPtr.Zero)
            {
                Delegate delegatePtr;

                // Try to load external symbol
                if ((delegatePtr = Marshal.GetDelegateForFunctionPointer(importAddress, function.FieldType)) == null)
                {
                    MethodInfo methodInfo;

                    if (functionContext.Imports.TryGetValue(importName, out methodInfo) == true)
                    {
#if !NETCORE
                        delegatePtr = Delegate.CreateDelegate(function.FieldType, methodInfo);
#else
                        delegatePtr = methodInfo.CreateDelegate(function.FieldType);
#endif
                    }
                }

                if (delegatePtr != null)
                {
                    function.SetValue(null, delegatePtr);
                }
            }
            else
            {
                function.SetValue(null, null);                                          // Function not implemented: reset
            }
        }
Пример #16
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OpenTK.Graphics.GraphicsContext"/> class using
        /// an external context handle that was created by a third-party library.
        /// </summary>
        /// <param name="handle">
        /// A valid, unique handle for an external OpenGL context, or <c>ContextHandle.Zero</c> to use the current context.
        /// It is an error to specify a handle that has been created through OpenTK or that has been passed to OpenTK before.
        /// </param>
        /// <param name="getAddress">
        /// A <c>GetAddressDelegate</c> instance that accepts the name of an OpenGL function and returns
        /// a valid function pointer, or <c>IntPtr.Zero</c> if that function is not supported. This delegate should be
        /// implemented using the same toolkit that created the OpenGL context (i.e. if the context was created with
        /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetProcAddress() to retrieve function
        /// pointers.)
        /// </param>
        /// <param name="getCurrent">
        /// A <c>GetCurrentContextDelegate</c> instance that returns the handle of the current OpenGL context,
        /// or <c>IntPtr.Zero</c> if no context is current on the calling thread. This delegate should be implemented
        /// using the same toolkit that created the OpenGL context (i.e. if the context was created with
        /// SDL_GL_CreateContext(), then this delegate should use SDL_GL_GetCurrentContext() to retrieve
        /// the current context.)
        /// </param>
        public GraphicsContext(ContextHandle handle, GetAddressDelegate getAddress, GetCurrentContextDelegate getCurrent)
        {
            if (getAddress == null || getCurrent == null)
                throw new ArgumentNullException();

            // Make sure OpenTK has been initialized.
            // Fixes https://github.com/opentk/opentk/issues/52
            Toolkit.Init();

            lock (SyncRoot)
            {
                // Replace a zero-handle by the current context, if any
                if (handle == ContextHandle.Zero)
                {
                    handle = getCurrent();
                }

                // Make sure this handle corresponds to a valid, unique OpenGL context
                if (handle == ContextHandle.Zero)
                {
                    throw new GraphicsContextMissingException();
                }
                else if (available_contexts.ContainsKey(handle))
                {
                    throw new InvalidOperationException("Context handle has already been added");
                }

                // We have a valid handle for an external OpenGL context, wrap it into a
                // DummyGLContext instance.
                implementation = new Platform.Dummy.DummyGLContext(handle, getAddress);
                GetCurrentContext = getCurrent ?? GetCurrentContext;
                AddContext(this);
            }
            implementation.LoadAll();
        }
Пример #17
0
        /// <summary>
        /// Link delegates fields using import declarations.
        /// </summary>
        /// <param name="path">
        ///     A <see cref="string"/> that specifies the assembly file path containing the import functions.
        /// </param>
        /// <param name="getAddress">
        ///     A <see cref="GetAddressDelegate"/> used for getting function pointers.
        /// </param>
        /// <param name="function">
        ///     A <see cref="FieldInfo"/> that specifies the underlying function field to be updated.
        /// </param>
        /// <param name="version"></param>
        /// <param name="extensions"></param>
        private static void BindAPIFunction(string path, GetAddressDelegate getAddress, FieldInfo function, KhronosVersion version, ExtensionsCollection extensions)
        {
            Debug.Assert(path != null);
            Debug.Assert(getAddress != null);
            Debug.Assert(function != null);

            RequiredByFeatureAttribute        requiredByFeature    = null;
            List <RequiredByFeatureAttribute> requiredByExtensions = new List <RequiredByFeatureAttribute>();
            string defaultName = function.Name.Substring(1);                       // Delegate name always prefixes with 'p'

            if (version != null || extensions != null)
            {
                bool isRemoved = false;

                #region Check Requirement

#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
                IEnumerable <Attribute> attrRequired = new List <Attribute>(function.GetCustomAttributes(typeof(RequiredByFeatureAttribute)));
#else
                IEnumerable <Attribute> attrRequired = Attribute.GetCustomAttributes(function, typeof(RequiredByFeatureAttribute));
#endif
                // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
                foreach (RequiredByFeatureAttribute attr in attrRequired)
                {
                    // Check for API support
                    if (!attr.IsSupported(version, extensions))
                    {
                        continue;
                    }
                    // Keep track of the features requiring this command
                    if (attr.FeatureVersion != null)
                    {
                        // Version feature: keep track only of the maximum version
                        if (requiredByFeature == null || requiredByFeature.FeatureVersion < attr.FeatureVersion)
                        {
                            requiredByFeature = attr;
                        }
                    }
                    else
                    {
                        // Extension feature: collect every supporting extension
                        requiredByExtensions.Add(attr);
                    }
                }

                #endregion

                #region Check Deprecation/Removal

                if (requiredByFeature != null)
                {
                    // Note: indeed the feature could be supported; check whether it is removed; this is checked only if
                    // a non-extension feature is detected: extensions cannot remove commands
#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
                    Attribute[] attrRemoved = new List <Attribute>(function.GetCustomAttributes(typeof(RemovedByFeatureAttribute))).ToArray();
#else
                    Attribute[] attrRemoved = Attribute.GetCustomAttributes(function, typeof(RemovedByFeatureAttribute));
#endif
                    KhronosVersion maxRemovedVersion = null;

                    // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
                    foreach (RemovedByFeatureAttribute attr in attrRemoved)
                    {
                        // Check for API support
                        if (!attr.IsRemoved(version, extensions))
                        {
                            continue;
                        }
                        // Removed!
                        isRemoved = true;
                        // Keep track of the maximum API version removing this command
                        if (maxRemovedVersion == null || maxRemovedVersion < attr.FeatureVersion)
                        {
                            maxRemovedVersion = attr.FeatureVersion;
                        }
                    }

                    // Check for resurrection
                    if (isRemoved)
                    {
                        Debug.Assert(requiredByFeature != null);
                        Debug.Assert(maxRemovedVersion != null);

                        if (requiredByFeature.FeatureVersion > maxRemovedVersion)
                        {
                            isRemoved = false;
                        }
                    }
                }

                #endregion

                // Do not check feature requirements in case of removal. Note: extensions are checked all the same
                if (isRemoved)
                {
                    requiredByFeature = null;
                }
            }

            // Load function pointer
            IntPtr importAddress;

            if (requiredByFeature != null || version == null)
            {
                // Load command address (version feature)
                string functionName = defaultName;

                if (requiredByFeature?.EntryPoint != null)
                {
                    functionName = requiredByFeature.EntryPoint;
                }

                if ((importAddress = getAddress(path, functionName)) != IntPtr.Zero)
                {
                    BindAPIFunction(function, importAddress);
                    return;
                }
            }

            // Load command address (extension features)
            foreach (RequiredByFeatureAttribute extensionFeature in requiredByExtensions)
            {
                string functionName = extensionFeature.EntryPoint ?? defaultName;

                if ((importAddress = getAddress(path, functionName)) != IntPtr.Zero)
                {
                    BindAPIFunction(function, importAddress);
                    return;
                }
            }

            // Function not implemented: reset
            function.SetValue(null, null);
        }
Пример #18
0
        /// <summary>
        /// Link delegates fields using import declarations.
        /// </summary>
        /// <param name="path">
        /// A <see cref="String"/> that specifies the assembly file path containing the import functions.
        /// </param>
        /// <param name="functionContext">
        /// A <see cref="FunctionContext"/> mapping a <see cref="MethodInfo"/> with the relative function name.
        /// </param>
        /// <param name="function">
        /// A <see cref="FieldInfo"/> that specifies the underlying function field to be updated.
        /// </param>
        /// <param name="getAddress">
        /// A <see cref="GetAddressDelegate"/> used for getting function pointers. This parameter is dependent on the currently running platform.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="path"/>, <paramref name="function"/> or <paramref name="getAddress"/> is null.
        /// </exception>
        private static void BindAPIFunction(string path, FunctionContext functionContext, FieldInfo function, GetAddressDelegate getAddress)
        {
            if (path == null)
            {
                throw new ArgumentNullException("path");
            }
            if (functionContext == null)
            {
                throw new ArgumentNullException("functionContext");
            }
            if (function == null)
            {
                throw new ArgumentNullException("function");
            }
            if (getAddress == null)
            {
                throw new ArgumentNullException("getAddress");
            }

            Attribute[] aliasOfAttributes = Attribute.GetCustomAttributes(function, typeof(AliasOfAttribute));
            string      importName        = function.Name.Substring(1);           // Delegate name always prefixes with 'p'
            IntPtr      importAddress     = IntPtr.Zero;

            // Manages aliases (load external symbol)
            if (aliasOfAttributes.Length > 0)
            {
                for (int i = 0; i < aliasOfAttributes.Length; i++)
                {
                    AliasOfAttribute aliasOfAttribute = (AliasOfAttribute)aliasOfAttributes[i];
                    if ((importAddress = getAddress(path, aliasOfAttribute.SymbolName)) != IntPtr.Zero)
                    {
                        break;
                    }
                }
            }
            else
            {
                importAddress = getAddress(path, importName);
            }

            if (importAddress != IntPtr.Zero)
            {
                Delegate delegatePtr;

                // Try to load external symbol
                if ((delegatePtr = Marshal.GetDelegateForFunctionPointer(importAddress, function.FieldType)) == null)
                {
                    MethodInfo methodInfo;

                    if (functionContext.Imports.TryGetValue(importName, out methodInfo) == true)
                    {
                        delegatePtr = Delegate.CreateDelegate(function.FieldType, methodInfo);
                    }
                }

                if (delegatePtr != null)
                {
                    function.SetValue(null, delegatePtr);
                }
            }
            else
            {
                function.SetValue(null, null);                                          // Function not implemented
            }
        }
Пример #19
0
 /// <summary>
 /// Link delegates fields using import declarations.
 /// </summary>
 /// <param name="path">
 /// A <see cref="string"/> that specifies the assembly file path containing the import functions.
 /// </param>
 /// <param name="getAddress">
 /// A <see cref="GetAddressDelegate"/> used for getting function pointers.
 /// </param>
 /// <exception cref="ArgumentNullException">
 /// Exception thrown if <paramref name="path"/> or <paramref name="getAddress"/> is null.
 /// </exception>
 internal static void BindAPI <T>(string path, GetAddressDelegate getAddress, KhronosVersion version)
 {
     BindAPI <T>(path, getAddress, version, null);
 }