
我最近被卡在帧缓冲区对象上,但是之前我已经了解了OpenGL ES,现在我更容易理解它了. 让我们现在总结一下.
基本知识
我们知道,在应用程序调用任何OpenGL ES命令之前,它首先需要创建一个渲染上下文和绘图表面,并将它们设为当前上下文和表面. 渲染时,始终使用本机窗口系统. (例如EAGL,GLFW)提供了渲染上下文和绘图表面(即帧缓冲区).
通常情况下,我们只需要系统提供的帧缓冲区作为绘图表面,但是有一些特殊情况需要渲染到阴影映射,动态反射,处理后的特殊效果等. 纹理(Render To Texture / RTT)操作,如果使用系统提供的帧缓冲区,效率将相对较低.
对于系统提供的帧缓冲区,如果要实现RTT,则有两种方法:
直接将帧缓冲区的相应区域分配给纹理以实现RTT. 使用glCopyTexImage2D / glCopyTexSubImage2D将颜色数据从帧缓冲区复制到纹理缓冲区. 由于需要复制数据,因此操作速度较慢,并且受EGLSurface的宽度和高度限制,因此纹理大小只能小于或等于帧缓冲区大小. 使用连接到纹理的pbuffer来实现RTT. 窗口系统提供的EGLSurface必须连接到EGLContext,但是pbuffer和EGLSurface可能需要不同的EGLContext,因此实现效率可能很低. 此外,在窗口系统提供的EGLSurface之间切换可能需要清除切换前渲染的所有图像,这将导致CPU空闲. 在这种情况下,建议不要使用它,因为与EGLSurface和EGLContext之间的切换相关的开销很大.
如果应用程序仅在屏幕表面上绘制,则窗口系统提供的帧缓冲区通常非常有效. 但是许多应用程序要求您渲染到纹理,并且使用提供的窗口并不理想,因此您需要自定义自己的帧缓冲区.
帧缓冲区对象API支持以下操作:
仅使用OpenGL ES命令创建帧缓冲区对象. 在单个EGL上下文中创建和使用多个帧缓冲区对象. 换句话说,不需要每个帧缓冲区都具有渲染上下文. 创建屏幕外的颜色,深度或模板渲染缓冲区和纹理,并将它们连接到帧缓冲区对象. 在多个帧缓冲区之间共享颜色,深度或模板缓冲区. 将纹理作为颜色或深度直接连接到帧缓冲区,从而避免了复制操作. 在帧缓冲区之间复制并使帧缓冲区的内容无效.
帧缓冲区对象是一组颜色,深度和模板纹理或渲染目标. 像默认帧缓冲区一样,自定义帧缓冲区还包括颜色缓冲区,深度和模板缓冲区. 这些逻辑缓冲区在FBO中称为可附加图像,它们是可以附加到FBO的二维像素阵列.
FBO包含两种类型的附加图像: 纹理图像和渲染缓冲区图像. 附加纹理时,OpenGL渲染到该纹理图像,可以在着色器中对其进行访问. 当附加到渲染缓冲区时,OpenGL执行屏幕外渲染.

但应注意,FBO可以连接多个缓冲区,并且可以在缓冲区之间灵活切换. FBO包含多个颜色附加点,并且各种2D图像可以连接到帧缓冲区对象. 附加点的颜色,但只有深度和模板附加点. 如下图所示:


使用帧缓冲对象
创建过程类似于创建VBO的过程.
void glGenFramebuffers(GLsizein,GLuint * ids)
void glDeleteFramebuffers(GLsizein,const GLuint * ids)
void glBindFramebuffer(GLenum目标,GLuint ID)
此处的对象类型是指与附着点相关的对象的类型. 如果要连接渲染缓冲区对象,则类型可以为GL_RENDERBUFFER,如果要连接纹理对象,则类型可以为GL_TEXTURE,但默认值为GL_NONE.
使用渲染缓冲区对象
void glGenRenderbuffers(GLsizein,GLuint * ids)

