图形API基础——Direct X相关

本系列会尝试对图形渲染常用的API比如DX/OpenGL/Metal/Vulcan中的一些术语进行列举与阐述,一方面方便做对比认知,一方面也可用作工作中的工具书使用。为了方便使用,列举的术语还会一并给出对应API版本。此外,由于涉及话题过于宏泛,无法一次性完成,因此内容会随时间不断补充。

  • Constant Buffer:DX10引入了Constant Buffer概念(每个Shader有16个Constant Buffer插槽),允许用户将需要的常量数据组织成一个struct一次性从CPU传给GPU,在Shader中对应的关键字为cbuffer,其数据格式与顺序需要与CPU侧保持一致(使用案例)。
    1. 需要注意的是,Constant Buffer的数据传输是作为一个整体完成的,只要struct中的任一变量发生改变,就需要对整个buffer进行更新,因此在使用的时候建议按照变化频率来组织buffer,保证同一buffer中的变量的修改时机是基本一致的。
    2. Constant Buffer相对于此前版本的Constant Register有何优越之处呢?此前版本的Constant Register基本上对应的是唯一的一个Buffer,因此每次进行Draw调用的时候都需要对这个buffer进行重新设置,而Constant Buffer的引入则可以针对这个过程进行优化,其基本原理是在每一帧中,如果Constant Buffer不做修改,那么在这一帧中的所有DP从这个Constant Buffer中获取的都是第一次设置时的数据不会丢失。按照这个逻辑,如果多个DP共享某一套参数,那么就可以将这套参数单独组织成一个Constant Buffer并在绘制之初设置完成直到所有用到这套参数的绘制完成为止(具体可以参考Windows to Reality: Getting the Most out of Direct3D 10 Graphics in Your Games)。

Resource Types

  • Structured Buffer[1]:这是DX11引入的Resource Type,用于将数据组织成Structure的方式塞入到GPU中,每个Structured Buffer实际上可以看成一个由Structure Elements组成的数组,即Array of Structures(AOS),因此在Shader中对数据进行访问,也可以按照数组的形式直接使用下标实现。在SIMT的Shader执行框架下,多个线程同时对相邻元素(顶点、像素)的同一种数据(比如顶点、颜色等)进行访问,为了保证执行的高效性,最好保证一个Warp/Wavefront中的多个线程读取的数据是相邻的,按照这种思路,数据的组织结构使用Structure of Arrays(SOA,这也是DX10 所推荐的使用策略)会比使用AOS更优秀,为什么DX 11反而推出了AOS的Structured Buffer呢?

    1. 使用时需要注意,每个struct的size最好是128(一个cache line的尺寸)的整数倍(比如128,256等)或者能够整除128(比如32,64等),这样就不会由于一个struct跨越多个cache line导致的性能损失(参考)
    2. StructuredBuffer对应的是只读Buffer,而RWStructuredBuffer对应的则是可读写Buffer,在可读写Buffer中,可以对int/uint类型的元素应用原子函数(Atomic functions)以实现interlocked操作(相当于同步逻辑以保证多个线程同时访问时数据的有效性)。
    3. RWStructuredBuffer与后面给出的RWBuffer的区别在于,RWStructuredBuffer是用Structure组织的各种类型的数据的Element的数组,Structure中的数据类型不支持硬件压缩与解压缩(如R10G10B10A2等特殊的格式到Vector4的转换),而RWBuffer则是支持硬件的压缩与解压缩,但是这个数组中的元素只包含一个某种类型的数据,而不像RWStructuredBuffer一样元素是一个Structure(参考)。
  • Read/Write Buffers and Textures[1]:DX10中的Buffer/Texture都是只读的(因为DX10硬件不支持UAV类型的资源,因此不能对贴图进行直接写入),而这些DX11引入的Resource Type,可以用于实现在Shader中对Buffer/Texture数据的同时读写,目前支持的这类资源具体有以下几种类型:

    1. RWBuffer
    2. RWTexture1D, RWTexture1DArray
    3. RWTexture2D, RWTexture2DArray
    4. RWTexture3D

使用注意事项:

  1. 虽然DX11给出了RWBuffer/RWTexture结构,但在DX11.2之前(包含DX11.2),其使用模式是受限的,具体表现为只有DXGI_FORMAT_R32_UINT格式的贴图数据才支持在同一个shader中对此类UAV进行Read&Write(如果只是Random Access Write的话,可以支持任意格式的UAV;如果只是Random Access Read,则支持任意格式的SRV),对于其他的贴图格式,就需要保证能够实现与DXGI_FORMAT_R32_UINT格式之间的转换,之后通过一种稍微复杂的packing/unpacking逻辑进行读写,具体参考Unpacking and Packing DXGI_FORMAT for In-Place Image Editing。在DX11.3中,可读UAV的格式限制被大大放宽,基本上保持与DX12一致,具体情况可以参考类型化无序访问视图 (UAV) 加载。
  • BYTE ADDRESS (RAW) BUFFERS[1]:Byte address buffers也称为Raw Buffers,是DX11引入的一种特殊的Buffer类型,这种Buffer通常是通过使用一个(相对于Buffer起始位置的)字节偏移量(即偏移量以字节为单位)来对数据进行访问的,这跟平常所熟知的通过数组下标访问的方式有着较为明显的区别。
    1. 字节偏移量也不是任意的整数,其约束条件为必须是4的倍数(即以word作为对齐单位),这是因为raw buffer中的数据总是按照32位无符号整数的方式来解析的(当然,也可以存储其他的数据类型,之后在shader中通过类似于asfloat之类的函数进行解析)。
    2. Raw buffer既可以用作VB也可以用作IB,因此非常适合用在CS中来生成geometry的mesh数据。
    3. DX目前支持的Raw buffer主要有两类:ByteAddressBuffer,RWByteAddressBuffer。
    4. 可以看成是一个特殊的RWStructuredBuffer,特殊在于可以用于实现VB/IB(RWStructuredBuffer是不能用作这个用途的)
  • Unordered Access View(UAV)[1]:这是在DX10中推出的可以实现对数据的无序读写的资源类型,在DX10中只有CS(Compute Shader)可以使用此类型,而在DX11中将其使用范围扩展到Pixel Shader上。借助这个实现机制,或许后面可以用于实现类似于A-buffer算法,即每个像素可以挂接多个fragments(如可以用于实现多层depth)

参考文献

1. DirectCompute PROGRAMMING GUID

你可能感兴趣的:(图形API基础——Direct X相关)