OpenGL超级宝典笔记(n)PBO缓冲区

7 篇文章 0 订阅
4 篇文章 0 订阅

前略好几章都没放上来,以后再补上吧。
之前一直使用gltools的GLBatch来填充数据传给shader,现在直接用自己的buffer来传数据了。

不外乎几步:

  1. 弄一个buffer指针,其实弄一个buffer数组也可以了,数组可以记得个数,指针可不能,容易出事儿
  2. 就这么着吧,算是上一步弄了个buffer数组,那数组名就是一个指针了,现在把指针传给OpenGL来分配一个buffer
    unsigned int n = 1;
    GLuint buffers[n];
    glGenBuffer(n, buffers);
    
  3. 接下来就是针对某一个buffer来bind了,bind的时候要说明用处,比如
    glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); // 当然想写成*buffers也可以
    
    上面提及这种类型就是可以拿来放顶点啊,颜色啊,纹理坐标啥的。
    迄今为止见过的还有GL_TEXTURE_BUFFER, GL_UNIFORM_BUFFER
  4. 用完之后不想要了就要删除,但是要保证buffer没有被绑定为任何用途。
    glDeleteBuffers(1, buffers);
    

另外,怎么传输数据是个问题。

glBufferData(GL_PIXEL_PACK_BUFFER, dataSize, data, GL_DYNAMIC_COPY);

第一个参数是绑定点(what?),第二个参数是用途。
不知道用啥的时候就用GL_DYNAMIC_DRAW
使用glBufferData之后原来缓冲区的所有东西会被删除,重新进行填充。
如只想更新部分数据而不清空旧有,可以使用

void glBufferSubData(GLenum target, intptr offset, sizeiptr size, const void data*);

why

为啥使用缓冲区。
在使用缓冲区的时代之前,要向OpenGL传递纹理需要通过CPU先把内容复制到ram,再在需要的时候,命令CPU把内容从RAM传给OpenGL。坏处有二:

  • RAM速度没有显存速度快 用的还是内存,并不是显存
  • 同步操作,占用CPU周期,浪费CPU时间

使用缓冲区之后,这一过程变成了:CPU把内容交给PBO,而PBO是OpenGL管理的(也即是GPU管理),在需要的时候OpenGL直接通过DMA(直接存取)来读取PBO,不需要经过CPU。这就是异步过程,不影响CPU周期。

图如下:

在这里插入图片描述

以上均整理自:http://www.songho.ca/opengl/gl_pbo.html

pack

关于pack和unpack。
GL_PIXEL_PACK_BUFFER模式下时,使用glReadPixels可以从帧缓存读取像素写到pbo。
GL_PIXEL_UNPACK_BUFFER模式下,使用glDrawPixels把像素从pbo写入帧缓存。

修改内存

使用void* glMapBuffer(target, access)可以获得地址,如果找不到会返回nullptr。

target可能的值有:

  • GL_PIXEL_PACK_BUFFER
  • GL_PIXEL_UNPACK_BUFFER

access可能的值:

  • GL_READ_ONLY
  • GL_WRITE_ONLY
  • GL_READ_WRITE

如果GPU正在操作这个buffer,glMapBuffer就会一直等待直到GPU同步完buffer信息。为了避免这个无用的等待,最好就是使用空指针来调用glBufferData,这会让这块空内存上啥都没有,然后马上调用glMapBuffer。这时,OpenGL会丢弃老的buffer,然后重新分配一块新的内存给它。

注意
在使用完pbo之后,必须调用glUnmapBuffer(),如果成功了,会返回一个GL_TRUE。

分配

在分配的时候没啥要注意的,如果是为纹理分配,那分配的空间就是长*宽*像素大小。

READ FRAMEBUFFER

从当前帧获取像素数据,使用glReadPixels

不使用pbo:

void *data = (void*)malloc(pixelDataSize);
glReadBuffer(GL_BACK_LEFT);
glReadPixels(0, 0, GetWidth(), GetHeight(), GL_RGB, GL_UNSIGNED_BTYE, pixelData);

使用pbo:

glReadBuffer(GL_BACK_LEFT);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pixBuffObjs[0]);
glReadPixels(0, 0, GetWidth(), GetHeight(), GL_RGB, GL_UNSIGNED_BYTE, NULL);

这就把数据读入了pbo。

使用pbo来做模糊效果。思路是存储前面五帧来和当前帧做混合。
说一下主要套路:

setup阶段
  1. 从硬盘读出bmp图片纹理
  2. 申请6个texture,全都用bmp纹理初始化
  3. 申请一个buffer并初始化,初始化的内容可以是空指针,但大小一定要指定
    // 这个时候啥功能都可以,pack或者unpack都行
    glBindBuffer(GL_PIXEL_PACK_BUFFER, g_bufferObjs[0]);
    glBufferData(GL_PIXEL_PACK_BUFFER, size, dataPtr, GL_DYNAMIC_DRAW);
    // 解绑
    glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
    
render阶段
  1. 从屏幕把像素打包到buffer
    glBindBuffer(GL_PIXEL_PACK_BUFFER, g_bufferObjs[0]);
    glReadPixels(0, 0, screenWidth, screenHeight, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
    glBindBuffer(GL_PIXEL_PACK_BUFFER, *g_bufferObjs);
    
  2. 这个时候buffer里面已经是慢慢的屏幕信息啦!接下来要从buffer里面把信息写入到texture。先把buffer先切到解包模式,才能写入到texture或者屏幕,然后切换到目标texture,写入,最后解绑buffer。
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, *g_bufferObjs);
    glActiveTexture(GL_TEXTURE0 + GetBlurTarget0());
    // 当数据是nullptr的时候,就读缓冲区~
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, screenWidth, screenHeight, 0, GL_UNSIGNED_BYTE, NULL);
    
  3. 最后一步是改写shader。片段shader要去读0~5号sampler,然后把结果叠加起来!
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值