AndroidOpenGLES分析与实践_第1页
AndroidOpenGLES分析与实践_第2页
AndroidOpenGLES分析与实践_第3页
AndroidOpenGLES分析与实践_第4页
AndroidOpenGLES分析与实践_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、AndroidOpenGLESih析与实践作者:雪夜刀手1. OpenGLES简介Android3D引擎采用的是OpenGLESOpenGLES是一套为手持和嵌入式系统设计的3D引擎API,由Khronos公司维护。在PC领域,一直有两种标准的3DAPI进行竞争,OpenGL和DirectX。一般主流的游戏和显卡都支持这两种渲染方式,DirectX在Windows平台上有很大的优势,但是OpenGL具有更好的跨平台性。由于嵌入式系统和PC相比,一般说来,CPU内存等都比PC差很多,而且对能耗有着特殊的要求,许多嵌入式设备并没有浮点运算协处理器,针对嵌入式系统的以上特点,Khronos对标准的O

2、penGL系统进行了维护和改动,以期望满足嵌入式设备对3D绘图的要求。2. AndroidOpenGLES简介Android系统使用OpenGL的标准接口来支持java框架和本地代码两部分。本地代码主要实现的3D图形功能,android3D图形系统也分为OpenGL接口的库,在Java框架层,javax.microedition.khronos.opengles是java标准的OpenGL包,android.opengl包提供了OpenGL系统和AndroidGUI系统之间的联系。Android的本地代码位于frameworks/base/opengl下,JNI代码位于frameworks/b

3、ase/core/com_google_android_gles_jni_GLImpl.cpp和frameworks/base/core/com_google_android_gles_jni_EGLImpl.cpp,java类位于opengl/java/javax/microedition/khronos下3. OpenGL的本地代码分析3.1 OpenGLESM试代码frameworks/base/opengl/tests下有OpenGL的本地测试代码。包括angeles、fillrate等14个测试代码,这些代码都可以通过终端进行本地调用测试(模拟器中使用adbshell)。在本文中,主

4、要使用了tritex这个测试用例。在tests文件夹中执行mm,打印出以下信息Install:out/target/product/generic/system/bin/angelesInstall:out/target/product/generic/system/bin/test-opengl-tritex由以上信息可知,测试用例被安装在了out/target/product/generic/system/bin/目录下,将之拷贝到nfs文件系统中,以便测试。我把这些测试用例都单独放在android的根文件系统的gltest文件夹中了。3.2OpenGLES勺编译编译libagl下的源码生

5、成Install:out/target/product/generic/system/lib/egl/libGLES_android.so编译libs下的生成了Install:out/target/product/generic/system/lib/libGLESv2.soInstall:out/target/product/generic/system/lib/libGLESv1_CM.soInstall:out/target/product/generic/system/lib/libEGL.so3.3 使用OpenGLESI图必经的步骤1、获取Display,Display代表显示器。

6、函数原型:EGLDisplayeglGetDisplay(NativeDisplayTypedisplay);display参数是native系统的窗口显示ID值,一般为EGL_DEFAULT_DISPLAY亥参数实际的意义是平台实现相关的,在X-Window下是XDisplayID,在MSWindows是WindowDC2、初始化egl库。函数原型:EGLBooleaneglInitialize(EGLDisplaydpy,EGLint*major,EGLint*minor);其中dpy应该是一个有效的EGLDisplay。函数返回时,major和minor将被赋予当前EGL版本号。3、选择

7、一个合适的EGLConfigurationFrameBuffer,实际指的是FrameBuffer的参数函数原型:EGLBooleaneglChooseConfig(EGLDisplaydpy,constEGLint*attrib_list,EGLConfig*configs,EGLintconfig_size,EGLint*num_config);参数attrib_list:指定了选择配置时需要参照的属性。参数configs:将返回一个按照attrib_list排序的平台有效的所有EGLframebuffer酉己置歹!J表。参数config_size:指定了可以返回到configs的总配置个

8、数参数num_config:返回了实际匹配的配置总数。4、创建一个可实际显示的EGLSurface,实际上就是一个FrameBuffer函数原型:EGLSurfaceeglCreateWindowSurface(EGLDisplaydpy,EGLConfigconfig,NativeWindowTypewin,constEGLint*attrib_list);5、创建Context函数原型:EGLContexteglCreateContext(EGLDisplaydpy,EGLConfigconfig,EGLContextshare_context,constEGLint*attrib_lis

9、t);6、绑定Display、Surface、Context函数原型:EGLBooleaneglMakeCurrent(EGLDisplaydpy,EGLSurfacedraw,EGLSurfaceread,EGLContextctx);3.4 OpenGLES执行过程运行android操作系统之后,输入logcat命令,然后执行gltest中的test-opengl-tritex,屏幕上打印了以下信息D/libEGL(1962):egl.cfgnotfound,usingdefaultconfigD/libEGL(1962):loaded/system/lib/egl/libGLES_and

