Bicameral Engine
GPU-resident engine for a magic-research open-world game
Loading...
Searching...
No Matches
work_graph.cpp
Go to the documentation of this file.
1// work_graph.cpp — Work Graph の状態オブジェクト・裏のメモリ・起動(T-0013。GPU の入力からの起動は T-0005)。
2// 手順は D3D12 Work Graphs の仕様(DirectX-Specs の "Work Graphs")の「Program setup」の順:
3// 状態オブジェクト(DXIL ライブラリ + グローバルのルート署名 + ワークグラフ)→ 必要な裏のメモリの大きさを聞いて確保
4// → SetProgram(最初は INITIALIZE)→ DispatchGraph
5#include "gpu/work_graph.h"
6
7#include "core/hresult.h"
8#include "core/log.h"
9#include "core/unicode.h"
10#include "gpu/com_ptr.h"
11#include "gpu/resources.h"
12
13namespace bicameral::gpu {
14 namespace {
15
16 ComPtr<ID3D12StateObject> CreateStateObject(ID3D12Device5* device, ID3D12RootSignature* globalRootSignature,
17 std::span<const std::byte> library, const std::wstring& name) {
18 CD3DX12_STATE_OBJECT_DESC desc(D3D12_STATE_OBJECT_TYPE_EXECUTABLE);
19 const CD3DX12_SHADER_BYTECODE bytecode(library.data(), library.size());
20 desc.CreateSubobject<CD3DX12_DXIL_LIBRARY_SUBOBJECT>()->SetDXILLibrary(&bytecode);
21 desc.CreateSubobject<CD3DX12_GLOBAL_ROOT_SIGNATURE_SUBOBJECT>()->SetRootSignature(globalRootSignature);
22 auto* workGraph = desc.CreateSubobject<CD3DX12_WORK_GRAPH_SUBOBJECT>();
23 workGraph->IncludeAllAvailableNodes();
24 workGraph->SetProgramName(name.c_str());
25
26 ComPtr<ID3D12StateObject> stateObject;
27 if (!BICAMERAL_CHECK_HR(Channel::WorkGraph, device->CreateStateObject(desc, IID_PPV_ARGS(&stateObject))))
28 return nullptr;
29
30 return stateObject;
31 }
32
33 } // namespace
34
35 std::expected<WorkGraph, std::string> WorkGraph::Create(ID3D12Device5* device,
36 ID3D12RootSignature* globalRootSignature,
37 std::span<const std::byte> library,
38 std::wstring_view programName) {
39 const std::wstring name(programName);
40 WorkGraph graph;
41 graph.m_stateObject = CreateStateObject(device, globalRootSignature, library, name);
42 if (!graph.m_stateObject)
43 return std::unexpected("ワークグラフの状態オブジェクトを作れない");
44
45 ComPtr<ID3D12StateObjectProperties1> stateProperties;
46 if (FAILED(graph.m_stateObject.As(&stateProperties)) || FAILED(graph.m_stateObject.As(&graph.m_properties)))
47 return std::unexpected("状態オブジェクトから Work Graphs のプロパティを取れない(ランタイムが古い)");
48
49 graph.m_programIdentifier = stateProperties->GetProgramIdentifier(name.c_str());
50 graph.m_graphIndex = graph.m_properties->GetWorkGraphIndex(name.c_str());
51
52 // --- 裏のメモリ(ノード間のレコードの置き場所。ドライバが大きさを決める)---
53 D3D12_WORK_GRAPH_MEMORY_REQUIREMENTS requirements{};
54 graph.m_properties->GetWorkGraphMemoryRequirements(graph.m_graphIndex, &requirements);
55 graph.m_backingMemoryBytes = requirements.MaxSizeInBytes;
56
57 if (graph.m_backingMemoryBytes > 0) {
59 if (!graph.m_backingMemory)
60 return std::unexpected("ワークグラフの裏のメモリを確保できない");
61 }
62
63 Log(Channel::WorkGraph, Level::Info, "ワークグラフ {}: 裏のメモリ {} バイト(最小 {})", ToUtf8(name),
64 requirements.MaxSizeInBytes, requirements.MinSizeInBytes);
65
66 return graph;
67 }
68
69 uint32_t WorkGraph::EntrypointIndex(std::wstring_view nodeName) const {
70 const std::wstring name(nodeName);
71 return m_properties->GetEntrypointIndex(m_graphIndex, {.Name = name.c_str(), .ArrayIndex = 0});
72 }
73
74 void WorkGraph::SetProgram(ID3D12GraphicsCommandList10* list, bool initialize) const {
75 D3D12_SET_PROGRAM_DESC desc{.Type = D3D12_PROGRAM_TYPE_WORK_GRAPH};
76 desc.WorkGraph = {
77 .ProgramIdentifier = m_programIdentifier,
78 .Flags = initialize ? D3D12_SET_WORK_GRAPH_FLAG_INITIALIZE : D3D12_SET_WORK_GRAPH_FLAG_NONE,
79 .BackingMemory = {.StartAddress = m_backingMemory ? m_backingMemory->GetGPUVirtualAddress() : 0,
80 .SizeInBytes = m_backingMemoryBytes},
81 };
82
83 list->SetProgram(&desc);
84 }
85
86 void WorkGraph::DispatchFromCpu(ID3D12GraphicsCommandList10* list, uint32_t entrypointIndex, const void* records,
87 uint32_t recordCount, uint64_t recordStrideBytes) {
88 D3D12_DISPATCH_GRAPH_DESC desc{.Mode = D3D12_DISPATCH_MODE_NODE_CPU_INPUT};
89 desc.NodeCPUInput = {
90 .EntrypointIndex = entrypointIndex,
91 .NumRecords = recordCount,
92 .pRecords = records,
93 .RecordStrideInBytes = recordStrideBytes,
94 };
95
96 list->DispatchGraph(&desc);
97 }
98
99 void WorkGraph::DispatchFromGpu(ID3D12GraphicsCommandList10* list, D3D12_GPU_VIRTUAL_ADDRESS nodeGpuInput) {
100 D3D12_DISPATCH_GRAPH_DESC desc{.Mode = D3D12_DISPATCH_MODE_NODE_GPU_INPUT};
101 desc.NodeGPUInput = nodeGpuInput;
102 list->DispatchGraph(&desc);
103 }
104
105} // namespace bicameral::gpu
static std::expected< WorkGraph, std::string > Create(ID3D12Device5 *device, ID3D12RootSignature *globalRootSignature, std::span< const std::byte > library, std::wstring_view programName)
D3D12_PROGRAM_IDENTIFIER m_programIdentifier
Definition work_graph.h:53
static void DispatchFromCpu(ID3D12GraphicsCommandList10 *list, uint32_t entrypointIndex, const void *records, uint32_t recordCount, uint64_t recordStrideBytes)
uint32_t EntrypointIndex(std::wstring_view nodeName) const
void SetProgram(ID3D12GraphicsCommandList10 *list, bool initialize) const
ComPtr< ID3D12Resource > m_backingMemory
Definition work_graph.h:57
static void DispatchFromGpu(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS nodeGpuInput)
ComPtr< ID3D12WorkGraphProperties > m_properties
Definition work_graph.h:52
ComPtr< ID3D12StateObject > m_stateObject
Definition work_graph.h:51
#define BICAMERAL_CHECK_HR(channel, expression)
Definition hresult.h:32
ComPtr< ID3D12StateObject > CreateStateObject(ID3D12Device5 *device, ID3D12RootSignature *globalRootSignature, std::span< const std::byte > library, const std::wstring &name)
ComPtr< ID3D12Resource > CreateBuffer(ID3D12Device *device, uint64_t sizeBytes, BufferKind kind)
Definition resources.cpp:18
void Log(Channel channel, Level level, FormatWithLocation< std::type_identity_t< Args >... > pattern, Args &&... args)
Definition log.h:140
std::string ToUtf8(std::wstring_view text)
Definition unicode.cpp:10