Exemple #1
0
        /// <summary>
        /// Get the library name used for loading OpenGL functions.
        /// </summary>
        /// <param name="version">
        /// A <see cref="KhronosVersion"/> that specifies the API to bind.
        /// </param>
        /// <returns>
        /// It returns a <see cref="String"/> that specifies the library name to be used.
        /// </returns>
        private static string GetPlatformLibrary(KhronosVersion version)
        {
            switch (version.Api)
            {
            case KhronosVersion.ApiGl:
            case KhronosVersion.ApiGlsc2:
                switch (Platform.CurrentPlatformId)
                {
                case Platform.Id.Linux:
                    return("libGL.so.1");

                case Platform.Id.MacOS:
                    return("/usr/X11/lib/libGL.1.dylib");

                default:
                    // EGL ignore library name
                    return(Library);
                }

            case KhronosVersion.ApiGles1:
                switch (Platform.CurrentPlatformId)
                {
                case Platform.Id.Linux:
                    return("libGLESv2.so");

                default:
                    return(Egl.IsRequired ? LibraryEs : Library);
                }

            case KhronosVersion.ApiGles2:
                switch (Platform.CurrentPlatformId)
                {
                case Platform.Id.Linux:
                    return("libGLESv2.so");

                default:
                    return(Egl.IsRequired ? LibraryEs2 : Library);
                }

            default:
                throw new NotSupportedException($"binding API for OpenGL {version} not supported");
            }
        }
Exemple #2
0
        /// <summary>
        /// Query the OpenGL version. Requires some information lookup functions to be bound.
        /// </summary>
        /// <returns>The version of the current OpenGL context.</returns>
        private static KhronosVersion QueryContextVersionInternal()
        {
            // Parse version string (effective for detecting Desktop and ES contextes)
            string         str       = GetString(StringName.Version);
            KhronosVersion glVersion = KhronosVersion.Parse(str);

            // Vendor/Render information
            CurrentVendor    = GetString(StringName.Vendor);
            CurrentRenderer  = GetString(StringName.Renderer);
            SoftwareRenderer = CurrentRenderer.Contains("llvmpipe");

            // Context profile
            if (glVersion.Api == KhronosVersion.API_GL && glVersion >= Version320)
            {
                string glProfile;

                Get(CONTEXT_PROFILE_MASK, out int ctxProfile);

                if ((ctxProfile & CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0)
                {
                    glProfile = KhronosVersion.PROFILE_COMPATIBILITY;
                }
                else if ((ctxProfile & CONTEXT_CORE_PROFILE_BIT) != 0)
                {
                    glProfile = KhronosVersion.PROFILE_CORE;
                }
                else
                {
                    glProfile = KhronosVersion.PROFILE_COMPATIBILITY;
                }

                return(new KhronosVersion(glVersion, glProfile));
            }
            else
            {
                string profile = KhronosVersion.PROFILE_COMPATIBILITY;
                if (CurrentRenderer.Contains("WebGL"))
                {
                    profile = KhronosVersion.PROFILE_WEBGL;
                }
                return(new KhronosVersion(glVersion, profile));
            }
        }
        /// <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 #4
0
            /// <summary>
            /// Default constructor.
            /// </summary>
            protected NativeSurface()
            {
                try {
                    if ((_Display = Egl.GetDisplay(new IntPtr(Egl.DEFAULT_DISPLAY))) == IntPtr.Zero)
                    {
                        throw new InvalidOperationException("unable to get display handle");
                    }

                    int[] major = new int[1], minor = new int[1];

                    if (Egl.Initialize(_Display, major, minor) == false)
                    {
                        throw new InvalidOperationException("unable to initialize the display");
                    }

                    _EglVersion = new KhronosVersion(major[0], minor[0], KhronosVersion.ApiEgl);
                } catch {
                    Dispose();
                    throw;
                }
            }
Exemple #5
0
        /// <summary>
        /// Query the version of the current OpenGL context.
        /// </summary>
        /// <returns>
        /// It returns the <see cref="KhronosVersion"/> specifying the actual version of the context current on this thread.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// Exception thrown if no GL context is current on the calling thread.
        /// </exception>
        public static KhronosVersion QueryContextVersion()
        {
            IntPtr ctx = DeviceContext.GetCurrentContext();

            if (ctx == IntPtr.Zero)
            {
                throw new InvalidOperationException("no current context");
            }

            // Parse version string (effective for detecting Desktop and ES contextes)
            KhronosVersion glversion = KhronosVersion.Parse(Gl.GetString(StringName.Version));

            // Context profile
            if (glversion.Api == KhronosVersion.ApiGl && glversion >= Gl.Version_320)
            {
                string glProfile  = null;
                int    ctxProfile = 0;

                Gl.Get(Gl.CONTEXT_PROFILE_MASK, out ctxProfile);

                if ((ctxProfile & Gl.CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0)
                {
                    glProfile = KhronosVersion.ProfileCompatibility;
                }
                else if ((ctxProfile & Gl.CONTEXT_CORE_PROFILE_BIT) != 0)
                {
                    glProfile = KhronosVersion.ProfileCore;
                }
                else
                {
                    glProfile = KhronosVersion.ProfileCompatibility;
                }

                return(new KhronosVersion(glversion, glProfile));
            }
            else
            {
                return(new KhronosVersion(glversion, KhronosVersion.ProfileCompatibility));
            }
        }
        /// <summary>
        /// Query the version of the current OpenGL context.
        /// </summary>
        /// <returns>
        /// It returns the <see cref="KhronosVersion" /> specifying the actual version of the context current on this thread.
        /// </returns>
        public static KhronosVersion QueryContextVersion()
        {
            BindAPIFunction <Gl>("glGetError", Version100, null);
            BindAPIFunction <Gl>("glGetString", Version100, null);
            BindAPIFunction <Gl>("glGetIntegerv", Version100, null);

            // Parse version string (effective for detecting Desktop and ES contextes)
            string         str       = GetString(StringName.Version);
            KhronosVersion glVersion = KhronosVersion.Parse(str);

            // Context profile
            if (glVersion.Api == KhronosVersion.API_GL && glVersion >= Version320)
            {
                string glProfile;

                Get(CONTEXT_PROFILE_MASK, out int ctxProfile);

                if ((ctxProfile & CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0)
                {
                    glProfile = KhronosVersion.PROFILE_COMPATIBILITY;
                }
                else if ((ctxProfile & CONTEXT_CORE_PROFILE_BIT) != 0)
                {
                    glProfile = KhronosVersion.PROFILE_CORE;
                }
                else
                {
                    glProfile = KhronosVersion.PROFILE_COMPATIBILITY;
                }

                return(new KhronosVersion(glVersion, glProfile));
            }
            else
            {
                return(new KhronosVersion(glVersion, KhronosVersion.PROFILE_COMPATIBILITY));
            }
        }
Exemple #7
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>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="path"/> or <paramref name="getAddress"/> is null.
        /// </exception>
        private 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);
            }
        }
