SPGardebiter's picture

System.Threading.Timer generating random OpenGL errors

Hello. I'm trying to learn hwo to use OpenTK with VB.NET and I run into trouble.
I'm trying to use a Timer instead of a GameWindow but it produces random errors, sometimes I run into a AccessViolation and sometimes I can't swap the buffers. At the moment I'm using the newest version of OpenTK together with Visual Basic .NET 2005.
Windows.Forms.Timer works but System.Threading.Timer doesn't.

This is my code:

Imports OpenTK
Imports OpenTK.Graphics.OpenGL
Imports OpenTK.Audio
Imports OpenTK.Audio.OpenAL
Imports OpenTK.Input
Imports OpenTK.GLControl
Imports OpenTK.Platform
Imports System.Drawing
Imports System.IO
Imports System.Threading
 
 
Public Class frm_main
    Public Loaded As Boolean
    Public Counter As New Stopwatch()
    Public Timer As System.Threading.Timer
 
 
    Private Sub GLC_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles GLC.Load
 
        GL.ShadeModel(ShadingModel.Flat)
        GL.ClearColor(Color.Black)
        GL.MatrixMode(MatrixMode.Projection) ' Projection Matrix
        GL.LoadIdentity() ' Reset
        GL.Viewport(0, 0, GLC.Width, GLC.Height)
        GL.Ortho(0, 640, 0, 480, 0, 256)
 
        Timer = New System.Threading.Timer(AddressOf Tick, Nothing, 1000, 2000)
 
    End Sub
 
 
    Private Sub GLC_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles GLC.Resize
 
        GL.MatrixMode(MatrixMode.Projection) ' Projection Matrix
        GL.LoadIdentity() ' Reset
        GL.MatrixMode(MatrixMode.Modelview) ' Modelview Matrix
        GL.LoadIdentity() ' Reset
        GL.Viewport(0, 0, GLC.Width, GLC.Height)
 
    End Sub
 
    Private Sub Tick(ByVal sender As System.Object)
 
        Counter.Stop()
 
        Me.Text = "Sturmfaust Engine .NET (" & Counter.ElapsedMilliseconds.ToString & ")"
 
        Counter.Reset()
        Counter.Start()
 
        GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)
        GL.LoadIdentity()
 
        GLC.SwapBuffers()
 
    End Sub
 
End Class

Anyone got an idea?


Comments

Comment viewing options

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

System.Threading.Timer runs on a separate thread that does not have access to an OpenGL context. You can only use OpenGL from a thread with an OpenGL context, see the documentation for more details.

In short, choose which thread will be issuing OpenGL commands (the main thread or the Timer thread) and call MakeCurrent() on that thread. Check the aforementioned documentation for example code.

ERP's picture

Timers run on worker threads in .Net, the resize and Paint methods run on the message pump thread, directly accessing GL on a timer thread is generally not safe without understanding multithreading in OpenGL.
You have a couple of options, the "right" way to do it is just to call Invalidate in the timer and leave the render code in the PAINT/Render function, windows will post a message back to the primary thread and it will do the rendering.
You could post your own custom message, but that's a lot of work for no benefit.
And the last is you could use Invoke to call your rendering code this posts a message back to the primary thread, and waits until it finishes executing the "Invoked" function before continuing, generally I would consider this a last resort.