乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Android SurfaceFlinger之OpenGL庫加載過程

       開花結(jié)果 2022-05-25 發(fā)布于北京
      • http://blog.csdn.net/ieearth/article/details/55518607

        1、egl_init_drivers

        Android中OpenGL庫加載從egl_init_drivers函數(shù)開始,源碼位置在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進(jìn)行同步保護(hù),下面分析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實(shí)現(xiàn)中可以看出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的返回值,成功時(shí)返回0。pthread_once保證多線程時(shí)early_egl_init只執(zhí)行一次,early_egl_init用來設(shè)置線程特有的數(shù)據(jù)(pthread_setspecific/pthread_getspecific),這也是一種數(shù)據(jù)共享方式。EGLFuncPointer為函數(shù)指針,如下所示:

        typedef void (*__eglMustCastToProperFunctionPointerType)(void);
        typedef __eglMustCastToProperFunctionPointerType EGLFuncPointer;
        
            1
            2

        gHooksNoContext是個(gè)有趣的數(shù)據(jù)結(jié)構(gòu),如下所示:

        // 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 256
        
        struct 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結(jié)構(gòu)體實(shí)際上包含了同OpenGL函數(shù)一致的函數(shù)指針,通過“entries.in”和GL_ENTRY進(jìn)行擴(kuò)展,如下所示:

        #define GL_ENTRY(_r, _api, ...) _r (*(_api))(__VA_ARGS__);
        
        // entries.in
        GL_ENTRY(void, glActiveShaderProgram, GLuint pipeline, GLuint program)
        GL_ENTRY(void, glActiveShaderProgramEXT, GLuint pipeline, GLuint program)
        ...
        ...

        gl_no_context用于檢查OpenGL函數(shù)調(diào)用是否設(shè)置了Context,其中用到了設(shè)置線程鍵的egl_tls_t類和收集函數(shù)調(diào)用棧幀的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設(shè)置線程鍵,而__get_tls則是通過匯編實(shí)現(xiàn)的(不同的硬件有不同的匯編代碼),如下所示:

        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,其結(jié)構(gòu)如下所示:

        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結(jié)構(gòu)體及前面的egl_init_drivers_locked函數(shù)定義可以看出,包括兩個(gè)hook,GLESv1和GLESv2,而dso則實(shí)際上指向了libEGL、libGLESv1和libGLESv2(從后面的Loader分析中可以看出),egl_t類似于gl_t,包含了一系列egl函數(shù)指針。下面著重分析Loader。

        5、Loader-open

        Loader是個(gè)單實(shí)例,如下所示:

        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,這是個(gè)Loader類的內(nèi)部結(jié)構(gòu)體,如下所示:

        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三個(gè)庫。open函數(shù)中還調(diào)用了setEmulatorGlesValue,這個(gè)函數(shù)就是檢查、設(shè)置一些模擬器屬性(是否在模擬器中運(yùn)行?在模擬中運(yùn)行時(shí)是否有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驅(qū)動需要提供一個(gè)單一的庫libGLES.so,或者是三個(gè)分開的庫libEGL.so、libGLESv1_CM.so和libGLESv2.so,模擬器中的軟描畫則需要提供單一的庫libGLES_android.so,為了兼容舊版本的“egl.cfg”文件配置,這幾個(gè)庫后面還可能加一個(gè)名稱如_emulation。在load_driver函數(shù)中還有個(gè)內(nèi)部類MatchFile,用于在某個(gè)lib目錄中查找特定的OpenGL庫是否存在,存在的話進(jìn)而通過dlopen打開,dlopen成功后再通過dlsym逐個(gè)獲取OpenGL所有API的地址并將它們保存下來。

        7、load_wrapper

        load_wrapper相對load_driver來說較簡單,就是dlopen一個(gè)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;
        }

        本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多