DirectX12 - Resource Binding(资源绑定)

这里是SunshineBooming,GPU公司一枚小小的Driver工程师,主要工作是写DirectX12 Driver,我会持续更新这个DX12 Spec系列,可能比较冷门,但是都是干货和工作中的心得体会,有任何GPU相关的问题都可以在评论区互动,知无不言:

DirectX12 Spec 总目录

目录

  • 1. Descriptor
    • 1.1 基本概念
    • 1.2 Descriptor Type
  • 2. Descriptor Heap & Descriptor Range & Descriptor Table
    • 2.1 Descriptor Heap
    • 2.2 Descriptor Range
    • 2.3 Descriptor Table
  • 3. Root Signature
    • 3.1 Signature
    • 3.2 Root Argument、Root Parament
    • 3.3 Descriptor Table、Root Constant、Root Descriptor
  • 4. Limits
    • 4.1 Tier Level
    • 4.2 Root Signature Size
  • 5. API
    • 5.1 CheckFeatureSupport()
    • 5.2 Create Descriptor Heap
      • 5.2.1 Descriptor Heap Type
      • 5.2.2 CreateDescriptorHeap()
      • 5.2.3 如何访问Descriptor Heap中的某个Descriptor?
      • 5.2.4 创建Root Descriptor?
      • 5.2.5 特殊的SOV、RTV、DSV
  • 6. Utils
    • 6.1 Register Space
  • 6. 参考文档

1. Descriptor

1.1 基本概念

  • Descriptor是DX12资源访问的核心概念,什么是Descriptor

  • 官方Spec的解释是:Descriptor is a relatively small block of data that fully describes an object to the GPU。展开来讲,就是CPU会将GPU要访问的Resource(可以理解为Memory)处理好,并把Resource相关信息封装到Descriptor中并提交给GPU,然后GPU端对Descriptor进行解析,并最终访问到相关Resource。

  • 比如说,APP在CPU端调用CreateShaderResourceView(),创建一个类型为SRV(Shader Resource View)的Descriptor,并将所要访问Memory的Address、Format、Dimension等信息填充到这个SRV中。GPU端拿到SRV中的信息,并解析出Memory的Address、Format、Dimension等信息,就可以访问到这块资源了:

void CreateShaderResourceView(
  [in, optional] ID3D12Resource                        *pResource,
  [in, optional] const D3D12_SHADER_RESOURCE_VIEW_DESC *pDesc,
  [in]           D3D12_CPU_DESCRIPTOR_HANDLE           DestDescriptor
);

1.2 Descriptor Type

  • Descriptor按照所访问Resource的类型,可以分为:
  1. Constant buffer view (CBV)Constant buffers contain shader constant data and can be accessed by any GPU shader,注意这里的constant不同于C/C++中的常量,这里的constant是在shader运算过程种保持数据不变,而其他状态可以更新数据。
  2. Unordered access view (UAV)An unordered access view enables the reading and writing to the texture (or other resource) in any order,这里是指为shader无序访问同一块Resource提供读写安全机制,类似于读写锁。
  3. Shader resource view (SRV)Shader resource views typically wrap textures in a format that the shaders can access them,这里SRV为Shader访问Resource最普通的一种形式,无特殊功能。
  4. Samplers:Shader访问采样资源,详细可以查一下细节,Sample采样是提高图形质量的一种手段,在抗锯齿方面有MSAA(多重采样抗锯齿)、SSAA(超级采样抗锯齿)等各种算法。
  5. Render Target View (RTV):Render Target就是dx12整个渲染出来的图形数据,会缓存到buffer中,系统再输出到显示器等,一般调用CreateSwapChainForHwnd()创建一块缓冲区,然后作为缓冲对象输出图形数据。
  6. Depth Stencil View (DSV):做Depth Stencil测试用的缓冲区,3D显示中有图形遮挡的概念,可以用Depth Stencil Buffer缓存像素点的Z坐标,然后根据Z深度判定点是否显示和进一步计算。
  7. Vertex Buffer View (VBV):Vertex用来保存所有输入的顶点信息(像素点用Vertex来表示,可以包括点的空间坐标、颜色、法向量等等,Vertex也可以是用户自定义的各种数据结构),是整个DX12 Pipeline的输入数据。
  8. Index Buffer View (IBV):Index是配合Vertex一起使用的,简而言之就是对于Vertex建立索引,这样对于Vertex大量使用的情况,可以直接用索引代替,不用重复保存Vertex数据。
  9. Stream Output View (SOV):在DX12 Pipeline中,我们可以选择在GS(Geometry Shader)之后,直接将数据通过Stream Output的方式,直接输出出来,SOV定义输出对象。

