Hi,
I’m developing an app with three threads using PVRVFrame v9.8 libraries on MacOSX.
In this app, the main thread is only responsible for spawning the rendering thread and a thread for uploading resources (textures, VBOs, shaders, …). Main thread doesn’t know about EGL or OpenGL ES 2.0.
The rendering thread creates a EGLContext without sharing with any other EGLContext. After that, it creates a EGLWindowSurface and then calls eglMakeCurrent with these two new objects. When everything is set up, it calls glClear with red and then eglSwapBuffers.
The resource uploader thread creates a shared EGLContext with the context created in the rendering thread. After that, it creates a PbufferSurface. When this thread calls eglMakeCurrent, the app crashes.
No GL or EGL errors are generated during the calls.
I’m using OSX 10.9.3 X86-64, PowerVR Tools & SDK v3.3.
The dump points to the following address in eglMakeCurrent:
Thread 9 Crashed:
0 libEGL.dylib 0x000000010152ff5e eglMakeCurrent + 606
This is the Rendering Thread source code:
void RenderingThread::Impl::onStart()
{
LOGE(“RenderingThread::Impl::onStart: %p”, std::this_thread::get_id() );
//
EGL_CHECK(m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY));
assert(m_eglDisplay != EGL_NO_DISPLAY);
EGLBoolean displayInited;
EGL_CHECK(displayInited = eglInitialize(m_eglDisplay, NULL, NULL));
assert(displayInited);
//
EGLint numConfig = 0;
EGLint confAttribs[] = {
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
EGL_CHECK(eglChooseConfig(m_eglDisplay, confAttribs, &m_eglConfig, 1, &numConfig));
assert(numConfig == 1);
//
EGLBoolean apiBound;
EGL_CHECK(apiBound = eglBindAPI(EGL_OPENGL_ES_API));
assert(apiBound);
//
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
EGL_CHECK(m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttribs));
assert(m_eglContext != EGL_NO_CONTEXT);
LOGE("RenderingThread::Impl::getEGLContext::eglCreateContext: %p", m_eglContext);
//
EGL_CHECK(m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_eglNativeWindow, nullptr));
assert(m_eglSurface != EGL_NO_SURFACE);
//
EGLBoolean madeCurrent;
EGL_CHECK(madeCurrent = eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
assert(madeCurrent);
//
doTask();
}
void RenderingThread::Impl::doTask()
{
LOGE("RenderingThread::Impl::doTask: %p", std::this_thread::get_id());
GL_CHECK(glClearColor(1.0, 0.0, 0.0, 1.0));
GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
//
EGLBoolean bufferSwapped;
EGL_CHECK(bufferSwapped = eglSwapBuffers(m_eglDisplay, m_eglSurface));
assert(bufferSwapped);
}
This is the Resource Uploader source code:
void ResourceUploadThread::Impl::onStart()
{
LOGE("ResourceUploadThread::Impl::onStart: %p", std::this_thread::get_id() );
//
EGL_CHECK(m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY));
assert(m_eglDisplay != EGL_NO_DISPLAY);
EGLBoolean displayInited;
EGL_CHECK(displayInited = eglInitialize(m_eglDisplay, NULL, NULL));
assert(displayInited);
//
EGLint numConfig = 0;
EGLint confAttribs[] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_NONE
};
EGL_CHECK(eglChooseConfig(m_eglDisplay, confAttribs, &m_eglConfig, 1, &numConfig));
assert(numConfig == 1);
//
EGLBoolean apiBound;
EGL_CHECK(apiBound = eglBindAPI(EGL_OPENGL_ES_API));
assert(apiBound);
//
EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
LOGE("ResourceUploadThread::Impl::onStart::SharedContext: %p", m_eglSharedContext);
EGL_CHECK(m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, m_eglSharedContext, contextAttribs));
assert(m_eglContext != EGL_NO_CONTEXT);
//
EGLint surfaceAttribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
};
EGL_CHECK(m_eglSurface = eglCreatePbufferSurface(m_eglDisplay, m_eglConfig, surfaceAttribs));
assert(m_eglSurface != EGL_NO_SURFACE);
//
EGLBoolean madeCurrent;
EGL_CHECK(madeCurrent = eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
assert(madeCurrent);
//
doTask();
}
void ResourceUploadThread::Impl::doTask()
{
LOGE("RenderingThread::Impl::doTask: %p", std::this_thread::get_id());
GL_CHECK(glClearColor(0.0, 0.0, 1.0, 1.0));
GL_CHECK(glClear(GL_COLOR_BUFFER_BIT));
}
The example code that comes with SDK 3.3 (Examples/Intermediate/MultiThreading) doesn't have a pre built binary for OSX. Is this a sign that PVRVFrame is not thread safe? If this is the case, it this a fix that is scheduled for a near future?
Regards,
Augusto Righetto