OpenGL ES与EGL的关系(二十一)

从上面的例子中,我们发现通过egl_函数调用后,直接就能调用gl_函数去画图了,为何?难道在egl*函数调用过程中,已经将opengl相关实现的库加载了吗?

涉及的库


首先,由于涉及的库较多,先列出来(高通平台,原生的只有前4个),

//算是android中的egl库,用来加载具体的实现

system\lib\libEGL.so

//opengl具体实现的wrapper

system\lib\libGLESv1_CM.so

system\lib\libGLESv2.so

//opengl软件实现,即agl

system\lib\egl\libGLES_android.so

//egl的实现

system\vendor\lib\egl\libEGL_adreno.so

//opengl硬件实现

system\vendor\lib\egl\libGLESv1_CM_adreno.so

system\vendor\lib\egl\libGLESv2_adreno.so

库的加载


继续以bootanimation为例,在bootanimation的makefile中,使用了libEGL 库,

// frameworks\base\cmds\bootanimation\Android.mk

LOCAL_SHARED_LIBRARIES := \

libcutils \

liblog \

libandroidfw \

libutils \

libbinder \

libui \

libskia \

libEGL \

libGLESv1_CM \

libgui

LOCAL_MODULE:= bootanimation

frameworks\native\opengl\libs\Android.mk中,定义了libEGL.so,makefile中并未指定特殊的存放path,所以最终生成的库保存在system\lib\libEGL.so这个库是用来加载具体的egl和opengl实现的,起到桥梁作用,需要和EGL实现的库区分开。

//frameworks\native\opengl\libs\Android.mk

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \

EGL/egl_tls.cpp \

EGL/egl_cache.cpp \

EGL/egl_display.cpp \

EGL/egl_object.cpp \

EGL/egl.cpp \

EGL/eglApi.cpp \

EGL/trace.cpp \

EGL/getProcAddress.cpp.arm \

EGL/Loader.cpp \

LOCAL_MODULE:= libEGL

include $(BUILD_SHARED_LIBRARY)

接下来看eglGetDisplay(),这个函数就是在system\lib\libEGL.so中实现的。

EGLDisplay eglGetDisplay(EGLNativeDisplayType display)

{

clearError();

uint32_t index = uint32_t(display);

if (index >= NUM_DISPLAYS) {

return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);

}

//从函数名上看是加载相关实现

if (egl_init_drivers() == EGL_FALSE) {

return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);

}

EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);

return dpy;

}

EGLBoolean egl_init_drivers() {

EGLBoolean res;

pthread_mutex_lock(&sInitDriverMutex);

res = egl_init_drivers_locked();

pthread_mutex_unlock(&sInitDriverMutex);

return res;

}

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) {

//gHooks保存的是gl开头的函数实现

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_connection_t gEGLImpl;

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 实现

egl_t egl;

void* libGles1;

void* libGles2;

};

// 还能这么用,以前真是没用过

// 将EGL/egl_entries.in文件include进来,都是些egl entry

struct egl_t {

#include “EGL/egl_entries.in”

};

//将entries.in文件include进来

struct gl_hooks_t {

struct gl_t {

#include “entries.in”

} gl;

struct gl_ext_t {

__eglMustCastToProperFunctionPointerType extensions[MAX_NUMBER_OF_GL_EXTENSIONS];

} ext;

};

EGL/http://egl_entries.in文件中都是如下的一条一条entry,以egl开头,都是函数声明,

EGL_ENTRY(EGLDisplay, eglGetDisplay, NativeDisplayType)

http://entries.in文件中,都是以gl开头的entry,都是函数声明,

GL_ENTRY(void, glActiveShaderProgramEXT, GLuint pipeline, GLuint program)

从下面的宏可以看出,转换完成后,上面的entry都是返回值,函数名,函数参数的型式。

#undef GL_ENTRY

#undef EGL_ENTRY

#define GL_ENTRY(_r, _api, …) _r (*_api)(VA_ARGS);

#define EGL_ENTRY(_r, _api, …) _r (*_api)(VA_ARGS);

