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

相关推荐
星栈独行9 小时前
Makepad 应用如何读文件、调接口、保存数据
前端·程序人生·ui·rust·github
IT_陈寒10 小时前
Vite热更新失效?可能你在用Windows
前端·人工智能·后端
tedcloud12311 小时前
taste-skill部署教程:打造个性化AI推荐工作流
服务器·前端·人工智能·系统架构·edge
xinhuanjieyi11 小时前
html修复游戏种太阳错误
前端·游戏·html
林希_Rachel_傻希希12 小时前
学React治好了我的焦虑症,1小时速通React 前20分钟。
前端·javascript·面试
Cache技术分享12 小时前
435. Java 日期时间 API - Clock 灵活获取当前时间
前端·后端
Strugglingler12 小时前
【Qt,OpenGL, RHI,Wayland 等概念梳理】
qt·opengl·wayland·rhi·x11·egl·glx
独泪了无痕13 小时前
Vue3中防御XSS攻击的“特效药”-DOMPurify
前端·vue.js·安全
小小199213 小时前
idea 配置less转化为css
前端·css·less
hhb_61813 小时前
Less嵌套避坑:优先级冲突实战解析
前端·css·less