OpenGL ES: (3) EGL、EGL绘图的基本步骤、EGLSurface、ANativeWindow

1. EGL概述

EGL 是 OpenGL ES 渲染 API 和本地窗口系统(native platform window system)之间的一个中间接口层,它主要由系统制造商实现。

EGL提供如下机制:

  • 与设备的原生窗口系统通信
  • 查询绘图表面的可用类型和配置
  • 创建绘图表面
  • 在OpenGL ES 和其他图形渲染API之间同步渲染
  • 管理纹理贴图等渲染资源
  • 为了让OpenGL ES能够绘制在当前设备上,我们需要EGL作为OpenGL ES与设备的桥梁。

2. 使用EGL绘图的基本步骤

Display(EGLDisplay) 是对实际显示设备的抽象。

Surface(EGLSurface)是对用来存储图像的内存区域。

FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer。Context (EGLContext) 存储 OpenGL ES绘图的一些状态信息。

使用EGL的绘图的一般步骤:

复制代码
1、获取 EGL Display 对象:eglGetDisplay()
2、初始化与 EGLDisplay 之间的连接:eglInitialize()
3、获取 EGLConfig 对象:eglChooseConfig()
4、创建 EGLContext 实例:eglCreateContext()
5、创建 EGLSurface 实例:eglCreateWindowSurface()
6、连接 EGLContext 和 EGLSurface:eglMakeCurrent()
7、使用 OpenGL ES API 绘制图形:gl_*()
8、切换 front buffer 和 back buffer 送显:eglSwapBuffer()
9、断开并释放与 EGLSurface 关联的 EGLContext 对象:eglRelease()
10、删除 EGLSurface 对象
11、删除 EGLContext 对象
12、终止与 EGLDisplay 之间的连接
复制代码

标准 EGL 数据类型如下所示:

EGLBoolean —— EGL_TRUE =1, EGL_FALSE=0
EGLint —— int 数据类型
EGLDisplay —— 系统显示 ID 或句柄,可以理解为一个前端的显示窗口
EGLConfig —— Surface的EGL配置,可以理解为绘制目标framebuffer的配置属性
EGLSurface —— 系统窗口或 frame buffer 句柄 ,可以理解为一个后端的渲染目标窗口。
EGLContext —— OpenGL ES 图形上下文,它代表了OpenGL状态机;如果没有它,OpenGL指令就没有执行的环境。

下面几个类型比较复杂,通过例子可以更深入的理解。这里要说明的是这几个类型在不同平台其实现是不同的,EGL只提供抽象标准。

NativeDisplayType—— Native 系统显示类型,标识你所开发设备的物理屏幕

NativeWindowType —— Native 系统窗口缓存类型,标识系统窗口

NativePixmapType —— Native 系统 frame buffer,可以作为 Framebuffer 的系统图像(内存)数据类型,该类型只用于离屏渲染。

3. EGLSurface

EGLSurface 可以是由 EGL 分配的离屏缓冲区(称为“pbuffer”),或由操作系统分配的窗口。EGL 窗口 Surface 通过 eglCreateWindowSurface() 调用被创建。该调用将“窗口对象”作为参数,在 Android 上,该对象可以是 SurfaceView、SurfaceTexture、SurfaceHolder 或 Surface,所有这些对象下面都有一个 BufferQueue。当您进行此调用时,EGL 将创建一个新的 EGLSurface 对象,并将其连接到窗口对象的 BufferQueue 的生产方接口。此后,渲染到该 EGLSurface 会导致一个缓冲区离开队列、进行渲染,然后排队等待消耗方使用。(术语“窗口”表示预期用途,但请注意,输出内容不一定会显示在显示屏上。)

EGL 不提供锁定/解锁调用,而是由您发出绘制命令,然后调用 eglSwapBuffers() 来提交当前帧。方法名称来自传统的前后缓冲区交换,但实际实现可能会有很大的不同。

一个 Surface 一次只能与一个 EGLSurface 关联(您只能将一个生产方连接到一个 BufferQueue),但是如果您销毁该 EGLSurface,它将与该 BufferQueue 断开连接,并允许其他内容连接到该 BufferQueue。

通过更改“当前”EGLSurface,指定线程可在多个 EGLSurface 之间进行切换。一个 EGLSurface 一次只能在一个线程上处于当前状态。

关于 EGLSurface 最常见的一个错误理解就是假设它只是 Surface 的另一方面(如 SurfaceHolder)。它是一个相关但独立的概念。您可以在没有 Surface 作为支持的 EGLSurface 上绘制,也可以在没有 EGL 的情况下使用 Surface。EGLSurface 仅为 GLES 提供一个绘制的地方。

4. ANativeWindow

公开的 Surface 类以 Java 编程语言实现。C/C++ 中的同等项是 ANativeWindow 类,由 Android NDK 半公开。您可以使用 ANativeWindow_fromSurface() 调用从 Surface 获取 ANativeWindow。就像它的 Java 语言同等项一样,您可以对 ANativeWindow 进行锁定、在软件中进行渲染,以及解锁并发布。

要从原生代码创建 EGL 窗口 Surface,可将 EGLNativeWindowType 的实例传递到 eglCreateWindowSurface()。EGLNativeWindowType 是 ANativeWindow 的同义词,您可以自由地在它们之间转换。

基本的“原生窗口”类型只是封装 BufferQueue 的生产方,这一点并不足为奇。

5. EGLSurface与ANativeWindow之间的关系

OpenGL ES 定义了一个渲染图形的 API,但没有定义窗口系统。为了让 GLES 能够适合各种平台,GLES 将与知道如何通过操作系统创建和访问窗口的库结合使用。用于 Android 的库称为 EGL。如果要绘制纹理多边形,应使用 GLES 调用;如果要在屏幕上进行渲染,应使用 EGL 调用。

在使用 GLES 进行任何操作之前,需要创建一个 GL 上下文。在 EGL 中,这意味着要创建一个 EGLContext 和一个 EGLSurface。GLES 操作适用于当前上下文,该上下文通过线程局部存储访问,而不是作为参数进行传递。这意味着您必须注意渲染代码在哪个线程上执行,以及该线程上的当前上下文。

 

参考链接:

1. Android Display System(2)

2. OpenGL ES 2.0 知识串讲

 



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   夜行过客  阅读(16681)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示