EGL使用记录

0.前言

EGL是Khronos渲染API(OpenGL、Vulkan、OpenVG等)和原生窗口系统之间的接口。使用EGL的流程较为固定,在搭建框架时又必不可少,简单记录一下。

1. EGL

1.1 EGLDisplay

EGLDisplay主要用于管理图形渲染与底层显示设备(如屏幕,窗口系统)之间的连接,是OpenGL,OpenGL ES或Vulkan等图形API与操作系统窗口系统(如X11,Android Surface,Windows GDI)之间交互的桥梁。
eglGetDisplay()的参数类型是EGLNativeDisplayType,在不同平台下具体实现的类型不同。

C++ 复制代码
EGLint majorVersion;
EGLint minorVersion;

// 获取display
display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if(display_ == EGL_NO_DISPLAY) {
    return Error::NewError(ErrorCode::NO_DISPLAY, "Egl get display failed.");
}

// 初始化EGL,
if(!eglInitialize(display_, &majorVersion, &minorVersion)) {
    return Error::NewError(ErrorCode::INIT_EGL_FAIL, "Egl initialize failed.");
}

1.2 EGLConfig

一旦初始化完EGL,我就就可以获得当前平台下可以支持的渲染表面的类型和配置。EGL中用EGLConfig来表示这些配置。我们可以使用eglChooseConfig()方法指定一组我们需要的配置,让EGL来返回最佳匹配的配置。

C++ 复制代码
const EGLint MaxConfigs = 10;
EGLConfig configs[MaxConfigs] = {0};
EGLint numConfigs = 0;
EGLint selectedIdx = -1;

// 我们想要使用RGBA8888, 获取可用的configs,选择第一个
EGLint attribList[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_NONE
};
if(!eglChooseConfig(display_, attribList, configs, MaxConfigs, &numConfigs) || numConfigs <= 0) {
    return Error::NewError(ErrorCode::CHOOSE_EGL_CONFIG_FAIL, "Egl Choose config failed.");
}
if(numConfigs <= 0) {
    return Error::NewError(ErrorCode::NO_SUITABLE_CONFIG, "No suitable config");
}
selectedIdx = 0;

1.3 EGLContext

EGLContext表示的是图形渲染的"上下文环境",负责管理OpenGL/OpenGL ES/Vulkan等图形API的状态和资源(如纹理,着色器,帧缓冲区等),可将其视为图形渲染的"容器",所有的绘图操作都必须在这个上下文中进行。

EGLContext的作用:

  1. 状态管理
    保存当前图形API所有的状态配置,包括着色器程序状态,顶点缓冲区(VBO)绑定,混合模式,深度测试等等。
  2. 资源共享
    在使用eglCreateContext()创建EGLContext时可以传入一个已有的EGLContext,允许多个EGLContext共享资源,如纹理,缓冲区等,避免重复加载。
  3. 维护线程关联性
    一个EGLContext必须在一个线程内使用。
C++ 复制代码
// 创建eglContext
EGLint contextAttribs[] = {
        EGL_CONTEXT_CLIENT_VERSION, 3,  // 请求 ES 3.0
        EGL_NONE
};

// EGL_NO_CONTEXT可以换成一个已有的EGLContext,用于共享上下文
context_ = eglCreateContext(display_, configs[selectedIdx], EGL_NO_CONTEXT, contextAttribs);
if(context_ == EGL_NO_CONTEXT) {
    EGLint error = eglGetError();
    if(error == EGL_BAD_ATTRIBUTE) {
        LogE("Create Context, egl bad attribute.")
    }
    return Error::NewError(ErrorCode::NO_EGL_CONTEXT, "Egl Create Context failed.");
}

1.4 EGLSurface

EGLSurface是OpenGL/Vulkan等图形API绘制图形时的输出载体,表示图形渲染的目标表面,可以是屏幕,离屏缓冲区。

EGLSurface作用:

  1. 渲染目标管理
    图形API输出载体,决定渲染结果的最终显示位置。
  2. 连接窗口系统
    如Android的ANativeWindow,Linux的X11,与之绑定,实现渲染屏幕上更新。
  3. 离屏渲染
    提供离屏渲染的Buffer

以下是使用eglCreateWindowSurface创建EGLSurface,用于屏上渲染的例子:

C++ 复制代码
// 创建EGLSurface,在屏幕渲染
surface_ = eglCreateWindowSurface(display_, configs[selectedIdx], nativeWindow,
                                  nullptr);
// 离屏渲染,创建一个512x512渲染目标
//EGLint attribList[] = {
//    EGL_WIDTH, 512,
//    EGL_HEIGHT, 512,
//    EGL_LARGEST_PBUFFER, EGL_TRUE,
//    EGL_NONE
//};
//surface_ = eglCreatePbufferSurface(display_, configs[selectedIdx], nativeWindow,
//                                  attribList);
if(surface_ == EGL_NO_SURFACE) {
    return Error::NewError(ErrorCode::CREATE_SURFACE_FAILED, "Egl create surface failed.");
}

当然,我们也可以使用eglCreatePbufferSurface()来生成离屏渲染的目标区域。PBuffer即是Pixel buffer,像素缓冲区。

1.5 指定现在的渲染环境

最后,在使用OpenGL/Vulkan前,我们需要指定当前的渲染环境,也就是上面已经创建的一组EGLDisplay,EGLContext,EGLSurface

C++ 复制代码
// make current
if(!eglMakeCurrent(display_, surface_, surface_, context_)) {
    return Error::NewError(ErrorCode::MAKE_CURRENT_FAILED, "Egl make current failed.");
}

2. 其他注意事项

  1. Surface在后台时释放

Android在使用SurfaceView+egl+opengl进行渲染时,当Activity进入后台时,对应的Surface会进行销毁。

我们可以在SurfaceHolder.Callback()surfaceDestroyed()中添加触发逻辑,释放掉底层的EGLSurface

而在Activity重新进入前台时,会触发SurfaceHolder.Callback()onSurfaceChanged()方法,我们可以在此方法中重新创建EGLSurface

相关推荐
阿珊和她的猫3 小时前
<video>` 和 `<audio>` 标签的常用属性解析
前端
LSL666_3 小时前
4 jQuery、JavaScript 作用域、闭包与 DOM 事件绑定
前端·javascript·html
yinuo3 小时前
前端跨页面通讯终极指南⑤:window.name 用法全解析
前端
小飞侠在吗3 小时前
vue computed 和 watch
前端·javascript·vue.js
yinuo3 小时前
前端跨页面通讯终极指南④:MessageChannel 用法全解析
前端
前端布鲁伊4 小时前
聊聊前端容易翻车的“环境管理”
前端·面试
毕设十刻4 小时前
基于Vue的考勤管理系统8n7j8(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
coding随想4 小时前
掌控选区的终极武器:getSelection API的深度解析与实战应用
java·前端·javascript
嵌入式小能手4 小时前
飞凌嵌入式ElfBoard-文件I/O的深入学习之存储映射I/O
java·前端·学习
沐风。565 小时前
Object方法
开发语言·前端·javascript