luca-piccioni / OpenGL.Net

Modern OpenGL bindings for C#.
MIT License
570 stars 109 forks source link

OSX GLFW compatibility #21

Closed AndreaDemontis closed 7 years ago

AndreaDemontis commented 7 years ago

While working on OSX10 with mono runtime a NotImplementedException is thrown while loading the Glx delegates at the Gl initialization.

The 0.2.1 version of this library works correctly.

Is there a way to load context from glfw without using an X11 context which requires an xquartz installation on OSX?

luca-piccioni commented 7 years ago

Personally I've never run anything on OSX. Can you give me the exception stack trace/message?

I remembered that native window system offers AGL, but the documentation declares all functions deprecated. I guess that EGL is the way to go, but I cannot be sure of that. (Anyway I still need to add P/Invokes).

Try to setup an EGL device context by setting Egl.IsRequired = true before creating device contextes. However, it will be a long journey because, I've never run OpenGL desktop on EGL (only ES2 on windows via ANGLE), even on Mac OS. Doing so the OpenGL ES entry points are loaded from libGLESv2.dll, that need a dllmap element in the application configuration. EGL functions are loaded from libEGL.dll.

What's wrong with Quartz? And why do you use glfw with OpenGL.Net?

AndreaDemontis commented 7 years ago

This is the exception with the stack trace.

System.TypeInitializationException: The type initializer for 'OpenGL.Gl' threw an exception. ---> System.TypeInitializationException: The type initializer for 'OpenGL.Glx' threw an exception. ---> System.NotImplementedException: The method or operation is not implemented.
  at OpenGL.GetProcAddressOSX.GetProcAddress (System.String library, System.String function) [0x00000] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.GetProcAddress.GetAddress (System.String path, System.String function) [0x00010] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.KhronosApi.<LoadProcDelegates>m__1 (System.String libpath, System.String function) [0x00000] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.KhronosApi.LoadProcDelegates (System.String path, System.Collections.Generic.SortedList`2[TKey,TValue] imports, System.Collections.Generic.List`1[T] delegates, OpenGL.KhronosApi+GetAddressDelegate getAddress) [0x000cf] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.KhronosApi.LoadProcDelegates (System.String path, System.Collections.Generic.SortedList`2[TKey,TValue] imports, System.Collections.Generic.List`1[T] delegates) [0x00000] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.Glx..cctor () [0x0007d] in <c7bca9c46bd441f9984041437d307a30>:0
  --- End of inner exception stack trace ---
  at OpenGL.XServerDeviceContext.QueryVersion () [0x00021] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.XServerDeviceContext..ctor (System.IntPtr display) [0x0007e] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.XServerDeviceContext..ctor () [0x00000] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.DeviceContextFactory.Create (System.Windows.Forms.Control window) [0x00071] in <c7bca9c46bd441f9984041437d307a30>:0
  at OpenGL.Gl..cctor () [0x001d6] in <c7bca9c46bd441f9984041437d307a30>:0
  --- End of inner exception stack trace ---

I tried to set Egl.IsRequired = true with the same result.

It throws an exception on GetProcAddressOSX.GetProcAddress with parameters: (Library : libEGL.dll) (function : eglSetBlobCacheFuncsANDROID)

Anyway I'm using glfw because i need a platform-indipendent interface for the input / window handling, and for OpenGL, i found this library from the glfw wrapper repository, and it's pretty nice and updated.

luca-piccioni commented 7 years ago

It cannot work since GetProcAddressOSX.GetProcAddress always throws NotSupportedException.

Here is a patch for trying to fix the problem on OSX:

diff --git "a/C:\\Users\\Luca\\AppData\\Local\\Temp\\TortoiseGit\\Get7A67.tmp\\GetProcAddress-4607032-left.cs" "b/C:\\Users\\Luca\\Source\\Repos\\OpenGL.Net\\OpenGL.Net\\GetProcAddress.cs"
index f005565..35e4871 100644
--- "a/C:\\Users\\Luca\\AppData\\Local\\Temp\\TortoiseGit\\Get7A67.tmp\\GetProcAddress-4607032-left.cs"
+++ "b/C:\\Users\\Luca\\Source\\Repos\\OpenGL.Net\\OpenGL.Net\\GetProcAddress.cs"
@@ -595,7 +595,7 @@ namespace OpenGL
        /// </returns>
        public IntPtr GetProcAddress(IntPtr library, string function)
        {
-           throw new NotImplementedException();
+           return (GetOpenGLProcAddress(function));
        }

        /// <summary>

