EGL简介以及窗口初始化

屏幕上可见的帧缓冲区由一个像素数据的二维数组表示。直接在可显示缓冲区上更新像素由一个严重的问题——用户在部分更新帧缓冲区时看到伪像或者闪烁的现象

为了解决这个问题,引入了双缓冲区。

OpenGLES应用程序中,这种活动通过EGL函数eglSwapBuffers控制:

eglSwapBuffers(exContext->eglDisplay, esContext->eglSurface);

EGL提供以下机制:

与设备的原生窗口系统通信

查询绘图表面的可用类型和配置

创建绘图表面

在OpenGLES3.0和其它图形渲染API(如桌面OpenGL和OpenVG——硬件加速矢量图形的跨平台API,活着窗口系统的原生绘图命令)之间同步渲染

管理纹理贴图等渲染资源

与窗口系统通信

Apple提供自己的EGL API的iOS 实现,称为EAGL

因为每个窗口系统都有不同语义,所以EGL提供基本的不透明类型——EGLDisplay,该类封装了所有系统相关性,用于和原生窗口系统接口交互。

任何使用EGL的应用程序必须执行的第一个操作是创建和初始化与本地EGL显示的连接。

一、初始化EGL

EGLConfig config;

EGLint majorVersion;

EGLint minorVersion;

EGLint contextAttribs[] = {

EGL_CONTEXT_CLIENT_VERSION,        3,        EGL_NONE

};

// 获取宽和高

esContext->width = ANativeWindow_getWidth(esContext->eglNativeWindow);esContext->height = ANativeWindow_getHeight(esContext->eglNativeWindow);

// 打开与EGL显示服务器的连接,默认为EGL_DEFAULT_DISPLAY

esContext->eglDisplay = eglGetDisplay(esContext->eglNativeDisplay);

// 如果显示连接不可用,则返回EGL_NO_DISPLAY标志,此时无法创建窗口

if (esContext->eglDisplay == EGL_NO_DISPLAY) {

return GL_FALSE;

}

// 初始化egl并回传版本号

if (!eglInitialize(esContext->eglDisplay, &majorVersion, &minorVersion)) {

return GL_FALSE;

}

成功打开连接后,需要初始化EGL,这通过调用如下函数完成:

EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);

dpy —— 指定EGL显示连接

major —— 返回EGL的主版本号

minor —— 返回EGL的副版本号

二、确定可用表面配置

一旦初始化了EGL,就可以确定可用渲染表面的类型和配置,有两种方法:

查询每个表面配置,找出最好的选择

指定一组需求,让EGL推荐最佳配置

通常使用第二种方法更简单,而且最有可能得到匹配。

任何一种情况下,EGL将返回一个EGLConfig,这是包含有关特定表面及其特性(每个颜色变量分量的位数、与EGLConfig相关的深度缓冲区(如果存在))的EGL内部数据结构的标识符。

EGLint numConfigs = 0;

