Using eglMakeCurrent with PVRVFrame on multi threaded environment

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

Hi Augusto,



Multithreading support on OSX is a little buggy at the moment, but it’s something I’ve been looking into recently as it’s gone overlooked for far too long. I believe the issue you’re seeing is due to an uninitialized variable bug within the emulation libraries.



If you like, you can file a ticket at our support portal requesting a beta version of PVRVFrame for testing. Otherwise, this should be fixed in the next SDK release (along with the MultiThreading example for OSX)

Hi Chris,



Thanks for you answer.

I`ve created a ticket in your support portal. Thanks for the link.



Regards,



Augusto