You can, if the two FBO were created in 2 different context.
However, compositing them together on screen in one window will require passing them back to software and then back to hardware in the window's context. This will be slower than just rendering them both in the main context on one thread.
You're better off focusing on getting the rendering into a single thread if it's going to be in one window, and putting your focus on threading elsewhere. Culling and physics are great places to thread (if you have those), but for rendering, one thread per context is the basic rule of thumb (and each window will pretty much mean one context).
I resolved this issue.
So here is what I do. Maybe there is some better / smarter way to do it, but it works perfectly fine now. Feel free to suggest adaptions...
I don't list the error handling beneath. You can find that further up in this question.
// create frame buffer object
glGenFramebuffers(1, frameBufferObject);
// create empty texture
int width = 512;
int height = 512;
int numberOfChannels = 3;
GLuint internalFormat = GL_RGB8;
GLuint format = GL_RGB;
unsigned char* texels = new unsigned char[width * height * numberOfChannels];
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, texels);
delete[] texels;
texels = NULL;
// draw the colored quad into the initially empty texture
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
// store attibutes
glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// reset viewport
glViewport(0, 0, width, height);
// setup modelview matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// setup projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
// setup orthogonal projection
glOrtho(-width / 2, width / 2, -height / 2, height / 2, 0, 1000);
// bind framebuffer object
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject);
// attach empty texture to framebuffer object
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
// check framebuffer status (see above)
// bind framebuffer object (IMPORTANT! bind before adding color attachments!)
glBindFramebuffer(GL_FRAMEBUFFER, frameBufferObject);
// define render targets (empty texture is at GL_COLOR_ATTACHMENT0)
glDrawBuffers(1, GL_COLOR_ATTACHMENT0); // you can of course have more than only 1 attachment
// activate & bind empty texture
// I figured activating and binding must take place AFTER attaching texture as color attachment
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// clear color attachments
glClear(GL_COLOR_BUFFER_BIT);
// make background yellow
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
// draw quad into texture attached to frame buffer object
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glVertex2f(0.0f, 100.0f); // top left
glColor4f(1.0f, 0.0f, 0.0f, 1.0f); glVertex2f(0.0f, 0.0f); // bottom left
glColor4f(0.0f, 1.0f, 0.0f, 1.0f); glVertex2f(100.0f, 0.0f); // bottom right
glColor4f(0.0f, 0.0f, 1.0f, 1.0f); glVertex2f(100.0f, 100.0f); // top right
glEnd();
// reset projection matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();
// reset modelview matrix
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
// restore attributes
glPopAttrib();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
// I guess, now it's OK to create MipMaps
// draw the scene
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor4f(1.0, 1.0, 1.0, 1.0);
// begin texture mapping
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// normal faces "camera"
glNormal3d(0.0f, 0.0f, 1.0f);
glBegin(GL_QUADS);
glNormal3d(0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(0.0f, 50.0f, -100.0f); // top left
glTexCoord2f(0.0f, 1.0f); glVertex3f(0.0f, 0.0f, -100.0f); // bottom left
glTexCoord2f(1.0f, 1.0f); glVertex3f(50.0f, 0.0f, -100.0f); // bottom right
glTexCoord2f(1.0f, 0.0f); glVertex3f(50.0f, 50.0f, -100.0f); // top right
glEnd();
glDisable(GL_TEXTURE_2D);
glPopMatrix();
// finish rendering
glFlush();
glFinish();
// swap buffers (I forgot to mention that I use SDL)
SDL_GL_SwapBuffers();
// do the clean up!
As you see, I got rid of the depth buffer attachment. I figured that I don't really need it for my task. As soon as I actually could draw things, I added the orthogonal projection. Without that, drawing to a texture results in pretty awkward images...
Hope this is useful for somebody out there
Walter
Best Answer
It is not possible to share framebuffers between different contexts. See the first paragraph of Appendix D, OpenGL 3.3 spec. However, you can share textures and renderbuffers, which should give you want you need.
As for the threading: It should be possible, but it is generally advised not to issue GL commands from multiple threads (Because it is just very hard to synchronize). Usually, you would copy the contents to a pixel-buffer-object and and map it from the GL thread, then use the mapped pointer from the other thread.