前置知识:
OPENGL 和OPENGL ELS的关系
OPENGL 是统一不同厂商GPU绘制的接口,通过GPU的计算得到一张图片(内存中的一块Buffer保存着信息)
openGl是一个操作GPU的接口,但是具体的图片信息需要一块窗口来呈现出来,这个窗口就是OPENGL EGL:
OPENGL EGL是OpenGl 和Native底层之间的视图接口。EGL可以获取手机配置(会根据不同Display屏幕的情况创建EGLConfig)创建出一个surface(默认BufferQuene的大小是屏幕分辨率乘以像素个数)和用于存放OPEGL状态集(OPENGL信息是传入的图元,顶点等信息,OPENGL状态是如何进行测试混合片段阶段的处理)的context。OPENGL生成图片数据(具体流程见图形学的图元处理部分,其完全由GPU处理)后保存到EGL创建的surface的buffer中,通过EGL的接口显示到窗口上
一句话总结:EGL获取Buffer用于和屏幕打交道,buffer的具体图像数据由OpenGl往里面填充
EGLSurface和EGLContext关系
EGLSurface:EGL 是用于在Surface绘制buffer 提供给 OpenGL ES 进行绘制的
EGLContext: EGL 还会根据格式生成一块 context,context 也是一块 buffer用于保存OpenGl的状态集
上下文保存着状态集,什么是状态集?
这些状态变量描述当前OpenGl应该如何运行,比如是绘制线段还是三角形,可以 通过改变上下文状态来改变OpenGl的绘制行为。
状态设置函数就是用来改变上下文的,而OpenGl是根据上下文进行渲染的。
surface 需要与 context 进行搭配使用, context 中是可以保存 OpenGL ES 状态集信息的,所以 context 就可以使用自己内部保存的信息往 surface 上进行绘制
Thread和EGLSurface,EGLContext关系
由于存在多个EGLSurface和多个Context,但是一个进程同一时间只能启动有相同格式的一块 surface 和一块对应于 OpenGL ES 的 context,一块 context 同时也只能被一个进程启动。,有时候也会设计到多线程操作,每个 thread 可以拥有自己的 surface 和 context,但是也要满足刚才的限制 : 一个 thread 同一时间只能启动有相同格式的 一块 surface 和一块对应于 OpenGL ES 的 context,一块 context 同时也只能被一 个 thread 启动,所以我们需要设置绑定这个Thread对应渲染的surface和context
具体api
通过eglMakeCurrent可以切换当前线程绑定的surface和context,接着通过OPENGL的接口设置context的状态,使用context的状态对surface进行绘制, 由于Surface是双缓冲,所以准备好数据之后需要调用egl的swapBuffer置换缓存,让Opengl去渲染,自己在继续生成下一个buffer的数据
Display和EGL关系
EGL有很多版本,不同设备也有多个Display通过displayID去区分(典型的场景是车机上的多联屏);不同的Display支持的版本不同其屏幕配置也可能不同这些通过eglgetConfig API 获取该块屏幕的配置信息,所以EGL初始化的过程和使用的过程需要指定对应的Display,初始化过程根据支持的opengl的版本初始化不同版本的opengl。使用过程比如创建EGLSurface和EGLContext需要指定display
Surface和EGLSurface的关系
Surface没有直接和OPENGL操作的接口其是一个承载的窗口,需要通过EGLSurface和Opengl对接绘制添加EGL的功能支持
大致初始化流程
经过上面的描述,来总结下大致流程:
- 获取EGLDisplay
- EGLDisplay初始化,通过Display获取EGLConfig
- 根据Config信息初始化所支持的OPENGL版本
- EGL环境初始化结束,接下来通过EGL获取EGLSurface和对应的EGLContext
- 设置当前线程绑定的EGLSurface和EGLContext(与线程绑定)
绘制过程
- perfromTravle中申请内存,其实就是Surface的BufferQuene(dequeBuffer设计BufferQuene的生命周期)
- 递归遍历RenderNode获取所有的DrawOp树,也叫DisplayList
- 同步Cpu的DisplayList到GPU(对应同步上传,等待CPU将数据同步至GPU;不像软件绘制那样直接使用的匿名共享内存,这部分存在一个时间差,)
- 转换DrawOp树为对应的glXXX函数,将命令同步至GPU,让GPU绘制(对应于向OpenGl发起渲染流程)
- swapBuffer提交缓冲区并申请下一块Buffer(对应于交换缓冲区依赖于GPU提交的数据如果SF对应合成的数据还没有渲染好则会阻塞等待GPU渲染完成),异步请求SF进行合成。只有EGL才可以对接屏幕显示,OPENGL只是操作GOU进行绘制图像)
参考文章
OPENGL ES 2.0 知识串讲(2)――EGL详解
OpenGL ES: (3) EGL、EGL绘图的基本步骤、EGLSurface、ANativeWindow
创建2个egl
我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表