10、roid.so可以看出,在执行OpenGL调用的过程中,会自动加载libGLES_android.so动态链接库。后面将会通过分析和修改源码的方式,了解OpenGLES系统的调用过程。通过3.3中的说明,我们在tritex测试程序中插入一些调试信息,查看OpenGLES的调用过程。在调用eglGetDisplay之前会执行early_egl_init函数,这是一个静态的函数。在eglGetDisplay中会去初始化驱动,最终调用到egl_init_drivers_locked函数中。这个函数的主要内容如下EGLBooleanegl_init_drivers_locked()if(sEarlyl

11、nitState)/initializedbystaticctor.shouldbesethere.returnEGL_FALSE;/getourdriverloaderLoader&loader(Loader:getlnstance();/dynamicallyloadallourEGLimplementationsforalldisplays/andretrievethecorrespondingEGLDisplay/ifthatfails,don'tusethisdriver./TODO:currentlyweonlydealwithEGL_DEFAULT_DISPLAY

12、egl_connection_t*cnx;egl_display_t*d=&gDisplay0;cnx=&gEGLImplIMPL_SOFTWARE;if(cnx->dso=0)cnx->hooksGLESv1_INDEX=&gHooksGLESv1_INDEXIMPL_SOFTWARE;cnx->hooksGLESv2_INDEX=&gHooksGLESv2_INDEXIMPL_SOFTWARE;cnx->dso=loader.open(EGL_DEFAULT_DISPL,A0Y,cnx);if(cnx->dso)EGLDispl

13、aydpy=cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);LOGE_IF(dpy=EGL_NO_DISPLA"NoEGLDisplayforsoftwareEGL!");d->dispIMPL_SOFTWARE.dpy=dpy;if(dpy=EGL_NO_DISPLAY)loader.close(cnx->dso);cnx->dso=NULL;cnx=&gEGLImplIMPL_HARDWARE;if(cnx->dso=0)charvaluePROPERTY_VALUE_MAX;property

14、_get("debug.egl.hw",value,"1");if(atoi(value)!=0)cnx->hooksGLESv1_INDEX=&gHooksGLESv1_INDEXIMPL_HARDWARE;cnx->hooksGLESv2_INDEX=&gHooksGLESv2_INDEXIMPL_HARDWARE;cnx->dso=loader.open(EGL_DEFAULT_DISPL,A1Y,cnx);if(cnx->dso)EGLDisplaydpy=cnx->egl.eglGetDisplay

15、(EGL_DEFAULT_DISPLAY);LOGE_IF(dpy=EGL_NO_DISPLAY'NoEGLDisplayforhardwareEGL!");d->dispIMPL_HARDWARE.dpy=dpy;if(dpy=EGL_NO_DISPLAY)loader.close(cnx->dso);cnx->dso=NULL;elseLOGD("3Dhardwareaccelerationisdisabled");if(!gEGLImplIMPL_SOFTWARE.dso&&!gEGLImplIMPL_HARDWAR

16、E.dso)returnEGL_FALSE;returnEGL_TRUE;由此代码可以看出,egl_init_drivers_locked函数主要的工作就是填充gEGLImp数组变量,这个变量是egl_connection_t类型。还有一个工作就是填充gDisplay数组(只有一个元素)的dispIMPL_HARDWARE.dpy以及dispIMPLSOFTWAREWARE.dpy填充的来源来自gEGLImplsoftorhard.egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);在Loader.cpp中的Loader:open中会加载对应的硬件和软件加速的驱动(动

17、态链接库)。软件的对应的是/system/lib/egl/libEGL_android.so,没有默认的硬件so,因此在硬件加速时,返回值hnd会指向NULL,在需要硬件加速时这个动态链接库需要进行实现。LoadDriver函数会根据其第三个参数,决定加载egl/gles,glesv1_cm,glesv2驱动。加载几个动态链接库的过程如下图返回此结构返回退出由我以上图表可以看出,加载驱动的时候,会尝试先从libGLES_android.so中加载EGL、GLESV1_CMGLESV2三个部分的函数,如果加载失败,则会尝试从libEGL_android.so,libGLESV1_cm.solib

