D3D的内存类型

时间:2021-05-07 22:04:08

一、对D3D中AGP显存、内存、显存三种内存的解释

 三种内存AGP内存(非本地显存),显存(本地内存),系统内存,其中我们都知道系统内存就是咱那内存条,那这AGP内存是个啥玩意啊?其实是因为在以前显卡内存都很小,那时还是在显存是16M,32M为主流的时候,如果你运行一个需要很多纹理的3D程序,那么显存一会就不够用了,那该咋办呢?只好问系统内存借点用用了!这就是AGP内存的由来, 在我们电脑BIOS中有个设置AGP Aperture的选项,这里就是设置显卡可以使用系统内存的最大允许值,通常是设置为64M。注意,这里只是说最 大允许值,并不是一开机他就把这64M给拿走了,你的256内存就变成192了!而是你的内存依然还是256M,只是限制显卡最多可以使用64M的系统内 存。

再说说这三个内存的速度的不同吧!

系统内存当然是人家CPU读和写操作最快啦!而显卡就会相对于使用自己的显存慢上很多很多!
AGP内存是显卡读和写的速度一般,当然肯定没
有显卡使用显存速度快啦!CPU就相对复杂点了,CPU读取AGP内存速度很慢,但是写的速度却并不会慢,而是速度一般,比使用系统内存慢那么一点,也就
是说适合CPU去写但不适合读。有人就要问了,同样是系统内存只不过名字不一样,咋速度的就有差别了呢?这个嘛,我也不太清楚,老外没有说的太详细,大家
只要记住就行了!
最后说的就是显存了,这个很简单,当然是显卡读和写的速度最快,而CPU读和写的速度肯定要慢好多的!
说了三个内存的区别,现在说说他们都有什么用处吧!这里涉及一个D3DUSAGE枚举量:

D3DUSAGE_DYNAMIC,这个变量是在你创建资源时使用到的,它指示D3D将资源指定为动态的,而动态的意思就是需要经常修改,修改通常是CPU进行修改,所以动态资源应该放在AGP内存中。这样对速度的影响可以减至最小。

D3DUSAGE_WRITEONLY标志您所创建的资源只允许写操作。使用这个标志可以让设备将这个资源放到内存中最适合进行写处理和渲染的区
域。如果没有使用D3DUSAGE_WRITEONLY标志,那么设备将假设您创建的资源既用来读也用来写,那么设备将很可能选择一块内存区域,读和写操
作的速度都适中的地方。这将牺牲一部分处理和渲染速度。

对D3DLOCK的标志和资源创建类型也有影响
但是三种内存是另外一种优化访问的方法,因为比如粒子系统就需要使用AGP内存,因为他需要CPU经常进行修改,又需要图形处理卡经常读取,如果放在显存那么CPU修改的效率太低了!如果放在内存,那么图形处理卡访问的速度太慢!所以这三种内存还是需要分别清楚的!

二、D3DPOOL(资源池)

D3DPOOL定义了资源对应的内存类型,资源可以是texture surface, vertex buffer等,有以下几种POOL类型

D3DPOOL_DEFAULT

D3DPOOL_MANAGED

D3DPOOL_SYSTEMMEM

D3DPOOL_SCRATCH

D3DPOOL_FORCE_DWORD

D3DPOOL_DEFAULT

资源被存储在最适合给定资源访问的内存中,这通常是显存,包括本地显内存和AGP内存,D3DPOOL_DEFAULT不同于 D3DPOOL_MANAGED和D3DPOOL_SYSTEMMEM,它指出了资源被存储在最适合设备访问的内存中,D3DPOOL_DEFAULT指 出D3DPOOL_MANAGED和D3DPOOL_SYSTEMMEM永远都不会作为资源内存的备选类型,使用D3DPOOL_DEFAULT分配的纹 理资源是无法锁定的,除非该纹理是动态纹理或者是私有的FOURCC driver 格式。想要访问无法锁定的纹理资源,必须使用如下函数

IDirect3DDevice9::UpdateSurface

IDirect3DDevice9::UpdateTexture

IDirect3DDevice9::GetFrontBufferData

IDirect3DDevice9::GetRenderTargetData

对大多数应用程序来说,使用D3DPOOL_MANAGED是一个更好的选择。一些使用driver特有的像素格式创建的纹理,无法被 Direct3D runtime识别,也是可以锁定的。与texture不同的是,swap chain back buffers, render targets, vertex buffers和index buffers都是可以锁定的,当设备丢失时,所有使用D3DPOOL_DEFAULT创建的资源必须在调用Reset函数前释放掉,使用 D3DPOOL_DEFAULT创建资源时,如果内存不够用,那么managed resource会释放一些内存空间来满足需要。

D3DPOOL_MANAGED

资源按需自动被拷贝到设备能访问的内存中。托管资源由系统内存备份,所以设备丢失时无需重建。托管资源可以被锁定,只有系统备份的那份内存能直接被修改。Direct3D按需将修改拷贝到设备可访问的内存中。

