The Beauty of DirectX 11 (2) --- Resource View & Vertex Buffer
作者:clayman
仅供个人学习使用,请勿转载,勿用于任何商业用途。
CPU Access Flag(D3D11_CPU_ACCESS_FLAG)
这是一个位标记,在指定usage flage之后,进一步说明是否允许cpu访问某块资源(其实个人觉得这个枚举稍微有些多余)。这个标记必须配合usage使用,比如只有dynamic和stagin资源能设置为D3D11_CPU_ACCESS_WRITE。如果一块资源不需要被CPU访问,那么必须把值设置为0.
Bind Flags
指定资源可以绑定到pipeline的哪些位置。这同样是一个位标记,因此可以组合起来,允许资源绑定到流水线的多个位置。
D3D11_BIND_FLAG {
D3D11_BIND_VERTEX_BUFFER,
D3D11_BIND_INDEX_BUFFER,
D3D11_BIND_CONSTANT_BUFFER,
D3D11_BIND_SHADER_RESOURCE,
D3D11_BIND_STREAM_OUTPUT,
D3D11_BIND_RENDER_TARGET,
D3D11_BIND_DEPTH_STENCIL,
D3D11_BIND_UNORDERED_ACCESS
}
整个管线只有8种类型的位置可以绑定资源,分别对应D3D11_BIND_FLAG中的一个值。Vertex/index buffer表示资源可以作为input assembler阶段的输入数据;render target和depth stencil表示资源可以接收output merger阶段的数据;stream out表示可以接收来自于pipeline生成的几何数据。这几个枚举分别对应着管线中的一个可绑定点。Constant buffer, shader resource和unorderer access则都可以作为可编程阶段的输入数据。后面会讨论三者之间的区别。
此外Miscellaneous Flags中的枚举值,用来指定一些特别的用途,大部分值都不经常用到,不再仔细介绍,详见文档。唯一值得一提的是D3D11_RESOURCE_MISC_GDI_COMPATIBLE,这个值允许创建与GDI兼容的资源,对于需要用GDI创建文字的程序可能会用到。
Resource View
有两种方法把资源绑定到pipeline,如前所述的8种绑定点中,有一半可以直接绑定资源,分别是vertex/index/const/stream buffer;其他4种类型则必须通过Resource View(RV)绑定。Resource View是在DirectX10时代引入的概念,它实际上是连接resouce和pipeline绑定点之间的一种适配器对象,作用类似翻译。同一种资源可以对应多个不同的RV,允许它被绑定到不同的pipline阶段。
resource type
有四种不同类型的RV,分别对应着pipeline中的4个可绑定位置:
Render target view (ID3D11RenderTargetView)
Depth stencil view (ID3D11DepthStencilView)
Shader resource view (ID3D11ShaderResourceView)
Unordered access view (ID3D11UnorderedAccessView)
第一种就是常见的render target,大家应该很熟悉,没有太多可说的。DSV和RTV的区别在于为了优化性能,可以选择DSV是否可写。不可写的DSV资源既可以绑定为depth stencil buffer做depth stencil test,又能*同时*绑定为SRV使用。SRV其实和之前DX中纹理的作用几乎一样。UVA则稍微有些特别,和SRV类似,UVA也可以为某个shader阶段提供数据,不仅如此,它还允许在同一个shader阶段,同时读取和写入数据,并且能把数据写入到资源的任意位置,灵活性非常高,但只能在pixel shader和compute shader中使用。
Resource View Creation
创建RV的模式和创建资源的模式类似,也通过ID3DDevice的成员函数完成,每个Create函数接收3个参数,第一个是RV所依赖的资源;第三个是所创建的RV对象。第二个参数则是每个类型都不同的一个属性结构,SDK中对这些结构有详细描述,这里不再重复。
Resource in Detail
Buffer Resource
BR是一维的线性内存块,虽然有多种不同的buffer配置选项,但内部数据都是基本的线性布局。Buffer以byte为单位,大小等于每个元素大小乘元素个数,与普通数组类似。接下来将详细介绍每一种buffer。
Vertex Buffer
VB最基本的用途就是保存几何体顶点数据,是一系列格式相同的顶点的集合。当然,也可以把顶点的不同元素分离到不同VB中,比如位置信息储存在vb1,纹理和法线信息储存在vb2,根据渲染时的需要选择使用合适的buffer,也就是常说的multi-stream。此外,VB也可以用来实现instancing rendering(注:后文将把instance翻译为”副本”,而不是常见的”实体”,这样更容易理解),比如用一块或几块vb保存per-vertex data,也就是普通的顶点数据,再用额外的vb来提供per-instance data,比如每个模型副本的world matrix,color等等,这样便可一次渲染大量图形,减少CPU负载。后面还会详细介绍与instancing rendering相关的内容。
VB主要用于Input Assembler阶段给整个流水线提供顶点数据,也可以用于stream out阶段接收生成的顶点,以便后续渲染使用。
创建VB时,必须使用D3D11_BIND_VERTEX_BUFFER以及可选的D3D11_BIND_STREAM_OUTPUT枚举。再根据程序预期的用途,选择合适的usage。e.g对于静态资源(静态模型,地形数据),使用D3D11_USAGE_IMMUTABLE枚举,并且使用D3D11_SUBRESOURCE_DATA参数初始化资源;对需要频繁修改的资源使用D3D11_USAGE_DYNAMIC以及D3D11_CPU_ACCESS_WRITE枚举;对于需要作为stream output输出目标的资源,使用D3D11_USAGE_DEFAULT。VB不需要RV就可以绑定到管线。
ID3DBuffer* CreateVertexBuffer(uint size, bool dynamic, bool streamout, D3D11_SUBRESOURCE_DATA* pData)
{
D3D11_BUFFER_DESC desc;
desc.ByteWidth = size;
desc.MiscFlags = 0;
desc.StructureByteStride = 0;
if(streamout)
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_STREAM_OUTPUT;
else
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
if(dynamic)
{
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE
}
else
{
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.CPUAccessFlags = 0;
}
ID3DBuffer* pBuffer = 0;
HRESULT hr = pDevice->CreateBuffer(&desc,pData,&pBuffer);
if(FAILED(hr))
{
return 0;
}
return pBuffer;
}
Index buffer
Index buffer的基本操作都与vertex buuffer基本类似,详细请参考sdk文档。