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

相关推荐
崔庆才丨静觅14 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606115 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了15 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅15 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅16 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅16 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment16 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅16 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊16 小时前
jwt介绍
前端
爱敲代码的小鱼17 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax