sgsrules's picture

Shared Contexts on multiple threads

Hi, I've got a main opengl context that i want to share data with a second context on a separate thread. I know i can have one context and switch it's use between threads by making it current but this is not what i'm after. I want to have both current at the same time on separate threads and be able to update buffers on the second context. here's what i've come up with so far:

On Main thread:

    private void CreateGLContext()
        {
 
            GraphicsMode gmode = new GraphicsMode(new ColorFormat(8,8,8,8),24,0,0,0,2,false);
 
 
            nWindow = new NativeWindow(Width, Height, "OpenGl Window", GameWindowFlags.Fullscreen, gmode, DisplayDevice.AvailableDisplays[0]);
 
            GlContext = new GraphicsContext(gmode, nWindow.WindowInfo, 3, 2, GraphicsContextFlags.Default);
            GlContext.MakeCurrent(nWindow.WindowInfo);
            (GlContext as IGraphicsContextInternal).LoadAll();
        }

On Secondary thread:

 
            SecondGlContext = new GraphicsContext(new ContextHandle(), nWindow.WindowInfo, GlContext, 3, 2, GraphicsContextFlags.Default);
            SecondGlContext.MakeCurrent(nWindow.WindowInfo);
            (SecondGlContext as IGraphicsContextInternal).LoadAll();

Obviously this doesn't work. My main questions are:

1) When creating the second context what is the context handle? and how do i make one?
2) Do i have to create a new window if i'm not using this context for rendering or can i use the same window as the main context?


Comments

Comment viewing options

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

I never managed to get GL calls on a second thread working properly, admittidly I did give up quickly and I'm not too good on OpenGL.

It doesn't seem safe either, what happens if you try to update a buffer thats currently being rendered from on the other thread?

I'd recommend going out of your way a bit to get all of your GL stuff on one thread. What I did is generate the buffer data on the new thread and passed it to the first thread to put it into the actual buffer.

sgsrules's picture

I'm aware of all this and this is what i've been doing but i would really like to know how to be able to share contexts. Any takers?

jdomnitz's picture

You need to release the context on one thread before using it on another.... MakeCurrent(null) to release a context.

sgsrules's picture

I'm not trying to share one context between two threads. I have two separate contexts running on two separate threads, both contexts are current and i want to share data between them.

Again My main questions are:
1) When creating the second context what is the context handle? and how do i make one?
2) Do i have to create a new window if i'm not using this context for rendering or can i use the same window as the main context?

the Fiddler's picture
Quote:

1) When creating the second context what is the context handle? and how do i make one?

The context handle is only necessary when interfacing with an external context, i.e. a context created through a 3rd party library (e.g. SDL or Qt).

You need to use one of the constructors that don't take a context handle.

Quote:

2) Do i have to create a new window if i'm not using this context for rendering or can i use the same window as the main context?

Yes. Simplest approach is to create a GameWindow on the second thread without calling its Run() method. (This is equivalent to creating an OpenTK.NativeWindow and instantiating a GraphicsContext on that).

OpenTK always attempts to share contexts if possible. For best results, create all contexts on startup (before creating any textures/buffers) and call MakeCurrent(null) on the first context prior to creating the second one. (Other approaches may or may not work depending on the drivers. Also note that context sharing is generally not supported by Intel drivers).

sgsrules's picture

Brilliant! that worked perfectly! thanks so much. One final question. How can i call a function from another thread? for example if i want to update my gui thread from my render thread i do something like

 pictureBox.Invoke((VoidDelegate)delegate { pictureBox.Image = bmp; });

But how do i invoke from my opengl render thread?

jdomnitz's picture

You need to create a messagepump for invokes.... the eaasiest way (afaik) is to create a static List... then on your render thread you add the delegate you want invoked to the list (or expose a public Invoke function to handle that)...and finally on the gui thread you invoke from that list. I usually do it right after the swap buffers command in the OnRenderFrame function...just loop through all the delegates in the list and invoke them.

JTalton's picture

You could use the threads dispatcher if the infrstructure is set up right...

Dispatcher.FromThread(renderThread).Invoke((VoidDelegate)delegate { pictureBox.Image = bmp; });