Exemple #8
0
        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 #9
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 (version == null)
                {
                    throw new ArgumentNullException("version");
                }
                if (extensions == null)
                {
                    throw new ArgumentNullException("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);
            }
        /// <summary>
        /// Creates a context, specifying attributes.
        /// </summary>
        /// <param name="sharedContext">
        /// A <see cref="IntPtr"/> that specify a context that will share objects with the returned one. If
        /// it is IntPtr.Zero, no sharing is performed.
        /// </param>
        /// <param name="attribsList">
        /// A <see cref="T:Int32[]"/> that specifies the attributes list.
        /// </param>
        /// <param name="api">
        /// A <see cref="KhronosVersion"/> that specifies the API to be implemented by the returned context. It can be null indicating the
        /// default API for this DeviceContext implementation. If it is possible, try to determine the API version also.
        /// </param>
        /// <returns>
        /// A <see cref="IntPtr"/> that represents the handle of the created context. If the context cannot be
        /// created, it returns IntPtr.Zero.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <see cref="attribsList"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Exception thrown if <paramref name="attribsList"/> length is zero or if the last item of <paramref name="attribsList"/>
        /// is not zero.
        /// </exception>
        public override IntPtr CreateContextAttrib(IntPtr sharedContext, int[] attribsList, KhronosVersion api)
        {
            if (api != null && api.Api != KhronosVersion.ApiGl)
            {
                List <int> adulteredAttribs = new List <int>(attribsList);

                // Support check
                switch (api.Api)
                {
                case KhronosVersion.ApiGles1:
                case KhronosVersion.ApiGles2:
                    if (Glx.CurrentExtensions.CreateContextEsProfile_EXT == false)
                    {
                        throw new NotSupportedException("OpenGL ES API not supported");
                    }
                    break;

                default:
                    throw new NotSupportedException(String.Format("'{0}' API not supported", api.Api));
                }

                // Remove trailing 0
                if (adulteredAttribs.Count > 0 && adulteredAttribs[adulteredAttribs.Count - 1] == Gl.NONE)
                {
                    adulteredAttribs.RemoveAt(adulteredAttribs.Count - 1);
                }

                // Add required attributes
                int majorVersionIndex = adulteredAttribs.FindIndex(delegate(int item) { return(item == Gl.MAJOR_VERSION); });
                int minorVersionIndex = adulteredAttribs.FindIndex(delegate(int item) { return(item == Gl.MINOR_VERSION); });
                int profileMaskIndex  = adulteredAttribs.FindIndex(delegate(int item) { return(item == Gl.CONTEXT_PROFILE_MASK); });

                if (majorVersionIndex < 0)
                {
                    adulteredAttribs.AddRange(new int[] { Gl.MAJOR_VERSION, api.Major });
                    majorVersionIndex = adulteredAttribs.Count - 2;
                }

                if (minorVersionIndex < 0)
                {
                    adulteredAttribs.AddRange(new int[] { Gl.MINOR_VERSION, api.Minor });
                    minorVersionIndex = adulteredAttribs.Count - 2;
                }

                if (profileMaskIndex < 0)
                {
                    adulteredAttribs.AddRange(new int[] { Gl.CONTEXT_PROFILE_MASK, 0 });
                    profileMaskIndex = adulteredAttribs.Count - 2;
                }

                switch (api.Api)
                {
                case KhronosVersion.ApiGles1:
                    // Ignore API version: force always to 1.0
                    adulteredAttribs[majorVersionIndex + 1] = 1;
                    adulteredAttribs[minorVersionIndex + 1] = 1;
                    adulteredAttribs[profileMaskIndex + 1] |= (int)Glx.CONTEXT_ES_PROFILE_BIT_EXT;
                    break;

                case KhronosVersion.ApiGles2:
                    // Uses API version: it may be greater than 2.0(?)
                    adulteredAttribs[majorVersionIndex + 1] = api.Major;
                    adulteredAttribs[minorVersionIndex + 1] = api.Minor;
                    adulteredAttribs[profileMaskIndex + 1] |= (int)Glx.CONTEXT_ES_PROFILE_BIT_EXT;
                    break;

                default:
                    throw new NotSupportedException(String.Format("'{0}' API not supported", api.Api));
                }

                // Restore trailing 0
                adulteredAttribs.Add(Gl.NONE);

                using (Glx.XLock displayLock = new Glx.XLock(Display)) {
                    Debug.Assert(_FBConfig != IntPtr.Zero, "SetPixelFormat not executed");
                    return(Glx.CreateContextAttribsARB(Display, _FBConfig, sharedContext, true, adulteredAttribs.ToArray()));
                }
            }
            else
            {
                using (Glx.XLock displayLock = new Glx.XLock(Display)) {
                    Debug.Assert(_FBConfig != IntPtr.Zero, "SetPixelFormat not executed");
                    return(Glx.CreateContextAttribsARB(Display, _FBConfig, sharedContext, true, attribsList));
                }
            }
        }
        /// <summary>
        /// Creates a context, specifying attributes.
        /// </summary>
        /// <param name="sharedContext">
        /// A <see cref="IntPtr"/> that specify a context that will share objects with the returned one. If
        /// it is IntPtr.Zero, no sharing is performed.
        /// </param>
        /// <param name="attribsList">
        /// A <see cref="T:Int32[]"/> that specifies the attributes list.
        /// </param>
        /// <param name="api">
        /// A <see cref="KhronosVersion"/> that specifies the API to be implemented by the returned context. It can be null indicating the
        /// default API for this DeviceContext implementation. If it is possible, try to determine the API version also.
        /// </param>
        /// <returns>
        /// A <see cref="IntPtr"/> that represents the handle of the created context. If the context cannot be
        /// created, it returns IntPtr.Zero.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="attribsList"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Exception thrown if <paramref name="attribsList"/> length is zero or if the last item of <paramref name="attribsList"/>
        /// is not zero.
        /// </exception>
        public override IntPtr CreateContextAttrib(IntPtr sharedContext, int[] attribsList, KhronosVersion api)
        {
            if (attribsList == null)
            {
                throw new ArgumentNullException(nameof(attribsList));
            }
            if (attribsList.Length == 0)
            {
                throw new ArgumentException("zero length array", nameof(attribsList));
            }
            if (attribsList[attribsList.Length - 1] != Egl.NONE)
            {
                throw new ArgumentException("not EGL_NONE-terminated array", nameof(attribsList));
            }

            IntPtr context;

            // Select surface pixel format automatically
            if (_NativeSurface != null && _NativeSurface.Handle != IntPtr.Zero)
            {
                int[] configId = new int[1];

                if (Egl.QuerySurface(Display, EglSurface, Egl.CONFIG_ID, configId) == false)
                {
                    throw new InvalidOperationException("unable to query EGL surface config ID");
                }

                _Config = ChoosePixelFormat(Display, configId[0]);
            }

            // Bind API
            if (Version >= Egl.Version_120)
            {
                uint apiEnum;

                switch (api.Api)
                {
                case KhronosVersion.ApiGles2:
                case KhronosVersion.ApiGles1:
                case null:
                    // Default
                    apiEnum = Egl.OPENGL_ES_API;
                    break;

                case KhronosVersion.ApiGl:
                    apiEnum = Egl.OPENGL_API;
                    break;

                case KhronosVersion.ApiVg:
                    apiEnum = Egl.OPENVG_API;
                    break;

                default:
                    throw new InvalidOperationException($"'{api}' API not available");
                }
                if (Egl.BindAPI(apiEnum) == false)
                {
                    throw new InvalidOperationException("no ES API");
                }
            }
            else if (api != null && api.Api != KhronosVersion.ApiGles2 && api.Api != KhronosVersion.ApiGles1)
            {
                throw new InvalidOperationException($"'{api}' API not available");
            }

            // Create context
            if ((context = Egl.CreateContext(Display, _Config, sharedContext, attribsList)) == IntPtr.Zero)
            {
                throw new EglException(Egl.GetError());
            }

            // Create native surface (pixel format pending)
            // @todo Back-buffer?
            if (_NativeSurface != null && _NativeSurface.Handle == IntPtr.Zero)
            {
                _NativeSurface.CreateHandle(_Config, new[] { Egl.NONE });
            }

            return(context);
        }
        /// <summary>
        /// Set the device pixel format.
        /// </summary>
        /// <param name="pixelFormat">
        /// A <see cref="DevicePixelFormat"/> that specifies the pixel format to set.
        /// </param>
        private static IntPtr ChoosePixelFormat(IntPtr display, KhronosVersion version, DevicePixelFormat pixelFormat)
        {
            if (version == null)
            {
                throw new ArgumentNullException(nameof(version));
            }
            if (pixelFormat == null)
            {
                throw new ArgumentNullException(nameof(pixelFormat));
            }

            List <int> configAttribs = new List <int>();

            int[]    configCount = new int[1];
            IntPtr[] configs     = new IntPtr[8];
            int      surfaceType = 0;

            if (version >= Egl.Version_120)
            {
                configAttribs.AddRange(new[] { Egl.RENDERABLE_TYPE, Egl.OPENGL_ES2_BIT });
            }

            if (pixelFormat.RenderWindow)
            {
                surfaceType |= Egl.WINDOW_BIT;
            }
            if (pixelFormat.RenderPBuffer)
            {
                surfaceType |= Egl.PBUFFER_BIT;
            }
            if (surfaceType != 0)
            {
                configAttribs.AddRange(new[] { Egl.SURFACE_TYPE, surfaceType });
            }

            switch (pixelFormat.ColorBits)
            {
            case 24:
                configAttribs.AddRange(new[] { Egl.RED_SIZE, 8, Egl.GREEN_SIZE, 8, Egl.BLUE_SIZE, 8 });
                break;

            case 32:
                configAttribs.AddRange(new[] { Egl.RED_SIZE, 8, Egl.GREEN_SIZE, 8, Egl.BLUE_SIZE, 8, Egl.ALPHA_SIZE, 8 });
                break;

            default:
                configAttribs.AddRange(new[] { Egl.BUFFER_SIZE, pixelFormat.ColorBits });
                break;
            }
            if (pixelFormat.DepthBits > 0)
            {
                configAttribs.AddRange(new[] { Egl.DEPTH_SIZE, pixelFormat.DepthBits });
            }
            if (pixelFormat.StencilBits > 0)
            {
                configAttribs.AddRange(new[] { Egl.STENCIL_SIZE, pixelFormat.StencilBits });
            }

            configAttribs.Add(Egl.NONE);

            if (Egl.ChooseConfig(display, configAttribs.ToArray(), configs, configs.Length, configCount) == false)
            {
                throw new InvalidOperationException("unable to choose configuration");
            }
            if (configCount[0] == 0)
            {
                throw new InvalidOperationException("no available configuration");
            }

            return(configs[0]);
        }
Exemple #13
0
 /// <summary>
 /// Bind a single OpenGL delegates to a specific API.
 /// </summary>
 /// <param name="version">
 /// A <see cref="KhronosVersion"/> that specifies the API to bind.
 /// </param>
 /// <param name="extensions">
 /// A <see cref="KhronosApi.ExtensionsCollection"/> that specifies the extensions supported. It can be null.
 /// </param>
 /// <param name="functionName">
 /// A <see cref="String"/> that specifies the name of the function to bind.
 /// </param>
 internal static void BindAPIFunction(KhronosVersion version, ExtensionsCollection extensions, string functionName)
 {
     BindAPIFunction <Gl>(GetPlatformLibrary(version), functionName, GetProcAddressGLOS, version, extensions);
 }
Exemple #14
0
 /// <summary>
 /// Check whether commands implemented by the current driver have a corresponding extension not enabled by driver.
 /// </summary>
 public static void EnableExperimentalExtensions(KhronosVersion version, Extensions extensions)
 {
     CheckExtensionCommands <Gl>(version, extensions, true);
 }
Exemple #15
0
 /// <summary>
 /// Bind the OpenGL delegates for the API corresponding to the specified OpenGL API.
 /// </summary>
 /// <param name="version">
 /// A <see cref="KhronosVersion"/> that specifies the API to bind.
 /// </param>
 /// <param name="extensions">
 /// A <see cref="ExtensionsCollection"/> that specifies the extensions supported. It can be null.
 /// </param>
 public static void BindAPI(KhronosVersion version, ExtensionsCollection extensions)
 {
     BindAPI(version, extensions, GetProcAddress.GetProcAddressGL);
 }
Exemple #16
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, KhronosVersion version, ExtensionsCollection extensions)
 {
     BindAPIFunction <T>(path, functionName, GetProcAddress.GetProcAddressOS, version, extensions);
 }
            /// <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");
                }

                var graphicsLimits = new Limits();
                IEnumerable <FieldInfo> graphicsLimitsFields = typeof(Limits).GetTypeInfo().DeclaredFields;

                // Supress errors. Some limits might be missing from certain drivers and versions.
                SuppressingErrors = true;

                foreach (FieldInfo field in graphicsLimitsFields)
                {
                    var graphicsLimitAttribute = (LimitAttribute)field.GetCustomAttribute(typeof(LimitAttribute));
                    if (graphicsLimitAttribute == null)
                    {
                        continue;
                    }

                    // Check extension support
                    Attribute[] graphicsExtensionAttributes = new List <Attribute>(field.GetCustomAttributes(typeof(RequiredByFeatureAttribute))).ToArray();
                    if (graphicsExtensionAttributes != null && graphicsExtensionAttributes.Length > 0)
                    {
                        bool supported = Array.Exists(graphicsExtensionAttributes, delegate(Attribute item)
                        {
                            var featureAttribute = (RequiredByFeatureAttribute)item;
                            return(featureAttribute.IsSupported(version, glExtensions));
                        });

                        if (!supported)
                        {
                            continue;
                        }
                    }

                    // Determine which method is used to get the OpenGL limit
                    MethodInfo getMethod;
                    if (field.FieldType != typeof(string))
                    {
                        getMethod = typeof(Gl).GetMethod("Get", field.FieldType.IsArray ? new[] { typeof(int), field.FieldType } : new[] { typeof(int), field.FieldType.MakeByRefType() });
                    }
                    else
                    {
                        getMethod = typeof(Gl).GetMethod("GetString", new[] { typeof(int) });
                    }

                    if (getMethod == null)
                    {
                        Engine.Log.Error($"GraphicsLimits field " + field.Name + " doesn't have a OpenGL compatible type.", MessageSource.GL);
                        continue;
                    }

                    if (field.FieldType != typeof(string))
                    {
                        object obj = field.FieldType.IsArray == false
                            ? Activator.CreateInstance(field.FieldType)
                            : Array.CreateInstance(field.FieldType.GetElementType(), (int)graphicsLimitAttribute.ArrayLength);

                        try
                        {
                            object[] @params = { graphicsLimitAttribute.EnumValue, obj };
                            getMethod.Invoke(null, @params);
                            field.SetValue(graphicsLimits, @params[1]);
                        }
                        catch (TargetInvocationException exception)
                        {
                            Engine.Log.Error($"Getting {field.Name} (0x{graphicsLimitAttribute.EnumValue:X4}): {exception.InnerException?.Message}", MessageSource.GL);
                        }
                    }
                    else
                    {
                        try
                        {
                            var s = (string)getMethod.Invoke(null, new object[] { graphicsLimitAttribute.EnumValue });
                            field.SetValue(graphicsLimits, s);
                        }
                        catch (TargetInvocationException exception)
                        {
                            Engine.Log.Error($"Getting {field.Name} (0x{graphicsLimitAttribute.EnumValue}): {exception.InnerException?.Message}", MessageSource.GL);
                        }
                    }
                }

                SuppressingErrors = false;
                return(graphicsLimits);
            }
