`
dengbaoleng
  • 浏览: 1131935 次
文章分类
社区版块
存档分类
最新评论

转载一篇介绍D3DPOOL和Lock的文章

 
阅读更多

D3D RUTIME的内存类型,分为3种,VIDEO MEMORY(VM)、AGP MEMORY(AM)和SYSTEM MEMORY(SM),
所有D3D资源都创建在这3种内存之中,在创建资源时,我们可以指定如下存储标志,
D3DPOOL_DEFAULT、D3DPOOL_MANAGED、D3DPOOL_SYSTEMMEM和D3DPOOL_SCRATCH。
VM就是位于显卡上的显存,CPU只能通过AGP或PCI-E总线访问到,读写速度都是非常慢的,
CPU连续写VM稍微快于读,因为CPU写VM时会在CACHE中分配32或64个字节(取决于CACHE LINE长度)
的写缓冲,当缓冲满后会一次性写入VM;SM就是系统内存,CPU读写都非常快,
因为SM是被CACHE到2级缓冲的,但GPU却不能直接访问到系统缓冲,所以创建在SM中的资源,
GPU是不能直接使用的;AM是最麻烦的一个类型,AM实际也存在于系统内存中,
但这部分MEM不会被CPU CACHE,意味着CPU读写AM都会写来个CACHE MISSING然后才通过内存总线访问AM,
所以CPU读写AM相比SM会比较慢,但连续的写会稍微快于读,
原因就是CPU写AM使用了“write combining”,而且GPU可以直接通过AGP或PCI-E总线访问AM。

如果我们使用D3DPOOL_DEFAULT来创建资源,则表示让D3D RUNTIME根据我们指定的资源使用
方法来自动使用存储类型,一般是VM或AM,系统不会在其他地方进行额外备份,当设备丢失后,
这些资源内容也会被丢失掉。但系统并不会在创建的时候使用D3DPOOL_SYSTEMMEM或D3DPOOL_MANAGED
来替换它,注意他们是完全不同的POOL类型,创建到D3DPOOL_DEFAULT中的纹理是不能被CPU LOCK的,
除非是动态纹理。但创建在D3DPOOL_DEFAULT中的VB IB RENDERTARGET BACK BUFFERS可以被LOCK。
当你用D3DPOOL_DEFAULT创建资源时,如果显存已经使用完毕,则托管资源会被换出显存来释放足够的空间。
D3DPOOL_SYSTEMMEM和D3DPOOL_SCRATCH都是位于SM中的,其差别是使用D3DPOOL_SYSTEMMEM时,
资源格式受限于Device性能,因为资源很可能会被更新到AM或VM中去供图形系统使用,
但SCRATCH只受RUNTIME限制,所以这种资源无法被图形系统使用。
D3DRUNTIME会优化D3DUSAGE_DYNAMIC 资源,一般将其放置于AM中,但不敢完全保证。
另外为什么静态纹理不能被LOCK,动态纹理却可以,都关系到D3D RUNTIME的设计,
在后面D3DLOCK说明中会叙述。

D3DPOOL_MANAGED表示让D3D RUNTIME来管理资源,被创建的资源会有2份拷贝,一份在SM中,
一份在VM/AM中,创建的时候被放置L在SM,在GPU需要使用资源时D3D RUNTIME自动将数据拷贝到
VM中去,当资源被GPU修改后,RUNTIME在必要时自动将其更新到SM中来,
而在SM中修改后也会被UPDATE到VM去中。所以被CPU或者GPU频发修改的数据,
一定不要使用托管类型,这样会产生非常昂贵的同步负担。当LOST DEVICE发生后,
RESET时RUNTIME会自动利用SM中的COPY来恢复VM中的数据

二 lock

如果LOCK DEFAULT资源会发生什么情况呢?DEFAULT资源可能在VM或AM中,如果在VM中,
必须在系统内容中开辟一个临时缓冲返回给数据,当应用程序将数据填充到临时缓冲后,
UNLOCK的时候,RUNTIME会将临时缓冲的数据传回到VM中去,如果资源D3DUSAGE属性不是WRITEONLY的,
则系统还需要先从VM里拷贝一份原始数据到临时缓冲区,这就是为什么不指定WRITEONLY会降低
程序性能的原因。CPU写AM也有需要注意的地方,因为CPU写AM一般是WRITE COMBINING,
也就是说将写缓冲到一个CACHE LINE上,当CACHE LINE满了之后才FLUSH到AM中去,
第一个要注意的就是写数据必须是WEAK ORDER的(图形数据一般都满足这个要求),
据说D3DRUNTIME和NV DIRVER有点小BUG,就是在CPU没有FLUSH到AM时,GPU就开始绘制相关资源产生
的错误,这时请使用SFENCE等指令FLUSH CACHE LINE。第二请尽量一次写满一个CACHE LINE,
否则会有额外延迟,因为CPU每次必须FLUSH整个CACHE LINE到目标,但如果我们只写了LINE中部分字节,
CPU必须先从AM中读取整个LINE长数据COMBINE后重新FLUSH。第三尽可能顺序写,
随机写会让WRITE COMBINING反而变成累赘,如果是随机写资源,不要使用D3DUSAGE_DYNAMIC创建,
请使用D3DPOOL_MANAGED,这样写会完全在SM中完成。

普通纹理(D3DPOOL_DEFAULT)是不能被锁定的,因为其位于VM中,只能通过UPDATESURFACE和
UPDATETEXTURE来访问,为什么D3D不让我们锁定静态纹理,却让我们锁定静态VB IB呢?我猜测可能
有2个方面的原因,第一就是纹理矩阵一般十分庞大,且纹理在GPU内部已二维方式存储;
第二是纹理在GPU内部是以NATIVE FORMAT方式存储的,并不是明文enRGBA格式。动态纹理因为表明
这个纹理需要经常修改,所以D3D会特别存储对待,高频率修改的动态纹理不适合用动态属性创建,
在此分两种情况说明,一种是GPU写入的RENDERTARGET,一种是CPU写入的TEXTURE VIDEO,
我们知道动态资源一般是放置在AM中的,GPU访问AM需要经过AGP/PCI-E总线,速度较VM慢许多,
而CPU访问AM又较SM慢很多,如果资源为动态属性,意味着GPU和CPU访问资源会持续的延迟,
所以此类资源最好以D3DPOOL_DEFAULT和D3DPOOL_SYSTEMMEM各创建一份,自己手动进行双向更新更好。
千万别 RENDERTARGET以D3DPOOL_MANAGED 属性创建,这样效率极低,原因自己分析。
而对于改动不太频繁的资源则推荐使用DEFAULT创建,自己手动更新,因为一次更新的效率损
失远比GPU持续访问AM带来的损失要小。

不合理的LOCK会严重影响程序性能,因为一般LOCK需要等待COMMAND BUFFER前面的绘制指令全部
执行完毕才能返回,否则很可能修改正在使用的资源,从LOCK返回到修改完毕UNLOCK这段时间GPU
全部处于空闲状态,没有合理使用GPU和CPU的并行性,DX8.0引进了一个新的LOCK标志D3DLOCK_DISCARD,
表示不会读取资源,只会全写资源,这样驱动和RUNTIME配合来了个瞒天过海,立即返回给应用程序
另外块VM地址指针,而原指针在本次UNLOCK之后被丢弃不再使用,这样CPU LOCK无需等待GPU使用
资源完毕,能继续操作图形资源(顶点缓冲和索引缓冲),这技术叫VB IB换名(renaming)。

分享到:
评论

相关推荐

    directx 3d 实例

    g_pD3DDevice->CreateVertexBuffer(sizeof(SkyVerts), D3DUSAGE_WRITEONLY, SKYFVF, D3DPOOL_DEFAULT, &g_SkyVB, NULL); char *Ptr; g_SkyVB->Lock(0,0, (void**)&Ptr, 0); memcpy(Ptr, SkyVerts, sizeof...

    java做的小型连接池(dpool)

    java 小型连接池 可以适合各种数据库的连接 代码简单易懂

    腾讯与新浪的通过IP地址获取当前地理位置(省份)的接口

    新浪的接口 : http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js 多地域测试方法:http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=218.192.3.42 返回值 var remote_ip_info = {...

    C#NET获取IP信息

    /// http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip={ip} /// </summary> /// 请求分析得IP地址</param> /// 服务器返回的编码类型</param> /// <returns>IpUtils.IpDetail...

    基于C++11 实现的动态线程池源码示例.zip

    基于C++11 实现的动态线程池源码示例.zip ... dpool::ThreadPool pool(10); auto fut = pool.submit(compute, 100, 100); std::cout () ; return 0; } 更多细节请看资源中源码示例,供学习实际项目使用!放心下载

    获取 IP地址归属地

    调用的借口http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip;={ip}获取IP地址的详细信息

    Node.js和PHP根据ip获取地理位置的方法

    一、Node.js实现代码 代码如下:var http = require(‘http’);var util = require(‘util’);/** * 根据 ip 获取获取地址信息 */var getIpInfo = function(ip, cb) { var sina_server = ...

    JavaScript获取用户所在城市及地理位置

    下面一段代码给大家分享js 获取用户所在城市,具体代码如下所述: <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>获取用户地理位置</title> ...

    使用Python程序抓取新浪在国内的所有IP的教程

    数据分析,特别是网站分析中需要对访问者的IP进行分析,分析IP中主要是区分来访者的省份+城市+行政区数据,考虑到目前纯真IP数据库并没有把这些数据做很好的区分,于是寻找了另外一个可行的方案(当然不是花钱买哈)...

    js实现PC端根据IP定位当前城市地理位置

    $.getScript('http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js', function(_result) { if (remote_ip_info.ret == '1') { alert('国家:' + remote_ip_info.country +'\n省:' + remote_ip_info....

    php利用新浪接口查询ip获取地理位置示例

    php function getIPLoc_sina($queryIP){ $url = ‘http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=’.$queryIP; $ch = curl_init($url); curl_setopt($ch,CURLOPT_ENCODING ,’utf8′); ...

    php实现根据IP地址获取其所在省市的方法

    根据现有IP地址获取其地理位置...'http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=' . $ip);\n if(empty($res)){ return false; }\n $jsonMatches = array();\n preg_match('#\{.+?\}#', $res,

Global site tag (gtag.js) - Google Analytics