16using namespace bicameral::multires;
43 static_assert(
sizeof(ImGpuNode) == 40 &&
sizeof(ImGpuLink) == 16,
"implicit_levels.hlsl の並び");
48 "implicit_levels.hlsl の見出しと GpuImplicit の計画の並び");
74 constexpr std::array<std::string_view, PassTotal>
PASS_NAMES = {
"clear",
111 return std::max<uint32_t>(1,
static_cast<uint32_t
>((threads +
THREADS - 1) /
THREADS));
119 const D3D12_RESOURCE_BARRIER barrier{.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV,
120 .UAV = {.pResource =
nullptr}};
121 list->ResourceBarrier(1, &barrier);
125 void CopyToReadback(ID3D12GraphicsCommandList* list, ID3D12Resource* source, ID3D12Resource* readback,
127 D3D12_RESOURCE_BARRIER barrier =
gpu::Transition(source, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
128 D3D12_RESOURCE_STATE_COPY_SOURCE);
129 list->ResourceBarrier(1, &barrier);
130 list->CopyBufferRegion(readback, 0, source, 0, bytes);
131 std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
132 list->ResourceBarrier(1, &barrier);
135 template <
typename T>
136 std::vector<T>
Slice(
const std::vector<std::byte>& bytes, uint32_t count) {
137 std::vector<T> values(count);
139 std::memcpy(values.data(), bytes.data(),
size_t{count} *
sizeof(T));
155 return std::unexpected(
"多重格子の段の上限が正しくない");
174 const uint64_t words = HEADER_WORDS + (uint64_t{NODE_WORDS} * limits.
nodes) +
176 constants.
linkTableMask + 1 + (2 * (uint64_t{ScanGroups(constants.maxCells)} + 1));
181 return std::unexpected(
"多重格子の段のルート署名を作れない");
183 for (
const std::string_view name : PASS_NAMES) {
184 const std::string shader = std::format(
"sim/implicit_levels_{}.cso", name);
187 return std::unexpected(bytecode.error());
191 return std::unexpected(std::format(
"多重格子の段のパイプラインを作れない({})", shader));
196 const uint64_t nodeBytes = uint64_t{limits.
nodes} *
sizeof(ImGpuNode);
197 const uint64_t linkBytes = uint64_t{limits.
links} *
sizeof(ImGpuLink);
198 const uint64_t childBytes = uint64_t{limits.
nodes} *
sizeof(uint32_t);
213 return std::unexpected(
"多重格子の段のバッファを作れない");
215 const D3D12_QUERY_HEAP_DESC queryDesc{
216 .Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP, .Count =
MAX_TIMESTAMPS, .NodeMask = 0};
217 if (FAILED(device->CreateQueryHeap(&queryDesc, IID_PPV_ARGS(&result.
m_timestamps))))
218 return std::unexpected(
"タイムスタンプのヒープを作れない");
227 GlobalUavBarrier(list);
233 D3D12_RESOURCE_STATE_PREDICATION);
234 list->ResourceBarrier(1, &barrier);
235 list->SetPredication(
m_predicate.Get(), uint64_t{coarsening} * 8, D3D12_PREDICATION_OP_NOT_EQUAL_ZERO);
239 list->SetPredication(
nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
241 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
242 list->ResourceBarrier(1, &barrier);
248 const std::array<ID3D12Resource*, UAV_COUNT> buffers = {
251 for (uint32_t i = 0; i < UAV_COUNT; ++i)
252 list->SetComputeRootUnorderedAccessView(i, buffers[i]->GetGPUVirtualAddress());
254 list->SetComputeRootUnorderedAccessView(ROOT_LAYOUT.
DebugRingIndex(), debugRing);
259 const uint32_t both = std::max(cells, links);
260 const uint32_t clearWords = std::max(
262 std::array<uint32_t, PassTotal> groups{};
263 groups[PassClear] = Groups(clearWords);
264 groups[PassCells] = Groups(cells);
265 groups[PassCellLinks] = Groups(links);
266 groups[PassNodeHash] = Groups(cells);
267 groups[PassNodeFirst] = Groups(cells);
268 groups[PassParentScanLocal] = ScanGroups(cells);
269 groups[PassParentScanGroups] = 1;
270 groups[PassParents] = Groups(cells);
271 groups[PassLinkHash] = Groups(links);
272 groups[PassCount] = Groups(both);
273 groups[PassRowScanLocal] = ScanGroups(cells);
274 groups[PassRowScanGroups] = 1;
275 groups[PassPlace] = Groups(both);
276 groups[PassSort] = Groups(both);
277 groups[PassAddCoefficients] = Groups(links);
278 groups[PassCoarseNodes] = Groups(cells);
279 groups[PassFinish] = Groups(both);
280 groups[PassRoundEnd] = 1;
281 groups[PassTail] = 1;
285 for (
const Pass pass : {PassClear, PassCells, PassCellLinks})
288 for (uint32_t coarsening = 0; coarsening <
m_dispatchRounds; ++coarsening) {
291 for (
const Pass pass : ROUND_PASSES)
295 Dispatch(list, PassRoundEnd, groups[PassRoundEnd]);
299 Dispatch(list, PassTail, groups[PassTail]);
312 std::array<D3D12_RESOURCE_BARRIER, 4> barriers{};
313 for (
size_t i = 0; i < sources.size(); ++i) {
314 barriers[i] =
gpu::Transition(sources[i], D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
315 D3D12_RESOURCE_STATE_COPY_SOURCE);
318 list->ResourceBarrier(
static_cast<UINT
>(barriers.size()), barriers.data());
320 for (D3D12_RESOURCE_BARRIER& barrier : barriers)
321 std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
323 list->ResourceBarrier(
static_cast<UINT
>(barriers.size()), barriers.data());
330 list->EndQuery(
m_timestamps.Get(), D3D12_QUERY_TYPE_TIMESTAMP, index);
336 CopyToReadback(list,
m_nodes.Get(),
m_nodesReadback.Get(), uint64_t{m_constants.maxNodes} *
sizeof(ImGpuNode));
337 CopyToReadback(list,
m_links.Get(),
m_linksReadback.Get(), uint64_t{m_constants.maxLinks} *
sizeof(ImGpuLink));
346 std::array<uint32_t, HEADER_WORDS> header{};
347 std::vector<std::byte> nodes(uint64_t{
m_constants.maxNodes} *
sizeof(ImGpuNode));
348 std::vector<std::byte> links(uint64_t{
m_constants.maxLinks} *
sizeof(ImGpuLink));
349 std::vector<std::byte> children(uint64_t{
m_constants.maxNodes} * 4);
353 return std::unexpected(
"作った段を読み戻せない");
356 system.
overflow = header[OVERFLOW_WORD] != 0;
357 const uint32_t levelCount = header[LEVEL_COUNT];
358 if (system.
overflow || levelCount == 0 || levelCount > MAX_LEVELS)
363 for (uint32_t depth = 0; depth < levelCount; ++depth) {
364 images.
levelOffsets.push_back(header[DepthWord(NODE_OFFSET, depth)]);
365 system.
linkOffsets.push_back(header[DepthWord(LINK_OFFSET, depth)]);
368 const uint32_t last = levelCount - 1;
369 images.
levelOffsets.push_back(header[DepthWord(NODE_OFFSET, last)] + header[DepthWord(NODE_COUNT, last)]);
370 system.
linkOffsets.push_back(header[DepthWord(LINK_OFFSET, last)] + header[DepthWord(LINK_COUNT, last)]);
ID3D12Resource * SystemBuffer() const
uint64_t ListsOffset() const
uint32_t CellKeysWord() const
const GpuImplicitBuildLimits & Limits() const
uint32_t ListCellsWord() const
uint64_t FacesOffset() const
ID3D12Resource * WorkBuffer() const
ComPtr< ID3D12Resource > m_links
uint32_t DispatchCount() const
void BeginSkippable(ID3D12GraphicsCommandList *list, uint32_t coarsening)
static constexpr uint32_t MAX_TIMESTAMPS
uint32_t m_dispatchRounds
ComPtr< ID3D12Resource > m_childrenReadback
void EndSkippable(ID3D12GraphicsCommandList *list)
void RecordCopyTo(ID3D12GraphicsCommandList *list, GpuImplicit &implicit)
static std::expected< GpuImplicitLevels, std::string > Create(ID3D12Device5 *device, const GpuImplicitBuild &build, const GpuImplicitLevelLimits &limits)
uint32_t m_timestampCount
ComPtr< ID3D12Resource > m_timestampReadback
ComPtr< ID3D12Resource > m_linksReadback
ComPtr< ID3D12Resource > m_children
GpuImplicitLevels()=default
ComPtr< ID3D12Resource > m_headerReadback
std::vector< ComPtr< ID3D12PipelineState > > m_pipelines
void RecordReadback(ID3D12GraphicsCommandList *list)
std::expected< GpuImplicitLevelSystem, std::string > Read() const
void RecordTimestamp(ID3D12GraphicsCommandList *list, uint32_t index)
void RecordBuild(ID3D12GraphicsCommandList *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, const GpuImplicitBuild &build)
ComPtr< ID3D12Resource > m_nodes
ComPtr< ID3D12Resource > m_predicate
ComPtr< ID3D12RootSignature > m_rootSignature
void Dispatch(ID3D12GraphicsCommandList *list, uint32_t pass, uint32_t groups)
ComPtr< ID3D12Resource > m_nodesReadback
ComPtr< ID3D12Resource > m_work
ComPtr< ID3D12QueryHeap > m_timestamps
std::vector< uint64_t > ReadTimestamps(uint32_t count) const
void RecordCopyLevels(ID3D12GraphicsCommandList *list, ID3D12Resource *header, ID3D12Resource *nodes, ID3D12Resource *links, ID3D12Resource *children)
ComPtr< ID3D12RootSignature > CreateRootSignature(ID3D12Device *device, const RootSignatureLayout &layout)
std::expected< std::vector< std::byte >, std::string > LoadShader(std::string_view relativePath)
bool ReadBuffer(ID3D12Resource *readback, std::span< std::byte > destination)
ComPtr< ID3D12PipelineState > CreateComputePipeline(ID3D12Device *device, ID3D12RootSignature *rootSignature, std::span< const std::byte > bytecode)
D3D12_RESOURCE_BARRIER Transition(ID3D12Resource *resource, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after)
ComPtr< ID3D12Resource > CreateBuffer(ID3D12Device *device, uint64_t sizeBytes, BufferKind kind)
constexpr uint32_t NODE_OFFSET
constexpr uint32_t LINK_WORDS
constexpr uint32_t THREADS
constexpr std::array< std::string_view, PassTotal > PASS_NAMES
uint32_t DepthWord(uint32_t kind, uint32_t depth)
constexpr uint32_t UAV_COUNT
constexpr std::array< Pass, 14 > ROUND_PASSES
uint32_t Groups(uint64_t threads)
constexpr uint32_t LEVEL_COUNT
constexpr uint32_t OVERFLOW_WORD
uint32_t ScanGroups(uint64_t count)
constexpr uint32_t LINK_COUNT
constexpr uint32_t DEPTH_BASE
void GlobalUavBarrier(ID3D12GraphicsCommandList *list)
constexpr uint32_t SCAN_THREADS
constexpr uint32_t NODE_WORDS
constexpr uint32_t MAX_LEVELS
constexpr uint32_t ROOT_CONSTANT_COUNT
constexpr uint32_t NODE_COUNT
constexpr uint32_t LINK_OFFSET
std::vector< T > Slice(const std::vector< std::byte > &bytes, uint32_t count)
constexpr uint32_t HEADER_WORDS
void CopyToReadback(ID3D12GraphicsCommandList *list, ID3D12Resource *source, ID3D12Resource *readback, uint64_t bytes)
constexpr gpu::RootSignatureLayout ROOT_LAYOUT
constexpr uint32_t DEPTH_STRIDE
uint32_t DebugRingIndex() const
uint32_t RootConstantIndex() const
std::vector< multires::ImGpuLink > links
std::vector< uint32_t > children
std::vector< uint32_t > levelOffsets
std::vector< multires::ImGpuNode > nodes
std::vector< uint32_t > linkOffsets
GpuImplicitLevelImages images