Howto render to a GL context from another thread?


#1

Hi all,

I’ve arrived at the part of my app where i need to code a separate thread which renders an image and displays it onto a GL quad in a GL viewport in my juce app.

how would i practically do this ?
I understand you can’t share a GL context between threads, so how would this be done ?

I’ve got the viewport as a component, derived from a OpenGLComponent.
This then creates the gl context and i can draw on it with it’s ‘void renderOpenGL()’ method.

How do i change this scenario to have a separate thread running which draws to this component with GL calls.

This thread runs continuously and keeps updating the viewport.

I haven’t used any of the juce threading stuff neither… i’m only familiar with boost threads and posix pthreads.

any help appreciated, just a structural outline of the concept is welcome, i can resolve the details afterwards :slight_smile:

thnx!,
Radiance


#2

There’s a few of us doing it. You can search the forums and get a lot of info, then see what specific questions you end up with.

Bruce


#3

Hi,

Thanks for your reply, have you any links ?
I can’t find much relevant with the forum search…

Radiance


#4

Search “openglcomponent rendering thread” with ‘all terms’ checked is a good start.

Bruce


#5

Hi,

Been sick so a late thanks, i think i’ve found most of what i need :slight_smile:

Radiance


#6

Hi all,

After playing with some code found here:
http://www.rawmaterialsoftware.com/juceforum/viewtopic.php?t=1709&highlight=openglcomponent+rendering+thread

I’ve had no success.

I’ve searched and searched, and can only find posts with little bits of code scattered around that solve small issues.
There does’nt seem to be a simple example, please point me to one if it exists somewhere on the forums.

I just need a simple example, a component which draws some opengl graphics in a loop in a separate thread, which i can control from the component, that’s enough to get me started.

I’ve no experience with juce threads neither, and the lack of documentation is frustrating…

Maybe jules can put up a community wiki or something where community members can add docs and tutorials ?
I’ve found this to be a great help on the luxrender project, relieving the project authors from writing docs as the community handles it.

Thanks,
Radiance


#7

here’s what i’ve pieced together:

class RenderGLThread : public Thread 
{
public:
	RenderGLThread(OpenGLComponent* g): Thread(T("RenderThread")) {
		glSurface = g;
	}

	void run() {
		while (!threadShouldExit()) {
			// Rendering work.
			glSurface->renderAndSwapBuffers();
		}
	}

private:
	OpenGLComponent*   glSurface;
};

class GLMonitor : public OpenGLComponent 
{
public:
	GLMonitor(): OpenGLComponent() {
		rotation = 0.f;
		frameTicks = Time::secondsToHighResolutionTicks(0.01); // 100 FPS
	}

	void resized() {
		// Set up viewport.
		//makeCurrentContextActive();

		width = getWidth();
		height = getHeight();

		//makeCurrentContextInactive();
	}

	void newOpenGLContextCreated() {
		width = getWidth();
		height = getHeight();
	}

	void renderOpenGL() {
		makeCurrentContextActive();
        glClearColor (0.42f, 0.42f, 0.42f, 1.0f);
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glMatrixMode (GL_PROJECTION);
        glLoadIdentity();
        glClear (GL_DEPTH_BUFFER_BIT);
        gluPerspective (45.0f,
                        width / (GLfloat) height,
                        0.1f,
                        100.0f);

        glMatrixMode (GL_MODELVIEW);

        glLoadIdentity();

        glPushMatrix();
            glTranslatef (0.0f, 0.0f, -5.0f);
            glRotatef (sinf(rotation) * 360.f, 0.5f, 1.0f, 0.0f);

			glColor3f(1., 1., 1.);

			glEnable(GL_DEPTH_TEST);
			glEnable ( GL_LIGHTING ) ;
			glEnable(GL_LIGHT0);

			//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

			//glShadeModel(GL_FLAT);
			glShadeModel(GL_SMOOTH);

			glutSolidTeapot(1.f);

			glDisable ( GL_LIGHTING ) ;
			glDisable(GL_DEPTH_TEST);
        glPopMatrix();

		makeCurrentContextInactive(); 
		rotation++;
	}

private:
	float rotation;
	int some_enum_view;
	int64 frameTicks;
	int width, height;
};

class Monitor : public Component 
{
public:
	Monitor()
	{
		glSurface = new GLMonitor();
		renderThread = new RenderGLThread(glSurface);
	}
	~Monitor() {
		deactivate();
	}

	void resized() {
		glSurface->setBounds(0, 0, getWidth(), getHeight());
		addAndMakeVisible(glSurface);
	}

	void activate() {
		renderThread->startThread(5);   // 5 is normal priority.
	}

	void deactivate() {
		renderThread->stopThread(500);   // .5 seconds.
	}

private:
	OpenGLComponent*   glSurface;
	RenderGLThread*      renderThread;
	bool            active;
}; 

the teapot only draws when juce repaints the Monitor component (eg resizing etc…)
when i activate() the monitor, the app blocks.

I’m also a bit weary as to if this code actually worked (as posted in the thread linked above), as there does’nt seem to be any locking.

If anyone could make this work, please do. :slight_smile:

Radiance