JTalton's picture

OpenTK 0.9.1 - Unhandled Exception: No GraphicsContext available in the calling thread.

When trying to call OpenTK.Graphics.GL.LoadAll() in my application that uses my GTK GLWidget I get

Unhandled Exception: System.InvalidOperationException: No GraphicsContext available in the calling thread.
at OpenTK.Graphics.GL.LoadAll () [0x00000]
at MainWindow..ctor () [0x0000d] in /home/jtalton/GLTest/GLTest/MainWindow.cs:13
at GLTest.MainClass.Main (System.String[] args) [0x00005] in /home/jtalton/GLTest/GLTest/Main.cs:11

OpenTK 0.9.0 did not have this issue.

The problem is that the GTK Sharp GLWidget does not create a graphic context until it is "realized". This is so that there will be a valid window and device handle to use when creating the graphics context.
I tried to hook the OpenTK.Graphics.GL.LoadAll () in the the realized event but for some reason my test code does not render anything. It does not crash though.
A problem with adding this call to the realized event is that there may be multiple GLWidgets in an application.

Any suggestions?


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

You are right (I was aware that this would be an issue on this release). The solution would be to have the GTK# GLWidget create a GraphicsContext instead of manually calling wgl/glxCreateContext etc.

To create a GraphicsContext, you'll need an OpenTK.Platform.IWindowInfo object. This object has platform specific implementations, which contain information about a window (window handle and window parent at the very least). Moreover on Windows, the implementation provides a method to get a device context, while on X11 it contains the display connection, screen and root window for that screen.

Now the problem is that these implementations are not public. However, if you modify the *WindowInfo classes in OpenTK.Platform.Windows and OpenTK.Platform.X11 to become public, you should be able to retrieve the necessary info and instantiate a platform-agnostic GraphicsContext as soon as the GLWidget is realized.

The tests for a GraphicsContext will become more rigorous in future versions, as this is a common source of errors (and having your program silently fail/crash is bad). Now, it might be possible to allow a GraphicsContext to "hook" into an existing context (something like a static GraphicsContext.CreateFromCurrentThread), but this leaves the potential for abuse and would have to be coded very careful.

I think the first is preferrable, but the second could be useful in a bnid (e.g. if you have to interface with code you cannot change for some reason). What do you think?

JTalton's picture

I am not wild about having the GLWidget dependent on OpenTK. With the current implementation it can be used with any .NET OpenGL wrapper.

While I have not tried it, I am also wondering if my other project will have a problem when upgrading to OpenTK 0.9.1. It currently uses the Tao.SDL wrapper to create the OpenGL window.

I love the fact that you are defensively programming and adding validation and error checking. I am just looking for a way to make it work for my needs.

With the GTK# GLWidget a user may be using multiple GLWidgets that each need their own OpenGL context, or they may be setup to use a shared OpenGL context. I'm not sure if that affects any design decisions or not.

I could code up an event that is raised when the first OpenGL context is created. This would allow LoadAll() to be called by the user when that happens. Of course it sounds like OpenTK would need to support hooking the GraphicsContext up to the created OpenGL context.

the Fiddler's picture

Nice, this makes things a little clearer. It seems there are a few projects that use GTK# or Tao.SDL along OpenTK, which means it might be nice to provide a way to hook into existing contexts.

This should be possible using the wgl/glX/aglGetCurrentContext functions. The question here is, should this be implicit (i.e. a GraphicsContext is created internally whenever an unknown OpenGL context is detected) or explicit?

Regarding multiple contexts, OpenTK internally keeps track of shared contexts it creates. I don't know if there is a way to detect whether two given contexts are shared after the fact (if not, the safest course is to assume they are not). Any ideas on this?

JTalton's picture

Seems like creating it internally would be easiest to use and I don't see any real drawbacks.

I am not sure about multiple contexts. I always used shared contexts, but the GLWidget also supports separate contexts. I guess the question is, if there were multiple contexts but not a GraphicsContext for each one, how would OpenTK behave?

