Imagination PowerVR SDK Blog

Using eglMakeCurrent with PVRVFrame on multi threaded environment

pvrvframe

#1

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

#2

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)


#3

Hi Chris,



Thanks for you answer.

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



Regards,



Augusto