美文网首页
OpenGL ES和EGL

OpenGL ES和EGL

作者: AI科技智库 | 来源:发表于2020-02-19 06:23 被阅读0次

1 Opengl ES

OpenGL ES(OpenGL for Embedded Systems)是 OpenGL 三维图形API的子集,针对手机、PDA和游戏主机等嵌入式设备而设计,各显卡制造商和系统制造商来实现这组 API。
既然OpenGL ES只是一组函数接口,那么如何使用呢?而android提供了两种类型的实现:软件实现和硬件实现。

  • 硬件实现,前面提到这组函数接口主要是为了和GPU这个硬件进行打交道的。所以各个硬件厂商会提供相关的实现。

  • 软件实现,android也提供了一套OpenGL ES的软件实现,就是说不用GPU了,完全用软件实现画图的相关功能,也就是libagl,代码在frameworks\native\opengl\libagl,软件实现最终编译完保存在system\lib\egl\libGLES_android.so

2 EGL

OpenGL是一个操作GPU的API,它通过驱动向GPU发送相关指令,控制图形渲染管线状态机的运行状态。但OpenGL需要本地视窗系统进行交互,这就需要一个中间控制层,最好与平台无关。
EGL 是 OpenGL ES和底层 Native 平台视窗系统之间的接口。EGL API 是独立于OpenGL ES各版本标准的独立API ,其主要作用是为OpenGL指令创建 Context 、绘制目标Surface 、配置Framebuffer属性、Swap提交绘制结果等。此外,EGL为GPU厂商和OS窗口系统之间提供了一个标准配置接口。
Android 使用 OpenGL ES (GLES) API 渲染图形。为了创建 GLES 上下文并为 GLES 渲染提供窗口系统,Android 使用 EGL 库。GLES 调用用于渲染纹理多边形,而 EGL 调用用于将渲染放到屏幕上。


捕获.PNG

3 EGL使用步骤

EGL 的使用要遵循一些固定的步骤,按照这些步骤去配置、创建、渲染、释放。


111.PNG

3.1 创建与本地窗口系统的连接

首先EGL必须建立本地窗口系统和OpenGL ES的连接。调用 eglGetDisplay 方法得到 EGLDisplay

EGLDisplay eglDisplay(EGLNativeDisplayType displayId);

EGL提供了平台无关类型EGLDisplay表示窗口。定义EGLNativeDisplayType是为了匹配原生窗口系统的显示类型,对于Windows,EGLNativeDisplayType被定义为HDC,对于Linux系统被定义为Display*类型,对于Android系统定义为ANativeWindow *类型,为了方便的将代码转移到不同的操作系统上,应该传入EGL_DEFAULT_DISPLAY,返回与默认原生窗口的连接。如果连接不可用,则返回EGL_NO_DISPLAY。

3.2 初始化EGL

创建与本地原生窗口的连接后需要初始化EGL,使用函数eglInitialize进行初始化操作。

EGLBoolean eglInitialize(EGLDisplay display, // 创建的EGL连接
                         EGLint *majorVersion, // 返回EGL主板版本号
                         EGLint *minorVersion); // 返回EGL次版本号

如果 EGL 不能初始化,它将返回EGL_FALSE,并将EGL错误码设置为EGL_BAD_DISPLAY表示制定了不合法的EGLDisplay,或者EGL_NOT_INITIALIZED表示EGL不能初始化。使用函数eglGetError用来获取最近一次调用EGL函数出错的错误代码。

3.3 确定渲染表面的配置信息

调用 eglChooseConfig 方法得到 EGLConfig

  • 一种方式是使用eglGetConfigs函数获取底层窗口系统支持的所有EGL表面配置,然后再使用eglGetConfigAttrib依次查询每个EGLConfig相关的信息,EGLConfig包含了渲染表面的所有信息,包括可用颜色、缓冲区等其他特性。
EGLBoolean eglGetConfigs(EGLDisplay display, EGLConfig *configs, 
                         EGLint maxReturnConfigs,EGLint *numConfigs);
EGLBoolean eglGetConfigAttrib(EGLDisplay display, EGLConfig config, 
                              EGLint attribute, EGLint *value);
  • 另一种方式是指定我们需要的渲染表面配置,让EGL自己选择一个符合条件的EGLConfig配置。eglChooseChofig调用成功返回EGL_TRUE,失败时返回EGL_FALSE,如果attribList包含了未定义的EGL属性,或者属性值不合法,EGL代码被设置为EGL_BAD_ATTRIBUTR
EGLBoolean eglChooseChofig(EGLDispay display, // 创建的和本地窗口系统的连接
                           const EGLint *attribList, // 指定渲染表面的参数列表,可以为null
                           EGLConfig *config,   // 调用成功,返会符合条件的EGLConfig列表
                           EGLint maxReturnConfigs, //最多返回的符合条件的EGLConfig个数
                           ELGint *numConfigs );  // 实际返回的符合条件的EGLConfig个数

3.4 创建渲染表面

有了符合条件的EGLConfig后,就可以通过eglCreateWindowSurface函数创建渲染表面。使用这个函数的前提是要使用原生窗口系统提供的API创建一个窗口。eglCreateWindowSurface中attribList一般可以使用null即可。函数调用失败会返回EGL_NO_SURFACE,并设置对应的错误码。