2. Descriptor Heap & Descriptor Range & Descriptor Table

DirectX12 - Resource Binding(资源绑定)_第1张图片

2.1 Descriptor Heap

  • 有了Descriptor的概念之后,Descriptor Heap也就好理解了:Descriptor heap is the backing memory for descriptors, it is a collection of contiguous allocation of descriptor storage from the API point of view,意思就是Descriptor Heap是分配出来的GPU Memory,是存储Descriptor的地方。

2.2 Descriptor Range

  • 如上图所示,Descriptor Range就是从Descriptor Heap中拎出来的subrange,一段连续的Descriptor。这个概念就像C语言中的数组和子数组。

2.3 Descriptor Table

  • Descriptor Table = Descriptor Range 1 + Descriptor Range 2 + … + Descriptor Range n,我把n个Descriptor Range放在一起,就形成了一个Descriptor Table。
  • 需要指出来的是:Descriptor Table是由Descriptor Range构成的,每个Descriptor Range只能存放CBV/SRV/UAV/Sampler中的一种,不同的CBV/SRV/UAV Range可以混合存放于一个Table中,Sampler需要单独放在一个Descriptor Table中,不可与CBV/SRV/UAV混合存放

3. Root Signature

DirectX12 - Resource Binding(资源绑定)_第2张图片

  • The root signature is the definition of an arranged collection of descriptor table, root constant and root descriptor,这里牵扯的概念有点多,官方文档也没仔细展开讲,我一个个说明:

3.1 Signature

  • 签名的概念应该很多编程语言都有,比如C/C++里面的函数签名,我在.h文件中做了一个函数申明,其中包括了函数形参,规定了传入实参的数据个数、类型等,这就是一个函数签名
  • 对应于DX12里面的Signature,你可以把GPU的Shader(前面提到的GPU流水线的各个运算模块)想象成一个函数,接受Descriptor(参数)并进行运算。开发者必须要在APP层申明一个Root Signature,规定好Shader需要用到哪些Descriptor,这样APP传下去的Descriptor(包含各种Resource信息)和Shader里面用到的(Resource)就会保持一致。

3.2 Root Argument、Root Parament

  • Root Signature类似于函数签名,Root Argument就是函数签名中的各个形参,所有Root Argument组合在一起形成了Root Signature。
  • Root Parament是啥?它其实就是开发者填写好的函数实参,是Root Argument的填好值的样子。

3.3 Descriptor Table、Root Constant、Root Descriptor

  • Descriptor Table:前文阐述过了,不再赘述。还是强调一点,Descriptor Table中只能用来存放CBV/SRV/UAV/Sampler中的1种或者组合
  • Root Descriptor:对于Descriptor Table,GPU会内部分配一块Memory专门存放Descriptor Table,而Root Descriptor则是直接将Descriptor信息放入GPU寄存器,这是硬件做好的。但是也会产生各种问题,比如硬件寄存器的数量是有限的,API申请的Root Descriptor数量可能会超,这些问题都会在Driver层做处理。Root Descriptor只能用来存放CBV/SRV/UAV
  • Root Constant:这个类似于Root Descriptor,不过Root Constant不会存储Resource的地址等信息让GPU解析访问,而是直接保存开发者给的Value,这些数值也是存在硬件寄存器中的,粒度是以32-bit为一个单位。

4. Limits

4.1 Tier Level

  • FL就是Feature Level的意思,可以看到Directx 9/10/11等不同Feature Level条件下,对于硬件需要支持的CBV/SRV/UAV/Sampler的最大数量是有要求的,达到对应的数量,硬件才能上报相应的Feature Level:
Tier 1, FL 9.4, 11.0+ Tier 2, FL 11.0+ Tier 3, FL 11.1+
Max # descriptors in a shader visible CBV/SRV/UAV heap 1000000 1000000 1000000+
Max CBVs in all descriptor tables per shader stage 14 14 full heap
Max SRVs in all descriptor tables per shader stage 128 full heap full heap
Max UAVs in all descriptor tables across all stages 8 (64 for FL 11.1+) 64 full heap
Max Samplers in all descriptor tables per shader stage 16 full heap full heap