Exemple #18
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("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
        }
Exemple #19
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 !NETCORE
            Attribute[] attrRequired = Attribute.GetCustomAttributes(function, typeof(RequiredByFeatureAttribute));
#else
            Attribute[] attrRequired = new List <Attribute>(function.GetCustomAttributes(typeof(RequiredByFeatureAttribute))).ToArray();
#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 !NETCORE
                Attribute[] attrRemoved = Attribute.GetCustomAttributes(function, typeof(RemovedByFeatureAttribute));
#else
                Attribute[] attrRemoved = new List <Attribute>(function.GetCustomAttributes(typeof(RemovedByFeatureAttribute))).ToArray();
#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 #20
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
            }
        }
Exemple #21
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="revision">
 /// A <see cref="Int32"/> that specifies that revision 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"/> or
 /// <paramref name="revision"/> are less than 0.
 /// </exception>
 /// <exception cref="ArgumentNullException">
 /// Exception thrown if <paramref name="api"/> is null.
 /// </exception>
 public CoreExtensionAttribute(int major, int minor, int revision, string api)
 {
     Version = new KhronosVersion(major, minor, revision, api);
 }
            /// <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);
            }
Exemple #23
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 (version == null)
                {
                    throw new ArgumentNullException("version");
                }
                if (extensions == null)
                {
                    throw new ArgumentNullException("extensions");
                }

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

                // Set all extension fields
                Type thisType = GetType();

                foreach (FieldInfo fieldInfo in thisType.GetFields(BindingFlags.Instance | BindingFlags.Public))
                {
                    // Check boolean field (defensive)
                    Debug.Assert(fieldInfo.FieldType == typeof(bool));
                    if (fieldInfo.FieldType != typeof(bool))
                    {
                        continue;
                    }

                    bool support = false;

                    // Support by extension
                    Attribute[] coreAttributes = Attribute.GetCustomAttributes(fieldInfo, typeof(CoreExtensionAttribute));
                    if ((coreAttributes != null) && (coreAttributes.Length > 0))
                    {
                        foreach (CoreExtensionAttribute coreAttribute in coreAttributes)
                        {
                            if (version.Api == coreAttribute.Version.Api && version >= coreAttribute.Version)
                            {
                                support |= true;
                                break;
                            }
                        }
                    }

                    // Support by extension
                    Attribute[] extensionAttributes = Attribute.GetCustomAttributes(fieldInfo, typeof(ExtensionAttribute));
                    if ((extensionAttributes != null) && (extensionAttributes.Length > 0))
                    {
                        foreach (ExtensionAttribute extensionAttribute in extensionAttributes)
                        {
                            if (_ExtensionsRegistry.ContainsKey(extensionAttribute.ExtensionName))
                            {
                                support |= true;
                                break;
                            }
                        }
                    }

                    fieldInfo.SetValue(this, support);
                }
            }
        /// <summary>
        /// Creates a context, specifying attributes.
        /// </summary>
        /// <param name="sharedContext">
        /// A <see cref="IntPtr"/> that specify a context that will share objects with the returned one. If
        /// it is IntPtr.Zero, no sharing is performed.
        /// </param>
        /// <param name="attribsList">
        /// A <see cref="T:Int32[]"/> that specifies the attributes list.
        /// </param>
        /// <param name="api">
        /// A <see cref="KhronosVersion"/> that specifies the API to be implemented by the returned context. It can be null indicating the
        /// default API for this DeviceContext implementation. If it is possible, try to determine the API version also.
        /// </param>
        /// <returns>
        /// A <see cref="IntPtr"/> that represents the handle of the created context. If the context cannot be
        /// created, it returns IntPtr.Zero.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <see cref="attribsList"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Exception thrown if <paramref name="attribsList"/> length is zero or if the last item of <paramref name="attribsList"/>
        /// is not zero.
        /// </exception>
        public override IntPtr CreateContextAttrib(IntPtr sharedContext, int[] attribsList, KhronosVersion api)
        {
            if ((attribsList != null) && (attribsList.Length == 0))
            {
                throw new ArgumentException("zero length array", "attribsList");
            }
            if ((attribsList != null) && (attribsList[attribsList.Length - 1] != 0))
            {
                throw new ArgumentException("not zero-terminated array", "attribsList");
            }

            if (api != null && api.Api != KhronosVersion.ApiGl)
            {
                List <int> adulteredAttribs = new List <int>(attribsList);

                // Support check
                switch (api.Api)
                {
                case KhronosVersion.ApiGles1:
                case KhronosVersion.ApiGles2:
                    if (Wgl.CurrentExtensions.CreateContextEsProfile_EXT == false)
                    {
                        throw new NotSupportedException("OpenGL ES API not supported");
                    }
                    break;

                default:
                    throw new NotSupportedException(String.Format("'{0}' API not supported", api.Api));
                }

                // Remove trailing 0
                if (adulteredAttribs.Count > 0 && adulteredAttribs[adulteredAttribs.Count - 1] == Gl.NONE)
                {
                    adulteredAttribs.RemoveAt(adulteredAttribs.Count - 1);
                }

                // Add required attributes
                int majorVersionIndex = adulteredAttribs.FindIndex(delegate(int item) { return(item == Wgl.CONTEXT_MAJOR_VERSION_ARB); });
                int minorVersionIndex = adulteredAttribs.FindIndex(delegate(int item) { return(item == Wgl.CONTEXT_MINOR_VERSION_ARB); });
                int profileMaskIndex  = adulteredAttribs.FindIndex(delegate(int item) { return(item == Wgl.CONTEXT_PROFILE_MASK_ARB); });

                if (majorVersionIndex < 0)
                {
                    adulteredAttribs.AddRange(new int[] { Gl.MAJOR_VERSION, api.Major });
                    majorVersionIndex = adulteredAttribs.Count - 2;
                }

                if (minorVersionIndex < 0)
                {
                    adulteredAttribs.AddRange(new int[] { Gl.MINOR_VERSION, api.Minor });
                    minorVersionIndex = adulteredAttribs.Count - 2;
                }

                if (profileMaskIndex < 0)
                {
                    adulteredAttribs.AddRange(new int[] { Gl.CONTEXT_PROFILE_MASK, 0 });
                    profileMaskIndex = adulteredAttribs.Count - 2;
                }

                switch (api.Api)
                {
                case KhronosVersion.ApiGles1:
                    // Ignore API version: force always to 1.0
                    adulteredAttribs[majorVersionIndex + 1] = 1;
                    adulteredAttribs[minorVersionIndex + 1] = 0;
                    adulteredAttribs[profileMaskIndex + 1] |= (int)Wgl.CONTEXT_ES_PROFILE_BIT_EXT;
                    break;

                case KhronosVersion.ApiGles2:
                    // Uses API version: it may be greater than 2.0(?)
                    adulteredAttribs[majorVersionIndex + 1] = 2;
                    adulteredAttribs[minorVersionIndex + 1] = 0;
                    adulteredAttribs[profileMaskIndex + 1] |= (int)Wgl.CONTEXT_ES_PROFILE_BIT_EXT;
                    break;

                default:
                    Debug.Fail("API not implemented");
                    throw new NotSupportedException(String.Format("'{0}' API not supported", api.Api));
                }

                // Restore trailing 0
                adulteredAttribs.Add(Gl.NONE);

                return(Wgl.CreateContextAttribsARB(_DeviceContext, sharedContext, adulteredAttribs.ToArray()));
            }
            else
            {
                return(Wgl.CreateContextAttribsARB(_DeviceContext, sharedContext, attribsList));
            }
        }
