入门

最初发布时间:

首次设置

首先,您需要一个支持 GPU 工作图的 Microsoft DirectX® 着色器编译器和 Agility SDK 运行时版本。这些可以从 Microsoft 直接获取,在此处。您还需要一张支持 GPU 工作图的显卡(AMD Radeon™ RX 7000 系列显卡)以及支持 GPU 工作图的 AMD 驱动程序,可以在此处获取。

Hello Work Graphs

注意:本示例旨在向熟悉 DirectX 12 的用户介绍工作图。如果您还不熟悉 DirectX 12,建议在继续之前了解更多信息

提供了一个最小的 C++ 示例,实现了工作图的基本“Hello World”范例。您可以在此处找到它。该程序还经历了设置 DirectX 并输出结果的过程,因此仅设置工作图本身的基本组件将在以下各节中进行概述。

声明一个工作图节点

创建一个包含至少一个工作图节点的 HLSL 源文件。请注意,声明中可能涉及许多新的 HLSL 内建函数和属性。其中许多选项是互斥的,本示例并未尝试展示所有这些选项!

[Shader("node")]
[NodeLaunch("broadcasting")]
[NodeDispatchGrid(1, 1, 1)]
[NumThreads(1, 1, 1)]
void BroadcastNode()
{
...
}

配置 DirectX 12

将应用程序配置为使用与工作图兼容的 Agility SDK 版本。

extern "C" { __declspec(dllexport) extern const UINT D3D12SDKVersion = 613; } // or later

验证工作图是否受支持

在继续之前,请确保当前的 DirectX 12 堆栈支持工作图。

D3D12_FEATURE_DATA_D3D12_OPTIONS21 Options = {};
pDevice->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS21, &Options, sizeof(Options));
return (Options.WorkGraphsTier != D3D12_WORK_GRAPHS_TIER_NOT_SUPPORTED);

编译工作图库

像编译传统着色器一样编译您的工作图源。将 nullptr 作为入口点,将 lib_6_8 作为目标配置文件。

{#highlight-nullptr-lib_6_8}

pCompiler->Compile(pSource, nullptr, nullptr, L"lib_6_8", nullptr, 0, nullptr, 0, nullptr, &pOperationResult)

创建状态对象

创建一个状态对象,其中包含一个 CD3DX12_DXIL_LIBRARY_SUBOBJECT(包含编译后的着色器源)和一个 CD3DX12_WORK_GRAPH_SUBOBJECT(包含目标节点和名称)。

说明

  • 即使您只有一个工作图子对象,也仍然希望指定一个名称以便稍后查找相应的程序标识符。
  • 在填充 CD3DX12_WORK_GRAPH_SUBOBJECT 时,我们调用了 IncludeAllAvailableNodes()。这简化了一些设置,我们稍后会再回到这一点。
CD3DX12_STATE_OBJECT_DESC Desc(D3D12_STATE_OBJECT_TYPE_EXECUTABLE);
...
CD3DX12_DXIL_LIBRARY_SUBOBJECT* LibraryDesc = Desc.CreateSubobject<CD3DX12_DXIL_LIBRARY_SUBOBJECT>();
CD3DX12_SHADER_BYTECODE gwgLibraryCode(pGwgLibrary);
LibraryDesc->SetDXILLibrary(&gwgLibraryCode);
CD3DX12_WORK_GRAPH_SUBOBJECT* WorkGraphDesc = Desc.CreateSubobject<CD3DX12_WORK_GRAPH_SUBOBJECT>();
WorkGraphDesc->IncludeAllAvailableNodes();
WorkGraphDesc->SetProgramName(kProgramName);
pDevice->CreateStateObject(Desc, IID_PPV_ARGS(&pStateObject));

准备 D3D12 描述

为工作图程序分配要使用的后备内存。

UINT WGIndex = pWorkGraphProperties->GetWorkGraphIndex(kProgramName);
D3D12_WORK_GRAPH_MEMORY_REQUIREMENTS MemoryRequirements = {};
pWorkGraphProperties->GetWorkGraphMemoryRequirements(WGIndex, &MemoryRequirements);
if (MemoryRequirements.MaxSizeInBytes > 0)
{
pBackingMemoryResource = AllocateBuffer(pDevice, MemoryRequirements.MaxSizeInBytes, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_HEAP_TYPE_DEFAULT);
}

创建一个 D3D12_SET_PROGRAM_DESC 来封装状态对象。

注意:每个唯一的程序至少需要设置一次 D3D12_SET_WORK_GRAPH_FLAG_INITIALIZE 标志,但使用它会产生性能开销。对于将运行多次的工作图,请不要在每次 Dispatch 时都指定它!

注意:我们建议将该值设置为 MaxSizeInBytes 以确保最佳性能。

D3D12_SET_PROGRAM_DESC Desc = {};
Desc.Type = D3D12_PROGRAM_TYPE_WORK_GRAPH;
Desc.WorkGraph.ProgramIdentifier = pStateObjectProperties->GetProgramIdentifier(kProgramName);
Desc.WorkGraph.Flags = D3D12_SET_WORK_GRAPH_FLAG_INITIALIZE;
if (pBackingMemoryResource)
{
Desc.WorkGraph.BackingMemory = { pBackingMemoryResource->GetGPUVirtualAddress(), MemoryRequirements.MaxSizeInBytes };
}

最后,创建一个 D3D12_DISPATCH_GRAPH_DESC 来封装 Dispatch 的输入。

说明

  • 即使图不接受任何输入记录,您也必须将 NumRecords 设置为大于 0 的值,否则将不会发生任何 Dispatch。如果您不确定这意味着什么,我们稍后会再讨论!
  • 在此示例中,我们编译的工作图源仅包含一个节点,并且该节点被包含为图的入口点(因为我们在创建状态对象时调用了 IncludeAllAvailableNodes())。这意味着我们可以安全地假设只有一个可能的入口点,并且该入口点的索引为 0。
D3D12_DISPATCH_GRAPH_DESC DispatchGraphDesc = { };
DispatchGraphDesc.Mode = D3D12_DISPATCH_MODE_NODE_CPU_INPUT;
DispatchGraphDesc.NodeCPUInput = { };
DispatchGraphDesc.NodeCPUInput.EntrypointIndex = 0;
DispatchGraphDesc.NodeCPUInput.NumRecords = 1;

调用 DispatchGraph

在活动命令列表中放置命令以设置程序并 Dispatch 工作图。如果插入到现有的命令列表中,您需要查询 ID3D12GraphicsCommandListExperimental 接口以访问这些命令。

pCommandList->SetProgram(&SetProgramDesc);
pCommandList->DispatchGraph(&DispatchGraphDesc);

相关新闻和技术文章

相关视频

© . This site is unofficial and not affiliated with AMD.