所以,

struct egl_t {

EGLDisplay eglGetDisplay(NativeDisplayType );

};

struct gl_t {

void glActiveShaderProgramEXT(GLuint pipeline, GLuint program);

} gl;

下面看cnx->dso = loader.open(cnx),

void* Loader::open(egl_connection_t* cnx)

{

void* dso;

driver_t* hnd = 0;

//首先,kind为GLES,mask为EGL,GLESv1_CM ,GLESv2

//在/vendor/lib/egl和/system/lib/egl下寻找libGLES.so或者libGLES_*.so

//这里只能找到system\lib\egl\libGLES_android.so,opengl的软件实现

//但是代码中直接continue了,不使用软件实现

//所以dso返回空

dso = load_driver(“GLES”, cnx, EGL | GLESv1_CM | GLESv2);

if (dso) {

hnd = new driver_t(dso);

} else {

// Always load EGL first

// kind为EGL,mask为EGL

// 可以找到system\vendor\lib\egl\libEGL_adreno.so

// 然后填充egl相关函数

dso = load_driver(“EGL”, cnx, EGL);

if (dso) {

hnd = new driver_t(dso);

//找到system\vendor\lib\egl\libGLESv1_CM_adreno.so库,

//填充gl相关函数

hnd->set( load_driver(“GLESv1_CM”, cnx, GLESv1_CM), GLESv1_CM );

//找到system\vendor\lib\egl\libGLESv2_adreno.so库,

//填充gl相关函数

hnd->set( load_driver(“GLESv2”, cnx, GLESv2), GLESv2 );

}

}

LOG_ALWAYS_FATAL_IF(!hnd, “couldn’t find an OpenGL ES implementation”);

//上面是opengle的实现,下面的cnx->libGles2和libGles1是gles实现的wrapper

// 只是打开/system/lib/libGLESv2.so和/system/lib/libGLESv1_CM.so这两个库,将地址返回给cnx

cnx->libGles2 = load_wrapper(“/system/lib/libGLESv2.so”);

cnx->libGles1 = load_wrapper(“/system/lib/libGLESv1_CM.so”);

LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,

“couldn’t load system OpenGL ES wrapper libraries”);

return (void*)hnd;

}

void Loader::load_driver(const char kind,

egl_connection_t* cnx, uint32_t mask)

{

class MatchFile {

public:

static String8 find(const char* kind) {

String8 result;

String8 pattern;

pattern.appendFormat(“lib%s”, kind);

//在下面路径中寻找

const char* const searchPaths[] = {

“/vendor/lib/egl”,

“/system/lib/egl”

};

// first, we search for the exact name of the GLES userspace

// driver in both locations.

// i.e.:

// libGLES.so, or:

// libEGL.so, libGLESv1_CM.so, libGLESv2.so

for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {

if (find(result, pattern, searchPaths[i], true)) {

return result;

}

}

// for compatibility with the old “egl.cfg” naming convention

// we look for files that match:

// libGLES_*.so, or:

// libEGL_.so, libGLESv1_CM_.so, libGLESv2_*.so

pattern.append(“_”);

for (size_t i=0 ; i<NELEM(searchPaths) ; i++) {

if (find(result, pattern, searchPaths[i], false)) {

return result;

}

}

// we didn’t find the driver. gah.

result.clear();

return result;

}

private:

static bool find(String8& result,

const String8& pattern, const char* const search, bool exact) {

// in the emulator case, we just return the hardcoded name

// of the software renderer.

if (checkGlesEmulationStatus() == 0) {

ALOGD("Emulator without GPU support detected. "

“Fallback to software renderer.”);

result.setTo(“/system/lib/egl/libGLES_android.so”);

return true;

}

if (exact) {

String8 absolutePath;

absolutePath.appendFormat(“%s/%s.so”, search, pattern.string());

if (!access(absolutePath.string(), R_OK)) {

result = absolutePath;

return true;

}

return false;

}

DIR* d = opendir(search);

if (d != NULL) {

struct dirent cur;

struct dirent* e;

while (readdir_r(d, &cur, &e) == 0 && e) {

if (e->d_type == DT_DIR) {

continue;

}

//system\lib\egl\libGLES_android.so直接跳过软件实现

//太慢,但是在某个项目中没有gpu,也没有overlay,

//只能用agl去合成layer。

if (!strcmp(e->d_name, “libGLES_android.so”)) {

// always skip the software renderer

continue;

}

if (strstr(e->d_name, pattern.string()) == e->d_name) {

if (!strcmp(e->d_name + strlen(e->d_name) - 3, “.so”)) {

result.clear();

result.appendFormat(“%s/%s”, search, e->d_name);

closedir(d);

return true;

}

}

}

closedir(d);

}

return false;

}

};

String8 absolutePath = MatchFile::find(kind);

if (absolutePath.isEmpty()) {

// this happens often, we don’t want to log an error

return 0;

}

const char* const driver_absolute_path = absolutePath.string();

//打开找到的库

void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);

