luca-piccioni / OpenGL.Net

Modern OpenGL bindings for C#.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Does not seem to work on Linux targeting .NET Core

harry-cpp opened this issue · comments

commented

Seems like the initialization is failing on Linux, I'm targeting netcoreapp2.0, using the NuGet package, and a simple call to any GL API crashes the app (ie. Gl.Initialize will crash it as well).

Can you post some more information about exception? Have you tried to disable EGL (see wiki/initialize)?

commented

Can you post some more information about exception?

There is no exception message, it just crashes without one when Initialize gets called (this does happen on Linux when you get a native exception).

Have you tried to disable EGL (see wiki/initialize)?

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at OpenGL.Gl.ClearColor(Single red, Single green, Single blue, Single alpha) in C:\OpenGL.Net\OpenGL.Net\Gl.VERSION_1_0.cs:line 6157
   at Demo.Program.Main(String[] args) in /mnt/Data/Projects/SdlSharp/Demo/Program.cs:line 27

Just like the function pointers are not loaded. It seems that you manage GL context creation using SDL, don't you? If this is the case, just call Gl.BindAPI() after having made the GL context current.

commented

Just like the function pointers are not loaded. It seems that you manage GL context creation using SDL, don't you?

Yea.

If this is the case, just call Gl.BindAPI() after having made the GL context current.

Too make this quicker, can you just add the few lines of code for the initialization to the following SDL example code:

Sdl.Init(InitFlags.Everything);

var win = new Window(WindowFlags.OpenGL | WindowFlags.Resizable);
win.Show();

var ctx = win.CreateContext();
ctx.MakeCurrent();

while (true)
{
    while (Sdl.PollEvent())
    {

    }

    Gl.ClearColor(0f, 0f, 1f, 1f);
    Gl.Clear(ClearBufferMask.ColorBufferBit);

    win.SwapWindow();
}
Gl.Initialize(); // Or after Sdl.Init?

Sdl.Init(InitFlags.Everything);

var win = new Window(WindowFlags.OpenGL | WindowFlags.Resizable);
win.Show();

var ctx = win.CreateContext();
ctx.MakeCurrent();

// Load function pointers available for the current GL context
Gl.BindAPI();

while (true)
{
    while (Sdl.PollEvent())
    {

    }

    Gl.ClearColor(0f, 0f, 1f, 1f);
    Gl.Clear(ClearBufferMask.ColorBufferBit);

    win.SwapWindow();
}
commented
> dotnet run
x > 
> OPENGL_NET_EGL_STATIC_INIT=NO dotnet run

Unhandled Exception: System.TypeInitializationException: The type initializer for 'OpenGL.GetGLProcAddressGLX' threw an exception. ---> System.InvalidOperationException: unable to load library at libGL.so.1 ---> System.InvalidOperationException: l: cannot open shared object file: No such file or directory
   --- End of inner exception stack trace ---
   at Khronos.GetProcAddressLinux.GetLibraryHandle(String libraryPath, Boolean throws) in C:\OpenGL.Net\Khronos.Net\GetProcAddressOS.cs:line 421
   at Khronos.GetProcAddressLinux.GetProcAddress(String library, String function) in C:\OpenGL.Net\Khronos.Net\GetProcAddressOS.cs:line 382
   at OpenGL.GetGLProcAddressGLX..cctor() in C:\OpenGL.Net\OpenGL.Net\GetProcAddressGL.cs:line 154
   --- End of inner exception stack trace ---
   at OpenGL.GetProcAddressGL.GetProcAddress(String function) in C:\OpenGL.Net\OpenGL.Net\GetProcAddressGL.cs:line 80
   at OpenGL.KhronosApi.GetProcAddressGLOS(String path, String function) in C:\OpenGL.Net\OpenGL.Net\KhronosApi.cs:line 131
   at Khronos.KhronosApi.BindAPIFunction(String path, GetAddressDelegate getAddress, FunctionContext functionContext, FieldInfo function, KhronosVersion version, ExtensionsCollection extensions) in C:\OpenGL.Net\Khronos.Net\KhronosApi.cs:line 349
   at OpenGL.Gl.QueryContextVersionCore() in C:\OpenGL.Net\OpenGL.Net\Gl.cs:line 396
   at OpenGL.Gl.BindAPI() in C:\OpenGL.Net\OpenGL.Net\Gl.cs:line 328
   at Demo.Program.Main(String[] args) in /mnt/Data/Projects/SdlSharp/Demo/Program.cs:line 22
