首页 > 其他分享 >OpenGL 之EGL API 介绍

OpenGL 之EGL API 介绍

时间:2024-08-14 20:28:01浏览次数:10  
标签:EGLint OpenGL EGLDisplay API EGL14 EGL 上下文 config

EGL介绍

EGL 是 OpenGL ES 和底层 Native 平台视窗系统之间的接口。OpenGL ES 本质上是一个图形渲染管线的状态机,而 EGL 则是用于监控这些状态以及维护 Frame buffer 和其他渲染 Surface 的外部层。EGL提供如下机制:

  • 与设备的原生窗口系统通信
  • 查询绘图表面的可用类型和配置
  • 创建绘图表面
  • 在OpenGL ES 和其他图形渲染API之间同步渲染
  • 管理纹理贴图等渲染资源

OpenGL ES的javax.microedition.khronos.openges包定义了平台无关的GL绘制指令,EGL(javax.microedition.khronos.egl)则定义了控制dispays,contexts以及surfaces的统一的平台接口.

![[8.Attachments/image/95ecf7e0c1fdc7edc11479a3a5cf8544_MD5.gif]]
EGL 是 OpenGL ES 渲染 API 和本地窗口系统(native platform window system)之间的一个中间接口层,它主要由系统制造商实现。

为了让OpenGL ES能够绘制在当前设备上,我们需要EGL作为OpenGL ES与设备的桥梁。

![[8.Attachments/image/134d0f8a32e58360190215c7ae7b789e_MD5.jpg]]

  • Display(EGLDisplay)是对实际显示设备的抽象
  • Surface(EGLSurface)是对用来存储图像的内存区域FrameBuffer的抽象,包括Color Buffer, Stencil Buffer, Depth Buffer.
  • Context(EGLContext)存储OpenGLES绘图的一些状态信息

使用EGL绘制的一般步骤:

  1. 获取EGLDisplay对象
  2. 初始化与EGLDisplay之间的连接
  3. 获取EGLConfig实例
  4. 创建EGLContext实例
  5. 创建EGLSurface实例
  6. 连接EGLContext和EGLSurface
  7. 使用GL指令绘制图形
  8. 断开并释放与EGLSurface关联的EGLContext对象
  9. 删除EGLSurface对象
  10. 删除EGLContext对象
  11. 终止与EGLDisplay之间的连接

EGL类型

EGLBoolean
EGL中的布尔类型。

typedef unsigned int EGLBoolean;
EGLDisplay
不透明类型,封装了与底层系统的交互,用于充当与原生窗口之间的接口。

typedef void * EGLDisplay;
EGLint
EGL整数类型。

typedef int32_t EGLint;
EGLNativeDisplayType
用于匹配原生窗口系统的显示类型。

typedef void * EGLNativeDisplayType;

EGL常量

布尔值
  • EGL_FALSE:条件为假
  • EGL_TRUE:条件为真
创建窗口的属性
  • EGL_RENDER_BUFFER:指定渲染所用的缓冲区
错误代码
  • EGL_SUCCESS:没有错误
  • EGL_NOT_INITIALIZED:没有初始化
  • EGL_BAD_ACCESS:数据访问失败
  • EGL_BAD_ALLOC:内存分配失败
  • EGL_BAD_ATTRIBUTE:错误的属性
  • EGL_BAD_CONFIG:错误的配置
  • EGL_BAD_CONTEXT:错误的上下文
  • EGL_BAD_CURRENT_SURFACE:当前Surface对象错误
  • EGL_BAD_DISPLAY:错误的设备对象
  • EGL_BAD_MATCH:无法匹配
  • EGL_BAD_NATIVE_PIXMAP:错误的像素图
  • EGL_BAD_NATIVE_WINDOW:错误的本地窗口对象
  • EGL_BAD_PARAMETER:错误的参数
  • EGL_BAD_SURFACE:错误的Surface对象
  • EGL_CONTEXT_LOST:上下文丢失
