eglMakeCurrent, eglSwapBuffers, glFlush, glFinish
2016-07-18 11:24
603 查看
Let’s talk about eglMakeCurrent, eglSwapBuffers, glFlush, glFinish
from:https://katatunix.wordpress.com/2014/09/17/lets-talk-about-eglmakecurrent-eglswapbuffers-glflush-glfinish/
eglMakeCurrent
First of all, do you remember the function eglMakeCurrent, its prototype is:EGLBoolean eglMakeCurrent( EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
This prototype would force you to understand what are Display, Surface, and Context.
Display
As you have seen, most EGL functions require a Display as the first parameter. A Display is just a connection to the native windowing system running on your computer, like the X Window System on GNU/Linux systems, or Microsoft Windows.Therefore, before you can use EGL functions, you must create and initialize a Display connection. This is easily done in a two-call sequence, as shown below:
EGLint majorVersion; EGLint minorVersion; EGLDisplay display; // EGLDisplay is just a void* type display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (display == EGL_NO_DISPLAY) { // Unable to open connection to local windowing system } if (!eglInitialize(display, &majorVersion, &minorVersion)) { // Unable to initialize EGL. Handle and recover }
You usually (always) pass EGL_DEFAULT_DISPLAY to the function eglGetDisplay so EGL will select the default Display automatically.
Context
Context is kừn-tếch, right :) just kidding. Context is nothing but a container that contains two things:Internal state machine (view port, depth range, clear color, textures, VBO, FBO …).
A command buffer to hold GL commands that have been called in this context.
In general, Context’s purpose is storing input data of rendering.
Surface
You can guess that Surface’s purpose is storing output of rendering. Indeed, a Surface extends a native window or pixmap with additional auxillary buffers. These buffers include a color buffer, a depth buffer, and a stencil buffer.
Back to eglMakeCurrent
So what does the function eglMakeCurrent do? If you are wondering: when I call a GL command (e.g. glDrawElements), which context and which surface is affected by that GL command; then the answer is eglMakeCurrent:EGLBoolean eglMakeCurrent( EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
eglMakeCurrent binds context to the current rendering thread AND TO the draw and read surfaces. draw is used for all GL operations except for any pixel data read back (glReadPixels, glCopyTexImage2D,
and glCopyTexSubImage2D), which is taken from the frame buffer values of read.
Therefore, when you call the GL command on a thread T, OpenGL ES will detect which context C was bound to T, and which surface S[draw] and S[read] were bound to C.
Multiple contexts
Sometimes, you want to create and use more than one context. Here is the rules for that case:Binding the same context in 2 threads is NEVER allowed.
Binding 2 different contexts in 2 different threads to the same surface is NEVER allowed.
Binding 2 different contexts in 2 different threads to 2 different surfaces MAY be allowed, but MAY fail (depending on the GPU implementation you are using).
Shared contexts
Shared contexts are useful in loading games. Because of the heavy of uploading data (especially textures) to GPU; if you want your game’s frame rate to be stable, you should run the uploading on another thread. Due to the threerules above, you must create a secondary context that uses the same internal state machine with the primary context. These primary and secondary contexts are called shared contexts.
Please note that, these two contexts share internal state machine only, they DO NOT share their command buffers.
To create the secondary context, you call:
EGLContext eglCreateContext( EGLDisplay display, EGLConfig config, EGLContext share_context, EGLint const * attrib_list);
The 3rd parameter share_context is important here, it is the primary context.
In the secondary thread, you should not draw anything, just upload data to GPU. Hence the surface that you use for this context should be a pixel buffer surface:
EGLSurface eglCreatePbufferSurface( EGLDisplay display, EGLConfig config, EGLint const * attrib_list);
eglSwapBuffers
EGLBoolean eglSwapBuffers(EGLDisplay display, EGLSurface surface);
At the first time I learned this function, I was thinking that its purpose is swapping the display and the surface :)) very silly.
Actually, the only thing that you need to focus here is the surface. If the surface is a pixel buffer surface, then nothing to do, the function returns without any error.
If the surface is a double-buffer surface (you often use this), the function will swap the front-buffer and the back-buffer inside the surface. The back-buffer is used to store output of rendering, while front-buffer is used by
the native window to show color on your monitors.
glFlush and glFinish
The OpenGL ES driver and GPU run in a parallel/asynchronous fashion. When you call a GL command, of course, the driver will try to send the command to GPU as soon as possible for best performance. However, the command will not be immediatelyexecuted by GPU, it is just added to a queue inside GPU. Hence, if you ask the driver to send too many GL commands in a short time, the GPU queue might be full so the driver has to keep those commands in the command buffer of the current context. (Do you remember
the command buffer of a context?)
That when these pending commands will be sent to the GPU is a question. In general, most OpenGL ES driver implementation may send these commands when there’s a new (next) GL command being called.
But if you need the sending to be explicitly happened, please call glFlush, this will block current thread until all commands to be sent to the GPU. glFinish is more powerful, it will block current
thread until all commands to be sent to GPU and completely executed by GPU. Be careful as your application’s performance will be declined.
glFlush and glFinish are called explicit synchronization. Sometimes, implicit synchronization might be happened. That is when the eglSwapBuffers command is
called. Because this command is directly executed by the driver, there’s a chance so that the GPU will draw pending glDraw* commands onto an unexpected surface buffer, since the front-buffer and back-buffer were swapped before. So, yes, as you are thinking,
before swapping, the driver must block current thread to wait for all pending glDraw* commands that affect the current surface being finished.
Of course, with double-buffer surfaces, you never need to call glFlush or glFinish because eglSwapBuffers performs an implicit synchronization. But with single-buffer surfaces (i.e. in the secondary
thread above), you MUST call glFlush on-time. For example, before the thread is exited, a call to glFlush is a MUST; otherwise, your GL commands might be NEVER sent to GPU.
相关文章推荐
- css3图片添加阴影
- 基于jQuery.validate及Bootstrap的tooltip开发气泡样式的表单校验组件思路详解
- 一个书页卷角的HTML&CSS效果
- javascript时间差插件分享
- Newtonsoft.Json(Json.Net)学习笔记
- JavaScript中函数节流的理解
- 一步一步写jQuery插件
- JavaScript 中一些值的比较,熟悉规范
- 一种跨域判断服务器是否宕机的JS解决办法
- jquery判断小数点两位跟自动删除小数两位后的数字
- Namenode HA原理详解(脑裂)
- 教你怎么写jQuery的插件
- Volley获取json数据乱码问题
- 前端基础 及遇到的问题
- [乐意黎转载]前端涉及的知识体系
- 如何用js实现鼠标向上滚动时浮动导航
- 终于实现了!精彩的jquery弹幕效果
- 【腾讯Bugly干货分享】深入理解 ButterKnife,让你的程序学会写代码
- 【POJ3294】 Life Forms (后缀数组+二分)
- css选择子项同类型的索引对象