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

相关推荐
几何心凉2 小时前
openGauss:多核时代企业级数据库的性能与高可用新标杆
前端·数据库·数据库开发
AiXed4 小时前
PC微信协议之AES-192-GCM算法
前端·数据库·python
AllData公司负责人4 小时前
实时开发平台(Streampark)--Flink SQL功能演示
大数据·前端·架构·flink·开源
小满zs5 小时前
Next.js第五章(动态路由)
前端
清沫5 小时前
VSCode debugger 调试指南
前端·javascript·visual studio code
一颗宁檬不酸5 小时前
页面布局练习
前端·html·页面布局
金木讲编程7 小时前
Claude、Agent与Copilot协作生成Angular应用
前端·ai编程
lvxiangyu117 小时前
wsl2 ubuntu24 opengl 无法使用nvidia显卡 解决方法记录
wsl·cuda·opengl
振华OPPO7 小时前
Vue:“onMounted“ is defined but never used no-unused-vars
前端·javascript·css·vue.js·前端框架
欧雷殿8 小时前
在富阳银湖成立地域化的软件研发团队
前端·程序员·创业