Exemple #25
0
        /// <summary>
        /// Link delegates fields using import declarations, using platform specific method for determining procedures addresses.
        /// </summary>
        /// <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>
        /// <exception cref="ArgumentNullException">
        /// Exception thrown if <paramref name="imports"/> or <paramref name="delegates"/> is null.
        /// </exception>
        internal static void BindAPI <T>(string path, IGetProcAddress getProcAddress, KhronosVersion version, ExtensionsCollection extensions)
        {
            BindAPI <T>(path, delegate(string libpath, string function) {
                // Note: IGetProcAddress implementation may have GetOpenGLProcAddress equivalent to GetProcAddress
                IntPtr procAddress = getProcAddress.GetOpenGLProcAddress(function);

                if (procAddress == IntPtr.Zero)
                {
                    return(GetProcAddress.GetProcAddressOS.GetProcAddress(libpath, function));
                }

                if (procAddress == IntPtr.Zero)
                {
                    LogComment("Warning: no address for command {0}.", function);
                }

                return(procAddress);
            }, version, extensions);
        }
Exemple #26
0
        /// <summary>
        /// Initialize OpenGL namespace static environment. This method shall be called before any other classes methods.
        /// </summary>
        public static void Initialize()
        {
            if (_Initialized == true)
            {
                return;                 // Already initialized
            }
            _Initialized = true;

            // Before linking procedures, append ANGLE directory in path
            string assemblyPath = GetAssemblyLocation();
            string anglePath    = null;

            switch (Platform.CurrentPlatformId)
            {
            case Platform.Id.WindowsNT:
                if (assemblyPath != null)
                {
#if DEBUG
                    if (IntPtr.Size == 8)
                    {
                        anglePath = Path.Combine(assemblyPath, @"ANGLE\winrt10d\x64");
                    }
                    else
                    {
                        anglePath = Path.Combine(assemblyPath, @"ANGLE\winrt10d\x86");
                    }
#else
                    if (IntPtr.Size == 8)
                    {
                        anglePath = Path.Combine(assemblyPath, @"ANGLE\winrt10\x64");
                    }
                    else
                    {
                        anglePath = Path.Combine(assemblyPath, @"ANGLE\winrt10\x86");
                    }
#endif
                }
                break;

            case Platform.Id.Linux:
                // Note: on RPi libEGL.so depends on libGLESv2.so, so it's required to pre-load the shared library
                // Note: maybe a configurable and generic method for pre-loading assemblies may be introduced
                GetProcAddressLinux.GetLibraryHandle("libGLESv2.so", false);
                break;
            }

            // Include ANGLE path, if any
#if NETSTANDARD1_1
            if (anglePath != String.Empty)
            {
                OpenGL.GetProcAddressOS.AddLibraryDirectory(Path.Combine(assemblyPath, anglePath));
            }
#else
            if (anglePath != null && Directory.Exists(anglePath))
            {
                OpenGL.GetProcAddressOS.AddLibraryDirectory(Path.Combine(assemblyPath, anglePath));
            }
#endif

            // Load procedures
            BindAPI();

            if (IsAvailable == false)
            {
                return;
            }

#if DEBUG
            string envEglInit = Environment.GetEnvironmentVariable("EGL_INIT");

            if (envEglInit != null && envEglInit == "NO")
            {
                return;
            }
#endif

            // Platform initialization
            EglEventArgs args = new EglEventArgs();

            RaiseEglInitializing(args);

            // Get EGL information
            IntPtr eglDisplay = Egl.GetDisplay(args.Display);

            try {
                if (Initialize(eglDisplay, null, null) == false)
                {
                    throw new InvalidOperationException("unable to initialize EGL");
                }

                // Query EGL version
                string eglVersionString = QueryString(eglDisplay, VERSION);
                _CurrentVersion = KhronosVersion.Parse(eglVersionString, KhronosVersion.ApiEgl);
                // Query EGL vendor
                _Vendor = QueryString(eglDisplay, VENDOR);
                // Client APIs
                List <string> clientApis = new List <string>();

                if (_CurrentVersion >= Version_120)
                {
                    string   clientApisString = QueryString(eglDisplay, CLIENT_APIS);
                    string[] clientApiTokens  = System.Text.RegularExpressions.Regex.Split(clientApisString, " ");

                    foreach (string api in DeviceContextEGL.ConvertApiNames(clientApiTokens))
                    {
                        clientApis.Add(api);
                    }
                }

                _AvailableApis = clientApis.ToArray();

                // Null device context for querying extensions
                using (DeviceContextEGL deviceContext = new DeviceContextEGL(args.Display, IntPtr.Zero)) {
                    _CurrentExtensions = new Extensions();
                    _CurrentExtensions.Query(deviceContext);
                }
            } finally {
                Terminate(eglDisplay);
            }
        }