EGLSurface eglCreateWindowSurface(EGLDisplay display,
                                  EGLConfig config, // 前面选好的可用EGLConfig
                                  EGLNatvieWindowType window, // 指定原生窗口
                                  const EGLint *attribList); // 指定窗口属性列表,可以为null

除了使用eglCreateWindowSurface函数创建在窗口上的渲染表面,此外还可以使用eglCreatePbufferSurface创建屏幕外渲染表面(Pixel Buffer 像素缓冲区)。使用Pbuffer一般用于生成纹理贴图,不过该功能已经被FrameBuffer替代了,使用帧缓冲对象的好处是所有的操作都由OpenGL ES来控制。使用Pbuffer的方法和前面创建窗口渲染表面一样,需要改动的地方是在选取EGLConfig时,增加EGL_SURFACE_TYPE参数使其值包含EGL_PBUFFER_BIT。而该参数默认值为EGL_WINDOW_BIT。

EGLSurface eglCreatePbufferSurface( EGLDisplay display,
                                   EGLConfig config,
                                   EGLint const * attrib_list); // 指定像素缓冲区属性列表             

3.5.创建渲染上下文

使用eglCreateContext为当前的渲染API创建EGL渲染上下文,返回一个上下文,当前的渲染API是由函数eglBindAPI设置的。OpenGL ES是一个状态机,用一系列变量描述OpenGL ES当前的状态如何运行,我们通常使用如下途径去更改OpenGL状态:设置选项,操作缓冲。最后,我们使用当前OpenGL上下文来渲染。比如我想告诉OpenGL ES接下来要绘制三角形,可以通过一些上下文变量来改变OpenGL ES的状态,一旦改变了OpenGL ES的状态为绘制三角形,下一个命令就会画出三角形。通过这些状态设置函数就会改变上下文,接下来的操作总会根据当前上下文的状态来执行,除非再次重新改变状态。

EGLContext eglCreateContext(EGLDisplay display, 
                            EGLConfig config, // 前面选好的可用EGLConfig
                            EGLContext shareContext, // 允许多个EGLContext共享特定类型的数据,传递EGL_NO_CONTEXT表示不与其他上下文共享资源
                            const EGLint* attribList); // 指定操作的属性列表,只能接受一个属性EGL_CONTEXT_CLIENT_VERSION用来表示使用的OpenGL ES版本                         

6 绑定上下文

指定某个EGLContext为当前上下文。使用eglMakeCurrent函数进行当前上下文的绑定将 EGLSurface、EGLContext、EGLDisplay 三者绑定。一个程序可能创建多个EGLContext,所以需要关联特定的EGLContext和渲染表面,一般情况下两个EGLSurface参数设置成一样的。

EGLBoolean eglMakeCurrent(EGLDisplay display,
                          EGLSurface draw, // EGL绘图表面
                          EGLSurface read, // EGL读取表面
                          EGLContext context); // 指定连接到该表面的渲染上下文       

3.7 绘制

使用OpenGL相关的API进行绘制操作

3.8 交换缓冲

EGL的Surface的内部缓冲和EGL创建的和平台无关的窗口diaplay。EGL实际上维护了两个buffer,前台buffer显示的时候,绘制操作会在后台buffer上进行。

EGLBoolean eglSwapBuffers(EGLDisplay display, // 指定的EGL和本地窗口的连接
                          EGLSurface surface);  // 指定要交换缓冲的EGL绘制表面                     

如果surface是一个window surface,那么该函数执行的结果将是将数据给本地窗口,即显示在屏幕上。如果surface是一个屏幕外渲染surface(pixel buffer),执行该函数没有效果。

3.9 释放 EGL 环境

绘制结束不再需要使用 EGL 时,取消 eglMakeCurrent 的绑定,销毁 EGLDisplay、EGLSurface、EGLContext。

4 EGLSurface

EGLSurface 可以是由 EGL 分配的离屏缓冲区(称为“pbuffer”),也可以是由操作系统分配的窗口。调用 eglCreateWindowSurface() 函数可创建 EGL 窗口 Surface。 eglCreateWindowSurface() 将“窗口对象”作为参数,在 Android 上该对象是 Surface。当调用 eglCreateWindowSurface() 时,EGL 将创建一个新的 EGLSurface 对象,渲染到该 EGLSurface 会导致一个缓冲区离开队列、进行渲染,然后排队等待使用方使用。

5 EGLNativeWindowType和ANativeWindow

公开的 Surface 类以Java 编程语言实现。C/C++ 中的同等项是 ANativeWindow 类,可以使用 ANativeWindow_fromSurface() 调用从Surface获取 ANativeWindow。要从原生代码创建EGL窗口 Surface,可将 EGLNativeWindowType 的实例传递到 eglCreateWindowSurface()。EGLNativeWindowType是ANativeWindow的同义词,可以互换使用。

参考:

https://blog.csdn.net/zhuyong006/article/details/88970628
https://www.cnblogs.com/yongdaimi/p/11244950.html

相关文章

网友评论

      本文标题:OpenGL ES和EGL

      本文链接:https://www.haomeiwen.com/subject/nxeofhtx.html