Opengl ES之EGL

源代码 2024-9-28 22:12:04 54 0 来自 中国
前言

前面我们发布了一系列的入门教程,比方C++系列的指针扫盲、多线程的使用等,JNI入门系列,ffmpeg入门系列等,有感爱好的童鞋们可以关注往回自行查阅。
本日我们的主题依然是音视频开辟的范畴,做过音视频开辟的都知道Opengl也是音视频开辟中的一项紧张技能,特别是涉及到视频录制、殊效处置处罚、画质渲染细分功能。因今后续笔者计划再出一系列的Opengl ES的学习条记,
渴望能与各人共同温故知新。
由于前面先容了一些NDK和C++的教程,以是为了巩固,后续的一些demo多以NDK的情势出现给各人,使用Opengl ES3的版本。
本日我们的主题是Opengl ES的第一篇-->EGL
EGL是什么

众所周知,Opengl是跨平台的,那么面临各种平台的差异性,Opengl是怎样抹平而做到跨平台的呢?这大概就是EGL的功劳吧,简朴地说EGL就是Opengl平静台各平台之间的一个适配器,是一系列的接口,详细实现是由详细的装备厂商实现的。
EGL 是渲染 API(如 OpenGL ES)和原生窗口体系之间的接口.通常来说,OpenGL 是一个使用 GPU 的 API,它通过驱动向 GPU 发送干系指令,控制图形渲染管线状态机的运行状态,但是当涉及到与本地窗口体系举行交互时,就须要这么一个中心层,且它最好是与平台无关的,
因此 EGL 被计划出来,作为 OpenGL 和原生窗口体系之间的桥梁。
[图片上传失败...(image-9ed82b-1662518126650)]
EGL API 是独立于 OpenGL 各版本尺度的独立的一套 API,其重要作用是为 OpenGL 指令 创建上下文 Context 、绘制目的 Surface 、设置 FrameBuffer 属性、Swap 提交绘制结果等。EGL提供如下机制:

  • 与装备的原生窗口体系通讯
  • 查询画图外貌的可用范例和设置
  • 创建画图外貌
  • 在 OpenGL ES 和其他图形渲染 API 之间同步渲染
  • 管理纹理贴图等渲染资源
下面这张图可扼要看出EGL的接口本领:
[图片上传失败...(image-14b629-1662518126651)]
EGL创建流程

想要在安卓上使用Opengl ES我们可以直接使用GLSurfaceView来举行Opengl的渲染,由于GLSurfaceView内部给我们封装好了EGL情况和渲染线程。如果我们想要更高的拓展性,我们也使用SurfaceView,然后参考SurfaceView中的EGL情况搭建、线程模子来
自行搭建Opengl ES的渲染情况。
本着学习探索的目的,我们实验在NDK搭建EGL情况。
下面这张图展示的是安卓体系上EGL的重要使用API:
[图片上传失败...(image-c07680-1662518126651)]
须要阐明的一点是EGL是单线程模子的,也就说说EGL情况的创建、渲染使用、EGL情况的烧毁都必须在同一个线程内完成,否则是无效的。固然我们可以通过共享EGL上下文来做多多线程渲染,但这些都是后话了...
任何OpenGL ES应用步伐都必须在开始渲染之前使用EGL实行如下使命:

  • 查询并初始扮装备商可用的体现器。
  • 创建渲染外貌。
    EGL中创建的外貌可以分类为屏幕上的外貌或者屏幕外的外貌。屏幕上的外貌连接到原生窗口体系,而屏幕外的外貌是不体现但是可以用作渲染外貌的像素缓冲区。这些外貌可以用来渲染纹理,并可以在多个Khronos API之间共享。
  • 创建渲染上下文。
    EGL是创建OpenGL ES渲染上下文所必须的。这个上下文必须连接到符合的外貌才气开始渲染。
