failed when calling glReadPixels

Posted on Updated on

I create an CGLContextObject, and would like to read frame buffer into a memory buffer to capture the current screen.
But it always failed when the sub-thread calls glReadPixels.

Root cause:
glReadPixels() not called in the same thread with CGLSetCurrentContext(contextobj) and CGLSetFullScreen( contextobj)

Solution:
the call sequence should be

  1. init OpenGL context object
  2. create thread to read image back from frame buffer
  3. call CGLSetCurrentContext(context_object) , CGLSetFullScreen(context_object), CGLSetFullScreen is optional
  4. loop glReadPixels
  5. call CGLSetCurrentContext(NULL);
  6. exit thread
  7. release OpenGL context object


the WRONG function calls looks like the following ( the codes couldn’t run, just pseudo codes)


void *threadFun(void * param)
{

... some codes
while ( run)
{
CapScreenFetchDataToContextFast( context, data, width, height,bytewidth, packedPixelFormat , mutex) ;
}
... some codes
pthread_exit( (void*) 0) ;

}


main()
{

pthread_attr_t attr;
pthread_attr_init(&attr,NULL);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZE;

CapScreenInitGLContextObj( glContextObj, mutex) ;
pthread_create(&thread,NULL,threadFun, NULL);

pthread_join(&thread);
void CapScreenReleaseGLContextObj(CGLContextObj glContextObj, pthread_mutex_t *mutex);
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&mutex);
pthread_exit( (void*) 0);

}

/* sub-routines */
int CapScreenFetchDataToContextFast(CGContextRef context, void * data, size_t width, size_t height,size_t bytewidth, GLenum packedPixelFormat , pthread_mutex_t *mutex)

{

if ( context == NULL)
return -1;

if ( data == NULL)
return -2;

pthread_mutex_lock( mutex) ;

glReadPixels( 0, 0, width, height, GL_BGRA, packedPixelFormat, data); < --- CRASHED HERE
pthread_mutex_unlock( mutex) ;

}
/*
* create and initiate OpenGL Context
*/
int CapScreenInitGLContextObj( CGLContextObj *glContextObj, pthread_mutex_t * mutex)
{

CGLPixelFormatObj pixelFormatObj ;
long numPixelFormats ;
CGDirectDisplayID display ;
CGLPixelFormatAttribute attribs[] =
{
kCGLPFAFullScreen,
kCGLPFADisplayMask,
(CGLPixelFormatAttribute) 0, /* Display mask bit goes here */
(CGLPixelFormatAttribute) 0
} ;

//if ( display == kCGNullDirectDisplay )
display = CGMainDisplayID();
attribs[2] = (CGLPixelFormatAttribute) CGDisplayIDToOpenGLDisplayMask(display);

/* Build a full-screen GL context */
CGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats );
if ( pixelFormatObj == NULL ) // No full screen context support
return -1;

pthread_mutex_lock( mutex) ;

CGLCreateContext( pixelFormatObj, NULL, glContextObj ) ;
CGLDestroyPixelFormat( pixelFormatObj ) ;
if ( glContextObj == NULL )
return -2;
USELESS CODES
CGLSetCurrentContext( *glContextObj ) ;
CGLSetFullScreen( *glContextObj ) ;

glReadBuffer(GL_FRONT);

/* Read framebuffer into our bitmap */
glFinish(); /* Finish all OpenGL commands */
glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

pthread_mutex_unlock( mutex) ;

return 1 ;

}

/*
* Release Context and OpenGL context object and dsassociate from full screen
*/
void CapScreenReleaseGLContextObj(CGLContextObj glContextObj, pthread_mutex_t *mutex)
{

pthread_mutex_lock( mutex) ;
/* Get rid of GL context */
CGLSetCurrentContext( NULL );
if ( glContextObj != NULL)
{
CGLClearDrawable( glContextObj ); // disassociate from full screen
CGLDestroyContext( glContextObj ); // and destroy the context
}
pthread_mutex_unlock( mutex) ;

}

The root cause of that glReadPixels failed is glReadPixels can’t get the correct address to read the frame buffer, so the sub-routines sould be modified as following:



void *threadFun(void * param)
{

... some codes

CGLSetCurrentContext( glContextObj ) ;
CGLSetFullScreen( glContextObj ) ;

while ( run)
{
CapScreenFetchDataToContextFast( context, data, width, height,bytewidth, packedPixelFormat , mutex) ;
}

CGLSetCurrentContext(NULL) ;
CGLSetFullScreen(NULL ) ;

... some codes
pthread_exit( (void*) 0) ;

}

int CapScreenFetchDataToContextFast(CGContextRef context, void * data, size_t width, size_t height,size_t bytewidth, GLenum packedPixelFormat , pthread_mutex_t *mutex)

{

if ( context == NULL)
return -1;

if ( data == NULL)
return -2;

pthread_mutex_lock( mutex) ;

glReadBuffer(GL_FRONT);

/* Read framebuffer into our bitmap */
glFinish(); /* Finish all OpenGL commands */
glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

glReadPixels( 0, 0, width, height,
GL_BGRA,
packedPixelFormat,
data);
pthread_mutex_unlock( mutex) ;

}

/*
* create and initiate OpenGL Context
*/
int CapScreenInitGLContextObj( CGLContextObj *glContextObj, pthread_mutex_t * mutex)
{

CGLPixelFormatObj pixelFormatObj ;
long numPixelFormats ;
CGDirectDisplayID display ;
CGLPixelFormatAttribute attribs[] =
{
kCGLPFAFullScreen,
kCGLPFADisplayMask,
(CGLPixelFormatAttribute) 0, /* Display mask bit goes here */
(CGLPixelFormatAttribute) 0
} ;

//if ( display == kCGNullDirectDisplay )
display = CGMainDisplayID();
attribs[2] = (CGLPixelFormatAttribute) CGDisplayIDToOpenGLDisplayMask(display);

/* Build a full-screen GL context */
CGLChoosePixelFormat( attribs, &pixelFormatObj, &numPixelFormats );
if ( pixelFormatObj == NULL ) // No full screen context support
return -1;

pthread_mutex_lock( mutex) ;

CGLCreateContext( pixelFormatObj, NULL, glContextObj ) ;
CGLDestroyPixelFormat( pixelFormatObj ) ;
if ( glContextObj == NULL )
return -2;


CGLSetCurrentContext( *glContextObj ) ;
CGLSetFullScreen( *glContextObj ) ;
glReadBuffer(GL_FRONT);
/* Read framebuffer into our bitmap */
glFinish(); /* Finish all OpenGL commands */
glPixelStorei(GL_PACK_ALIGNMENT, 4); /* Force 4-byte alignment */
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);

pthread_mutex_unlock( mutex) ;

return 1 ;

}

廣告

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s