这段时间,我对基于硬件的辐射度生成算法进行了多线程优化.使用256*256的光照图时性能的提升大约为1/6,远远没有达到预期的效果.
主要有这样一些原因:
1.最主要的问题在于这个算法不只是受限于CPU的,同时也是受限于GPU的.而最主要的瓶颈在于CPU和GPU之间存在着严重的相互等待现象,这主要是从GPU读取大量的纹理数据造成的.程序在单线程模式下CPU占用率50%(可能是由于回读纹理时系统使用的是热等待),但GPU只有可怜的40%左右.而使用了基于线程池(Thread Pool)的多线程方法后CPU占用率只提高到68%,而GPU也只提高了10%.
2.OPENGL本身不是线程安全的,每个线程只能使用一个context,从下面这段文字可以看出,每个线程一个context主要带来了两方面的开销:
首先,在不同的context之间频繁切换是一笔不小的开销,
其次,不同的context需要使用独立的内存,当内存需要大于显存空间的时候会造成大量的内存交换,造成新的性能问题.
3.驱动可能根本没有考虑同时使用两个独立context的问题,因为我使用了完全独立的context,还需要把所有的绘制操作放到互斥区(Critical Section)中.否则会出现严重的冲突问题,估计是两个独立的context之间仍然存在冲突.
即使把所有的绘制操作全部放到互斥区中,仍然不能解决所有问题.如下图,
呆会更新了驱动再试.
下面引用自:parallel OpenGL FAQ
Using Multiple OpenGL contexts with one Graphics Card
- Q: How should I update multiple windows on one graphics card?
- A: It is advisable to minimize switching between different contexts. If the draw operation is not CPU-bound, the windows should be updated sequentially. If the draw operation is CPU-bound, the CPU-intensive part should be pipelined with the draw thread (see Section 2) while still updating the windows sequentially from the draw thread. If that is not feasible, updating the windows from multiple threads might be faster on a multicore machine.
- Q: Why is my application so slow when rendering from multiple threads?
- A: The OpenGL driver has to schedule the threads on a single hardware resource. This causes a lot of context switching, which is particularly slow when each context uses a lot of GPU memory. Try updating your windows sequentially.
- Q: How can I minimize the memory used by multiple OpenGL contexts?
- A: Share the context by using the appropriate option to glXCreateContext, aglCreateContext or wglShareLists. Create your OpenGL objects (textures, VBO's, etc.) in one context and then use them in all the other contexts.