【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 快捷方式实战指南:静态、动态与固定快捷方式详解
android
hqk4 小时前
鸿蒙项目实战:手把手带你实现 WanAndroid 布局与交互
android·前端·harmonyos
LING5 小时前
RN容器启动优化实践
android·react native
恋猫de小郭7 小时前
Flutter 发布官方 Skills ,Flutter 在 AI 领域再添一助力
android·前端·flutter
Kapaseker12 小时前
一杯美式搞懂 Any、Unit、Nothing
android·kotlin
黄林晴12 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭1 天前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab1 天前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe1 天前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农1 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos