/// <summary>
        /// Determine whether an API implementation supports this feature.
        /// </summary>
        /// <param name="version">
        /// The <see cref="KhronosVersion"/> that specifies the API version.
        /// </param>
        /// <param name="extensions">
        /// The <see cref="ExtensionsCollection"/> that specifies the API extensions registry. It can be null.
        /// </param>
        /// <returns>
        /// It returns a <see cref="Boolean"/> that specifies whether this feature is supported by the
        /// API having the version <paramref name="version"/> and the extensions registry <paramref name="extensions"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="version"/> is null.
        /// </exception>
        public bool IsSupported(KhronosVersion version, KhronosApi.ExtensionsCollection extensions)
        {
            if (version == null)
            {
                throw new ArgumentNullException("version");
            }

            // Feature is an API version?
            if (FeatureVersion != null)
            {
                // API must match
                // Note: no need or regex, since Api cannot be a pattern
                if (version.Api != FeatureVersion.Api)
                {
                    return(false);
                }
                // Profile must match, if defined
                if (Profile != null && version.Profile != null && Regex.IsMatch(version.Profile, Profile) == false)
                {
                    return(false);
                }
                // API version must be greater than or equal to the required version
                return(version >= FeatureVersion);
            }

            // No API version: indeed it is an API extension
            if (extensions != null)
            {
                // Check compatible API
                // Note: regex is required since extensions can be implemented by multiple APIs
                if (Regex.IsMatch(version.Api, Api) == false)
                {
                    return(false);
                }
                // Last chance: extension name
                return(extensions.HasExtensions(FeatureName));
            }
            else
            {
                return(false);
            }
        }
Exemple #2
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);
            }
        }
Exemple #3
0
            /// <summary>
            /// Query the supported extensions.
            /// </summary>
            /// <param name="version">
            /// The <see cref="KhronosVersion" /> that specifies the version of the API context.
            /// </param>
            /// <param name="extensions">
            /// An array of strings that specifies the supported extensions.
            /// </param>
            /// <exception cref="ArgumentNullException">
            /// Exception thrown if <paramref name="extensions" /> is null.
            /// </exception>
            protected void Query(KhronosVersion version, string[] extensions)
            {
                if (extensions == null)
                {
                    throw new ArgumentNullException(nameof(extensions));
                }

                // Cache extension names in registry
                _extensionsRegistry.Clear();
                foreach (string extension in extensions)
                {
                    if (!_extensionsRegistry.ContainsKey(extension))
                    {
                        _extensionsRegistry.Add(extension, true);
                    }
                }

                // Sync fields
                SyncMembers(version);
            }
Exemple #4
0
        /// <summary>
        ///  Determine whether an API implementation removes this feature.
        /// </summary>
        /// <param name="version">
        /// The <see cref="KhronosVersion"/> that specifies the API version.
        /// </param>
        /// <param name="extensions">
        /// The <see cref="KhronosApi.ExtensionsCollection"/> that specifies the API extensions registry. It can be null.
        /// </param>
        /// <returns>
        /// It returns a <see cref="Boolean"/> that specifies whether this feature is removed by the
        /// API having the version <paramref name="version"/> and the extensions registry <paramref name="extensions"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="version"/> is null.
        /// </exception>
        public bool IsRemoved(KhronosVersion version, KhronosApi.ExtensionsCollection extensions)
        {
            if (version == null)
            {
                throw new ArgumentNullException(nameof(version));
            }

            // Feature is an API version?
            if (FeatureVersion != null)
            {
                // API must match
                // Note: no need or regex, since Api cannot be a pattern
                if (version.Api != FeatureVersion.Api)
                {
                    return(false);
                }
                // Profile must match, if defined
                if (Profile != null && version.Profile != null && !Regex.IsMatch(version.Profile, Profile))
                {
                    return(false);
                }
                // API version must be greater than or equal to the required version
                return(version >= FeatureVersion);
            }

            if (extensions != null)
            {
                // Check compatible API
                if (!Regex.IsMatch(version.Api, Api))
                {
                    return(false);
                }

                // Last chance: extension name
                return(extensions.HasExtensions(FeatureName));
            }
            else
            {
                return(false);
            }
        }