Exemple #27
0
        /// <summary>
        /// Initialize OpenGL namespace static environment. This method shall be called before any other classes methods.
        /// </summary>
        public static void Initialize()
        {
            if (_Initialized == true)
            {
                return;                 // Already initialized
            }
            _Initialized = true;
#if !NETSTANDARD1_1
            // Optional initialization
            string envGlInit = Environment.GetEnvironmentVariable("OPENGL_NET_INIT");
            if (envGlInit != null && envGlInit == "NO")
            {
                return;
            }
#endif
            // Environment options
            LogComment("OpenGL.Net is initializing");

            // Loader function			OS API			GL API
            // ------------------------------------------------------
            // Supported platform: Windows
            // wglGetProcAddress		WGL				GL
            // wglGetProcAddress		WGL				GLES2+ (with WGL_create_context_es(2)?_profile_EXT)
            // eglGetProcAddress		EGL(Angle)		GLES2+
            // ------------------------------------------------------
            // Supported platform: Linux
            // glXGetProcAddress		GLX				GL
            // glXGetProcAddress		GLX				GLES2+ (with GLX_create_context_es(2)?_profile_EXT)
            // eglGetProcAddress		EGL				GLES2+
            // ------------------------------------------------------
            // Supported platform: Android
            // eglGetProcAddress		EGL				GL
            // eglGetProcAddress		EGL				GLES2+

            try {
#if !MONODROID
                // Determine whether use EGL as device context backend
                if (Egl.IsAvailable)
                {
                    switch (Platform.CurrentPlatformId)
                    {
                    case Platform.Id.Linux:
                        if (Glx.IsAvailable == false)
                        {
                            Egl.IsRequired = true;
                        }
                        break;
                    }
                }
#endif

                // Create native window for getting preliminary information on desktop systems
                // This instance will be used for creating contexts without explictly specify a window
                _NativeWindow = DeviceContext.CreateHiddenWindow();

                // Create device context
                using (DeviceContext windowDevice = DeviceContext.Create()) {
                    // Create basic OpenGL context
                    IntPtr renderContext = windowDevice.CreateSimpleContext();
                    if (renderContext == IntPtr.Zero)
                    {
                        throw new NotImplementedException("unable to create a simple context");
                    }

                    // Make contect current
                    if (windowDevice.MakeCurrent(renderContext) == false)
                    {
                        throw new InvalidOperationException("unable to make current", windowDevice.GetPlatformException());
                    }

#if !MONODROID
                    // Reload platform function pointers, if required
                    if (Egl.IsRequired == false)
                    {
                        switch (Platform.CurrentPlatformId)
                        {
                        case Platform.Id.WindowsNT:
                            Wgl.BindAPI();
                            break;
                        }
                    }
#endif

                    // Query OpenGL informations
                    string glVersion = GetString(StringName.Version);
                    _CurrentVersion = KhronosVersion.Parse(glVersion);

                    // Query OpenGL extensions (current OpenGL implementation, CurrentCaps)
                    _CurrentExtensions = new Extensions();
                    _CurrentExtensions.Query();
                    // Query platform extensions
                    windowDevice.QueryPlatformExtensions();
                    // Query OpenGL limits
                    _CurrentLimits = Limits.Query(Gl.CurrentVersion, _CurrentExtensions);

                    // Obtain current OpenGL Shading Language version
                    string glslVersion = null;

                    switch (_CurrentVersion.Api)
                    {
                    case KhronosVersion.ApiGl:
                        if (_CurrentVersion >= Version_200 || _CurrentExtensions.ShadingLanguage100_ARB)
                        {
                            glslVersion = GetString(StringName.ShadingLanguageVersion);
                        }
                        break;

                    case KhronosVersion.ApiGles2:
                        glslVersion = GetString(StringName.ShadingLanguageVersion);
                        break;
                    }

                    if (glslVersion != null)
                    {
                        _CurrentShadingVersion = GlslVersion.Parse(glslVersion, _CurrentVersion.Api);
                    }

                    // Vendor/Render information
                    _Vendor   = GetString(StringName.Vendor);
                    _Renderer = GetString(StringName.Renderer);

                    if (EnvDebug || EnvExperimental)
                    {
                        Debug.Assert(CurrentVersion != null && CurrentExtensions != null);
                        CheckExtensionCommands <Gl>(CurrentVersion, CurrentExtensions, EnvExperimental);
                    }

                    // Before deletion, make uncurrent
                    windowDevice.MakeCurrent(IntPtr.Zero);
                    // Detroy context
                    if (windowDevice.DeleteContext(renderContext) == false)
                    {
                        throw new InvalidOperationException("unable to delete OpenGL context");
                    }
                }

                LogComment("OpenGL.Net has been initialized");
            } catch (Exception excepton) {
                _InitializationException = excepton;
                LogComment("Unable to initialize OpenGL.Net: {0}", _InitializationException.ToString());
            }
        }
