Android 的OpenGL ES与EGL

原文地址:http://hi.baidu.com/aokikyon/item/70e973d043bad21c21e2500d

Android 的OpenGL ES与EGL

Android OpenGL ES与EGL

1 名词解释
OpenGL ES
(OpenGL for Embedded Systems,以下简称OpenGL)
OpenGL 三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。该API由Khronos集团定义推广,Khronos是一个图形软硬件行业协会,该协会主要关注图形和多媒体方面的开放标准。
EGL
EGL™ 是介于诸如OpenGL 或OpenVG的Khronos渲染API与底层本地平台窗口系统的接口。它被用于处理图形管理、表面/缓冲捆绑、渲染同步及支援使用其他Khronos API进行的高效、加速、混合模式2D和3D渲染。
http://www.khronos.cn/index.shtml

2 Android中的OpenGL 与EGL
Android 2.0版本之后图形系统的底层渲染均由OpenGL负责,OpenGL除了负责处理3D API调用,还需负责管理显示内存及处理Android SurfaceFlinger或上层应用对其发出的2D API调用请求。
本地代码:
framework/base/opengl/libs/egl
Android EGL框架,负责加载OpenGL函数库和EGL本地实现。
framework/base/opengl/libagl  
Android提供的OpenGL软件库
JNI代码:
framework/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp
EGL本地代码的JNI调用接口
framework/base/core/jni/com_google_android_gles_jni_GLImpl.cpp
framework/base/core/jni/android_opengl_GLESXXX.cpp
OpenGL功能函数的JNI调用接口
Java代码:
framework/base/opengl/java/javax/microedition/khronos/egl
framework/base/opengl/java/javax/microedition/khronos/opengles
framework/base/opengl/java/com/google/android/gles_jni/
framework/base/opengl/android/opengl
EGL和OpenGL的Java层接口,提供给应用开发者,通过JNI方式调用底层函数。

3 Android EGL实现
3.1 EGL的主要功能
EGL是用来管理绘图表面(Drawing surfaces),并且提供了如下的机制
1) 与本地窗口系统进行通信
2) 查找绘图表面可用的类型和配置信息
3) 创建绘图表面
4) 同步OpenGL ES 2.0和其他的渲染API(Open VG、本地窗口系统的绘图命令等)
5) 管理渲染资源,比如材质

3.2 EGL数据结构
egl_object_t结构用来描述没一个elg对象。
egl_display_t结构用来存储get_display函数获取的物理显示设备。
egl_surface_t结构用来存储surface对象,系统可以同时拥有多个surface对象。
egl_context_t结构用用来存储OpenGL状态机信息。
egl_image_t结构用来存储EGLImage对象。
以下结构体在libagl中实现
egl_window_surface_v2_t继承egl_surface_t,提供egl_surface_t功能的具体实现,属于可实际显示的Surface。
egl_pixmap_surface_t存储保存在系统内存中的位图。
egl_pbuffer_surface_t存储保存在显存中的帧,以上两种位图属于不可显示的Surface。



3.3 EGL主要功能函数(省略了函数参数)
EGLDisplay eglGetDisplay()
eglGetDisplay调用egl_display_t::get_display(dpy)获取显示设备的句柄。
EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
初始化EGL,获取EGL版本号。
EGLBoolean eglTerminate()
结束一个EGLDisplay,并不结束EGL本身。
EGLBoolean eglGetConfigs()
获取EGL配置参数。
EGLBoolean eglChooseConfig()
选择EGL配置参数,配置一个期望并尽可能接近一个有效的系统配置。
EGLBoolean eglGetConfigAttrib()
获取EGL配置时需要参照的属性。
EGLSurface eglCreateWindowSurface()
创建一个EGL surface,surface是可以实际显示在屏幕上类型。
EGLSurface eglCreatePixmapSurface()
EGLSurface eglCreatePbufferSurface()
创建EGL PixmapSurface和PbufferSurface类型,这两种类型不可直接显示与屏幕上。
EGLBoolean eglDestroySurface()
销毁一个EGL surface对象
EGLBoolean eglQuerySurface()
查询surface的参数。
EGLContext eglCreateContext()
创建一个OpenGL状态机。
EGLBoolean eglDestroyContext()
销毁一个OpenGL状态机
EGLBoolean eglMakeCurrent()
将OpenGL context与surface绑定。
EGLBoolean eglQueryContext()
查询context的参数。
EGLBoolean eglSwapBuffers()
绘制完图形后用于显示的函数。
const char* eglQueryString()
查询EGL参数字串。
以上仅为EGL 1.0提供的基础功能,后续EGL版本陆续添加了更多的API。

