DX11多线程学习与思考

来源:互联网 发布:淘宝太坑了女主角视频 编辑:程序博客网 时间:2024/05/19 03:27

http://blog.csdn.net/randerwang/article/details/6316282

 

多线程支持是DX11的几大改进之一,也是顺应了多核的潮流。在DX最新的实现中引入一个新的Context, 叫Defered Context,而原来的Context叫immediate Context,这两个Context一起来完成multi-thread支持。程序开始创建几个Defered Context,并将application的场景分为几个部分,每个部分分别由不同的Defered Context来render。这里的render并不是交给Hardware去render,而是生成DX的DDI命令,然后将这些命令送给immediate Context去真正送给hardware render。微软引入displaylist这个概念来描述这个过程,当然它还特意说明了这是借用了某些图形库的想法,可偏偏就不说明是OpengL。具体过程如下图。

 

这里有几个疑问,

(1)     每个线程每个Context需要同步吗

(2)     每个线程render的算法是有driver来保证还是有程序来保证呢

(3)     每个线程是如何保持Context的正确性呢

(4)     Driver有哪些地方需要保证线程安全,会不会有bottleneck呢

(5)     OpenGL是否也可以借鉴呢

(6)     这种模型是否可以改进呢

 

根据DX11 SDK中的sample来看,第一个问题每个defered Context线程之间不需要同步,但是他们需要和immediate Context 线程同步。 认真想想微软的实现,这个是必须的。由于immediate Context线程是主线程,同时也是真正的render线程, 其他defered Context线程是辅助线程,只完成场景中某部分的render,所以主线程必须等其他辅助线程全部完成才能完全的render一个frame。这些等待的算法可以由类似于linux的pthread的wait、sync来完成

 

对于第二个问题,根据各种资料看来还是有程序本身来保证的,即由程序员来分配各个线程的render工作。对于某些问题如Alpha blend的问题,如果程序交由两个线程来完成,其正确性是由程序保证,而不是微软的DX runtime或者是各个vendor的driver。从这个意义上说来, 多线程算法的实现对程序员来说绝对是个挑战,而不免费的蛋糕。

 

第三个问题也是很重要的问题。大家知道当程序由一个线程来render的时候其Context只有一个,下面一个draw继承前一draw的Context, 同时可能有些修改,如改变transform的matrix等等,当然也可以完全不变。当有多线程时,问题就复杂了。每个线程都有自己的Context,但是自己的Command list却是交给immediate Context线程去执行的,那Context怎么办。微软的办法是每个Command list 执行前有微软自己来保证其Context都是default状态,同时每个Defererd Context 必须在画之前设定自己的context, 即在其command list中要包含context设置的command。这样实际上是相当于多个context在那不停的切换,当然这也是必须的

 

第四个问题很重要, 线程安全是必须的。根据前面给出的模型,只有immediate context线程才是真正的render线程,所以微软的patch,render, present 都是安全,但是create resource ,lock,map呢?这些操作都不是放在command list中的,而且defered context线程也是必须支持这些操作,利用它们来完成资源的载入,这样就可以节省时间。这就要求driver必须能在resource的操作上是线程安全的。当然对于多个线程同时分配resource,原有的单线程分配算法是否快速,这就是一个问题。关于这方面的论文很多,大家可以去查一下多线程下的堆分配算法,这里由于某些原因我就不解释了。对于那些多个线程共享的resource怎么办? 如果数个线程都map了如何保证正确性?这种问题对于任何多线程的程序都是一个挑战,而不仅仅是DX。办法也是通用的,就是你尽量避免共享resource,同时大部分情况下是可以避免的。对于某些不能避免的情况,可以利用resource的rename机制来绕过去。当然对于opengl的fbo, DX的render target来说这是必须面对的,这只能加入flush机制了

 

     第五个问题对linux下工作的同事来说是相当关心的,毕竟只有opengl才能工作。不过很伤心的告诉大家,opengl是不能简单的照抄的,因为其图形接口有很大的不同。DX有一个runtime,defered context所在线程调用的图形库接口全被其转化为相应的DDI接口调用序列,存储 在command list中,并且通过它送给immediate thread。而作为opengl在windows根本没有这么一个runtime, 也没有办法作出这么一个runtime,因为这一切都被微软限定死了。 在linux下面,这种方法是可以借鉴,因为libGL可以是每个vendor自己开发的。 当然这首先必须opengl 本身引入这些接口,否则一切都是空谈。那opengl是否无法利用多线程呢,答案是否定的,利用生产者|消费者模型照样可以加速。

 

                最后一个问题,答案是肯定的。现在的command list并不是转化成了机器码,而是一种DDI的中间形式,这并没有节省driver的时间,因为它并没有把driver时间平分到各个CPU。

当然微软这么做考虑到尽量减少vender开发driver的难度,它这样设计driver并不需要改多少东西。

 

 

                最后推荐大家去看一看GDC2011的ppt,上面有其他角度讨论这方面的东西。