配置属性
  • EGL_ALPHA_SIZE:颜色缓冲区中的透明度分量的位数
  • EGL_ALPHA_MASK_SIZE:透明度掩码位数
  • EGL_BUFFER_SIZE:颜色缓冲区中颜色分量的位数
  • EGL_BLUE_SIZE:颜色缓冲区中的蓝色分量的位数
  • EGL_BIND_TO_TEXTURE_RGB:是否可以绑定RGB纹理
  • EGL_BIND_TO_TEXTURE_RGBA:是否可以绑定EGBA纹理
  • EGL_CONFIG_CAVEAT:注意事项
  • EGL_COLOR_BUFFER_TYPE:颜色缓冲区类型
  • EGL_CONFORMANT:创建的上下文是否兼容
  • EGL_CONFIG_ID:配置信息ID
  • EGL_DEPTH_SIZE:深度缓冲区位数
  • EGL_GREEN_SIZE:颜色缓冲区中的绿色分量的位数
  • EGL_LEVEL:帧缓冲区级别
  • EGL_LUMINANCE_SIZE:颜色缓冲区亮度位数
  • EGL_MAX_PBUFFER_HEIGHT:Pbuffer的最大高度
  • EGL_MAX_PBUFFER_PIXELS:Pbuffer的最大尺寸
  • EGL_MAX_PBUFFER_WIDTH:Pbuffer的最大宽度
  • EGL_MATCH_NATIVE_PIXMAP
  • EGL_MIN_SWAP_INTERVAL:最小缓冲区交换间隔
  • EGL_MAX_SWAP_INTERVAL:最大缓冲区交换间隔
  • EGL_NATIVE_RENDERABLE:是否可用原生渲染库渲染
  • EGL_NONE
  • EGL_NATIVE_VISUAL_ID:原生窗口系统的可视ID
  • EGL_NATIVE_VISUAL_TYPE:原生窗口系统的可视类型
  • EGL_RED_SIZE:颜色缓冲区中的红色分量的位数
  • EGL_RENDERABLE_TYPE:可渲染接口类型
  • EGL_STENCIL_SIZE:模板缓冲区位数
  • EGL_SAMPLES:每个像素的样本数量
  • EGL_SAMPLE_BUFFERS:可用多重采样缓冲区数量
  • EGL_SURFACE_TYPE:EGL表面类型
  • EGL_TRANSPARENT_TYPE:透明度类型
  • EGL_TRANSPARENT_BLUE_VALUE:透明的蓝色值
  • EGL_TRANSPARENT_GREEN_VALUE:透明的绿色值
  • EGL_TRANSPARENT_RED_VALUE:透明的红色值
显示设备对象
  • EGL_NO_DISPLAY:当前无可用设备
显示设备类型
  • EGL_DEFAULT_DISPLAY:默认为当前使用设备

EGL函数

eglChooseConfig

在初始化EGL时,我们需要列出并让EGL选择最合适的配置。

EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
  • dpy:已连接的设备
  • attrib_list:传入的配置信息数组
  • configs:保存返回的配置信息的数组
  • config_size:传入的配置数组的长度
  • num_config:保存返回的配置信息的数组的长度
EGLConfig config;
EGLint numConfigs = 0;
EGLint attribList[] =
        {
                EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
                EGL_RED_SIZE, 8,
                EGL_GREEN_SIZE, 8,
                EGL_BLUE_SIZE, 8,
                EGL_ALPHA_SIZE, 8,
                EGL_DEPTH_SIZE, 16,
                EGL_NONE
        };
if (!eglChooseConfig(context->eglDisplay, attribList, &config, 1, &numConfigs)) {
    return GL_FALSE;
}
eglCreateContext

渲染上下文是OpenGL ES的内部数据结构,包含操作所需的所有状态信息。例如程序中使用的顶点着色器或者片元着色器的引用。OpenGL ES必须有一个可用的上下文才能绘图。使用下面的函数可以创建一个上下文:

EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext shareContext, const EGLint *attribList);
  • display:指定显示连接
  • config:指定配置对象
  • shareContext:允许多个EGL上下文共享特定的数据,EGL_NO_CONTEXT参数表示没有共享
  • attribList:指定创建上下文使用的属性列表
  • return:创建的上下文对象
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
context->eglContext = eglCreateContext(context->eglDisplay, config, EGL_NO_CONTEXT, contextAttribs);
if (context->eglContext == EGL_NO_CONTEXT) {
    return GL_FALSE;
}
eglCreateWindowSurface