Let me know if you are successful. I'm very curious.

Ps: run OpenGL.Net with debugging symbol so I can get line numbers in exception stacktraces.

AndreaDemontis commented 7 years ago

Ok, i have tried with this fix, now it throws an exception on XserverDeviceContext.NativeWindow constructor on row 268

Glx.XVisualInfo visual = Glx.ChooseVisual(_Display, 0, visualAttrs);

System.TypeInitializationException: The type initializer for 'OpenGL.Gl' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object
  at OpenGL.Glx.ChooseVisual (System.IntPtr dpy, System.Int32 screen, System.Int32[] attribList) [0x0003d] in /Users/Desktop/pEngine/Build/OpenGL.Net/OpenGL.Net/Glx.VERSION_1_0.cs:461
  at OpenGL.XServerDeviceContext+NativeWindow..ctor () [0x0004f] in /Users/Desktop/pEngine/Build/OpenGL.Net/OpenGL.Net/XServerDeviceContext.cs:268
  --- End of inner exception stack trace ---
  at pEngine.Core.Graphics.API.OpenGLContext..ctor (pEngine.Platform.Context.IOpenGLContextTarget Target, System.String ContextName) [0x0001b] in /Users/Desktop/pEngine/Core/Graphics/API/OpenGLContext.cs:25
  at pEngine.Game.GraphicsInitialization () [0x00019] in /Users/Desktop/pEngine/Core/Game.cs:263
  at pEngine.Base.Timing.Loops.TimedLoop.Start () [0x0001b] in /Users/Desktop/pEngine/Base/Timing/Loops/TimedLoop.cs:34
  at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00017] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/thread.cs:68
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x0008d] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:957
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:904
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x00031] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:893
  at System.Threading.ThreadHelper.ThreadStart () [0x0000b] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/thread.cs:105

At Glx.VERSION_1_0 row 461: Delegates.pglXChooseVisual is null

I also checked Egl.IsRequired parameter, I can't set it true because IsAvailable and IsMandatory are false.

Can it be a problem of missing dylibs ? this is my OpenGL.Net.dll.config

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
    <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
    <dllmap os="osx" dll="libX11.so.6" target="/usr/X11/lib/libX11.6.dylib"/>
</configuration>
luca-piccioni commented 7 years ago

Currently, Glx delegates are mapped on libGL.so.1, so mono should find the glX* entry points in /usr/X11/lib/libGL.dylib, which it seems very unlikely.

I may guess that the correct config file is:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <dllmap os="osx" dll="opengl32.dll" target="/usr/X11/lib/libGL.dylib"/>
    <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libX11.dylib"/>
</configuration>

Instead here is mine for running on Linux:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
</configuration>

Edit: actually I do not understand how dllmap works under OSX, since the calls do not accept library names for those functions. Indeed I missed something.

However, the IGetProcAddress implementation for OSX is aligned to the one described in this link

Here the OpenTK config file: do not specifies any dllmap. Probably there are differences with OpenTK.

Can you tell me where you can find glXChooseVisual entry point?

AndreaDemontis commented 7 years ago

Ok I found a solution!

I reimplemented the GetProcAddress functions, using the same code of GetProcAddressX11.GetProcAddress because dlopen and dlsym are from unix libraries; now glXChooseVisual loads correctly but dllmapping not works for dynamic libraries loading, so I had to use the full path on Glx.Library:

private const string Library = "/usr/X11/lib/libGL.1.dylib";

instead of

private const string Library = "libGL.so.1";

Now it throw an exception on XServerDeviceContext.XServerDeviceContext

