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

提交評論