Exemple #5
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("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, getAddress, functionContext, fi, version, extensions);
            }
        }
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (Object.ReferenceEquals(value, null))
            {
                return(base.ConvertFrom(context, culture, value));
            }

            Type valueType = value.GetType();

            if (valueType == typeof(string))
            {
                string valueString = (string)value;

                if (valueString == String.Empty)
                {
                    return(null);
                }

                return(KhronosVersion.Parse(valueString));
            }

            // Base implementation
            return(base.ConvertFrom(context, culture, value));
        }
Exemple #7
0
        public static void BindAPIFunction(FieldInfo function, KhronosVersion version, ExtensionsCollection extensions, GraphicsContext context)
        {
            Debug.Assert(function != null);

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

            if (version != null || extensions != null)
            {
                var removed = false;

                #region Check Requirement

                IEnumerable <Attribute> attrRequired = new List <Attribute>(function.GetCustomAttributes(typeof(RequiredByFeatureAttribute)));
                // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
                foreach (RequiredByFeatureAttribute attr in attrRequired)
                {
                    // Check for API support
                    if (attr.IsSupported(version, extensions) == false)
                    {
                        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
                    Attribute[]    attrRemoved       = Attribute.GetCustomAttributes(function, typeof(RemovedByFeatureAttribute));
                    KhronosVersion maxRemovedVersion = null;

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

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

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

                #endregion

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

            // Load function pointer
            IntPtr   importAddress;
            Delegate importDelegate;

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

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

                if (context.Native)
                {
                    if ((importAddress = context.GetProcAddress(functionName)) != IntPtr.Zero)
                    {
                        BindNativeAPIFunction(function, importAddress);
                        return;
                    }
                }
                else
                {
                    if ((importDelegate = context.GetProcAddressNonNative(functionName)) != null)
                    {
                        function.SetValue(null, importDelegate);
                        return;
                    }
                }
            }

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

                if (context.Native)
                {
                    if ((importAddress = context.GetProcAddress(functionName)) != IntPtr.Zero)
                    {
                        BindNativeAPIFunction(function, importAddress);
                        return;
                    }
                }
                else
                {
                    if ((importDelegate = context.GetProcAddressNonNative(functionName)) != null)
                    {
                        function.SetValue(null, importDelegate);
                        return;
                    }
                }
            }

            // Function not implemented: reset
            function.SetValue(null, null);
        }
Exemple #8
0
 /// <summary>
 /// Construct a CoreExtensionAttribute specifying the version numbers.
 /// </summary>
 /// <param name="major">
 /// A <see cref="Int32" /> that specifies that major version number.
 /// </param>
 /// <param name="minor">
 /// A <see cref="Int32" /> that specifies that minor version number.
 /// </param>
 /// <param name="api">
 /// A <see cref="string" /> that specifies the API name.
 /// </param>
 /// <exception cref="ArgumentException">
 /// Exception thrown if <paramref name="major" /> is less or equals to 0, or if <paramref name="minor" /> is less than 0.
 /// </exception>
 /// <exception cref="ArgumentNullException">
 /// Exception thrown if <paramref name="api" /> is null.
 /// </exception>
 public CoreExtensionAttribute(int major, int minor, string api)
 {
     Version = new KhronosVersion(major, minor, 0, api);
 }
Exemple #9
0
 public static void BindAPIFunction(string functionName, KhronosVersion version, ExtensionsCollection extensions, GraphicsContext context)
 {
     BindAPIFunction(_functionContext.GetFunction(functionName), version, extensions, context);
 }
Exemple #10
0
        /// <summary>
        /// Determine whether an API command is compatible with the specific API version and extensions registry.
        /// </summary>
        /// <param name="function">
        /// A <see cref="FieldInfo" /> that specifies the command delegate to set. This argument make avail attributes useful
        /// to determine the actual support for this command.
        /// </param>
        /// <param name="version">
        /// The <see cref="KhronosVersion" /> that specifies the API version.
        /// </param>
        /// <param name="extensions">
        /// The <see cref="ExtensionsCollection" /> that specifies the API extensions registry.
        /// </param>
        /// <returns>
        /// It returns a <see cref="bool" /> that specifies whether <paramref name="function" /> is supported by the
        /// API having the version <paramref name="version" /> and the extensions registry <paramref name="extensions" />.
        /// </returns>
        internal static bool IsCompatibleField(FieldInfo function, KhronosVersion version, ExtensionsCollection extensions)
        {
            Debug.Assert(function != null);
            Debug.Assert(version != null);

            IEnumerable <Attribute> attrRequired = Attribute.GetCustomAttributes(function, typeof(RequiredByFeatureAttribute));

            KhronosVersion maxRequiredVersion = null;
            bool           required = false, removed = false;

            // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
            foreach (RequiredByFeatureAttribute attr in attrRequired)
            {
                // Check for API support
                if (attr.IsSupported(version, extensions) == false)
                {
                    continue;
                }
                // Supported!
                required = true;
                // Keep track of the maximum API version supporting this command
                // Note: useful for resurrected commands after deprecation
                if (maxRequiredVersion == null || maxRequiredVersion < attr.FeatureVersion)
                {
                    maxRequiredVersion = attr.FeatureVersion;
                }
            }

            if (required)
            {
                // Note: indeed the feature could be supported; check whether it is removed
                IEnumerable <Attribute> attrRemoved       = Attribute.GetCustomAttributes(function, typeof(RemovedByFeatureAttribute));
                KhronosVersion          maxRemovedVersion = null;

                // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
                foreach (RemovedByFeatureAttribute attr in attrRemoved)
                {
                    if (attr.IsRemoved(version, extensions) == false)
                    {
                        continue;
                    }

                    // Removed!
                    removed = true;
                    // Keep track of the maximum API version removing this command
                    if (maxRemovedVersion == null || maxRemovedVersion < attr.FeatureVersion)
                    {
                        maxRemovedVersion = attr.FeatureVersion;
                    }
                }

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

                    if (maxRequiredVersion > maxRemovedVersion)
                    {
                        removed = false;
                    }
                }

                return(removed == false);
            }

            return(false);
        }
