概述:无论是什么系统,数据永远是其最核心的部分,DX系列火了这么多年直到今天才把其数据结构整的比较简洁。以ID3D11Resource 为基类和以ID3D11View为基类的所有类型使DX的数据分层了model-view两层结构,使得原本的数据变的更加清晰。ID3D11Resource 可以确定数据的成分是buffer还是texture,ID3D11View确定数据的应用场景是渲染目标还是深度模板。
资源的属性:(在创建资源的时候需要描述的内容)
Usage :资源的使用方式,例如纹理资源,是作为texture还是render target
format :数据的格式。主要是存储的格式,例如像素的存储格式之类。
pool :存放资源的存储器类型,以及管理方式。
type :资源类型。
内存划分:
1.System Memory :系统内存
2.Local Video Memory :显存,GPU会有比较高的读写能力,但是CPU读写的话效率比较低。
3.Nonlocal Video Memory (AGP/PCIE):这个是主板上的一块内存,这块内存GPU和CPU读和写的效率都比较高。
策略:如果只是CPU用的就放到系统内存,如果是GPU用的就放到LVM,如果是两者交互比较多的,就放到NVM中。此外,在使用的优先级上,GPU先使用显存,CPU先使用AGP/PCIE(效率比系统内存高)。
资源的介绍:
资源分为缓冲资源和纹理资源
ID3D11Resource -----> ID3D11Buffer (缓冲资源)
ID3D11Resource -----> ID3D11Texture1D,ID3D11Texture2D,ID3D11Texture3D (纹理资源)
虽然buffer和texture都是resource,但是在使用上还是有些区别。buffer在创建的时候就指定了它的view而且可以指定多种类型的view,所以在使用的时候buffer具备model和view两种身份它可以直接被hlsl使用。
ID3D11Resource :它不能被直接使用,一般使用它的子。
GetEvictionPriority :的资源获取驱逐优先。
SetEvictionPriority :将驱逐优先的资源。
- DXGI_RESOURCE_PRIORITY_MINIMUM // 最小优先级
- DXGI_RESOURCE_PRIORITY_LOW
- DXGI_RESOURCE_PRIORITY_NORMAL
- DXGI_RESOURCE_PRIORITY_HIGH
- DXGI_RESOURCE_PRIORITY_MAXIMUM // 最大优先级
这两个方法用于处理,当存储空间不够的时候优先释放那些内存的,主要用于对性能的优化。这里不清楚的是,不知道是先驱逐优先级高的,还是优先级低的。
getType :获取的资源的类型,一看应该很明白哦。
- typedef enum D3D11_RESOURCE_DIMENSION {
- D3D11_RESOURCE_DIMENSION_UNKNOWN = 0,
- D3D11_RESOURCE_DIMENSION_BUFFER = 1,
- D3D11_RESOURCE_DIMENSION_TEXTURE1D = 2,
- D3D11_RESOURCE_DIMENSION_TEXTURE2D = 3,
- D3D11_RESOURCE_DIMENSION_TEXTURE3D = 4
- } D3D11_RESOURCE_DIMENSION;
ID3D11Buffer :缓冲区接口访问缓冲区的资源,即非结构化的内存(这里提到非结构化内存是因为还有结构化内存)。缓冲区通常存储顶点或索引数据。
VertexBuffer 和 IndexBuffer:(分别描述顶点和顶点的索引)
1.定义顶点格式:用一个结构体描述顶点的信息,渲染的时候用到
- struct VertexInput // 结构体的名字任意取,成员的类型也不是必须得用D3DX的类型,关键得hlsl里面有这样的类型即可。
- {
- Vector3 position; // 位置
- Vector3 normal; // 法向量
- Vector3 tangent; // 切线
- Vector3 bitangent; // 双向切线
- Vector2 texture; // 纹理坐标
- Color4 color; // 顶点颜色
- };
这个是我自己定义的格式,根据不同需要灵活定义。
2.CreateBuffer :
- HRESULT CreateBuffer(
- [in] const D3D11_BUFFER_DESC *pDesc,
- [in, optional] const D3D11_SUBRESOURCE_DATA *pInitialData,
- [out, optional] ID3D11Buffer **ppBuffer
- );
最终会得到一个ID3D11Buffer对象,但是要想创建必须传入上述两个结构体对象。
3.D3D11_SUBRESOURCE_DATA :(这个结构在创建纹理的时候也会用到)
- typedef struct D3D11_SUBRESOURCE_DATA {
- const void *pSysMem; // 指向数据源的指针
- UINT SysMemPitch; // 步长,当缓存的是纹理的时候有用
- UINT SysMemSlicePitch; // 同上
- } D3D11_SUBRESOURCE_DATA;
这个结构比上面的简单,pSysMem此时指向数据存储在内存的源,最终它在创建buffer的时候被拷贝到一个新的位置。
4.D3D11_BUFFER_DESC :
typedef struct D3D11_BUFFER_DESC { // 这个结构体对buffer的结果进行描述,站多大内容空间之类的,这样好开辟内存空间。 UINT ByteWidth; // 缓冲区大小,单位为字节 D3D11_USAGE Usage; // 一个枚举,描述的是GPU和CPU对此buffer的读写能力,其实这涉及到这个buffer将会存储在那个地方 UINT BindFlags; // 这个描述的是buffer的类型 UINT CPUAccessFlags; // 设置CPU访问权限,不访问设置为0 UINT MiscFlags; // 如果不使用设置为0,可以多选,暂时不知用法 UINT StructureByteStride; // ??? 不理解 } D3D11_BUFFER_DESC; typedef enum D3D11_USAGE { // 2(描述的是访问权限) D3D11_USAGE_DEFAULT = 0, // 默认值,GPU具备读写能力 D3D11_USAGE_IMMUTABLE = 1, // GPU可读,CPU不可访问,如果选择这种方式必须得初始化buffer,你懂的 D3D11_USAGE_DYNAMIC = 2, // GPU只读,CPU只写 D3D11_USAGE_STAGING = 3 // 这种是CPU可以完全控制,GPU只能复制数据,与0完全相反。 } D3D11_USAGE; typedef enum D3D11_BIND_FLAG { // 对应第3个参数,此标志是多选 D3D11_BIND_VERTEX_BUFFER = 0x1L, // 顶点缓存 D3D11_BIND_INDEX_BUFFER = 0x2L, // 索引缓存 D3D11_BIND_CONSTANT_BUFFER = 0x4L, // 常数缓存,不可与其他标志共用 D3D11_BIND_SHADER_RESOURCE = 0x8L, // view :作为渲染器的使用缓冲 D3D11_BIND_STREAM_OUTPUT = 0x10L, // view :作为流出去的目标缓冲 D3D11_BIND_RENDER_TARGET = 0x20L, // view :作为渲染目标 D3D11_BIND_DEPTH_STENCIL = 0x40L, // view :作为深度模板 D3D11_BIND_UNORDERED_ACCESS = 0x80L, // view :作为无序的什么东东 D3D11_BIND_DECODER = 0x200L, // ??? D3D11_BIND_VIDEO_ENCODER = 0x400L // ??? } D3D11_BIND_FLAG; typedef enum D3D11_CPU_ACCESS_FLAG { // 对应第4个参数,多选,与第二个参数要结合使用. D3D11_CPU_ACCESS_WRITE = 0x10000L, D3D11_CPU_ACCESS_READ = 0x20000L } D3D11_CPU_ACCESS_FLAG;
buffer只有3类:顶点,索引和常量。然后他们会以各种view的形势被使用D3D11_BIND_FLAG就是描述这些的。
ID3D11Texture1D,ID3D11Texture2D,ID3D11Texture3D : 纹理接口访问 纹理数据,这是结构化的内存。
CreateTexture2D :
HRESULT CreateTexture2D( // [in] const D3D11_TEXTURE2D_DESC *pDesc, [in] const D3D11_SUBRESOURCE_DATA *pInitialData, [out] ID3D11Texture2D **ppTexture2D ); typedef struct D3D11_TEXTURE2D_DESC { UINT Width; // 宽度 UINT Height; // 高度 UINT MipLevels; // mip的级别 UINT ArraySize; // 这个值在创建纹理数组时有用 DXGI_FORMAT Format; // 格式,像素点存储的格式 DXGI_SAMPLE_DESC SampleDesc; // 多重采样? D3D11_USAGE Usage; // GPU和CPU对纹理的访问权限 UINT BindFlags; // 绑定到流水线标志 (多选) UINT CPUAccessFlags; // 定制CPU访问权限 UINT MiscFlags; // ??? } D3D11_TEXTURE2D_DESC; typedef struct D3D11_SUBRESOURCE_DATA { const void *pSysMem; // 这个指针指向数据的真实位置 UINT SysMemPitch; // 这两个参数描述的是纹理的跨度 UINT SysMemSlicePitch; // } D3D11_SUBRESOURCE_DATA;
上述这些接口都只有一个方法:GetDesc 用来获取描述信息,这说明它们自身的内容并不是有自己提供接口给外部使用,而是借组第三方接口来进行使用。从某种意义上来讲,在我们使用的时候,我们只需把它们当中一个普通的变量即可,真正需要关注的是使用它们的类。
ID3D11View :一个ID3D11View的子类可以把渲染过程中,需要用到的一部分资源绑定到渲染管道。
- void GetResource(
- [out] ID3D11Resource **ppResource
- );
这是它的唯一方法,可以获取与之对应的资源对象。
ID3D11DepthStencilView :访问数据在纹理深度模版。
ID3D11RenderTargetView :访问数据的渲染目标。
ID3D11ShaderResourceView :在着色器资源的访问数据。
ID3D11UnorderedAccessView :在一个无序的资源访问数据。
CreateShaderResourceView :其它与之类似
HRESULT CreateShaderResourceView( [in] ID3D11Resource *pResource, // 这个就是纹理对象 [in] const D3D11_SHADER_RESOURCE_VIEW_DESC *pDesc, // [out] ID3D11ShaderResourceView **ppSRView ); typedef struct D3D11_SHADER_RESOURCE_VIEW_DESC { DXGI_FORMAT Format; // 纹理创建的时候已经描述过这个属性,不清楚这里是否可以空着 D3D11_SRV_DIMENSION ViewDimension; // 描述资源的类型,与union 对应 union { D3D11_BUFFER_SRV Buffer; D3D11_TEX1D_SRV Texture1D; D3D11_TEX1D_ARRAY_SRV Texture1DArray; D3D11_TEX2D_SRV Texture2D; D3D11_TEX2D_ARRAY_SRV Texture2DArray; D3D11_TEX2DMS_SRV Texture2DMS; D3D11_TEX2DMS_ARRAY_SRV Texture2DMSArray; D3D11_TEX3D_SRV Texture3D; D3D11_TEXCUBE_SRV TextureCube; D3D11_TEXCUBE_ARRAY_SRV TextureCubeArray; D3D11_BUFFEREX_SRV BufferEx; }; } D3D11_SHADER_RESOURCE_VIEW_DESC;
创建ResourceView本身比较简单,因为方法已经对ResourceView的性质做了决定,还有就是在创建纹理和buffer的时候也有一个标志位描述view。
在渲染管道的使用:
渲染管道几乎每个阶段都配备有setbuffer和setview(Resources)的方法。这即表示每个渲染阶段都能够获取到自己想要的数据,另一方面又说明buffer的传递与texture的传递并不是采用相同的API。但是,我们看到ResourceView的定义里面很明显有支持buffer的痕迹,但是在使用上又为其开小灶。不清楚微软的意图是什么?不知道如果我们不buffer定义到ResourceView里面渲染管道会怎么处理它。
保存纹理到本地: