D3D如何做多线程异步资源加载?

D3D如何做多线程异步资源加载?

  
电梯直达 跳转到指定楼层
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  分享分享
 
  
2#
  发表于 2011-12-28 20:51:16  |  只看该作者
D3D9支持多线程,但必须在创建时传一个请求多线程的flag,否则不是线程安全的。
当然,这个多线程只是说你可以从多个线程同时访问。

D3DXCreateTextureFromFileInMemoryEx 这个函数做了太多的事情,其中只有最后一步创建d3d texture对象时需要D3D device,其他的部分都可以交给子线程。
 
 
  
3#
  楼主 |  发表于 2011-12-28 21:28:10  |  只看该作者
本帖最后由 fg5823820 于 2011-12-28 21:28 编辑
lidudu 发表于 2011-12-28 20:51 
D3D9支持多线程,但必须在创建时传一个请求多线程的flag,否则不是线程安全的。
当然,这个多线程只是说你 ...

据说加了多线程标记会使D3D性能降低,虽然我没发现有多少降低,不过加了之后的确能大大减少闪烁的几率但不能消除,大概如你所说只能进行访问,而创建纹理会修改。

至于D3DXCreateTextureFromFileInMemoryEx 函数,这个函数不是需要传一个D3D设备指针吗,百思不得其解
 
 
  
4#
  发表于 2011-12-28 22:31:11  |  只看该作者
要彻底解决此问题,就自己实现纹理 Streaming 功能,每帧分一些时间片加载纹理,或者丢到另一个线程中去加载,注意我说的是加载到显存中,而不是 IO。
 
 
  
5#
  发表于 2011-12-28 23:07:36  |  只看该作者
dx10的sample里有你想要的答案
 
 
  
6#
  发表于 2011-12-28 23:08:02  |  只看该作者
我也是后台IO,主线程填充显卡资源,貌似还没有遇到卡的问题,可能是数量小.呵呵
你看看每帧创建的texture数量是多少,如果大的话,可能会卡,可以试试分帧提交.
还有看看主线程创建texture有没有等待IO线程或者同步锁.理论上不需要任何同步的开销.
 
 
  
7#
  发表于 2011-12-29 12:28:43  |  只看该作者
fg5823820 发表于 2011-12-28 21:28 
据说加了多线程标记会使D3D性能降低,虽然我没发现有多少降低,不过加了之后的确能大大减少闪烁的几率但不 ...

一、我说的访问是access,包括读写

二、D3DX函数是辅助函数库,都是基于D3D API写的,只是用到了D3D而已。你自己写个函数来加载图片、解码图片、放缩到2的指数次方、最后创建D3D纹理对象,效果一样。
 
 
  
9#
  楼主 |  发表于 2011-12-29 15:37:37  |  只看该作者
lidudu 发表于 2011-12-29 12:28 
一、我说的访问是access,包括读写

二、D3DX函数是辅助函数库,都是基于D3D API写的,只是用到了D3D而已 ...

自己写个函数来加载图片、解码图片、放缩到2的指数次方、最后创建D3D纹理对象,这个对我来说似乎有点困难,我还是先尝试下4楼的方法。
 
 
  
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无缘了
 
 
  
11#
  发表于 2011-12-29 18:21:25  |  只看该作者
少年,你看了没有,里面讲了从dx9~11的线程模型
 
 
  
12#
  发表于 2011-12-29 20:31:12  |  只看该作者
这几天也在做多线程资源加载的工作,要把原先的单线程引擎改造成支持多线程加载,一团乱麻啊
 
 
  
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
  解锁后执行一个快速的加锁解锁来避免腐败?

不太明白这两句是解决闪烁的方法还是闪烁产生的原因
 
 
  
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!
 
 
  
16#
  发表于 2011-12-29 23:24:24  |  只看该作者
哪有主动选择dx9的人,都是被逼无奈啊,能自己选的话肯定都去dx11了
 
 
  
