【openGLES】安卓端EGL的使用

文章目录

  • [1. EGL是什么?](#1. EGL是什么?)
  • [2. EGL的使用流程](#2. EGL的使用流程)
    • [2.1 在线渲染](#2.1 在线渲染)
    • [2.2 离屏渲染](#2.2 离屏渲染)

1. EGL是什么?

EGL(Embedded-System Graphics Library)​​ 是 Khronos Group 制定的标准接口,用于 ​管理 OpenGL ES / OpenVG 与本地窗口系统之间的交互。它相当于一个"中间层",解决以下问题:

  • 跨平台兼容性:不同操作系统(Android、Linux、Windows 等)的窗口系统差异。
  • 资源管理:创建渲染表面(Surface)、上下文(Context)、缓冲区等。
  • 多API支持:支持 OpenGL ES、OpenGL、OpenVG 等多种图形API。
html 复制代码
EGLDisplay (连接显示系统)
    │
    ├── EGLSurface (渲染目标:窗口或离屏缓冲区)
    │
    └── EGLContext (渲染状态和环境)
          │
          └── OpenGL ES 绘制命令

2. EGL的使用流程

EGL 的初始化流程有严格的顺序要求,错误顺序会导致崩溃或上下文创建失败。

​标准流程​:

  1. 获取 Display → eglGetDisplay()
  2. 初始化 EGL → eglInitialize()
  3. 绑定 API → eglBindAPI()(明确使用 OpenGL ES 还是 OpenGL)
  4. 选择 Config → eglChooseConfig()。EGL Config 决定了渲染表面的属性(如颜色深度、深度缓冲区、模板缓冲区等)。
  5. 创建 Surface → eglCreateWindowSurface()(在线渲染)或者eglCreatePbufferSurface()(离屏渲染)
  6. 创建 Context → eglCreateContext()
  7. 绑定 Context 和 Surface → eglMakeCurrent()

EGL 资源必须手动释放,且顺序与创建相反:

  • 解绑 Context → eglMakeCurrent(..., EGL_NO_CONTEXT)
  • 销毁 Context → eglDestroyContext()
  • 销毁 Surface → eglDestroySurface()
  • 终止 Display → eglTerminate()

​注意事项​:

  • 在 eglInitialize() 之前调用 eglChooseConfig() 会直接失败。
  • 单线程绑定:eglMakeCurrent() 会将 Context 绑定到当前线程,同一线程只能绑定一个 Context。
  • 多线程渲染:需在每个线程单独创建和绑定 Context,并共享资源(通过 eglCreateContext() 的 share_context 参数)。
  • 解绑时机:在销毁 Context 前必须调用 eglMakeCurrent(..., EGL_NO_CONTEXT)。

若使用 ​PBuffer​ 或 ​FBO​ 离屏渲染:

  • PBuffer:通过 eglCreatePbufferSurface() 创建,需指定宽高。
  • FBO:更灵活,但需额外管理帧缓冲和纹理附件。
  • 性能优化:离屏渲染可能比窗口渲染更快(无垂直同步限制)。

2.1 在线渲染

cpp 复制代码
#include <EGL/egl.h>
#include <GLES3/gl3.h>

EGLDisplay eglDisplay;
EGLSurface eglSurface;
EGLContext eglContext;

bool initOnScreenEGL() {
    // 1. 获取默认显示连接
    eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (eglDisplay == EGL_NO_DISPLAY) return false;

    // 2. 初始化 EGL
    EGLint major, minor;
    if (!eglInitialize(eglDisplay, &major, &minor)) return false;

    // 3. 选择配置
    const EGLint configAttribs[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_DEPTH_SIZE, 24,
        EGL_NONE
    };
    EGLConfig eglConfig;
    EGLint numConfigs;
    if (!eglChooseConfig(eglDisplay, configAttribs, &eglConfig, 1, &numConfigs)) return false;

    // 4. 创建窗口表面(绑定到原生窗口)
    // 安卓端从 SurfaceHolder 获取 ANativeWindow
	ANativeWindow* nativeWindow = ANativeWindow_fromSurface(env, surface);
	eglCreateWindowSurface(display, config, window, nullptr);
    eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, nativeWindow, nullptr);  
    if (eglSurface == EGL_NO_SURFACE) return false;
    
    // 5. 创建上下文
    const EGLint contextAttribs[] = {
        EGL_CONTEXT_CLIENT_VERSION, 3,
        EGL_NONE
    };
    eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttribs);
    if (eglContext == EGL_NO_CONTEXT) return false;

    // 6. 绑定上下文和表面
    if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) return false;

    return true;
}

void renderFrame() {
    glClearColor(0.2f, 0.3f, 0.4f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    // 绘制代码...
    eglSwapBuffers(eglDisplay, eglSurface); // 交换缓冲区,显示到屏幕
}

void cleanup() {
    eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroyContext(eglDisplay, eglContext);
    eglDestroySurface(eglDisplay, eglSurface);
    eglTerminate(eglDisplay);
}

2.2 离屏渲染

cpp 复制代码
#include <EGL/egl.h>
#include <GLES3/gl3.h>

EGLDisplay eglDisplay;
EGLSurface eglSurface; // PBuffer Surface
EGLContext eglContext;

bool initOffScreenEGL(int width, int height) {
    // 1. 获取默认显示连接
    eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (eglDisplay == EGL_NO_DISPLAY) return false;

    // 2. 初始化 EGL
    EGLint major, minor;
    if (!eglInitialize(eglDisplay, &major, &minor)) return false;

    // 3. 选择配置(不需要 EGL_WINDOW_BIT)
    const EGLint configAttribs[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, // 使用 PBuffer
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_DEPTH_SIZE, 24,
        EGL_NONE
    };
    EGLConfig eglConfig;
    EGLint numConfigs;
    if (!eglChooseConfig(eglDisplay, configAttribs, &eglConfig, 1, &numConfigs)) return false;

    // 4. 创建 PBuffer 表面(离屏渲染目标)
    const EGLint pbufferAttribs[] = {
        EGL_WIDTH, width,
        EGL_HEIGHT, height,
        EGL_NONE
    };
    eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, pbufferAttribs);
    if (eglSurface == EGL_NO_SURFACE) return false;

    // 5. 创建上下文
    const EGLint contextAttribs[] = {
        EGL_CONTEXT_CLIENT_VERSION, 3,
        EGL_NONE
    };
    eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttribs);
    if (eglContext == EGL_NO_CONTEXT) return false;

    // 6. 绑定上下文和 PBuffer 表面
    if (!eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) return false;

    return true;
}

