最近在帧缓冲区对象这里卡了一下,不过前面已经了解了相关的OpenGL ES的知识,现在再去了解就感觉轻松多了。现在就进行总结。

基础知识

我们知道,在应用程序调用任何的OpenGL ES命令之前,需要首先创建一个渲染上下文和绘图表面,并使之成为现行上下文和表面,之前在渲染的时候,其实一直使用的是原生窗口系统(比如EAGL,GLFW)提供的渲染上下文和绘图表面(即帧缓冲区)。

一般情况下,我们只需要系统提供的帧缓冲区作为绘图表面,但是又有些特殊情况,比如阴影贴图、动态反射、处理后特效等需要渲染到纹理(Render To Texture/RTT)操作的,如果使用系统提供的帧缓冲区,效率会比较低低下。

对于系统提供的帧缓冲区,如果要实现RTT,有下面两种方式:

  1. 直接将帧缓冲区的对应区域赋值到纹理来实现RTT。借助glCopyTexImage2D/glCopyTexSubImage2D来从帧缓冲区复制颜色数据到纹理缓冲区,因为需要复制数据,所以操作比较慢,而且受限于EGLSurface的宽高尺寸,纹理的尺寸只能小于等于帧缓冲区尺寸大小。
  2. 使用连接到纹理的pbuffer来实现RTT。窗口系统提供的EGLSurface必须连接到EGLContext,但是pbuffer和EGLSurface可能需要不同的EGLContext,这样实现可能效率低。而且,在窗口系统提供的EGLSurface之间转换可能需要清除所有切换之前渲染的图像,这会造成CPU的闲置,这种情况下建议不要使用,因为EGLSurface和EGLContext切换相关的开销很大。

如果应用程序只在屏幕上的表面绘图,则窗口系统提供的帧缓冲区通常很高效。但是很多应用程序需要你渲染到纹理,使用窗口提供的不太理想,因此需要自定义自己的帧缓冲区。

帧缓冲区对象API支持以下操作:

  1. 仅使用OpenGL ES命令创建帧缓冲区对象。
  2. 在单一EGL上下文中创建和使用多个帧缓冲区对象。也就是说,不需要每个帧缓冲区都有一个渲染上下文。
  3. 创建屏幕外颜色,深度或者模版渲染缓冲区和纹理,并将它们连接到帧缓冲区对象。
  4. 在多个帧缓冲区之间共享颜色、深度或者模版缓冲区。
  5. 将纹理直接连接到帧缓冲区作为颜色或者深度,从而避免了进行复制操作的必要。
  6. 在帧缓冲区之间复制并使帧缓冲区内容失效。

帧缓冲区对象是一组颜色、深度和模版纹理或者渲染目标,和默认的帧缓冲区一样,自定义的帧缓冲区也包括颜色缓冲区、深度和模版缓冲区,这些逻辑上的缓冲区在FBO中称之为可附加的图像,它们是可以附加到FBO的二维像素数组。

FBO包含两种类型的附加图像,纹理图像和渲染缓冲区图像。附加纹理时,OpenGL渲染到这个纹理图像,在着色器中可以访问到这个纹理对象;附加到渲染缓冲区时,OpenGL执行离屏渲染。

但是需要注意的地方是,FBO可以附加多个缓冲区,而且可以灵活的在缓冲区进行切换,FBO中包含一个以上的颜色附加点,各种2D图像可以连接到帧缓冲区对象中的颜色附加点,但是只有一个深度和模版附加点。如下图:

使用帧缓冲区对象

创建的过程和创建VBO是类似的。

void glGenFramebuffers(GLsizei n, GLuint* ids)

void glDeleteFramebuffers(GLsizei n, const GLuint* ids)

void glBindFramebuffer(GLenum target, GLuint id)

这里的对象类型是指与附着点相关的对象的类型,如果要连接一个渲染缓冲区对象,则类型可以是GL_RENDERBUFFER,如果连接的是一个纹理对象,那么类型可以是GL_TEXTURE,但是默认值是GL_NONE。

使用渲染缓冲区对象

void glGenRenderbuffers(GLsizei n, GLuint* ids)

void glDeleteRenderbuffers(GLsizei n, const Gluint* ids)

void glBindRenderbuffer(GLenum target, GLuint id)

一旦绑定渲染缓冲区对象,就可以指定保存在渲染缓冲区对象中的图像大小和格式。

void glRenderbufferStorage(GLenum target,
GLenum internalFormat, GLsizei width, GLsizei height)

void glGetRenderbufferParameteriv(GLenum target, GLenum param, GLint* value)

附着

其中颜色附着可以分为渲染缓冲区附着或者纹理附着

glFramebufferTexture2D(GLenum target,GLenum attachmentPoint,GLenum textureTarget,GLuint textureId, GLint level)

void glFramebufferRenderbuffer(GLenum target,GLenum attachmentPoint, GLenum renderbufferTarget, GLuint renderbufferId)