System.TypeInitializationException: The type initializer for 'OpenGL.Gl' threw an exception. ---> System.PlatformNotSupportedException: mono runtime version no supported
  at OpenGL.XServerDeviceContext..ctor (System.IntPtr windowHandle) [0x00043] in /Users/Desktop/pEngine/Build/OpenGL.Net/OpenGL.Net/XServerDeviceContext.cs:111
  at OpenGL.DeviceContext.Create (System.IntPtr windowHandle) [0x00037] in /Users/Desktop/pEngine/Build/OpenGL.Net/OpenGL.Net/DeviceContext.cs:86
  at OpenGL.Gl.Initialize () [0x0005a] in /Users/Desktop/pEngine/Build/OpenGL.Net/OpenGL.Net/Gl.cs:64
  at OpenGL.Gl..cctor () [0x001aa] in /Users/Desktop/pEngine/Build/OpenGL.Net/OpenGL.Net/Gl.cs:43
  --- End of inner exception stack trace ---
  at pEngine.Core.Graphics.API.OpenGLContext..ctor (pEngine.Platform.Context.IOpenGLContextTarget Target, System.String ContextName) [0x0001b] in /Users/Desktop/pEngine/Core/Graphics/API/OpenGLContext.cs:27
  at pEngine.Game.GraphicsInitialization () [0x00019] in /Users/Desktop/pEngine/Core/Game.cs:263
  at pEngine.Base.Timing.Loops.TimedLoop.Start () [0x0001b] in /Users/Desktop/pEngine/Base/Timing/Loops/TimedLoop.cs:34
  at System.Threading.ThreadHelper.ThreadStart_Context (System.Object state) [0x00017] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/thread.cs:68
  at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x0008d] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:957
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:904
  at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state) [0x00031] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/executioncontext.cs:893
  at System.Threading.ThreadHelper.ThreadStart () [0x0000b] in /private/tmp/source-mono-4.6.0-c8sr0/bockbuild-mono-4.6.0-branch-c8sr0/profiles/mono-mac-xamarin/build-root/mono-x86/mcs/class/referencesource/mscorlib/system/threading/thread.cs:105

I think is related to the mono runtime version, now I'm using Mono / .NET 4.5.

luca-piccioni commented 7 years ago

In this case, there should be a static property that discriminates the use of xquartz (i.e. Glx.RequiresXQuartz = true). In the case the Platform is MacOS, create a XServerDeviceContext.

Changing the library can be performed at runtime, so it should not be an issue if dllmap is not working.

The exception solution is more tricky. The XServerDeviceContext requires the display handle, which is fundamental for managing glX* functions. Where I can get the display handle?

Running Mono on Linux, the runtime exposes the System.Windows.Forms.XplatUIX11, which have static fields DisplayHandle and ScreenNo. Their values are got using reflection.

Indeed Mono on OSX have a different implementation, hence the exception. The solution is find a function related to xquartz runtime to get the display handle. Probably is sufficient to call XOpenDisplay(NULL).

AndreaDemontis commented 7 years ago

I tried with XOpenDisplay setting display number to 0, it create a context but windowDevice.MakeCurrent(renderContext) returns false.

It throws an InvalidOperationException on Gl.Initialize(): row 72

render context is not null.


I think it can be useful add a manual initialization specifying the supported GL version. If i make a glfw context, I don't know if OpenGl.Net loads the same version of OpenGL.


Update: I tried to catch Glx error with XSetErrorHandler, on MakeCurrent it returns an error code 9 : BadDrawable (invalid Pixmap or Window parameter).

luca-piccioni commented 7 years ago

If you can take comfort in, I get the same exception on Linux/GLX: BadDrawable. The problem seems related to the XServerDeviceContext.NativeWindow implementation (previously I was using a Forms instance (now decoupled from OpenGL.Net).

I'll investigate on what's going on, since I'm following the official minimal example. I swear that it worked at least one time! However, by skipping static initialization, everything go well. So there is some problem at Gl static constructor.

luca-piccioni commented 7 years ago

Ok, now it works on my Linux machine. There was wrong invocation of XCreateWindow (missing XColorMap). Indeed I'm expecting it will work on xQuartz.

AndreaDemontis commented 7 years ago

nice, now it works on xQuartz.