luca-piccioni / OpenGL.Net

Modern OpenGL bindings for C#.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Couple of Questions

mellinoe opened this issue · comments

I'm interested in trying out the library, and had a couple of questions:

  • Is there a NuGet package supporting .NET Core and/or .NET Standard? I see that there are projects targeting them, but the latest nuget packages don't seem to have the support in them.
  • What does the integration look like if I have an existing OpenGL context -- for example, one created through SDL2? With OpenTK, I'm able to hook in and load functions with just:
    • A context handle
    • A function pointer to GetProcAddress
    • A function pointer to GetCurrentContext

Thanks!

Currently, NuGet packages are built by AppVeyor using the VS2015 image. Indeed the VS2017 projects are not integrated with the CI yet (it is in the TODO list, and it will be done, soon or later).

To load GL function pointers just call Gl.BindAPI() after you made current a GL context. With the most probability you need to manually call Gl.Initialize() before creating the SDL window.

@mellinoe I'm wondering about... How is going? I would appreciate any comment about the .NET Standard project, since I've never tried to run it.

I haven't had time to experiment with it -- not sure when I'll be able to do so. For more context I am considering switching to this from OpenTK for the OpenGL backend of my graphics lib Veldrid.

One thing I noticed after looking around is that there aren't any ref overloads for GL functions taking pointers. Is that something you would consider adding? It would probably make switching over easier (plus it helps usability).

Instead of ref arguments I preferred the object parameter, and fixing it with unsafe/fixed: it is meant to pass Array values (but actually it could be any reference/value type); the IntPtr methods are meant to pass constant values (i.e. IntPtr.Zero) or un-managed pointers (i.e. shared memory pointers).

Adding ref arguments is not a big issue. However, how the default marshaller pins the memory of the ref argument? Is it safe for memory coherence? (and that's why I still have no ref arguments). Of course any suggestion about correct parameter marshalling is welcome.

After having a quick look at Veldrid, you could merge GL and GLES backends implementations, since the OpenGL.Net methods can be bound to both API (depending on the current context, of course).

Having an object parameter will cause the values to be boxed -- that will cause a lot of unnecessary temporary allocations to pop up for every call that you use.

Adding ref arguments is not a big issue. However, how the default marshaller pins the memory of the ref argument? Is it safe for memory coherence? (and that's why I still have no ref arguments). Of course any suggestion about correct parameter marshalling is welcome.

OpenTK handles this in their binary rewriter step. They declare the ref / out parameters as pinned where necessary. For example. I'd have to think about whether that could be done without a rewriter step. That should cause the parameters to be pinned where necessary.

After having a quick look at Veldrid, you could merge GL and GLES backends implementations, since the OpenGL.Net methods can be bound to both API (depending on the current context, of course).

I would definitely like to reduce some of the duplication, but there are definitely some differences in function calls that I make between the two.

Having an object parameter will cause the values to be boxed -- that will cause a lot of unnecessary temporary allocations to pop up for every call that you use.

Sure, but it doesn't happens in the case of Array argument (or any reference type, really), which is the 99.99% of the values passed to that commands. After that, you should consider that modern OpenGL assumes that you uploads buffers into VBO, indeed most of the times (if not always) you pass an offset as argument, avoiding boxing and pinning.

OpenTK handles this in their binary rewriter step.

That's one of the many reason I don't use OpenTK. It hides implementation, it makes debugging difficult, and it is error prone, especially on an large API like OpenGL. And, as far I can understand, it causes a big obstacle to run on newer .NET frameworks (i.e. .NET Core), due the calli operation.

I'd have to think about whether that could be done without a rewriter step. That should cause the parameters to be pinned where necessary.

I solved the issue by entrusting me to the compiler. I suppose that .NET compilers do a smarter job than my emitted code, leaving it to play with its optimizations. After that, you should consider that modern OpenGL is minimizing required commands during the drawing phase, because the issue has caused too much CPU overhead even on un-managed languages; indeed the problem should be minimized at the API specification level: infact, with proper GL extensions, I can draw any arbitrary string with very few commands (Textured font).

I would definitely like to reduce some of the duplication, but there are definitely some differences in function calls that I make between the two.

Let me know about them, because I found very little differences between the APIs when I compiled by OpenGL.Net.Objects sub-project for Xamarin/Android.

I'm also not a fan of the rewriter step in general. I hope that eventually features like "Compiler Intrinsics" will get implemented, and the things the rewriter does could be done in regular C# code. FWIW, the rewriter isn't a problem for running on .NET Core -- it supports calli just fine.

I would have to see how many places I end up using ref overloads in my OpenGL backend. I brought it up because it might end up taking a little bit longer to convert everything if I had to fiddle with a bunch of call sites.

I wonder if I can replace parts of the GL calls with this library, piece by piece. Any idea if there would be some weird issues from having OpenTK and OpenGL.NET both load function pointers and try to call them?

I wonder if I can replace parts of the GL calls with this library, piece by piece. Any idea if there would be some weird issues from having OpenTK and OpenGL.NET both load function pointers and try to call them

I don't see any evident issue, since they are "just" the same function pointers.

In case anyone struggles with SDL2 initialization:

        static void InitSdl()
        {
            if (SDL_Init(SDL_INIT_VIDEO) != 0)
            {
                Console.WriteLine("Can't initialize SDL: \n" +
                                  SDL_GetError());
                Environment.Exit(-1);
            }

            SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK,
                (int) SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE);
            SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, 4);
            SDL_GL_SetAttribute(SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, 4);

            Gl.Initialize(); // This!

            _window = SDL_CreateWindow(
                "MyGame",
                SDL_WINDOWPOS_CENTERED,
                SDL_WINDOWPOS_CENTERED,
                1920,
                1080,
                SDL_WindowFlags.SDL_WINDOW_OPENGL);

            if (_window == IntPtr.Zero)
            {
                Console.WriteLine("Can't create window: \n" +
                                  SDL_GetError());
                Environment.Exit(-1);
            }

            _glContext = SDL_GL_CreateContext(_window);

            Console.WriteLine(SDL_GetError());
            if (_glContext == IntPtr.Zero)
            {
                Console.WriteLine("Can't create glContext: \n" +
                                  SDL_GetError());
                Environment.Exit(-1);
            }

            if (SDL_GL_SetSwapInterval(1) != 0)
            {
                Console.WriteLine("Couldn't enable VSync!");
            }
            
            Gl.BindAPI(); // And this!
            
            Gl.Enable(EnableCap.DepthTest);
            Gl.Enable(EnableCap.CullFace);
            Gl.CullFace(CullFaceMode.Back);
            Gl.FrontFace(FrontFaceDirection.Ccw);

            Gl.Enable(EnableCap.Blend);
            Gl.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);

            Console.WriteLine("SDL initialized successfully.");
        }

I was debugging this for hours not knowing why I was getting a black screen (I always use a non-black ClearColor).