Hi folks,
I create two threads, one (Thread A) renders the UI and the other (Thread B) creates a Pbuffer to do off-screen rendering.
The structure is as follows.
Thread A
Call Thread B;
While ();
Rendering(GUI);
Thread B
Create Buffer;
Create FBO, texture;
Render to Texture (to FBO)
Each source is as follows.
Thread A
static EGLint const attrib_list[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BUFFER_SIZE, 32,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
// ...
m_EGLDisplay = eglGetDisplay((EGLNativeDisplayType)0);
eglInitialize(m_EGLDisplay, &major, &minor);
eglGetConfigs(m_EGLDisplay, NULL, 0, &max_num_config);
eglChooseConfig(m_EGLDisplay, attrib_list, configs, max_num_config, &max_num_config);
m_EGLSurface = eglCreateWindowSurface(m_EGLDisplay, m_EGLConfig, 0, NULL);
m_EGLContext = eglCreateContext(m_EGLDisplay, m_EGLConfig, EGL_NO_CONTEXT, attribs_context);
eglMakeCurrent(m_EGLDisplay, m_EGLSurface, m_EGLSurface, m_EGLContext);
eglSwapInterval(m_EGLDisplay, 1);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glViewport(0, 0, gWidth, gHeight);
// ...
// Create Shader program
// Create VAO, VBO for triangle rendering
while (1)
Rendering();
void Rendering()
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(ShaderprogramObject);
glBindVertexArray(VAO);
glUniform1i(texLoc[0], 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
eglSwapBuffers(m_EGLDisplay, m_EGLSurface);
}
Thread B
static EGLint const attrib_list[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
EGL_NONE
};
eglQueryDevicesEXT(MAX_DEVICES, eglDevs, &numDevices);
m_EGLDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, eglDevs[0], 0);
eglInitialize(m_EGLDisplay, &major, &minor);
eglGetConfigs(m_EGLDisplay, NULL, 0, &max_num_config);
eglChooseConfig(m_EGLDisplay, attrib_list, configs, max_num_config, &max_num_config);
EGLint pbuffer_attribs[] = {
EGL_WIDTH, gWidth,
EGL_HEIGHT, gHeight,
EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
EGL_NONE
};
m_EGLSurface = eglCreatePbufferSurface(m_EGLDisplay, m_EGLConfig, pbuffer_attribs);
eglCreateContext(m_EGLDisplay, m_EGLConfig, EGL_NO_CONTEXT, attribs_context);
eglMakeCurrent(m_EGLDisplay, m_EGLSurface, m_EGLSurface, m_EGLContext));
eglSwapInterval(m_EGLDisplay, 1);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glViewport(0, 0, gWidth, gHeight);
// ...
// Create Shader program
// Create VAO, VBO for triangle rendering
/* generate FBO for offscreen rendering */
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
/* generate null texture for framebuffer */
glGenTextures(1, &fb_tex);
glBindTexture(GL_TEXTURE_2D, fb_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gWidth, gHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
/* bind texture to FBO */
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex, 0);
GLenum status;
status = glCheckFramebufferStatus(GL_FRAMEBUFFER); // It retuns 0 error.
if (status != GL_FRAMEBUFFER_COMPLETE) {
printf("%s: FBO error: %#x\n", __func__, status);
glDeleteFramebuffers(1, &FBO);
return;
}
while (1)
Rendering();
void Rendering()
{
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(ShaderprogramObject);
glBindVertexArray(VAO);
glUniform1i(texLoc[0], 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);
/* dump offscreen FBO to file */
char *ptr = (char *)malloc(sizeof(char) * gWidth * gHeight * 4);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, gWidth, gHeight, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
RawFileWrite("./data/dump.raw", ptr);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
free(ptr);
}
- Note that Thread A and Thread B do not share resources. And Thread B does the headless rendering.
- If Thread B creates and binds the FBO and calls glCheckFramebufferStatus(), an error (0) is returned. (In this case, GL_NO_ERROR is returned when glGetError() is called.)
- Also, if Thread B is operated as a single process, no error occurs in the FBO, and if you read the FBO with glReadPixels(), it is rendered properly.
Are there any additional points to note when running multi-thread under the condition that resources are not shared?
Any advice will be appreciated!