FBO error 0 in multiple threads

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!

I solved the problem.

After a closer look at the code, I tried to create an EGL initialization and context in Thread A and use that context as is in Thread B. This is a very rudimentary mistake. I hope my mistake helps someone.