avic's picture

GraphicsContextMissingException Problem

I'm getting a GraphicsContextMissingException. What is this and what does it mean? What exactly is a graphics context?

I have a data collection class which contains a form to visualize the data. As the data is collected it sends the data to its form which converts the data into color data and then is supposed to render it. But when I call the visualization form's update data and render command:

Public Sub render()
        GL.ColorPointer(3, ColorPointerType.Double, 0, colorArray)
        GlControl1.Invalidate()
 End Sub

I get the exception when setting the color pointer. I don't understand what's going on because the form with the glcontrol initializes just fine and the initialization routine contains a GL.colorPointer call. The data collection class initializes and displays the form without any issues but when the ColorPointer function is called again, I get "No context is current in the calling thread" The subroutine which collects the data (which is in the data collection class) and sends it to the visualization form is executed on a separate thread from the main program. Here's my paint subroutine:

    Private Sub GlControl1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles GlControl1.Paint
        If Not loaded Then
            Return
        End If
        Dim rand As New Random()
        GL.Clear(ClearBufferMask.ColorBufferBit)
 
        GL.MatrixMode(MatrixMode.Modelview)
        GL.LoadIdentity()
 
        GL.DrawArrays(BeginMode.Points, 0, imageHeight * imageWidth)
 
        GlControl1.SwapBuffers()
    End Sub

And here are my initialization subroutines:

    Public Sub New(ByVal width As Double, ByVal height As Double, ByVal xmin As Double, ByVal ymin As Double, _
                   ByVal xstep As Double, ByVal ystep As Double)
        InitializeComponent()
        Me.imageHeight = height
        Me.imageWidth = width
         ...
         ...
    End Sub
    Private Sub ScanVisualizer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        loaded = True
        fillVertexArray()
        initializeColorArray()
        GL.ClearColor(Color.Black)
        GlControl1.VSync = True
        GL.VertexPointer(2, VertexPointerType.Double, 0, vertexArray)
        GL.ColorPointer(3, ColorPointerType.Double, 0, colorArray)
        GL.EnableClientState(EnableCap.VertexArray)
        GL.EnableClientState(EnableCap.ColorArray)
 
 
        SetupViewport()
        GL.Disable(EnableCap.DepthTest)
    End Sub
    Private Sub SetupViewport()
        Dim w = GlControl1.Width()
        Dim h = GlControl1.Height()
        GL.MatrixMode(MatrixMode.Projection)
        GL.LoadIdentity()
        GL.Ortho(0, imageWidth, imageHeight, 0, 0, 1) 'define clipping planes
        GL.Viewport(0, 0, w, h)  'Use all of the glControl painting area
    End Sub

(For those of you who put up with my previous question, yes I'm still using a bunch of points to display a 2d image because I decided to keep it this way because eventually, I'm going to turn this into a 3d image once I get the basic structure working)

I apologize for this question but I couldn't find any satisfactory explanation for what a graphics context is and what this exception means on the internet. Thanks for your help.


Comments

Comment viewing options

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

A GraphicsContext (aka OpenGL context) is the most fundamental part of OpenGL: without a context, you cannot use any OpenGL commands. OpenTK creates a context for you as part of the GLControl.

An OpenGL context may be "current" on one thread at a time. All OpenGL commands issued on that thread are routed to the current context. OpenGL commands issued on a thread without a context will result in a GraphicsContextMissingException. This is a safeguard placed by OpenTK - under normal circumstances, you'd get an abrupt and unexplained crash.

You have a few different options if you wish to use OpenGL commands on multiple threads:

  • Create one OpenGL context on each thread.
  • Use GraphicsContext.MakeCurrent() to make an existing context current on a different thread.

Both alternatives can be quite complicated to implement - your best bet is to restrict OpenGL commands on a single thread (preferably the main WM thread) and use Control.BeginInvoke() to issue commands from a different thread.

Edit: grammar.

avic's picture

Got it. Thanks a lot!!

MasterEvilAce's picture

Similar issue, but looking for a good solution to my specific problem.
I have a windows form which I want purely as a GUI. All of my processing is done through separate classes / threads and I use delegates when required to interact with the GUI.
My windows form has the GLControl on it.

Problem is, my game loop is on another thread. And everything else is attached to that. Input, rendering, etc. My render class gets passed in objects and it draws them appropriately.. The GUI is literally only there to provide input and interaction with objects

I went from XNA to Tao Framework to get away from lots of XNA's restrictions and difficulties. Tao unfortunately didn't lend itself to a lot of example code. So now I'm at OpenTK. I swear Tao did not seem to have this context/thread limitation. I could call all of the GL stuff from my other class and it rendered smoothly. Not only that, with OpenTK I think I also have to deal with GLControl.SwapBuffer.... so I will have to use a delegate back to the GUI to call SwapBuffer on the GLControl at the end of my render loop?

I need a good solution on how to set this up between all my classes. Suggestions?

the Fiddler's picture

Tao has the exact same limitation (this is mandated by the OpenGL specs), but it does not check for this error condition. Some versions of Windows will silently ignore this error, but the issue is there waiting to manifest - not a good situation to be in. Actually, both GLControl and Tao's SimpleOpenGlControl have very similar implementations on Windows - the only significant difference is that GLControl also supports OpenGL 3.0+ (and can also run on non-Windows platforms).

If I understand correctly, you have a single OpenGL context attached to your Form (the GLControl) while the renderer is in another thread, is this correct? If so, the renderer won't be able to use any OpenGL commands, unless it creates a second OpenGL context on its thread. This way, you could render-to-texture from the renderer thread and simply display the texture from the GUI thread (context resources are shared by default, if possible).

One other potential solution is to use a thread-safe render queue: add all "to be rendered" items into the queue and have the GUI thread consume and render them with OpenGL. SwapBuffers() calls could also be treated as part of this queue. This can be more performant than cross-thread delegate invocations, but introduces some (relatively easy to avoid) synchronization issues.

The reason why SwapBuffers() is not called automatically is that OpenTK supports stereoscopic rendering, which requires explicit control over buffer swaps. If you prefer Tao's more automated approach you can check out OpenTK from SVN trunk - the OpenTK.Compatibility project contains a reimplementation of Tao's SimpleOpenGlControl on top of OpenTK's GLControl. You could also inherit from GLControl and override the Paint event to add an explicit SwapBuffers() call (this is what Tao does anyway).