【Android】Android SurfaceFlinger之OpenGL库加载过程
来源:互联网 发布:网易企业邮箱端口号 编辑:程序博客网 时间:2024/05/29 18:04
1、egl_init_drivers
Android中OpenGL库加载从egl_init_drivers函数开始,源码位置在frameworks/native/opengl/libs/EGL/egl.cpp。
static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;EGLBoolean egl_init_drivers() { EGLBoolean res; pthread_mutex_lock(&sInitDriverMutex); res = egl_init_drivers_locked(); pthread_mutex_unlock(&sInitDriverMutex); return res;}
初始化过程中使用了mutex进行同步保护,下面分析egl_init_drivers_locked。
2、egl_init_drivers_locked
// this mutex protects:// d->disp[]// egl_init_drivers_locked()//static EGLBoolean egl_init_drivers_locked() { if (sEarlyInitState) { // initialized by static ctor. should be set here. return EGL_FALSE; } // get our driver loader Loader& loader(Loader::getInstance()); // dynamically load our EGL implementation egl_connection_t* cnx = &gEGLImpl; if (cnx->dso == 0) { cnx->hooks[egl_connection_t::GLESv1_INDEX] = &gHooks[egl_connection_t::GLESv1_INDEX]; cnx->hooks[egl_connection_t::GLESv2_INDEX] = &gHooks[egl_connection_t::GLESv2_INDEX]; cnx->dso = loader.open(cnx); } return cnx->dso ? EGL_TRUE : EGL_FALSE;}
从上面的egl_init_drivers_locked实现中可以看出OpenGL库最终是通过loader对象完成的,首先看一下sEarlyInitState是何方神圣。
3、sEarlyInitState
static void early_egl_init(void){ int numHooks = sizeof(gHooksNoContext) / sizeof(EGLFuncPointer); EGLFuncPointer *iter = reinterpret_cast<EGLFuncPointer*>(&gHooksNoContext); for (int hook = 0; hook < numHooks; ++hook) { *(iter++) = reinterpret_cast<EGLFuncPointer>(gl_no_context); } setGLHooksThreadSpecific(&gHooksNoContext);}static pthread_once_t once_control = PTHREAD_ONCE_INIT;static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
sEarlyInitState为pthread_once的返回值,成功时返回0。pthread_once保证多线程时early_egl_init只执行一次,early_egl_init用来设置线程特有的数据(pthread_setspecific/pthread_getspecific),这也是一种数据共享方式。EGLFuncPointer为函数指针,如下所示:
typedef void (*__eglMustCastToProperFunctionPointerType)(void);typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer;
gHooksNoContext是个有趣的数据结构,如下所示:
// maximum number of GL extensions that can be used simultaneously in// a given process. this limitation exists because we need to have// a static function for each extension and currently these static functions// are generated at compile time.#define MAX_NUMBER_OF_GL_EXTENSIONS 256struct gl_hooks_t { struct gl_t { #include "entries.in" } gl; struct gl_ext_t { __eglMustCastToProperFunctionPointerType extensions[MAX_NUMBER_OF_GL_EXTENSIONS]; } ext;};extern gl_hooks_t gHooksNoContext;
上面的gl_t结构体实际上包含了同OpenGL函数一致的函数指针,通过“entries.in”和GL_ENTRY进行扩展,如下所示:
#define GL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__);// entries.inGL_ENTRY(void, glActiveShaderProgram, GLuint pipeline, GLuint program)GL_ENTRY(void, glActiveShaderProgramEXT, GLuint pipeline, GLuint program)......
gl_no_context用于检查OpenGL函数调用是否设置了Context,其中用到了设置线程键的egl_tls_t类和收集函数调用栈帧的CallStack类。
static int gl_no_context() { if (egl_tls_t::logNoContextCall()) { char const* const error = "call to OpenGL ES API with " "no current context (logged once per thread)"; if (LOG_NDEBUG) { ALOGE(error); } else { LOG_ALWAYS_FATAL(error); } char value[PROPERTY_VALUE_MAX]; property_get("debug.egl.callstack", value, "0"); if (atoi(value)) { CallStack stack(LOG_TAG); } } return 0;}
随后,将修改过的gHooksNoContext通过setGLHooksThreadSpecific设置线程键,而__get_tls则是通过汇编实现的(不同的硬件有不同的汇编代码),如下所示:
void setGLHooksThreadSpecific(gl_hooks_t const *value) { setGlThreadSpecific(value);}void setGlThreadSpecific(gl_hooks_t const *value) { gl_hooks_t const * volatile * tls_hooks = get_tls_hooks(); tls_hooks[TLS_SLOT_OPENGL_API] = value;}inline gl_hooks_t const * volatile * get_tls_hooks() { volatile void *tls_base = __get_tls(); gl_hooks_t const * volatile * tls_hooks = reinterpret_cast<gl_hooks_t const * volatile *>(tls_base); return tls_hooks;}// Well-known TLS slots. What data goes in which slot is arbitrary unless otherwise noted.enum { TLS_SLOT_SELF = 0, // The kernel requires this specific slot for x86. TLS_SLOT_THREAD_ID, TLS_SLOT_ERRNO, // These two aren't used by bionic itself, but allow the graphics code to // access TLS directly rather than using the pthread API. TLS_SLOT_OPENGL_API = 3, TLS_SLOT_OPENGL = 4, // This slot is only used to pass information from the dynamic linker to // libc.so when the C library is loaded in to memory. The C runtime init // function will then clear it. Since its use is extremely temporary, // we reuse an existing location that isn't needed during libc startup. TLS_SLOT_BIONIC_PREINIT = TLS_SLOT_OPENGL_API, TLS_SLOT_STACK_GUARD = 5, // GCC requires this specific slot for x86. TLS_SLOT_DLERROR, // Fast storage for Thread::Current() in ART. TLS_SLOT_ART_THREAD_SELF, // Lets TSAN avoid using pthread_getspecific for finding the current thread // state. TLS_SLOT_TSAN, BIONIC_TLS_SLOTS // Must come last!};
4、egl_connection_t
在分析Loader前先来看一下egl_connection_t,其结构如下所示:
extern egl_connection_t gEGLImpl;extern gl_hooks_t gHooks[2];struct egl_connection_t { enum { GLESv1_INDEX = 0, GLESv2_INDEX = 1 }; inline egl_connection_t() : dso(0) { } void * dso; gl_hooks_t * hooks[2]; EGLint major; EGLint minor; egl_t egl; void* libEgl; void* libGles1; void* libGles2;};
从上面的egl_connection_t结构体及前面的egl_init_drivers_locked函数定义可以看出,包括两个hook,GLESv1和GLESv2,而dso则实际上指向了libEGL、libGLESv1和libGLESv2(从后面的Loader分析中可以看出),egl_t类似于gl_t,包含了一系列egl函数指针。下面着重分析Loader。
5、Loader-open
Loader是个单实例,如下所示:
class Loader : public Singleton<Loader>
从Loader::open开始,包括两部分,load_driver和load_wrapper,如下所示:
void* Loader::open(egl_connection_t* cnx){ void* dso; driver_t* hnd = 0; setEmulatorGlesValue(); dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2); if (dso) { hnd = new driver_t(dso); } else { // Always load EGL first dso = load_driver("EGL", cnx, EGL); if (dso) { hnd = new driver_t(dso); hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM ); hnd->set( load_driver("GLESv2", cnx, GLESv2), GLESv2 ); } } LOG_ALWAYS_FATAL_IF(!hnd, "couldn't find an OpenGL ES implementation"); cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so"); cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so"); cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so"); LOG_ALWAYS_FATAL_IF(!cnx->libEgl, "couldn't load system EGL wrapper libraries"); LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1, "couldn't load system OpenGL ES wrapper libraries"); return (void*)hnd;}
在分析load_driver和load_wrapper之前,先来看一下driver_t,这是个Loader类的内部结构体,如下所示:
struct driver_t { explicit driver_t(void* gles); ~driver_t(); status_t set(void* hnd, int32_t api); void* dso[3]; };
driver_t的dso分别保存了EGL、GLESv1_CM和GLESv2三个库。open函数中还调用了setEmulatorGlesValue,这个函数就是检查、设置一些模拟器属性(是否在模拟器中运行?在模拟中运行时是否有GPU支持?),比较简单,代码如下:
static void setEmulatorGlesValue(void) { char prop[PROPERTY_VALUE_MAX]; property_get("ro.kernel.qemu", prop, "0"); if (atoi(prop) != 1) return; property_get("ro.kernel.qemu.gles",prop,"0"); if (atoi(prop) == 1) { ALOGD("Emulator has host GPU support, qemu.gles is set to 1."); property_set("qemu.gles", "1"); return; } // for now, checking the following // directory is good enough for emulator system images const char* vendor_lib_path =#if defined(__LP64__) "/vendor/lib64/egl";#else "/vendor/lib/egl";#endif const bool has_vendor_lib = (access(vendor_lib_path, R_OK) == 0); if (has_vendor_lib) { ALOGD("Emulator has vendor provided software renderer, qemu.gles is set to 2."); property_set("qemu.gles", "2"); } else { ALOGD("Emulator without GPU support detected. " "Fallback to legacy software renderer, qemu.gles is set to 0."); property_set("qemu.gles", "0"); }}
6、Loader-load_driver
void *Loader::load_driver(const char* kind, egl_connection_t* cnx, uint32_t mask){class MatchFile {};...}
EGL驱动需要提供一个单一的库libGLES.so,或者是三个分开的库libEGL.so、libGLESv1_CM.so和libGLESv2.so,模拟器中的软描画则需要提供单一的库libGLES_android.so,为了兼容旧版本的“egl.cfg”文件配置,这几个库后面还可能加一个名称如_emulation。在load_driver函数中还有个内部类MatchFile,用于在某个lib目录中查找特定的OpenGL库是否存在,存在的话进而通过dlopen打开,dlopen成功后再通过dlsym逐个获取OpenGL所有API的地址并将它们保存下来。
7、load_wrapper
load_wrapper相对load_driver来说较简单,就是dlopen一个so,如下所示:
static void* load_wrapper(const char* path) { void* so = dlopen(path, RTLD_NOW | RTLD_LOCAL); ALOGE_IF(!so, "dlopen(\"%s\") failed: %s", path, dlerror()); return so;}
- Android SurfaceFlinger之OpenGL库加载过程
- 【Android】Android SurfaceFlinger之OpenGL库加载过程
- 【Android】Android SurfaceFlinger之SurfaceFlinger启动过程
- Android SurfaceFlinger之SurfaceFlinger启动过程
- 【Android】Android SurfaceFlinger之OpenGL ES
- Android OpenGL库加载过程源码分析
- Android OpenGL库加载过程源码分析
- Android GDI之SurfaceFlinger
- Android GDI之SurfaceFlinger
- android 4.2 dumpsys SurfaceFlinger 过程
- 【Android】Android SurfaceFlinger之Gralloc
- 【Android】Android SurfaceFlinger之NativeWindow
- 【Android】Android SurfaceFlinger之BufferQueue
- 【Android】Android SurfaceFlinger之VSync
- Android SurfaceFlinger 学习之路(四)----SurfaceFlinger服务的启动与连接过程
- Android SurfaceFlinger之CS架构
- android surfaceflinger
- Android SurfaceFlinger服务启动过程源码分析
- JSR303使用说明文档
- Qt布局详解
- C++之set和multiset容器初学
- 观察者模式
- WPScan初体验
- 【Android】Android SurfaceFlinger之OpenGL库加载过程
- Android studio下将项目代码上传至github包括更新,同步,创建依赖
- C# 控件Anchor和Dock的区别
- Mac 处理 .DS_Store 的方法
- poj1236 有线图的强连通分量 tarjan算法判断
- Android SQLite数据库的使用小结
- Android 数字标记
- plt绘图
- Java之Semaphore