16#include "common/implicit_conduction.hlsli"
20using namespace bicameral::fx;
21using namespace bicameral::multires;
51 constexpr std::array<const char*, 15>
SHADERS = {
52 "sim/implicit_begin.cso",
"sim/implicit_start.cso",
"sim/implicit_smooth.cso",
53 "sim/implicit_restrict.cso",
"sim/implicit_prolong.cso",
"sim/implicit_converged.cso",
54 "sim/implicit_cycle_end.cso",
"sim/implicit_flows.cso",
"sim/implicit_mark.cso",
55 "sim/implicit_limit_end.cso",
"sim/implicit_limit_faces.cso",
"sim/implicit_apply.cso",
56 "sim/implicit_tail.cso",
"sim/implicit_plan_levels.cso",
"sim/implicit_plan_args.cso"};
59 constexpr std::array<bool, 11>
UPLOADED = {
true,
true,
true,
true,
true,
false,
60 false,
false,
false,
true,
false};
64 return IM_PLAN_DEPTH_BASE + (kind * IM_PLAN_DEPTH_STRIDE) + depth;
69 return IM_SLOT_DEPTH_BASE + (depth * IM_SLOT_DEPTH_STRIDE);
73 std::vector<std::byte>
ToBytes(
const std::vector<T>& values) {
74 std::vector<std::byte> bytes(values.size() *
sizeof(T));
76 std::memcpy(bytes.data(), values.data(), bytes.size());
81 bool WriteUpload(ID3D12Resource* upload, std::span<const std::byte> bytes) {
82 void* mapped =
nullptr;
83 const D3D12_RANGE noRead{.Begin = 0, .End = 0};
84 if (FAILED(upload->Map(0, &noRead, &mapped)))
87 std::memcpy(mapped, bytes.data(), bytes.size());
88 upload->Unmap(0,
nullptr);
94 const D3D12_RESOURCE_BARRIER barrier{.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV,
95 .UAV = {.pResource =
nullptr}};
96 list->ResourceBarrier(1, &barrier);
100 std::vector<ImGpuCell> cells(grid.
cells.size());
101 for (
size_t i = 0; i < cells.size(); ++i) {
103 cells[i] = {.energy = cell.
energy,
107 .faceStart = faceStarts[i],
108 .faceEnd = faceStarts[i + 1]};
116 std::vector<std::vector<uint32_t>> perCell(grid.
cells.size());
117 for (uint32_t f = 0; f < grid.
faces.size(); ++f) {
118 perCell[grid.
faces[f].fine].push_back(f * 2);
119 perCell[grid.
faces[f].coarse].push_back((f * 2) + 1);
122 std::vector<uint32_t> list;
123 std::vector<uint32_t> starts(1, 0);
124 for (
const std::vector<uint32_t>& faces : perCell) {
125 list.insert(list.end(), faces.begin(), faces.end());
126 starts.push_back(
static_cast<uint32_t
>(list.size()));
129 return {std::move(list), std::move(starts)};
140 std::vector<ImGpuNode>& nodes, std::vector<uint32_t>& lists) {
142 const uint32_t offset = levelOffsets[depth];
143 std::vector<std::vector<uint32_t>> children(grid.
levels[depth].levels.size());
144 for (uint32_t i = 0; i < finer.
parents.size(); ++i)
145 children[finer.
parents[i]].push_back(levelOffsets[depth - 1] + i);
147 for (
size_t p = 0; p < children.size(); ++p) {
148 nodes[offset + p].childStart =
static_cast<uint32_t
>(lists.size());
149 lists.insert(lists.end(), children[p].begin(), children[p].end());
150 nodes[offset + p].childEnd =
static_cast<uint32_t
>(lists.size());
155 std::vector<uint32_t>& lists) {
156 std::vector<ImGpuNode> nodes(levelOffsets.back());
157 std::vector<ImGpuLink> links;
158 for (
size_t depth = 0; depth < grid.
levels.size(); ++depth) {
160 const uint32_t offset = levelOffsets[depth];
161 const bool coarsest = depth + 1 == grid.
levels.size();
162 for (
size_t i = 0; i < level.
levels.size(); ++i) {
163 ImGpuNode& node = nodes[offset + i];
166 node.parent = coarsest ? 0 : levelOffsets[depth + 1] + level.
parents[i];
167 node.color = level.
colors[i];
168 node.linkStart =
static_cast<uint32_t
>(links.size());
170 links.push_back({.weight = level.
weights[k], .neighbor = offset + level.
neighbors[k]});
172 node.linkEnd =
static_cast<uint32_t
>(links.size());
179 return {.nodes = std::move(nodes), .links = std::move(links)};
187 limits.
levels > IM_PLAN_MAX_LEVELS)
188 return std::unexpected(
"陰解法の上限が正しくない");
194 .maxCells = limits.
cells,
195 .maxFaces = limits.
faces,
200 .maxLevels = limits.
levels};
203 return std::unexpected(pipelines.error());
206 return std::unexpected(buffers.error());
214 return std::unexpected(
"陰解法の段が無い");
221 .faces =
static_cast<uint32_t
>(grid.
faces.size()),
224 .levels = std::max<uint32_t>(1,
static_cast<uint32_t
>(grid.
levels.size()))};
226 limits.
nodes +=
static_cast<uint32_t
>(level.
levels.size());
236 const uint32_t levels = std::max(previous.
levelCount, 1u);
237 const uint32_t terminal = std::min(previous.
wantedTailDepth, levels - 1);
244 const uint64_t nodes =
m_limits.nodes;
245 const uint64_t cells =
m_limits.cells;
246 const uint64_t faces =
m_limits.faces;
248 case BufferCells:
return cells *
sizeof(ImGpuCell);
249 case BufferFaces:
return std::max<uint64_t>(1, faces) *
sizeof(ImGpuFace);
250 case BufferLists:
return ((2 * faces) + nodes + 1) *
sizeof(uint32_t);
251 case BufferNodes:
return nodes *
sizeof(ImGpuNode);
253 case BufferWork:
return ((3 * nodes) + cells + (2 * faces) + 1) *
sizeof(int64_t);
254 case BufferState:
return (STATE_WORDS + cells) *
sizeof(uint32_t);
255 case BufferWide:
return uint64_t{WIDE_WORDS} *
sizeof(int64_t);
256 case BufferPredicate:
return uint64_t{PREDICATE_WORDS} *
sizeof(uint64_t);
257 case BufferPlan:
return (IM_PLAN_FLAGS_BASE + (4 * nodes)) *
sizeof(uint32_t);
259 return uint64_t{IM_SLOT_DEPTH_BASE + (IM_SLOT_DEPTH_STRIDE *
m_maxDispatchLevels)} * ARGS_BYTES;
267 return std::unexpected(
"陰解法のルート署名を作れない");
269 for (uint32_t pass = 0; pass <
PassCount; ++pass) {
272 return std::unexpected(bytecode.error());
276 return std::unexpected(std::format(
"陰解法のパイプラインを作れない({})", SHADERS[pass]));
280 const D3D12_INDIRECT_ARGUMENT_DESC argument{.Type = D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH};
281 const D3D12_COMMAND_SIGNATURE_DESC signature{
282 .ByteStride = ARGS_BYTES, .NumArgumentDescs = 1, .pArgumentDescs = &argument, .NodeMask = 0};
283 if (FAILED(device->CreateCommandSignature(&signature,
nullptr, IID_PPV_ARGS(&
m_dispatchSignature))))
284 return std::unexpected(
"陰解法の間接の Dispatch の署名を作れない");
291 const auto buffer =
static_cast<Buffer>(i);
294 return std::unexpected(
"陰解法のバッファを作れない");
299 const uint64_t uploadBytes = buffer ==
BufferPlan ? uint64_t{IM_PLAN_HEADER_WORDS} *
sizeof(uint32_t)
303 return std::unexpected(
"陰解法の写すバッファを作れない");
314 return std::unexpected(
"陰解法の読み戻しを作れない");
316 const D3D12_QUERY_HEAP_DESC queryDesc{
317 .Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP, .Count =
MAX_TIMESTAMPS, .NodeMask = 0};
318 if (FAILED(device->CreateQueryHeap(&queryDesc, IID_PPV_ARGS(&
m_timestamps))))
319 return std::unexpected(
"タイムスタンプのヒープを作れない");
332 std::vector<uint32_t> levelOffsets(1, 0);
334 levelOffsets.push_back(levelOffsets.back() +
static_cast<uint32_t
>(level.
levels.size()));
336 auto [lists, faceStarts] = MakeCellFaces(grid);
337 auto [nodes, links] = MakeNodes(grid, levelOffsets, lists);
338 lists.insert(lists.begin() +
static_cast<std::ptrdiff_t
>(2 * grid.
faces.size()),
343 std::vector<ImGpuFace> faces(std::max<size_t>(1, grid.
faces.size()));
344 for (
size_t f = 0; f < grid.
faces.size(); ++f) {
346 faces[f] = {.coefficientHigh = face.
coefficient.hi,
351 .coarseFraction = grid.
cells[face.
coarse].coarseFraction ? 1u : 0u};
354 std::vector<uint32_t> plan(IM_PLAN_HEADER_WORDS, 0);
355 plan[IM_PLAN_LEVEL_COUNT] = need.
levels;
356 plan[IM_PLAN_FACES] = need.
faces;
357 for (uint32_t depth = 0; depth < grid.
levels.size(); ++depth) {
358 plan[PlanDepthWord(IM_PLAN_NODE_OFFSET, depth)] = levelOffsets[depth];
359 plan[PlanDepthWord(IM_PLAN_NODE_COUNT, depth)] = levelOffsets[depth + 1] - levelOffsets[depth];
362 std::array<std::vector<std::byte>,
BufferCount> images;
363 images[
BufferCells] = ToBytes(MakeCellImage(grid, faceStarts));
371 std::array<D3D12_RESOURCE_BARRIER, BufferCount> barriers{};
374 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
378 if (!WriteUpload(
m_uploads[i].Get(), images[i]))
381 list->CopyBufferRegion(
m_buffers[i].Get(), 0,
m_uploads[i].Get(), 0, images[i].size());
382 barriers[i].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
385 list->ResourceBarrier(
BufferCount, barriers.data());
391 std::array<D3D12_RESOURCE_BARRIER, BufferCount> barriers{};
394 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
397 list->ResourceBarrier(
BufferCount, barriers.data());
401 uint64_t facesOffset, uint64_t listsOffset, ID3D12Resource* header,
402 uint64_t faceCountOffset) {
403 const std::array<CopyRegion, 4> regions = {
407 .sourceOffset = cellsOffset,
412 .sourceOffset = facesOffset,
417 .sourceOffset = listsOffset,
418 .bytes = uint64_t{2} *
m_limits.faces *
sizeof(uint32_t)},
420 .targetOffset = uint64_t{IM_PLAN_FACES} *
sizeof(uint32_t),
422 .sourceOffset = faceCountOffset,
423 .bytes =
sizeof(uint32_t)}};
428 ID3D12Resource* links, ID3D12Resource* children) {
429 const uint64_t childrenOffset = uint64_t{2} *
m_limits.faces *
sizeof(uint32_t);
430 const std::array<CopyRegion, 4> regions = {
435 .bytes = uint64_t{IM_PLAN_SHAPE_WORDS} *
sizeof(uint32_t)},
447 .targetOffset = childrenOffset,
456 std::vector<D3D12_RESOURCE_BARRIER> barriers;
458 ID3D12Resource* target =
m_buffers[region.target].Get();
459 const bool seen = std::ranges::any_of(barriers, [&](
const D3D12_RESOURCE_BARRIER& barrier) {
460 return barrier.Transition.pResource == target;
464 gpu::Transition(target, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST));
468 list->ResourceBarrier(
static_cast<UINT
>(barriers.size()), barriers.data());
470 const uint64_t sourceBytes = region.source->GetDesc().Width;
471 const uint64_t targetBytes =
BufferBytes(region.target);
472 if (region.sourceOffset >= sourceBytes || region.targetOffset >= targetBytes)
475 const uint64_t bytes = std::min(
476 {region.bytes, sourceBytes - region.sourceOffset, targetBytes - region.targetOffset});
478 list->CopyBufferRegion(
m_buffers[region.target].Get(), region.targetOffset, region.source,
479 region.sourceOffset, bytes);
483 for (D3D12_RESOURCE_BARRIER& barrier : barriers)
484 std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
486 list->ResourceBarrier(
static_cast<UINT
>(barriers.size()), barriers.data());
496 auto [lists, faceStarts] = MakeCellFaces(grid);
497 auto [nodes, links] = MakeNodes(grid, images.
levelOffsets, lists);
498 images.
nodes = std::move(nodes);
499 images.
links = std::move(links);
500 images.
children.assign(lists.begin() +
static_cast<std::ptrdiff_t
>(2 * grid.
faces.size()), lists.end());
508 list->Dispatch(groups, 1, 1);
509 GlobalUavBarrier(list);
518 GlobalUavBarrier(list);
526 m_buffers[
BufferArgs].Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
527 list->ResourceBarrier(1, &barrier);
533 for (uint32_t sweep = 0; sweep < sweeps; ++sweep) {
534 for (uint32_t color = 0; color < COLOR_COUNT; ++color) {
544 const uint32_t levels =
m_constants.dispatchLevels;
545 for (uint32_t depth = 0; depth + 1 < levels; ++depth) {
546 const uint32_t slot = DepthSlot(depth);
556 for (uint32_t depth = levels - 1; depth-- > 0;) {
557 const uint32_t slot = DepthSlot(depth);
570 const D3D12_RESOURCE_BARRIER barrier =
gpu::Transition(predicate, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
571 D3D12_RESOURCE_STATE_PREDICATION);
572 list->ResourceBarrier(1, &barrier);
573 list->SetPredication(predicate, uint64_t{word} * 8, D3D12_PREDICATION_OP_NOT_EQUAL_ZERO);
580 list->SetPredication(
nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO);
583 list->ResourceBarrier(1, &barrier);
598 list->SetComputeRootUnorderedAccessView(i,
m_buffers[i]->GetGPUVirtualAddress());
600 list->SetComputeRootUnorderedAccessView(ROOT_LAYOUT.
DebugRingIndex(), debugRing);
611 for (uint32_t cycle = 0; cycle < options.
cycles; ++cycle) {
628 for (uint32_t pass = 0; pass <= maxLimitRounds; ++pass) {
642 m_buffers[
BufferArgs].Get(), D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
643 list->ResourceBarrier(1, &barrier);
654 return ((
m_constants.dispatchLevels - 1) * perLevel) + 1 + coarsest + judge;
661 list->EndQuery(
m_timestamps.Get(), D3D12_QUERY_TYPE_TIMESTAMP, index);
666 std::array<D3D12_RESOURCE_BARRIER, BufferCount> barriers{};
669 D3D12_RESOURCE_STATE_COMMON);
672 list->ResourceBarrier(
BufferCount, barriers.data());
685 m_buffers[
BufferPlan].Get(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE);
686 list->ResourceBarrier(1, &barrier);
688 uint64_t{IM_PLAN_HEADER_WORDS} *
sizeof(uint32_t));
689 std::swap(barrier.Transition.StateBefore, barrier.Transition.StateAfter);
690 list->ResourceBarrier(1, &barrier);
701 std::vector<ImGpuCell> cells(grid.
cells.size());
705 for (
size_t i = 0; i < cells.size(); ++i) {
706 grid.
cells[i].energy = cells[i].energy;
707 grid.
cells[i].fraction = cells[i].fraction;
714 std::vector<uint32_t> state(STATE_WORDS);
715 std::vector<int64_t> wide(WIDE_WORDS);
716 std::vector<uint32_t> plan(IM_PLAN_HEADER_WORDS);
722 cost = {.cycles = state[STATE_CYCLES],
723 .limitedCells = state[STATE_LIMITED_CELLS],
724 .limitRounds = state[STATE_LIMIT_ROUNDS],
725 .worstExcessMillikelvin = wide[WIDE_WORST_EXCESS],
726 .limitFinished = state[STATE_LIMIT_DONE] != 0,
727 .levelCount = plan[IM_PLAN_LEVEL_COUNT],
728 .tailDepth = plan[IM_PLAN_TAIL],
729 .wantedTailDepth = plan[IM_PLAN_WANTED_TAIL]};
std::vector< uint64_t > ReadTimestamps(uint32_t count) const
ComPtr< ID3D12QueryHeap > m_timestamps
ComPtr< ID3D12Resource > m_wideReadback
ComPtr< ID3D12Resource > m_cellsReadback
void RecordCopies(ID3D12GraphicsCommandList *list, std::span< const CopyRegion > regions)
bool ReadCost(GpuImplicitCost &cost) const
void RecordSmooth(ID3D12GraphicsCommandList *list, uint32_t depth, uint32_t slot, uint32_t sweeps)
std::expected< void, std::string > CreatePipelines(ID3D12Device5 *device)
ComPtr< ID3D12Resource > m_planReadback
void RecordVCycle(ID3D12GraphicsCommandList *list, const ImplicitOptions &options)
static constexpr uint32_t MAX_TIMESTAMPS
bool RecordUpload(ID3D12GraphicsCommandList *list, const ImplicitGrid &grid)
ComPtr< ID3D12RootSignature > m_rootSignature
void RecordRelease(ID3D12GraphicsCommandList *list)
std::expected< void, std::string > CreateBuffers(ID3D12Device5 *device)
static std::expected< GpuImplicit, std::string > Create(ID3D12Device5 *device, const GpuImplicitLimits &limits, const GpuImplicitTuning &tuning={})
void RecordCopySystem(ID3D12GraphicsCommandList *list, ID3D12Resource *source, uint64_t cellsOffset, uint64_t facesOffset, uint64_t listsOffset, ID3D12Resource *header, uint64_t faceCountOffset)
static GpuImplicitRecordShape ShapeFrom(const GpuImplicitCost &previous)
uint32_t DispatchesPerCycle(const ImplicitOptions &options) const
void RecordCopyLevels(ID3D12GraphicsCommandList *list, ID3D12Resource *header, ID3D12Resource *nodes, ID3D12Resource *links, ID3D12Resource *children)
void Dispatch(ID3D12GraphicsCommandList *list, Pass pass, uint32_t groups)
bool Read(ImplicitGrid &grid, GpuImplicitCost &cost) const
uint32_t m_maxDispatchLevels
uint32_t m_timestampCount
ComPtr< ID3D12CommandSignature > m_dispatchSignature
void BeginSkippable(ID3D12GraphicsCommandList *list, uint32_t word)
void RecordPlan(ID3D12GraphicsCommandList *list)
ComPtr< ID3D12Resource > m_timestampReadback
void RecordReadback(ID3D12GraphicsCommandList *list)
void RecordReset(ID3D12GraphicsCommandList *list)
void RecordCostReadback(ID3D12GraphicsCommandList *list)
void EndSkippable(ID3D12GraphicsCommandList *list)
void RecordTimestamp(ID3D12GraphicsCommandList *list, uint32_t index)
ComPtr< ID3D12Resource > m_stateReadback
static GpuImplicitLimits LimitsOf(const ImplicitGrid &grid)
std::array< ComPtr< ID3D12PipelineState >, PassCount > m_pipelines
std::array< ComPtr< ID3D12Resource >, BufferCount > m_buffers
std::array< ComPtr< ID3D12Resource >, BufferCount > m_uploads
GpuImplicitTuning m_tuning
void DispatchIndirect(ID3D12GraphicsCommandList *list, Pass pass, uint32_t slot)
bool RecordStep(ID3D12GraphicsCommandList *list, uint64_t debugRing, const ImplicitOptions &options, uint32_t maxLimitRounds=DEFAULT_MAX_LIMIT_ROUNDS, const GpuImplicitRecordShape &shape={})
uint64_t BufferBytes(Buffer buffer) const
GpuImplicitLimits m_limits
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)
void RecordCopyToReadback(ID3D12GraphicsCommandList *list, ID3D12Resource *source, ID3D12Resource *readback)
std::pair< std::vector< uint32_t >, std::vector< uint32_t > > MakeCellFaces(const ImplicitGrid &grid)
constexpr uint32_t ARGS_BYTES
std::vector< std::byte > ToBytes(const std::vector< T > &values)
bool WriteUpload(ID3D12Resource *upload, std::span< const std::byte > bytes)
void AppendChildren(const ImplicitGrid &grid, size_t depth, const std::vector< uint32_t > &levelOffsets, std::vector< ImGpuNode > &nodes, std::vector< uint32_t > &lists)
constexpr uint32_t STATE_LIMIT_ROUNDS
constexpr uint32_t DepthSlot(uint32_t depth)
constexpr uint32_t THREADS
constexpr uint32_t UAV_COUNT
constexpr uint32_t STATE_WORDS
constexpr gpu::RootSignatureLayout ROOT_LAYOUT
constexpr uint32_t PlanDepthWord(uint32_t kind, uint32_t depth)
constexpr uint32_t STATE_LIMIT_DONE
std::vector< ImGpuCell > MakeCellImage(const ImplicitGrid &grid, const std::vector< uint32_t > &faceStarts)
constexpr uint32_t PREDICATE_CYCLES
constexpr std::array< const char *, 15 > SHADERS
constexpr uint32_t STATE_CYCLES
void GlobalUavBarrier(ID3D12GraphicsCommandList *list)
constexpr uint32_t COLOR_COUNT
constexpr uint32_t WIDE_WORST_EXCESS
constexpr uint32_t PREDICATE_WORDS
constexpr uint32_t STATE_LIMITED_CELLS
NodeImages MakeNodes(const ImplicitGrid &grid, const std::vector< uint32_t > &levelOffsets, std::vector< uint32_t > &lists)
constexpr uint32_t SWEEP_BITS
constexpr uint32_t ROOT_CONSTANT_COUNT
constexpr std::array< bool, 11 > UPLOADED
constexpr uint32_t WIDE_WORDS
constexpr uint32_t PREDICATE_LIMIT
GpuImplicitLevelImages MakeGpuImplicitLevelImages(const ImplicitGrid &grid)
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
uint32_t coarsestTailMaxNodes
std::vector< int32_t > levels
std::vector< uint32_t > neighbors
std::vector< int64_t > weights
std::vector< uint32_t > parents
std::vector< int64_t > selfWeights
std::vector< uint32_t > rowStarts
std::vector< uint8_t > colors
std::vector< int64_t > restrictWeights
std::vector< ImplicitGridLevel > levels
std::vector< ImplicitFace > faces
std::vector< ImplicitCell > cells
uint32_t toleranceMillikelvin
uint32_t limitSlackMillikelvin
std::vector< ImGpuNode > nodes
std::vector< ImGpuLink > links