其实还可以连接3D纹理的一个图像作为帧缓冲区附着。

void glFramebufferTextureLayer(GLenum target,GLenum attachment, GLuint texture, GLint level, GLint layer);

检查帧缓冲区完整性

帧缓冲区对象必须定义为完整的才能够用作渲染目标。

其中帧缓冲区对象被视为完整的规则如下:

  1. 确保颜色、深度和模版附着有效;帧缓冲区至少有一个有效的附着,如果没有任何附着,那么帧缓冲区则是不完整的,因为没有可以绘制或者读取的区域。
  2. 与帧缓冲区对象相关的有效附着必须有相同的宽度和高度。
  3. 如果存在深度和模版附着,则它们必须是相同的宽度和高度。
  4. 所有渲染缓冲区附着的GL_RENDERBUFFER_SAMPLES值都相同。如果附着是渲染缓冲区和纹理的结合,则GL_RENDERBUFFER_SAMPLES的值为0。

glCheckFramebufferStatus命令可用于验证帧缓冲区对象是否完整,其返回的是一个枚举,是否完整。

GLenum glCheckFramebufferStatus( GLenum target);

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 mask, GLenum filter);

这个函数是从es 3.0才开始支持。

帧缓冲区失效

帧缓冲区失效为应用程序提供了一个通知驱动程序不再需要帧缓冲区内容的机制。因为可以通知无效,所以这可以使得驱动程序采取多种优化步骤:1.跳过在块状渲染(TBR)架构中为了进一步渲染到帧缓冲区而做的不必要的图块内容修复;2.跳过多GPU系统中GPU之间不必要的数据复制;3.跳过某些实现中为了改进性能而对特定缓存的刷新。这种功能对于许多应用程序中实现峰值性能很重要,特别是那些执行大量屏幕外渲染的应用。

这个函数在es 3.0中才会实现。

我们需要先了解TBR GPU中的设计,才能知道帧缓冲区失效对于GPU的重要性。TBR GPU常常部署在移动设备上,以最小化GPU和系统内存之间数据传输量,从而减少最大的电力消耗者之一,内存带宽;这通过添加能够保存少量像素数据的芯片内建快速存储器来实现,然后,帧缓冲区被区分为许多个图块,对于每个图块,图元被渲染到芯片内建的存储器中,然后结果在完成时被复制到系统内存。因为每个像素的最少量数据(最终像素结果)被复制到系统内存,所以这种方法节约了GPU和系统内存之间的内存带宽。

有了帧缓冲区失效机制,GPU就可以删除不再需要的帧缓冲区内容,以减少每个帧保留的内容数量,此外,如果图块数据不再有效,GPU还可以消除从芯片内建存储器到系统内存不必要的数据传输,因为GPU和系统内存之间内存带宽需求明显降低,所以电力消耗随之下降,性能则得到改善。

其中glInvalidateFramebuffer和glInvalidateSubFramebuffer命令用于使整个帧缓冲区或者帧缓冲区的像素子区域失效。

void glInvalidateFramebuffer( GLenum target, GLsizei numAttachments, const GLenum *attachments);

void glInvalidateSubFramebuffer( GLenum target, GLsizei numAttachments, const GLenum * attachments, GLint x, GLint y, GLint width, GLint height);

性能提示和技巧

在使用帧缓冲区对象时应该要认真考虑的性能提示:

  1. 避免频繁地在渲染到窗口系统提供的帧缓冲区和渲染到帧缓冲区对象之间切换。
  2. 不要逐帧创建和删除帧缓冲区和帧缓冲区对象(或者任何其他大型数据对象)。
  3. 尝试避免修改用作渲染图标的帧缓冲区对象附着的纹理,也就是说当指定纹理附着到帧缓冲区对象上以后,不要再进行修改(使用glTexImage2D、glTexSubImage2D、glCopyTexImage2D等)。
  4. 如果整个纹理图像将被渲染,则将glTexImage2D和glTexImage3D中的pixel参数设置为NULL,因为原始数据不会被使用。如果你希望图像包含任何预先定义的像素值,那么在绘制到纹理之前使用glInvalidateFramebuffer清除纹理图像。
  5. 尽可能共享帧缓冲区对象使用的用作附着的深度和模版渲染缓冲区,以保证内存占用需求最小,但是需要注意的是,因为帧缓冲区的宽度和高度必须相同。