void renderToTexture() {
    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);

    // 绑定 FBO 并渲染到纹理
    GLuint fbo;
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);

    glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    // 绘制代码...

    glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑 FBO
}

void cleanup() {
    eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroyContext(eglDisplay, eglContext);
    eglDestroySurface(eglDisplay, eglSurface);
    eglTerminate(eglDisplay);
}
相关推荐
安东尼肉店4 小时前
Android compose屏幕适配终极解决方案
android
2501_916007475 小时前
HTTPS 抓包乱码怎么办?原因剖析、排查步骤与实战工具对策(HTTPS 抓包乱码、gzipbrotli、TLS 解密、iOS 抓包)
android·ios·小程序·https·uni-app·iphone·webview
feiyangqingyun6 小时前
基于Qt和FFmpeg的安卓监控模拟器/手机摄像头模拟成onvif和28181设备
android·qt·ffmpeg
用户20187928316710 小时前
ANR之RenderThread不可中断睡眠state=D
android
煤球王子10 小时前
简单学:Android14中的Bluetooth—PBAP下载
android
小趴菜822710 小时前
安卓接入Max广告源
android
齊家治國平天下10 小时前
Android 14 系统 ANR (Application Not Responding) 深度分析与解决指南
android·anr
ZHANG13HAO10 小时前
Android 13.0 Framework 实现应用通知使用权默认开启的技术指南
android
【ql君】qlexcel10 小时前
Android 安卓RIL介绍
android·安卓·ril
写点啥呢10 小时前
android12解决非CarProperty接口深色模式设置后开机无法保持
android·车机·aosp·深色模式·座舱