线程级并行计算在图形渲染引擎中的研究

赵建斌,李灵巧,杨辉华:线程级并行计算在图形渲染引擎中的研究2011, V ol.32, No.124143

0引言

更容易、更直接地利用硬件加速的3D 图形系统开发应用[4]。OGRE 是一款典型的串行方法设计的图形引擎,在多核系统下对其进行并行优化,将会大幅提高其性能。

2009年底,随着首次支持多线程渲染的图形API DirctX11的问世,并行计算方法在图形引擎中的应用成为热议话题,但在底层渲染层面的应用却鲜有相关研究。本文首先用OpenMP 方法对图形引擎的逻辑运算层面进行了并行优化,然后参考OpenMP 的Fork-Join 思路,结合Win32线程库和DirectX11的多线程支持提出了一种新的多线程渲染方法,实现了渲染层面的多线程。通过在带超线程技术的双核平台上的实验证明,该方法能有效提高渲染速率和CPU 利用率。

多核并行计算技术是当前计算机领域的研究热点。多核中的并行分为指令级并行(instruction-level parallelism ,ILP ) 和

线程级并行(thread-level parallelism ,TLP ) ,而线程级并行被普遍认为将是下一代高性能处理器的主流体系结构技术[1]。随着多核计算机的普及,线程级并行计算已经广泛用于计算机科学的多个领域[2],也正引领着程序设计由串行到并行的基础性变化[3]。然而在图形领域,通过大量的性能测试来看,GPU 性能仍占绝对主导,而CPU 只是考验单核性能,使用四核或者带超线程技术的“八核”处理器几乎不会有任何性能提升。这是因为目前大多图形应用程序中仍然采用单线程设计,并行计算技术只是应用于资源异步加载和音频独立线程等较浅层面,在多核成为大势所趋的情况下大量CPU 资源被浪费,瓶颈依然卡在CPU 上面。

面向对象图形渲染引擎(object-oriented graphics rendering engine ,OGRE ) 是当前流行的一款开源图形引擎,它是一个用C++开发的面向场景、非常灵活的3D 引擎,旨在让开发人员

收稿日期:2011-01-20;修订日期:2011-03-28。

1OGRE 渲染框架分析

对OGRE 进行多线程优化,首先要分析OGRE 的渲染循环框架。OGRE 通过面向对象的方法实现了一个从实际应用进入到图形引擎的入口,将开发图形应用程序开发人员从几何体级别的处理中分离出来,转而处理具体的场景和在场景中的物体。其中的物体包括:可活动的物体、静态物体组成的

41442011, V ol.32, No.12计算机工程与设计Computer Engineering and Design

的线程化,从而提高应用程序在多处理器系统上的性能[8]。

OpenMP 采用Fork-Join 执行模式。其工作原理为:①在开始执行的时候,只有主线程的运行线程存在;②主线程在运行过程中,当遇到需要进行并行计算的时候,派生出Fork 线程来执行并行任务(包括创建新线程或者唤醒已有线程) ;③在并行执行的时候,主线程和派生线程共同工作;④在并行代码结束执行后,派生线程退出或者挂起,不再工作,控制流程回到单独的主线程中,即Join [9]。如图2所示。

场景本身、灯光和摄像机等。开发人员只需简单的将物体放入场景中,OGRE 会完成杂乱的几何渲染处理,使其脱离对底层API 的依赖。OGRE 的面向对象渲染框架提供了包括全部

渲染过程的对象模型。渲染系统(render system ) 把复杂且底层的API (例如OpenGL 或DirectX ) 的功能抽象成一个统一的接口,场景图被抽象成另外一组接口,并且允许对不同的场景管理算法实现“即插即用”的调用。所有可渲染对象,无论动态还是静态,被抽象成一组接口,供具体的渲染系统调用[5]。

每一帧OGRE 的渲染都是从Root::renderOneFrame 函数开始,接着更新所有的渲染目标,渲染目标挂接到视口上,随视口更新。场景管理器负责更新场景中节点信息,经过视锥裁剪等操作后将可视节点放入渲染队列,然后交与Render System 按顺序对渲染队列中挂接到节点上的实体进行渲染[6],如图1所示。

OpenMP 中任务分配指令主要有section 和for 两个[10]。sec-tion 指令将函数分配至多个并行线程,for 指令将一个for 循环分割分配至多个并行线程。下面分别用这两个指令对逻辑帧

静态几何体

静态实体

动态实体

前两个过程实现并行化,以提升逻辑帧的生成速率,从而减少渲染帧的等待时间。

(1) 用section 指令实现资源初始化并行化

OGRE 中资源初始化阶段是各部分间依赖性最小,也最容易实现多线程的地方。用OpenMP 方法在.net 平台下优化方法如下:

void createScene (void ){

#pragmaomp parallel sections {#pragmaomp section {//…

Node_A=mSceneMgr->getRootSceneNode()->createChi-ldSceneNode ();

//…}

#pragmaomp section {//…

Node_B=mSceneMgr->getRootSceneNode()->create-ChildSceneNode ();

//…}}}

(2) 用for 指令实现节点信息更新并行化

在更新节点信息时,OGRE 中大量采用了vector 模式和multimap 模式的迭代循环,选取合适的位置用OpenMP 方法优化将提高逻辑帧的生成速率,减少渲染帧的等待时间。选取原则如下:

(1) 循环必须在生成渲染队列前结束,以免造成与渲染线程的同步问题;

(2) 在原则(1) 的基础上尽量选取最外层循环,以便实现最大程度的多线程优化[11]。

经过对OGRE 源码的分析,void RenderSystem::_updateAll-RenderTargets (bool swapBuffers ) 函数内部for 循环符合上述原

Render

System

图1OGRE 渲染框架

2

2.1

逻辑帧的多线程实现

OGRE 逻辑帧的串行实现原理及缺陷

我们人为地将OGRE 渲染过程分为两个阶段,处理逻辑

运算并填充渲染队列的过程称为逻辑运算阶段,简称逻辑帧;读取渲染队列并提交给Render System 渲染,最终输出图像的过程称为渲染阶段,简称渲染帧。OGRE 中逻辑帧的实现过程为:①通过实例化一个root 对象启动OGRE ,包括创建渲染窗口(render window ) ,创建摄像机,初始化资源,创建场景节点和绑定实体到子节点等;②通过迭代循环更新所有实体的位置信息、摄像机位置信息以及视口(viewport ) ;③将更新后的实体信息放入渲染队列中,与位置和视口信息一并供渲染帧调用。

由于OGRE 采用串行设计,渲染帧必须等待逻辑帧填充完每一帧的渲染队列之后才能执行,致使渲染帧会出现等待状态,造成CPU 资源浪费[6]。在多核平台下,通过对逻辑帧的并行优化,可以提升CPU 利用率,从而提高其生成速率并减少渲染帧的等待时间。

2.2基于OpenMP 的逻辑帧的并行化

OpenMP 是intel 极力推荐的一个多线程开发工具,是一

种编译指导语句,包括一套编译制导语句和一个用来支持它的函数库,能够显式指导多线程、共享内存并行的应用程序编程[7]。OpenMP 是可移植多线程应用程序开发的行业标准,在循环级别的细粒度与函数级别的粗粒度线程技术上具有很高的效率,通过自动处理迭代划分、线程调度等任务以实现循环

赵建斌,李灵巧,杨辉华:线程级并行计算在图形渲染引擎中的研究

则,用OpenMP 优化如下:

void RenderSystem::_updateAllRenderTargets(bool swapB-uffers ){

//…

#pragmaomp parallel for

for (itarg =mPrioritisedRenderTargets.begin (); itarg !=itargend; ++itarg){

//…

}

}

2011, V ol.32, No.124145

多线程技术支持下,每一帧画面可以被分为几个图层,每个图层又可以分为若干个区块,所有这些都可以被并行调度到延迟执行的线程之中,并最终合并到标识为立即执行(immediate context ) 的线程中,从而使得渲染不再受到CPU 瓶颈的制约[14]。

在渲染队列中,OGRE 根据绘制顺序将可视实体划分为多个优先级,优先级高的实体先于优先级低的实体绘制,相同优先级情况下则依照通路是否相同再次细分绘制顺序。根据RenderQueueGroupID 的不同,OGRE 中默认的绘制顺序为先天空体,后场景实体,最后绘制用户界面。

根据OGRE 上述特点,利用DirectX11的延迟执行技术,可以把场景实体(例如粒子系统、模型等) 的绘制放入延迟执行的线程中,在后台将资源做预先的存取(比如像素生成、纹理拾取、常数缓冲等) 并生成相应命令列表(command list ) ,主线程(即立即执行线程) 则同步生成渲染队列中的天空体和界面的绘制命令列表,最后执行所有线程的命令列表,从而实现渲染帧的多线程同步执行,实现原理如图4所示。

3

3.1

渲染帧的多线程实现

OGRE 渲染帧的串行实现原理及缺陷

OGRE 渲染帧从读取渲染队列开始。渲染队列是构成

Ogre 渲染流程和控制渲染效率的关键部分,主要起两个作用:①确保正确的绘制顺序。比如先绘制天空盒再绘制一般物体,最后绘制界面;②提高渲染效率。Ogre 将具有相同通路

(pass ) 的物体放在一起进行绘制,目的是尽可能减少渲染状态的切换[12]。场景中的所有物体在绘制前都被按一定顺序放入到一个特定的渲染队列中,每个场景管理器拥有一个Re-nderQueue 对象用来管理渲染队列。RenderQueue 这个类为每一个渲染队列组对象(RenderQueueGroup ) 保存一个索引编号(RenderQueueGroupID ) 作为排序依据,每个索引编号会再以通路细分优先级。渲染队列通过sort 方法完成全部排序工作,排序完成后最终通过renderSingleObjec 方法对渲染队列中物体逐个进行渲染。

文献[6]中采用将渲染循环分为两个相对独立的逻辑帧和渲染帧,创建更新队列的方法对OGRE 进行了优化,如图3所示。实验结果显示,该方法能有效提高场景组织较为简单的实例的渲染效率,但对于场景组织较为复杂的实例,优化效果

[6]

不明显。这是因为:对于复杂场景,渲染队列中通路(Pass ) 数目较多,完成一帧的渲染需多次切换渲染状态,每一次渲染状态切换都会带来额外的时间开销,致使瓶颈集中在渲染帧[13],而上述方法并没有对渲染帧做优化处理,渲染层面依然是单线程。对于图形应用程序,大部分时间开销来自几何体渲染阶段,对渲染帧进行并行化优化会极大提升图形应用程序的性能。

实现上述功能,需修改OGRE::D3D11Devices 和OGRE::SceneManager 类。程序设计如下:

(1) 在函数SceneManager::_renderScene()中统计静态几何体和场景实体个数N1、N2,以确定延迟执行上下文(deffered

context ) 数量。

(2) 创建指针数组存储渲染对象的延迟执行上下文和命令列表。

ID3D11DeviceContext *pDefferedPerStaticGeom[N1]; ID3D11DeviceContext *pDefferedPerSceneEntity[N2]; ID3D11CommandList *pCommandlist[N1+N2];

(3) 创建子线程,循环执行_render()函数使pDefferedPe-rSceneEntity [i ](i =1,2, …,N2) 得到矩阵变换、光照等绘制信息,循环结束后调用pDefferedPerSceneEntity [i ]->FinishCommand-List (false,&pCommandlist [i ])生成子线程命令列表,生成完毕执行SetEvent ()向主线程发送事件信号。

(4) 主线程并行填充pStaticGeomCommandlist [N1],并调用Wait-ForSingleObject ()函数等待子线程事件信号。若返回值为真,调用pDefferedPerStaticGeom [i ]->FinishCommandList (fasle,&pComma-

3.2渲染帧并行化的设计与实现

2009年10月22日,微软同步发布了Windows7操作系统

和DirectX11。与以往的DirectX 版本相比,最新的DirectX11首次引入了针对多核系统的多线程处理技术。它通过引入延迟执行的指令将一个渲染进程拆分为多个线程,并根据线程

数设定延迟执行上下文(Deffered Context ) 的数目。在DirectX11

41462011, V ol.32, No.12计算机工程与设计Computer Engineering and Design

ndlist [N2+i])(i =1,2, …,N1) 生成所有渲染对象的命令列表。

(5) 主线程调用ID3D11DeviceContext *pd3dContext->ExecuteCommandList (pCommandlist [i ],fasle ) (i =1,2, …,N1+N2) 执行所有绘制语句。

4实验结果与讨论

评价多线程图形应用程序性能的标准主要有FPS (每秒帧

数) 、CPU 利用率和均衡负载[15]。采用上述方法对OGRE 进行优化,实验平台为Intel CoreI5560双核处理器(采用超线程,可并行处理4个线程) ,4G 内存,A TIRadeonHD5650图形处理器。OGRE 版本为1.7.1,测试程序选择OGRE 中demo 程序。实验步骤:

(1) 备份RenderSystem_Direct3D11和OgreMain 两个插件。按2.2中方法修改OgreMain 中RenderSystem 类,按3.2中方法修改OgreMain 中SceneManager 类和RenderSystem_Direct3D11中D3D11Devices 类,编译生成新的DLL 插件。

(3) 测试OGRE 中原始的demo 程序的FPS 。

(4) 加载修改后的两个DLL 插件,重新生成demo 程序并测试其FPS 。

(4) 选取优化效果理想的demo 程序,测试优化前后其CPU 使用情况。优化前后的对比结果如表1所示。

表1

demo 程序Demo_BSP

Demo_LightingDemo_SkeletalAnimation

Demo_ParticleFXDemo_SmokeDemo_TerrainDemo_Water

层渲染的多线程,取得了理想的效果,证实了并行计算方法在图形渲染系统中的可行性。该方法是对最新图形API 技术的一次尝试,对用户图形处理器等硬件要求较高,但可以预见,随着多核系统的普及,OpenMP 和DirectX11多线程方法会越来越多的被应用到图形应用程序开发中。

参考文献:

[1][2][3]

提升比例17.6%

15.1%8.2%26.9%13.7%

陈国良, 孙广中, 徐云, 等. 并行化计算的一体化研究与发展趋势[J ]. 科学通报,2009,54(8) :1043-1049.

郑峰. 图像分析多核并行计算类库的构建与优化[D ]. 厦门:厦门大学,2008:17-20.

Gorder P F.Multicore processors for science and engineering [J ]. Computing in Science &Engineering,2007,9(2) :3-7.

邸锐.OGRE 3D 游戏开发框架指南[M ]. 北京:电子工业出版社, 2010:1-4.

孙益辉, 陈福民, 王海峰. 一种基于OGRE 图形引擎的实时分布式渲染系统[J ]. 计算机工程与应用,2008,44(31) :102-103.Jeff Andrews.Threading the OGRE 3D render system [OL ].http://www.intel.com/cd/ids/developer/asmo-na/eng/dc/games/331359.htm,2006.

优化前后平均FPS 对比

优化前平均FPS

[***********]431038

优化后平均FPS

[***********]66371135

[4][5][6]

从表1可以看出,本优化方法能够提升大多数测试程序的性能,平均提升率在15%,对于复杂场景的例子提升效果尤为明显,例如粒子系统实例(26.9%) 和BSP 场景管理实例(17.6%) 。对于地形管理实例(Demo_Terrain) ,由于其逻辑运算较为简单,渲染几何资源较少,而无论是OpenMP 方法还是Di-rectX11API 的多线程方法在创建新线程时都会带来额外的时间开销,较简单场景实例中这部分开销跟主线程时间开销在同一数量级,已不能忽略,使得优化后性能反而出现略微的下降。总体来看,本文提出的优化方案效果是理想的。

选取Demo_ParticleFX实例检测其CPU 使用情况,优化前后对比如图5所示。从图5看出,优化前CPU 的利用率为57%,优化后为66%,提升了约16%。通过CPU 使用记录对比可以看出,优化后4个处理核心都得到了充分的调度,负载更加均衡。

[7][8][9]

陈学亮. 基于多核平台优化的OGRE 3D 渲染引擎[D ]. 杭州:浙江大学,2007:33-39.

李妮, 陈铮. 多核并行计算技术在景象匹配仿真中的应用[J ]. 系统工程与电子技术,2010,32(2) :428-432.

蔡佳佳, 李名世, 郑锋. 多核微机基于OpenMP 的并行计算[J ]. 计算机技术与发展,2007,17(10) :87-91.

[10]张平, 李清宝, 赵荣彩.OpenMP 并行程序的编译器优化[J ]. 计算

机工程,2006,32(24) :37-40.

[11]奎因, 陈文光, 武永卫.MPI 与OpenMP 并行程序设计[M ]. 北京:

清华大学出版社,2004

[12]余忠德, 吴红艳, 林峰.DirectX 实时渲染技术详解[M ]. 重庆:重

庆大学出版社,2006:43-44.

[13]Bruce Dawson. Coding for multiple cores on Xbox 360and

Microsoft Windows [OL ].http://msdn.microsoft.com/en-us/li-brary/ee416321(v=vs.85) .aspx,2006.

[14]Microsoft MSDN.Immediate and deferred rendering [OL ].http://

msdn.microsoft.com/zh-cn/library/ff476892(v=VS.85) .aspx, 2011.

[15]陈颉, 周智, 黄刘生. 负载平衡在三维渲染中的应用[J ]. 计算机工

程与应用,2005,41(34) :65-68.

5结束语

当前图形处理器的硬件渲染流程都采用单线程设计,受

此限制在图形应用程序中尤其是渲染阶段中,并行计算方法始终无法深入,这方面的研究也鲜有报道。本文使用两种线程级并行方法对OGRE 两个层面进行了优化,针对OGRE 中渲染队列的特点并利用DirectX11的延迟执行技术实现了底

赵建斌,李灵巧,杨辉华:线程级并行计算在图形渲染引擎中的研究2011, V ol.32, No.124143

0引言

更容易、更直接地利用硬件加速的3D 图形系统开发应用[4]。OGRE 是一款典型的串行方法设计的图形引擎,在多核系统下对其进行并行优化,将会大幅提高其性能。

2009年底,随着首次支持多线程渲染的图形API DirctX11的问世,并行计算方法在图形引擎中的应用成为热议话题,但在底层渲染层面的应用却鲜有相关研究。本文首先用OpenMP 方法对图形引擎的逻辑运算层面进行了并行优化,然后参考OpenMP 的Fork-Join 思路,结合Win32线程库和DirectX11的多线程支持提出了一种新的多线程渲染方法,实现了渲染层面的多线程。通过在带超线程技术的双核平台上的实验证明,该方法能有效提高渲染速率和CPU 利用率。

多核并行计算技术是当前计算机领域的研究热点。多核中的并行分为指令级并行(instruction-level parallelism ,ILP ) 和

线程级并行(thread-level parallelism ,TLP ) ,而线程级并行被普遍认为将是下一代高性能处理器的主流体系结构技术[1]。随着多核计算机的普及,线程级并行计算已经广泛用于计算机科学的多个领域[2],也正引领着程序设计由串行到并行的基础性变化[3]。然而在图形领域,通过大量的性能测试来看,GPU 性能仍占绝对主导,而CPU 只是考验单核性能,使用四核或者带超线程技术的“八核”处理器几乎不会有任何性能提升。这是因为目前大多图形应用程序中仍然采用单线程设计,并行计算技术只是应用于资源异步加载和音频独立线程等较浅层面,在多核成为大势所趋的情况下大量CPU 资源被浪费,瓶颈依然卡在CPU 上面。

面向对象图形渲染引擎(object-oriented graphics rendering engine ,OGRE ) 是当前流行的一款开源图形引擎,它是一个用C++开发的面向场景、非常灵活的3D 引擎,旨在让开发人员

收稿日期:2011-01-20;修订日期:2011-03-28。

1OGRE 渲染框架分析

对OGRE 进行多线程优化,首先要分析OGRE 的渲染循环框架。OGRE 通过面向对象的方法实现了一个从实际应用进入到图形引擎的入口,将开发图形应用程序开发人员从几何体级别的处理中分离出来,转而处理具体的场景和在场景中的物体。其中的物体包括:可活动的物体、静态物体组成的

41442011, V ol.32, No.12计算机工程与设计Computer Engineering and Design

的线程化,从而提高应用程序在多处理器系统上的性能[8]。

OpenMP 采用Fork-Join 执行模式。其工作原理为:①在开始执行的时候,只有主线程的运行线程存在;②主线程在运行过程中,当遇到需要进行并行计算的时候,派生出Fork 线程来执行并行任务(包括创建新线程或者唤醒已有线程) ;③在并行执行的时候,主线程和派生线程共同工作;④在并行代码结束执行后,派生线程退出或者挂起,不再工作,控制流程回到单独的主线程中,即Join [9]。如图2所示。

场景本身、灯光和摄像机等。开发人员只需简单的将物体放入场景中,OGRE 会完成杂乱的几何渲染处理,使其脱离对底层API 的依赖。OGRE 的面向对象渲染框架提供了包括全部

渲染过程的对象模型。渲染系统(render system ) 把复杂且底层的API (例如OpenGL 或DirectX ) 的功能抽象成一个统一的接口,场景图被抽象成另外一组接口,并且允许对不同的场景管理算法实现“即插即用”的调用。所有可渲染对象,无论动态还是静态,被抽象成一组接口,供具体的渲染系统调用[5]。

每一帧OGRE 的渲染都是从Root::renderOneFrame 函数开始,接着更新所有的渲染目标,渲染目标挂接到视口上,随视口更新。场景管理器负责更新场景中节点信息,经过视锥裁剪等操作后将可视节点放入渲染队列,然后交与Render System 按顺序对渲染队列中挂接到节点上的实体进行渲染[6],如图1所示。

OpenMP 中任务分配指令主要有section 和for 两个[10]。sec-tion 指令将函数分配至多个并行线程,for 指令将一个for 循环分割分配至多个并行线程。下面分别用这两个指令对逻辑帧

静态几何体

静态实体

动态实体

前两个过程实现并行化,以提升逻辑帧的生成速率,从而减少渲染帧的等待时间。

(1) 用section 指令实现资源初始化并行化

OGRE 中资源初始化阶段是各部分间依赖性最小,也最容易实现多线程的地方。用OpenMP 方法在.net 平台下优化方法如下:

void createScene (void ){

#pragmaomp parallel sections {#pragmaomp section {//…

Node_A=mSceneMgr->getRootSceneNode()->createChi-ldSceneNode ();

//…}

#pragmaomp section {//…

Node_B=mSceneMgr->getRootSceneNode()->create-ChildSceneNode ();

//…}}}

(2) 用for 指令实现节点信息更新并行化

在更新节点信息时,OGRE 中大量采用了vector 模式和multimap 模式的迭代循环,选取合适的位置用OpenMP 方法优化将提高逻辑帧的生成速率,减少渲染帧的等待时间。选取原则如下:

(1) 循环必须在生成渲染队列前结束,以免造成与渲染线程的同步问题;

(2) 在原则(1) 的基础上尽量选取最外层循环,以便实现最大程度的多线程优化[11]。

经过对OGRE 源码的分析,void RenderSystem::_updateAll-RenderTargets (bool swapBuffers ) 函数内部for 循环符合上述原

Render

System

图1OGRE 渲染框架

2

2.1

逻辑帧的多线程实现

OGRE 逻辑帧的串行实现原理及缺陷

我们人为地将OGRE 渲染过程分为两个阶段,处理逻辑

运算并填充渲染队列的过程称为逻辑运算阶段,简称逻辑帧;读取渲染队列并提交给Render System 渲染,最终输出图像的过程称为渲染阶段,简称渲染帧。OGRE 中逻辑帧的实现过程为:①通过实例化一个root 对象启动OGRE ,包括创建渲染窗口(render window ) ,创建摄像机,初始化资源,创建场景节点和绑定实体到子节点等;②通过迭代循环更新所有实体的位置信息、摄像机位置信息以及视口(viewport ) ;③将更新后的实体信息放入渲染队列中,与位置和视口信息一并供渲染帧调用。

由于OGRE 采用串行设计,渲染帧必须等待逻辑帧填充完每一帧的渲染队列之后才能执行,致使渲染帧会出现等待状态,造成CPU 资源浪费[6]。在多核平台下,通过对逻辑帧的并行优化,可以提升CPU 利用率,从而提高其生成速率并减少渲染帧的等待时间。

2.2基于OpenMP 的逻辑帧的并行化

OpenMP 是intel 极力推荐的一个多线程开发工具,是一

种编译指导语句,包括一套编译制导语句和一个用来支持它的函数库,能够显式指导多线程、共享内存并行的应用程序编程[7]。OpenMP 是可移植多线程应用程序开发的行业标准,在循环级别的细粒度与函数级别的粗粒度线程技术上具有很高的效率,通过自动处理迭代划分、线程调度等任务以实现循环

赵建斌,李灵巧,杨辉华:线程级并行计算在图形渲染引擎中的研究

则,用OpenMP 优化如下:

void RenderSystem::_updateAllRenderTargets(bool swapB-uffers ){

//…

#pragmaomp parallel for

for (itarg =mPrioritisedRenderTargets.begin (); itarg !=itargend; ++itarg){

//…

}

}

2011, V ol.32, No.124145

多线程技术支持下,每一帧画面可以被分为几个图层,每个图层又可以分为若干个区块,所有这些都可以被并行调度到延迟执行的线程之中,并最终合并到标识为立即执行(immediate context ) 的线程中,从而使得渲染不再受到CPU 瓶颈的制约[14]。

在渲染队列中,OGRE 根据绘制顺序将可视实体划分为多个优先级,优先级高的实体先于优先级低的实体绘制,相同优先级情况下则依照通路是否相同再次细分绘制顺序。根据RenderQueueGroupID 的不同,OGRE 中默认的绘制顺序为先天空体,后场景实体,最后绘制用户界面。

根据OGRE 上述特点,利用DirectX11的延迟执行技术,可以把场景实体(例如粒子系统、模型等) 的绘制放入延迟执行的线程中,在后台将资源做预先的存取(比如像素生成、纹理拾取、常数缓冲等) 并生成相应命令列表(command list ) ,主线程(即立即执行线程) 则同步生成渲染队列中的天空体和界面的绘制命令列表,最后执行所有线程的命令列表,从而实现渲染帧的多线程同步执行,实现原理如图4所示。

3

3.1

渲染帧的多线程实现

OGRE 渲染帧的串行实现原理及缺陷

OGRE 渲染帧从读取渲染队列开始。渲染队列是构成

Ogre 渲染流程和控制渲染效率的关键部分,主要起两个作用:①确保正确的绘制顺序。比如先绘制天空盒再绘制一般物体,最后绘制界面;②提高渲染效率。Ogre 将具有相同通路

(pass ) 的物体放在一起进行绘制,目的是尽可能减少渲染状态的切换[12]。场景中的所有物体在绘制前都被按一定顺序放入到一个特定的渲染队列中,每个场景管理器拥有一个Re-nderQueue 对象用来管理渲染队列。RenderQueue 这个类为每一个渲染队列组对象(RenderQueueGroup ) 保存一个索引编号(RenderQueueGroupID ) 作为排序依据,每个索引编号会再以通路细分优先级。渲染队列通过sort 方法完成全部排序工作,排序完成后最终通过renderSingleObjec 方法对渲染队列中物体逐个进行渲染。

文献[6]中采用将渲染循环分为两个相对独立的逻辑帧和渲染帧,创建更新队列的方法对OGRE 进行了优化,如图3所示。实验结果显示,该方法能有效提高场景组织较为简单的实例的渲染效率,但对于场景组织较为复杂的实例,优化效果

[6]

不明显。这是因为:对于复杂场景,渲染队列中通路(Pass ) 数目较多,完成一帧的渲染需多次切换渲染状态,每一次渲染状态切换都会带来额外的时间开销,致使瓶颈集中在渲染帧[13],而上述方法并没有对渲染帧做优化处理,渲染层面依然是单线程。对于图形应用程序,大部分时间开销来自几何体渲染阶段,对渲染帧进行并行化优化会极大提升图形应用程序的性能。

实现上述功能,需修改OGRE::D3D11Devices 和OGRE::SceneManager 类。程序设计如下:

(1) 在函数SceneManager::_renderScene()中统计静态几何体和场景实体个数N1、N2,以确定延迟执行上下文(deffered

context ) 数量。

(2) 创建指针数组存储渲染对象的延迟执行上下文和命令列表。

ID3D11DeviceContext *pDefferedPerStaticGeom[N1]; ID3D11DeviceContext *pDefferedPerSceneEntity[N2]; ID3D11CommandList *pCommandlist[N1+N2];

(3) 创建子线程,循环执行_render()函数使pDefferedPe-rSceneEntity [i ](i =1,2, …,N2) 得到矩阵变换、光照等绘制信息,循环结束后调用pDefferedPerSceneEntity [i ]->FinishCommand-List (false,&pCommandlist [i ])生成子线程命令列表,生成完毕执行SetEvent ()向主线程发送事件信号。

(4) 主线程并行填充pStaticGeomCommandlist [N1],并调用Wait-ForSingleObject ()函数等待子线程事件信号。若返回值为真,调用pDefferedPerStaticGeom [i ]->FinishCommandList (fasle,&pComma-

3.2渲染帧并行化的设计与实现

2009年10月22日,微软同步发布了Windows7操作系统

和DirectX11。与以往的DirectX 版本相比,最新的DirectX11首次引入了针对多核系统的多线程处理技术。它通过引入延迟执行的指令将一个渲染进程拆分为多个线程,并根据线程

数设定延迟执行上下文(Deffered Context ) 的数目。在DirectX11

41462011, V ol.32, No.12计算机工程与设计Computer Engineering and Design

ndlist [N2+i])(i =1,2, …,N1) 生成所有渲染对象的命令列表。

(5) 主线程调用ID3D11DeviceContext *pd3dContext->ExecuteCommandList (pCommandlist [i ],fasle ) (i =1,2, …,N1+N2) 执行所有绘制语句。

4实验结果与讨论

评价多线程图形应用程序性能的标准主要有FPS (每秒帧

数) 、CPU 利用率和均衡负载[15]。采用上述方法对OGRE 进行优化,实验平台为Intel CoreI5560双核处理器(采用超线程,可并行处理4个线程) ,4G 内存,A TIRadeonHD5650图形处理器。OGRE 版本为1.7.1,测试程序选择OGRE 中demo 程序。实验步骤:

(1) 备份RenderSystem_Direct3D11和OgreMain 两个插件。按2.2中方法修改OgreMain 中RenderSystem 类,按3.2中方法修改OgreMain 中SceneManager 类和RenderSystem_Direct3D11中D3D11Devices 类,编译生成新的DLL 插件。

(3) 测试OGRE 中原始的demo 程序的FPS 。

(4) 加载修改后的两个DLL 插件,重新生成demo 程序并测试其FPS 。

(4) 选取优化效果理想的demo 程序,测试优化前后其CPU 使用情况。优化前后的对比结果如表1所示。

表1

demo 程序Demo_BSP

Demo_LightingDemo_SkeletalAnimation

Demo_ParticleFXDemo_SmokeDemo_TerrainDemo_Water

层渲染的多线程,取得了理想的效果,证实了并行计算方法在图形渲染系统中的可行性。该方法是对最新图形API 技术的一次尝试,对用户图形处理器等硬件要求较高,但可以预见,随着多核系统的普及,OpenMP 和DirectX11多线程方法会越来越多的被应用到图形应用程序开发中。

参考文献:

[1][2][3]

提升比例17.6%

15.1%8.2%26.9%13.7%

陈国良, 孙广中, 徐云, 等. 并行化计算的一体化研究与发展趋势[J ]. 科学通报,2009,54(8) :1043-1049.

郑峰. 图像分析多核并行计算类库的构建与优化[D ]. 厦门:厦门大学,2008:17-20.

Gorder P F.Multicore processors for science and engineering [J ]. Computing in Science &Engineering,2007,9(2) :3-7.

邸锐.OGRE 3D 游戏开发框架指南[M ]. 北京:电子工业出版社, 2010:1-4.

孙益辉, 陈福民, 王海峰. 一种基于OGRE 图形引擎的实时分布式渲染系统[J ]. 计算机工程与应用,2008,44(31) :102-103.Jeff Andrews.Threading the OGRE 3D render system [OL ].http://www.intel.com/cd/ids/developer/asmo-na/eng/dc/games/331359.htm,2006.

优化前后平均FPS 对比

优化前平均FPS

[***********]431038

优化后平均FPS

[***********]66371135

[4][5][6]

从表1可以看出,本优化方法能够提升大多数测试程序的性能,平均提升率在15%,对于复杂场景的例子提升效果尤为明显,例如粒子系统实例(26.9%) 和BSP 场景管理实例(17.6%) 。对于地形管理实例(Demo_Terrain) ,由于其逻辑运算较为简单,渲染几何资源较少,而无论是OpenMP 方法还是Di-rectX11API 的多线程方法在创建新线程时都会带来额外的时间开销,较简单场景实例中这部分开销跟主线程时间开销在同一数量级,已不能忽略,使得优化后性能反而出现略微的下降。总体来看,本文提出的优化方案效果是理想的。

选取Demo_ParticleFX实例检测其CPU 使用情况,优化前后对比如图5所示。从图5看出,优化前CPU 的利用率为57%,优化后为66%,提升了约16%。通过CPU 使用记录对比可以看出,优化后4个处理核心都得到了充分的调度,负载更加均衡。

[7][8][9]

陈学亮. 基于多核平台优化的OGRE 3D 渲染引擎[D ]. 杭州:浙江大学,2007:33-39.

李妮, 陈铮. 多核并行计算技术在景象匹配仿真中的应用[J ]. 系统工程与电子技术,2010,32(2) :428-432.

蔡佳佳, 李名世, 郑锋. 多核微机基于OpenMP 的并行计算[J ]. 计算机技术与发展,2007,17(10) :87-91.

[10]张平, 李清宝, 赵荣彩.OpenMP 并行程序的编译器优化[J ]. 计算

机工程,2006,32(24) :37-40.

[11]奎因, 陈文光, 武永卫.MPI 与OpenMP 并行程序设计[M ]. 北京:

清华大学出版社,2004

[12]余忠德, 吴红艳, 林峰.DirectX 实时渲染技术详解[M ]. 重庆:重

庆大学出版社,2006:43-44.

[13]Bruce Dawson. Coding for multiple cores on Xbox 360and

Microsoft Windows [OL ].http://msdn.microsoft.com/en-us/li-brary/ee416321(v=vs.85) .aspx,2006.

[14]Microsoft MSDN.Immediate and deferred rendering [OL ].http://

msdn.microsoft.com/zh-cn/library/ff476892(v=VS.85) .aspx, 2011.

[15]陈颉, 周智, 黄刘生. 负载平衡在三维渲染中的应用[J ]. 计算机工

程与应用,2005,41(34) :65-68.

5结束语

当前图形处理器的硬件渲染流程都采用单线程设计,受

此限制在图形应用程序中尤其是渲染阶段中,并行计算方法始终无法深入,这方面的研究也鲜有报道。本文使用两种线程级并行方法对OGRE 两个层面进行了优化,针对OGRE 中渲染队列的特点并利用DirectX11的延迟执行技术实现了底


相关文章

  • 毛熊一家:从软件角度818兔子的后发优势(6)
  • 2013到2017的五年,是兔子秀肌肉,威吓霉菌的时候. 大家等着看一个又一个的精彩大戏吧. 很明显的一点,兔吧的很多都没看出来,就是现在兔子的官方媒体,都变得很文雅很克制,啥重大实验,收费,射蛋蛋,都是国外媒体先报导,网络跟风,记者提问, ...查看


  • 网络爬虫的设计与实现(完整版)
  • 网络爬虫的设计与实现 摘 要 网络爬虫将下载的网页和收集到的网页信息存储在本地数据库中以供搜索引擎使用,它是一个专门从万维网上下载网页并分析网页的程序.随着网络的快速发展,人们对搜索引擎的要求也越来越高,而网络爬虫的效率直接影响着搜索引擎的 ...查看


  • EOS工作流引擎工作原理
  • 1. 工作流基础知识 -- 2. EOS工作流引擎工作原理 本文是我在工作之余写的一点我对EOS工作流的了解,我的理解不一定全是对的,可能会与引擎的真正的面目有出入.所以只能提供给大家一点参考. 2.1. EOS工作流引擎核心调度算法 EO ...查看


  • 网络处理器设计的复杂性
  • 网络处理器设计的复杂性 李华伟 网络处理器(Network Processor,简称NP )是面向网络应用领域的专用指令处理器(Application Specific Instruction Processor ),是面向数据分组处理的. ...查看


  • Web信息采集技术研究与发展
  • 第27卷第12期2009年12月 情报科学 Vol. 27, No. 12December,2009 ·综述· Web 信息采集技术研究与发展 庞景安 (中国科学技术信息研究所, 北京100038) 摘要:本文对Web 信息采集技术的重要研 ...查看


  • 常见英语缩写
  • [转] 常见英文缩写 常用英文缩写 VIP = very important person重要人物 IMP (import)进口 EXP (export)出口 MAX (maximum)最大的.的最大限度的 MIN (minimum)最小的 ...查看


  • 特殊英语词汇
  • ASIC: Application Specific Integrated Circuit(特殊应用积体电路) ASC (Auto-Sizing and Centering,自动调效屏幕尺寸和中心位置) ASC (Anti Static C ...查看


  • 基于并行粒子群优化算法的蛋白质二级结构预测
  • 第31卷第5期周口师范学院学报 2014年9月基于并行粒子群优化算法的蛋白质二级结构预测 周文刚1,毋红军2,孙 挺1 (1.周口师范学院计算机科学与技术学院,河南周口466001: 2.华北水利水电大学数学与信息科学学院,河南郑州4500 ...查看


  • 计算机体系结构的现状及其发展趋势VLIW 指令系统
  • 计算机体系结构的现状及其发展趋势 庞春江 孟建良 王晓华 (华北电力大学计算机系,保定071000) 摘 要 该文系统概述了现代计算机的两种主要体系结构CISC 体系和RISC 体系,指出了基于冯・诺伊曼体系结构的 现代计算机体系存在的问题 ...查看


热门内容