Android EGL

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

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

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

1637548266(1)

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,该目录下文件如图所示:

1637548323(1)

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之后


转载链接:https://www.jianshu.com/p/95dfe935b169

posted @ 2021-11-22 10:33  不止所见  阅读(1123)  评论(0编辑  收藏  举报