Exemple #11
0
        /// <summary>
        /// Check whether commands implemented by the current driver have a corresponding extension declaring the
        /// support of them.
        /// </summary>
        /// <typeparam name="T">
        /// The type of the KhronosApi to inspect for commands.
        /// </typeparam>
        /// <param name="version">
        /// The <see cref="KhronosVersion"/> currently implemented by the current context on this thread.
        /// </param>
        /// <param name="extensions">
        /// The <see cref="ExtensionsCollection"/> that specifies the extensions supported by the driver.
        /// </param>
        protected static void CheckExtensionCommands <T>(KhronosVersion version, ExtensionsCollection extensions, bool enableExtensions) where T : KhronosApi
        {
            if (version == null)
            {
                throw new ArgumentNullException(nameof(version));
            }
            if (extensions == null)
            {
                throw new ArgumentNullException(nameof(extensions));
            }

#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
            throw new NotImplementedException();
#else
            FunctionContext functionContext = GetFunctionContext(typeof(T));
            Debug.Assert(functionContext != null);

            LogComment($"Checking commands for {version}");

            Dictionary <string, List <Type> > hiddenVersions   = new Dictionary <string, List <Type> >();
            Dictionary <string, bool>         hiddenExtensions = new Dictionary <string, bool>();

            foreach (FieldInfo fi in functionContext.Delegates)
            {
                Delegate fiDelegateType     = (Delegate)fi.GetValue(null);
                bool     commandDefined     = fiDelegateType != null;
                bool     supportedByFeature = false;

#if DEBUG_VERBOSE
                string commandName = fi.Name.Substring(3);
#endif
                // Get the delegate type
                Type delegateType = fi.DeclaringType?.GetNestedType(fi.Name.Substring(1), BindingFlags.Public | BindingFlags.NonPublic);
                if (delegateType == null)
                {
                    continue;                                   // Support fields names not in sync with delegate types
                }
                // TODO Why not use 'fi' directly for getting attributes? They should be in sync
                IEnumerable <object> requiredByFeatureAttributes = delegateType.GetCustomAttributes(typeof(RequiredByFeatureAttribute), false);

                foreach (RequiredByFeatureAttribute requiredByFeatureAttribute in requiredByFeatureAttributes)
                {
                    supportedByFeature |= requiredByFeatureAttribute.IsSupported(version, extensions);
                }

                // Find the underlying extension
                RequiredByFeatureAttribute hiddenVersionAttrib   = null;
                RequiredByFeatureAttribute hiddenExtensionAttrib = null;

                foreach (RequiredByFeatureAttribute requiredByFeatureAttribute in requiredByFeatureAttributes)
                {
                    if (!requiredByFeatureAttribute.IsSupportedApi(version.Api))
                    {
                        // Version attribute
                        if (hiddenVersionAttrib == null)
                        {
                            hiddenVersionAttrib = requiredByFeatureAttribute;
                        }
                    }
                    else
                    {
                        // Extension attribute
                        if (hiddenExtensionAttrib == null)
                        {
                            hiddenExtensionAttrib = requiredByFeatureAttribute;
                        }
                    }
                }

                if (commandDefined != supportedByFeature)
                {
#if DEBUG_VERBOSE
                    string supportString = "any feature";

                    if (hiddenVersionAttrib != null)
                    {
                        supportString = hiddenVersionAttrib.FeatureName;
                        if (hiddenExtensionAttrib != null)
                        {
                            supportString += " or ";
                        }
                    }

                    if (hiddenExtensionAttrib != null)
                    {
                        if (hiddenVersionAttrib == null)
                        {
                            supportString = string.Empty;
                        }
                        supportString += hiddenExtensionAttrib.FeatureName;
                    }
#endif

                    if (commandDefined)
                    {
#if DEBUG_VERBOSE
                        LogComment("The command {0} is defined, but {1} support is not advertised.", commandName, supportString);
#endif
                        if (hiddenVersionAttrib != null && hiddenExtensionAttrib == null)
                        {
                            List <Type> versionDelegates;

                            if (!hiddenVersions.TryGetValue(hiddenVersionAttrib.FeatureName, out versionDelegates))
                            {
                                hiddenVersions.Add(hiddenVersionAttrib.FeatureName, versionDelegates = new List <Type>());
                            }
                            versionDelegates.Add(delegateType);
                        }

                        if (hiddenExtensionAttrib != null)
                        {
                            // Eventually leave to false for incomplete extensions
                            if (!hiddenExtensions.ContainsKey(hiddenExtensionAttrib.FeatureName))
                            {
                                hiddenExtensions.Add(hiddenExtensionAttrib.FeatureName, true);
                            }
                        }
                    }
                    else
                    {
#if DEBUG_VERBOSE
                        LogComment("The command {0} is not defined, but required by some feature.", commandName);
#endif
                    }
                }

                // Partial extensions are not supported
                if (hiddenExtensionAttrib != null && !commandDefined && hiddenExtensions.ContainsKey(hiddenExtensionAttrib.FeatureName))
                {
                    hiddenExtensions[hiddenExtensionAttrib.FeatureName] = false;
                }
            }

            if (hiddenExtensions.Count > 0)
            {
                LogComment($"Found {hiddenExtensions.Count} experimental extensions:");
                foreach (KeyValuePair <string, bool> hiddenExtension in hiddenExtensions)
                {
                    LogComment(string.Format($"- {0}: {1}", hiddenExtension.Key, hiddenExtension.Value ? "experimental" : "experimental (partial, unsupported)"));
                }
            }

            if (hiddenVersions.Count > 0)
            {
                LogComment($"Found {hiddenVersions.Count} experimental version commands:");
                foreach (KeyValuePair <string, List <Type> > hiddenVersion in hiddenVersions)
                {
                    LogComment($"- {hiddenVersion.Key}");
                    foreach (Type delegateType in hiddenVersion.Value)
                    {
                        LogComment($"    > {delegateType.Name}");
                    }
                }
            }

            if (enableExtensions)
            {
                bool sync = false;

                foreach (KeyValuePair <string, bool> hiddenExtension in hiddenExtensions)
                {
                    if (!hiddenExtension.Value)
                    {
                        continue;                               // Do not enable partial extension
                    }
                    extensions.EnableExtension(hiddenExtension.Key);
                    sync = true;
                }

                if (sync)
                {
                    extensions.SyncMembers(version);
                }
            }
#endif
        }
