Android EGL

部分内容摘自其他博客,请见最下[参考资料]

首先来看看Android官方对EGL的解释:

OpenGL ES 定义了一个渲染图形的 API,但没有定义窗口系统。为了让 GLES 能够适合各种平台,GLES 将与知道如何通过操作系统创建和访问窗口的库结合使用。用于 Android 的库称为 EGL。如果要绘制纹理多边形,应使用 GLES 调用;如果要在屏幕上进行渲染,应使用 EGL 调用。

OpenGL ES 是Android绘图API,但OpenGL ES是平台通用的,在特定设备上使用需要一个中间层做适配,这个中间层就是EGL。


EGL架构
  • Display(EGLDisplay) 是对实际显示设备的抽象。
  • Surface(EGLSurface)是对用来存储图像的内存区域 FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer。
  • Context (EGLContext) 存储 OpenGL ES绘图的一些状态信息。

Android中的OpenGL 与EGL
Android 2.0版本之后图形系统的底层渲染均由OpenGL负责,OpenGL除了负责处理3D API调用,还需负责管理显示内存及处理Android SurfaceFlinger或上层应用对其发出的2D API调用请求。

  • 本地代码:
    frameworks/native/opengl/libs/EGL
    Android EGL框架,负责加载OpenGL函数库和EGL本地实现。
    frameworks/native/opengl/libagl
    Android提供的OpenGL软件库

  • JNI代码:
    frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp
    EGL本地代码的JNI调用接口
    frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp
    frameworks/base/core/jni/android_opengl_GLESXXX.cpp
    OpenGL功能函数的JNI调用接口

  • Java代码:
    frameworks/base/opengl/java/javax/microedition/khronos/egl
    frameworks/base/opengl/java/javax/microedition/khronos/opengles
    frameworks/base/opengl/java/com/google/android/gles_jni/
    frameworks/base/opengl/java/android/opengl
    EGL和OpenGL的Java层接口,提供给应用开发者,通过JNI方式调用底层函数。

首先从Native代码入手: frameworks/native/opengl/libs/EGL,该目录下文件如图所示:


frameworks/native/opengl/libs/EGL

依次解析该目录下各个文件的作用,由于文件缺少注释,只能从代码解读含义:
eglApi.cpp:提供暴露给上层的API。包含EGL对象的创建、配置、销毁等操作。

初始化EGL
OpenGL ES的初始化过程(EGL初始化)如下图所示意:
Display → Config → Surface

Context

Application → OpenGL Command

  1. 获取Display。
    获得Display要调用EGLboolean eglGetDisplay(NativeDisplay dpy),参数一般为 EGL_DEFAULT_DISPLAY 。

  2. 初始化egl。
    调用 EGLboolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor),该函数会进行一些内部初始化工作,并传回EGL版本号(major.minor)。
    开机时打出的信息:
    如下信息可以由const char * eglQueryString (EGLDisplay dpy, EGLint name);给出,name可以是EGL_VENDOR, EGL_VERSION, 或者EGL_EXTENSIONS 。该函数常用来查询当前版本EGL实现了哪些扩展,方便向下兼容。

