/// <summary> /// Query the OpenGL implementation limits. /// </summary> /// <param name="version"> /// The <see cref="KhronosVersion"/> that specifies the GL version. /// </param> /// <param name="glExtensions"> /// A <see cref="Gl.Extensions"/> that specify the supported OpenGL extension by the current /// implementation. /// </param> /// <returns> /// It returns a <see cref="Gl.Limits"/> that specify the current OpenGL implementation limits. /// </returns> /// <remarks> /// It is assumed to have a valid OpenGL context current on the calling thread. /// </remarks> public static Limits Query(KhronosVersion version, Extensions glExtensions) { if (glExtensions == null) { throw new ArgumentNullException("glExtensions"); } LogComment("Query OpenGL implementation limits."); Limits graphicsLimits = new Limits(); #if NETSTANDARD1_1 || NETSTANDARD1_4 IEnumerable <FieldInfo> graphicsLimitsFields = typeof(Limits).GetTypeInfo().DeclaredFields; #else IEnumerable <FieldInfo> graphicsLimitsFields = typeof(Limits).GetFields(BindingFlags.Public | BindingFlags.Instance); #endif foreach (FieldInfo field in graphicsLimitsFields) { #if NETSTANDARD1_1 || NETSTANDARD1_4 || NETCORE LimitAttribute graphicsLimitAttribute = (LimitAttribute)field.GetCustomAttribute(typeof(LimitAttribute)); Attribute[] graphicsExtensionAttributes = new List <Attribute>(field.GetCustomAttributes(typeof(RequiredByFeatureAttribute))).ToArray(); #else LimitAttribute graphicsLimitAttribute = (LimitAttribute)Attribute.GetCustomAttribute(field, typeof(LimitAttribute)); Attribute[] graphicsExtensionAttributes = Attribute.GetCustomAttributes(field, typeof(RequiredByFeatureAttribute)); #endif MethodInfo getMethod; if (graphicsLimitAttribute == null) { continue; } // Check extension support if ((graphicsExtensionAttributes != null) && (graphicsExtensionAttributes.Length > 0)) { bool supported = Array.Exists(graphicsExtensionAttributes, delegate(Attribute item) { RequiredByFeatureAttribute featureAttribute = (RequiredByFeatureAttribute)item; return(featureAttribute.IsSupported(version, glExtensions)); }); if (supported == false) { continue; } } // Determine which method is used to get the OpenGL limit #if NETSTANDARD1_1 || NETSTANDARD1_4 if (field.FieldType != typeof(String)) { if (field.FieldType.IsArray == true) { getMethod = typeof(Gl).GetTypeInfo().GetDeclaredMethod("Get"); } else { getMethod = typeof(Gl).GetTypeInfo().GetDeclaredMethod("Get"); } } else { getMethod = typeof(Gl).GetTypeInfo().GetDeclaredMethod("GetString"); } #elif NETCORE if (field.FieldType != typeof(String)) { if (field.FieldType.IsArray == true) { getMethod = typeof(Gl).GetMethod("Get", new Type[] { typeof(Int32), field.FieldType }); } else { getMethod = typeof(Gl).GetMethod("Get", new Type[] { typeof(Int32), field.FieldType.MakeByRefType() }); } } else { getMethod = typeof(Gl).GetMethod("GetString", new Type[] { typeof(Int32) }); } #else if (field.FieldType != typeof(String)) { if (field.FieldType.IsArray == true) { getMethod = typeof(Gl).GetMethod("Get", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(Int32), field.FieldType }, null); } else { getMethod = typeof(Gl).GetMethod("Get", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(Int32), field.FieldType.MakeByRefType() }, null); } } else { getMethod = typeof(Gl).GetMethod("GetString", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(Int32) }, null); } #endif if (getMethod != null) { if (field.FieldType != typeof(String)) { object obj; if (field.FieldType.IsArray == false) { obj = Activator.CreateInstance(field.FieldType); } else { obj = Array.CreateInstance(field.FieldType.GetElementType(), (int)graphicsLimitAttribute.ArrayLength); } try { object[] @params = new object[] { graphicsLimitAttribute.EnumValue, obj }; getMethod.Invoke(null, @params); field.SetValue(graphicsLimits, @params[1]); } catch (GlException) { } catch (Exception) { } } else { try { string s = (string)getMethod.Invoke(null, new object[] { graphicsLimitAttribute.EnumValue }); field.SetValue(graphicsLimits, s); } catch (GlException) { } catch (Exception) { } } } else { throw new InvalidOperationException("GraphicsLimits field " + field.Name + " doesn't have a OpenGL compatible type"); } } return(graphicsLimits); }
/// <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 }