缓存对象(Buffer Object)简介
OpenGL Buffer Object(缓存对象,简写BO),是OpenGL管理的一段内存,为了与我们CPU的内存区分开,一般叫OpenGL管理的内存,叫显存。
为了区分内存与显存,我这里从京东上搜索了内存条与显卡,如下图,这是一张显卡的截图,显卡使用的DDR为GDDR5,就是我们的显存,这个2G就表示这个显存的大小为2G。
再看内存,内存条,下面的内存条,使用的是DDR4,这里有2根,容量大小为8GB。
内存,是通过PCIE插槽,插在主板上的,也就是位于主板上的DDR。CPU访问内存比较快。
显存,其实就是位于显卡内部的DDR。显卡访问显存比较快。而Buffer Object,就是由OpenGL维护的一块显存区域。比如说上面的显卡显存为2G, 我从这个2G里面,分配 32K的大小给我用,这个32K大小的区域,就叫一个Buffer Object。
那为什么需要Buffer Object呢?这个,主要就是我们的显卡,访问显存,比访问内存要快很多。正如你到隔壁邻居家,比到你远方亲戚家,要近很多,这个叫远亲不如近邻,对吧。而且显卡做运算,一般都是访问显存的数据,然后运算的结果,也都保存在显存中。所以一般,我们需要先把数据,从内存传输到显存中去。
缓存对象操作函数
- 分配缓存对象名字, glGenBuffers
- 绑定缓存对象到OpenGL的目标上, glBindBuffer
- 给缓存对象,分配显存,并将内存数据,传输到显存,glBufferData
- 删除缓冲区对象, glDeleteBuffers
- 缓冲区对象,映射到内存上,glMapBuffer,解除映射glUnmapBuffer
这几个函数的具体解释,书上都有。这里就不解释了。
但是我想说一下, glBindBuffer的目标点target。
假如target为GL_ARRAY_BUFFER,说明这个Buffer Object是用来存储顶点数据的,那么就说这个Buffer Object为 Vertex Buffer Object,也就是我们的VBO。
假如target为GL_PIXEL_PACK_BUFFER和GL_PIXEL_UNPACK_BUFFER,那么这个Buffer Object为Pixel Buffer Object,也就是我们的PBO。
所以, 这个Buffer Object,就是一块显存区域。这个显存区域,存放顶点数据,就叫VBO,存放图像数据,就叫PBO,根据它glBindBuffer的 target不同,就有不同的叫法。这样就很好理解这个BO,那个BO了。
缓存对象操作实例
下面的代码,展示了数据在内存和显存之间传输,说明了如何使用Buffer Object。
- 开辟了一个内存,mem,mem的大小为64,里面数据,填了64个0x18
- 创建了一个Buffer Object,并使用mem的内容,初始化Buffer Object
- 将Buffer Object的内容,映射出来,然后与我们mem的内容进行比较
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <GL3/gl3w.h>
#include <GLFW/glfw3.h>
void testbo()
{
char* mem = (char*)malloc(64);
memset(mem, 0x18, 64);
/*创建Buffer Object,并将内存mem里面的数据,传输到显存里面去*/
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_COPY_WRITE_BUFFER, buffer);
glBufferData(GL_COPY_WRITE_BUFFER, 64, mem, GL_STATIC_DRAW);
/*将显存数据,映射出来,然后跟内存数据进行比较,两者应该一致*/
void* data = glMapBuffer(GL_COPY_WRITE_BUFFER, GL_READ_WRITE);
printf("data = %p, mem = %p\n", data, mem);
printf("0x%x \n", *((unsigned int*)(data)));
int ret = memcmp(data, mem, 64);
assert(ret == 0);
glUnmapBuffer(GL_COPY_WRITE_BUFFER);
free(mem);
glDeleteBuffers(1, &buffer);
printf("test bo succeed \n");
}
int main(int argc, char** argv)
{
glfwInit();
GLFWwindow* window = glfwCreateWindow(800, 600, "Triangles", NULL, NULL);
glfwMakeContextCurrent(window);
gl3wInit();
testbo();
glfwTerminate();
return 0;
}