本章主要讲了些D3D12概念和理论,对第一、二章相关概念的补充和纠正,要的理解D3D12概念和理论基础,结合代码加深理解。
命令队列和命令列表
为了实现渲染工作的重用和多线程缩放, 在 D3D12 中,做了三个重要方面不同于 早期版本的改变:
-
- 消除了即时上下文。 这样可以实现多线程。
-
- 应用现在拥有将渲染调用分组到图形处理单元 (GPU) 工作项中的方法。 这样可以重 复使用。
-
- 应用现在显式控制何时将工作提交到 GPU。 这可实现第 1 项和第 2 项。
**常用命令列表的类型 (**D3D12_COMMAND_LIST_TYPE)
-
1直接命令列表 DIRECT
-
2.捆绑 BUNDLE
-
3计算命令列表 COMPUTE
-
4.复制命令列表COPY
typedef enum D3D12_COMMAND_LIST_TYPE
{
D3D12_COMMAND_LIST_TYPE_DIRECT = 0,
D3D12_COMMAND_LIST_TYPE_BUNDLE = 1,
D3D12_COMMAND_LIST_TYPE_COMPUTE = 2,
D3D12_COMMAND_LIST_TYPE_COPY = 3,
D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE = 4,
D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS = 5,
D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE = 6,
D3D12_COMMAND_LIST_TYPE_NONE = -1
}
命令列表的创建
-
命令列表是由命令分配器 创建的,通过调用CreateCommandAllocator 创建命令分配器,再由命令分配器创建命令列表,关联一个图形管道状态(PSO)对象,如果此参数为 NULL,则使用默认状态。分配器的命令列表类型(由 D3D12_COMMAND_LIST_TYPE 指定)必须与所创建的命令列表类型匹配。如下:
void CD3D12Triangle::CreateGPUPipelineState(ComPtr<ID3D12PipelineState>& pipelineState, ComPtr<ID3D12CommandAllocator>& commandAllocator, ComPtr<ID3D12GraphicsCommandList>& commandList)
{
...
ThrowIfFailed(m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator)));
ThrowIfFailed(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator.Get(), m_pipelineState.Get(), IID_PPV_ARGS(&commandList)));
...}
-
ID3D12GraphicsCommandList::Close() 标记完成后再交给ID3D12CommandQueue::ExecuteCommandLists()执行,再次使用时要先ID3D12GraphicsCommandList::Reset()操作ID3D12GraphicsCommandList 中的大多数 API 不会返回错误。建命令列表期间遇到的错误将推迟到 ID3D12GraphicsCommandList::Close(),
-
对提供的命令列表调用 ID3D12GraphicsCommandList::Close,标记完成记录
-
大多数 D3D12 API 继续遵循 COM 约定使用引用计数。一个值得注意的例外情况是 ID3D12GraphicsCommandList 中的所有 API 不保留对传入 这些 API 的对象的引用。 这意味着,应用程序需负责确保永远不会提交引用已销毁资源的命令列表以供执行
命令队列
一般情况下,DIRECT 队列和命令列表接受任何命令,COMPUTE 队列和命令列表接受计算和复制相关的命令,COPY 队列和命令列表仅接受复制命令。
命令队列使用围栏同步命令列表执行
这种设计也意味着应用需要显式管理工作同步,尤其是当一个队列中的命令列表依赖于另一个命令队列操作的资源时。
多引擎同步(围栏)
大多数新式 GPU 都包含多个独立引擎,可提供专门的功能。 许多 GPU 拥有一个或多个 专用复制引擎和一个计算引擎,3D引擎。使用队列和命令列表提供对 3D 引擎、计算引擎和复制引擎访问, 这些引擎可以彼此并行执行命令。使用围栏同步命令执行。如纹理先用复制引擎然后用3D引擎显示.
围栏相关API
-
ID3D12Fence::GetCompletedValue() :返回围栏的当前值。
-
ID3D12Fence::SetEventOnCompletion() :围栏达到给定的值时激发事件。
-
ID3D12Fence::Signal() :从CPU端更新围栏值。
-
ID3D12CommandQueue:Signal() 从 GPU端更新围栏值, 在命令队列上完成所有其他操作后,将发生此更新。围栏使用代码:
cppvoid CD3D12Texture::WaitForPreviousFrame(void) { // m_fenceValue初值为1 const UINT64 fence = m_fenceValue; ThrowIfFailed(m_commandQueue->Signal(m_fence.Get(), fence)); //在命令队列上完成所有其他操作后,将GPU端围栏值更新为1。 m_fenceValue++; if (m_fence->GetCompletedValue() < fence) { // 用一个事件去等GPU端围栏值更新 ThrowIfFailed(m_fence->SetEventOnCompletion(fence, m_fenceEvent)); //围栏达到给定的值时激发事件m_fenceEvent WaitForSingleObject(m_fenceEvent, INFINITE); } m_frameIndex = m_swapChain->GetCurrentBackBufferIndex(); }
命令队列 使用资源屏障访问资源
在 D3D12 中,同步某些资源的状态是使用资源屏障实现的。 在每个资源屏障中, 应用声明资源的之前和之后状态。 一个常见示例是资源在着色器资源视图与渲染器目标 视图之间转换。
图形管道状态(PSO)****
-
当几何图形提交到要绘制的图形处理单元 (GPU) 时,有各种硬件设置可用来确定如何解 释和呈现输入数据。 这些设置统称为图形管道状态,并包括光栅器状态、混合状态和深 度模具状态以及提交的 几何图形的基元拓扑类型和将用于呈现的着色器等常见设置。 在 D3D12 中,大多数图形管道状态是使用管道状态对象 (PSO) 设置的。 应用可以创建无限数量的这些对象,然后在呈现时,命令列表可以通过调用直接命令列表或捆绑中的
-
ID3D12GraphicsCommandList::SetPipelineState() 来设置活动 PSO,以便快速切换管道状 态的多个设置。
-
请注意,虽然大多数管道状态设置是使用 PSO 设置的,但有一些状态设置是使用 ID3D12GraphicsCommandList 提供的 API 单独设置的。
资源屏障
为了减少总体 CPU 使用率并启用驱动程序多线程和预处理,D3D12将按资 源状态管理的责任从图形驱动程序转移到应用程序。
资源屏障有三种类型
1.转换屏障
-
转换屏障指示不同用法之间的一组子资源转换。
2.失真屏障
- 失真屏障指示两个不同资源的用法之间的转换,这些资源在同一个堆中 存在重叠的映射。 这适用于保留的资源和定位的资源。
3.无序访问视图 (UAV) 屏障
- UAV 屏障指示对特定资源的所有 UAV 访问(读取或写 入)必须在任何后续 UAV 访问(读取或写入)之间完成。
性能影响
总而言之,每当其语义允许在不发出 ResourceBarrier 调用的情况下转换状态时,都请尝 试依赖于通用状态提升和衰减。
通用状态提升
- 访问时从D3D12_RESOURCE_STATE_COMMON隐式提升到相关状态
通用状态衰减
-
访问时从相关状态隐式降回到D3D12_RESOURCE_STATE_COMMON。
-
通用状态提升和衰减都是无开销的,因为不需要附加的同步。 将通用状态提升和 衰减相结合有助于消除许多不必要的 ResourceBarrier 转换。 在某些情况下,这可以大幅 提高性能。
资源提交方式
已提交资源CreateCommittedResource()
同时创建资源和堆。 堆是隐式的,不可直接访问。 堆的大小适当,可在其中放置整个资源。
已定位资源 CreatePlacedResource()
允许将资源放在堆中的非零偏移位置。 已定位资源不能直接重新定位或重新映射到另一个堆;但 是,使用它们可在堆之间方便地重新定位资源数据。 在不同的堆中创建新的已定位 资源并复制资源数据后,必须对新的资源数据位置使用新的资源描述符。
已保留资源 CreateReservedResource()
仅当适配器支持图块式资源层 1 或更高的层时,已保留资源才可用。 如果可用,它 们会提供可用的最先进驻留管理技术;但目前并非所有适配器都支持这些技术。
资源类型和视图
资源类型
- Texture1D/Texture2D/Texture3D
- 缓冲区(类型化、结构化和原始)
资源视图
-
常量缓冲区视图 (CBV)
-
无序访问视图 (UAV)
-
着色器资源视图 (SRV)
-
采样器
-
渲染器目标视图 (RTV)
-
深度模板视图 (DSV)
-
索引缓冲区视图 (IBV)
-
顶点缓冲区视图 (VBV)
-
流输出视图 (SOV)
-
着色器资源(例如纹理、常量表、图像、缓冲区等不会直接绑定到着色器管道,而是通过描述符进行引用。 描述符是包含有关一个资源的信息的小型对象。
-
描述符组合在一起构成了描述符表。
-
每个描述符表存储有关一个资源类型范围的信息。
-
例如: 常量缓冲区视图 (CBV) 无序访问视图 (UAV) 着色器资源视图 (SRV) 采样器 SRV、UAV 和 CBV 描述符可以合并到同一个描述符表中。
-
图形和计算管道通过按索引引用描述符表来获取对资源的访问权限。 描述符表存储在描述符堆中。 在理想情况下,描述符堆包含要渲染的一个或多个帧的所 有描述符(在描述符表中)。 所有资源将存储在用户模式堆中。
描述符种类
描述符由 API 调用创建并标识资源。
1. 描述符数据
-
是一个相对较小的数据块,以 GPU 特定的不透明格式全面描述提交到 GPU 的对 象。 有多种不同类型,如:呈现目标视图 (RTV)、深度模具视图 (DSV)、着色器资源 视图 (SRV)、无序访问视图 (UAV)、常量缓冲区视图 (CBV) 和采样器,描述符的大小因 GPU 硬件而异。
-
可以通过调用 ID3D12Device::GetDescriptorHandleIncrementSize 来查询 SRV、UAV 或 CBV 的大小。
-
无需释放对象描述符。 驱动程序不会为描述符创建附加任何分配。 但是,描述符可能会 对应用程序永久拥有的其他分配的引用进行编码。 例如,SRV 的描述符必须包含 SRV 引 用的 D3D 资源(例如纹理)的虚拟地址。 由应用来确保在 SRV 描述符所依赖的基础 D3D 资源已被销毁或修改(例如,声明为非常驻)时不使用该描述符。 使用描述符的主要方法是将它们放置在描述符堆中,这些描述符堆是描述符的后备内存。
2. 描述符句柄
-
描述符句柄是描述符的唯一地址。 它类似于指针,但不透明,因为其实现特定于硬件。 句柄在描述符堆唯一,例如,句柄数组可以引用多个堆中的描述符。
-
CPU 句柄可供立即使用,
-
GPU 句柄不可立即使用,它们从命令列表中确定位置,以便在 GPU 执行时使用。 必须保 留它们,直到引用它们的任何命令列表已完全执行为止。
-
请调用以下方法之一:
-
ID3D12DescriptorHeap::GetCPUDescriptorHandleForHeapStart 返回 CPU 可见描述符堆的 CPU 句柄。 如果描述 符堆对 CPU 不可见,则将返回 NULL 句柄(并且调试层将报告错误)。
-
ID3D12DescriptorHeap::GetGPUDescriptorHandleForHeapStart 返回着色器可见描述符堆的 GPU 句柄。 如果描 述符堆对着色器不可见,则将返回 NULL 句柄(并且调试层将报告错误)。
-
由于描述符大小因硬件而异,因此若要获得堆中的每个描述符之间的增量,请使用: ID3D12Device::GetDescriptorHandleIncrementSize 可以安全地使用若干增量偏移起始位置,复制句柄并将句柄传递到 API 调用数中。
3.Null 描述符
-
使用 API 调用创建描述符时,应用程序针对描述符定义中的资源指针传递 NULL 以达到被 着色器访问时未绑定的效果。
-
总之,若要创建 null 描述符,请在使用 CreateShaderResourceView 等方法创建视图时 针对 pResource 参数传递 null。 对于视图描述参数 pDesc,设置在资源不是 null 时可 行的配置(否则,某些硬件可能会崩溃)。
4. 默认描述符
-
若要创建特定视图的默认描述符,请传入有效的 pResource 参数,以创建视图方法(例 如,CreateShaderResourceView),但为 pDesc 参数传入 null。 例如,如果资源包含 14 个 mip,则视图将包含 14 个 mip。 默认情况包含资源到视图的最明显映射。 这需要 资源分配有完全限定的格式名称(例如 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,而 不是 DXGI_FORMAT_R8G8B8A8_TYPELESS)
-
默认描述符不能与光线跟踪加速结构视图一起使用,因为提供的 pResource 参数必须为 NULL,并且必须通过 D3D12_RAYTRACING_ACCELERATION_STRUCTURE_SRV传递位置。
描述符堆
描述符堆是描述符的连续分配的集合,每个描述符有一个分配。
描述符堆包含不属于管道状态对象 (PSO) 的许多对象类型,例如,着色器资源视图 (SRV)、无序访问视图 (UAV)、常量缓冲区视图 (CBV) 和取样器。
描述符堆的主要用途是包含所需的批量内存分配,用于存储着色器在尽可能大的渲染窗口 (最好是在整个渲染帧或更大的窗口)中引用的对象类型的描述符规范。
相同的描述符堆中存在一些限制。 CBV、UAV 和 SRV 条目可以位于相同的描述符堆中。 但是,取样器条目不能共享带有 CBV、UAV 或 SRV 条目的堆。 通常,有两组描述符堆, 一组用于公共资源,另一组用于取样器。
描述符堆只能由 CPU 立即编辑,没有选项可以由 GPU 编辑描述符堆。
绑定
任何时候最多可以绑定一个 CBV/SRV/UAV 组合堆和一个取样器堆。 这些堆在图形管道 和计算管道之间共享(如其 PSO 中所述)。
切换堆
可以接受应用程序使用 SetDescriptorHeaps 和 Reset API 在相同或不同的命令列表中切 换堆。 在某些硬件上,此操作开销巨大,需要 GPU 停滞才能刷新依赖于当前绑定的描述 符堆的所有工作。
着色器可见描述符堆
着色器可见描述符堆是着色器可通过描述符表引用的描述符堆。
可以包含着色器资源视图、无序访问视图和 常量缓冲区视图,所有这些内容都混合在一起。
另一个堆类型(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER)仅存储采样器。
着色器不可见描述符堆
着色器无法通过描述符表引用部分描述符堆,但描述符堆的存在是为了帮助应用在记录命 令列表之前暂存描述符,或者是因为不需着色器可见堆。
创建描述符堆
若要创建和配置描述符堆,必须选择描述符堆类型,确定所包含的描述符数,并设置指示 CPU 是否可见和/或着色器是否可见的标志。
描述符表
描述符表在逻辑上是描述符数组。
每个描述符表存储一个或多个类型的描述符 - SRV、UAV、CBV 和采样器。 描述符表不是内存分配;它只是描述符堆中的偏移量和长度。
描述符表(每个表标识描述符堆中的一个范围)绑定在由命令列表上的当前根签名所 定义的槽中。
引用描述符表
图形管道通(pso)过根签名通过索引引用描述符表来获取对资源的访问权限。描述符表实际上只是描述符堆的子范围。 描述符堆表示一批描述符的基础内存分配。因此从一个描述符表中定义描述符表可以保证与将堆 中的区域标识到硬件一样便宜。不需要在 API 级别创建或销毁描述符表 - 系统仅会在堆 被引用时向驱动程序将它们标识为堆的偏移量和大小。
可共享相同的描述符表和堆
- 着色器资源视图
- 无序访问视图
- 常量缓冲区视图
不可共享相同的描述符表和堆(必须独立)
- 采样器
以下资源不在描述符表或堆中,而是使用命令列表直接绑定
- 索引缓冲区
- 顶点缓冲区
- 流输出缓冲区
- 呈现器目标
- 深度模具视图
根签名
根签名定义绑定到图形管道的资源类型。根签名由应用配置,并将命令列表链接到着色器所需的资源。 图形命令列表同时具有图形和计算根签名。 计算命令列表只具有一个计算根签名。 这些根签名彼此独立。
根签名是描述符表(包括其布局)、根常量和根描述符的任意排列集合的定义,包含嵌套结构的复杂数据结构。 这些结构可以使用以下数据结构定义(包括 帮助初始化成员的方法)以编程方式定义。 或者,可以使用高级着色语言 (HLSL) 编写它们,这样编译器会尽早验证布局是否与着色器兼容。"根签名"类似于 API 函数签名,它确定着色器应期望的数据类型,但不定义实际的内存或数据。
根形参和根实参
**"根形参"**是根签名中的一个条目。
在运行时设置和更改的根形参的实际值称为**"根实参"**。
根签名可以包含三种类型的形参;根常量(根实参中内联的常量),根描述符(根实参中 内联的描述符)和描述符表(指向描述符堆中一系列描述符的指针)。
根常量是内联 32 位值,在着色器中显示为常量缓冲区
内联根描述符应该包含访问频率最高的描述符,但仅限于 CBV、原始或结构化 UAV 或 SRV 缓冲区。
复杂的类型(如 2D texture SRV)不能用作根描述符。 根描述符不包含 大小限制,因此不能进行越界检查。
应用程序都应尽量使根签名尽可能小,以获得最大的效率。 应用程序可以在根签名中权衡使用更多描述符表,而为根常量预留更少空间。
创建根签名
根签名是可在 API 中通过手动规范创建的对象。 PSO 中的所有着色器都必须与使用 PSO 指定的根布局兼容,各个着色器必须包括相互匹配的嵌入式根布局;否则,PSO 创建将失败。
1. 描述符表绑定类型
枚举 D3D12_DESCRIPTOR_RANGE_TYPE 定义可以作为描述符表布局定义的一部分引用 的描述符类型。
2. 描述符范围
D3D12_DESCRIPTOR_RANGE 结构定义一系列给定类型的描述符。
3. 描述符表布局
D3D12_ROOT_DESCRIPTOR_TABLE 结构将描述符表的布局声明为描述符范围集合,这些 范围从描述符堆的给定偏移量开始。 CBV/UAV/SRV 所在的同一个描述符表中不允许采样器。
若要设置图形(CBV、SRV、UAV、采样器)描述符表,
请使用 ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable。
若要设置计算描述符表,
请使用 ID3D12GraphicsCommandList::SetComputeRootDescriptorTable。
4. 根常量
D3D12_ROOT_CONSTANTS 结构将根签名中的内联常量声明为一个常量缓冲区出现在着色器中。
5. 根描述符
D3D12_ROOT_DESCRIPTOR 结构声明在着色器中显示的描述符 () 根签名中内联。
将根签名槽类型设置为
D3D12_ROOT_PARAMETER_TYPE_CBV、 D3D12_ROOT_PARAMETER_TYPE_SRV 或 着色器可见性 D3D12_ROOT_PARAMETER_TYPE_UAV 时,将使用此结构。
6. 根签名定义
D3D12_ROOT_SIGNATURE_DESC结构可以包含描述符表和内联常量、由 D3D12_ROOT_PARAMETER结构和枚举D3D12_ROOT_PARAMETER_TYPE定义的每种槽类型。静态采样器在根签名中使用 D3D12_STATIC_SAMPLER 结构进行描述。
7. 管道状态对象中的根签名
创建管道状态的方法 (ID3D12Device::CreateGraphicsPipelineState 和 ID3D12Device::CreateComputePipelineState ) 采用可选的 ID3D12RootSignature 接 口作为输入参数, (存储在 ) D3D12_GRAPHICS_PIPELINE_STATE_DESC 结构中。 这会重 写着色器中已存在的任何根签名。
8. 静态采样器
静态采样器(状态完全定义且不可更改的采样器)是根签名的一部分, 如果可以将采样器定义为静态,则无需将采样器作为描述符堆的一部分。
使用静态采样器没有性能成本,根签名可以包含静态采样器(存储在根签名中,或存储在 某些硬件上的预留空间中)与动态采样器(存储在采样器描述符堆中)的混合。 描述符堆中的采样器可以动态分配和编制索引,而静态采样器不能。
9. 直接在根签名中使用描述符
若要避免需要遍历描述符堆,可以将描述符直接放入根签名中。 这些描述符在根签名中 占用了大量空间,因此建议谨慎使用它们。 例如,在根布局中放置一个常量缓冲区视图, (每次绘图都会更改的 CBV) 。 这样一来, 应用程序不必按绘制 (分配描述符堆空间,并将指向描述符表保存在描述符堆) 的新位置。 通过将某些内容放入根签名中,应用程序只是将版本控制责任交给驱动程序;但这是 驱动程序已经拥有的基础结构。
10. 静态和易失性标志
DESCRIPTORS_VOLATILE
设置此标志后,应用程序随时可以更改根描述符表指向的描述符堆中的描述符,但当绑定 描述符表的命令列表/捆绑已提交和未完成执行时则不可以。
DATA_STATIC
**如果未设置DESCRIPTORS_VOLATILE 标志,则描述符为静态。**如果设置此标志,记录期间在命令列表/捆绑中设置引用内存的根描述符或描述符表时, 将初始化描述符指向的数据,并且在命令列表/捆绑最后一次完成执行之前,该数据无法更改。
DATA_STATIC_WHILE_SET_AT_EXECUTE
设置此标志后,从在 GPU 时间线上执行期间在命令列表/捆绑中设置基础根描述符或描述 符表开始,到后续绘制/调度不再引用数据为止,描述符指向的数据无法更改。
Shader程序(HLSL) 中的资源绑定
着色器模型 5 (SM5.0) 资源语法使用 register 关键字 (keyword) 将有关资源的重要信息 中继到 HLSL 编译器。 例如,以下语句声明在槽 t3、t4、t5 和 t6 中绑定的四个纹理的数 组。 t3 是唯一显示在该语句中的寄存器槽,而它仅仅是四个寄存器的数组中的第一个,如
Texture2D tex1[4] : register(t3)
HLSL 中的 D3D12 资源绑定到逻辑寄存器空间中的虚拟寄存器:
t -- 表示着色器资源视图 (SRV)
s -- 表示采样器
u -- 表示无序访问视图 (UAV)
b -- 表示常量缓冲区视图 (CBV)
资源和父堆具有对齐要求
用于多样本纹理 (4MB) D3D12_DEFAULT_MSAA_RESOURCE_PLACEMENT_ALIGNMENT
对于单个样本纹理和缓冲区 64KB D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT
线性子资源复制必须与D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT(512 字 节)对齐,行间距与D3D12_TEXTURE_DATA_PITCH_ALIGNMENT(256 字节)对 齐。
常量缓冲区视图必须与 D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT(256 字节)对齐。
类型化无序访问视图 (UAV) 加载
无序访问视图 (UAV) 类型化负载是着色器能够读取具有特定 DXGI_FORMAT的 UAV。无序访问视图 (UAV) 是无序访问资源的视图(可包括缓冲区、纹理和纹理数组,但无需 多次采样)。 使用 UAV 可通过多个线程临时进行无序读/写访问。 这意味着此资源类型 可由多个线程同时读/写,且不会产生内存冲突。 这种同时访问是通过使用 Atomic Functions(原子函数)来进行的。
在 HLSL 中指定根签名
如果在 HLSL 着色器模型 5.1 中指定根签名,则无需在 C++ 代码中指定这些根签名。
可在 HLSL 中将根签名指定为字符串。 该字符串包含一个逗号分隔的子句集合,这些子 句描述根签名的组成部分。 根签名在任何一个管道状态对象 (PSO) 的不同着色器中应该相同。
根签名指定为逗号分隔的子句序列。 子句的顺序非常重要,因为分析顺序决定了根签名中的槽位置。 每个子句采用一个或多个命名参数,参数的顺序并不重要。
RootFlags
可选的 RootFlags 子句采用 0 (默认值来指示没有) 标志,或者通过 OR"|"运算符连接的一 个或多个预定义根标志值。
cpp
RootFlags(0)
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT) RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT|DENY_VERTEX_SHADER_ROOT_ACCESS)
根常量RootConstants
RootConstants 子句指定根签名中的根常量。 两个必需的参数是:cbuffer 的 num32BitConstants 和 bReg(对应于 C++ API 中 BaseShaderRegister 的寄存器)。 space(C++ API 中的 RegisterSpace)和 visibility(C++ 中的 ShaderVisibility)参数是可选的,默认值为
cpp
RootConstants(num32BitConstants=N, bReg [, space=0, visibility=SHADER_VISIBILITY_ALL ])
根级 CBV
CBV(常量缓冲区视图)子句指定根级常量缓冲区 b-register 寄存器条目。 请注意,这是 一个标量条目;无法指定根级别的范围。
cpp
CBV(bReg [, space=0, visibility=SHADER_VISIBILITY_ALL ])
根级 SRV
SRV(着色器资源视图)子句指定根级 SRV t-register 寄存器条目。 请注意,这是一个标 量条目;无法指定根级别的范围。
cpp
SRV(tReg [, space=0, visibility=SHADER_VISIBILITY_ALL, // Version 1.1 flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
根级 UAV
UAV(无序访问视图)子句指定根级 UAV u-register 寄存器条目。 请注意,这是一个标量 条目;无法指定根级别的范围。
cpp
UAV(uReg [, space=0, visibility=SHADER_VISIBILITY_ALL, // Version 1.1 flags=DATA_VOLATILE ])
描述符表 DescriptorTable
DescriptorTable 子句本身是逗号分隔的描述符表子句列表,以及可选的可见性参数。 DescriptorTable 子句包括 CBV、SRV、UAV 和采样器。 请注意,其参数不同于根级子句 的参数。
cpp
DescriptorTable( DTClause1, [ DTClause2, ... DTClauseN, visibility=SHADER_VISIBILITY_ALL ] )
DescriptorTable(CBV(b0),SRV(t3, numDescriptors=unbounded))
编译 HLSL 根签名
可以使用两种机制来编译 HLSL 根签名。 首先,可以通过 RootSignature 属性将根签名字 符串附加到特定的着色器(以下示例使用 MyRS1 入口点):
cpp
[RootSignature(MyRS1)]
float4 main(float4 coord : COORD) : SV_Target
{ ... }
编译器将创建并验证着色器的根签名 Blob,并将它连同着色器字节码一起嵌入到着色器 Blob。 编译器支持着色器模型 5.0 及更高版本的根签名语法。
另一种机制是创建独立的根签名 Blob。也许可对大量的着色器重用该 Blob,以节省空 间。 效果编译器工具 (FXC) 支持rootsig_1_0和rootsig_1_1着色器模型。 通过常用的 /E 参 数指定定义字符串的名称。 例如: fxc.exe /T rootsig_1_1 MyRS1.hlsl /E MyRS1 /Fo MyRS1.fxo
多适配器系统
D3D12 对已安装多个适配器的系统的支持,包括应用程序明确使用多个 GPU 适配器的情况,以及驱动程序代表应用程序隐式使用多个 GPU 适配器的情况。
应用程序可以通过调用 ID3D12Device::GetNodeCount 来确定与给定设备关联的物理适 配器数量。 D3D12 中的许多 API 都接受节点掩码(位掩码),它表示 API 调用所指向的节点 集。 每个节点都有一个从 0 开始的索引。 但在节点掩码中,0 表示第 1 位;1 表示第 2 位;以此类推。
创建保留资源时,未指定节点索引或掩码。 可将保留资源映射到任何节点的堆上。 方法 MakeResident 在内部与适配器队列一起工作,应用程序无需为此指定任何内容。
在调用以下 ID3D12Device API 时,应用程序无需指定 API 调用将关联的节点集,因为 API 调用适用于所有节点。
感谢大家的支持,如要问题欢迎提问指正。