转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=3304

个顶点。这样的数据对GPU来说是很头疼的。所以引擎往往需要在Buffer上做一些工作来改善渲染的性能。

由于在目前常见的架构上,CPU和GPU不能同时读写一块内存,CPU在写入数据的时候GPU只能读取另一个地方来渲染。所以一定需要某个机制,来避免这样的冲突。

:Discard

最古老的一个做法就是,自己维护一块内存,每一次需要画东西的时候先放在那块内存中。每一帧用一次discard的方式对GPU buffer做一次map,把数据拷贝进去。这么做很简单,所有复杂的同步都交给驱动去完成。

倍的内存空间,加上自己维护的那块内存,就需要3倍空间。同时,由于空间的申请和释放并不快,每一帧都这么做对性能来说有一定影响。

:No overwrite + Discard

自从图形API支持no overwrite了之后,就出现了一个新方法。不需要自己维护一块内存,而是在每次画东西的时候直接用no overwrite的方式map GPU buffer,把数据放进去。同时,记录下buffer是用了多少。如果已经满了,就用discard来map,抛弃旧有空间。

No overwrite避免CPU/GPU冲突的方式是由程序自己保证,CPU新的填充数据不覆盖到GPU需要用的数据,所以CPU和GPU总是在读写同一块内存的不同区域。这么做并不需要申请新空间,map的性能远高于discard。但是这么做仍会有不少时候会遇到空间满了需要discard。其实很多数据已经被GPU用完,完全可以复用而不必总discard。

更高效的方法:transient

重新考虑一下这个情景,可以发现如果是个CPU程序,需要反复申请和释放很多小块的内存,那么大家都会想到用memory pool。那么为何不把memory pool的思路用到这里来呢?GDC 2012上Don't Throw it all Away: Efficient Buffer Management中的Transient buffer正是如此。不久以前KlayGE的团队成员林胜华实现了ppt中所说的transient buffer,目前UI和文字都已经转成了用这种buffer管理方式。

Transient和思路和memory pool一样,都是基于free list管理一块空间。区别在于,CPU的memory pool,free list就保存在那块空间里,每个item包含了下一个未分配区域的指针。对于GPU buffer来说,平常需要让GPU用来渲染,所以不能处于map状态。所以free list是在CPU端单独维护,而每个item包含的是未分配区域在GPU buffer中的偏移量。通过这样的间接转换,就能在CPU端管理GPU buffer中的空闲非空闲区域了。接口方面,transient buffer和memory pool也非常相似,主要都是Alloc和Dealloc。在Alloc的时候,需要通过no overwrite来map内部的GPU buffer,把数据拷贝进去。因为有free list标记所有空闲区域,所以这时候是可以非常安全地使用no overwrite,而不用担心数据覆盖问题。

帧之后才真正被GPU使用。所以在transient buffer内部还需要维护一个列表,保存每一帧被Dealloc的数据,在3帧之后才真正把它标记成空闲区域。

那么,还剩一个问题是,满了怎么办。一个做法是discard,再把整个区域当作空闲区域。另一个做法是申请一个更大的GPU buffer,把旧的数据拷贝过去,并加长free list。第一种做法如果遇到一次Alloc就需要大于整个buffer空间的情况,还是需要退化到第二种做法。所以目前KlayGE里只实现了第二种。

不支持no overwrite的平台

对于OpenGL 3.0之前而且不支持GL_ARB_map_buffer_range,或者OpenGL ES 3.0之前而且不支持GL_EXT_map_buffer_range的平台,是没有no overwrite的能力的。对于这样的平台,原文没涉及。在KlayGE中,遇到这种情况会在CPU端维护一个和GPU buffer一样大的vector,并在渲染之前通过discard的方式拷贝给真正的GPU buffer。这保证了对上层程序来说,不必考虑no overwrite的支持度。这也是KlayGE的实现对原文的一个扩展。

未来

在目前的D3D11上,也就只能做到这个程度了。如果未来需要进一步加速,在OpenGL上可以考虑用GL_ARB_buffer_storage提供的GL_MAP_PERSISTENT_BIT,做到CPU和GPU同时使用一块Buffer的目的。D3D12改善了这点,也能同时使用,解除了目前的读写冲突。

另一方面,对于particle system那样非常规则地申请和释放内存的情况,原文中还提供了一个叫做Discard-Free Temporary Buffers的方法,来自于StarCraft 2。比transient buffer更适合这种使用模式。在以后我们也会做一些尝试。

 
 



来自 <http://www.klayge.org/2015/05/25/%E9%AB%98%E6%95%88gpu-buffer%E7%AE%A1%E7%90%86%E4%B9%8Btransient-buffer/>

