七、D3D12学习笔记——根签名&动态顶点缓冲区

基本的流程就是前边6篇的那点东西,之后更多的是专项的剖析。例如:根签名&动态顶点缓冲区。

一、根签名

前边在常量缓冲区构建的时候我们提到过根签名,讲述了它的作用:将常量资源映射到GPU寄存器的特定槽当中,以供着色器取用。之前只以根描述符表的形式,实际还有根常量,根描述符两种,并且介绍根描述符表也可以有多个表,现在来详细看看各自的一些特性。

区别:

根描述符表逻辑:

  1. 创建上传堆,将上传堆地址作为CBV结构体参数创建一个CBV,通过Map和Copy将数据传递到上传堆;
  2. 建立根签名;
  3. 将根参数索引(跟参数定义了数据对应的槽和类型)与CBV地址建立映射;

根描述符&根常量:不再需要CBV,直接建立根参数索引与上传堆的联系。

空间占用:根描述符表和跟常量都占用1DWORD,可以理解为就是一个地址的占用;根描述符占用2DWORD。但是他们能传递的信息量是不同的,根描述符&根描述符表都可以传递数组类(矩阵等),跟常量只传递一个数据,一般根签名以64DWORD为限。

使用方式:

1.根描述符表

后边就是从根参数到根签名部分的序列化,创建等代码,与之前常量缓冲相同,不做赘述。

上图展示了定义多个CBV/SRV/UAV时的使用方法,主要通过Init的最后一个参数来进行偏移设置,最后将根参数InitAsDescriptorTable(根参数size,根参数数组,shader中可见性)。之后的工作就是将对应根参数索引与 描述符 的地址建立映射:

cmdList->SetGraphicsRootDescriptorTable(paramIndex, cbvHandle);

这里有一个技巧可以考虑,Init的最后一个参数是相对起始地址的偏移,一种办法是如上计算偏移,另一种办法是设置为D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,将根据根描述符表中前一个描述符数量来自动计算。

2.根描述符

CD3DX12_ROOT_PARAMETER slotRootParameter[2];
//使用根描述符,直接InitAsConstantBufferView,就没有创建CBV来关联上传堆的部分
slotRootParameter[0].InitAsConstantBufferView(0);//槽号
slotRootParameter[1].InitAsConstantBufferView(1);

后边就是从根参数到根签名部分的序列化,创建等代码,与之前常量缓冲相同,不做赘述。

之后使用:

mCommandList->SetGraphicsRootConstantBufferView(0/*ParamIndex*/, objCBAddress/*上传堆地址*/);

mCommandList->SetGraphicsRootConstantBufferView(1, passCB->GetGPUVirtualAddress());

这里直接是与上传堆地址建立映射,不同于根描述符表是与CBV建立映射(CBV中有上传堆地址),所以核心就是根签名与数据建立流通渠道

注意:根参数一个索引里边只能传单个数据,但数据类型没有限制。

3.根常量

CD3DX12_ROOT_PARAMETER slotRootParameter[1];
//12个数据放在0#槽
slotRootParameter[0].InitAsConstants(12, 0);

 后边就是从根参数到根签名部分的序列化,创建等代码,与之前常量缓冲相同,不做赘述。

std::vector<float> arr(11);
int num = arr.size()/2;
//paramIndex,数据数目,数据,偏移
mCommandList->SetGraphicsRoot32BitConstants(0, 1, &num, 0);
mCommandList->SetGraphicsRoot32BitConstants(0, arr.size(), arr.data(), 1);

可见三种方法都可以利用特定的槽向shader中映射数据,不同之处在于使用的便捷性(是否依赖创建CBV堆和上传堆),数据量大小。

二、动态顶点缓冲区

为什么要用动态顶点缓冲:static的物体,顶点都是通过上传堆存到默认堆,并不要每帧都更新顶点数据,但是当顶点如果每帧都在修改,比如:模拟一个起伏的水面,或者受到力作用变形的面,要让顶点数据的改变反映到shader阶段的顶点中来绘制图形,就需要每帧都更新。要实现每帧更新,那就使用上传堆而不是默认堆。

绘制static物体的顶点数据传输:一次性将顶点与索引都存储到默认堆。

geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(), mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);

geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(), mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);

geo->VertexByteStride = sizeof(Vertex);
geo->VertexBufferByteSize = vbByteSize;
geo->IndexFormat = DXGI_FORMAT_R16_UINT;
geo->IndexBufferByteSize = ibByteSize;

使用动态顶点缓冲:

geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(), mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);

geo->VertexByteStride = sizeof(Vertex);
geo->VertexBufferByteSize = vbByteSize;
geo->IndexFormat = DXGI_FORMAT_R16_UINT;
geo->IndexBufferByteSize = ibByteSize;

这里只有索引,放到了默认堆,因为数据的拓扑关系不变,如果拓扑关系要改变,那么也要使用上传堆。而对于上传堆要类比常量缓冲那样使用CopyData解决:

//上传堆通过Map和memcpy得到的数据
currWavesVB->CopyData(i, v);

//直接将地址给默认堆
geo->VertexBufferGPU = currWavesVB->Resource();

可以看到我们并没有创建顶点数据的默认堆,而是把顶点数据的上传堆地址直接给到默认堆,相当于可以理解,输入装配阶段总是从默认堆去拿数据。我们将这个CopyData及地址设置部分放到每帧的循环里,后边DrawCall则都是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值