SurfaceFlinger: EGL information:
SurfaceFlinger: vendor    : Android
SurfaceFlinger: version   : 1.4 Android META-EGL
SurfaceFlinger: extensions: EGL_KHR_get_all_proc_addresses EGL_ANDROID_presentation_time EGL_KHR_swap_buffers_with_damage EGL_ANDROID_get_native_client_buffer EGL_ANDROID_front_buffer_auto_refresh EGL_ANDROID_get_frame_timestamps EGL_KHR_image EGL_KHR_image_base EGL_KHR_gl_colorspace EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_cubemap_image EGL_KHR_gl_renderbuffer_image EGL_KHR_fence_sync EGL_KHR_create_context EGL_KHR_config_attribs EGL_KHR_surfaceless_context EGL_EXT_create_context_robustness EGL_ANDROID_image_native_buffer EGL_KHR_wait_sync EGL_ANDROID_recordable EGL_KHR_partial_update EGL_KHR_mutable_render_buffer EGL_IMG_context_priority 
SurfaceFlinger: Client API: OpenGL_ES
SurfaceFlinger: EGLSurface: 8-8-8-8, config=0x785f32d008
SurfaceFlinger: OpenGL ES informations:
SurfaceFlinger: vendor    : ARM
SurfaceFlinger: renderer  : Mali-T860
SurfaceFlinger: version   : OpenGL ES 3.2 v1.r18p0-00cet0.e348142bb0bcdf18abb600a2670c56a1
SurfaceFlinger: extensions: GL_EXT_debug_marker GL_ARM_rgba8 GL_ARM_mali_shader_binary GL_OES_depth24 GL_OES_depth_texture GL_OES_depth_texture_cube_map GL_OES_packed_depth_stencil GL_OES_rgb8_rgba8 GL_EXT_read_format_bgra GL_OES_compressed_paletted_texture GL_OES_compressed_ETC1_RGB8_texture GL_OES_standard_derivatives GL_OES_EGL_image GL_OES_EGL_image_external GL_OES_EGL_image_external_essl3 GL_OES_EGL_sync GL_OES_texture_npot GL_OES_vertex_half_float GL_OES_required_internalformat GL_OES_vertex_array_object GL_OES_mapbuffer GL_EXT_texture_format_BGRA8888 GL_EXT_texture_rg GL_EXT_texture_type_2_10_10_10_REV GL_OES_fbo_render_mipmap GL_OES_element_index_uint GL_EXT_shadow_samplers GL_OES_texture_compression_astc GL_KHR_texture_compression_astc_ldr GL_KHR_texture_compression_astc_hdr GL_KHR_texture_compression_astc_sliced_3d GL_KHR_debug GL_EXT_occlusion_query_boolean GL_EXT_disjoint_timer_query GL_EXT_blend_minmax GL_EXT_discard_framebuffer GL_OES_get_prog...
SurfaceFlinger: GL_MAX_TEXTURE_SIZE = 8192
SurfaceFlinger: GL_MAX_VIEWPORT_DIMS = 8192
  1. 选择Config。
    Config实际指的是FrameBuffer的参数,
    一般用EGLboolean eglChooseConfig(EGLDisplay dpy, const EGLint * attr_list, EGLConfig * config, EGLint config_size, EGLint *num_config),其中attr_list是以EGL_NONE结束的参数数组,通常以id,value依次存放,对于个别标识性的属性可以只有 id,没有value。另一个办法是用EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint config_size, EGLint *num_config) 来获得所有config。
    这两个函数都会返回不多于config_size个Config,结果保存在config[]中,系统的总Config个数保存 在num_config中。
    可以利用eglGetConfig()中间两个参数为0来查询系统支持的Config总个数。Config有众多的Attribute,这些Attribute决定FrameBuffer的格式和能力,通过eglGetConfigAttrib ()来读取,但不能修改。

  2. 构造Surface
    Surface实际上就是一个FrameBuffer,也就是渲染目的地,通过EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig confg, NativeWindow win, EGLint *cfg_attr)来创建一个可实际显示的Surface。
    系统通常还支持另外两种Surface:PixmapSurface和PBufferSurface,这两种都不是可显示的Surface,PixmapSurface是保存在系统内存中的位图,PBuffer则是保存在显存中的帧。
    对于这两种surface,Android系统中,支持PBufferSurface。Surface也有一些attribute,基本上都可以顾名思义,

EGL_HEIGHT EGL_WIDTH EGL_LARGEST_PBUFFER
EGL_TEXTURE_FORMAT EGL_TEXTURE_TARGET
EGL_MIPMAP_TEXTURE EGL_MIPMAP_LEVEL