18、GLESV2.so三个动态库中对应的函数。在这部分代码中,我们可以看到一个非常重要的结构体,egl_connection_t,structegl_connection_tvoid*dso;gl_hooks_t*hooks2;EGLintmajor;EGLintminor;egl_tegl;到处都有他的身影,对这几个变量进行一下解释。structsoinfo(constcharnameSOINFO_NAME_LEN;Elf32_Phdr*phdr;intphnum;unsignedentry;unsignedbase;unsignedsize;/buddy-allocatorindex,nega

19、tiveforprelinkedlibrariesintba_index;unsigned*dynamic;unsignedwrprotect_start;unsignedwrprotect_end;soinfo*next;unsignedflags;constchar*strtab;Elf32_Sym*symtab;unsignednbucket;unsignednchain;unsigned*bucket;unsigned*chain;unsigned*plt_got;Elf32_Rel*plt_rel;unsignedplt_rel_count;Elf32_Rel*rel;unsigne

20、drel_count;unsigned*preinit_array;unsignedpreinit_array_count;unsigned*init_array;unsignedinit_array_count;unsigned*fini_array;unsignedfini_array_count;void(*init_func)(void);void(*fini_func)(void);#ifdefANDROIDARMLINKER/*ARMEABIsectionusedforstackunwinding.*/unsigned*ARM_exidx;unsignedARM_exidx_cou

21、nt;#endifunsignedrefcount;structlink_maplinkmap;看一下load_driver中到底做了什么手脚。1 .首先调用dlopen打开动态链接库,返回值是void*,这个void*指向的是什么内容呢?追踪到bionic/linker/Dlfcn.c中。其中调用了find_library函数,这个函数是一个奇怪的函数,因为它虽然叫做find_library,在其实现中,不但在系统的so链表中去查找指定的文件名的动态链接库信息,而且对其动态链接库进行加载并返回。至此我们明白了,这个void*指向的是一个soinfo类型的结构体这是mandlopen的说明。一

22、个标准的linux函数。Thefunctiondlopen()loadsthedynamiclibraryfilenamedbythenull-terminatedstringfilenameandreturnsanopaque"handle"forthedynamiclibrary.IffilenameisNULL,thenthereturnedhandleisforthemainprogram.Iffilenamecontainsaslash("/"),thenitisinterpretedasa(relativeorabsolute)pathnam

23、e.2 .由上一步的分析,我们知道了egl_connection_t的第一个变量dso,是指向的一个soinfo结构体(discover/decompresssharedobject的缩写?)Printf("HAHALetmeprintthesoinfomationn");Printf("name=%s:phdr=%x:entry=%x:base=%x:size=%xn",soi->name,soi->phdr,soi->entry,soi->base,soi->size);这是上一条语句打印的一些信息。name=libGL

24、ES_android.so:phdr=acc80034:entry=0:base=acc80000:size=1c0003dsym可以卞!据dlopen的返回值,查找第二个参数指定的函数名的地址并返回Thefunctiondlsym()takesa"handle"ofadynamiclibraryreturnedbydlopen()andthenull-terminatedsymbolname,returningtheaddresswherethatsymbolisloadedintomemory.Ifthesymbolisnotfound,inthespecifiedli

25、braryoranyofthelibrariesthatwereautomati-callyloadedbydlopen()whenthatlibrarywasloaded,dlsym()returnsNULL.(Thesearchperformedbydlsym()isbreadthfirstthroughthedependencytreeoftheselibraries.)SincethevalueofthesymbolcouldactuallybeNULL(sothataNULLreturnfromdlsym()neednotindicateanerror),thecorrectwayt

26、otestforanerroristocalldlerror()toclearanyolderrorconditions,thencalldlsym(),andthencalldlerror()again,savingitsreturnvalueintoavariable,andcheckwhetherthissavedvalueisnotNULL.getProcAddress=(getProcAddressType)dlsym(dso,"eglGetProcAddress");Printf("eglGetProcAddress'slocationis%x

27、n",getProcAddress);打印信息如下,可以和刚才的打印信息比较一下。我们确实找到了一个函数。eglGetProcAddress'slocationisacc930b1Printf("curr=%x,it'saddressis%xn",curr,f);打印如下eglGetProcAddress'slocationisacc930b1*api=eglGetDisplaycurr=ac708a60,it'saddressisacc931a5*api=eglInitializecurr=ac708a64,it'sadd

28、ressisacc93c9d*api=eglTerminatecurr=ac708a68,it'saddressisacc93cdd*api=eglGetConfigscurr=ac708a6c,it'saddressisacc93d41*api=eglChooseConfigcurr=ac708a70,it'saddressisacc9472d*api=eglGetConfigAttribcurr=ac708a74,it'saddressisacc94325*api=eglCreateWindowSurfacecurr=ac708a78,it'sadd

29、ressisacc94689*api=eglCreatePixmapSurfacecurr=ac708a7c,it'saddressisacc945d5*api=eglCreatePbufferSurfacecurr=ac708a80,it'saddressisacc9451d*api=eglDestroySurfacecurr=ac708a84,it'saddressisacc93a1d*api=eglQuerySurfacecurr=ac708a88,it'saddressisacc94341*api=eglCreateContextcurr=ac708a8

30、c,it'saddressisacc9415d*api=eglDestroyContextcurr=ac708a90,it'saddressisacc93d09*api=eglMakeCurrentcurr=ac708a94,it'saddressisacc93a6d*api=eglGetCurrentContextcurr=ac708a98,it'saddressisacc93055*api=eglGetCurrentSurfacecurr=ac708a9c,it'saddressisacc941a1*api=eglGetCurrentDisplayc

31、urr=ac708aa0,it'saddressisacc93061*api=eglQueryContextcurr=ac708aa4,it'saddressisacc942ed*api=eglWaitGLcurr=ac708aa8,it'saddressisacc9307d*api=eglWaitNativecurr=ac708aac,it'saddressisacc93081*api=eglSwapBufferscurr=ac708ab0,it'saddressisacc93bf5*api=eglCopyBufferscurr=ac708ab4,it

32、'saddressisacc93d71*api=eglGetErrorcurr=ac708ab8,it'saddressisacc93125*api=eglQueryStringcurr=ac708abc,it'saddressisacc9373d*api=eglGetProcAddresscurr=ac708ac0,it'saddressisacc930b1*api=eglSurfaceAttribcurr=ac708ac4,it'saddressisacc93d89*api=eglBindTexImagecurr=ac708ac8,it'sa

33、ddressisacc93da5*api=eglReleaseTexImagecurr=ac708acc,it'saddressisacc93dc1*api=eglSwapIntervalcurr=ac708ad0,it'saddressisacc93ddd*api=eglBindAPIcurr=ac708ad4,it'saddressisacc93df9*api=eglQueryAPIcurr=ac708ad8,it'saddressisacc93085*api=eglWaitClientcurr=ac708adc,it'saddressisacc93

34、0e5*api=eglReleaseThreadcurr=ac708ae0,it'saddressisacc9308d*api=eglCreatePbufferFromClientBuffercurr=ac708ae4,it'saddressisacc941e5*api=eglLockSurfaceKHRcurr=ac708ae8,it'saddressisacc93091*api=eglUnlockSurfaceKHRcurr=ac708aec,it'saddressisacc93095*api=eglCreateImageKHRcurr=ac708af0,i

35、t'saddressisacc94201*api=eglDestroyImageKHRcurr=ac708af4,it'saddressisacc93e15*api=eglSetSwapRectangleANDROIDcurr=ac708af8,it'saddressisacc93c51*api=eglGetRenderBufferANDROIDcurr=ac708afc,it'saddressisacc94125egl_connection_t的第二个变量是一个指针数组,类型是gl_hooks_t,从名字可以看出,它指向的是一组函数指针。跟踪一下structg

36、l_hooks_tstructgl_t#include"entries.in"gl;structgl_ext_tvoid(*extensionsMAX_NUMBER_OF_GL_EXTENSIONS)(void);ext;这个entries.ini文件里全部是函数的一些原型。证明了猜想。cnx->hooksGLESv1_INDEX=&gHooksGLESv1_INDEXIMPL_SOFTWARE;cnx->hooksGLESv2_INDEX=&gHooksGLESv2_INDEXIMPL_SOFTWARE;这里将egl_connecttion_t

37、变量指向了全局的gHooks,这些函数指针从哪里赋值的呢?跟踪发现,是在LoadDriver时,也是从libGLES_android.so中查找出GLESV1_CM和GLESV2两组函数来对其进行了赋值操作。major和minor是版本号。最后一个变量egl_tegL这个变量非常重要。在load_driver中可以看到它的身影(通过loader:open间接调用的)。structegl_t#include"EGL/egl_entries.in"egl_t中也是一组函数指针,其中包含了OpenGLES中底层的实现。所以如果要实现硬件加速的话,这里面的函数都要实现。egl_t*

38、egl=&cnx->egl;curr_eglMustCastToProperFunctionPointerType(_eglMustCastToProperFunctionPointerType*)egl;charconst*const*api=egl_names;while(*api)(charconst*name=*api;_eglMustCastToProperFunctionPointerTypef=(_eglMustCastToProperFunctionPointerType)dlsym(dso,nam9;if(f=NULL(/couldn'tfindtheentry-point,useeglGetProcA

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论