From 840007d2c3051836a54df0a9a7048cf41f837aff Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 02:02:19 +0530 Subject: [PATCH 01/11] .gitignore: add vscode --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c53b7bd..6038d12 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ ### VisualStudioCode ### +.vscode .vscode/* !.vscode/settings.json !.vscode/tasks.json From 4bfdfc792bf14043a37628b631ffe59cb1af98c2 Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 02:02:27 +0530 Subject: [PATCH 02/11] initial EGL support --- SPB/Platform/EGL/EGL.cs | 141 +++++++++++++++++++++++++++ SPB/Platform/EGL/EGLHelper.cs | 133 +++++++++++++++++++++++++ SPB/Platform/EGL/EGLOpenGLContext.cs | 128 ++++++++++++++++++++++++ SPB/Platform/EGL/EGLWindow.cs | 70 +++++++++++++ SPB/Platform/PlatformHelper.cs | 2 +- SPB/Platform/X11/X11.cs | 3 + SPB/Platform/X11/X11Helper.cs | 85 ++++++++++------ 7 files changed, 531 insertions(+), 31 deletions(-) create mode 100644 SPB/Platform/EGL/EGL.cs create mode 100644 SPB/Platform/EGL/EGLHelper.cs create mode 100644 SPB/Platform/EGL/EGLOpenGLContext.cs create mode 100644 SPB/Platform/EGL/EGLWindow.cs diff --git a/SPB/Platform/EGL/EGL.cs b/SPB/Platform/EGL/EGL.cs new file mode 100644 index 0000000..4215ef6 --- /dev/null +++ b/SPB/Platform/EGL/EGL.cs @@ -0,0 +1,141 @@ +using System; +using System.Runtime.InteropServices; + +using Display = System.IntPtr; +using Config = System.IntPtr; +using Surface = System.IntPtr; +using Context = System.IntPtr; +using System.Runtime.Versioning; + +namespace SPB.Platform.EGL +{ + [SupportedOSPlatform("linux")] + internal sealed class EGL + { + private const string LibraryName = "libEGL.dll"; + + static EGL() + { + NativeLibrary.SetDllImportResolver(typeof(EGL).Assembly, (name, assembly, path) => + { + if (name != LibraryName) + { + return IntPtr.Zero; + } + + if (!NativeLibrary.TryLoad("libEGL.so.1", assembly, path, out IntPtr result)) + { + if (!NativeLibrary.TryLoad("libEGL.so", assembly, path, out result)) + { + return IntPtr.Zero; + } + } + + return result; + }); + } + + [DllImport(LibraryName, EntryPoint = "eglChooseConfig")] + public unsafe extern static uint ChooseConfig(Display display, int[] attributes, IntPtr* configs, int config_size, out int num_config); + + [DllImport(LibraryName, EntryPoint = "eglGetConfigAttrib")] + public unsafe extern static uint GetConfigAttrib(Display display, Config config, int attribute, out int value); + + [DllImport(LibraryName, EntryPoint = "eglDestroyContext")] + public static extern void DestroyContext(Display display, Context context); + + [DllImport(LibraryName, EntryPoint = "eglGetCurrentContext")] + public static extern Context GetCurrentContext(); + + [DllImport(LibraryName, EntryPoint = "eglSwapBuffers")] + public static extern void SwapBuffers(Display display, Surface drawable); + + [DllImport(LibraryName, EntryPoint = "eglMakeCurrent")] + public static extern bool MakeCurrent(Display display, Surface drawable, Surface readable, Context context); + + internal enum Attribute : int + { + COLOR_BUFFER_TYPE = 0x303F, + RGB_BUFFER = 0x308E, + CONFIG_CAVEAT = 0x3027, + RENDERABLE_TYPE = 0x3040, + OPENGL_BIT = 0x0008, + CONFORMANT = 0x3042, + RED_SIZE = 0x3024, + GREEN_SIZE = 0x3023, + BLUE_SIZE = 0x3022, + ALPHA_SIZE = 0x3021, + DEPTH_SIZE = 0x3025, + STENCIL_SIZE = 0x3026, + SAMPLE_BUFFERS = 0x3032, + SAMPLES = 0x3031, + NONE = 0x3038 + } + + internal enum RenderTypeMask : int + { + COLOR_INDEX_BIT_SGIX = 0x00000002, + RGBA_BIT = 0x00000001, + RGBA_FLOAT_BIT_ARB = 0x00000004, + RGBA_BIT_SGIX = 0x00000001, + COLOR_INDEX_BIT = 0x00000002, + } + + public enum ErrorCode : int + { + EGL_SUCCESS = 0x3000, + EGL_NOT_INITIALIZED = 0x3001, + EGL_BAD_ACCESS = 0x3002, + EGL_BAD_ALLOC = 0x3003, + EGL_BAD_ATTRIBUTE = 0x3004, + EGL_BAD_CONFIG = 0x3005, + EGL_BAD_CONTEXT = 0x3006, + EGL_BAD_CURRENT_SURFACE = 0x3007, + EGL_BAD_DISPLAY = 0x3008, + EGL_BAD_MATCH = 0x3009, + EGL_BAD_NATIVE_PIXMAP = 0x300A, + EGL_BAD_NATIVE_WINDOW = 0x300B, + EGL_BAD_PARAMETER = 0x300C, + EGL_BAD_SURFACE = 0x300D, + EGL_CONTEXT_LOST = 0x300E + } + + + + internal sealed class ARB + { + public enum ContextFlags : int + { + DEBUG = 0x31B0 + } + + public enum ContextProfileFlags : int + { + CORE_PROFILE = 0x1, + COMPATIBILITY_PROFILE = 0x2, + } + + public enum CreateContextAttr : int + { + MAJOR_VERSION = 0x3098, + MINOR_VERSION = 0x30FB, + FLAGS = 0x30FC, + PROFILE_MASK = 0x30FD, + } + + [DllImport(LibraryName, EntryPoint = "eglGetProcAddress")] + public static extern IntPtr GetProcAddress(string procName); + + + [DllImport(LibraryName, EntryPoint = "eglCreateContext")] + public static extern Context CreateContext(Display display, Config config, Context shareContext, int[] attributes); + } + + internal sealed class Ext + { + [DllImport(LibraryName, EntryPoint = "eglSwapInterval")] + public static extern ErrorCode SwapInterval(Display display, int interval); + } + + } +} \ No newline at end of file diff --git a/SPB/Platform/EGL/EGLHelper.cs b/SPB/Platform/EGL/EGLHelper.cs new file mode 100644 index 0000000..d3d85a3 --- /dev/null +++ b/SPB/Platform/EGL/EGLHelper.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Versioning; +using SPB.Graphics; +using SPB.Graphics.OpenGL; + +using static SPB.Platform.X11.X11; + +namespace SPB.Platform.EGL +{ + [SupportedOSPlatform("linux")] + public sealed class EGLHelper + { + public static List FramebufferFormatToVisualAttribute(FramebufferFormat format) + { + List result = new List(); + + result.Add((int)EGL.Attribute.COLOR_BUFFER_TYPE); + result.Add((int)EGL.Attribute.RGB_BUFFER); + + result.Add((int)EGL.Attribute.RENDERABLE_TYPE); + result.Add((int)EGL.Attribute.OPENGL_BIT); + result.Add((int)EGL.Attribute.CONFORMANT); + result.Add((int)EGL.Attribute.OPENGL_BIT); + + result.Add((int)EGL.Attribute.CONFIG_CAVEAT); + result.Add((int)EGL.Attribute.NONE); + + if (format.Color.BitsPerPixel > 0) + { + result.Add((int)EGL.Attribute.RED_SIZE); + result.Add(format.Color.Red); + + result.Add((int)EGL.Attribute.GREEN_SIZE); + result.Add(format.Color.Green); + + result.Add((int)EGL.Attribute.BLUE_SIZE); + result.Add(format.Color.Blue); + + result.Add((int)EGL.Attribute.ALPHA_SIZE); + result.Add(format.Color.Alpha); + } + + if (format.DepthBits > 0) + { + result.Add((int)EGL.Attribute.DEPTH_SIZE); + result.Add(format.DepthBits); + } + + if (format.StencilBits > 0) + { + result.Add((int)EGL.Attribute.STENCIL_SIZE); + result.Add(format.StencilBits); + } + + if (format.Samples > 0) + { + result.Add((int)EGL.Attribute.SAMPLE_BUFFERS); + result.Add(1); + + result.Add((int)EGL.Attribute.SAMPLES); + result.Add((int)format.Samples); + } + + result.Add((int)EGL.Attribute.NONE); + + return result; + } + + public static IntPtr SelectFBConfig(IntPtr display, FramebufferFormat format) + { + List visualAttribute = FramebufferFormatToVisualAttribute(format); + + IntPtr result = IntPtr.Zero; + + unsafe + { + int configCnt; + int[] attribs = visualAttribute.ToArray(); + + uint res = EGL.ChooseConfig(display, attribs, (IntPtr *)IntPtr.Zero.ToPointer(), 0, out configCnt); + + if (configCnt < 0 || res != 0) + { + return IntPtr.Zero; + } + + fixed (IntPtr* fbConfig = new IntPtr[configCnt]) { + EGL.ChooseConfig(display, attribs, fbConfig, configCnt, out configCnt); + result = fbConfig[0]; + } + } + + return result; + } + + public static List GetContextCreationARBAttribute(OpenGLContextBase context) + { + List result = new List(); + + result.Add((int)EGL.ARB.CreateContextAttr.MAJOR_VERSION); + result.Add(context.Major); + + result.Add((int)EGL.ARB.CreateContextAttr.MINOR_VERSION); + result.Add(context.Minor); + + if (context.Flags != 0) + { + if (context.Flags.HasFlag(OpenGLContextFlags.Debug)) + { + result.Add((int)EGL.ARB.CreateContextAttr.FLAGS); + result.Add((int)EGL.ARB.ContextFlags.DEBUG); + } + + + result.Add((int)EGL.ARB.CreateContextAttr.PROFILE_MASK); + + if (context.Flags.HasFlag(OpenGLContextFlags.Compat)) + { + result.Add((int)EGL.ARB.ContextProfileFlags.COMPATIBILITY_PROFILE); + } + else + { + result.Add((int)EGL.ARB.ContextProfileFlags.CORE_PROFILE); + } + } + + result.Add((int)EGL.Attribute.NONE); + + return result; + } + } +} \ No newline at end of file diff --git a/SPB/Platform/EGL/EGLOpenGLContext.cs b/SPB/Platform/EGL/EGLOpenGLContext.cs new file mode 100644 index 0000000..6f40409 --- /dev/null +++ b/SPB/Platform/EGL/EGLOpenGLContext.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Versioning; +using SPB.Graphics; +using SPB.Graphics.Exceptions; +using SPB.Graphics.OpenGL; +using SPB.Windowing; + +using static SPB.Platform.X11.X11; + +namespace SPB.Platform.EGL +{ + [SupportedOSPlatform("linux")] + public class EGLOpenGLContext : OpenGLContextBase + { + private IntPtr _display; + + private NativeWindowBase _window; + + public EGLOpenGLContext(FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags = OpenGLContextFlags.Default, bool directRendering = true, OpenGLContextBase shareContext = null) : base(framebufferFormat, major, minor, flags, directRendering, shareContext) + { + _display = IntPtr.Zero; + _window = null; + } + + public override bool IsCurrent => EGL.GetCurrentContext() == ContextHandle; + + protected override void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) + { + MakeCurrent(null); + + EGL.DestroyContext(_display, ContextHandle); + } + + IsDisposed = true; + } + } + + public override IntPtr GetProcAddress(string procName) + { + return EGL.ARB.GetProcAddress(procName); + } + + public override void Initialize(NativeWindowBase window = null) + { + IntPtr display = IntPtr.Zero; + + if (window != null) + { + // TODO: Do we want to handle the window providing us a framebuffer format? + display = window.DisplayHandle.RawHandle; + } + + if (display == IntPtr.Zero) + { + display = DefaultDisplay; + } + + IntPtr fbConfig = EGLHelper.SelectFBConfig(display, FramebufferFormat); + + if (fbConfig == IntPtr.Zero) + { + // TODO: fall back to legacy API + throw new NotImplementedException("Framebuffer configuration couldn't be selected and fallback not implemented!"); + } + + List contextAttribute = EGLHelper.GetContextCreationARBAttribute(this); + + IntPtr shareContextHandle = ShareContext == null ? IntPtr.Zero : ShareContext.ContextHandle; + + IntPtr context = EGL.ARB.CreateContext(display, fbConfig, shareContextHandle, contextAttribute.ToArray()); + + ContextHandle = context; + + if (ContextHandle != IntPtr.Zero) + { + _display = display; + } + + if (ContextHandle == IntPtr.Zero) + { + throw new ContextException("CreateContext() failed."); + } + } + + public override void MakeCurrent(NativeWindowBase window) + { + if (_window != null && window != null && _window.WindowHandle.RawHandle == window.WindowHandle.RawHandle && IsCurrent) + { + return; + } + + bool success; + + if (window != null) + { + if (!(window is EGLWindow)) + { + throw new InvalidOperationException($"MakeCurrent() should be used with a {typeof(EGLWindow).Name}."); + } + if (_display != window.DisplayHandle.RawHandle) + { + throw new InvalidOperationException("MakeCurrent() should be used with a window originated from the same display."); + } + + success = EGL.MakeCurrent(_display, window.WindowHandle.RawHandle, window.WindowHandle.RawHandle, ContextHandle); + } + else + + { + success = EGL.MakeCurrent(_display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + } + + if (success) + { + _window = window; + } + else + { + throw new ContextException("MakeCurrent() failed."); + } + } + } +} diff --git a/SPB/Platform/EGL/EGLWindow.cs b/SPB/Platform/EGL/EGLWindow.cs new file mode 100644 index 0000000..60b5f94 --- /dev/null +++ b/SPB/Platform/EGL/EGLWindow.cs @@ -0,0 +1,70 @@ +using SPB.Windowing; +using System.Runtime.Versioning; + +namespace SPB.Platform.EGL +{ + [SupportedOSPlatform("linux")] + public sealed class EGLWindow : SwappableNativeWindowBase + { + public override NativeHandle DisplayHandle { get; } + public override NativeHandle WindowHandle { get; } + + private uint _swapInterval; + + public bool IsDisposed { get; private set; } + + public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) + { + DisplayHandle = displayHandle; + WindowHandle = windowHandle; + + _swapInterval = 1; + } + + public override uint SwapInterval + { + // TODO: check extension support + // TODO: support MESA and SGI + // TODO: use glXQueryDrawable to query swap interval when GLX_EXT_swap_control is supported. + get + { + return _swapInterval; + } + set + { + // TODO: exception here + EGL.Ext.SwapInterval(DisplayHandle.RawHandle, (int)_swapInterval); + _swapInterval = value; + } + } + + public override void SwapBuffers() + { + EGL.SwapBuffers(DisplayHandle.RawHandle, WindowHandle.RawHandle); + } + + protected override void Dispose(bool disposing) + { + if (!IsDisposed) + { + if (disposing) + { + X11.X11.UnmapWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); + X11.X11.DestroyWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); + } + + IsDisposed = true; + } + } + + public override void Show() + { + X11.X11.MapWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); + } + + public override void Hide() + { + X11.X11.UnmapWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); + } + } +} \ No newline at end of file diff --git a/SPB/Platform/PlatformHelper.cs b/SPB/Platform/PlatformHelper.cs index 5fbbca8..324891d 100644 --- a/SPB/Platform/PlatformHelper.cs +++ b/SPB/Platform/PlatformHelper.cs @@ -17,7 +17,7 @@ public static SwappableNativeWindowBase CreateOpenGLWindow(FramebufferFormat for if (OperatingSystem.IsLinux()) { // TODO: detect X11/Wayland/DRI - return X11Helper.CreateGLXWindow(new NativeHandle(X11.X11.DefaultDisplay), format, x, y, width, height); + return X11Helper.CreateEGLWindow(new NativeHandle(X11.X11.DefaultDisplay), format, x, y, width, height); } else if (OperatingSystem.IsWindows()) { diff --git a/SPB/Platform/X11/X11.cs b/SPB/Platform/X11/X11.cs index b9131e6..d06bef6 100644 --- a/SPB/Platform/X11/X11.cs +++ b/SPB/Platform/X11/X11.cs @@ -68,6 +68,9 @@ public static int CloseDisplay(Display display) [DllImport(LibraryName, EntryPoint = "XCreateColormap")] public static extern IntPtr CreateColormap(Display display, Window window, IntPtr visual, int alloc); + [DllImport(LibraryName, EntryPoint = "XGetVisualInfo")] + public unsafe static extern X11.XVisualInfo* GetVisualInfo(Display display, long vInfoMask, out X11.XVisualInfo vInfoTemplate, out int nitemsReturn); + [DllImport("libX11-xcb", EntryPoint = "XGetXCBConnection")] public extern static IntPtr GetXCBConnection(Display display); diff --git a/SPB/Platform/X11/X11Helper.cs b/SPB/Platform/X11/X11Helper.cs index b826e27..511b178 100644 --- a/SPB/Platform/X11/X11Helper.cs +++ b/SPB/Platform/X11/X11Helper.cs @@ -1,5 +1,6 @@ using SPB.Graphics; using SPB.Platform.GLX; +using SPB.Platform.EGL; using SPB.Windowing; using System; using System.Runtime.Versioning; @@ -9,6 +10,58 @@ namespace SPB.Platform.X11 [SupportedOSPlatform("linux")] public sealed class X11Helper { + private static unsafe NativeHandle CreateX11Window(NativeHandle display, X11.XVisualInfo* visualInfo, int x, int y, int width, int height) { + if (visualInfo == null) + { + throw new NotImplementedException(); + } + + // make screen configurable? + int screen = X11.DefaultScreenLocked(display.RawHandle); + + IntPtr rootWindow = X11.RootWindow(display.RawHandle, screen); + + X11.XSetWindowAttributes attributes = new X11.XSetWindowAttributes + { + BackgroundPixel = IntPtr.Zero, + BorderPixel = IntPtr.Zero, + ColorMap = X11.CreateColormap(display.RawHandle, rootWindow, visualInfo->Visual, 0) + }; + // TODO: events + + X11.SetWindowValueMask windowValueMask = X11.SetWindowValueMask.ColorMap | X11.SetWindowValueMask.EventMask | X11.SetWindowValueMask.BackPixel | X11.SetWindowValueMask.BorderPixel; + + X11.XSetWindowAttributes* attributesPtr = &attributes; + + IntPtr rawWindowHandle = X11.CreateWindow(display.RawHandle, rootWindow, x, y, width, height, 0, visualInfo->Depth, (int)X11.CreateWindowArgs.InputOutput, visualInfo->Visual, (IntPtr)windowValueMask, (IntPtr)attributesPtr); + + if (rawWindowHandle == IntPtr.Zero) + { + throw new ApplicationException("Cannot create X window!"); + } + + return new NativeHandle(rawWindowHandle); + } + public static EGLWindow CreateEGLWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) { + unsafe { + int num_visuals = 0; + X11.XVisualInfo template = new X11.XVisualInfo(); + X11.XVisualInfo* visualInfo = X11.GetVisualInfo( + display.RawHandle, + 1, + out template, + out num_visuals + ); + + if (num_visuals != 1) { + throw new NotImplementedException(); + } + + NativeHandle windowHandle = CreateX11Window(display, visualInfo, x, y, width, height); + + return new EGLWindow(display, windowHandle); + } + } public static GLXWindow CreateGLXWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) { IntPtr fbConfig = GLXHelper.SelectFBConfig(display.RawHandle, format); @@ -27,37 +80,9 @@ public static GLXWindow CreateGLXWindow(NativeHandle display, FramebufferFormat throw new NotImplementedException(); } + NativeHandle windowHandle = CreateX11Window(display, visualInfo, x, y, width, height); - if (visualInfo == null) - { - throw new NotImplementedException(); - } - - // make screen configurable? - int screen = X11.DefaultScreenLocked(display.RawHandle); - - IntPtr rootWindow = X11.RootWindow(display.RawHandle, screen); - - X11.XSetWindowAttributes attributes = new X11.XSetWindowAttributes - { - BackgroundPixel = IntPtr.Zero, - BorderPixel = IntPtr.Zero, - ColorMap = X11.CreateColormap(display.RawHandle, rootWindow, visualInfo->Visual, 0) - }; - // TODO: events - - X11.SetWindowValueMask windowValueMask = X11.SetWindowValueMask.ColorMap | X11.SetWindowValueMask.EventMask | X11.SetWindowValueMask.BackPixel | X11.SetWindowValueMask.BorderPixel; - - X11.XSetWindowAttributes* attributesPtr = &attributes; - - IntPtr rawWindowHandle = X11.CreateWindow(display.RawHandle, rootWindow, x, y, width, height, 0, visualInfo->Depth, (int)X11.CreateWindowArgs.InputOutput, visualInfo->Visual, (IntPtr)windowValueMask, (IntPtr)attributesPtr); - - if (rawWindowHandle == IntPtr.Zero) - { - throw new ApplicationException("Cannot create X window!"); - } - - return new GLXWindow(display, new NativeHandle(rawWindowHandle)); + return new GLXWindow(display, windowHandle); } } } From 12fdc035c5bfa82c8d30853856f8635588cc9f3b Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 02:11:18 +0530 Subject: [PATCH 03/11] Platform: PlatformHelper: use egl context --- SPB/Platform/PlatformHelper.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/SPB/Platform/PlatformHelper.cs b/SPB/Platform/PlatformHelper.cs index 324891d..83cdcfb 100644 --- a/SPB/Platform/PlatformHelper.cs +++ b/SPB/Platform/PlatformHelper.cs @@ -1,7 +1,7 @@ using SPB.Graphics; using SPB.Graphics.Exceptions; using SPB.Graphics.OpenGL; -using SPB.Platform.GLX; +using SPB.Platform.EGL; using SPB.Platform.X11; using SPB.Platform.WGL; using SPB.Platform.Win32; @@ -32,13 +32,11 @@ public static OpenGLContextBase CreateOpenGLContext(FramebufferFormat framebuffe { if (OperatingSystem.IsLinux()) { - // TODO: detect X11/Wayland/DRI - if (shareContext != null && !(shareContext is GLXOpenGLContext)) + if (shareContext != null && !(shareContext is EGLOpenGLContext)) { - throw new ContextException($"shared context must be of type {typeof(GLXOpenGLContext).Name}."); + throw new ContextException($"shared context must be of type {typeof(EGLOpenGLContext).Name}."); } - - return new GLXOpenGLContext(framebufferFormat, major, minor, flags, directRendering, (GLXOpenGLContext)shareContext); + return new EGLOpenGLContext(framebufferFormat, major, minor, flags, directRendering, shareContext); } else if (OperatingSystem.IsWindows()) { From 3dcb087a98ab4119f8f6ed3ce63d36f5629b145a Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 04:42:16 +0530 Subject: [PATCH 04/11] EGL: sane usage --- SPB/Platform/EGL/EGL.cs | 23 +++++++++--- SPB/Platform/EGL/EGLHelper.cs | 53 ++++++++++++++++------------ SPB/Platform/EGL/EGLOpenGLContext.cs | 23 ++++++------ SPB/Platform/EGL/EGLWindow.cs | 14 ++++++-- SPB/Platform/X11/X11.cs | 2 +- SPB/Platform/X11/X11Helper.cs | 21 +++++++++-- 6 files changed, 94 insertions(+), 42 deletions(-) diff --git a/SPB/Platform/EGL/EGL.cs b/SPB/Platform/EGL/EGL.cs index 4215ef6..016cc59 100644 --- a/SPB/Platform/EGL/EGL.cs +++ b/SPB/Platform/EGL/EGL.cs @@ -36,29 +36,44 @@ static EGL() } [DllImport(LibraryName, EntryPoint = "eglChooseConfig")] - public unsafe extern static uint ChooseConfig(Display display, int[] attributes, IntPtr* configs, int config_size, out int num_config); + public unsafe extern static uint ChooseConfig(Display display, int* attributes, Config* configs, int config_size, int* num_config); [DllImport(LibraryName, EntryPoint = "eglGetConfigAttrib")] public unsafe extern static uint GetConfigAttrib(Display display, Config config, int attribute, out int value); [DllImport(LibraryName, EntryPoint = "eglDestroyContext")] - public static extern void DestroyContext(Display display, Context context); + public static extern uint DestroyContext(Display display, Context context); [DllImport(LibraryName, EntryPoint = "eglGetCurrentContext")] public static extern Context GetCurrentContext(); [DllImport(LibraryName, EntryPoint = "eglSwapBuffers")] - public static extern void SwapBuffers(Display display, Surface drawable); + public static extern uint SwapBuffers(Display display, Surface drawable); [DllImport(LibraryName, EntryPoint = "eglMakeCurrent")] - public static extern bool MakeCurrent(Display display, Surface drawable, Surface readable, Context context); + public static extern uint MakeCurrent(Display display, Surface drawable, Surface readable, Context context); + + [DllImport(LibraryName, EntryPoint = "eglBindAPI")] + public static extern uint BindApi(int api); + + [DllImport(LibraryName, EntryPoint = "eglInitialize")] + public static extern uint Initialize(Display display, IntPtr major, IntPtr minor); + + [DllImport(LibraryName, EntryPoint = "eglGetPlatformDisplay")] + public unsafe static extern Display GetPlatformDisplay(int platform, IntPtr nativeDisplay, IntPtr* attribList); + + [DllImport(LibraryName, EntryPoint = "eglCreateWindowSurface")] + public unsafe static extern Surface CreateWindowSurface(Display display, Config config, IntPtr nativeWindow, IntPtr* attribList); internal enum Attribute : int { + OPENGL_API = 0x30A2, COLOR_BUFFER_TYPE = 0x303F, RGB_BUFFER = 0x308E, CONFIG_CAVEAT = 0x3027, RENDERABLE_TYPE = 0x3040, + NATIVE_VISUAL_ID = 0x302E, + PLATFORM_X11_KHR = 0x31D5, OPENGL_BIT = 0x0008, CONFORMANT = 0x3042, RED_SIZE = 0x3024, diff --git a/SPB/Platform/EGL/EGLHelper.cs b/SPB/Platform/EGL/EGLHelper.cs index d3d85a3..515d1c5 100644 --- a/SPB/Platform/EGL/EGLHelper.cs +++ b/SPB/Platform/EGL/EGLHelper.cs @@ -4,13 +4,22 @@ using SPB.Graphics; using SPB.Graphics.OpenGL; -using static SPB.Platform.X11.X11; - namespace SPB.Platform.EGL { [SupportedOSPlatform("linux")] public sealed class EGLHelper { + + public IntPtr eglDisplay; + + public EGLHelper(IntPtr display) { + unsafe { + eglDisplay = EGL.GetPlatformDisplay((int)EGL.Attribute.PLATFORM_X11_KHR, display, (IntPtr *)IntPtr.Zero.ToPointer()); + } + EGL.Initialize(eglDisplay, IntPtr.Zero, IntPtr.Zero); + EGL.BindApi((int) EGL.Attribute.OPENGL_API); + } + public static List FramebufferFormatToVisualAttribute(FramebufferFormat format) { List result = new List(); @@ -23,9 +32,6 @@ public static List FramebufferFormatToVisualAttribute(FramebufferFormat for result.Add((int)EGL.Attribute.CONFORMANT); result.Add((int)EGL.Attribute.OPENGL_BIT); - result.Add((int)EGL.Attribute.CONFIG_CAVEAT); - result.Add((int)EGL.Attribute.NONE); - if (format.Color.BitsPerPixel > 0) { result.Add((int)EGL.Attribute.RED_SIZE); @@ -55,9 +61,6 @@ public static List FramebufferFormatToVisualAttribute(FramebufferFormat for if (format.Samples > 0) { - result.Add((int)EGL.Attribute.SAMPLE_BUFFERS); - result.Add(1); - result.Add((int)EGL.Attribute.SAMPLES); result.Add((int)format.Samples); } @@ -67,7 +70,11 @@ public static List FramebufferFormatToVisualAttribute(FramebufferFormat for return result; } - public static IntPtr SelectFBConfig(IntPtr display, FramebufferFormat format) + public unsafe IntPtr eglWindowSurface(IntPtr nativeWindowHandle, IntPtr fbConfig) { + return EGL.CreateWindowSurface(eglDisplay, fbConfig, nativeWindowHandle, (IntPtr *)IntPtr.Zero.ToPointer()); + } + + public IntPtr SelectFBConfig(FramebufferFormat format) { List visualAttribute = FramebufferFormatToVisualAttribute(format); @@ -75,26 +82,28 @@ public static IntPtr SelectFBConfig(IntPtr display, FramebufferFormat format) unsafe { - int configCnt; + int configCnt = 0; int[] attribs = visualAttribute.ToArray(); - - uint res = EGL.ChooseConfig(display, attribs, (IntPtr *)IntPtr.Zero.ToPointer(), 0, out configCnt); - - if (configCnt < 0 || res != 0) - { - return IntPtr.Zero; - } - - fixed (IntPtr* fbConfig = new IntPtr[configCnt]) { - EGL.ChooseConfig(display, attribs, fbConfig, configCnt, out configCnt); - result = fbConfig[0]; + + fixed (int* attr = &attribs[0]) { + uint res = EGL.ChooseConfig(eglDisplay, attr, (IntPtr *)IntPtr.Zero.ToPointer(), 0, &configCnt); + + if (configCnt == 0 || res == 0) + { + return IntPtr.Zero; + } + + fixed (IntPtr* fbConfig = new IntPtr[configCnt]) { + EGL.ChooseConfig(eglDisplay, attr, fbConfig, configCnt, &configCnt); + result = fbConfig[0]; + } } } return result; } - public static List GetContextCreationARBAttribute(OpenGLContextBase context) + public List GetContextCreationARBAttribute(OpenGLContextBase context) { List result = new List(); diff --git a/SPB/Platform/EGL/EGLOpenGLContext.cs b/SPB/Platform/EGL/EGLOpenGLContext.cs index 6f40409..276ded7 100644 --- a/SPB/Platform/EGL/EGLOpenGLContext.cs +++ b/SPB/Platform/EGL/EGLOpenGLContext.cs @@ -13,13 +13,13 @@ namespace SPB.Platform.EGL [SupportedOSPlatform("linux")] public class EGLOpenGLContext : OpenGLContextBase { - private IntPtr _display; + private EGLHelper _helper; + private IntPtr _nativeDisplay; private NativeWindowBase _window; public EGLOpenGLContext(FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags = OpenGLContextFlags.Default, bool directRendering = true, OpenGLContextBase shareContext = null) : base(framebufferFormat, major, minor, flags, directRendering, shareContext) { - _display = IntPtr.Zero; _window = null; } @@ -33,7 +33,7 @@ protected override void Dispose(bool disposing) { MakeCurrent(null); - EGL.DestroyContext(_display, ContextHandle); + EGL.DestroyContext(_helper.eglDisplay, ContextHandle); } IsDisposed = true; @@ -60,7 +60,9 @@ public override void Initialize(NativeWindowBase window = null) display = DefaultDisplay; } - IntPtr fbConfig = EGLHelper.SelectFBConfig(display, FramebufferFormat); + _helper = new EGLHelper(display); + + IntPtr fbConfig = _helper.SelectFBConfig(FramebufferFormat); if (fbConfig == IntPtr.Zero) { @@ -68,17 +70,17 @@ public override void Initialize(NativeWindowBase window = null) throw new NotImplementedException("Framebuffer configuration couldn't be selected and fallback not implemented!"); } - List contextAttribute = EGLHelper.GetContextCreationARBAttribute(this); + List contextAttribute = _helper.GetContextCreationARBAttribute(this); IntPtr shareContextHandle = ShareContext == null ? IntPtr.Zero : ShareContext.ContextHandle; - IntPtr context = EGL.ARB.CreateContext(display, fbConfig, shareContextHandle, contextAttribute.ToArray()); + IntPtr context = EGL.ARB.CreateContext(_helper.eglDisplay, fbConfig, shareContextHandle, contextAttribute.ToArray()); ContextHandle = context; if (ContextHandle != IntPtr.Zero) { - _display = display; + _nativeDisplay = display; } if (ContextHandle == IntPtr.Zero) @@ -102,17 +104,18 @@ public override void MakeCurrent(NativeWindowBase window) { throw new InvalidOperationException($"MakeCurrent() should be used with a {typeof(EGLWindow).Name}."); } - if (_display != window.DisplayHandle.RawHandle) + if (_nativeDisplay != window.DisplayHandle.RawHandle) { throw new InvalidOperationException("MakeCurrent() should be used with a window originated from the same display."); } + IntPtr surface = ((EGLWindow) window).windowSurface; - success = EGL.MakeCurrent(_display, window.WindowHandle.RawHandle, window.WindowHandle.RawHandle, ContextHandle); + success = EGL.MakeCurrent(_helper.eglDisplay, surface, surface, ContextHandle) != 0; } else { - success = EGL.MakeCurrent(_display, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); + success = EGL.MakeCurrent(_helper.eglDisplay, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0; } if (success) diff --git a/SPB/Platform/EGL/EGLWindow.cs b/SPB/Platform/EGL/EGLWindow.cs index 60b5f94..ded912e 100644 --- a/SPB/Platform/EGL/EGLWindow.cs +++ b/SPB/Platform/EGL/EGLWindow.cs @@ -1,5 +1,6 @@ using SPB.Windowing; using System.Runtime.Versioning; +using System; namespace SPB.Platform.EGL { @@ -13,8 +14,15 @@ public sealed class EGLWindow : SwappableNativeWindowBase public bool IsDisposed { get; private set; } - public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) + private EGLHelper _helper; + public IntPtr windowSurface; + + public EGLWindow(EGLHelper helper, IntPtr fbConfig, NativeHandle displayHandle, NativeHandle windowHandle) { + _helper = helper; + unsafe { + windowSurface = helper.eglWindowSurface(windowHandle.RawHandle, fbConfig); + } DisplayHandle = displayHandle; WindowHandle = windowHandle; @@ -33,14 +41,14 @@ public override uint SwapInterval set { // TODO: exception here - EGL.Ext.SwapInterval(DisplayHandle.RawHandle, (int)_swapInterval); + EGL.Ext.SwapInterval(_helper.eglDisplay, (int)_swapInterval); _swapInterval = value; } } public override void SwapBuffers() { - EGL.SwapBuffers(DisplayHandle.RawHandle, WindowHandle.RawHandle); + EGL.SwapBuffers(_helper.eglDisplay, WindowHandle.RawHandle); } protected override void Dispose(bool disposing) diff --git a/SPB/Platform/X11/X11.cs b/SPB/Platform/X11/X11.cs index d06bef6..b24c6d7 100644 --- a/SPB/Platform/X11/X11.cs +++ b/SPB/Platform/X11/X11.cs @@ -69,7 +69,7 @@ public static int CloseDisplay(Display display) public static extern IntPtr CreateColormap(Display display, Window window, IntPtr visual, int alloc); [DllImport(LibraryName, EntryPoint = "XGetVisualInfo")] - public unsafe static extern X11.XVisualInfo* GetVisualInfo(Display display, long vInfoMask, out X11.XVisualInfo vInfoTemplate, out int nitemsReturn); + public unsafe static extern X11.XVisualInfo* GetVisualInfo(Display display, long vInfoMask, X11.XVisualInfo* vInfoTemplate, out int nitemsReturn); [DllImport("libX11-xcb", EntryPoint = "XGetXCBConnection")] public extern static IntPtr GetXCBConnection(Display display); diff --git a/SPB/Platform/X11/X11Helper.cs b/SPB/Platform/X11/X11Helper.cs index 511b178..8529992 100644 --- a/SPB/Platform/X11/X11Helper.cs +++ b/SPB/Platform/X11/X11Helper.cs @@ -43,13 +43,30 @@ private static unsafe NativeHandle CreateX11Window(NativeHandle display, X11.XVi return new NativeHandle(rawWindowHandle); } public static EGLWindow CreateEGLWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) { + EGLHelper helper = new EGLHelper(display.RawHandle); + IntPtr fbConfig = helper.SelectFBConfig(format); + if (fbConfig == IntPtr.Zero) { + throw new NotImplementedException(); + } + unsafe { int num_visuals = 0; + int visualId = 0; + + EGL.EGL.GetConfigAttrib( + helper.eglDisplay, + fbConfig, + (int)EGL.EGL.Attribute.NATIVE_VISUAL_ID, + out visualId + ); + X11.XVisualInfo template = new X11.XVisualInfo(); + template.VisualId = (ulong) visualId; + X11.XVisualInfo* visualInfo = X11.GetVisualInfo( display.RawHandle, 1, - out template, + &template, out num_visuals ); @@ -59,7 +76,7 @@ out num_visuals NativeHandle windowHandle = CreateX11Window(display, visualInfo, x, y, width, height); - return new EGLWindow(display, windowHandle); + return new EGLWindow(helper, fbConfig, display, windowHandle); } } public static GLXWindow CreateGLXWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) From ee8672f7901aafc29cb129fab20b83a7b968012c Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 05:20:38 +0530 Subject: [PATCH 05/11] EGL: simplify usage also reduce the number of helpers --- SPB/Platform/EGL/EGLOpenGLContext.cs | 9 ++++++--- SPB/Platform/EGL/EGLWindow.cs | 22 +++++++++++++--------- SPB/Platform/X11/X11Helper.cs | 2 +- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/SPB/Platform/EGL/EGLOpenGLContext.cs b/SPB/Platform/EGL/EGLOpenGLContext.cs index 276ded7..857a5f4 100644 --- a/SPB/Platform/EGL/EGLOpenGLContext.cs +++ b/SPB/Platform/EGL/EGLOpenGLContext.cs @@ -16,6 +16,7 @@ public class EGLOpenGLContext : OpenGLContextBase private EGLHelper _helper; private IntPtr _nativeDisplay; + private IntPtr _fbConfig; private NativeWindowBase _window; public EGLOpenGLContext(FramebufferFormat framebufferFormat, int major, int minor, OpenGLContextFlags flags = OpenGLContextFlags.Default, bool directRendering = true, OpenGLContextBase shareContext = null) : base(framebufferFormat, major, minor, flags, directRendering, shareContext) @@ -53,6 +54,9 @@ public override void Initialize(NativeWindowBase window = null) { // TODO: Do we want to handle the window providing us a framebuffer format? display = window.DisplayHandle.RawHandle; + _helper = ((EGLWindow) window).helper; + } else { + _helper = new EGLHelper(display); } if (display == IntPtr.Zero) @@ -60,8 +64,6 @@ public override void Initialize(NativeWindowBase window = null) display = DefaultDisplay; } - _helper = new EGLHelper(display); - IntPtr fbConfig = _helper.SelectFBConfig(FramebufferFormat); if (fbConfig == IntPtr.Zero) @@ -69,6 +71,7 @@ public override void Initialize(NativeWindowBase window = null) // TODO: fall back to legacy API throw new NotImplementedException("Framebuffer configuration couldn't be selected and fallback not implemented!"); } + _fbConfig = fbConfig; List contextAttribute = _helper.GetContextCreationARBAttribute(this); @@ -108,7 +111,7 @@ public override void MakeCurrent(NativeWindowBase window) { throw new InvalidOperationException("MakeCurrent() should be used with a window originated from the same display."); } - IntPtr surface = ((EGLWindow) window).windowSurface; + IntPtr surface = ((EGLWindow) window).helper.eglWindowSurface(window.WindowHandle.RawHandle, _fbConfig); success = EGL.MakeCurrent(_helper.eglDisplay, surface, surface, ContextHandle) != 0; } diff --git a/SPB/Platform/EGL/EGLWindow.cs b/SPB/Platform/EGL/EGLWindow.cs index ded912e..e134f82 100644 --- a/SPB/Platform/EGL/EGLWindow.cs +++ b/SPB/Platform/EGL/EGLWindow.cs @@ -14,15 +14,19 @@ public sealed class EGLWindow : SwappableNativeWindowBase public bool IsDisposed { get; private set; } - private EGLHelper _helper; - public IntPtr windowSurface; + public EGLHelper helper; - public EGLWindow(EGLHelper helper, IntPtr fbConfig, NativeHandle displayHandle, NativeHandle windowHandle) + public EGLWindow(EGLHelper helper_, NativeHandle displayHandle, NativeHandle windowHandle) { + helper = helper_; + DisplayHandle = displayHandle; + WindowHandle = windowHandle; + + _swapInterval = 1; + } + + public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) { - _helper = helper; - unsafe { - windowSurface = helper.eglWindowSurface(windowHandle.RawHandle, fbConfig); - } + helper = new EGLHelper(displayHandle.RawHandle); DisplayHandle = displayHandle; WindowHandle = windowHandle; @@ -41,14 +45,14 @@ public override uint SwapInterval set { // TODO: exception here - EGL.Ext.SwapInterval(_helper.eglDisplay, (int)_swapInterval); + EGL.Ext.SwapInterval(helper.eglDisplay, (int)_swapInterval); _swapInterval = value; } } public override void SwapBuffers() { - EGL.SwapBuffers(_helper.eglDisplay, WindowHandle.RawHandle); + EGL.SwapBuffers(helper.eglDisplay, WindowHandle.RawHandle); } protected override void Dispose(bool disposing) diff --git a/SPB/Platform/X11/X11Helper.cs b/SPB/Platform/X11/X11Helper.cs index 8529992..1ab5dfd 100644 --- a/SPB/Platform/X11/X11Helper.cs +++ b/SPB/Platform/X11/X11Helper.cs @@ -76,7 +76,7 @@ out num_visuals NativeHandle windowHandle = CreateX11Window(display, visualInfo, x, y, width, height); - return new EGLWindow(helper, fbConfig, display, windowHandle); + return new EGLWindow(helper, display, windowHandle); } } public static GLXWindow CreateGLXWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) From 394ccbbc2f44b73fc26f1e7d50f7d1cee1d76aa1 Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 05:57:01 +0530 Subject: [PATCH 06/11] EGL: EGLHelper: fix setting debug --- SPB/Platform/EGL/EGLHelper.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SPB/Platform/EGL/EGLHelper.cs b/SPB/Platform/EGL/EGLHelper.cs index 515d1c5..c1a10ef 100644 --- a/SPB/Platform/EGL/EGLHelper.cs +++ b/SPB/Platform/EGL/EGLHelper.cs @@ -117,11 +117,10 @@ public List GetContextCreationARBAttribute(OpenGLContextBase context) { if (context.Flags.HasFlag(OpenGLContextFlags.Debug)) { - result.Add((int)EGL.ARB.CreateContextAttr.FLAGS); result.Add((int)EGL.ARB.ContextFlags.DEBUG); + result.Add(1); } - result.Add((int)EGL.ARB.CreateContextAttr.PROFILE_MASK); if (context.Flags.HasFlag(OpenGLContextFlags.Compat)) From 738dc605455a0caadea96892e4330cc587be70d2 Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 08:58:44 +0530 Subject: [PATCH 07/11] EGL: fixes and improvements properly implement SwapBuffers, Cache handles agressively --- SPB/Platform/EGL/EGL.cs | 9 +++++++++ SPB/Platform/EGL/EGLHelper.cs | 20 ++++++++++++++++---- SPB/Platform/EGL/EGLOpenGLContext.cs | 10 +++++----- SPB/Platform/EGL/EGLWindow.cs | 15 ++++++++++++++- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/SPB/Platform/EGL/EGL.cs b/SPB/Platform/EGL/EGL.cs index 016cc59..a478b7f 100644 --- a/SPB/Platform/EGL/EGL.cs +++ b/SPB/Platform/EGL/EGL.cs @@ -65,6 +65,12 @@ static EGL() [DllImport(LibraryName, EntryPoint = "eglCreateWindowSurface")] public unsafe static extern Surface CreateWindowSurface(Display display, Config config, IntPtr nativeWindow, IntPtr* attribList); + [DllImport(LibraryName, EntryPoint = "eglDestroySurface")] + public unsafe static extern uint DestroySurface(Display display, Surface surface); + + [DllImport(LibraryName, EntryPoint = "eglGetError")] + public static extern int GetError(); + internal enum Attribute : int { OPENGL_API = 0x30A2, @@ -84,6 +90,9 @@ internal enum Attribute : int STENCIL_SIZE = 0x3026, SAMPLE_BUFFERS = 0x3032, SAMPLES = 0x3031, + SURFACE_TYPE = 0x3033, + WINDOW_BIT = 0x4, + PBUFFER_BIT = 0x0001, NONE = 0x3038 } diff --git a/SPB/Platform/EGL/EGLHelper.cs b/SPB/Platform/EGL/EGLHelper.cs index c1a10ef..5391dac 100644 --- a/SPB/Platform/EGL/EGLHelper.cs +++ b/SPB/Platform/EGL/EGLHelper.cs @@ -9,14 +9,23 @@ namespace SPB.Platform.EGL [SupportedOSPlatform("linux")] public sealed class EGLHelper { + public static IntPtr _eglDisplay; + private static bool init; - public IntPtr eglDisplay; + public IntPtr eglDisplay { + get { + return _eglDisplay; + } + } public EGLHelper(IntPtr display) { - unsafe { - eglDisplay = EGL.GetPlatformDisplay((int)EGL.Attribute.PLATFORM_X11_KHR, display, (IntPtr *)IntPtr.Zero.ToPointer()); + if (!init) { + unsafe { + _eglDisplay = EGL.GetPlatformDisplay((int)EGL.Attribute.PLATFORM_X11_KHR, display, (IntPtr *)IntPtr.Zero.ToPointer()); + } + EGL.Initialize(eglDisplay, IntPtr.Zero, IntPtr.Zero); + init = true; } - EGL.Initialize(eglDisplay, IntPtr.Zero, IntPtr.Zero); EGL.BindApi((int) EGL.Attribute.OPENGL_API); } @@ -27,6 +36,9 @@ public static List FramebufferFormatToVisualAttribute(FramebufferFormat for result.Add((int)EGL.Attribute.COLOR_BUFFER_TYPE); result.Add((int)EGL.Attribute.RGB_BUFFER); + result.Add((int)EGL.Attribute.SURFACE_TYPE); + result.Add((int)EGL.Attribute.WINDOW_BIT); + result.Add((int)EGL.Attribute.RENDERABLE_TYPE); result.Add((int)EGL.Attribute.OPENGL_BIT); result.Add((int)EGL.Attribute.CONFORMANT); diff --git a/SPB/Platform/EGL/EGLOpenGLContext.cs b/SPB/Platform/EGL/EGLOpenGLContext.cs index 857a5f4..bcf099e 100644 --- a/SPB/Platform/EGL/EGLOpenGLContext.cs +++ b/SPB/Platform/EGL/EGLOpenGLContext.cs @@ -54,9 +54,6 @@ public override void Initialize(NativeWindowBase window = null) { // TODO: Do we want to handle the window providing us a framebuffer format? display = window.DisplayHandle.RawHandle; - _helper = ((EGLWindow) window).helper; - } else { - _helper = new EGLHelper(display); } if (display == IntPtr.Zero) @@ -64,6 +61,8 @@ public override void Initialize(NativeWindowBase window = null) display = DefaultDisplay; } + _helper = new EGLHelper(display); + IntPtr fbConfig = _helper.SelectFBConfig(FramebufferFormat); if (fbConfig == IntPtr.Zero) @@ -88,6 +87,7 @@ public override void Initialize(NativeWindowBase window = null) if (ContextHandle == IntPtr.Zero) { + Console.WriteLine("ERR {0}", EGL.GetError()); throw new ContextException("CreateContext() failed."); } } @@ -111,12 +111,12 @@ public override void MakeCurrent(NativeWindowBase window) { throw new InvalidOperationException("MakeCurrent() should be used with a window originated from the same display."); } - IntPtr surface = ((EGLWindow) window).helper.eglWindowSurface(window.WindowHandle.RawHandle, _fbConfig); + + IntPtr surface = ((EGLWindow) window).eglSurface(_fbConfig); success = EGL.MakeCurrent(_helper.eglDisplay, surface, surface, ContextHandle) != 0; } else - { success = EGL.MakeCurrent(_helper.eglDisplay, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero) != 0; } diff --git a/SPB/Platform/EGL/EGLWindow.cs b/SPB/Platform/EGL/EGLWindow.cs index e134f82..6e5aa71 100644 --- a/SPB/Platform/EGL/EGLWindow.cs +++ b/SPB/Platform/EGL/EGLWindow.cs @@ -15,6 +15,7 @@ public sealed class EGLWindow : SwappableNativeWindowBase public bool IsDisposed { get; private set; } public EGLHelper helper; + private IntPtr _surface = IntPtr.Zero; public EGLWindow(EGLHelper helper_, NativeHandle displayHandle, NativeHandle windowHandle) { helper = helper_; @@ -33,6 +34,15 @@ public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) _swapInterval = 1; } + public IntPtr eglSurface(IntPtr fbConfig) { + if (_surface != IntPtr.Zero) { + Console.WriteLine("true hae bosh"); + return _surface; + } + _surface = helper.eglWindowSurface(WindowHandle.RawHandle, fbConfig); + return _surface; + } + public override uint SwapInterval { // TODO: check extension support @@ -52,7 +62,7 @@ public override uint SwapInterval public override void SwapBuffers() { - EGL.SwapBuffers(helper.eglDisplay, WindowHandle.RawHandle); + EGL.SwapBuffers(helper.eglDisplay, _surface); } protected override void Dispose(bool disposing) @@ -61,6 +71,9 @@ protected override void Dispose(bool disposing) { if (disposing) { + if (_surface != IntPtr.Zero) { + EGL.DestroySurface(helper.eglDisplay, _surface); + } X11.X11.UnmapWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); X11.X11.DestroyWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); } From f42a8f0809f5ffc570e90e1272778ddab645adf0 Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 09:16:47 +0530 Subject: [PATCH 08/11] EGL: EGLWindow: remove unnecessary log --- SPB/Platform/EGL/EGLWindow.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SPB/Platform/EGL/EGLWindow.cs b/SPB/Platform/EGL/EGLWindow.cs index 6e5aa71..6e69188 100644 --- a/SPB/Platform/EGL/EGLWindow.cs +++ b/SPB/Platform/EGL/EGLWindow.cs @@ -36,7 +36,6 @@ public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) public IntPtr eglSurface(IntPtr fbConfig) { if (_surface != IntPtr.Zero) { - Console.WriteLine("true hae bosh"); return _surface; } _surface = helper.eglWindowSurface(WindowHandle.RawHandle, fbConfig); @@ -92,4 +91,4 @@ public override void Hide() X11.X11.UnmapWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); } } -} \ No newline at end of file +} From d95321fc822a00ea4aa0cc65ac4b116d29fa661e Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 21:48:06 +0530 Subject: [PATCH 09/11] EGL: Reduce redundant eglBind calls --- SPB/Platform/EGL/EGLHelper.cs | 3 +++ SPB/Platform/EGL/EGLOpenGLContext.cs | 3 ++- SPB/Platform/EGL/EGLWindow.cs | 27 +++++++++------------------ SPB/Platform/X11/X11Helper.cs | 3 ++- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/SPB/Platform/EGL/EGLHelper.cs b/SPB/Platform/EGL/EGLHelper.cs index 5391dac..64e9932 100644 --- a/SPB/Platform/EGL/EGLHelper.cs +++ b/SPB/Platform/EGL/EGLHelper.cs @@ -26,6 +26,9 @@ public EGLHelper(IntPtr display) { EGL.Initialize(eglDisplay, IntPtr.Zero, IntPtr.Zero); init = true; } + } + + public static void BindApi() { EGL.BindApi((int) EGL.Attribute.OPENGL_API); } diff --git a/SPB/Platform/EGL/EGLOpenGLContext.cs b/SPB/Platform/EGL/EGLOpenGLContext.cs index bcf099e..68b4914 100644 --- a/SPB/Platform/EGL/EGLOpenGLContext.cs +++ b/SPB/Platform/EGL/EGLOpenGLContext.cs @@ -62,6 +62,7 @@ public override void Initialize(NativeWindowBase window = null) } _helper = new EGLHelper(display); + EGLHelper.BindApi(); IntPtr fbConfig = _helper.SelectFBConfig(FramebufferFormat); @@ -112,7 +113,7 @@ public override void MakeCurrent(NativeWindowBase window) throw new InvalidOperationException("MakeCurrent() should be used with a window originated from the same display."); } - IntPtr surface = ((EGLWindow) window).eglSurface(_fbConfig); + IntPtr surface = ((EGLWindow) window).EGLSurface(_helper, _fbConfig); success = EGL.MakeCurrent(_helper.eglDisplay, surface, surface, ContextHandle) != 0; } diff --git a/SPB/Platform/EGL/EGLWindow.cs b/SPB/Platform/EGL/EGLWindow.cs index 6e69188..6bcb63c 100644 --- a/SPB/Platform/EGL/EGLWindow.cs +++ b/SPB/Platform/EGL/EGLWindow.cs @@ -14,31 +14,22 @@ public sealed class EGLWindow : SwappableNativeWindowBase public bool IsDisposed { get; private set; } - public EGLHelper helper; + private EGLHelper _helper; private IntPtr _surface = IntPtr.Zero; - public EGLWindow(EGLHelper helper_, NativeHandle displayHandle, NativeHandle windowHandle) { - helper = helper_; + public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) { DisplayHandle = displayHandle; WindowHandle = windowHandle; _swapInterval = 1; } - public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) - { - helper = new EGLHelper(displayHandle.RawHandle); - DisplayHandle = displayHandle; - WindowHandle = windowHandle; - - _swapInterval = 1; - } - - public IntPtr eglSurface(IntPtr fbConfig) { + public IntPtr EGLSurface(EGLHelper helper, IntPtr fbConfig) { if (_surface != IntPtr.Zero) { return _surface; } - _surface = helper.eglWindowSurface(WindowHandle.RawHandle, fbConfig); + _helper = helper; + _surface = _helper.eglWindowSurface(WindowHandle.RawHandle, fbConfig); return _surface; } @@ -54,14 +45,14 @@ public override uint SwapInterval set { // TODO: exception here - EGL.Ext.SwapInterval(helper.eglDisplay, (int)_swapInterval); + EGL.Ext.SwapInterval(_helper.eglDisplay, (int)_swapInterval); _swapInterval = value; } } public override void SwapBuffers() { - EGL.SwapBuffers(helper.eglDisplay, _surface); + EGL.SwapBuffers(_helper.eglDisplay, _surface); } protected override void Dispose(bool disposing) @@ -71,7 +62,7 @@ protected override void Dispose(bool disposing) if (disposing) { if (_surface != IntPtr.Zero) { - EGL.DestroySurface(helper.eglDisplay, _surface); + EGL.DestroySurface(_helper.eglDisplay, _surface); } X11.X11.UnmapWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); X11.X11.DestroyWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); @@ -91,4 +82,4 @@ public override void Hide() X11.X11.UnmapWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); } } -} +} \ No newline at end of file diff --git a/SPB/Platform/X11/X11Helper.cs b/SPB/Platform/X11/X11Helper.cs index 1ab5dfd..a53488c 100644 --- a/SPB/Platform/X11/X11Helper.cs +++ b/SPB/Platform/X11/X11Helper.cs @@ -44,6 +44,7 @@ private static unsafe NativeHandle CreateX11Window(NativeHandle display, X11.XVi } public static EGLWindow CreateEGLWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) { EGLHelper helper = new EGLHelper(display.RawHandle); + EGLHelper.BindApi(); IntPtr fbConfig = helper.SelectFBConfig(format); if (fbConfig == IntPtr.Zero) { throw new NotImplementedException(); @@ -76,7 +77,7 @@ out num_visuals NativeHandle windowHandle = CreateX11Window(display, visualInfo, x, y, width, height); - return new EGLWindow(helper, display, windowHandle); + return new EGLWindow(display, windowHandle); } } public static GLXWindow CreateGLXWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) From 924c9a46c00c81e7fa23be9baf4a8014987412d0 Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 23 Jan 2022 22:35:55 +0530 Subject: [PATCH 10/11] EGL: Attr: require HW Accel --- SPB/Platform/EGL/EGLHelper.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SPB/Platform/EGL/EGLHelper.cs b/SPB/Platform/EGL/EGLHelper.cs index 64e9932..19e2580 100644 --- a/SPB/Platform/EGL/EGLHelper.cs +++ b/SPB/Platform/EGL/EGLHelper.cs @@ -47,6 +47,9 @@ public static List FramebufferFormatToVisualAttribute(FramebufferFormat for result.Add((int)EGL.Attribute.CONFORMANT); result.Add((int)EGL.Attribute.OPENGL_BIT); + result.Add((int)EGL.Attribute.CONFIG_CAVEAT); + result.Add((int)EGL.Attribute.NONE); + if (format.Color.BitsPerPixel > 0) { result.Add((int)EGL.Attribute.RED_SIZE); @@ -153,4 +156,4 @@ public List GetContextCreationARBAttribute(OpenGLContextBase context) return result; } } -} \ No newline at end of file +} From 560bfab1e2aa419ae6984b6572b64507b8866c96 Mon Sep 17 00:00:00 2001 From: rupansh Date: Sun, 30 Jan 2022 22:27:26 +0530 Subject: [PATCH 11/11] EGL: address formatting issues --- SPB/Platform/EGL/EGL.cs | 32 +++++++++++++--------------- SPB/Platform/EGL/EGLHelper.cs | 27 +++++++++++++++-------- SPB/Platform/EGL/EGLOpenGLContext.cs | 3 +-- SPB/Platform/EGL/EGLWindow.cs | 17 ++++++++------- SPB/Platform/X11/X11Helper.cs | 16 +++++++++----- 5 files changed, 54 insertions(+), 41 deletions(-) diff --git a/SPB/Platform/EGL/EGL.cs b/SPB/Platform/EGL/EGL.cs index a478b7f..683ec47 100644 --- a/SPB/Platform/EGL/EGL.cs +++ b/SPB/Platform/EGL/EGL.cs @@ -107,25 +107,23 @@ internal enum RenderTypeMask : int public enum ErrorCode : int { - EGL_SUCCESS = 0x3000, - EGL_NOT_INITIALIZED = 0x3001, - EGL_BAD_ACCESS = 0x3002, - EGL_BAD_ALLOC = 0x3003, - EGL_BAD_ATTRIBUTE = 0x3004, - EGL_BAD_CONFIG = 0x3005, - EGL_BAD_CONTEXT = 0x3006, - EGL_BAD_CURRENT_SURFACE = 0x3007, - EGL_BAD_DISPLAY = 0x3008, - EGL_BAD_MATCH = 0x3009, - EGL_BAD_NATIVE_PIXMAP = 0x300A, - EGL_BAD_NATIVE_WINDOW = 0x300B, - EGL_BAD_PARAMETER = 0x300C, - EGL_BAD_SURFACE = 0x300D, - EGL_CONTEXT_LOST = 0x300E + SUCCESS = 0x3000, + NOT_INITIALIZED = 0x3001, + BAD_ACCESS = 0x3002, + BAD_ALLOC = 0x3003, + BAD_ATTRIBUTE = 0x3004, + BAD_CONFIG = 0x3005, + BAD_CONTEXT = 0x3006, + BAD_CURRENT_SURFACE = 0x3007, + BAD_DISPLAY = 0x3008, + BAD_MATCH = 0x3009, + BAD_NATIVE_PIXMAP = 0x300A, + BAD_NATIVE_WINDOW = 0x300B, + BAD_PARAMETER = 0x300C, + BAD_SURFACE = 0x300D, + CONTEXT_LOST = 0x300E } - - internal sealed class ARB { public enum ContextFlags : int diff --git a/SPB/Platform/EGL/EGLHelper.cs b/SPB/Platform/EGL/EGLHelper.cs index 19e2580..5dd6c9b 100644 --- a/SPB/Platform/EGL/EGLHelper.cs +++ b/SPB/Platform/EGL/EGLHelper.cs @@ -12,15 +12,20 @@ public sealed class EGLHelper public static IntPtr _eglDisplay; private static bool init; - public IntPtr eglDisplay { - get { + public IntPtr eglDisplay + { + get + { return _eglDisplay; } } - public EGLHelper(IntPtr display) { - if (!init) { - unsafe { + public EGLHelper(IntPtr display) + { + if (!init) + { + unsafe + { _eglDisplay = EGL.GetPlatformDisplay((int)EGL.Attribute.PLATFORM_X11_KHR, display, (IntPtr *)IntPtr.Zero.ToPointer()); } EGL.Initialize(eglDisplay, IntPtr.Zero, IntPtr.Zero); @@ -28,7 +33,8 @@ public EGLHelper(IntPtr display) { } } - public static void BindApi() { + public static void BindApi() + { EGL.BindApi((int) EGL.Attribute.OPENGL_API); } @@ -88,7 +94,8 @@ public static List FramebufferFormatToVisualAttribute(FramebufferFormat for return result; } - public unsafe IntPtr eglWindowSurface(IntPtr nativeWindowHandle, IntPtr fbConfig) { + public unsafe IntPtr EGLWindowSurface(IntPtr nativeWindowHandle, IntPtr fbConfig) + { return EGL.CreateWindowSurface(eglDisplay, fbConfig, nativeWindowHandle, (IntPtr *)IntPtr.Zero.ToPointer()); } @@ -103,7 +110,8 @@ public IntPtr SelectFBConfig(FramebufferFormat format) int configCnt = 0; int[] attribs = visualAttribute.ToArray(); - fixed (int* attr = &attribs[0]) { + fixed (int* attr = &attribs[0]) + { uint res = EGL.ChooseConfig(eglDisplay, attr, (IntPtr *)IntPtr.Zero.ToPointer(), 0, &configCnt); if (configCnt == 0 || res == 0) @@ -111,7 +119,8 @@ public IntPtr SelectFBConfig(FramebufferFormat format) return IntPtr.Zero; } - fixed (IntPtr* fbConfig = new IntPtr[configCnt]) { + fixed (IntPtr* fbConfig = new IntPtr[configCnt]) + { EGL.ChooseConfig(eglDisplay, attr, fbConfig, configCnt, &configCnt); result = fbConfig[0]; } diff --git a/SPB/Platform/EGL/EGLOpenGLContext.cs b/SPB/Platform/EGL/EGLOpenGLContext.cs index 68b4914..bf34fab 100644 --- a/SPB/Platform/EGL/EGLOpenGLContext.cs +++ b/SPB/Platform/EGL/EGLOpenGLContext.cs @@ -88,8 +88,7 @@ public override void Initialize(NativeWindowBase window = null) if (ContextHandle == IntPtr.Zero) { - Console.WriteLine("ERR {0}", EGL.GetError()); - throw new ContextException("CreateContext() failed."); + throw new ContextException(String.Format("CreateContext() failed: {0}", EGL.GetError())); } } diff --git a/SPB/Platform/EGL/EGLWindow.cs b/SPB/Platform/EGL/EGLWindow.cs index 6bcb63c..452a923 100644 --- a/SPB/Platform/EGL/EGLWindow.cs +++ b/SPB/Platform/EGL/EGLWindow.cs @@ -17,27 +17,27 @@ public sealed class EGLWindow : SwappableNativeWindowBase private EGLHelper _helper; private IntPtr _surface = IntPtr.Zero; - public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) { + public EGLWindow(NativeHandle displayHandle, NativeHandle windowHandle) + { DisplayHandle = displayHandle; WindowHandle = windowHandle; _swapInterval = 1; } - public IntPtr EGLSurface(EGLHelper helper, IntPtr fbConfig) { - if (_surface != IntPtr.Zero) { + public IntPtr EGLSurface(EGLHelper helper, IntPtr fbConfig) + { + if (_surface != IntPtr.Zero) + { return _surface; } _helper = helper; - _surface = _helper.eglWindowSurface(WindowHandle.RawHandle, fbConfig); + _surface = _helper.EGLWindowSurface(WindowHandle.RawHandle, fbConfig); return _surface; } public override uint SwapInterval { - // TODO: check extension support - // TODO: support MESA and SGI - // TODO: use glXQueryDrawable to query swap interval when GLX_EXT_swap_control is supported. get { return _swapInterval; @@ -61,7 +61,8 @@ protected override void Dispose(bool disposing) { if (disposing) { - if (_surface != IntPtr.Zero) { + if (_surface != IntPtr.Zero) + { EGL.DestroySurface(_helper.eglDisplay, _surface); } X11.X11.UnmapWindow(DisplayHandle.RawHandle, WindowHandle.RawHandle); diff --git a/SPB/Platform/X11/X11Helper.cs b/SPB/Platform/X11/X11Helper.cs index a53488c..2d648f0 100644 --- a/SPB/Platform/X11/X11Helper.cs +++ b/SPB/Platform/X11/X11Helper.cs @@ -10,7 +10,8 @@ namespace SPB.Platform.X11 [SupportedOSPlatform("linux")] public sealed class X11Helper { - private static unsafe NativeHandle CreateX11Window(NativeHandle display, X11.XVisualInfo* visualInfo, int x, int y, int width, int height) { + private static unsafe NativeHandle CreateX11Window(NativeHandle display, X11.XVisualInfo* visualInfo, int x, int y, int width, int height) + { if (visualInfo == null) { throw new NotImplementedException(); @@ -42,15 +43,19 @@ private static unsafe NativeHandle CreateX11Window(NativeHandle display, X11.XVi return new NativeHandle(rawWindowHandle); } - public static EGLWindow CreateEGLWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) { + + public static EGLWindow CreateEGLWindow(NativeHandle display, FramebufferFormat format, int x, int y, int width, int height) + { EGLHelper helper = new EGLHelper(display.RawHandle); EGLHelper.BindApi(); IntPtr fbConfig = helper.SelectFBConfig(format); - if (fbConfig == IntPtr.Zero) { + if (fbConfig == IntPtr.Zero) + { throw new NotImplementedException(); } - unsafe { + unsafe + { int num_visuals = 0; int visualId = 0; @@ -71,7 +76,8 @@ out visualId out num_visuals ); - if (num_visuals != 1) { + if (num_visuals != 1) + { throw new NotImplementedException(); }