D3DPOOL_SYSTEMMEM

资源被分配在不能被设备直接访问的内存中。这些内存消耗系统的RAM但是并不减少可分页的RAM。这些资源不必在设备丢失时重建。这种资源也可以被 锁定,并且可以用作函数IDirect3DDevice9::UpdateSurface或 IDirect3DDevice9::UpdateTexture的源,这两个函数的操作目标都是D3DPOOL_DEFAULT类型的资源。

D3DPOOL_SCRATCH

资源分配在系统RAM中并且无需在设备丢失时重建。这种资源不受设备大小和格式的限制。因此,这种资源不能被Direct3D设备使用,也不能设置为纹理或者Render targets,尽管如此,这种资源也可以被创建,锁定和拷贝。

D3DPOOL_FORCE_DWORD

强制该类型编译为32bit大小,没有这个值,一些编译器将会把这个枚举类型编译为非32bit大小的类型,该值暂未使用。

所有的内存类型适用于所有的资源类型,包括Vertex Buffers, Index Buffers, textures和Surfaces

下面的表指出了资源的内存类型及用法之间的兼容关系,x表示兼容

D3D的内存类型

同一个资源中的不同对象间的资源池不能混合(mip levels in a mipmap),并且当一个资源池被选中时就不能被改变了。

对于大多数静态资源,应用程序应该使用D3DPOOL_MANAGED,因为这使得应用程序不必处理设备丢失。这在统一内存架构的系统(UMA)上
显得尤为有益。其他动态资源类型并不适合使用D3DPOOL_MANAGED,实际上,index buffers和vertex
buffers不能同时使用D3DPOOL_MANAGED和D3DUSAGE_DYNAMIC创建。

对于动态纹理,有时需要使用一对内存,一个是使用D3DPOOL_DEFAULT分配的显存,另一个是使用D3DPOOL_SYSTEMMEM分配
的系统内存。可以用锁定的方法在系统内存上修改纹理,并使用函数IDirect3DDevice9::UpdateTexture将修改更新到显存中。

三、D3DPOOL和D3D资源

D3D资源管理

资源分类      
    顶点缓冲(VertexBuffer)
    索引缓冲(IndexBuffer)
    纹理(Texture)

资源存储      
       显存(Video Memory)
       通过AGP直接访问的内存(AGP Aperture,也叫做非本地显存)
       系统内存(System Memory)

性能权衡      
      我们在创建D3D资源的时候需要填写两个参数:D3DPOOL、D3DUSAGE。这两个参数共同决定了资源最终存储在显存、非本地显存还是系统内存中。

枚举类型D3DPOOL

D3DPOOL_DEFAULT
 
D3DPOOL_MANAGED
 
D3DPOOL_SYSTEMMEM
 
D3DPOOL_SCRATCH
 
      D3DPOOL_MANAGED:
        资源存储位置:由D3D内部管理此资源,此类资源通常被创建在系统内存中。在显卡需要此资源时,D3D将它从内存拷贝到显存。
       当设备丢失时,D3D会自动恢复显存中的数据。
       适用情况:由于D3D自己的资源管理方案很高效、使用简单,游戏中大部分资源都可以使用此标识创建。
       例子:游戏中使用的大部分纹理贴图,静态模型。

D3DPOOL_DEFAULT:
     资源存储位置:此类资源不由D3D管理,通常被创建在显存或AGP Aperture中。
             当设备丢失时,必需手动恢复资源,增加了代码复杂度。
             适用情况:有时候我们希望将某些资源一直放在显存里,以提高访问速度。同时使用D3DUSAGE_WRITEONLY标记会提高效率。
       例子:游戏中使用的光标贴图,在游戏运行过程中一直要使用,可以直接创建在显存中。
       如果数据需要高频率更新(不断的Lock, Unlock),也需要使用D3DPOOL_DEFAULT,同时使用D3DUSAGE_DYNAMIC标记。这意味着此资源会被创建在AGP Aperture中。
       例子:使用CPU进行物理运算的粒子系统、使用CPU计算蒙皮的骨骼动画。

D3D的内存类型

上图显示了使用不同USAGE和POOL参数创建资源的存储情况。

一个例子:Direct3D绘制简单图形  绘制立方体。

[Copy to clipboard]
CODE:
//创建顶点缓冲
if(FAILED(g_pD3DDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX), 
0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVertexBuffer,NULL)))
{
    return E_FAIL;
}

此代码使用D3DPOOL_DEFAULT 创建VertexBuffer,但是USAGE没有指定为D3DUSAGE_WRITEONLY,这样会造成严重的性能损失。应改为:

[Copy to clipboard]
CODE:
//创建顶点缓冲
if(FAILED(g_pD3DDevice->CreateVertexBuffer(3*sizeof(CUSTOMVERTEX), 
D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT,
&g_pVertexBuffer,NULL)))
{
    return E_FAIL;
}