Android EGL

部分內(nèi)容摘自其他博客,請(qǐng)見最下[參考資料]

首先來看看Android官方對(duì)EGL的解釋:

OpenGL ES 定義了一個(gè)渲染圖形的 API,但沒有定義窗口系統(tǒng)。為了讓 GLES 能夠適合各種平臺(tái),GLES 將與知道如何通過操作系統(tǒng)創(chuàng)建和訪問窗口的庫結(jié)合使用。用于 Android 的庫稱為 EGL。如果要繪制紋理多邊形,應(yīng)使用 GLES 調(diào)用;如果要在屏幕上進(jìn)行渲染,應(yīng)使用 EGL 調(diào)用。

OpenGL ES 是Android繪圖API,但OpenGL ES是平臺(tái)通用的,在特定設(shè)備上使用需要一個(gè)中間層做適配,這個(gè)中間層就是EGL。


EGL架構(gòu)
  • Display(EGLDisplay) 是對(duì)實(shí)際顯示設(shè)備的抽象。
  • Surface(EGLSurface)是對(duì)用來存儲(chǔ)圖像的內(nèi)存區(qū)域 FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer。
  • Context (EGLContext) 存儲(chǔ) OpenGL ES繪圖的一些狀態(tài)信息。

Android中的OpenGL 與EGL
Android 2.0版本之后圖形系統(tǒng)的底層渲染均由OpenGL負(fù)責(zé),OpenGL除了負(fù)責(zé)處理3D API調(diào)用,還需負(fù)責(zé)管理顯示內(nèi)存及處理Android SurfaceFlinger或上層應(yīng)用對(duì)其發(fā)出的2D API調(diào)用請(qǐng)求。

  • 本地代碼:
    frameworks/native/opengl/libs/EGL
    Android EGL框架,負(fù)責(zé)加載OpenGL函數(shù)庫和EGL本地實(shí)現(xiàn)。
    frameworks/native/opengl/libagl
    Android提供的OpenGL軟件庫

  • JNI代碼:
    frameworks/base/core/jni/com_google_android_gles_jni_EGLImpl.cpp
    EGL本地代碼的JNI調(diào)用接口
    frameworks/base/core/jni/com_google_android_gles_jni_GLImpl.cpp
    frameworks/base/core/jni/android_opengl_GLESXXX.cpp
    OpenGL功能函數(shù)的JNI調(diào)用接口

  • 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層接口,提供給應(yīng)用開發(fā)者,通過JNI方式調(diào)用底層函數(shù)。

首先從Native代碼入手: frameworks/native/opengl/libs/EGL,該目錄下文件如圖所示:


frameworks/native/opengl/libs/EGL

依次解析該目錄下各個(gè)文件的作用,由于文件缺少注釋,只能從代碼解讀含義:
eglApi.cpp:提供暴露給上層的API。包含EGL對(duì)象的創(chuàng)建、配置、銷毀等操作。

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

Context

