在OpenGL里面使用多线程加载纹理是很美好的构想。
网上讨论这个的并不多。中文博客里http://www.cnblogs.com/mazhenyu/archive/2010/04/29/1724190.html
参考了某个老外的尝试:
http://veelck.wordpress.com/2008/11/28/multithread-texture-loading-in-opengl/
其基本思路如下:
要创建新的rendering context (RC), 先需要device context(DC).
DC可以在得到HWND后得到:HDC hDC = GetDC(hWnd);
接下来使用Windows extension函数:wglCreateContext创建RC。如果失败返回NULL。
在这里我们用1个hDC创建2个RC:
HGLRC rendContext1 = wglCreateContext(hDC);
HGLRC rendContext2 = wglCreateContext(hDC);
接下来我们用1个RC加载图片,一个用来渲染。困难的是你必须共享2个RC之间的资源。
因为你在一个RC中创建的纹理在另外一个RC中是不可访问的,反之亦然。
使用这个方法共享RC:
wglShareLists(rendContext2, rendContext1);
最好在调用context任何操作前完成这个操作!最好在与OpenGL做任何交互前调用。
现在可以在不同线程里使用RC了。不需要每次都使用,只需要在线程开始前调用即可。
renderingThread()
{
//...
wglMakeCurrent(hDC, rendContext1);
//...
wglDeleteContext(rendContext1);
}
loadingThread()
{
//...
wglMakeCurrent(hDC, rendContext2);
//...
wglDeleteContext(rendContext2);
}
再次注意,wglShareLists 只能在进程内工作。所以使用多线程而不是多进程。
wglMakeCurrent只是设置本线程的默认RC。所以并不关心其他线程在干什么。
现在你可以在Load线程里放心的调用图片加载,如glGenTextures、glTexParameteri、glTexImage2D了。
而Render线程也可以访问Load线程的资源。
如果你想在Render线程里也加载图片,记住某些图片库( DevIL)不支持多线程加载。自己去做线程互斥把。
我没有尝试多线程渲染。但从网上资料来看,即使有也没有意义。 OpenGLz的contexts切换会带来大量额外负担。
在进程的最后要释放并删除contexts。
wglMakeCurrent(NULL, NULL).
====================================================
以上是作者的基本思路。
在我的项目里,我尝试用一个线程专门用于动态加载纹理。
看上去运行的不错。不幸的是,当纹理加载频率教高的时候,纹理会出现白框和闪烁。
在ATI的某些显卡上效果会好很多,基本看不到奇怪现象;在NV的显卡上相当明显。
这个问题尚没有完美解决。基本只能在多线程里将纹理读到内存,然后在主渲染线程里读入显存。