3.4 EGL本地调用关系
framework/base/opengl/libs/egl编译生成libEGL.so。
   libEGL.so是Android系统的EGL框架,默认通过以下调用关系加载OpenGL库libGLES_android.so:
eglGetDisplay()->egl_init_drivers()->egl_init_drivers_locked()-> loader.open()->load_driver()。


4 Android OpenGL的实现
4.1 Android 提供的OpenGL库
framework/base/opengl/libagl 编译生成libGLES_android.so。
libGLES_android.so,这是一个由系统提供的纯软件3D加速库,可以兼容各种环境。libGLES_android.so中包含了一个EGL框架的实现和OpenGL各种API的实现。OpenGL的API底层是通过libpixelflinger.so库实现的。
针对不同的硬件设计,GPU厂商都会提供相应的硬件3D加速库,需要重写libGLES_android.so并实现相对应的libpixelflinger.so,工程量较大,一般由GPU厂商的软件开发团队来完成。

4.2 EGL加载OpenGL API的方法
libGLES_android.so提供了两种API,一种是egl实现API,另一种是OpenGL标准API。
4.2.1 加载EGL API
在函数load_driver中,通过dlsym从动态链接库中获取egl函数指针。其中egl_names包含egl_entries.in 文件,egl_entries.in 文件则是egl API的声明。

void *Loader::load_driver(const char* driver_absolute_path,
        egl_connection_t* cnx, uint32_t mask)
{
... ...
        char const * const * api = egl_names;
        while (*api) {
            char const * name = *api;
            __eglMustCastToProperFunctionPointerType f =
                (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
            if (f == NULL) {
                // couldn't find the entry-point, use eglGetProcAddress()
                f = getProcAddress(name);
                if (f == NULL) {
                    f = (__eglMustCastToProperFunctionPointerType)0;
                }
            }
            *curr++ = f;
            api++;
        }
... ...
}
每次读取的函数地址赋值给了cnx->egl指向的egl_t结构体。
4.2.2 加载OpenGL API(这一段摘自师弟写的文章,要修)
Android 2.0系统之前,加载OpenGL API和EGL API方式相同,均是通过dlsym加载。新版本的Android系统采用TLS技术进行动态加载。
TLS 让多线程程序设计更容易。TLS 是一个机制,通过它,程序可以拥有全局变量,但处于“每一线程各不相同”的状态。也就是说,进程中的所有线程都可以拥有全局变量,但这些变量只对某个线程才有意义。一段代码在任何情况下都是相同的,而从TLS中取出的对每个线程却各不相同。
在EGL的early_egl_init()中,对TLS机制进行初始化。将TLS里放入一个结构体指针,这个指针指向gHooksNoContext,这个结构体里的每个函数指针被初始化为gl_no_context。也就是现在如果通过TLS调用的OpenGL ES API都会调到gl_no_context这个函数中。
在eglMakeCurrent中,会将渲染上下文绑定到渲染面。在EGL中首先会处理完一系列和本地窗口系统的变量后,调用libGLES_android.so中的eglMakeCurrent,调用成功的话会设置TLS。将TLS指针指向前面已经初始化化好的gl_hooks_t结构体指针,这个结构体里的成员都已经指向了libGLES_android.so中的OpenGL API函数。

4.3动态加载库的优化
Android 2.0以上系统为libagl的Android.mk定义新的编译器参数-fvisibility=hidden。根据GCC编译器定义,使用该参数生成的动态库将不会导出函数符号表,亦是动态库函数的Vis参数为HIDDEN。这样可以防止导出多余函数,提高动态库的加载速度,对于需要导出的函数,可用参数__attribute__((visibility("default")))手动指定其为“default”属性。
针对libGLES_android.so库,以egl和gl的API均由手动指定其属性为“default”。在opengl/include/中,定义了API的额外参数GL_API。
#define GL_API      KHRONOS_APICALL
#define KHRONOS_APICALL __attribute__((visibility("default")))

5 Android OpenGL 2D部分
libagl中包含egl的实现和OpenGL API,虽然OpenGL API属于软件实现,但是已为2D硬件加速预留了接口,主要位于Texture相关函数,调用Android的Copybit和Gralloc模块。
5.1宏定义
libagl的Android.mk中有如下定义,如果定义了LIBAGL_USE_GRALLOC_COPYBITS宏,编译时将加入libagl的copybit.cpp文件,并链接libui库。
# Set to 1 to use gralloc and copybits
LIBAGL_USE_GRALLOC_COPYBITS := 1
ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1)
    LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS
    LOCAL_SRC_FILES += copybit.cpp
    LOCAL_SHARED_LIBRARIES += libui
