D3D如何做多线程异步资源加载? fg5823820 电梯直达 1# 发表于 2011-12-28 20:19:35 | 只看该作者 其实我现在用的引擎是HGE,这里貌似是3D引擎板块,不知道会不会被砍掉。虽然HGE是2D引擎,但底层是D3D的。玩过尘埃2的一定知道,尘埃2在加载的时候会有各种动画让你不至于在加载的时候干等。于是我对这样的技术很感兴趣,假如不是很吃内存的游戏,那么在当前关卡进行时就加载下一关,那么进入下一关的时候玩家就不需等待。于是去尝试用多线程异步加载资源,这样就不会在加载的时候影响到游戏的循环。HGE里的纹理加载函数是Texture_Load,去看底层实现则是先将纹理载入内存,然后直接用D3D的D3DXCreateTextureFromFileInMemoryEx。事实上我在这里卡住了,一旦子线程里调用Texture_Load,屏幕就会有一定几率闪烁,轻微的时候是游戏里的某些单位闪烁,严重的时候整个屏幕都会闪烁,后来查了相关资料得知DX8/9不支持多线程。HGE是基于DX8,即使换成DX9也是一样。不过这种现象在不同电脑上的表现不同,似乎是显卡越差的机子闪烁越厉害,已经排除是帧数的关系。于是我尝试将IO交给子线程,D3DXCreateTextureFromFileInMemoryEx只在主线程里执行,也就是D3D的操作都在一条线程里执行。但结果很糟糕,IO的时候的确没有问题了,但当纹理由内存转到显存的时候,游戏就会明显顿一下,崩溃ing…… 分享到: 微信 收藏2 分享 回复 使用道具 举报 lidudu 2# 发表于 2011-12-28 20:51:16 | 只看该作者 D3D9支持多线程,但必须在创建时传一个请求多线程的flag,否则不是线程安全的。当然,这个多线程只是说你可以从多个线程同时访问。D3DXCreateTextureFromFileInMemoryEx 这个函数做了太多的事情,其中只有最后一步创建d3d texture对象时需要D3D device,其他的部分都可以交给子线程。 回复 支持 反对 使用道具 举报 fg5823820 3# 楼主 | 发表于 2011-12-28 21:28:10 | 只看该作者 本帖最后由 fg5823820 于 2011-12-28 21:28 编辑 lidudu 发表于 2011-12-28 20:51 D3D9支持多线程,但必须在创建时传一个请求多线程的flag,否则不是线程安全的。 当然,这个多线程只是说你 ... 据说加了多线程标记会使D3D性能降低,虽然我没发现有多少降低,不过加了之后的确能大大减少闪烁的几率但不能消除,大概如你所说只能进行访问,而创建纹理会修改。至于D3DXCreateTextureFromFileInMemoryEx 函数,这个函数不是需要传一个D3D设备指针吗,百思不得其解 回复 支持 反对 使用道具 举报 congy 4# 发表于 2011-12-28 22:31:11 | 只看该作者 要彻底解决此问题,就自己实现纹理 Streaming 功能,每帧分一些时间片加载纹理,或者丢到另一个线程中去加载,注意我说的是加载到显存中,而不是 IO。 回复 支持 反对 使用道具 举报 sssa2000 5# 发表于 2011-12-28 23:07:36 | 只看该作者 dx10的sample里有你想要的答案 回复 支持 反对 使用道具 举报 crazii 6# 发表于 2011-12-28 23:08:02 | 只看该作者 我也是后台IO,主线程填充显卡资源,貌似还没有遇到卡的问题,可能是数量小.呵呵你看看每帧创建的texture数量是多少,如果大的话,可能会卡,可以试试分帧提交.还有看看主线程创建texture有没有等待IO线程或者同步锁.理论上不需要任何同步的开销. 回复 支持 反对 使用道具 举报 lidudu 7# 发表于 2011-12-29 12:28:43 | 只看该作者 fg5823820 发表于 2011-12-28 21:28 据说加了多线程标记会使D3D性能降低,虽然我没发现有多少降低,不过加了之后的确能大大减少闪烁的几率但不 ... 一、我说的访问是access,包括读写二、D3DX函数是辅助函数库,都是基于D3D API写的,只是用到了D3D而已。你自己写个函数来加载图片、解码图片、放缩到2的指数次方、最后创建D3D纹理对象,效果一样。 回复 支持 反对 使用道具 举报 clayman 8# 发表于 2011-12-29 12:53:23 | 只看该作者 http://www.microsoft.com/downloa ... ang=en&id=18367 回复 支持 反对 使用道具 举报 fg5823820 9# 楼主 | 发表于 2011-12-29 15:37:37 | 只看该作者 lidudu 发表于 2011-12-29 12:28 一、我说的访问是access,包括读写 二、D3DX函数是辅助函数库,都是基于D3D API写的,只是用到了D3D而已 ... 自己写个函数来加载图片、解码图片、放缩到2的指数次方、最后创建D3D纹理对象,这个对我来说似乎有点困难,我还是先尝试下4楼的方法。 回复 支持 反对 使用道具 举报 fg5823820 10# 楼主 | 发表于 2011-12-29 17:37:56 | 只看该作者 clayman 发表于 2011-12-29 12:53 http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=18367 因为平台是XP,所以和DX10无缘了 回复 支持 反对 使用道具 举报 clayman 11# 发表于 2011-12-29 18:21:25 | 只看该作者 少年,你看了没有,里面讲了从dx9~11的线程模型 回复 支持 反对 使用道具 举报 glcolor 12# 发表于 2011-12-29 20:31:12 | 只看该作者 这几天也在做多线程资源加载的工作,要把原先的单线程引擎改造成支持多线程加载,一团乱麻啊 回复 支持 反对 使用道具 举报 fg5823820 13# 楼主 | 发表于 2011-12-29 21:03:40 | 只看该作者 clayman 发表于 2011-12-29 18:21 少年,你看了没有,里面讲了从dx9~11的线程模型 的确有讲,谢了。可惜讲的还是比较简单啊,比如创建纹理后填充,但是解压资源的过程却交给加载线程,那加载过程渲染线程岂不是要干等着(卡住),不过应该可以事先解压好。里面也提到了闪烁问题,不过我英文不好那块恰好看不懂Lock & Unlock on D3D9 can have strange behavior when they span frame boundaries Untested code path 未经测试的代码路径? After the Unlock, execute a quick Lock & Unlock in succession to avoid corruption 解锁后执行一个快速的加锁解锁来避免腐败?不太明白这两句是解决闪烁的方法还是闪烁产生的原因 回复 支持 反对 使用道具 举报 crazii 14# 发表于 2011-12-29 22:51:26 | 只看该作者 clayman 发表于 2011-12-29 12:53 http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=18367 多谢clay叔 回复 支持 反对 使用道具 举报 新乞丐王子 15# 发表于 2011-12-29 22:57:33 | 只看该作者 珍惜生命,放弃XP,远离DX9! 回复 支持 反对 使用道具 举报 sssa2000 16# 发表于 2011-12-29 23:24:24 | 只看该作者 哪有主动选择dx9的人,都是被逼无奈啊,能自己选的话肯定都去dx11了 回复 支持 反对 使用道具 举报 fg5823820 17# 楼主 | 发表于 2011-12-30 09:11:46 | 只看该作者 sssa2000 发表于 2011-12-29 23:24 哪有主动选择dx9的人,都是被逼无奈啊,能自己选的话肯定都去dx11了 是啊,都是被逼的,玩家们就是抱着XP不放,经销商认为XP稳定,这有什么办法 回复 支持 反对 使用道具 举报 yulier 18# 发表于 2011-12-31 12:44:24 | 只看该作者 wellbye 发表于 2011-12-29 22:54 呵呵,又看到有人来踩雷了啊。可以翻下我在基础版发的相关帖。那是去年的事了,为这个异步加载来回折腾了好 ... 啊哦,这个真的是学习了 回复 支持 反对 使用道具 举报 xoyojank 19# 发表于 2011-12-31 13:45:23 | 只看该作者 别用D3DX的CreateTexture, 直接用device的试试还卡不 回复 支持 反对 使用道具 举报 timlly 20# 发表于 2011-12-31 17:36:15 | 只看该作者 DX9貌似在多线程很多问题啊,之前在弄图片渲染的时候就遇到过,头疼. 回复 支持 反对 使用道具 举报 fg5823820 21# 楼主 | 发表于 2012-1-1 17:09:44 | 只看该作者 xoyojank 发表于 2011-12-31 13:45 别用D3DX的CreateTexture, 直接用device的试试还卡不 具体现在没空没试卡不卡,不过比较了一下效率,除去IO时间,同一张纹理D3DXCREATE平均需要64ms,自己用D3DCREATE填充纹理平均需要5ms,不过这么算下来,假如资源比较多,平均到每帧貌似还是需要的 回复 支持 反对 使用道具 举报 fg5823820 22# 楼主 | 发表于 2012-1-1 17:21:43 | 只看该作者 clayman 发表于 2011-12-29 18:21 少年,你看了没有,里面讲了从dx9~11的线程模型 那东西很有用,非常感谢 回复 支持 反对 使用道具 举报 lovewhatilove 23# 发表于 2012-1-6 11:46:44 | 只看该作者 IO,解压放到一个独立的线程去做,然后主渲染线程分帧去载入显存,只是不知道有没有类似DMA的机制将内存数据载入到显存~