/// <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); } }
/// <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("version"); } if (extensions == null) { throw new ArgumentNullException("extensions"); } #if !NETCORE Type apiType = typeof(T); FunctionContext functionContext = GetFunctionContext(apiType); Debug.Assert(functionContext != null); if (functionContext == null) { throw new InvalidOperationException("unrecognized API type"); } LogComment("Checking commands for {0}", 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); string commandName = fi.Name.Substring(3); bool commandDefined = fiDelegateType != null; bool supportedByFeature = false; Type delegateType = fi.DeclaringType.GetNestedType(fi.Name.Substring(1), BindingFlags.Public | BindingFlags.NonPublic); 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 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 = new List <Type>(); if (hiddenVersions.TryGetValue(hiddenVersionAttrib.FeatureName, out 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); } } } 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 == false && hiddenExtensions.ContainsKey(hiddenExtensionAttrib.FeatureName)) { hiddenExtensions[hiddenExtensionAttrib.FeatureName] = false; } } if (hiddenExtensions.Count > 0) { LogComment("Found {0} experimental extensions:", hiddenExtensions.Count); foreach (KeyValuePair <string, bool> hiddenExtension in hiddenExtensions) { LogComment("- {0}: {1}", hiddenExtension.Key, hiddenExtension.Value ? "experimental" : "experimental (partial, unsupported)"); } } if (hiddenVersions.Count > 0) { LogComment("Found {0} experimental version commands:", hiddenVersions.Count); foreach (KeyValuePair <string, List <Type> > hiddenVersion in hiddenVersions) { LogComment("- {0}", hiddenVersion.Key); foreach (Type delegateType in hiddenVersion.Value) { LogComment(" > {0}", delegateType.Name); } } } if (enableExtensions) { bool sync = false; foreach (KeyValuePair <string, bool> hiddenExtension in hiddenExtensions) { if (hiddenExtension.Value == false) { continue; // Do not enable partial extension } extensions.EnableExtension(hiddenExtension.Key); sync = true; } if (sync) { extensions.SyncMembers(version); } } #endif }
/// <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 }