Exemple #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="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);
 }
Exemple #13
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);
        }
Exemple #14
0
            protected internal void SyncMembers(KhronosVersion version)
            {
                if (version == null)
                {
                    throw new ArgumentNullException("version");
                }

                Type thisType = GetType();

#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
                IEnumerable <FieldInfo> thisTypeFields = thisType.GetTypeInfo().DeclaredFields;
#else
                IEnumerable <FieldInfo> thisTypeFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public);
#endif

                foreach (FieldInfo fieldInfo in thisTypeFields)
                {
                    // Check boolean field (defensive)
                    Debug.Assert(fieldInfo.FieldType == typeof(bool));
                    if (fieldInfo.FieldType != typeof(bool))
                    {
                        continue;
                    }

                    bool support = false;

                    // Support by extension
#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
                    IEnumerable <Attribute> coreAttributes = fieldInfo.GetCustomAttributes(typeof(CoreExtensionAttribute));
#else
                    IEnumerable <Attribute> coreAttributes = Attribute.GetCustomAttributes(fieldInfo, typeof(CoreExtensionAttribute));
#endif
                    if (coreAttributes != null)
                    {
                        foreach (CoreExtensionAttribute coreAttribute in coreAttributes)
                        {
                            if (version.Api == coreAttribute.Version.Api && version >= coreAttribute.Version)
                            {
                                support |= true;
                                break;
                            }
                        }
                    }

                    // Support by extension
#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
                    IEnumerable <Attribute> extensionAttributes = fieldInfo.GetCustomAttributes(typeof(ExtensionAttribute));
#else
                    IEnumerable <Attribute> extensionAttributes = Attribute.GetCustomAttributes(fieldInfo, typeof(ExtensionAttribute));
#endif
                    if (extensionAttributes != null)
                    {
                        foreach (ExtensionAttribute extensionAttribute in extensionAttributes)
                        {
                            if (_ExtensionsRegistry.ContainsKey(extensionAttribute.ExtensionName))
                            {
                                support |= true;
                                break;
                            }
                        }
                    }

                    fieldInfo.SetValue(this, support);
                }
            }
