像素缓冲区对象(PBO)的异步Read-Back 源码解析
【摘要】
接这篇文章 OpenGL深入探索——像素缓冲区对象 (PBO)(附完整工程代码地址)
原理示意图如下:
关键代码如下:
int main(int argc, char **argv){ initSharedMem(); // register exit callback atexit(exitC...
接这篇文章 OpenGL深入探索——像素缓冲区对象 (PBO)(附完整工程代码地址)
原理示意图如下:
关键代码如下:
-
int main(int argc, char **argv)
-
{
-
initSharedMem();
-
-
// register exit callback
-
atexit(exitCB);
-
-
// init GLUT and GL
-
initGLUT(argc, argv);
-
initGL();
-
-
// get OpenGL info
-
glInfo glInfo;
-
glInfo.getInfo();
-
glInfo.printSelf();
-
-
#ifdef _WIN32
-
// 检查视频显卡是否支持 PBO
-
if (glInfo.isExtensionSupported("GL_ARB_pixel_buffer_object"))
-
{
-
// get pointers to GL functions
-
glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB");
-
glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB");
-
glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB");
-
glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)wglGetProcAddress("glBufferSubDataARB");
-
glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB");
-
glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)wglGetProcAddress("glGetBufferParameterivARB");
-
glMapBufferARB = (PFNGLMAPBUFFERARBPROC)wglGetProcAddress("glMapBufferARB");
-
glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)wglGetProcAddress("glUnmapBufferARB");
-
-
// check once again PBO extension
-
if (glGenBuffersARB && glBindBufferARB && glBufferDataARB && glBufferSubDataARB &&
-
glMapBufferARB && glUnmapBufferARB && glDeleteBuffersARB && glGetBufferParameterivARB)
-
{
-
pboSupported = pboUsed = true;
-
std::cout << "Video card supports GL_ARB_pixel_buffer_object." << std::endl;
-
}
-
else
-
{
-
pboSupported = pboUsed = false;
-
std::cout << "Video card does NOT support GL_ARB_pixel_buffer_object." << std::endl;
-
}
-
}
-
-
// check EXT_swap_control is supported
-
if (glInfo.isExtensionSupported("WGL_EXT_swap_control"))
-
{
-
// get pointers to WGL functions
-
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
-
wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
-
if (wglSwapIntervalEXT && wglGetSwapIntervalEXT)
-
{
-
// disable v-sync
-
wglSwapIntervalEXT(0);
-
std::cout << "Video card supports WGL_EXT_swap_control." << std::endl;
-
}
-
}
-
-
#else // for linux, do not need to get function pointers, it is up-to-date
-
if (glInfo.isExtensionSupported("GL_ARB_pixel_buffer_object"))
-
{
-
pboSupported = pboUsed = true;
-
std::cout << "Video card supports GL_ARB_pixel_buffer_object." << std::endl;
-
}
-
else
-
{
-
pboSupported = pboUsed = false;
-
std::cout << "Video card does NOT support GL_ARB_pixel_buffer_object." << std::endl;
-
}
-
#endif
-
-
if (pboSupported)
-
{
-
// create 2 pixel buffer objects, you need to delete them when program exits.
-
//(创建两个 PBO)
-
// glBufferDataARB with NULL pointer reserves only memory space.
-
glGenBuffersARB(PBO_COUNT, pboIds);
-
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[0]);
-
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);
-
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[1]);
-
glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_READ_ARB);
-
-
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
-
}
-
-
// start timer, the elapsed time will be used for updateVertices()
-
timer.start();
-
-
// the last GLUT call (LOOP)
-
// window will be shown and display callback is triggered by events
-
// NOTE: this call never return main().
-
glutMainLoop(); /* Start GLUT event-processing loop */
-
-
return 0;
-
}
-
void displayCB()
-
{
-
static int shift = 0;
-
static int index = 0;
-
int nextIndex = 0; // pbo index used for next frame
-
-
// brightness shift amount
-
shift = ++shift % 200;
-
-
// increment current index first then get the next index(增加当前的index,再获得 nextIndex)
-
// "index" is used to read pixels from a framebuffer to a PBO(从 FB 中读取像素到 index 指定的 PBO 中)
-
// "nextIndex" is used to process pixels in the other PBO(nextIndex 指定 PBO 中待处理的像素[先前从 FB 中读取])
-
index = (index + 1) % 2; // 两个 PBO 交替
-
nextIndex = (index + 1) % 2;
-
-
// set the framebuffer to read(设置当前读取的 FB)
-
glReadBuffer(GL_FRONT);
-
-
if (pboUsed) // with PBO
-
{
-
// read framebuffer ///
-
t1.start(); // 启动计时器,计算读取 FB 到 PBO 的时间
-
-
// copy pixels from framebuffer to PBO (从 FB 中拷贝像素到 index指定的 PBO 中)
-
// Use offset instead of ponter.(注意glReadPixels最后一个参数不是指针,而是偏移量)
-
// OpenGL should perform asynch DMA transfer, so glReadPixels() will return immediately.
-
//(OpenGL 将执行一个异步的DMA[Direcct Memory Access],所以 glReadPixels方法会立刻返回,不会阻塞CPU时间)
-
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[index]);
-
glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_FORMAT, GL_UNSIGNED_BYTE, 0);
-
-
// measure the time reading framebuffer
-
t1.stop();
-
readTime = t1.getElapsedTimeInMilliSec();
-
///
-
-
// process pixel data /
-
t1.start(); // 启动计时器,计算处理 PBO中像素的时间
-
-
// map the PBO that contain framebuffer pixels before processing it
-
//(映射存储着先前 FB 像素的 PBO ,便于处理像素)
-
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboIds[nextIndex]);
-
// 后续的 add() 并没有改变 PBO 中的像素值,计算的结果保存在 colorBuffer 中,所以标记为只读
-
GLubyte *src = (GLubyte *)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
-
if (src)
-
{
-
// change brightness
-
add(src, SCREEN_WIDTH, SCREEN_HEIGHT, shift, colorBuffer);
-
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); // release pointer to the mapped buffer
-
}
-
-
// measure the time processing the pixels of PBO
-
t1.stop();
-
processTime = t1.getElapsedTimeInMilliSec();
-
///
-
-
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
-
}
-
else // without PBO
-
{
-
// read framebuffer ///
-
t1.start();
-
// 不使用 PBO 的情况下,最后一个参数就是保存读取数据的指针
-
glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_FORMAT, GL_UNSIGNED_BYTE, colorBuffer);
-
-
// measure the time reading framebuffer
-
t1.stop();
-
readTime = t1.getElapsedTimeInMilliSec();
-
///
-
-
// covert to greyscale
-
t1.start();
-
-
// change brightness
-
add(colorBuffer, SCREEN_WIDTH, SCREEN_HEIGHT, shift, colorBuffer);
-
-
// measure the time reading framebuffer
-
t1.stop();
-
processTime = t1.getElapsedTimeInMilliSec();
-
///
-
}
-
-
// render to the framebuffer //
-
glDrawBuffer(GL_BACK); // 设定绘制在后缓冲区
-
toPerspective(); // set to perspective on the left side of the window(当前窗口左侧的投影矩阵)
-
-
// clear buffer
-
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-
-
// tramsform camera
-
glTranslatef(0, 0, -cameraDistance);
-
glRotatef(cameraAngleX, 1, 0, 0); // pitch
-
glRotatef(cameraAngleY, 0, 1, 0); // heading
-
-
// draw a cube(在左侧绘制普通的立方体)
-
glPushMatrix();
-
draw();
-
glPopMatrix();
-
-
// draw the read color buffer to the right side of the window
-
//(在右侧绘制之前处理的 colorBuffer)
-
toOrtho(); // set to orthographic on the right side of the window(窗口右侧的正交矩阵[想象为把左侧的图处理一下直接贴上去])
-
glRasterPos2i(0, 0); // 设置字体光栅的位置
-
glDrawPixels(SCREEN_WIDTH, SCREEN_HEIGHT, PIXEL_FORMAT, GL_UNSIGNED_BYTE, colorBuffer);
-
-
// draw info messages
-
showInfo();
-
printTransferRate();
-
-
glutSwapBuffers();// 切换前后缓冲区
-
}
程序的执行对比情况:
可见通过 PBO的异步read-back技术,FPS 还是有明显提高的(我的显卡是 GeForce GTX 970,CPU 是 i7-6700 HQ,主频为2.6GHz)。
文章来源: panda1234lee.blog.csdn.net,作者:panda1234lee,版权归原作者所有,如需转载,请联系作者。
原文链接:panda1234lee.blog.csdn.net/article/details/53270443
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)