目录
egl,opengl es的软硬件实现
需要的库
库的分工
加载模块
软件实现模块
硬件实现模块
egl,opengl es的软硬件实现
需要的库
//算是android中的egl库,用来加载具体的实现(软件实现或者硬件实现)
system\lib\libEGL.so
//opengl具体实现的wrapper,无论软件硬件实现时,均需加载这2个调用转发库
system\lib\libGLESv1_CM.so // opengl es 1.0调用的wrapper壳,对应的源文件是:
///frameworks/native/opengl/libs/GLES_CM/gl.cpp
system\lib\libGLESv2.so // opengl es 2.0调用的wrapper壳,可shader编程, 对应的源文件是:
//opengl软件实现,即agl,包括egl和gl的实现,不分opengl es 1.0和2.0
system\lib\egl\libGLES_android.so
//opengl的硬件实现,例如高通的实现
system\vendor\lib\egl\libEGL_adreno.so
//opengl硬件实现
system\vendor\lib\egl\libGLESv1_CM_adreno.so
system\vendor\lib\egl\libGLESv2_adreno.so
以上无论软件还是硬件具体实现的接口是 EGL/egl.h,GLES/gl.h。
库的分工
Egl和gl的标准在/frameworks/native/opengl/include/下,通常如下加入标准:
include <EGL/egl.h>
include <GLES/gl.h>
加载模块
这俩标准的实现一个是软件实现,一个硬件实现,无论软硬,都需要一个加载模块。在/frameworks/native/opengl/libs/Android.mk文件里的libEGL模块便是。
23LOCAL_SRC_FILES:= \
24 EGL/egl_tls.cpp \
25 EGL/egl_cache.cpp \
26 EGL/egl_display.cpp \
27 EGL/egl_object.cpp \
28 EGL/egl.cpp \
29 EGL/eglApi.cpp \ ,
30 EGL/trace.cpp \
31 EGL/getProcAddress.cpp.arm \
32 EGL/Loader.cpp \
37LOCAL_MODULE:= libEGL
当开始使用libEGL 模块中的egl接口(eglApi.cpp中的某些函数,他们是eglGetDisplay,eglGetProcAddress,eglBindAPI等,他们包含了egl_init_drivers()函数用来初始化模块的加载,它是实现在egl.cpp中,而且eglApi.cpp是egl接口实现,它是软件实现的第一层调用)时,就会触发软硬件实现模块的加载,加载软件实现还硬件实现,在4.3版本中的判断是:
153 FILE* cfg = fopen("/system/lib/egl/egl.cfg", "r");
154 if (cfg == NULL) {//说明软件模块
155 // default config
156 ALOGD("egl.cfg not found, using default config");
157 mDriverTag.setTo("android");//说明软件模块
158 } else {//硬件模块
159 while (fgets(line, 256, cfg)) {
160 int dpy, impl;
161 if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
162 //ALOGD(">>> %u %u %s", dpy, impl, tag);
163 // We only load the h/w accelerated implementation
164 if (tag != String8("android")) {
165 mDriverTag = tag;
166 }
167 }
168 }
169 fclose(cfg);
170 }
其中EGL/eglApi.cpp 实现了egl接口,这里的是egl接口的第一层调用,最终调用的是软硬件实现里面的egl实现,为什么?Loader.cpp加载libGLES_android.so或者加载其他opengl厂商实现的so包的时候,有如下一段代码:
void *Loader::load_driver(const char* kind, const char *tag,
282 egl_connection_t* cnx, uint32_t mask)
……
egl_t* egl = &cnx->egl;//加载实现包里的egl接口实现到此处。
342 __eglMustCastToProperFunctionPointerType* curr =
343 (__eglMustCastToProperFunctionPointerType*)egl;
344 char const * const * api = egl_names;
345 while (*api) {
346 char const * name = *api;
347 __eglMustCastToProperFunctionPointerType f =
348 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
349 if (f == NULL) {
350 // couldn't find the entry-point, use eglGetProcAddress()
351 f = getProcAddress(name);
352 if (f == NULL) {
353 f = (__eglMustCastToProperFunctionPointerType)0;
354 }
355 }
356 *curr++ = f;
357 api++;
358 }
//看一下egl_connection_t结构:
34struct egl_connection_t {
35 enum {
36 GLESv1_INDEX = 0,
37 GLESv2_INDEX = 1
38 };
39
40 inline egl_connection_t() : dso(0) { }
41 void * dso;
42 gl_hooks_t * hooks[2];//gl1,gl2接口函数实现加载到此处
43 EGLint major;
44 EGLint minor;
45 egl_t egl;//软硬件实现的egl接口函数加载到此处
46
47 void* libGles1;
48 void* libGles2;
49};
//在看一下其中的egl_t,gl_hooks_t结构:
71struct egl_t {
72 #include "EGL/egl_entries.in",//一系列egl接口中的函数指针变量,待实现库来填充
73};
74
75struct gl_hooks_t {
76 struct gl_t {
77 #include "entries.in"//,一系列gl接口中函数指针变量,待实现库来填充
78 } gl;
79 struct gl_ext_t {
80 __eglMustCastToProperFunctionPointerType extensions[MAX_NUMBER_OF_GL_EXTENSIONS];
81 } ext;
82};
总结,无论是SF模块,还是Bootanimation模块,他们在使用egl的时候,首先找到eglApi.cpp的第一层调用,然后再:例如:
344EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
345 EGLint attribute, EGLint *value)
346{
347 clearError();
348
349 egl_connection_t* cnx = NULL;
350 const egl_display_ptr dp = validate_display_connection(dpy, cnx);
351 if (!dp) return EGL_FALSE;
352
353 return cnx->egl.eglGetConfigAttrib(//!
354 dp->disp.dpy, config, attribute, value);
355}
至于gl的调用逻辑,在调用egl_init_drivers()函数用来初始化模块的加载的时候,也把软硬家的gl实现加载到了一个地方。
361 if (mask & GLESv1_CM) {
362 init_api(dso, gl_names,
363 (__eglMustCastToProperFunctionPointerType*)
364 &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,
365 getProcAddress);
366 }
367
368 if (mask & GLESv2) {
369 init_api(dso, gl_names,
370 (__eglMustCastToProperFunctionPointerType*)
371 &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,
372 getProcAddress);
373 }
就是egl_connection_t的hooks成员中。
那么egl_connection_t又在哪里存储呢?libEGL 模块的egl_context_t里。当我们eglcreateContext后,我们会把创建的eglcontext中的egl_connection_t的hooks存储在线程相关的tls中,当调用的gl函数的时候,就从当前线程的tls里取出hooks来,然后再调用相关gl函数。它的存储过程是在eglMakeCurrent函数中:
581EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
582 EGLSurface read, EGLContext ctx)
583{
……
613 // these are our objects structs passed in
614 egl_context_t * c = NULL;
……
621 if (ctx != EGL_NO_CONTEXT) {
622 c = get_context(ctx);
623 impl_ctx = c->context;
624 } else {
……
650 EGLBoolean result = dp->makeCurrent(c, cur_c,
651 draw, read, ctx,
652 impl_draw, impl_read, impl_ctx);
653
654 if (result == EGL_TRUE) {
655 if (c) {
656 setGLHooksThreadSpecific(c->cnx->hooks[c->version]);//!
……
}
libGLESv1_CM.so和libGLESv2.so他们其实是对gl接口的第一层实现,他们转发调用了当前线程里的hooks里相关的实现。
看一下gl2接口的调用逻辑,:
// /frameworks/native/opengl/libs/GLES2/gl2.cpp
109 #define API_ENTRY(_api) _api
110
111 #define CALL_GL_API(_api, ...) \
112 gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \ //!
113 _c->_api(__VA_ARGS__);
114
115 #define CALL_GL_API_RETURN(_api, ...) \
116 gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
117 return _c->_api(__VA_ARGS__)
……
122extern "C" {
123#include "gl3_api.in"
124#include "gl2ext_api.in"
125#include "gl3ext_api.in"
126}
// /frameworks/native/opengl/libs/GLES2/gl3_api.in :
1void API_ENTRY(glActiveTexture)(GLenum texture) {
2 CALL_GL_API(glActiveTexture, texture);
3}
4void API_ENTRY(glAttachShader)(GLuint program, GLuint shader) {
5 CALL_GL_API(glAttachShader, program, shader);
6}
7void API_ENTRY(glBindAttribLocation)(GLuint program, GLuint index, const GLchar* name) {
8 CALL_GL_API(glBindAttribLocation, program, index, name);
9}
…….
// 最后看一下关于hooks的本地线程存储:
368void setGlThreadSpecific(gl_hooks_t const *value) {
369 pthread_setspecific(gGLWrapperKey, value);
370}
371
372gl_hooks_t const* getGlThreadSpecific() {
373 gl_hooks_t const* hooks = static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
374 if (hooks) return hooks;
375 return &gHooksNoContext;
376}
总结,无论是SF模块,还是Bootanimation模块,他们在使用gl接口的时候,先去找libGLESv1_CM.so和libGLESv2.so的第一层实现,然后再转发软件或硬件实现。
软件实现模块
这俩标准的agl软件实现在/frameworks/native/opengl/libagl/下,观其部分mk文件:
9LOCAL_SRC_FILES:= \
10 egl.cpp \ //egl的实现,其余是gl的实现
11 state.cpp \
12 texture.cpp \
13 Tokenizer.cpp \
14 TokenManager.cpp \
15 TextureObjectManager.cpp \
16 BufferObjectManager.cpp \
17 array.cpp.arm \
18 fp.cpp.arm \
19 light.cpp.arm \
20 matrix.cpp.arm \
21 mipmap.cpp.arm \
22 primitives.cpp.arm \
23 vertex.cpp.arm
……
29LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils liblog libpixelflinger libETC1 libui
30LOCAL_LDLIBS := -lpthread -ldl
31
32ifeq ($(TARGET_ARCH),arm)
33 LOCAL_SRC_FILES += fixed_asm.S iterators.S
34 LOCAL_CFLAGS += -fstrict-aliasing
35endif
……
44# we need to access the private Bionic header <bionic_tls.h>
45LOCAL_C_INCLUDES += bionic/libc/private
……
48LOCAL_MODULE:= libGLES_android
49
50include $(BUILD_SHARED_LIBRARY)
硬件实现模块
硬件的实现包括在/frameworks/native/opengl/libs/Android.mk文件里:
Egl实现:例如高通的\libEGL_adreno.so
Gl实现:system\vendor\lib\egl\libGLESv1_CM_adreno.so,system\vendor\lib\egl\libGLESv2_adreno.so
图示:
转载请注明。