> ls -l /usr/lib | grep libGL.so.1
lrwxrwxrwx.  1 root root       14 Nov 11 09:17 libGL.so.1 -> libGL.so.1.0.0
-rwxr-xr-x.  1 root root   404616 Nov 11 09:17 libGL.so.1.0.0
commented

On a side note, my code for Windows looked the same as yours, just without Gl.BindAPI, and it run fine.

Indeed your system lacks of libGL.so.1, maybe you can create a symbolic link to the actual GL library. On Windows the library opengl32.dll is found.

On net core, dll mapping is not supported. Maybe I'll make configurable the path used for loading function pointers.

commented

Indeed your system lacks of libGL.so.1, maybe you can create a symbolic link to the actual GL library. On Windows the library opengl32.dll is found.

Look at the last code block :|, its there.

> ls -l /usr/lib | grep libGL.so.1
lrwxrwxrwx.  1 root root       14 Nov 11 09:17 libGL.so.1 -> libGL.so.1.0.0
-rwxr-xr-x.  1 root root   404616 Nov 11 09:17 libGL.so.1.0.0

Sorry, I missed the second block.

Quite odd, since it's trying to load libGL.so.1 with dlopen, which returns zero. The function to be loaded is glXGetProcAddress, required for loading GL function pointers.

The text of the exception you get is returned by dlerror.

Personally, I never tried .NET Core on Linux, but I can run on Linux using mono, do you? In any case, it seems that the problem is related to dlopen.

I remember my bug report on mono. Maybe bitness problem?

commented

but I can run on Linux using mono, do you?

I really just wanted some C# OpenGL bindings which work on .NET Core.

it seems that the problem is related to dlopen.

I've been abusing dlopen with a bunch of my projects which require native libs, and it worked fine so far (ie. https://github.com/GtkSharp/GtkSharp/blob/develop/Source/Libs/Shared/FuncLoader.cs).

However I might see a clue to the problem, looking at the flag you are using with dlopen(RTLD_NOW) it seems that there is a chance of failing:

If this value is specified, or the environment variable LD_BIND_NOW is set to a 
nonempty string, all undefined symbols in the library are resolved before dlopen() 
returns. If this cannot be done, an error is returned.

https://linux.die.net/man/3/dlopen

I remember my bug report on mono. Maybe bitness problem?

Doubt it.

Perhaps trying the LAZY flag can be worth it. The "no such file" error could be referring another dependency required by libGL.so.1, which really does not exists.

Is it possible to trace system calls? It would confirm this conjecture.

commented

I spy with my little eye:

> OPENGL_NET_EGL_STATIC_INIT=NO dotnet run
FailFast: pglXChooseFBConfig not implemented

   at System.Diagnostics.Debug.Assert(Boolean condition, String message, String detailMessage)
   at OpenGL.Glx.ChooseFBConfig(IntPtr dpy, Int32 screen, Int32[] attrib_list, Int32[] nelements) in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/Glx.VERSION_1_3.cs:line 676
   at OpenGL.DeviceContextGLX.NativeWindow..ctor(Int32 x, Int32 y, UInt32 width, UInt32 height) in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/DeviceContextGLX.cs:line 186
   at OpenGL.DeviceContextGLX.NativeWindow..ctor() in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/DeviceContextGLX.cs:line 152
   at OpenGL.DeviceContext.CreateHiddenWindow() in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/DeviceContext.cs:line 76
   at OpenGL.Gl.Initialize() in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/Gl.cs:line 117
   at OpenGL.Gl..cctor() in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/Gl.cs:line 60
   at OpenGL.Gl.Initialize() in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/Gl.cs:line 70
   at Demo.Program.Main(String[] args) in /mnt/Data/Projects/SdlSharp/Demo/Program.cs:line 13

   at System.Environment.FailFast(System.String, System.Exception)
   at OpenGL.Glx.ChooseFBConfig(IntPtr, Int32, Int32[], Int32[])
   at OpenGL.DeviceContextGLX+NativeWindow..ctor(Int32, Int32, UInt32, UInt32)
   at OpenGL.DeviceContextGLX+NativeWindow..ctor()
   at OpenGL.DeviceContext.CreateHiddenWindow()
   at OpenGL.Gl.Initialize()
   at OpenGL.Gl..cctor()
   at OpenGL.Gl.Initialize()
   at Demo.Program.Main(System.String[])

How did you solved the previous issue?

And just to make it quick, set OPENGL_NET_INIT to NO. The initialization process should be optional.

commented

How did you solved the previous issue?

Just changed the dlopen flags.

commented

And just to make it quick, set OPENGL_NET_INIT to NO. The initialization process should be optional.

