CR的代码文本

all for learning about the world
  订阅 订阅  :: 管理

D3D10中的Resource 02

Posted on 2012-06-15 12:36  mumuliang  阅读(816)  评论(3编辑  收藏  举报
原文:http://msdn.microsoft.com/en-us/library/windows/desktop/bb205132(v=vs.85).aspx 

 

WDDM引以为傲的是APP不需要关心Resource开辟的内存位于哪里,也不需要操心我要管理呢管理呢还是管理呢?

WDDM只要求APP在创建Resource提供一个标识(Usage flag)用来说明该Resource的使用方式,剩下的事情您就甭管了。

这些剩下的事情主要就是从哪儿划块地皮用于建立Resource,是显存呢还是内存。

Resource的默认(Usage Flag default)位于显存,由GPU操作。既然是GGGGGGGraphic编程,那默认肯定是由GGGGGGGGpu在做事。就这么理解。 但肯定也有CPU需要访问Resource的时候,但CPU只能访问内存中的数据。CPU访问内存数据的效率和GPU访问显存数据相比,就弱爆了。所以尽管WDDM希望你甭管,但还是得关心一下那些关于Resource的API们到底是肿么在工作。

 

 USAGE,复制Resource 

当俺们调用Create*创建一个Resource的时候,在那一刹那,Resource是从内存中被创建出来的。

上面这句完全错误。WDDM引以为傲的就是不需要操心这某存位于哪里,Resource是从一个虚拟的存储空间的概念上创建出。它在物理上是内存显存还是别的什么存,WDDM不想告诉你。 但是有一点傻瓜都知道,GPU只能访问显存中的数据。复习一下,Resource是指完成绘制所需要的数据,GPU肯定要访问的。——但是CPU也可能会需要访问,甚至可能修改一些Resource。肿么办?

再复习一下,创建Resource时用一个usage flag告诉WDDM,我APP会这么这么用这个Resource。 

CPU:我要那个 
WDDM:你不告诉我你要我怎么知道你要啊,你告诉了我你要难道我会不给你嘛,你告诉我你不要那我也不会非要给你啊。。
CPU:说人话
WDDM:你得说create with USAGE::dynamic 或者 create with USAGE::staging
CPU:能改吗?
WDDM:不能。

4个USAGE,只有dynamic和staging是CPU可直接访问的Resource。 (另俩是default和immutable, immutable就厉害了,即使GPU也不能修改哦。)

创建完成的Resource,其Usage是不能修改的。(如果能改,那immutable岂不悲催了)

但是可以把Resource数据拷贝给另外一个USAGE不同的Resource。D3D10提供了两个方法

ID3D10Device::CopyResource  
ID3D10Device::CopySubresourceRegion

上面两个方法是异步执行的,会立刻返回。不单如此,直到目标resource调用了map(),它才真正的被复制。

D3D10中这样异步调用的方法非常多。

为了减少核心模式和用户模式切换的开销,它们都会被存储在指令缓冲区,有present、flush、或者缓冲区满、或者需要访问某条指令的返回值时,一次执行。

另提供了一个方法从内存拷贝数据到Resource

ID3D10Device::UpdateSubresource 


WDDM维持的Resource其实是两种,一种是可以映射的mappable,一种是不可以映射non-mappable。这个映射其实就是从显存映射到AGP缓存或者内存什么的。 

CPU:我知道了。拿到satging和dynamic,你就创建mappable的Resource。要不就是non-mappable.
WDDM:被你看出来了。(脸红绕手指)  

non-mappable因为完全只考虑在显卡内部访问,完全不考虑和CPU之间的IO,因此会被优化的很好,读取和复制都相当的快。

mappable类型的Resource,dynamic,GPU读还行,但不能写。 staging,GPU不能读也不能写。mappble Resource之间复制的效率可不大好。

 

也是因为这个mappable,因此会看到有map()/unmap()方法对用来从GPU那里获得resource控制权、更新数据然后释放控制权。

 

  小结一下USAGE  

一开始只有两种,一种是只能被GPU访问的,一种是同时被CPU和GPU访问的。(为啥没有CPU单独访问的?人家是显示驱动框架显示驱动显示好吗)

被GPU访问的就是default。(为啥是被GPU访问的是default?人家是显示驱动框架好吗好吗好吗好吗)

同时..是dynamic。

后来又发现如果有一些default,从创建以后就没变过,这部分如果事先知道它始终不会改变,岂不是还能优化?于是就有了immutable。

后来又发现,娘啊,我想访问一下default,但是如果把default改成dynamic的话,那效率又下降的太厉害,划不来。而且我访问的频率又不是太频繁。而且我只是想拿到default resource的值并不是想改。于是。。。。就有了staging。

 

  访问Resource数据   

CPU可以访问的是mappalbe resource。映射实际上就是让GPU向CPU出让访问权限的动作,这会引起性能瓶颈。比如你想要map某一步stage的输出,但是你还没等渲染管线做完就map了。为嘛可能没做完呢,因为比如早之前CopyResource()给某个staging resource,实际上该函数是直接返回的。所有渲染指令都会被缓冲,并不会立刻执行。 

map()的时候,如果该resource是某个CopyResource的目标,并且在map之前也没有present或者flush什么的,CopyResource指令现在仍然还停留在指令缓冲区,此种情况的map就极可能会引起渲染管线忙死,因为指令缓冲区内的渲染指令总是一次全部被执行掉。在GPU执行整个指令缓冲区的时候,CPU一直在等待map()返回结果,因此CPU闲置了;当map结果返回以后,因为GPU的指令缓冲区已经清空,所以GPU又闲置了。

所以map用不好就是个拖油瓶,必须用好。对一个staging resource用map之前最好等一段时间,确保它确实已经从别的default resource拿到了数据。建议等2帧。通常应用程序在第N帧的时候,GPU正在执行第N-1帧的指令。也就是说,如果你第N帧CopyResource(),那么它会在第N+1帧时被执行;也就是说在N+2帧调用map时,就不会引起CPU和GPU的同步问题。 

 

另外,map()拿到的是内部数据的指针。这里有一个内存对齐的问题。feature level是D3D_FEATURE_LEVEL_10_0及以上的,是16bytes对齐,以下是4bytes。