if (dso == 0) {

const char* err = dlerror();

ALOGE(“load_driver(%s): %s”, driver_absolute_path, err?err:“unknown”);

return 0;

}

ALOGD(“loaded %s”, driver_absolute_path);

//mask为EGL

if (mask & EGL) {

//首先在库中找到eglGetProcAddress这个函数

getProcAddress = (getProcAddressType)dlsym(dso, “eglGetProcAddress”);

ALOGE_IF(!getProcAddress,

“can’t find eglGetProcAddress() in %s”, driver_absolute_path);

egl_t* egl = &cnx->egl;

__eglMustCastToProperFunctionPointerType* curr =

(__eglMustCastToProperFunctionPointerType*)egl;

//egl_names就是egl的entry

char const * const * api = egl_names;

while (*api) {

char const * name = *api;

//寻找entry中的函数

__eglMustCastToProperFunctionPointerType f =

(__eglMustCastToProperFunctionPointerType)dlsym(dso, name);

//如果未找到,用eglGetProcAddress再去找一下

if (f == NULL) {

// couldn’t find the entry-point, use eglGetProcAddress()

f = getProcAddress(name);

//依然未找到,则置为0

if (f == NULL) {

f = (__eglMustCastToProperFunctionPointerType)0;

}

}

*curr++ = f;

api++;

}

}

if (mask & GLESv1_CM) {

init_api(dso, gl_names,

(__eglMustCastToProperFunctionPointerType*)

&cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl,

getProcAddress);

}

if (mask & GLESv2) {

init_api(dso, gl_names,

(__eglMustCastToProperFunctionPointerType*)

&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,

getProcAddress);

}

return dso;

}

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

七大模块学习资料:如NDK模块开发、Android框架体系架构…

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
mask & GLESv2) {

init_api(dso, gl_names,

(__eglMustCastToProperFunctionPointerType*)

&cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl,

getProcAddress);

}

return dso;

}

学习分享

在当下这个信息共享的时代,很多资源都可以在网络上找到,只取决于你愿不愿意找或是找的方法对不对了

很多朋友不是没有资料,大多都是有几十上百个G,但是杂乱无章,不知道怎么看从哪看起,甚至是看后就忘

如果大家觉得自己在网上找的资料非常杂乱、不成体系的话,我也分享一套给大家,比较系统,我平常自己也会经常研读。

2021最新上万页的大厂面试真题

[外链图片转存中…(img-rKrDRPu3-1715863022816)]

七大模块学习资料:如NDK模块开发、Android框架体系架构…

[外链图片转存中…(img-g8i0J3A3-1715863022818)]

只有系统,有方向的学习,才能在段时间内迅速提高自己的技术。

这份体系学习笔记,适应人群:
**第一,**学习知识比较碎片化,没有合理的学习路线与进阶方向。
**第二,**开发几年,不知道如何进阶更进一步,比较迷茫。
**第三,**到了合适的年纪,后续不知道该如何发展,转型管理,还是加强技术研究。

由于文章内容比较多,篇幅不允许,部分未展示内容以截图方式展示 。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值