EGLint attribList[] = {

EGL_RED_SIZE, 5,

EGL_GREEN_SIZE, 6,

EGL_BLUE_SIZE, 5,

EGL_ALPHA_SIZE, (flags & ES_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,

EGL_DEPTH_SIZE, (flags & ES_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,

EGL_STENCIL_SIZE, (flags & ES_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,

EGL_SAMPLE_BUFFERS, (flags & ES_WINDOW_MULTISAMPLE) ? 1 : 0,

EGL_RENDERABLE_TYPE, getContextRenderableType(esContext->eglDisplay),

EGL_NONE

};

// 选择Config

if (!eglChooseConfig(esContext->eglDisplay, attribList, &config, 1, &numConfigs)) {

return GL_FALSE;

}

if (numConfigs < 1) {

return GL_FALSE;

}

三、查询EGLConfig属性

EGLConfig包含关于EGL启用的表面的所有信息。可用颜色、与配置相关的其它缓冲区(深度和模板缓冲区等)、表面类型和其它特性

// Android需要获取EGL_NATIVE_VISUAL_ID的值并将其放如ANativeWindow_setBuffersGeometry函数中

EGLint format = 0;

eglGetConfigAttrib(esContext->eglDisplay, config, EGL_NATIVE_VISUAL_ID, &format);

ANativeWindow_setBuffersGeometry(esContext->eglNativeWindow, 0, 0, format);

四、创建屏幕上的渲染区域:EGL窗口

EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy,

EGLConfig config,

EGLNativeWindowType win,

const EGLint *attrib_list);

该函数用于创建一个窗口,以我们得到的原生显示管理器的连接和前一步得到的EGLConfig为参数。它需要原生窗口系统事先创建一个窗口。

创建窗口示例:

// 创建一个EGL窗口表面示例

EGLint list[] = {

EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE

};

EGLSurface window = eglCreateWindowSurface(esContext->eglDisplay, config,

esContext->eglNativeWindow, list);

if (window == EGL_NO_SURFACE) {

switch (eglGetError()) {

case EGL_BAD_MATCH:

break;

case EGL_BAD_CONFIG:

break;

case EGL_BAD_NATIVE_WINDOW:

break;

case EGL_BAD_ALLOC:

break;

}

}

上面的代码是创建一个绘图场景,但是我们还必须完成两个步骤,才能成功地用OpenGLES绘图。然而窗口不是唯一可用的渲染表面,也可以使用屏幕外渲染区域,也就是离屏渲染。

屏幕外渲染区域(离屏渲染):EGL Pbuffer

OpenGLES3.0除了可以进行屏幕渲染,也可以在不可见的屏幕外渲染,也就是在像素缓冲区上进行渲染,支持硬件加速。Pbuffer最常用于纹理贴图。

创建Pbuffer 和 创建EGL窗口非常相似,只有少数微笑的不同。

创建Pbuffer需要和窗口一样找到EGLConfig,并作一些修改:需要扩增EGL_SURFACE_TYPE的值,使其包含EGL_PBUFFER_BIT。

创建EGL像素缓冲区示例如下:

EGLint bufferList[] = {

EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,

EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,

EGL_RED_SIZE, 5,

EGL_GREEN_SIZE, 6,

EGL_BLUE_SIZE, 5,

EGL_DEPTH_SIZE, 1,

EGL_NONE

};

const EGLint MaxConfigs = 10;

EGLConfig configs[MaxConfigs];

EGLint numConfigs;

if (!eglChooseConfig(esContext->eglDisplay, bufferList, configs, MaxConfigs, &numConfigs)) {

return GL_FALSE;

}

EGLSurface pbuffer;

EGLint attribufferList[] = {

EGL_WIDTH, 512,

EGL_HEIGHT, 512,

EGL_LARGEST_PBUFFER, EGL_TRUE,

EGL_NONE

};

pbuffer = eglCreatePbufferSurface(esContext->eglDisplay, config, attribufferList);

if (pbuffer == EGL_NO_SURFACE) {

switch (eglGetError()) {

case EGL_BAD_ALLOC:

break;

case EGL_BAD_CONFIG:

break;

case EGL_BAD_PARAMETER:

break;

case EGL_BAD_MATCH:

break;

}

}

// 检查pbuffer 分配的内存大小

EGLint width;

EGLint height;

if (!eglQuerySurface(esContext->eglDisplay, pbuffer, EGL_WIDTH, &width)

|| !eglQuerySurface(esContext->eglDisplay, pbuffer, EGL_HEIGHT, &height)) {

// 不能查询 surface的信息

return GL_FALSE;

}

五、创建渲染上下文

渲染上下文是OpenGLES3.0的内部数据结构,包含操作所需要的所有状态信息。它包含了对顶点着色器和片元着色器数据的引用。

// 5.创建上下文

esContext->eglContext = eglCreateContext(esContext->eglDisplay, config,

EGL_NO_CONTEXT, contextAttribs);

// 判断上下文是否创建成功

if (esContext->eglContext == EGL_NO_CONTEXT) {

return GL_FALSE;

}

// 根据之前的配置构建上下文

if (!eglMakeCurrent(esContext->eglDisplay, esContext->eglSurface, esContext->eglSurface, esContext->eglContext)) {

return GL_FALSE;

}

六、指定某个EGLContext为当前上下文

// 指定某个EGLContext为当前上下文

if (!eglMakeCurrent(esContext->eglDisplay, esContext->eglSurface,

esContext->eglSurface, esContext->eglContext)) {

return GL_FALSE;

}

同步渲染

多个图形API在单个窗口中的渲染,此时需要使用同步渲染,需要应用程序允许多个库渲染到共享窗口。

如果不止使用OpenGLES3.0渲染,则不能简单地调用glFinish来抱着个所有渲染已经发生,你可以调用:

EGLBoolean eglWaitClient()

延迟客户端的执行,直到某个API的所有渲染完成,成功返回EGL_TRUE,失败时返回EGL_FALSE并发送EGL_BAD_CURRENT_SURFACE错误

同样,如果你需要保证原生窗口系统的渲染完成,则调用如下函数:

EGLBoolean eglWaitNative(EGLint engine)

engine,指定渲染程序等待渲染完成

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容