And we are back to square one:

Unhandled Exception: System.TypeInitializationException: The type initializer for 'OpenGL.GetGLProcAddressGLX' threw an exception. ---> System.InvalidOperationException: unable to load library at libGL.so.1 ---> System.InvalidOperationException: Exception of type 'System.InvalidOperationException' was thrown.
   --- End of inner exception stack trace ---
   at Khronos.GetProcAddressLinux.GetLibraryHandle(String libraryPath, Boolean throws) in /mnt/Data/GitHub/OpenGL.Net/Khronos.Net/GetProcAddressOS.cs:line 387
   at Khronos.GetProcAddressLinux.GetLibraryHandle(String libraryPath) in /mnt/Data/GitHub/OpenGL.Net/Khronos.Net/GetProcAddressOS.cs:line 376
   at Khronos.GetProcAddressLinux.GetProcAddress(String library, String function) in /mnt/Data/GitHub/OpenGL.Net/Khronos.Net/GetProcAddressOS.cs:line 347
   at Khronos.GetProcAddressOS.GetProcAddress(String library, String function) in /mnt/Data/GitHub/OpenGL.Net/Khronos.Net/GetProcAddressOS.cs:line 149
   at OpenGL.GetGLProcAddressGLX..cctor() in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/GetProcAddressGL.cs:line 154
   --- End of inner exception stack trace ---
   at OpenGL.GetProcAddressGL.GetProcAddress(String function) in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/GetProcAddressGL.cs:line 73
   at OpenGL.KhronosApi.GetProcAddressGLOS(String path, String function) in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/KhronosApi.cs:line 118
   at Khronos.KhronosApi.BindAPIFunction(String path, GetAddressDelegate getAddress, FieldInfo function, KhronosVersion version, ExtensionsCollection extensions) in /mnt/Data/GitHub/OpenGL.Net/Khronos.Net/KhronosApi.cs:line 313
   at Khronos.KhronosApi.BindAPIFunction[T](String path, String functionName, GetAddressDelegate getProcAddress, KhronosVersion version, ExtensionsCollection extensions) in /mnt/Data/GitHub/OpenGL.Net/Khronos.Net/KhronosApi.cs:line 164
   at OpenGL.Gl.BindAPIFunction(KhronosVersion version, ExtensionsCollection extensions, String functionName) in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/Gl.cs:line 427
   at OpenGL.Gl.QueryContextVersionCore() in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/Gl.cs:line 400
   at OpenGL.Gl.BindAPI() in /mnt/Data/GitHub/OpenGL.Net/OpenGL.Net/Gl.cs:line 337
   at Demo.Program.Main(String[] args) in /mnt/Data/Projects/SdlSharp/Demo/Program.cs:line 22

What SDL wrapper are you using?

commented

What SDL wrapper are you using?

In the process of writing my own (I will publish it once its done).

commented

Just FYI, it works fine with mono (and the OPENGL_NET_EGL_STATIC_INIT=NO flag ofc).

Same issue on macOS

OS Version: 10.13.4 (17E199)
.NET Version: dotnet core 2.1.300-preview1-008174

EDIT:
Your commit seems to have fixed the issue
I'm using it with the GLFW binding btw

Is it possible to get a new NuGet release with the fix ?

Thanks!

commented

@Scellow Always try to write a new comment instead of editing an existing one if you want to ask a question since editing a comment does not trigger notifications.

Thanks @cra0zy, didn't noticed the edit.

@Scellow nuget package 0.8 is in my todo for long time, I need to find few hours to dedicate on it. I wish to run successfully unit tests on linux before to publish it, but EGL is troublesome on that platform...

commented

@cra0zy Did you ever find a solution that worked for you with .NET Core on Linux? I am having the same issues, and even changing the dlopen flags did not seem to make much difference.

commented

Ah, okay. I've been eyeing OpenTK as an alternative, but I was hoping I could get away with something lighter weight. After toying around with it, I can see that it's working straight away. Thanks!

Any fix on the horizon for this?
Somewhat related would be the addition of allow users to supply their own loader. For example, a handler that could be passed to the bindings instead of trying to load the natives itself.

public delegate IntPtr GetProcAddressHandler(string functionName);

Popular libraries for context creation such as GLFW handle this responsibility reliably across platforms, and are pretty much the standard for creating native windows/contexts, and would allow easily bypassing this issue.

Had made my own quick/dirty bindings by auto-generated them from the registry, and uses GLFW as the loader works without any issues, where as this can't even initialize, and BindAPI fails.