Exemple #28
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, IGetProcAddress 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");
            }

            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));
            }

            BindAPIFunction(path, delegate(string libpath, string function) {
                // Note: IGetProcAddress implementation may have GetOpenGLProcAddress equivalent to GetProcAddress
                IntPtr procAddress = getProcAddress.GetOpenGLProcAddress(function);

                if (procAddress == IntPtr.Zero)
                {
                    return(GetProcAddress.GetProcAddressOS.GetProcAddress(libpath, function));
                }

                return(procAddress);
            }, functionContext, functionField, version, extensions);
        }
Exemple #29
0
 /// <summary>
 /// Creates a context, specifying attributes.
 /// </summary>
 /// <param name="sharedContext">
 /// A <see cref="IntPtr"/> that specify a context that will share objects with the returned one. If
 /// it is IntPtr.Zero, no sharing is performed.
 /// </param>
 /// <param name="attribsList">
 /// A <see cref="T:Int32[]"/> that specifies the attributes list. The attribute list is dependent on the actual
 /// platform and the GL version and extension support.
 /// </param>
 /// <param name="api">
 /// A <see cref="KhronosVersion"/> that specifies the API to be implemented by the returned context. It can be null indicating the
 /// default API for this DeviceContext implementation. If it is possible, try to determine the API version also.
 /// </param>
 /// <returns>
 /// A <see cref="IntPtr"/> that represents the handle of the created context. If the context cannot be
 /// created, it returns IntPtr.Zero.
 /// </returns>
 /// <exception cref="ArgumentNullException">
 /// Exception thrown if <see cref="attribsList"/> is null.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// Exception thrown if <paramref name="attribsList"/> length is zero or if the last item of <paramref name="attribsList"/>
 /// is not zero.
 /// </exception>
 public abstract IntPtr CreateContextAttrib(IntPtr sharedContext, int[] attribsList, KhronosVersion api);
