部分內(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。

- 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,該目錄下文件如圖所示:
依次解析該目錄下各個(gè)文件的作用,由于文件缺少注釋,只能從代碼解讀含義:
eglApi.cpp:提供暴露給上層的API。包含EGL對(duì)象的創(chuàng)建、配置、銷毀等操作。
初始化EGL
OpenGL ES的初始化過程(EGL初始化)如下圖所示意:
Display → Config → Surface
↑
Context
↑
Application → OpenGL Command
獲取Display。
獲得Display要調(diào)用EGLboolean eglGetDisplay(NativeDisplay dpy),參數(shù)一般為 EGL_DEFAULT_DISPLAY 。初始化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
選擇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 ()來讀取,但不能修改。構(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()讀取。
創(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。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。繪制。
應(yīng)用程序通過OpenGL API進(jìn)行繪制,一幀完成之后,調(diào)用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)來顯示。
If
surfaceis a window surface,eglSwapBuffersposts its color buffer to the associated native window.
The contents of ancillary buffers are always undefined after callingeglSwapBuffers. The contents of the color buffer are left unchanged if the value of theEGL_SWAP_BEHAVIORattribute ofsurfaceisEGL_BUFFER_PRESERVED, and are undefined if the value isEGL_BUFFER_DESTROYED. The value ofEGL_SWAP_BEHAVIORcan be set for some surfaces using eglSurfaceAttrib.
eglSwapBuffersperforms an implicit flush operation on the context (glFlushfor an OpenGL ES or OpenGL context,vgFlushfor an OpenVG context) bound tosurfacebefore swapping. Subsequent client API commands may be issued on that context immediately after callingeglSwapBuffers, but are not executed until the buffer exchange is completed.
Ifsurfaceis a pixel buffer or a pixmap,eglSwapBuffershas 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;
}
- 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接口解析與理解