17#
  楼主 |  发表于 2011-12-30 09:11:46  |  只看该作者
sssa2000 发表于 2011-12-29 23:24 
哪有主动选择dx9的人,都是被逼无奈啊,能自己选的话肯定都去dx11了

是啊,都是被逼的,玩家们就是抱着XP不放,经销商认为XP稳定,这有什么办法
 
 
  
18#
  发表于 2011-12-31 12:44:24  |  只看该作者
wellbye 发表于 2011-12-29 22:54 
呵呵,又看到有人来踩雷了啊。可以翻下我在基础版发的相关帖。那是去年的事了,为这个异步加载来回折腾了好 ...

啊哦,这个真的是学习了
 
 
  
19#
  发表于 2011-12-31 13:45:23  |  只看该作者
别用D3DX的CreateTexture, 直接用device的试试还卡不
 
 
  
20#
  发表于 2011-12-31 17:36:15  |  只看该作者
DX9貌似在多线程很多问题啊,之前在弄图片渲染的时候就遇到过,头疼.
 
 
  
21#
  楼主 |  发表于 2012-1-1 17:09:44  |  只看该作者
xoyojank 发表于 2011-12-31 13:45 
别用D3DX的CreateTexture, 直接用device的试试还卡不

具体现在没空没试卡不卡,不过比较了一下效率,除去IO时间,同一张纹理D3DXCREATE平均需要64ms,自己用D3DCREATE填充纹理平均需要5ms,不过这么算下来,假如资源比较多,平均到每帧貌似还是需要的
 
 
  
22#
  楼主 |  发表于 2012-1-1 17:21:43  |  只看该作者
clayman 发表于 2011-12-29 18:21 
少年,你看了没有,里面讲了从dx9~11的线程模型

那东西很有用,非常感谢
 
 
  
23#
  发表于 2012-1-6 11:46:44  |  只看该作者
IO,解压放到一个独立的线程去做,然后主渲染线程分帧去载入显存,只是不知道有没有类似DMA的机制将内存数据载入到显存~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
异步加载地图数据可以提高页面加载速度和渲染效率,D3.js提供了多种方式实现异步加载地图数据,以下是一种常用方式的代码示例: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>中国地图</title> <style> svg { width: 100%; height: 100%; } .province { fill: #ccc; stroke: #fff; stroke-width: 1px; } .city { fill: #f00; stroke: #fff; stroke-width: 1px; } </style> <script src="https://d3js.org/d3.v5.min.js"></script> </head> <body> <svg id="map"></svg> <script> // 创建地图容器 var svg = d3.select("#map"); var width = svg.node().getBoundingClientRect().width; var height = svg.node().getBoundingClientRect().height; // 定义投影 var projection = d3.geoMercator() .center([105, 38]) .scale(600) .translate([width / 2, height / 2]); // 定义路径生成器 var path = d3.geoPath() .projection(projection); // 异步加载省份数据 d3.json("provinces.json").then(function(provinces) { // 绘制省份 svg.selectAll(".province") .data(provinces.features) .enter() .append("path") .attr("class", "province") .attr("d", path); }); // 异步加载城市数据 d3.json("cities.json").then(function(cities) { // 绘制城市 svg.selectAll(".city") .data(cities.features) .enter() .append("circle") .attr("class", "city") .attr("cx", function(d) { return projection(d.geometry.coordinates)[0]; }) .attr("cy", function(d) { return projection(d.geometry.coordinates)[1]; }) .attr("r", 5); }); </script> </body> </html> ``` 该示例代码中使用了D3.js的Promise机制实现异步加载地图数据。通过`d3.json()`方法异步加载JSON格式的地图数据,然后在`then()`回调函数中绘制地图。由于异步加载是并行进行的,因此可以提高地图绘制效率。需要注意的是,在异步加载过程中需要进行错误处理,确保地图数据加载成功并正确解析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值