GLFW多上下文与多线程资源读取

感觉不惧英文后,能在网上找到很多更笃定、更自信的回答。

由于三维编程需要读取大量的资源,但是不能让窗口干等着啊,所以打算起新线程来读资源,主线程根据读取进度进行不同程度的渲染。

底层Opengl的API支持

Opengl是通过context间共享资源实现多线程加载的。虽然官方不太推荐,但是好歹给了一个方法。

GLFW封装的方法

但是我这从头学起的工程,都是基于GLFW编的,所以我就找了一圈,找到一个老司机的答案:

一老司机的回答

Make a second invisible window that has the main window as the parent (the last parameter is for list sharing)
E.g.: GLUtil::_loaderWindow = glfwCreateWindow(1, 1, “whatever”, nullptr, GLUtil::_mainWindow);
Create another thread and in its run()(or whatever) method call this: glfwMakeContextCurrent(GLUtil::_loaderWindow);

If you are using GLEW, build GLEW with the GLEW_MX define and call init() in the second thread as well. Read up on GLEW_MX about multithreaded usage. I strongly recommend boost thread specific pointers for this.

Remember to destroy the second window just like the main one. That’s it. I’ve been using this method for background resource loading for years and haven’t ran into any issues.

Hope it helps.

大意是直接用glfw通过与原上下文共享的方式创建新上下文即可,把新出现的窗口隐藏就行了。
然后主线程用主上下文,在资源读取线程中,将新的上下文设置为当前上下文即可。由于在创建时新的上下文使用了GLFWWindow作为最后一个参数,即与原上下文共享了列表(sharelist,一大堆显卡相关的东西),所以在使用新的上下文线程中可以进行shader编译、texture读取等等操作。

好吧,老司机说这么多年都这么过来了,我决定听老司机的了。

需要注意的事项

  1. OpenGL不允许在不同的context下共享顶点缓存(VAO)。
    所以顶点缓存还需要在主线程中创建。
    目前在线程中做的主要是将纹理的读取和处理放在非主线程中了。用c++11的std::thread非常方便,爱上新标准了。
  2. 在Load线程结束时需要加一句glfwMakeContextCurrent(mainWindow);具体原因还需要再看一下。