一旦我们有了符合渲染需求的EGLConfig,就为窗口创建做好了准备。调用如下函数可以创建一个窗口。

EGLSurface eglCreateWindowSurface(EGLDisplay display, EGLConfig config, EGLNativeWindowType window,const EGLint *attribList);
  • display:已连接的设备对象
  • config:指定的配置对象
  • window:指定原生窗口对象
  • attriList:指定窗口的属性列表
  • return:EGL渲染区域对象
    这个函数以我们到原生显示管理器的连接和前一步获得的EGLConfig为参数。此外,它需要原生窗口系统事先创建一个窗口。因为EGL是许多不同窗口系统和OpenGL ES之间的软件接口层。最后这个函数需要一个属性列表;但是,这个列表中的属性与参数属性不完全相同,并且额外使用到了创建窗口的属性。该函数在多种情况下都有可能失败。
context->eglSurface = eglCreateWindowSurface(context->eglDisplay, config, context->nativeWindow,
                                                NULL);
if (context->eglSurface == EGL_NO_SURFACE) {
    EGLint error;
    while((error = eglGetError()) != EGL_SUCCESS){
        switch(error) {
            case EGL_BAD_MATCH:{
                //提供的原生窗口不匹配或者不支持渲染
            }
            case EGL_BAD_CONFIG:{
                //系统不支持该配置
            }
            case EGL_BAD_NATIVE_WINDOW:{
                //提供的原生窗口无效
            }
            case EGL_BAD_ALLOC:{
                //无法为新的EGL分配资源或者该窗口已经被关联
            }
        }
    }
}
eglGetConfigAttrib

如果我们获获取了一个EGL配置对象,我们可以通过下列函数查询该对象中指定属性的值。

EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
  • dpy:已连接的设备对象
  • config:待查询的配置对象
  • attribute:需要查询的参数属性
  • value:返回的查询结果
  • return:查询结果,如果attribute不是有效属性,则产生一个EGL_BAD_ATTRIBUTE错误。
eglGetConfigs

在初始化EGL之后,我们需要给EGL选择一组配置。

EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
  • dpy:已连接设备对象
  • configs:保存配置信息的列表
  • size:configs的长度
  • num_config:EGL返回的配置信息数量
  • return:查询结果状态
    通常情况下,我们有两种方式使用该函数。首先,我们指定configs参数为NULL,此时EGL会查询所有可用的EGLConfigs数量并赋值给num_config,但此时不会有任何其他信息返回。

另外,我们也可以创建一个未初始化的EGLConfig,并作为函数的参数传入。此时,EGL将会查询不超过config_size数量的配置信息存入到configs,并通过num_config返回保存数据的数量。

eglGetDisplay

获得并与可用设备进行连接。

EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id);
  • display_id:当前需要连接的设备类型
  • return:已经连接上的设备对象
EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglGetError

EGL中大部分函数在成功时都会返回EGL_TRUE,否则返回EGL_FALSE。但是,我们仅从这个返回值上并不能看出错误原因是什么。如果想要明确的知道EGL的错误代码,应该调用下列函数。

EGLint eglGetError(void);

return:见 [EGL常量-错误代码]

eglInitialize

一般在成功打开设备连接之后需要初始化EGL。初始化过程将会对EGL内部的数据结构进行设置,然后返回EGL的主次版本号。

EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
  • dpy:指定EGL设备对象。
  • major:设备主版本号。
  • minor:设备次版本号。
GLint majorVersion;
GLint minorVersion;
if (!eglInitialize(eglDisplay, &majorVersion, &minorVersion)) {
    return EGL_FALSE;
}
eglMakeCurrent

因为一个应用程序可能创建多个EGLContext用作不同的用途,所以我们需要指定关联特定的EGLContext和渲染表面——这一过程被称为“指定当前上下文”。

EGLBoolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
  • display:指定EGL显示设备
  • draw:指定EGL绘图表面
  • read:指定EGL读取表面
  • context:指定连接到该表面的渲染上下文
  • return:函数时候执行成功

EGL的基本使用步骤

