目錄
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
圖示:
轉載請注明。