Exemple #30
0
        /// <summary>
        /// Initialize OpenGL namespace static environment. This method shall be called before any other classes methods.
        /// </summary>
        public static void Initialize()
        {
            if (_Initialized == true)
            {
                return;                 // Already initialized
            }
            _Initialized = true;

            // Before linking procedures, append ANGLE directory in path
            string assemblyPath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(Egl)).Location);
            string anglePath    = null;

            switch (Platform.CurrentPlatformId)
            {
            case Platform.Id.WindowsNT:
#if DEBUG
                if (IntPtr.Size == 8)
                {
                    anglePath = Path.Combine(assemblyPath, @"ANGLE\winrt10d\x64");
                }
                else
                {
                    anglePath = Path.Combine(assemblyPath, @"ANGLE\winrt10d\x86");
                }
#else
                if (IntPtr.Size == 8)
                {
                    anglePath = Path.Combine(assemblyPath, @"ANGLE\winrt10\x64");
                }
                else
                {
                    anglePath = Path.Combine(assemblyPath, @"ANGLE\winrt10\x86");
                }
#endif
                break;

            case Platform.Id.Linux:
                // Note: on RPi libEGL.so depends on libGLESv2.so, so it's required to pre-load the shared library
                GetProcAddressX11.GetLibraryHandle("libGLESv2.so", false);
                break;
            }

            // Include ANGLE path, if any
            if (anglePath != null && Directory.Exists(anglePath))
            {
                OpenGL.GetProcAddress.GetProcAddressOS.AddLibraryDirectory(Path.Combine(assemblyPath, anglePath));
            }

            // Load procedures
            string platformLibrary = GetPlatformLibrary();
            try {
                LogComment("Querying EGL from {0}", platformLibrary);
                BindAPI <Egl>(platformLibrary, OpenGL.GetProcAddress.GetProcAddressOS);
                LogComment("EGL availability: {0}", IsAvailable);
            } catch (Exception exception) {
                /* Fail-safe (it may fail due Egl access) */
                LogComment("EGL not available:\n{0}", exception.ToString());
            }

            if (IsAvailable == false)
            {
                return;
            }

#if DEBUG
            string envEglInit = Environment.GetEnvironmentVariable("EGL_INIT");

            if (envEglInit != null && envEglInit == "NO")
            {
                return;
            }
#endif

            // Platform initialization
            EglEventArgs args = new EglEventArgs();

            RaiseEglInitializing(args);

            // Get EGL information
            IntPtr eglDisplay = Egl.GetDisplay(args.Display);

            try {
                if (Initialize(eglDisplay, null, null) == false)
                {
                    throw new InvalidOperationException("unable to initialize EGL");
                }

                // Query EGL version
                string eglVersionString = QueryString(eglDisplay, VERSION);
                _CurrentVersion = KhronosVersion.Parse(eglVersionString, KhronosVersion.ApiEgl);
                // Query EGL vendor
                _Vendor = QueryString(eglDisplay, VENDOR);
                // Client APIs
                if (_CurrentVersion >= Version_120)
                {
                    string clientApisString = QueryString(eglDisplay, CLIENT_APIS);
                    _AvailableApis = System.Text.RegularExpressions.Regex.Split(clientApisString, " ");
                }
            } finally {
                Terminate(eglDisplay);
            }
        }