OpenGL ES总结(六)OpenGL ES中EGL

Agenda:

  • EGL是什么?
  • EGL数据类型
  • EGL在Android中应用
  • EGL的工作流程
  • GLSurfaceView与EGL区别
  • 简单Demo

EGL是什么?

EGL? is an interface between Khronos rendering APIs such as OpenGL ES or OpenVG and the underlying native platform window system.

It handles graphics context management, surface/buffer binding, and rendering synchronization and enables high-performance, accelerated, mixed-mode 2D and 3D rendering using other Khronos APIs.

那么什么是EGL?EGL是OpenGL ES和底层的native window system之间的接口,承上启下。

在Android上,EGL完善了OpenGL ES。利用类似eglCreateWindowSurface的EGL函数可以创建surface 用来render ,有了这个surface你就能往这个surface中利用OpenGL ES函数去画图了。OpenGL ES 本质上是一个图形渲染管线的状态机,而 EGL 则是用于监控这些状态以及维护 Frame buffer 和其他渲染 Surface 的外部层。下图是一个3d游戏典型的 EGL 系统布局图。

EGL数据类型

数据类型
EGLBoolean EGL_TRUE =1, EGL_FALSE=0
EGLint int 数据类型
EGLDisplay 系统显示 ID 或句柄
EGLConfig Surface 的 EGL 配置
EGLSurface 系统窗口或 frame buffer 句柄
EGLContext OpenGL ES 图形上下文
NativeDisplayType Native 系统显示类型
NativeWindowType Native 系统窗口缓存类型
NativePixmapType Native 系统 frame buffer

EGL在Android中应用

下面是开机动画BootAnimation中的实现,首先是创建本地环境,

status_t BootAnimation::readyToRun() {

    // 创建SurfaceControl
    // create the native surface
    sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);

    SurfaceComposerClient::openGlobalTransaction();
    // 设置layerstack
    control->setLayer(0x40000000);
    SurfaceComposerClient::closeGlobalTransaction();

    //获取Surface
    sp<Surface> s = control->getSurface();

    // initialize opengl and egl
    const EGLint attribs[] = {
            EGL_RED_SIZE,   8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE,  8,
            EGL_DEPTH_SIZE, 0,
            EGL_NONE
    };
    EGLint w, h, dummy;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    //调用eglGetDisplay
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); // 第一步

    eglInitialize(display, 0, 0); // 第二步
    eglChooseConfig(display, attribs, &config, 1, &numConfigs); // 第三步
    //调用eglCreateWindowSurface将Surface s转换为本地窗口,
    surface = eglCreateWindowSurface(display, config, s.get(), NULL); // 第四步
    context = eglCreateContext(display, config, NULL, NULL); // 第五步
    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    //eglMakeCurrent后生成的surface就可以利用opengl画图了
    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
        return NO_INIT;

    return NO_ERROR;
}

egl创建好后,调用gl相关命令去画图,注意eglSwapBuffers(mDisplay, mSurface) 函数是非常重要的一个函数,会去触发queueBuffer和dequeueBuffer,图画就一帧一帧的画出来了。

bool BootAnimation::android()
{
    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");

    // clear screen
    glShadeModel(GL_FLAT);
    glDisable(GL_DITHER);
    glDisable(GL_SCISSOR_TEST);
    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT);
    //调用eglSwapBuffers会去触发queuebuffer,dequeuebuffer,
    //queuebuffer将画好的buffer交给surfaceflinger处理,
    //dequeuebuffer新创建一个buffer用来画图
    eglSwapBuffers(mDisplay, mSurface); // 第六步

    glEnable(GL_TEXTURE_2D);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    const GLint xc = (mWidth  - mAndroid[0].w) / 2;
    const GLint yc = (mHeight - mAndroid[0].h) / 2;
    const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);

    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
            updateRect.height());

    // Blend state
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    const nsecs_t startTime = systemTime();
    do {
        nsecs_t now = systemTime();
        double time = now - startTime;
        float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
        GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
        GLint x = xc - offset;

        glDisable(GL_SCISSOR_TEST);
        glClear(GL_COLOR_BUFFER_BIT);

        glEnable(GL_SCISSOR_TEST);
        glDisable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
        glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
        glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);

        glEnable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
        glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);

        EGLBoolean res = eglSwapBuffers(mDisplay, mSurface);
        if (res == EGL_FALSE)
            break;

        // 12fps: don‘t animate too fast to preserve CPU
        const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
        if (sleepTime > 0)
            usleep(sleepTime);

        checkExit();
    } while (!exitPending());

    glDeleteTextures(1, &mAndroid[0].name);
    glDeleteTextures(1, &mAndroid[1].name);
    return false;
}

