美文网首页iOS技术文章OpenGLAndroid开发经验谈
NDK OpenGL ES 3 编译C/C++可执行文件(无需J

NDK OpenGL ES 3 编译C/C++可执行文件(无需J

作者: 熊皮皮 | 来源:发表于2016-02-23 22:13 被阅读1771次

    无需JNI调用是指将C/C++代码编译成Linux可执行程序,不需打包成APK或APK + JNI调用。此方式适用于已Root的手机。

    这里的使用场景是OpenGL ES作为通用计算单元,只处理数据,不用显示到屏幕。也可以考虑OpenCL、RenderScript,不过OpenCL只有部分Android设备才支持。

    运行环境为Android 6.0。

    1、Android.mk编译脚本

    Android.mk文件内容如下:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR-VARS)
    LOCAL_MODULE := opengles_module
    LOCAL_MODULE_FILENAME := libopengles_module
    LOCAL_SRC_FILES := *.cpp
    LOCAL_CFLAGS += -pie -fPIE
    LOCAL_LDFLAGS += -pie -fPIE
    LOCAL_LDLIBS += -lGLESv3 -lEGL -landroid
    
    include $(BUILD_EXECUTABLE)
    

    PIE安全机制从4.1引入,Android L之前的系统并不会去检验可执行文件是否基于PIE编译出的,但是Android L已经开启验证,如果调用的可执行文件不是基于PIE方式编译的,则无法运行并提示错误error: only position independent executables (PIE) are supported.。解决办法为在Android.mk中加入LOCAL_LDFLAGS += -pie -fPIE即可。

    因为OpenGL ES系统与本地窗口系统连接在Android系统中需要配置EGL,在iOS中为EAGL,-lEGL -landroid完成了链接任务。当然-lGLESv3也是必须的,不然用不了OpenGL ES 3.0。

    使用OpenGL ES 3.0是因为它提供了新功能Transform Feedback,允许用户读取Vertex Shader的计算结果,设置不进行光栅化,省掉渲染管线后续流程。而OpenGL ES 2.0只能读取Fragment Shader的处理结果。虽然,对于做通用计算的场合,Fragment Shader是多余的,只想利用Vertex Shader作并行处理单元,而无需屏幕显示界面。但是,还得为OpenGL ES提供Fragment Shader,空操作就行。

    2、配置EGL

    首先,定义后面用的变量。

    static EGLConfig eglConf;
    static EGLSurface eglSurface;
    static EGLContext eglCtx;
    static EGLDisplay eglDisp;
    

    现在创建EGL环境,只有设置EGLContext为当前绘图上下文才能使用OpenGL ES接口,否则它们都调用失败。

    void setupEGL(int w, int h) {
        // EGL config attributes
        const EGLint confAttr[] = {
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,    // very important!
            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,          // we will create a pixelbuffer surface
            EGL_RED_SIZE,   8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE,  8,
            EGL_ALPHA_SIZE, 8,     // if you need the alpha channel
            EGL_DEPTH_SIZE, 16,    // if you need the depth buffer
            EGL_NONE
        };
        
        // EGL context attributes
        const EGLint ctxAttr[] = {
            EGL_CONTEXT_CLIENT_VERSION, 3,              // 初始化3.0的上下文
            EGL_NONE
        };
        
        // surface attributes
        // the surface size is set to the input frame size
        const EGLint surfaceAttr[] = {
            EGL_WIDTH, w,
            EGL_HEIGHT, h,
            EGL_NONE
        };
        
        EGLint eglMajVers, eglMinVers;
        EGLint numConfigs;
        
        eglDisp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        eglInitialize(eglDisp, &eglMajVers, &eglMinVers);
        
        printf("EGL init with version %d.%d", eglMajVers, eglMinVers);
        
        // choose the first config, i.e. best config
        eglChooseConfig(eglDisp, confAttr, &eglConf, 1, &numConfigs);
        
        eglCtx = eglCreateContext(eglDisp, eglConf, EGL_NO_CONTEXT, ctxAttr);
        
        // create a pixelbuffer surface
        eglSurface = eglCreatePbufferSurface(eglDisp, eglConf, surfaceAttr);
        
        eglMakeCurrent(eglDisp, eglSurface, eglSurface, eglCtx);
    }
    

    3、检查OpenGL ES版本

    有很多种办法获取当前Android设备支持的OpenGL ES版本,直接打印也行:

    static void printGLString(const char *name, GLenum s) {
        const char *v = (const char *) glGetString(s);
        printf("GL %s = %s\\n", name, v);
    }
    
    void printOpenGLInfo() {
        printGLString("Version", GL_VERSION);
        printGLString("Vendor", GL_VENDOR);
        printGLString("Renderer", GL_RENDERER);
        printGLString("Extensions", GL_EXTENSIONS);
    }
    

    如果输出类似Version = OpenGL ES 3.1,那就可以用Transform Feedback。

    4、使用Transform Feedback编程

    因内容较多,另起一篇文档描述Transform Feedback的使用

    参考

    1. Android off-screen rendering using EGL pixelbuffers and OpenGL ES 2.0

    相关文章

      网友评论

        本文标题:NDK OpenGL ES 3 编译C/C++可执行文件(无需J

        本文链接:https://www.haomeiwen.com/subject/pftikttx.html