glEnable(GL_TEXTURE_2D);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const GLint xc = (mWidth - mAndroid[0].w) / 2;
const GLint yc = (mHeight - mAndroid[0].h) / 2;
const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
// Blend state
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
const nsecs_t startTime = systemTime();
do {
nsecs_t now = systemTime();
double time = now - startTime;
float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
GLint x = xc - offset;
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);
glEnable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);
EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
if (res == EGL_FALSE)
break;
// 12fps: don’t animate too fast to preserve CPU
const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
if (sleepTime > 0)
usleep(sleepTime);
checkExit();
} while (!exitPending());
glDeleteTextures(1, &mAndroid[0].name);
glDeleteTextures(1, &mAndroid[1].name);
return false;
}
EGL加载OpenGL ES库
从上面的例子中,我们发现通过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;
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
总结
Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!
上面分享的字节跳动公司2020年的面试真题解析大全,笔者还把一线互联网企业主流面试技术要点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
就先写到这,码字不易,写的很片面不好之处敬请指出,如果觉得有参考价值的朋友也可以关注一下我
①「Android面试真题解析大全」PDF完整高清版+②「Android面试知识体系」学习思维导图压缩包阅读下载,最后觉得有帮助、有需要的朋友可以点个赞
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-aYq3Pb8s-1711693968677)]
总结
Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!
上面分享的字节跳动公司2020年的面试真题解析大全,笔者还把一线互联网企业主流面试技术要点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。
就先写到这,码字不易,写的很片面不好之处敬请指出,如果觉得有参考价值的朋友也可以关注一下我
①「Android面试真题解析大全」PDF完整高清版+②「Android面试知识体系」学习思维导图压缩包阅读下载,最后觉得有帮助、有需要的朋友可以点个赞
[外链图片转存中…(img-Fw4iD0eG-1711693968677)]
[外链图片转存中…(img-iQSnZsgd-1711693968678)]
[外链图片转存中…(img-wOXS8p6P-1711693968678)]文章来源:https://www.toymoban.com/news/detail-847160.html
本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录文章来源地址https://www.toymoban.com/news/detail-847160.html
到了这里,关于OpenGL ES与EGL的关系(二十一),完美讲解内存缓存LruCache实现原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!