D3D12常用术语与函数

“计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决”
“Any problem in computer science can be solved by another layer of indirection.”

概览

D3D实质上就是一种状态机(state machine),里面的事物会保持它们各自的状态,直到我们将其改变。

I开头对象:COM 接口都以大写字母“I”作为开头。例如表示命令列表的COM接口为 ID3D12GraphicsCommandList
C开头对象:一些辅助方法。如 CD3D12_RASTERIZER_DESC

常用术语

  • COM:组件对象模型(Component Object Model)。这是基于Windows 平台的一套组件对象接口标准。通常将COM对象视为一种接口,但当考虑当前编程的目的,遂将其当作一个C++类来使用。 COM对象会统计其引用次数,因此在使用完某接口时我们应调用它的 Release 方法而不是 delete ——当COM对象的引用计数为0它将自行释放自己所占用的内存
    “COM技术的奇怪地方在于微软实在是脑洞太大了,它们构造了一个操作系统级别的Factory,规定所有人的Interface都统一用UUID来标识,以后想要哪个Interface只要报出UUID来就行了。这样甚至连链接到特定的dll都省了。”
    来自:https://www.zhihu.com/question/49433640/answer/115952604
    注:COM 接口都以大写字母“I”作为开头。例如表示命令列表的COM接口为 ID3D12GraphicsCommandList

  • UUID:UUID 通用唯一识别码(Universally Unique Identifier)
    GUID:目前最广泛应用的UUID,是微软公司的全局唯一标识符GUID。全局唯一标识符(GUID,Globally Unique Identifier)

  • ComPtr:可以把它当作是COM对象的智能指针。常用的ComPtr方法有Get(返回一个指向此底层COM接口的指针)、GetAddressOf(返回指向此底层COM接口指针的地址)、Reset(将此ComPtr实例设置为nullptr 释放与之相关的所有引用(同时减少其底层COM接口的引用计数),此方法的功能与将 ComPtr 目标实例赋值为 nullptr 的效果相同)
    (注:Microsoft::WRL::ComPtr类,#include <wrl.h>,Windows运行时库 Windows Runtime Library 即 WRL)

  • 交换链(swap chain):前台缓冲区(front buffer)和后台缓冲区(back buffer)构成了交换链。

  • 描述符(descriptor):一种对送往GPU的资源进行描述的轻量级结构。本质上是一个中间层:指定了资源描述符,GPU就可以获得实际的资源数据。同时也能了解到资源的必要信息。我感觉有点类似于不同编码解释字节流,描述符就是解释那些资源,比如解释成 常量缓冲区视图(constant buffer view,CBV)、着色器资源视图(shader resource view,SRV)、无序访问视图(unordered access view,UAV)、采样器资源(sample,用于纹理贴图)、渲染目标视图资源(render target view,RTV)、深度/模板视图资源(depth/stencil view,DSV)

  • 视图(view):与描述符是同义词。是D3D旧版本的常用术语。龙书中视图与描述符交替使用。

  • 描述符堆(descriptor heap):存有一系列描述符(可将其看作是描述符数组),本质上是存放用户程序中某种特定类型描述符的一块内存。(龙书 P84、P107)

  • 子像素(subpixel):文中指像素内部再次细分出的小像素,用以采样。(好像有时又指显示器硬件层面的子像素,迷惑)

  • 显示适配器(display adapter):龙书 P89。适配器用接口 IDXGIAdapter 来表示。

  • 命令队列:command queue,本质上是环形缓冲区ring buffer。线程自由对象(龙书P102)。
    命令列表:command list,可用其将命令提交到命令队列中。不是线程自由对象。
    命令分配器:command allocator,每个记录在命令列表内的命令都存储在与之相关联的命令分配器上。本质上是一个内存管理类接口。不是线程自由对象。

  • IID_PPV_ARGS:一个辅助函数,IID_PPV_ARGS(ppType) 是将 ppType 强制转换为 void** 类型

  • 围栏(fence):可以用来刷新命令队列(flushing the command queue,强制CPU等待直到GPU完成所有命令的处理,达到某个指定的围栏点fence point)。龙书 P98
    转换资源屏障(transition resource barrier):通过命令列表设置转换资源屏障数组,即可指定资源的转换(比如从渲染目标状态转换为着色器资源状态)。龙书 P100、P101

  • Resource:ID3D12Resource接口将物理内存与堆资源抽象组织为可处理的数据数组与多维数组,从而使CPU和GPU可以对这些资源进行读写。 D3D不存在3D纹理数组的概念。

  • 堆(Heap):GPU资源都存于堆中,其本质是具有特定属性的 GPU 显存块。
    在 D3D12_HEAP_PROPERTIES 的 D3D12_HEAP_TYPE 枚举类型中的成员有:默认堆(default heap,向这堆里提交的资源只有GPU可以访问)、上传堆(upload heap,向这堆里提交的都是需要经CPU上传至GPU的资源)、回读堆(read-back heap,向这堆里提交的都是需要由CPU读取的资源)等。(龙书 P111)
    为了使性能达到最佳,通常应将资源放置于默认堆中。只有在需要使用上传堆或回读堆的特性之时才选用其他类型的堆。
    对于静态几何体(static geometry,即每一帧都不会发生改变的几何体)而言,我们会将其顶点缓冲置于默认堆(D3D12_HEAP_TYPE_DEFAULT)中来优化性能。(龙书 P179)

  • 上传缓冲区(upload buffer):使用D3D12_HEAP_TYPE_UPLOAD这种堆类型来创建上传缓冲区后,就可以将顶点数据从系统内存复制到上传缓冲区,而后再把顶点数据从上传缓冲区复制到真正的顶点缓冲区中。且在d3dUtil.h/.cpp 中构建了一个工具函数。(龙书P179)

  • 输入布局描述(input layout description):提供顶点结构体的描述,对应结构体D3D12_INPUT_LAYOUT_DESC。(龙书P175)输入布局描述由两部分组成:一个 D3D12_INPUT_ELEMENMT_DESC 元素构成的数组(该数组中的元素要与顶点结构体的成员一一对应),一个记录该数组中元素个数的无符号整数。
    事实上,输入布局描述为结构体 D3D12_GRAPHICS_PIPELINE_STATE_DESC 中的一个字段,也就是说输入布局描述实为 PSO 的一个组成部分,用于与顶点着色器输入签名进行各式的比对验证。因此当PSO与渲染流水线绑定时,输入布局也将以PSO组成元素的身份随PSO与渲染流水线的IA阶段(Input Assembler,输入装配器阶段,详见P146)相绑定(P229)

  • 输入槽(input slot index):可以通过它们来向输入装配阶段传递顶点数据。D3D共支持16个输入槽(0~15)。(龙书 P177、P182)
    将顶点缓冲区设置到输入槽并不会对其执行实际的绘制操作,而是仅为顶点数据送至渲染流水线做好准备而已。这最后一步才是通过 ID3D12GraphicsCommandList::DrawInstanced方法(D3D12精简为3种绘制调用方法,这只是一种)真正绘制顶点。(龙书 P183、P185)

  • 顶点缓冲区(vertex buffer):存储顶点的缓冲区。(龙书P178)
    索引缓冲区(index buffer):存储索引的缓冲区。(龙书P184)
    这两个缓冲区,为了绑定上渲染流水线(即传到渲染流水线该如何去解释这两个缓冲区),都会创建两个缓冲区视图。并且顶点缓冲区视图(vertex buffer view)和索引缓冲区视图(index buffer view)都不需要创建对应的描述符堆。而是通过对应的命令列表的 IASetVertexBuffers 方法去进行绑定(龙书P182、P184)

  • 常量缓冲区(constant buffer):也是一种GPU资源(ID3D12Resource),其数据内容可供着色器程序所引用。通常由CPU每帧更新一次。(龙书P195、P196)
    常量缓冲区视图(constant buffer view,CBV):(龙书P196)。需要存放在以 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV 类型所建的描述符堆里。这种堆内可以混合 常量缓冲区描述符、着色器资源描述符和无序访问描述符(龙书P201)

  • 子资源(subresource):龙书P198

  • Map、Unmap:CPU端分配的某块虚拟内存到GPU中的资源的映射、取消映射(龙书P198)

  • 寄存器槽(register slot):寄存器槽就是向着色器传递资源的手段,register(*#)中*表示寄存器传递的资源类型,可以是t(表示着色器资源视图)、s(采样器)、u(无序访问视图)、以及b(常量缓冲区视图),#则为所用的寄存器编号。(龙书P203)
    例如:cbuffer cbPerObject : register(b0)

  • 根签名(root signature):定义:在执行绘制命令之前,那些应用程序将绑定到渲染流水线上的资源,它们会被映射到着色器的对应输入寄存器。(龙书P203)
    如果把着色器程序当作一个函数,而将输入资源看作着色器的函数参数,那么根签名则定义了函数签名。
    从 PSO 被创建之时起,根签名和着色器程序的组合就开始生效(P262)
    D3D中,根签名由ID3D12RootSignature接口来表示,并以一组描述绘制调用过程中着色器所需资源的根参数(root parameter)定义而成。
    根参数可以是 根常量(root constant)、根描述符(root descriptor)、根描述符表(descriptor table)(龙书P204、P263)。描述符表指定的是描述符堆中存有描述符的一块连续区域。
    在代码中要通过填写 CD3DX12_ROOT_PARAMETER 结构体来描述根参数(P263)

  • .cso文件(compiled shader object,已编译的着色器对象):离线编译着色器。.cso作为已编译着色器的扩展名。(P208)

  • 光栅器状态(rasterizer state):由结构体 D3D12_RASTERIZER_DESC 来表示。其中有三个关键成员:FillMode(实体还是线框模式渲染)、CullMode、FrontCounterClockwise(P213)

  • 流水线状态对象(Pipeline State Object,PSO):大多数控制图形流水线状态的对象被统称为流水线状态对象,用 ID3D12PipelineState 接口表示。要创建PSO,我们首先要填写一份描述其细节的 D3D12_GRAPHICS_PIPELINE_STATE_DESC 结构体实例。(龙书P214)
    如果把一个PSO与命令列表相绑定,那么,在我们设置另一个 PSO 或重置命令列表之前,会一直沿用当前的 PSO 绘制物体。(P217)

  • 帧资源(frame resource):以CPU每帧都需要更新的资源作为基本元素,创建一个环形数组(circular array,也有译作循环数组)。称这些资源为帧资源(frame resource),而这种循环数组通常是由3个帧资源元素所构成的。(P236)

  • 渲染项(render item):我们把单次绘制调用过程中,需要向渲染流水线提交的数据集称为渲染项(render item)。P238

  • 寻址模式(address mode):重复寻址模式(wrap)、边框颜色寻址模式(border color)、钳位寻址模式(clamp)、镜像寻址模式(mirror)(P339)寻址模式由枚举类型 D3D12_TEXTURE_ADDRESS_MODE 来表示(P341)

  • 静态采样器:特殊的方式来定义采样器数组,使用户可以在不创建采样器堆的情况下也能对它们进行配置。 CD3DX12_ROOT_SIGNATURE_DESC 类有两种参数不同的 Init 函数,用户可借此为应用程序定义所用的静态采样器数组。 我们通过结构体 D3D12_STATIC_SAMPLER_DESC 来描述静态采样器(P344),它与 D3D12_SAMPLER_DESC 结构体(P342)有些类似。

  • 混合状态(blend state):就像其他的Direct3D状态一样,混合状态亦是PSO的一部分。为了配置非默认混合状态,我们必须填写 D3D12_BLEND_DESC 结构体。(P363)其中的RenderTarget为具有8个 D3D12_RENDER_TARGET_BLEND_DESC 元素的数组(P364)

  • 数组切片(array slice):表示纹理数组中的某个纹理及其 mipmap 链
    mip切片(mip slice):表示纹理数组中特定层级的所有 mipmap
    纹理子资源(subresource):纹理数组中某纹理的单个mipmap层级
    平面切片(plane slice):使用户将某些 YUV 平面格式(planar format)的分量以索引方式单独提取出来,以供使用。若程序不涉及此功能,可将参数 PlaneSlice 设置为0
    请添加图片描述

常用API

  • ID3D12Device:要初始化Direct3D,必须先初始化Direct3D 12 设备(ID3D12Device)。此设备代表着一个显示适配器(一般来说是一种3D图形硬件如显卡)。(P102)

  • Signal:ID3D12CommandQueue::Signal 方法从 GPU 端设置围栏值,而 ID3D12Fence::Signal 方法则从 CPU 端设置围栏值。(P99)ID3D12CommandQueue::Signal(fence, n + 1) 方法实际上只是在命令列表的结尾处添加了一条命令,使围栏值变为 n + 1(n初始值为0)。而在GPU处理完命令队列中Signal(fence, n + 1)之前的所有命令以前,CPU端调用的 mFence->GetCompletedValue() 方法会一直返回值 n(P100)

  • IID_PPV_ARGS:一个辅助函数,IID_PPV_ARGS(ppType) 是将 ppType 强制转换为 void** 类型

  • ID3D12Resource:D3D12中,所有的资源均用ID3D12Resource接口表示
    资源的类型由 D3D12_RESOURCE_DESC::D3D12_RESOURCE_DIMENSION 字段来加以区分。
    例如缓冲区用 D3D12_RESOURCE_DESC::D3D12_RESOURCE_DIMENSION_BUFFER 类型表示,
    而2D纹理则以 D3D12_RESOURCE_DESC::D3D12_RESOURCE_DIMENSION_TEXTURE2D 类型表示。

  • ID3D12Device::CreateDescriptorHeap方法来创建描述符堆。(龙书 P107)
    ID3D12Device::CreateCommittedResource:根据我们所提供的属性创建一个资源与一个堆,并把该资源提交到这个堆中。(龙书P111)要创建缓冲区资源需要填写D3D12_RESOURCE_DESC结构体,再调用 ID3D12Device::CreateCommittedResource 方法。顶点缓冲区的视图与索引缓冲区的视图分别用 D3D12_VERTEX_BUFFER_VIEW 与 D3D12_INDEX_BUFFER_VIEW 结构体加以描述。(P229)
    ID3D12Device::CreateConstantBufferView:结构体 D3D12_CONSTANT_VIEW_DESC 描述的是绑定到 HLSL 常量缓冲区结构体的常量缓冲区资源子集。这里把该实例(常量缓冲区描述符)存放到以 D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV 类型所建的描述符堆里。(P202)
    ID3D12Device::CreateGraphicsPipelineState:创建 ID3D12PipelineState 对象。(龙书P216)

  • ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable:只要率先通过命令列表(command list)设置好根签名,我们就能用此方法令描述符表与渲染流水线相绑定。(P205)
    ID3D12GraphicsCommandList::IASetVertexBuffers、IASetIndexBuffers:通过此方法分别将顶点缓冲区与索引缓冲区绑定到渲染流水线的IA阶段(P229、P182)
    ID3D12GraphicsCommandList::DrawInstanced、DrawIndexedInstanced:绘制非索引(non-indexed)描述的几何体(即已顶点数据来绘制的几何体)可借助 ID3D12GraphicsCommandList::DrawInstanced 方法,而以索引描述的几何体可由 ID3D12GraphicsCommandList::DrawIndexedInstanced 方法进行绘制。(P229)
    ID3D12GraphicsCommandList::SetGraphicsRoot32BitConstants:设置根常量(P268)
    ID3D12GraphicsCommandList::OMSetBlendFactor:通过这种方法可直接指定所用的混合因子值。但是在改变混合状态(blend state)之前此值是不会生效的。(P362、P363)
    ID3D12GraphicsCommandList::ClearDepthStencilView:可以在绘制每一帧之初,用这个方法来重置模板缓冲区中的局部数据(也可用于清理深度缓冲区)(P380)
    ID3D12GraphicsCommandList::OMSetStencilRef:以一个无符号整数作为参数,表示如何来设置模板参考值。(P385)
    ID3D12GraphicsCommandList::Dispatch:开启一个由线程组构成的 3D 网格。(P428)

  • D3DCompileFromFile:在DX中,着色器程序必须先被编译成一种可移植的字节码,这样图形驱动程序才能将其继续编译成针对当前系统GPU所优化的本地指令。我们可以在运行期间使用这个函数对着色器进行编译。(龙书P206)

  • D3D12_SHADER_BYTECODE:这个结构体存有指向已编译好的字节码数据的指针,以及该字节码数据所占的字节大小(P214)

  • ID3DBlob:Blob数据类型以随机存取块的形式存储任何种类的二进制数据。比如在(龙书P218页)中就把顶点/索引用Blob类型来表示(因为它们可以是泛型格式,具体格式应该依用户而定),等到用户在使用时再将其转换为适当的类型。

  • ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart:可以获得堆中第一个描述符的句柄。
    示例(P260):

auto handle = CD3DX12_CPU_DESCRIPTOR_HANDLE(mCbvHeap->GetCPUDescriptorHandleForHeapStart());
handle.Offset(n, mCbvSrvUavDescriptorSize);
最后一行等价于:
handle.Offset(n * mCbvSrvUavDescriptorSize);

通过如上代码偏移到第n个描述符的句柄处,之后可以填入描述符:
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc;
cbvDesc.BufferLocation = cbAddress;
cbvDesc.SizeInBytes = objCBByteSize;

md3dDevice->CreateConstantBufferView(&cbvDesc, handle);

其中mCbvSrvUavDescriptorSize需要从设备上查询(P259、P260)

HLSL参考

HLSL中与C++相同(类似)的地方:

  • 变量修饰符const、结构体struct(但是不能含有成员函数)、typedef关键字
  • HLSL有极其灵活的强制转换机制(龙书P717、P720)
  • HLSL中有很多运算符与C++的非常相似,不过有的有差异(比如取模运算符%既可以用于整数也能用于浮点数,且HLSL中必须保证%左右操作数同正或同负)
  • 支持一些C++中常见的选择、循环以及顺序程序流控制语句(比如return、if else、for、while、do while)
  • HLSL中函数采用类C++语法(除了in、out和inout关键字以外,其余语法和C++中的函数基本一致),且参数只能按值传递、不支持递归且强制内联函数(龙书P721)

*号对于向量是标量式乘法。若要进行矩阵乘法运算则应该用mul函数。

HLSL中常用的内置函数:龙书P723

HLSL中常量缓冲区的封装规则:会以补齐填充(padding)的方式将其中的元素都包装成4D向量(龙书P725),但是数组例外(龙书P727)

微软官方手册:
https://docs.microsoft.com/zh-cn/windows/win32/direct3dhlsl/dx-graphics-hlsl
完整的内置函数:
https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-intrinsic-functions
关键字:
https://docs.microsoft.com/zh-cn/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords
常量缓冲区:
https://docs.microsoft.com/zh-cn/windows/win32/direct3dhlsl/dx-graphics-hlsl-constants

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值