Exemple #15
0
        /// <summary>
        /// Determine whether an API command is compatible with the specific API version and extensions registry.
        /// </summary>
        /// <param name="function">
        /// A <see cref="FieldInfo"/> that specifies the command delegate to set. This argument make avail attributes useful
        /// to determine the actual support for this command.
        /// </param>
        /// <param name="version">
        /// The <see cref="KhronosVersion"/> that specifies the API version.
        /// </param>
        /// <param name="extensions">
        /// The <see cref="ExtensionsCollection"/> that specifies the API extensions registry.
        /// </param>
        /// <returns>
        /// It returns a <see cref="Boolean"/> that specifies whether <paramref name="function"/> is supported by the
        /// API having the version <paramref name="version"/> and the extensions registry <paramref name="extensions"/>.
        /// </returns>
        internal static bool IsCompatibleField(FieldInfo function, KhronosVersion version, ExtensionsCollection extensions)
        {
            if (function == null)
            {
                throw new ArgumentNullException("function");
            }
            if (version == null)
            {
                throw new ArgumentNullException("version");
            }

#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
            Attribute[] attrRequired = new List <Attribute>(function.GetCustomAttributes(typeof(RequiredByFeatureAttribute))).ToArray();            // XXX
#else
            Attribute[] attrRequired = Attribute.GetCustomAttributes(function, typeof(RequiredByFeatureAttribute));
#endif

            KhronosVersion maxRequiredVersion = null;
            bool           isRequired = false, isRemoved = false;

            foreach (RequiredByFeatureAttribute attr in attrRequired)
            {
                // Check for API support
                if (attr.IsSupported(version, extensions) == false)
                {
                    continue;
                }
                // Supported!
                isRequired |= true;
                // Keep track of the maximum API version supporting this command
                // Note: useful for resurrected commands after deprecation
                if (maxRequiredVersion == null || maxRequiredVersion < attr.FeatureVersion)
                {
                    maxRequiredVersion = attr.FeatureVersion;
                }
            }

            if (isRequired)
            {
                // Note: indeed the feature could be supported; check whether it is removed

#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;

                foreach (RemovedByFeatureAttribute attr in attrRemoved)
                {
                    if (attr.IsRemoved(version, extensions) == false)
                    {
                        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(maxRequiredVersion != null);
                    Debug.Assert(maxRemovedVersion != null);

                    if (maxRequiredVersion > maxRemovedVersion)
                    {
                        isRemoved = false;
                    }
                }

                return(isRemoved == false);
            }
            else
            {
                return(false);
            }
        }
Exemple #16
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="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");
            }

            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
                Attribute[] attrRequired = new List <Attribute>(function.GetCustomAttributes(typeof(RequiredByFeatureAttribute))).ToArray();
