Android OpenGL库加载和调用过程
(2016-04-28 21:24:13)
标签:
androidopenglegl |
OpenGL和EGL
Android里跟OpenGL相关的模块主要是两个,一个是OpenGL ES, 另一个是EGL。EGL是OpenGL和本地窗口的接口。在调用GLES glXX函数进行绘图之前,必须要调用egl的函数进行opengl环境的初始化,比如eglGetDisplay,eglInitialize,eglChooseConfig,eglCreateWindowSurface等。这些函数结合本地窗口,做完后就可以调OpenGL的glxxxx函数来画图了。Android的起机动画是一个很好的例子,frameworks/base/cmds/bootanimation/BootAnimation.cpp。
EGL和OpenGL的关系网上有很多教程和文章,这里就不细述了。
OpenGL/EGL库加载过程
当前支持Android主流SOC平台都硬件支持OpenGL ES,这些平台提供预先编译好的对OpenGL ES支持的二进制库文件,一般库文件位于/system/lib/egl或/system/vendor/lib/egl/目录中。这个加载方式跟gralloc和hwcomposer类似,都是用dlopen的方式加载。
当eglGetDisplay被调用时,opengl的库文件就被加载了,具体过程是:
eglApi.cpp:: eglGetDisplay
egl_init_drivers
egl_init_drivers_locked
Loader::open
load_driver("GLES",…);
在Loader.cpp::load_driver里,它把所有eglxxx, glxxx函数定位,并存到egl_connection_t. gl_hooks_t(hooks[2]).gl里,两个hooks是针对于gles v1和v2。
gl_hooks_t的结构定义
struct gl_hooks_t {
} gl;
…
};
entries.in里定义了GLES的函数集,库加载时根据这个表循环就可以查找GLES函数的实现了:
GL_ENTRY(void, glActiveShaderProgram, GLuint pipeline, GLuint program)
GL_ENTRY(void, glActiveShaderProgramEXT
GL_ENTRY(void, glActiveTexture, GLenum texture)
GL_ENTRY(void, glAlphaFunc, GLenum func, GLfloat ref)
GL_ENTRY(void, glAlphaFuncQCOM, GLenum func, GLclampf ref)
GL_ENTRY(void, glAlphaFuncx, GLenum func, GLfixed ref)
GL_ENTRY(void, glAlphaFuncxOES, GLenum func, GLfixed ref)
GL_ENTRY(void, glAttachShader, GLuint program, GLuint shader)
GL_ENTRY(void, glBeginPerfMonitorAMD, GLuint monitor)
GL_ENTRY(void, glBeginPerfQueryINTEL, GLuint queryHandle)
GL_ENTRY(void, glBeginQuery, GLenum target, GLuint id)
…
加载egl的函数表和GLES的方式非常类似,区别就在于egl的函数表是在egl_entries.in里定义:
EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)
EGL_ENTRY(EGLBoolean, eglInitialize, EGLDisplay, EGLint*, EGLint*)
EGL_ENTRY(EGLBoolean, eglTerminate, EGLDisplay)
EGL_ENTRY(EGLBoolean, eglGetConfigs, EGLDisplay, EGLConfig*, EGLint, EGLint*)
EGL_ENTRY(EGLBoolean, eglChooseConfig, EGLDisplay, const EGLint *, EGLConfig *, EGLint, EGLint *)
….
egl的函数不在hooks里存,它存在egl_connection_t. egl_t里,这里egl_t也是一个函数表:
struct egl_t {
};
OpenGL/EGL函数调用流程
这一节是说java/native c/c++的glxxx/eglxxx函数是怎么调用Soc提供的.so库文件里的。
egl函数调用
egl函数可以在java或native里调用,如果从java里调用,直接调EGL14的静态函数:
mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
然后函数就走到jni里:
android_opengl_EGL14.cpp::android_eglGetDisplay里,最后调到eglAPI.cpp:: eglGetDisplay里了。
有些egl函数会调用加载的库函数表里,有些不会。比如下面这个eglGetConfigs会:
}
cnx->egl就是前面说的函数表
struct egl_t {
};
GLES函数调用
GLES也是既可以从java/jni里调,也可以在native里调用。GLES函数都以gl开头。
比如java/native glViewport,这个函数GLES v1/V2里都有,以v1为例,java的glViewport通过android_opengl_GLES10.cpp:: android_glViewport__IIII调到了glViewport(native函数)。这个函数是在frameworks/native/opengl/libs/GLES_CM/gl.cpp里实现。这个文件里有:
extern "C" {
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include "gl_api.in"
#include "glext_api.in"
#pragma GCC diagnostic warning "-Wunused-parameter"
}
它跟前面类似,函数定于在函数表gl_api.in里。gl_api.in里定义是:
…
void API_ENTRY(glVertexPointer)(GLint size, GLenum type, GLsizei stride, const void * pointer) {
}
void API_ENTRY(glViewport)(GLint x, GLint y, GLsizei width, GLsizei height) {
}
CALL_GL_API是一个宏定义,就在gl.cpp里。它定义是如果调了这个函数(比如glViewport),最终会调用gl_hooks_t里的函数指针。
ARM的:
I386的:
前面说过,GLES的函数库动态加载,并存于gl_hooks_t里。这里就跟前面对上了,也就是说,如果调了GLES的glxxxx函数,它会最终调用存在gl_hooks_t里动态加载的函数指针。