(转)KlayGE游戏引擎 :高效的GBUFFER管理方式的更多相关文章

  1. [ZZ] KlayGE 游戏引擎 之 Order Independent Transparency(OIT)

    转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2233 http://dogasshole.iteye.com/blog/1429665 ht ...

  2. 最先进的开源游戏引擎KlayGE 4.3发布

    转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2536 经过KlayGE团队半年来的努力,今天KlayGE 4.3正式发布了!在这个版本的开发 ...

  3. 最先进的开源游戏引擎KlayGE 4.4发布

    转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2785 随着半年一个新版本的周期,今天KlayGE 4.4正式发布了!在这个版本的开发中,多名 ...

  4. 转:高层游戏引擎——基于OGRE所实现的高层游戏引擎框架

    高层游戏引擎——基于OGRE所实现的高层游戏引擎框架 这是意念自己的毕业论文,在一个具体的实践之中,意念主要负责的是物件和GUI之外的其他游戏系统.意念才学疏陋,望众位前辈不吝赐教.由于代码质量不高. ...

  5. 开源免费的HTML5游戏引擎

    青瓷引擎的成长 青瓷引擎自2015年4月项目启动开始,7月首次亮相2015年ChinaJoy,便得到业界的极大关注,随后开启限量测试,收到数百个开发者团队的试用申请及反馈,期间经历了18个内测版本,完 ...

  6. GJM : 各大开发游戏引擎

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  7. 转载:[转]如何学好3D游戏引擎编程

      [转]如何学好3D游戏引擎编程 Albert 本帖被 gamengines 从 游戏引擎(Game Engine) 此文为转载,但是值得一看. 此篇文章献给那些为了游戏编程不怕困难的热血青年,它的 ...

  8. 20个免费的 JavaScript 游戏引擎分享给开发者

    这篇文章收集了20个免费的 JavaScript 游戏引擎分享给开发者.这些游戏引擎能够帮助游戏开发人员更快速高效的开发出各种好玩的游戏. 使用 HTML5.CSS3 和 Javascript 可以帮 ...

  9. 开源免费的HTML5游戏引擎——青瓷引擎(QICI Engine) 1.0正式版发布了!

    青瓷引擎的成长 青瓷引擎自2015年4月项目启动开始,7月首次亮相2015年ChinaJoy,便得到业界的极大关注,随后开启限量测试,收到数百个开发者团队的试用申请及反馈,期间经历了18个内测版本,完 ...

随机推荐

  1. 从Java官网下载JDK1.6等低版本JDK

    今天在浏览Java官网的时候发现旧版本(1.8之前)的JDK安装包下载地址没有在下载页面明显的提供出来.个人通过在官网查看,发现oracle官方将旧版本的JDK全都放在Java Archive模块中了 ...

  2. svn更改地址怎么办

    开发过程中有时会遇到服务器更换地址的情况,比如之前地址是 svn://www.aaa.com 后来换成了 svn://www.bbb.com 这时候怎么办呢?分客户端和服务器端2种情况处理 客户端: ...

  3. centos 6.5 配置nginx环境

    1.卸载系统中默认的php和httpd [root@x ~]# yum remove httpd* php* Loaded plugins: fastestmirror Setting up Remo ...

  4. git中.gitignore 文件

    现在项目的根目录放了 .gitignore 文件,并且git远程仓库的项目根目录已经有了 logs文件夹. 由于每次本地运行项目,都会生成新的log文件,但是我并不想提交logs文件夹里面的内容,所以 ...

  5. 第51章 设置FLASH的读写保护及解除—零死角玩转STM32-F429系列

    第51章     设置FLASH的读写保护及解除 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...

  6. background和background-image一点小区别

    如果使用background-image属性,则no-repeat不能使用,因为其对background-image不起作用. 可以使用background属性,再设置no-repeat.

  7. django批量form表单处理

    1.应用说明 一般在表单信息录入中,如果存在许多重复提交的信息,我们就需要进行批量处理,比如学生信息的批量录入. 这里一种方式就是使用xlrd模块处理,把学生信息录入到系统内 另外一种方式就是采用我们 ...

  8. vue中登录模块的插件封装

    一个电商城的项目,场景是:在未登录的情况下点击收藏或者加入购物车等操作,执行一个方法如this.$login()来动态插入登录组件. 第一步:写好关于这个登录弹窗的单文件组件 loginBox.vue ...

  9. 触发ionic弹窗区域外的方法

    最近项目需要在页面弹窗的时候需要点击弹窗区域外的地方,其实也就是点击页面HTML就可以关闭弹窗, 首先在controller通过js获取到html的dom节点,然后绑定点击事件,话不多说上代码:   ...

  10. 对于未来学习Linux的决心书,以此为鉴

    学习Linux的决心书 我叫曹佳佳,来自祖国的大西北甘肃庆阳,2016年大专毕业之后从事自己的专业风力发电行业工作了两年多在从事风电行业的过程中越来越感觉到自己的薪资待遇和以后的发展空间越来越小,而且 ...