PBO(Pixel Buffer Object),将像素数据存储在显存中。
优点:
1、快速的像素数据传递,它采用了一种叫DMA(Direct Memory Access)的技术,无需CPU介入
2、 高效并不在于传输更快,而在于与硬件相关的异步调用方式,调用之后CPU即返回执行其它操作(使用DMA方式的传输、由OpenGL直接控制)
3、在单个PBO情况下并不能得到很好的效果,毕竟传输过程仍然存在(但速度可能变快,比如显存内部的数据传输),但其异步性就提供了双PBO实现的可能性,用双PBO来进行加速
左图是传统的加载一个纹理的示意图,可以看到,首先将纹理图像读到内存,然后再从内存拷贝到纹理对象中,这两个过程均需CPU的参与;而右图采用了PBO加载纹理,首先将像素数据加载到PBO中,然后通过DMA方式传送到纹理对象,最后一步不需要CPU参与。
创建PBO:
1. 用glGenBuffersARB()生成缓存对象;
2. 用glBindBufferARB()绑定缓存对象;
3. 用glBufferDataARB()将像素数据拷贝到缓存对象。
映射PBO:
void* glMapBufferARB(GLenum target, GLenum access);
GLboolean glUnmapBufferARB(GLenum target);
几个参数的释疑:
GL_PIXEL_PACK_BUFFER_ARB 将像素数据传给PBO
GL_PIXEL_UNPACK_BUFFER_ARB 从PBO得到像素数据
比如说,glReadPixel就是从帧缓存中读取数据,写到PBO中,可理解为“pack”;glDrawPixel是从PBO中读取数据,写到到帧缓存,可理解为“unpack”;glGetTexImage是从纹理对象到PBO,可理解为“pack”;glTexImage2d从PBO写到纹理对象(texture object),可理解为“unpack”。
[cpp] view plaincopy
- #include <iostream>
- #include <gl/glew.h>
- #include <gl/glut.h>
- using namespace std;
- GLuint pboIds[2];
- GLuint textureId; // Storage For 6 face Textures
- //camera
- float cameraAngleX;
- float cameraAngleY;
- float cameraDistance = -5.0;
- //mouse
- bool mouseLeftDown;
- bool mouseRightDown;
- float LastXPos;
- float LastYPos;
- const int IMAGE_WIDTH = 1024;
- const int IMAGE_HEIGHT = 1024;
- const int CHANNEL_COUNT = 4;
- const int DATA_SIZE = IMAGE_WIDTH * IMAGE_HEIGHT * CHANNEL_COUNT;
- GLubyte* imageData = 0;
- void initGL()
- {
- glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
- glShadeModel(GL_SMOOTH); // Enable Smooth Shading
- glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
- glGenTextures(1, &textureId);
- glBindTexture(GL_TEXTURE_2D, textureId);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, IMAGE_WIDTH, IMAGE_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)imageData);
- glBindTexture(GL_TEXTURE_2D, 0);
- glGenBuffers(2, pboIds);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[0]);
- glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, 0, GL_STREAM_DRAW);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[1]);
- glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, 0, GL_STREAM_DRAW);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- }
- void updatePixels(GLubyte* dst, int size)
- {
- static int color = 0;
- if(!dst)
- return;
- int* ptr = (int*)dst;
- // copy 4 bytes at once
- for(int i = 0; i < IMAGE_HEIGHT; ++i)
- {
- for(int j = 0; j < IMAGE_WIDTH; ++j)
- {
- *ptr = color;
- ptr++;
- }
- color += 257; // add an arbitary number (no meaning)
- }
- ++color; // scroll down
- }
- void display()
- {
- static int index = 0;
- int nextIndex = 0;
- index = (index + 1) % 2;
- nextIndex = (index + 1) % 2;
- glBindTexture(GL_TEXTURE_2D, textureId);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[index]);
- // copy pixels from PBO to texture object
- // Use offset instead of ponter.
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, 0);
- // bind PBO to update pixel values
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[nextIndex]);
- glBufferData(GL_PIXEL_UNPACK_BUFFER, DATA_SIZE, 0, GL_STREAM_DRAW);
- GLubyte* ptr = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
- if(ptr)
- {
- // update data directly on the mapped buffer
- updatePixels(ptr, DATA_SIZE);
- glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); // release pointer to mapping buffer
- }
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- glClear(GL_COLOR_BUFFER_BIT);
- glPushMatrix();
- // tramsform camera
- glTranslatef(0, 0, cameraDistance);
- glRotatef(cameraAngleX, 1, 0, 0); // pitch
- glRotatef(cameraAngleY, 0, 1, 0); // heading
- glBindTexture(GL_TEXTURE_2D, textureId);
- glColor4f(1, 1, 1, 1);
- glBegin(GL_QUADS);
- glNormal3f(0, 0, 1);
- glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 0.0f);
- glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 0.0f);
- glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f);
- glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);
- glEnd();
- glBindTexture(GL_TEXTURE_2D, 0);
- glPopMatrix();
- glutSwapBuffers();
- }
- void reshape(int w, int h)
- {
- glViewport(0, 0, w, h);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective(60.0f, (GLfloat)w/(GLfloat)h, 0.01f, 100.0f);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- }
- void mouse(int button, int state, int x, int y)
- {
- if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
- {
- mouseLeftDown = true;
- LastXPos = x;
- LastYPos = y;
- }
- if (button == GLUT_RIGHT_BUTTON && state == GLUT_UP)
- {
- mouseRightDown = true;
- }
- }
- void mouseMotion(int x, int y)
- {
- if (mouseLeftDown)
- {
- cameraAngleX += GLfloat(y - LastYPos)/GLfloat(20.0);
- cameraAngleY += GLfloat(x - LastXPos)/GLfloat(20.0);
- LastYPos = y;
- LastXPos = x;
- }
- }
- int main(int argc, char **argv)
- {
- imageData = new GLubyte[DATA_SIZE];
- memset(imageData, 0, DATA_SIZE);
- glutInit(&argc, argv);
- glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
- glutInitWindowSize(480, 640);
- glutInitWindowPosition(100, 100);
- glutCreateWindow("PBO");
- glewInit();
- if(!glewIsSupported("GL_VERSION_2_0"))
- {
- fprintf(stderr, "ERROR: Support for necessary OpengGL extensions missing.");
- }
- initGL();
- glutDisplayFunc(display);
- glutIdleFunc(display);
- glutReshapeFunc(reshape);
- glutMouseFunc(mouse);
- glutMotionFunc(mouseMotion);
- glutMainLoop();
- glDeleteBuffers(2, pboIds);
- glDeleteTextures(1, &textureId);
- delete []imageData;
- return 0;
- }