private static IntPtr ChoosePixelFormat(IntPtr display, int configId) { List <int> configAttribs = new List <int>(); int[] configCount = new int[1]; IntPtr[] configs = new IntPtr[8]; configAttribs.AddRange(new int[] { Egl.CONFIG_ID, configId }); 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]); }
/// <summary> /// Initialize LTS information for the calling thread. /// </summary> public static void InitializeThread() { #if !MONODROID if (Egl.IsRequired == false) { switch (Platform.CurrentPlatformId) { case Platform.Id.WindowsNT: Wgl.BindAPI(); break; case Platform.Id.Linux: Glx.BindAPI(); break; case Platform.Id.MacOS: if (Glx.IsRequired) { Glx.BindAPI(); } else { throw new NotSupportedException("platform MacOS not supported without Glx.IsRequired=true"); } break; case Platform.Id.Android: Egl.BindAPI(); break; default: throw new NotSupportedException(String.Format("platform {0} not supported", Platform.CurrentPlatformId)); } } else #endif Egl.BindAPI(); }
/// <summary> /// Set the device pixel format. /// </summary> /// <param name="pixelFormat"> /// A <see cref="DevicePixelFormat"/> that specifies the pixel format to set. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="pixelFormat"/> is null. /// </exception> public override void SetPixelFormat(DevicePixelFormat pixelFormat) { if (pixelFormat == null) { throw new ArgumentNullException("pixelFormat"); } if (_NativeSurface.Handle != IntPtr.Zero) { throw new InvalidOperationException("pixel format already set"); } List <int> configAttribs = new List <int>(); if (Version >= Egl.Version_120) { configAttribs.AddRange(new int[] { Egl.RENDERABLE_TYPE, Egl.OPENGL_ES2_BIT }); } configAttribs.AddRange(new int[] { Egl.CONFIG_ID, pixelFormat.FormatIndex, }); configAttribs.Add(Egl.NONE); int[] configCount = new int[1]; IntPtr[] configs = new IntPtr[1]; if (Egl.ChooseConfig(Display, configAttribs.ToArray(), configs, 1, configCount) == false) { throw new InvalidOperationException("unable to choose configuration"); } if (configCount[0] == 0) { throw new InvalidOperationException("no available configuration"); } _Config = configs[0]; }
/// <summary> /// Control the the buffers swap of a device. /// </summary> /// <param name="interval"> /// A <see cref="Int32"/> that specifies the minimum number of video frames that are displayed /// before a buffer swap will occur. /// </param> /// <returns> /// It returns a boolean value indicating whether the operation was successful. /// </returns> public override bool SwapInterval(int interval) { return(Egl.SwapInterval(Display, interval)); }
/// <summary> /// Swap the buffers of a device. /// </summary> public override void SwapBuffers() { Egl.SwapBuffers(Display, EglSurface); }
/// <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]); }
/// <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); } }
/// <summary> /// Swap the buffers of a device. /// </summary> public override void SwapBuffers() { Egl.SwapBuffers(_Display, IntPtr.Zero); }
/// <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); } }
/// <summary> /// Control the the buffers swap of a device. /// </summary> /// <param name="interval"> /// A <see cref="System.Int32"/> that specifies the minimum number of video frames that are displayed /// before a buffer swap will occur. /// </param> /// <returns> /// It returns a boolean value indicating whether the operation was successful. /// </returns> public override bool SwapInterval(int interval) { return(Egl.SwapInterval(_Display, interval) != IntPtr.Zero); }
/// <summary> /// Makes the context current on the calling thread. /// </summary> /// <param name="ctx"> /// A <see cref="IntPtr"/> that specify the context to be current on the calling thread, bound to /// thise device context. It can be IntPtr.Zero indicating that no context will be current. /// </param> /// <returns> /// It returns a boolean value indicating whether the operation was successful. /// </returns> /// <exception cref="NotSupportedException"> /// Exception thrown if the current platform is not supported. /// </exception> public override bool MakeCurrent(IntPtr ctx) { return(Egl.MakeCurrent(_Display, IntPtr.Zero, IntPtr.Zero, ctx) != IntPtr.Zero); }
/// <summary> /// Creates a context. /// </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> /// <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="InvalidOperationException"> /// Exception thrown in the case <paramref name="sharedContext"/> is different from IntPtr.Zero, and the objects /// cannot be shared with it. /// </exception> public override IntPtr CreateContext(IntPtr sharedContext) { return(Egl.CreateContext(_Display, _Config, sharedContext, null)); }