/// <summary> /// Create the GlControl context. /// </summary> protected virtual void CreateContext() { if (_RenderContext != IntPtr.Zero) { throw new InvalidOperationException("context already created"); } KhronosVersion currentVersion = Gl.CurrentVersion; Gl.Extensions currentExtensions = Gl.CurrentExtensions; bool hasCreateContext = true; bool hasCreateContextProfile = true; bool hasCreateContextRobustness = true; hasCreateContextProfile &= currentVersion.Api == KhronosVersion.ApiGl && currentVersion >= Gl.Version_300; switch (Environment.OSVersion.Platform) { case PlatformID.Win32NT: Wgl.Extensions currentWglExtensions = Wgl.CurrentExtensions; hasCreateContext &= currentWglExtensions.CreateContext_ARB || currentWglExtensions.CreateContextProfile_ARB; hasCreateContextProfile &= currentWglExtensions.CreateContextProfile_ARB; hasCreateContextRobustness = currentWglExtensions.CreateContextRobustness_ARB; break; case PlatformID.Unix: Glx.Extensions currentGlxExtensions = Glx.CurrentExtensions; hasCreateContext &= currentGlxExtensions.CreateContext_ARB; hasCreateContextProfile &= currentGlxExtensions.CreateContextProfile_ARB; hasCreateContextRobustness = currentGlxExtensions.CreateContextRobustness_ARB; break; } if (hasCreateContext) { List <int> attributes = new List <int>(); uint contextProfile = 0, contextFlags = 0; bool debuggerAttached = Debugger.IsAttached; #region WGL_ARB_create_context|GLX_ARB_create_context // The default values for WGL_CONTEXT_MAJOR_VERSION_ARB and WGL_CONTEXT_MINOR_VERSION_ARB are 1 and 0 respectively. In this // case, implementations will typically return the most recent version of OpenGL they support which is backwards compatible with OpenGL 1.0 // (e.g. 3.0, 3.1 + GL_ARB_compatibility, or 3.2 compatibility profile) [from WGL_ARB_create_context spec] Debug.Assert(Wgl.CONTEXT_MAJOR_VERSION_ARB == Glx.CONTEXT_MAJOR_VERSION_ARB); Debug.Assert(Wgl.CONTEXT_MINOR_VERSION_ARB == Glx.CONTEXT_MINOR_VERSION_ARB); if (Version != null) { attributes.AddRange(new int[] { Wgl.CONTEXT_MAJOR_VERSION_ARB, Version.Major, Wgl.CONTEXT_MINOR_VERSION_ARB, Version.Minor }); } else { attributes.AddRange(new int[] { Wgl.CONTEXT_MAJOR_VERSION_ARB, currentVersion.Major, Wgl.CONTEXT_MINOR_VERSION_ARB, currentVersion.Minor }); } if ((_DebugContextBit == AttributePermission.Enabled) || (debuggerAttached && _DebugContextBit == AttributePermission.EnabledInDebugger)) { Debug.Assert(Wgl.CONTEXT_DEBUG_BIT_ARB == Glx.CONTEXT_DEBUG_BIT_ARB); contextFlags |= Wgl.CONTEXT_DEBUG_BIT_ARB; } if ((_ForwardCompatibleContextBit == AttributePermission.Enabled) || (debuggerAttached && _ForwardCompatibleContextBit == AttributePermission.EnabledInDebugger)) { Debug.Assert(Wgl.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB == Glx.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB); contextFlags |= Wgl.CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; } #endregion #region WGL_ARB_create_context_profile|GLX_ARB_create_context_profile if (hasCreateContextProfile) { switch (_ProfileType) { case ProfileType.Core: Debug.Assert(Wgl.CONTEXT_CORE_PROFILE_BIT_ARB == Glx.CONTEXT_CORE_PROFILE_BIT_ARB); contextProfile |= Wgl.CONTEXT_CORE_PROFILE_BIT_ARB; break; case ProfileType.Compatibility: Debug.Assert(Wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB == Glx.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); contextProfile |= Wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; break; } } #endregion #region WGL_ARB_create_context_robustness|GLX_ARB_create_context_robustness if (hasCreateContextRobustness) { if ((_RobustContextBit == AttributePermission.Enabled) || (debuggerAttached && _RobustContextBit == AttributePermission.EnabledInDebugger)) { Debug.Assert(Wgl.CONTEXT_ROBUST_ACCESS_BIT_ARB == Glx.CONTEXT_ROBUST_ACCESS_BIT_ARB); contextFlags |= Wgl.CONTEXT_ROBUST_ACCESS_BIT_ARB; } } #endregion Debug.Assert(Wgl.CONTEXT_FLAGS_ARB == Glx.CONTEXT_FLAGS_ARB); if (contextFlags != 0) { attributes.AddRange(new int[] { Wgl.CONTEXT_FLAGS_ARB, unchecked ((int)contextFlags) }); } Debug.Assert(Wgl.CONTEXT_PROFILE_MASK_ARB == Glx.CONTEXT_PROFILE_MASK_ARB); if (contextProfile != 0) { attributes.AddRange(new int[] { Wgl.CONTEXT_PROFILE_MASK_ARB, unchecked ((int)contextProfile) }); } attributes.Add(0); if ((_RenderContext = _DeviceContext.CreateContextAttrib(IntPtr.Zero, attributes.ToArray())) == IntPtr.Zero) { throw new InvalidOperationException(String.Format("unable to create render context ({0})", Gl.GetError())); } } else { // Create OpenGL context using compatibility profile if ((_RenderContext = _DeviceContext.CreateContext(IntPtr.Zero)) == IntPtr.Zero) { throw new InvalidOperationException("unable to create render context"); } } }
/// <summary> /// Query the OpenGL implementation limits. /// </summary> /// <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="GraphicsLimits"/> 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 GraphicsLimits Query(Gl.Extensions glExtensions) { if (glExtensions == null) { throw new ArgumentNullException("glExtensions"); } KhronosApi.LogComment("Query OpenGL implementation imits."); GraphicsLimits graphicsLimits = new GraphicsLimits(); FieldInfo[] graphicsLimitsFields = typeof(GraphicsLimits).GetFields(BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo field in graphicsLimitsFields) { GraphicsLimitAttribute graphicsLimitAttribute = (GraphicsLimitAttribute)Attribute.GetCustomAttribute(field, typeof(GraphicsLimitAttribute)); Attribute[] graphicsExtensionAttributes = Attribute.GetCustomAttributes(field, typeof(KhronosApi.ExtensionAttribute)); MethodInfo getMethod; if (graphicsLimitAttribute == null) { continue; } // Check extension support if ((graphicsExtensionAttributes != null) && (graphicsExtensionAttributes.Length > 0)) { bool supported = Array.Exists(graphicsExtensionAttributes, delegate(Attribute item) { return(glExtensions.HasExtensions(((KhronosApi.ExtensionAttribute)item).ExtensionName)); }); if (supported == false) { continue; } } // Determine which method is used to get the OpenGL limit 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); } 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(), graphicsLimitAttribute.ArrayLenght); } object[] @params = new object[] { graphicsLimitAttribute.EnumValue, obj }; try { getMethod.Invoke(null, @params); field.SetValue(graphicsLimits, @params[1]); } catch (Exception) { } } else { try { string s = (string)getMethod.Invoke(null, new object[] { graphicsLimitAttribute.EnumValue }); field.SetValue(graphicsLimits, s); } catch (Exception) { } } } else { throw new InvalidOperationException("GraphicsLimits field " + field.Name + " doesn't have a OpenGL compatible type"); } string fieldValueString; object fieldValue = field.GetValue(graphicsLimits); if (fieldValue is Array) { StringBuilder sb = new StringBuilder(); sb.Append("{ "); if (((Array)fieldValue).Length > 0) { foreach (object arrayItem in (Array)fieldValue) { sb.AppendFormat("{0}, ", arrayItem); } sb.Remove(sb.Length - 2, 2); } sb.Append(" }"); fieldValueString = sb.ToString(); } else { fieldValueString = fieldValue.ToString(); } } return(graphicsLimits); }