通过eglSurfaceAttrib()设置、eglQuerySurface()读取。

  1. 创建Context
    OpenGL ES的pipeline从程序的角度看就是一个状态机,有当前的颜色、纹理坐标、变换矩阵、绚染模式等一大堆状态,这些状态作用于OpenGL API程序提交的顶点坐标等图元从而形成帧缓冲内的像素。在OpenGL的编程接口中,Context就代表这个状态机,OpenGL API程序的主要工作就是向Context提供图元、设置状态,偶尔也从Context里获取一些信息。
    可以用EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write, EGLSurface read, EGLContext * share_list)来创建一个Context。

  2. EGL变量之间的绑定
    boolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context)
    该接口将申请到的display,draw(surface)和 context进行了绑定。也就是说,在context下的OpenGLAPI指令将draw(surface)作为其渲染最终目的地。而display作为draw(surface)的前端显示。调用后,当前线程使用的EGLContex为context。

  3. 绘制。
    应用程序通过OpenGL API进行绘制,一帧完成之后,调用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)来显示。

If surface is a window surface, eglSwapBuffers posts its color buffer to the associated native window.
The contents of ancillary buffers are always undefined after calling eglSwapBuffers. The contents of the color buffer are left unchanged if the value of the EGL_SWAP_BEHAVIOR attribute of surface is EGL_BUFFER_PRESERVED, and are undefined if the value is EGL_BUFFER_DESTROYED. The value of EGL_SWAP_BEHAVIOR can be set for some surfaces using eglSurfaceAttrib.
eglSwapBuffers performs an implicit flush operation on the context (glFlush for an OpenGL ES or OpenGL context, vgFlush for an OpenVG context) bound to surface before swapping. Subsequent client API commands may be issued on that context immediately after calling eglSwapBuffers, but are not executed until the buffer exchange is completed.
If surface is a pixel buffer or a pixmap, eglSwapBuffers has no effect, and no error is generated.

看看frameworks/native/opengl/libagl/egl.cpp对eglSwapBuffers的实现:

EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
    egl_surface_t* d = static_cast<egl_surface_t*>(draw);

    ...

    // post the surface
    d->swapBuffers();

    // if it's bound to a context, update the buffer
    if (d->ctx != EGL_NO_CONTEXT) {
        d->bindDrawSurface((ogles_context_t*)d->ctx);
        // if this surface is also the read surface of the context
        // it is bound to, make sure to update the read buffer as well.
        // The EGL spec is a little unclear about this.
        egl_context_t* c = egl_context_t::context(d->ctx);
        if (c->read == draw) {
            d->bindReadSurface((ogles_context_t*)d->ctx);
        }
    }

    return EGL_TRUE;
}
  1. eglSwapBuffers之后
    应该是生成了layer供HWC合成,这部分仍在学习当中

参考资料
Android OpenGL ES(四):关于EGL
Android 的OpenGL ES与EGL
极客学院 Android OpenGL ES 开发教程
腾讯GAD开发者平台 - EGL接口解析与理解

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容

  • 本篇文章是基于谷歌有关Graphic的一篇概览文章的翻译:http://source.android.com/de...
    lee_3do阅读 7,123评论 2 21
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,122评论 25 707
  • 1、人是软弱的,所以要觉知,让自己定下来。问题在自己处,不在别人。 ——素黑《好好爱自己》 2、有这样一些人,他...
    喵月嗅雪阅读 490评论 0 2
  • “姐,我今天特别感动,不不不,是能当你的妹妹我很幸运,因为你一直一直包容我的臭脾气!” 其实,今天我是被妹妹感动了...
    是舒格阅读 369评论 0 4
  • 以前看过笔名特立独行的猪写的《不要让未来的你讨厌现在的自己》,就像这种快餐类的鸡汤文集,我一般很少看,看了也就忘了...
    唐森的阅读笔记阅读 509评论 1 6