Let me know if there is anything I can do or test.

the Fiddler's picture

I guess the question is, if there were multiple contexts but not a GraphicsContext for each one, how would OpenTK behave?
Indeed, this is the question.

As long as OpenTK is in control of context creation, it will behave correctly (you can choose which GraphicContexts to share on creation time). If someone else creates the contexts, OpenTK won't be able to detect if they are shared, because there is no API for that. Inconsistencies such as these are unavoidable - which is why OpenTK doens't provide direct access to WGL/GLX.

Fortunately this specific issue isn't significant - OpenTK doesn't keep track of allocated GL resources, so this responsibillity is up to the user. On the other hand this might cause problems in the future, when (and if) the experimental OpenGL GC API is realized. The safest option is to disallow use of this API with non-OpenTK controlled contexts. This is a corner-case however, so I'm not really worried about that.

What's important now is to provide the hooks so that OpenTK works with SDL/GLWidget once more. I'll let you know when that's ready for testing.

the Fiddler's picture

As of revision 1329, there is a workaround: GraphicsContext.CreateFromCurrentThead(IWindowInfo window)

Once you create a new context, just call this method to make OpenTK happy. If you plan to use any of the GraphicsContext<c/> members (e.g. <c>SwapBuffers, VSync, etc), you'll also have to create an IWindowInfo object (check OpenTK.Platform.Windows and OpenTK.Platform.X11 for WinWindowInfo and X11WindowInfo respectively). Finally, you should call the Dispose method whenever a context is destroyed, as there is no way to detect this automatically.

Can anyone affected please test this code? Thanks!

JTalton's picture

I am looking into this but it will be a couple of days.

JTalton's picture

OpenTK.Platform.IWindowInfo windowInfo = new OpenTK.Platform.X11.X11WindowInfo();
GraphicsContext.CreateFromCurrentThread(windowInfo);

This does keep it from crashing, but it renders nothing.
I tried to fill out some of the information in the OpenTK.Platform.X11.X11WindowInfo but I'm not sure what all needs to be filled out. Also when I tried to fill out some of the XVisualInfo it would not let me change the values. I didn't look into it really hard.

Seems like we need a GTK GLWidget intergrated into OpenTK much like the WinForms GLControl. I would be interested in working on this if there is interest in having it. I would base the code much like the current GLControl.

On the Tao.SDL front I am not sure what to do. I am using Tao.SDL because I found it had a lot less overhead for input polling and such. I am not sure how to set it up so that it will work with OpenTK 0.9.1. I may just have to convert the project to use the OpenTK main loop. I have also been using the TrueType font support from SDL since I found it more accurate than the .NET font support that OpenTK uses (I need accurate sizes for dynamic layout).

the Fiddler's picture

When you say it renders nothing, do you mean that the original GTK# widget stops functioning?

While a GLWidget built on top of GraphicsContext would certainly be nice (and probably quite simple to implement), we still need to make OpenTK work with Tao.SDL etc. If you can upload a minimal Tao.Sdl or GTK# example, I'll be able to find out what's missing.

Another idea that just occured, is that could create a "dummy" GraphicsContext and fool OpenTK into thinking everything's alright. In fact, one already exists for use in the Visual Studio designer! We'd lose the ability to SwapBuffers() etc through GraphicsContext, but since you can do that through Tao.SDL/GLWidget it's no problem.

How does this solution sound?

Darian's picture

It seems that it is possible to get a Graphics context set on the same area:

MainWindow.cs:
public partial class MainWindow: Gtk.Window
{
// needed to create a GraphicsContext for GLWidget
OpenTK.GLControl glControl = new OpenTK.GLControl();

}

public MainWindow (): base (Gtk.WindowType.Toplevel)
{
Build();
GL.LoadAll();
Glu.LoadAll();
glwidget1.Render += new EventHandler(Render); //
}

The void Render would be left untouched for that matter.

I've pasted the relevant parts, a working example might be posted later.

- Darian