OpenGL渲染中有一个线程相关
的上下文(Context), OpenGL所创建的资源, 其实对程序员可见的仅仅是上下文ID
而已, 其内容依赖于这个上下文, 有时候为了方便起见, 在某个线程中创建了上下文之后, 所有的OpenGL操作都转到此线程来调用. 这样在简单的2d/3d 渲染中尚可, 但是如果涉及复杂的OpenGL渲染时, 这样就未必足够, 事实上OpenGL已经考虑到这一点, 上下文是可以在多个线程间共享的
,在使用glXCreateContext
或eglCreateContext
时, 可以传入一个已创建成功的上下文, 这样就可以得到一个共享的上下文(Shared Context).
OpenGL的绘制命令都是作用在当前的Context上,这个Current Context是一个线程私有(thread-local)的变量
,也就是说如果我们在线程中绘制,那么需要为该线程制定一个Current Context的,当多个线程参与绘制任务时,需要原线程解绑再重新绑定新的线程。多个线程不能同时指定同一个Context为Current Context,否则会导致崩溃。
共享上下文
一个是进程可以创建多个Context,它们可以分别描绘出不同的图形界面,就像一个应用程序可以打开多个窗口一样。每个OpenGL Context是相互独立的,它们都有自己的OpenGL对象集。但有时会有场景需要多个上下文使用同一份纹理资源的情况,创建Context,意味着系统资源的占用,同一份纹理重复申请会造成资源浪费,因此OpenGL上下文允许共享一部分资源。大部分OpenGL Objects是可以共享的,包括Sync Object
和GLSL Objects
。Container Objects
和Query Objects
是不能共享的。例如纹理、shader、Buffer等资源是可以共享的,但Frame Buffer Object(FBO)、Vertex Array Object(VAO)等容器对象不可共享,但可将共享的纹理和VBO绑定到各自上下文的容器对象上。
- 共享资源:
纹理
、shader
、Buffer
- 不共享资源:
FBO
, VAO
EGL Context
1 2 3 4
| EGLContext eglCreateContext(EGLDisplay display, EGLConfig config, EGLContext share_context, EGLint const * attrib_list);
|
GLX Context
1 2 3 4
| GLXContext glXCreateContext(Display * dpy, XVisualInfo * vis, GLXContext shareList, Bool direct);
|
GLX创建共享上下文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| GLXContext currctx = glXGetCurrentContext(); GLXFBConfig* fb_config; int fb_config_id; int nelements; int res;
XInitThreads();
Display* dpy = XOpenDisplay(NULL); assert(dpy != NULL)
res = glXQueryContext(dpy, currctx, GLX_FBCONFIG_ID, &fb_config_id); assert(res);
int visual_attribs[] = { GLX_FBCONFIG_ID, fb_config_id, None }; fb_config = glXChooseFBConfig(dpy, DefaultScreen(dpy), visual_attribs, &nelements); assert(fb_config);
int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 0, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, None }; GLXContext glx_share_context = glXCreateContextAttribsARB(dpy, fb_config[0], currctx, True, context_attribs); assert(glx_share_context);
|
上下文切换
在执行OpenGL函数之前,必须将切换到其当前的上下文进行处理
EGL
1 2 3 4
| EGLBoolean eglMakeCurrent(EGLDisplay display, EGLSurface draw, EGLSurface read, EGLContext context);
|
1
| eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context);
|
GLX
1 2 3
| Bool glXMakeCurrent(Display * dpy, GLXDrawable drawable, GLXContext ctx);
|
参考
- https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglCreateContext.xhtml
- https://khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXCreateContext.xml
- https://www.khronos.org/registry/EGL/sdk/docs/man/html/eglMakeCurrent.xhtml
- https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXMakeCurrent.xml
- OpenGL中的上下文 理解整理
- GLX Reference Pages
- EGL Reference Pages