像素缓冲区对象(PBO)的异步Read-Back 源码解析
来源:互联网 发布:淘宝网如何注销账户 编辑:程序博客网 时间:2024/05/01 00:38
接这篇文章 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 还是略有提高的。
0 0
- 像素缓冲区对象(PBO)的异步Read-Back 源码解析
- 像素缓冲区对象(PBO) 的Streaming-Texture上传 源码解析
- 最简单的PBO(异步Read-Back)Demo 完整代码示例
- OpenGL深入探索——像素缓冲区对象 (PBO)
- OpenGL系列教程之九:OpenGL像素缓冲区对象(PBO)
- OpenGL系列教程之九:OpenGL像素缓冲区对象(PBO)
- OpenGL像素缓冲对象(PBO)
- OpenGL super bible(5th) 学习笔记 -- 像素缓冲区对象(PBO)
- OpenGL像素缓冲区对象
- OpenGL像素缓冲区对象
- 《Java源码解析》NIO中Buffer缓冲区的实现
- Read() 和 ReadLine() 的区别-------缓冲区问题
- PBO
- PBO
- VBO与PBO,DMA异步快速传递
- 深入解析RxJava源码(一)Observable对象的构建
- 有關 Cache 的 read/write through/back/allocate
- android源码解析-异步消息
- CentOS6.5 + Nginx1.10.2 + FastDFS5.08
- 5.视图
- HashSet
- 《Effective C++》学习笔记——条款45
- 技术的坚持
- 像素缓冲区对象(PBO)的异步Read-Back 源码解析
- Linux进程管理简介及进程管理工具
- Android 性能优化 内存优化 How to do
- Codeforces Round #379 (Div. 2)
- Linux内核移植--开机动画
- AngularJS 的基础使用
- 东秦第四届图灵杯-G-爬楼梯【DP】
- 闲聊阿里加固(一)
- letcode5 最长回文子串