4.2 Root Signature Size

  • Root Argument:最大长度是64 DWORDS,这点会在Create Root Signature的时候由DX12 Runtime检查,如果长度超过64 DW并且开启了调试层,Runtime会直接报错并打印详细信息(DX12官方做好的这层Debug Layer很好用,错误信息打印非常全)。
  • Descriptor Table:占用1 DW。
  • Root Descriptor:占用2 DW。
  • Root Constant:占用1 DW * NumOfConstant(1个constant占用32-bit数据,具体占用多少取决于用户申明的NumOfConstant)。

5. API

5.1 CheckFeatureSupport()

  • 上面提到了,DirectX12根据硬件支持的Descriptor数量,将硬件的Feature Level数量划分为Tier1/2/3这3个Level,当DX12的Rumtime调用CheckFeatureSupport()向GPU Driver查询时,硬件可以根据自身情况返回3个Tier Level:
typedef enum D3D12_RESOURCE_BINDING_TIER {
  D3D12_RESOURCE_BINDING_TIER_1 = 1,
  D3D12_RESOURCE_BINDING_TIER_2 = 2,
  D3D12_RESOURCE_BINDING_TIER_3 = 3
} ;

5.2 Create Descriptor Heap

5.2.1 Descriptor Heap Type

typedef enum D3D12_DESCRIPTOR_HEAP_TYPE
{
    D3D12_CBV_SRV_UAV_DESCRIPTOR_HEAP,
    D3D12_SAMPLER_DESCRIPTOR_HEAP,
    D3D12_RTV_DESCRIPTOR_HEAP,
    D3D12_DSV_DESCRIPTOR_HEAP,
    D3D12_NUM_DESCRIPTOR_HEAP_TYPES
} D3D12_DESCRIPTOR_HEAP_TYPE;

5.2.2 CreateDescriptorHeap()

HRESULT CreateDescriptorHeap(
  [in]  const D3D12_DESCRIPTOR_HEAP_DESC *pDescriptorHeapDesc,
        REFIID                           riid,
  [out] void                             **ppvHeap
);
  • 其中需要填充好D3D12_DESCRIPTOR_HEAP_DESC结构体,其中规定了Heap存放Descriptor的类型和数量:
typedef struct D3D12_DESCRIPTOR_HEAP_DESC {
  D3D12_DESCRIPTOR_HEAP_TYPE  Type;
  UINT                        NumDescriptors;
  D3D12_DESCRIPTOR_HEAP_FLAGS Flags;
  UINT                        NodeMask;
} D3D12_DESCRIPTOR_HEAP_DESC;

5.2.3 如何访问Descriptor Heap中的某个Descriptor?

  • 答案是和C/C++中的数组一样,采用Start+Offset的形式,GetCPUHandleForHeapStart()获取Descriptor Heap的Start(不可直接解引用,需要给到DX12 Runtime),GetDescriptorHandleIncrementSize()获取Descriptor的SizeStart + Size * Index即可定位到某个Descriptor。

5.2.4 创建Root Descriptor?

  • Root Descriptor无外乎CBV/SRV/UAV/Sampler,那么我们对应调用CreateShaderResourceView() / CreateConstantBufferView() / CreateUnorderedAccessView()/CreateSampler()即可,注意填充对应的ResourceView参数。

5.2.5 特殊的SOV、RTV、DSV

  • 这3种Descriptor类型在1.1 Descriptor Type有提到过,在GPU Driver层一般有对应的register存储该Descriptor信息,我们只需要将对应的Resource创建好,然后将Resource信息存到Descriptor中,调用CreateStreamOutputView() / CreateRenderTargetView() / CreateDepthStencilView()即可,在Driver中会将Descriptor信息写到对应register。

6. Utils

6.1 Register Space

  • The purpose of the register space field is to expand the namespace for register bindings。举个例子,开发者对于同一个SRV寄存器t#0(t#0就是指t寄存器中的第0个,t#对应SRV,u#对应UAV,s#对应Sampler,c#对应CBV),既想要绑定到Resource0上,又想绑定到Resource1上面,那可以这样声明:在绑定到Resource0时,声明为(t#0,space0),绑定到Resource1时,声明为(t#0,space1)。这里的space0/1就是Register Space,类似于C++中的namespace,我在不同的namespace可以申明同一个名称的变量。

6. 参考文档

  • DirectX-Specs
  • DirectX 12 3D 游戏开发实战(龙书)

你可能感兴趣的:(DirextX12,驱动开发,图形渲染,3d,windows,微软)