1.首先我们需要知道绘制内容的目标在哪里,EGLDisplayer是一个封装系统屏幕的数据类型,通常通过eglGetDisplay方法来返回EGLDisplay作为OpenGl ES的渲染目标,eglGetDisplay()

 if ( (mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY)) == EGL14.EGL_NO_DISPLAY) {
                throw new RuntimeException("unable to get EGL14 display");
            }

2.初始化显示设备,第一参数代表Major版本,第二个代表Minor版本。如果不关心版本号,传0或者null就可以了。初始化与 EGLDisplay 之间的连接:eglInitialize()

if (!EGL14.eglInitialize(mEGLDisplay, 0, 0)) {
    throw new RuntimeException("unable to initialize EGL14");
}

3.下面我们进行配置选项,使用eglChooseConfig()方法,Android平台的配置代码如下:

int[] attribList = {
                    EGL14.EGL_RED_SIZE, 8,
                    EGL14.EGL_GREEN_SIZE, 8,
                    EGL14.EGL_BLUE_SIZE, 8,
                    EGL14.EGL_ALPHA_SIZE, 8,
                    EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
                    EGL_RECORDABLE_ANDROID, 1,
                    EGL14.EGL_NONE
            };
            EGLConfig[] configs = new EGLConfig[1];
            int[] numConfigs = new int[1];
            EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length,
                    numConfigs, 0);

3.接下来我们需要创建OpenGl的上下文环境 EGLContext 实例,这里值得留意的是,OpenGl的任何一条指令都是必须在自己的OpenGl上下文环境中运行,我们可以通过eglCreateContext()方法来构建上下文环境:

int[] attrib_list = {
                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                EGL14.EGL_NONE
        };
        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
                attrib_list, 0);

eglCreateContext中的第三个参数可以传入一个EGLContext类型的变量,改变量的意义是可以与正在创建的上下文环境共享OpenGl资源,包括纹理ID,FrameBuffer以及其他Buffer资源。如果没有的话可以填写Null.

4.通过上面四步,获取OpenGl 上下文之后,说明EGL和OpenGl ES端的环境已经搭建完毕,也就是说OpengGl的输出我们可以获取到了。下面的步骤我们讲如何将EGl和设备屏幕连接起来。如果连接呢?当然,这时候我们就要使用EGLSurface了,我们通过EGL库提供eglCreateWindowSurface可以创建一个实际可以显示的surface.当然,如果需要离线的surface,我们可以通过eglCreatePbufferSurface创建。eglCreateWindowSurface()

private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;
int[] surfaceAttribs = {
            EGL14.EGL_NONE
    };
    mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], mSurface,
            surfaceAttribs, 0);

5.通过上面的步骤,EGL的准备工作做好了,一方面我们为OpenGl ES渲染提供了目标及上下文环境,可以接收到OpenGl ES渲染出来的纹理,另一方面我们连接好了设备显示屏(这里指SurfaceView或者TextureView),接下来我们讲解如何在创建好的EGL环境下工作的。首先我们有一点必须要明确,OpenGl ES 的渲染必须新开一个线程,并为该线程绑定显示设备及上下文环境(Context)。因为前面有说过OpenGl指令必须要在其上下文环境中才能执行。所以我们首先要通过 eglMakeCurrent()方法来绑定该线程的显示设备及上下文。

EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);

6.当我们绑定完成之后,我们就可以进行RenderLoop循环了。这里简单说一下,EGL的工作模式是双缓冲模式,其内部有两个FrameBuffer(帧缓冲区,可以理解为一个图像存储区域),当EGL将一个FrameBuffer显示到屏幕上的时候,另一个FrameBuffer就在后台等待OpenGl ES进行渲染输出。知道调用了eglSwapBuffers这条指令的时候,才会把前台的FrameBuffers和后台的FrameBuffer进行交换,这样界面呈现的就是OpenGl ES刚刚渲染的结构了。

mInputSurface.swapBuffers();

7.当然,在所有的操作都执行完之后,我们要销毁资源。特别注意,销毁资源必须在当前线程中进行,不然会报错滴。首先我们销毁显示设备(EGLSurface),然后销毁上下文(EGLContext),停止并释放线程,最后终止与EGLDisplay之间的链接,

 EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
                EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
                EGL14.eglReleaseThread();
                EGL14.eglTerminate(mEGLDisplay);