void glDeleteRenderbuffers(GLsizein,const Gluint * ids)
void glBindRenderbuffer(GLenum目标,GLuint ID)
绑定渲染缓冲区对象后,就可以指定保存在渲染缓冲区对象中的图像的大小和格式.
void glRenderbufferStorage(GLenum目标,
GLenum internalFormat,GLsizei宽度,GLsizei高度)
void glGetRenderbufferParameteriv(GLenum目标,GLenum参数,GLint *值)
附加
颜色附件可以分为渲染缓冲区附件或纹理附件.
glFramebufferTexture2D(GLenum目标,GLenum附件点,GLenum textureTarget,GLuint textureId,GLint级别)
void glFramebufferRenderbuffer(GLenum target,GLenum attachmentPoint,GLenum renderbufferTarget,GLuint renderbufferId)
实际上,您还可以将3D纹理的图像连接为帧缓冲区.
void glFramebufferTextureLayer(GLenum目标,GLenum附件,GLuint纹理,GLint级别,GLint层);
检查帧缓冲区的完整性
必须先将帧缓冲区对象定义为完整对象,然后才能将其用作渲染目标.
认为帧缓冲区对象完整的规则如下:
确保颜色,深度和模板附件有效;帧缓冲区至少具有一个有效的附件. 如果没有附件,则由于没有绘制或读取区域,因此帧缓冲区不完整. 与帧缓冲区对象关联的有效附件必须具有相同的宽度和高度. 如果有深度和模板附件,则它们的宽度和高度必须相同. 附加到所有渲染缓冲区的GL_RENDERBUFFER_SAMPLES值是相同的. 如果附件是渲染缓冲区和纹理的组合,则GL_RENDERBUFFER_SAMPLES的值为0.
glCheckFramebufferStatus命令可用于验证帧缓冲区对象是否完整,返回的是枚举以及是否完整.
GLenum glCheckFramebufferStatus(GLenum目标);
GLenum glCheckNamedFramebufferStatus(GLuint framebuffer,GLenum target);
帧缓冲区位块传输
帧缓冲区位块传输可以有效地将矩形区域的像素值从一个帧缓冲区(读取帧缓冲区)复制到另一帧缓冲区(绘制帧缓冲区). 帧缓冲区位阻塞的关键应用之一是将多次采样的渲染缓冲区解析为纹理(使用帧缓冲区对象并将纹理绑定作为其颜色附件).
void glBlitFramebuffer(GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield掩码,GLenum过滤器);
仅从es 3.0开始支持此功能.
帧缓冲区无效
帧缓冲区的无效为应用程序提供了一种机制,用于通知驱动程序不再需要帧缓冲区的内容. 由于可以通知无效性,因此驱动程序可以采取各种优化步骤: 1.跳过块渲染(TBR)体系结构中不必要的块内容修复,以进一步渲染到帧缓冲区; 2.跳过多GPU系统中各GPU之间不必要的数据复制; 3.跳过特定缓存的刷新,以提高某些实现中的性能. 此功能对于在许多应用程序(尤其是那些执行大量屏外渲染的应用程序)中达到最佳性能至关重要.
此功能仅在es 3.0中实现.
在了解帧缓冲器故障对GPU的重要性之前,我们需要了解TBR GPU的设计. TBR GPU通常部署在移动设备上,以最大程度地减少GPU和系统内存之间传输的数据量,从而减少最大的功耗用户之一,即内存带宽;这是通过添加可以节省少量像素数据的内置快速存储器的芯片来实现的. 实现时,将帧缓冲区划分为许多图块,对于每个图块,将原语呈现到内置在芯片中的内存中,然后在完成时将结果复制到系统内存中. 由于每个像素的最小数据量(最终像素结果)被复制到系统内存,因此该方法节省了GPU与系统内存之间的内存带宽.
通过帧缓冲区无效机制,GPU可以删除不再需要的帧缓冲区内容,以减少每个帧中保留的内容量. 此外,如果块数据不再有效,GPU也可以消除从芯片不必要的数据从内置存储器传输到系统存储器的问题,因为显着降低了GPU与系统存储器之间的存储器带宽需求,从而降低了功耗并提高了性能.
glInvalidateFramebuffer和glInvalidateSubFramebuffer命令用于使整个帧缓冲区或帧缓冲区的像素子区域无效.
void glInvalidateFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments);
void glInvalidateSubFramebuffer(GLenum目标,GLsizei numAttachments,const GLenum *附件,GLint x,GLint y,GLint宽度,GLint高度);
性能提示和技巧
使用帧缓冲区对象时应仔细考虑的性能提示:
避免在渲染到窗口系统提供的帧缓冲区和渲染到帧缓冲区对象之间频繁切换. 请勿逐帧创建和删除帧缓冲区和帧缓冲区对象(或任何其他大数据对象). 尝试避免修改附加到用作渲染图标的帧缓冲区对象的纹理,也就是说,将指定的纹理附加到帧缓冲区对象后,请勿对其进行修改(使用glTexImage2D,glTexSubImage2D,glCopyTexImage2D等). 如果将渲染整个纹理图像,请将glTexImage2D和glTexImage3D中的pixel参数设置为NULL,因为将不使用原始数据. 如果希望图像包含任何预定义的像素值,请在绘制到纹理之前使用glInvalidateFramebuffer清除纹理图像. 尽可能共享帧缓冲区对象使用的附件深度和模板渲染缓冲区,以确保最小的内存占用,但是应注意,帧缓冲区的宽度和高度必须相同.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-312477-1.html
早就不喝这玩意儿