#else
                Attribute[] attrRequired = Attribute.GetCustomAttributes(function, typeof(RequiredByFeatureAttribute));
#endif
                foreach (RequiredByFeatureAttribute attr in attrRequired)
                {
                    // Check for API support
                    if (attr.IsSupported(version, extensions) == false)
                    {
                        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;

                    foreach (RemovedByFeatureAttribute attr in attrRemoved)
                    {
                        // Check for API support
                        if (attr.IsRemoved(version, extensions) == false)
                        {
                            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 != null && 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);
        }
Exemple #17
0
        /// <summary>
        /// Check whether commands implemented by the current driver have a corresponding extension declaring the
        /// support of them.
        /// </summary>
        /// <param name="version">
        /// The <see cref="KhronosVersion" /> currently implemented by the current context on this thread.
        /// </param>
        /// <param name="extensions">
        /// The <see cref="ExtensionsCollection" /> that specifies the extensions supported by the driver.
        /// </param>
        /// <param name="enableExtensions"></param>
        protected static void CheckExtensionCommands(KhronosVersion version, ExtensionsCollection extensions, bool enableExtensions)
        {
            if (version == null)
            {
                throw new ArgumentNullException(nameof(version));
            }
            if (extensions == null)
            {
                throw new ArgumentNullException(nameof(extensions));
            }

            var hiddenVersions   = new Dictionary <string, List <Type> >();
            var hiddenExtensions = new Dictionary <string, bool>();

            foreach (FieldInfo fi in _functionContext.Delegates)
            {
                var  fiDelegateType     = (Delegate)fi.GetValue(null);
                bool commandDefined     = fiDelegateType != null;
                var  supportedByFeature = false;

                // Get the delegate type
                Type delegateType = fi.DeclaringType?.GetNestedType(fi.Name.Substring(1), BindingFlags.Public | BindingFlags.NonPublic);
                if (delegateType == null)
                {
                    continue; // Support fields names not in sync with delegate types
                }
                // TODO Why not use 'fi' directly for getting attributes? They should be in sync
                IEnumerable <object> requiredByFeatureAttributes = delegateType.GetCustomAttributes(typeof(RequiredByFeatureAttribute), false);

                foreach (RequiredByFeatureAttribute requiredByFeatureAttribute in requiredByFeatureAttributes)
                {
                    supportedByFeature |= requiredByFeatureAttribute.IsSupported(version, extensions);
                }

                // Find the underlying extension
                RequiredByFeatureAttribute hiddenVersionAttrib   = null;
                RequiredByFeatureAttribute hiddenExtensionAttrib = null;

                foreach (RequiredByFeatureAttribute requiredByFeatureAttribute in requiredByFeatureAttributes)
                {
                    if (requiredByFeatureAttribute.IsSupportedApi(version.Api) == false)
                    {
                        // Version attribute
                        if (hiddenVersionAttrib == null)
                        {
                            hiddenVersionAttrib = requiredByFeatureAttribute;
                        }
                    }
                    else
                    {
                        // Extension attribute
                        if (hiddenExtensionAttrib == null)
                        {
                            hiddenExtensionAttrib = requiredByFeatureAttribute;
                        }
                    }
                }

                if (commandDefined != supportedByFeature)
                {
                    if (commandDefined)
                    {
                        if (hiddenVersionAttrib != null && hiddenExtensionAttrib == null)
                        {
                            if (hiddenVersions.TryGetValue(hiddenVersionAttrib.FeatureName, out List <Type> versionDelegates) == false)
                            {
                                hiddenVersions.Add(hiddenVersionAttrib.FeatureName, versionDelegates = new List <Type>());
                            }
                            versionDelegates.Add(delegateType);
                        }

                        if (hiddenExtensionAttrib != null) // Eventually leave to false for incomplete extensions
                        {
                            if (hiddenExtensions.ContainsKey(hiddenExtensionAttrib.FeatureName) == false)
                            {
                                hiddenExtensions.Add(hiddenExtensionAttrib.FeatureName, true);
                            }
                        }
                    }
                }

                // Partial extensions are not supported
                if (hiddenExtensionAttrib != null && commandDefined == false && hiddenExtensions.ContainsKey(hiddenExtensionAttrib.FeatureName))
                {
                    hiddenExtensions[hiddenExtensionAttrib.FeatureName] = false;
                }
            }

            if (!enableExtensions)
            {
                return;
            }

            var sync = false;

            foreach (KeyValuePair <string, bool> hiddenExtension in hiddenExtensions.Where(hiddenExtension => hiddenExtension.Value))
            {
                extensions.EnableExtension(hiddenExtension.Key);
                sync = true;
            }

            if (sync)
            {
                extensions.SyncMembers(version);
            }
        }
Exemple #18
0
            /// <summary>
            /// Set all fields of this ExtensionsCollection, depending on current extensions.
            /// </summary>
            /// <param name="version">
            /// The <see cref="KhronosVersion"/> that specifies the context version/API. It can be null.
            /// </param>
            protected internal void SyncMembers(KhronosVersion version)
            {
                Type thisType = GetType();

#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
                IEnumerable <FieldInfo> thisTypeFields = thisType.GetTypeInfo().DeclaredFields;
#else
                IEnumerable <FieldInfo> thisTypeFields = thisType.GetFields(BindingFlags.Instance | BindingFlags.Public);
#endif

                foreach (FieldInfo fieldInfo in thisTypeFields)
                {
                    // Check boolean field (defensive)
                    // Debug.Assert(fieldInfo.FieldType == typeof(bool));
                    if (fieldInfo.FieldType != typeof(bool))
                    {
                        continue;
                    }

                    bool support = false;

                    // Support by extension
#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
                    IEnumerable <Attribute> extensionAttributes = fieldInfo.GetCustomAttributes(typeof(ExtensionAttribute));
#else
                    IEnumerable <Attribute> extensionAttributes = Attribute.GetCustomAttributes(fieldInfo, typeof(ExtensionAttribute));
#endif
                    // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
                    foreach (ExtensionAttribute extensionAttribute in extensionAttributes)
                    {
                        if (!_ExtensionsRegistry.ContainsKey(extensionAttribute.ExtensionName))
                        {
                            continue;
                        }
                        if (version != null && version.Api != null && extensionAttribute.Api != null && !Regex.IsMatch(version.Api, "^" + extensionAttribute.Api + "$"))
                        {
                            continue;
                        }

                        support = true;
                        break;
                    }

                    // Support by version
                    if (version != null && !support)
                    {
#if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE
                        IEnumerable <Attribute> coreAttributes = fieldInfo.GetCustomAttributes(typeof(CoreExtensionAttribute));
#else
                        IEnumerable <Attribute> coreAttributes = Attribute.GetCustomAttributes(fieldInfo, typeof(CoreExtensionAttribute));
#endif
                        // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop
                        foreach (CoreExtensionAttribute coreAttribute in coreAttributes)
                        {
                            if (version.Api != coreAttribute.Version.Api || version < coreAttribute.Version)
                            {
                                continue;
                            }

                            support = true;
                            break;
                        }
                    }

                    fieldInfo.SetValue(this, support);
                }
            }
Exemple #19
0
 /// <summary>
 /// Link delegates fields using import declarations.
 /// </summary>
 /// <param name="version"></param>
 /// <exception cref="ArgumentNullException">
 /// Exception thrown if <paramref name="path"/> or <paramref name="getAddress"/> is null.
 /// </exception>
 internal static void BindAPI <T>(KhronosVersion version)
 {
     BindAPI <T>(version, null);
 }
Exemple #20
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);
        }