endif
5.2 2D图形API
 void glDrawTexsvOES()
 void glDrawTexivOES()
 void glDrawTexsOES()
 void glDrawTexiOES()
以上四个API调用函数
static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)

 void glDrawTexfvOES()
 void glDrawTexxvOES()
 void glDrawTexfOES()
 void glDrawTexxOES()
以上四个API调用函数
static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
ogles_context_t* c)
以上8个API的主要不同在于传入参数的类型。
drawTexiOES函数用于处理整形数据,drawTexxOES函数用于处理浮点转定点后的数据。以上两个函数如果定义了LIBAGL_USE_GRALLOC_COPYBITS,则直接调用位于copybit.cpp中的drawTexiOESWithCopybit(x, y, z, w, h, c)进行硬件加速,否则调用drawTexxOESImp()纯软件实现。drawTexiOESWithCopybit调用copybit函数处理surface以适应copybit模块。

5.3 libagl中的copybit函数
copybit函数共有8个参数,分别为x、y坐标,w、h高宽,EGLTextureObject对象,
crop_rect对象,transform旋转方式,ogles_context_t OpenGL context上下文。
该函数主要执行以下操作:
 判断源是否有alpha值;
 判断是否需要进行blending操作;
 选择纹理模式,并将纹理转换为copybit模块兼容模式;
 确定copybit模块矩形框大小;
 如果需要计算alpha通道:
 调用copybit模块,将数据从目的地址考出至临时地址;
 调用copybit模块,从源地址复制至目的地址;
 调用copybit模块,从临时地址复制到目的地址,并带有alpha值。
 如果不需要计算alpha值:
 调用copybit模块,从源地址复制至目的地址;
针对需要计算alpha通道情况进行进一步解释:
这种情况属于整个图形区域采用相同的alpha值。 需要表现的效果为背景透明效果,前景明显可见。由此得出计算公式为“前景x(1-Alpha)+背景x Alpha”,需要三个步骤,移出背景,移入前景,带Alpha参数移入背景。

图中飞鸽这种背景就是这样生成的。

Rockie Cheng


下面是android openGL ES与EGL常见的问题:

原帖地址:http://stackoverflow.com/questions/17291774/the-game-will-quit-after-click-the-admobs-ad

I am writing a game and add the admob (version 6.4.1). When click the AD, it will have two problem and I don't know how to solve or debug.

I am using following code to add admob to surfaceview. Basically, it refered to other post at here.

adView = new AdView(this, AdSize.SMART_BANNER, "My_ID");
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
       RelativeLayout.LayoutParams.WRAP_CONTENT, 
       RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
adView.setLayoutParams(lp);
RelativeLayout layout = new RelativeLayout(this);
layout.addView(new MySurfaceViewX(this));
layout.addView(adView);
adView.loadAd(new AdRequest());
setContentView(layout);

Following is the logcat information:

06-25 15:08:24.214: I/System.out(25294): Pause all Music
06-25 15:08:24.218: I/System.out(25294): onPause
06-25 15:08:25.007: I/Ads(25294): onPresentScreen()
06-25 15:08:25.007: I/System.out(25294): onPresentScreen
06-25 15:08:25.148: I/Ads(25294): onLeaveApplication()
06-25 15:08:25.148: I/System.out(25294): onLeaveApplication
06-25 15:08:25.273: I/System.out(25294): SurfaceDestoryed
06-25 15:08:25.402: I/System.out(25294): onStop (Game exit temperory and AD is running)
06-25 15:08:28.261: D/webviewglue(25294): OnTrimMemory with EGL Context 0x0
06-25 15:08:28.308: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:28.308: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:28.308: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:28.308: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:28.308: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:32.652: D/webviewglue(25294): OnTrimMemory with EGL Context 0x0
06-25 15:08:32.656: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:32.656: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:32.656: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:32.656: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:32.656: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:35.789: I/Ads(25294): onDismissScreen()
06-25 15:08:35.800: I/System.out(25294): onDismissScreen
06-25 15:08:35.960: I/System.out(25294): onRestart
06-25 15:08:35.960: I/System.out(25294): onResume
06-25 15:08:36.035: I/System.out(25294): SurfaceCreated
06-25 15:08:36.050: I/System.out(25294): surfaceChanged 
06-25 15:08:39.722: I/System.out(25294): Pause all Music (when press "Back" key, it will go to  background at here)
06-25 15:08:39.722: I/System.out(25294): onPause
06-25 15:08:40.164: I/System.out(25294): SurfaceDestoryed
06-25 15:08:41.285: W/IInputConnectionWrapper(25294): showStatusIcon on inactive InputConnection
06-25 15:08:42.621: D/webviewglue(25294): OnTrimMemory with EGL Context 0x0
06-25 15:08:42.621: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:42.621: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:42.625: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:42.625: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:42.625: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)
06-25 15:08:42.636: I/System.out(25294): onStop
06-25 15:08:42.699: E/webview(25294): Error: WebView.destroy() called while still attached!
06-25 15:08:42.699: D/webviewglue(25294): nativeDestroy view: 0x52039c80
06-25 15:08:42.703: I/System.out(25294): onDestory