EGL的工作流程

以上开机动画,可分如下几个阶段:

  • 1、 获取Display。

    Display代表显示。获得Display要调用EGLboolean eglGetDisplay(NativeDisplay dpy),参数一般为 EGL_DEFAULT_DISPLAY 。对应开机动画就是如下代码:

    //调用eglGetDisplay
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  • 2、 初始化egl。

    调用 EGLboolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor),该函数会进行一些内部初始化工作,并传回EGL版本号(major.minor)。对应开机动画就是如下代码:

    eglInitialize(display, 0, 0); 
  • 3、 选择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 ()来读取,但不能修改。对应开机动画就是如下代码:

    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
  • 4、 构造Surface。

    Surface实际上就是一个FrameBuffer,通过 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig confg, NativeWindow win, EGLint *cfg_attr) 来创建一个可实际显示的Surface。系统通常还支持另外两种Surface:PixmapSurface和PBufferSurface,这两种都不是可显示的Surface,PixmapSurface是保存在系统内存中的位图,PBuffer则是保存在显存中的帧。

    Surface也有一些attribute,基本上都可以故名思意, EGL_HEIGHT EGL_WIDTH EGL_LARGEST_PBUFFER EGL_TEXTURE_FORMAT EGL_TEXTURE_TARGET EGL_MIPMAP_TEXTURE EGL_MIPMAP_LEVEL,通过eglSurfaceAttrib()设置、eglQuerySurface()读取。对应开机动画就是如下代码:

    surface = eglCreateWindowSurface(display, config, s.get(), NULL);
  • 5、 创建Context。

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

    用EGLContext eglCreateContext(EGLDisplay dpy, EGLSurface write, EGLSurface read, EGLContext * share_list)来创建一个Context。对应开机动画就是如下代码:

    context = eglCreateContext(display, config, NULL, NULL);
  • 6、 绘制。

    应用程序通过OpenGL API进行绘制,一帧完成之后,调用eglSwapBuffers(EGLDisplay dpy, EGLContext ctx)来显示。对应开机动画就是如下代码:

    eglSwapBuffers(mDisplay, mSurface); /

EGL 官网详细讲述了Surface、Display、Context 概念。对应链接:

简单地说

(1)Display 是图形显示设备(显示屏)的抽象表示。大部分EGL函数都要带一个 Display 作为参数

(2)Context 是 OpenGL 状态机。Context 与 Surface 可以是一对一、多对一、一对多的关系

(3)Surface 是绘图缓冲,可以是 window、pbuffer、pixmap 三种类型之一

EGL 工作流程为:

(1)初始化

(2)配置

(3)创建Surface(绑定到平台Windowing系统)

(4)绑定Surface与Context

(5)Main Loop:渲染(OpenGL),交换离线缓冲(offline buffer)与显示缓冲

(6)释放资源

GLSurfaceView与EGL区别

  • GLSurfaceView隐藏了EGL操作及渲染线程的细节,并提供了生命周期回调方法。
  • EGL可以控制渲染循环,例如:可以没法控制帧速(fps),GLSurfaceView不能

简单Demo:

时间: 2024-10-06 22:16:30

OpenGL ES总结(六)OpenGL ES中EGL的相关文章

