PBO

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张图片PBO_第2张图片



创建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”。


#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;
}


参考:http://www.songho.ca/opengl/gl_pbo.html

你可能感兴趣的:(PBO)