标签:EGLint,OpenGL,EGLDisplay,API,EGL14,EGL,上下文,config
From: https://blog.csdn.net/sjw890821sjw/article/details/141141434

相关文章

  • Robyn与FastAPI全面对比:选择最适合你的Python Web框架
    引言1.1背景介绍在当今的软件开发领域,选择合适的Web框架对于项目的成功至关重要。Python作为一种广泛使用的编程语言,其生态系统中涌现出了众多优秀的Web框架,如FastAPI和Robyn。FastAPI自发布以来,因其高性能、易用性和自动生成API文档的特性,迅速成为开发者的首选。而Robyn......
  • 如何使用Zabbix API批量修正主机名称
    先说为什么要修正?这其实源自于Ansible安装zabbixagent的一个小Bug。有小伙伴发现,利用ansible批量安装zabbixagent后,zabbix系统上显示的主机名出错了,主机显示的名称都变成了操作系统的IP(如下图),这在一定程度增加了维护难度。如果一台一台去修改和校正主机名将会非常耗费时间,这......
  • Taro——Error: Can't resolve '@/api/xxx'
    前言在使用@去import的时候,报错提示不能够载入,看了下tsconfig.json已经配置了paths,所以考虑是不是taro本身上还有些配置没有完善,查询taro文档后解决;taro版本:3.6.34alias:https://docs.taro.zone/docs/config-detail#alias内容config在配置文件config/index.ts中的config中......
  • Minio .NET 新版API使用
     Minio新版API有很多改动网上搜索不到做个记录。 创建Client创建client的方式和以前差别不大varminioClient=newMinioClient().WithEndpoint(AppSettings._minio?.EndPoint,(int)(AppSettings._minio?.Port)).WithCredentials(AppSettings._minio?.AccessKey......
  • 英智大模型推理API:免费让Llama 3.1成为您创新项目的强力后盾
     “免费版(Llama3.1扩展包)”是英智大模型推理API服务平台面向开发者推出的Llama3.1免费套餐,供广大开发者无门槛、不限制Tokens、永久使用,每位用户限购1次。包含服务:“英智Llama3.1服务”:QPS(每秒查询数)限制为1次,统计Tokens。立即免费使用Llama3.18B,请访问:https:......
  • Magic-Api数据库插入操作汇总
    1.测试表准备--id非自增CREATETABLE`test_idms`(`id`varchar(32)CHARACTERSETutf8mb4COLLATEutf8mb4_general_ciNOTNULL,`name`varchar(255)COLLATEutf8mb4_general_ciDEFAULTNULLPRIMARYKEY(`id`))ENGINE=InnoDB;--id自增CREATETABLE......
  • ag-grid api方法
    ag-Grid 的 gridApi 提供了一系列功能,允许你对网格进行各种操作,如数据操作、过滤、排序、分页等。以下是一些常用的 gridApi 方法及其功能:数据操作setRowData(rowData):设置网格的数据。gridApi.setRowData(myRowData);updateRowData(transaction):更新网格的数......
  • 解决《龙珠超宇宙2》中缺失 api-ms-win-crt-runtime-l1-1-0.dll 的问题 快速恢复游戏
    在尝试启动《龙珠超宇宙2》(DragonBallXenoverse2)时,可能会遇到一个常见的问题:“丢失api-ms-win-crt-runtime-l1-1-0.dll”。这个问题通常是由游戏所需的MicrosoftVisualC++运行库缺失或损坏引起的。本文将详细介绍该问题的原因以及如何解决它。问题原因api-ms-win-cr......
  • Java并发类的主要API方法-Semaphore
    一、Semaphoreemaphore是Java并发包(java.util.concurrent)中的一个同步工具类,类Semaphore所提供的功能完全就是synchronized关键字的升级版,但它提供的功能更加的强大与方便,主要的作用就是控制线程并发的数量,而这一点,单纯地使用synchronized是做不到的。emaphore它用......
  • OpenGL ES->GLSurfaceView着色器程序中传递顶点数组和颜色数组绘制渐变三角形
    自定义View代码classMyGLSurfaceView(context:Context,attrs:AttributeSet):GLSurfaceView(context,attrs){init{//设置OpenGLES3.0版本setEGLContextClientVersion(3)//设置当前类为渲染器,注册回调接口的实现类......