Application → OpenGL Command

  1. 獲取Display。
    獲得Display要調(diào)用EGLboolean eglGetDisplay(NativeDisplay dpy),參數(shù)一般為 EGL_DEFAULT_DISPLAY 。

  2. 初始化egl。
    調(diào)用 EGLboolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor),該函數(shù)會(huì)進(jìn)行一些內(nèi)部初始化工作,并傳回EGL版本號(hào)(major.minor)。
    開機(jī)時(shí)打出的信息:
    如下信息可以由const char * eglQueryString (EGLDisplay dpy, EGLint name);給出,name可以是EGL_VENDOR, EGL_VERSION, 或者EGL_EXTENSIONS 。該函數(shù)常用來查詢當(dāng)前版本EGL實(shí)現(xiàn)了哪些擴(kuò)展,方便向下兼容。

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實(shí)際指的是FrameBuffer的參數(shù),
    一般用EGLboolean eglChooseConfig(EGLDisplay dpy, const EGLint * attr_list, EGLConfig * config, EGLint config_size, EGLint *num_config),其中attr_list是以EGL_NONE結(jié)束的參數(shù)數(shù)組,通常以id,value依次存放,對(duì)于個(gè)別標(biāo)識(shí)性的屬性可以只有 id,沒有value。另一個(gè)辦法是用EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint config_size, EGLint *num_config) 來獲得所有config。
    這兩個(gè)函數(shù)都會(huì)返回不多于config_size個(gè)Config,結(jié)果保存在config[]中,系統(tǒng)的總Config個(gè)數(shù)保存 在num_config中。
    可以利用eglGetConfig()中間兩個(gè)參數(shù)為0來查詢系統(tǒng)支持的Config總個(gè)數(shù)。Config有眾多的Attribute,這些Attribute決定FrameBuffer的格式和能力,通過eglGetConfigAttrib ()來讀取,但不能修改。

  2. 構(gòu)造Surface
    Surface實(shí)際上就是一個(gè)FrameBuffer,也就是渲染目的地,通過EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig confg, NativeWindow win, EGLint *cfg_attr)來創(chuàng)建一個(gè)可實(shí)際顯示的Surface。
    系統(tǒng)通常還支持另外兩種Surface:PixmapSurface和PBufferSurface,這兩種都不是可顯示的Surface,PixmapSurface是保存在系統(tǒng)內(nèi)存中的位圖,PBuffer則是保存在顯存中的幀。
    對(duì)于這兩種surface,Android系統(tǒng)中,支持PBufferSurface。Surface也有一些attribute,基本上都可以顧名思義,

EGL_HEIGHT EGL_WIDTH EGL_LARGEST_PBUFFER
EGL_TEXTURE_FORMAT EGL_TEXTURE_TARGET
EGL_MIPMAP_TEXTURE EGL_MIPMAP_LEVEL

通過eglSurfaceAttrib()設(shè)置、eglQuerySurface()讀取。

  1. 創(chuàng)建Context
    OpenGL ES的pipeline從程序的角度看就是一個(gè)狀態(tài)機(jī),有當(dāng)前的顏色、紋理坐標(biāo)、變換矩陣、絢染模式等一大堆狀態(tài),這些狀態(tài)作用于OpenGL API程序提交的頂點(diǎn)坐標(biāo)等圖元從而形成幀緩沖內(nèi)的像素。在OpenGL的編程接口中,Context就代表這個(gè)狀態(tài)機(jī),OpenGL API程序的主要工作就是向Context提供圖元、設(shè)置狀態(tài),偶爾也從Context里獲取一些信息。
    可以用EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write, EGLSurface read, EGLContext * share_list)來創(chuàng)建一個(gè)Context。

  2. EGL變量之間的綁定
    boolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context)
    該接口將申請(qǐng)到的display,draw(surface)和 context進(jìn)行了綁定。也就是說,在context下的OpenGLAPI指令將draw(surface)作為其渲染最終目的地。而display作為draw(surface)的前端顯示。調(diào)用后,當(dāng)前線程使用的EGLContex為context。

  3. 繪制。
    應(yīng)用程序通過OpenGL API進(jìn)行繪制,一幀完成之后,調(diào)用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對(duì)eglSwapBuffers的實(shí)現(xiàn):

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之后
    應(yīng)該是生成了layer供HWC合成,這部分仍在學(xué)習(xí)當(dāng)中

參考資料
Android OpenGL ES(四):關(guān)于EGL
Android 的OpenGL ES與EGL
極客學(xué)院 Android OpenGL ES 開發(fā)教程
騰訊GAD開發(fā)者平臺(tái) - EGL接口解析與理解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本篇文章是基于谷歌有關(guān)Graphic的一篇概覽文章的翻譯:http://source.android.com/de...
    lee_3do閱讀 7,466評(píng)論 2 21
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,057評(píng)論 25 709
  • 1、人是軟弱的,所以要覺知,讓自己定下來。問題在自己處,不在別人。 ——素黑《好好愛自己》 2、有這樣一些人,他...
    喵月嗅雪閱讀 556評(píng)論 0 2
  • “姐,我今天特別感動(dòng),不不不,是能當(dāng)你的妹妹我很幸運(yùn),因?yàn)槟阋恢币恢卑菸业某羝猓 ?其實(shí),今天我是被妹妹感動(dòng)了...
    是舒格閱讀 404評(píng)論 0 4

友情鏈接更多精彩內(nèi)容