下面是EGL情况创建的重要流程:
[图片上传失败...(image-911bb2-1662518126651)]
说完烦躁的根本理论,那就放码过来吧!!!
使用Android Studio创建一个Native工程,然后设置好CMakeLists.txt引入干系库:
cmake_minimum_required(VERSION 3.18.1)project("learn")#找到包罗全部的cpp文件file(GLOB allCpp *.cpp **/**.cpp **/**/**.cpp  **/**/**/**.cpp  **/**/**/**/**.cpp)add_library( # Sets the name of the library.        # 库名称        learn        SHARED        ${allCpp})target_link_libraries(        learn        # 引入egl        egl        # 引入gles 3        GLESv3        # 安卓干系库        android        # 安卓log        log)下面我们创建一个与Native映射的EGLHelper类:
package com.fly.opengles.learn.egl;import android.view.Surface;public class EGLHelper {    protected long nativePtr;    public void surfaceCreated(Surface surface) {        nativePtrInit();        n_surfaceCreated(nativePtr,surface);    }    public void surfaceChanged(int width, int height) {        nativePtrInit();        n_surfaceChanged(nativePtr,width,height);    }    public void surfaceDestroyed() {        if(nativePtr != 0){            n_surfaceDestroyed(nativePtr);            nativePtr = 0;        }    }    private void nativePtrInit(){        if(nativePtr == 0){            nativePtr = n_nativePtrInit();        }    }    private native long n_nativePtrInit();    private native void n_surfaceCreated(long nativePtr,Surface surface);    private native void n_surfaceChanged(long nativePtr,int width, int height);    private native void n_surfaceDestroyed(long nativePtr);}然后自界说一个MySurfaceView继续于SurfaceView,在它的Callback回调方法中对EGL举行使用:
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {    private EGLHelper eglHelper;    public MySurfaceView(Context context) {        this(context,null);    }    public MySurfaceView(Context context, AttributeSet attrs) {        super(context, attrs);        eglHelper = new EGLHelper();        getHolder().addCallback(this);    }    @Override    public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {        eglHelper.surfaceCreated(surfaceHolder.getSurface());    }    @Override    public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int w, int h) {        eglHelper.surfaceChanged(w,h);    }    @Override    public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {        eglHelper.surfaceDestroyed();    }}测试结果时,我们在结构中使用我们自界说好MySurfaceView即可,自此java层代码编写完毕,在NDK层我们将EGL情况创建完毕后即可通过MySurfaceView看到渲染结果。
为了方便调试和debug,我们界说Log.h日记工具:
#ifndef NDK_OPENGLES_LEARN_LOG_H#define NDK_OPENGLES_LEARN_LOG_H#include "android/log.h"#define LOGD(FORMAT, ...) __android_log_print(ANDROID_LOG_DEBUG, "fly_learn_opengl", FORMAT, ##__VA_ARGS__);#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR, "fly_learn_opengl", FORMAT, ##__VA_ARGS__);#endif //NDK_OPENGLES_LEARN_LOG_H将EGL的干系使用封装在类C++的类EglHelper中:
EglHelper.h#ifndef NDK_OPENGLES_LEARN_EGLHELPER_H#define NDK_OPENGLES_LEARN_EGLHELPER_H#include "EGL/egl.h"class EglHelper {public:    EGLDisplay  mEglDisplay;    EGLSurface  mEglSurface;    EGLConfig  mEglConfig;    EGLContext mEglContext;public:    EglHelper();    ~EglHelper();    int initEgl(EGLNativeWindowType win);    int swapBuffers();    void destroyEgl();};#endifEglHelper.cpp重要实现如下,EGL的重要创建过程在函数initEgl中,详细看解释:
#include "EglHelper.h"#include "../utils/Log.h"EglHelper::EglHelper() {    mEglDisplay = EGL_NO_DISPLAY;    mEglSurface = EGL_NO_SURFACE;    mEglContext = EGL_NO_CONTEXT;    mEglConfig = NULL;}EglHelper::~EglHelper() {    destroyEgl();}int EglHelper::initEgl(EGLNativeWindowType window) {    //1、获取体现装备    mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);    if(mEglDisplay == EGL_NO_DISPLAY)    {        LOGE("eglGetDisplay error");        return -1;    }    // 2、 EGL初始化    EGLint *version = new EGLint[2];    if(!eglInitialize(mEglDisplay, &version[0], &version[1]))    {        LOGE("eglInitialize error");        return -1;    }    //3、 资源设置,比方颜色位数等    const EGLint attribs[] = {            EGL_RED_SIZE, 8,            EGL_GREEN_SIZE, 8,            EGL_BLUE_SIZE, 8,            EGL_ALPHA_SIZE, 8,            EGL_DEPTH_SIZE, 8,            EGL_STENCIL_SIZE, 8,            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,            EGL_NONE    };    EGLint num_config;    if(!eglChooseConfig(mEglDisplay, attribs, NULL, 1, &num_config))    {        LOGE("eglChooseConfig  error 1");        return -1;    }    //4、ChooseConfig    if(!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_config, &num_config))    {        LOGE("eglChooseConfig  error 2");        return -1;    }    // 5、创建上下文    int attrib_list[] = {            EGL_CONTEXT_CLIENT_VERSION, 2,            EGL_NONE    };    mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attrib_list);    if(mEglContext == EGL_NO_CONTEXT)    {        LOGE("eglCreateContext  error");        return -1;    }    //6、创建渲染的Surface    mEglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, NULL);    if(mEglSurface == EGL_NO_SURFACE)    {        LOGE("eglCreateWindowSurface  error");        return -1;    }    // 7、使用    if(!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext))    {        LOGE("eglMakeCurrent  error");        return -1;    }    LOGD("egl init success! ");    return 0;}int EglHelper::swapBuffers() {    if(mEglDisplay != EGL_NO_DISPLAY && mEglSurface != EGL_NO_SURFACE)    {        if(eglSwapBuffers(mEglDisplay, mEglSurface))        {            return 0;        }    }    return -1;}void EglHelper::destroyEgl() {    if(mEglDisplay != EGL_NO_DISPLAY)    {        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);    }    if(mEglDisplay != EGL_NO_DISPLAY && mEglSurface != EGL_NO_SURFACE)    {        eglDestroySurface(mEglDisplay, mEglSurface);        mEglSurface = EGL_NO_SURFACE;    }    if(mEglDisplay != EGL_NO_DISPLAY && mEglContext != EGL_NO_CONTEXT){        eglDestroyContext(mEglDisplay, mEglContext);        mEglContext = EGL_NO_CONTEXT;    }    if(mEglDisplay != EGL_NO_DISPLAY)    {        eglTerminate(mEglDisplay);        mEglDisplay = EGL_NO_DISPLAY;    }}本身EGL情况创建完毕,我们通过JNI调用起来看看结果,native-lib.cpp:
#include <jni.h>#include <string>#include "eglhelper/EglHelper.h"#include <cstdint>#include "android/native_window.h"#include "android/native_window_jni.h"#include "GLES3/gl3.h"jlong eglHelperNativePtrInit(JNIEnv *env, jobject thiz) {    EglHelper *eglHelper = new EglHelper();    return reinterpret_cast<uintptr_t>(eglHelper);}void eglSurfaceCreated(JNIEnv *env, jobject thiz,jlong native_ptr, jobject surface) {    if(native_ptr != 0){        EglHelper *eglHelper = reinterpret_cast<EglHelper *>(native_ptr);        ANativeWindow *nativeWindow = ANativeWindow_fromSurface(env, surface);        eglHelper->initEgl(nativeWindow);    }}void eglSurfaceChanged(JNIEnv *env, jobject thiz,jlong native_ptr, jint width,jint height) {    if(native_ptr != 0){        //设置视口巨细        glViewport(0, 0, width, height);        // 绿色清屏//        glClearColor(0.0f, 1.0f, 0.0f, 1.0f);        // 蓝色清屏        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);        glClear(GL_COLOR_BUFFER_BIT);        EglHelper *eglHelper = reinterpret_cast<EglHelper *>(native_ptr);        eglHelper->swapBuffers();    }}void eglSurfaceDestroyed(JNIEnv *env, jobject thiz,jlong native_ptr) {    if(native_ptr != 0){        EglHelper *eglHelper = reinterpret_cast<EglHelper *>(native_ptr);        delete eglHelper;    }}static JNINativeMethod nativeMethod_EGLHelper[] = {        // Java中的函数名        {"n_nativePtrInit",                // 函数署名信息         "()J",                // native的函数指针         (jlong *) (eglHelperNativePtrInit)},        {"n_surfaceCreated",                // 函数署名信息         "(JLandroid/view/Surface;)V",                // native的函数指针         (void *) (eglSurfaceCreated)},        {"n_surfaceChanged",                // 函数署名信息         "(JII)V",                // native的函数指针         (void *) (eglSurfaceChanged)},        {"n_surfaceDestroyed",                // 函数署名信息         "(J)V",                // native的函数指针         (void *) (eglSurfaceDestroyed)},};static int RegisterNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodNum){    jclass clazz = env->FindClass(className);    if (clazz == NULL)    {        return JNI_FALSE;    }    if (env->RegisterNatives(clazz, methods, methodNum) < 0)    {        return JNI_FALSE;    }    return JNI_TRUE;}// 类库加载时自动调用JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reversed){    JNIEnv *env = NULL;    // 初始化JNIEnv    if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK){        return JNI_FALSE;    }    // 动态注册    RegisterNativeMethods(env,"com/fly/opengles/learn/egl/EGLHelper",nativeMethod_EGLHelper,sizeof(nativeMethod_EGLHelper) / sizeof(JNINativeMethod) );    // 返回JNI使用的版本    return JNI_VERSION_1_6;}上述native-lib.cpp涉及到了之前先容过的JNI函数署名、动态注册等干系知识点,忘记了的童鞋可往回看之前的记载。
如偶然外,运行看到的是一个蓝屏画面则阐明EGL情况搭建乐成了,后续开启你的Opengl炫酷之旅吧!!!
保举阅读

JNI根本简介   
JNI之数组与字符串的使用   
JNI之动态注册与静态注册   
JNI之访问java属性和方法   
JNI之缓存与引用  
JNI之非常处置处罚  
JNI之常用本领与陷阱
关注我,一起进步,人生不止coding!!!
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-18 18:19, Processed in 0.161116 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表