Problems :

1) When the AD clicked, the google play or explorer will be running. Logcat will have following error appear.

06-25 15:08:41.285: W/IInputConnectionWrapper(25294): showStatusIcon on inactive InputConnection
06-25 15:08:42.621: D/webviewglue(25294): OnTrimMemory with EGL Context 0x0
06-25 15:08:42.621: E/libEGL(25294): call to OpenGL ES API with no current context (logged once per thread)

2) When press "Back" key and return to game, if press "Back" key again, the game will goto background. It likes to use finish() or press "Home" key. The game not crash and it can call back after press the icon again.

If I haven't click the AD, everything is running OK.

I also found if it run at emulator, it will not have above ERROR.

Please , Who can help me? it make me crazy!

share | improve this question
 add comment

I think you are probably allowing your EGL Surface and context to be used by more than one thread. Android requires that all calls to OpenGL ES for a given context must come from only a single thread. This article explains in detail:

http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1/

share | improve this answer
 
 
But my game is not 3D Game, does it will use openGL? –  John Jun 26 '13 at 0:58
 
Since the ICS version, Android uses OpenGL ES 2.0 by default. Since you said it works on the AVD emulator, the problem may be that the OpenGL ES or EGL driver on your device has bugs. What is the device? Try a different one. –  ClayMontgomery Jun 26 '13 at 23:21
 
I had tried the Samsung i9000 and tablet Aurora 2. –  John Jun 27 '13 at 2:18
 
What type of GPU does the Aurora 2 have? Does it work better than the Samsung? If so, than I think your problem is probably a bug in Samsung's drivers. –  ClayMontgomery Jun 27 '13 at 4:05


  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是Android系统上,OpenGL ESEGL和Gralloc等的层次依赖关系的画图说明。 ``` +---------------------+ | App Layer | |---------------------| | Java API | |---------------------| | Android SDK | +---------------------+ | Frameworks & Libraries| |---------------------| | Native Layer | +---------------------+ | Hardware Abstraction Layer | +---------------------+ | Kernel | +---------------------+ | Hardware | +---------------------+ ``` 在Android系统中,App Layer(应用层)是最上层的,它包含了应用程序、Java API和Android SDK。应用程序通过Java API与Android SDK进行交互,Android SDK则通过Framework和Libraries层提供各种服务和功能。 在Native Layer(本地层)中,我们可以使用C/C++编写代码,包括OpenGL ESEGL和Gralloc等。其中,OpenGL ES是用于绘制3D图形的API,EGL是用于管理OpenGL ES和设备的交互的API,而Gralloc则是用于管理内存缓冲区的API。 在Hardware Abstraction Layer(硬件抽象层)中,我们可以使用HAL(Hardware Abstraction Layer)来访问硬件资源,如摄像头、传感器、Wi-Fi等。HAL负责将硬件资源的底层实现与上层软件的抽象接口进行适配。 在Kernel层(内核层)中,包含了操作系统的核心模块,如进程管理、内存管理、文件系统等。它提供了一个安全和稳定的环境,让应用和硬件通过HAL进行交互。 在Hardware层(硬件层)中,包含了设备的硬件组件,如CPU、GPU、内存、闪存、传感器等。硬件层提供了最底层的硬件支持,为上层提供数据存储和处理的能力。 希望这个画图能够帮助你更好地理解Android系统上,OpenGL ESEGL和Gralloc等的层次依赖关系。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值