OpenGL ES 3.0 帧缓冲区对象基础知识的更多相关文章

  1. OpenGL ES 3.0 顶点缓冲区VBO使用

    一般情况下数据都是有CPU从RAM取数据 然后传给GPU去处理,相对于GPU速度要慢一些. 使用VBO技术 可以把数据存储到GPU的内存空间中,这样GPU可以直接从GPU的内存中取得数据进行处理 速度 ...

  2. OpenGL ES 3.0之Fragment buffer objects(FBO)详解 (转)

    http://www.cnblogs.com/salam/p/4957250.html 片段操作图 这篇文章将介绍从写入帧缓冲和读取帧缓冲的方式. Buffers(缓冲) OpenGL ES支持三种缓 ...

  3. OpenGL ES 3.0之Fragment buffer objects(FBO)详解(二)

    我们可以使用帧缓冲对象来实现离屏渲染.帧缓冲对象支持下列操作 1.只使用OpenGL ES 函数创建帧缓冲区对象. 2.使用EGL context创建多个FBO. 3.创建离屏颜色.深度.模板渲染缓冲 ...

  4. [置顶] 使用Android OpenGL ES 2.0绘图之五:添加运动

    传送门 ☞ 系统架构设计 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229 传送门 ☞ GoF23种设计模式 ☞ 转载请注明 ☞ http://blog.csd ...

  5. OpenGL ES 3.0 基础知识

    首先要了解OpenGL的图形管线有哪些内容,再分别去了解其中的相关的关系: 管线分别包括了顶点缓冲区/数组对象,定点着色器,纹理,片段着色器,变换反馈,图元装配,光栅化,逐片段操作,帧缓冲区.其中顶点 ...

  6. OpenGL ES 3.0之VertexAttributes,Vertex Arrays,and Buffer Objects(九)

    顶点数据,也称为顶点属性,指每一个顶点数据.指能被用来描述每个顶点的数据,或能被所有顶点使用的常量值.例如你想绘制一个具有颜色的立方体三角形.你指定一个恒定的值用于三角形的所有三个顶点颜色.但三角形的 ...

  7. 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)

    0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...

  8. OpenGL ES 2.0 渲染管线 学习笔记

    图中展示整个OpenGL ES 2.0可编程管线 图中Vertex Shader和Fragment Shader 是可编程管线: Vertex Array/Buffer objects 顶点数据来源, ...

  9. 【Android 应用开发】OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器 片元着色器 使用详解

    最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 . 案例下载地址 : http://download.csdn.net/detail/han120201 ...

随机推荐

  1. 【codeforces】【比赛题解】#849 CF Round #431 (Div.2)

    cf的比赛越来越有难度了……至少我做起来是这样. 先看看题目吧:点我. 这次比赛是北京时间21:35开始的,算是比较良心. [A]奇数与结束 "奇数从哪里开始,又在哪里结束?梦想从何处起航, ...

  2. torch.Tensor.view (Python method, in torch.Tensor)

    返回具有相同数据但大小不同的新张量.返回的张量共享相同的数据,必须具有相同数量的元素,但可能有不同的大小. Example >>> x = torch.randn(4, 4) > ...

  3. Shell-脚本只能运行1次

    用空文件进行判断 path=`pwd` if [ -f ${path}/.runned ]; then { echo "This script can only execute once! ...

  4. Linux禁止ping的俩种方法【转】

    Linux禁止ping以及开启ping的方法   Linux默认是允许Ping响应的,系统是否允许Ping由2个因素决定的:A.内核参数,B.防火墙,需要2个因素同时允许才能允许Ping,2个因素有任 ...

  5. 02 How to Write Go Code 如何编写go语言代码

    How to Write Go Code   如何编写go语言代码 Introduction   介绍 Code organization  组织代码 Overview  概述 Workspaces  ...

  6. MongoDB安全:所有操作(Privilege Actions)

    本文展示了两张思维导图,分别是MongoDB 3.6.4.0的所有权限操作,未做深入研究,仅仅是列出来. 3.6总共9类105个操作,4.0版本比3.6多了两类操作,同时增加了3个操作,共11类108 ...

  7. nginx防止DDOS攻击

    防御DDOS是一个系统工程,攻击花样多,防御的成本高瓶颈多,防御起来即被动又无奈.DDOS的特点是分布式,针对带宽和服务攻击,也就是四层流量攻击和七层应用攻击,相应的防御瓶颈四层在带宽,七层的多在架构 ...

  8. hdu 5475 模拟计算器乘除 (2015上海网赛H题 线段树)

    给出有多少次操作 和MOD 初始值为1 操作1 y 表示乘上y操作2 y 表示除以第 y次操作乘的那个数 线段树的叶子结点i 表示 第i次操作乘的数 将1替换成y遇到操作2 就把第i个结点的值 替换成 ...

  9. HBase(六)HBase整合Hive,数据的备份与MR操作HBase

    一.数据的备份与恢复 1. 备份 停止 HBase 服务后,使用 distcp 命令运行 MapReduce 任务进行备份,将数据备份到另一个地方,可以是同一个集群,也可以是专用的备份集群. 即,把数 ...

  10. 【51nod】1709 复杂度分析

    题解 考虑朴素的暴力,相当于枚举u点的每个祖先f,然后统计一下这个点f除了某个儿子里有u的那个子树之外的节点个数,乘上f到u距离的二进制1的个数 那么我们用倍增来实现这个东西,每次枚举二进制的最高位j ...