部分內(nèi)容摘自其他博客定枷,請見最下[參考資料]
首先來看看Android官方對EGL的解釋:
OpenGL ES 定義了一個(gè)渲染圖形的 API伺帘,但沒有定義窗口系統(tǒng)园担。為了讓 GLES 能夠適合各種平臺奏纪,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是平臺通用的诚些,在特定設(shè)備上使用需要一個(gè)中間層做適配飞傀,這個(gè)中間層就是EGL。
- Display(EGLDisplay) 是對實(shí)際顯示設(shè)備的抽象诬烹。
- Surface(EGLSurface)是對用來存儲圖像的內(nèi)存區(qū)域 FrameBuffer 的抽象砸烦,包括 Color Buffer, Stencil Buffer 绞吁,Depth Buffer幢痘。
- Context (EGLContext) 存儲 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)用對其發(fā)出的2D API調(diào)用請求购岗。
本地代碼:
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對象的創(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ù)會進(jìn)行一些內(nèi)部初始化工作碳抄,并傳回EGL版本號(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依次存放,對于個(gè)別標(biāo)識性的屬性可以只有 id澎粟,沒有value蛀序。另一個(gè)辦法是用EGLboolean eglGetConfigs(EGLDisplay dpy, EGLConfig * config, EGLint config_size, EGLint *num_config) 來獲得所有config。
這兩個(gè)函數(shù)都會返回不多于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則是保存在顯存中的幀。
對于這兩種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)
該接口將申請到的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
surface
is a window surface,eglSwapBuffers
posts 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_BEHAVIOR
attribute ofsurface
isEGL_BUFFER_PRESERVED
, and are undefined if the value isEGL_BUFFER_DESTROYED
. The value ofEGL_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 tosurface
before swapping. Subsequent client API commands may be issued on that context immediately after callingeglSwapBuffers
, but are not executed until the buffer exchange is completed.
Ifsurface
is a pixel buffer or a pixmap,eglSwapBuffers
has no effect, and no error is generated.
看看frameworks/native/opengl/libagl/egl.cpp對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ā)者平臺 - EGL接口解析與理解