OpenGL ES SL 3.0规范中以前的attribute改成了in varying改成了out

       OpenGL ES和OpenGL的图标 关于"OpenGL ES SL 3.0规范中以前的attribute改成了in varying改成了out"这个问题,做一阐述: 1.关键字的小修改大概由如下两点决定 第一,先考虑一个成本原则 一个关键字的定义是否修改,是由熟练程序员在使用该关键字时的思维成本来决定的. 当然,还有一个原则,是由初学者的学习成本来决定的,这时一条市场原则(微软喜欢这个原则). attribute改成in,varying 改成out,恰巧符合上面两条原

[转]用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口

原文链接: 1.用多线程方法实现在MFC/WIN32中调用OpenGL函数并创建OpenGL窗口 2.Windows MFC 两个OpenGL窗口显示与线程RC问题 原文地址:https://www.cnblogs.com/rainbow70626/p/8973440.html

[OpenGL]环境搭建以及OpenGL初识

想往游戏行业发展的话,经常被提及到的就是OpenGL和DirectX,这两者听起来感觉是一门挺高深的技术,今天我也开始摸索学习OpenGL,那么OpenGL到底是什么?它和DirectX有什么区别和联系? OpenGL初识 OpenGL只是一套图形函数库 DirectX包含图形.声音.输入.网络等模块. 但就图形而论,DirectX的图形库性能不如OpenGL,OpenGL稳定,可以跨平台使用,DirectX只支持Windows平台,所以OpenGL还是有它的优势!OpenGL ES是OpenG

深入理解OpenGL拾取模式(OpenGL Picking)

深入理解OpenGL拾取模式(OpenGL Picking) 本文转自:http://blog.csdn.net/zhangci226/article/details/4749526 在用OpenGL进行图形编程的时候,通常要用鼠标进行交互操作,比如用鼠标点选择画面中的物体,我们称之为拾取(Picking),在网上看了很多OpenGL拾取的文章,但大多是只是介绍在OpenGL中如何拾取,如何利用OpenGL提供的一系列函数来完成拾取,最多再简单介绍下OpenGL的名字栈(Name stack),

【《Objective-C基础教程 》笔记ch05】(六)OC中的复合机制Composition

 1.复合通过包含作为实例变量的的对象指针实现的.        @interface Unicycle : NSObject        {           Pedal*pedal;           Tire*tire;         }//Pedal和tire通过复合的方式组成了Unicycle 2.存取方法--用来读取或者改变某个对象属性的方法. #import <Foundation/Foundation.h> @interface Car : NSObject { Eng

一个无锁消息队列引发的血案(六)——RingQueue(中) 休眠的艺术 [续]

目录 (一)起因 (二)混合自旋锁 (三)q3.h 与 RingBuffer (四)RingQueue(上) 自旋锁 (五)RingQueue(中) 休眠的艺术 (六)RingQueue(中) 休眠的艺术 [续] 开篇 这是第五篇的后续,这部分的内容同时会更新和添加在 第五篇:RingQueue(中) 休眠的艺术 一文的末尾. 归纳 紧接上一篇的末尾,我们把 Windows 和 Linux 下的休眠策略归纳总结一下,如下图: 我们可以看到,Linux 下的 sched_yield() 虽然包括了

四十六、android中的Bitmap

四十六.android中的Bitmap: http://www.cnblogs.com/linjiqin/archive/2011/12/28/2304940.html 四十七.实现调用Android手机的拍照功能: http://www.cnblogs.com/linjiqin/archive/2011/12/28/2304970.html

Android见招拆招六:LinearLayout中Gravity、Layout_Gravity何时生效

对于LinearLayout何时生效的问题 对于 LinearLayout 当 android:orientation="vertical"  时, 只有水平方向的设置才起作用,垂直方向的设置不起作用.即:left,right,center_horizontal 是生效的. 当 android:orientation="horizontal" 时, 只有垂直方向的设置才起作用,水平方向的设置不起作用.即:top,bottom,center_vertical 是生效的

OpenGL模板 Mac Cmake OpenGL(Glut) Template

自己经常使用的一些功能做一个模板,有灯光效果,你可以用鼠标放大,围绕所述旋转坐标系的原点 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcHlhbmcxOTg5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > Main.cpp #include <GLUT/glut.h> #include <cstdlib> /*