16#include "common/multires_activity.hlsli"
22using namespace bicameral::multires;
63 "sim/multires_tree_resolve.cso",
"sim/multires_tree_settle.cso",
"sim/multires_tree_allocate.cso",
64 "sim/multires_tree_release.cso",
"sim/multires_tree_clear_index.cso",
"sim/multires_tree_fill_index.cso",
65 "sim/multires_tree_quiet.cso",
"sim/multires_tree_expand.cso",
"sim/multires_tree_fold_check.cso",
66 "sim/multires_tree_fold.cso",
"sim/multires_tree_fractions.cso",
"sim/multires_tree_quiet_check.cso"};
78 "sim/multires_conduct_begin.cso",
"sim/multires_conduct_mark.cso",
"sim/multires_conduct_prepare.cso",
79 "sim/multires_conduct_flows.cso",
"sim/multires_conduct_apply.cso",
"sim/multires_conduct_end.cso"};
116 const auto base =
static_cast<uint16_t
>(
static_cast<int16_t
>(options.
subcycleBaseLevel));
137 static_assert(offsetof(D3D12_NODE_GPU_INPUT, EntrypointIndex) == 0);
138 static_assert(offsetof(D3D12_NODE_GPU_INPUT, NumRecords) == 4);
139 static_assert(offsetof(D3D12_NODE_GPU_INPUT, Records) == 8);
152 static_assert(
sizeof(MrRequest) == 40);
160 static_assert(offsetof(
ActivityHeader, input) + offsetof(D3D12_NODE_GPU_INPUT, NumRecords) ==
161 MR_ACTIVITY_NUM_RECORDS);
162 static_assert(offsetof(
ActivityHeader, reserved) == MR_ACTIVITY_RESERVED);
163 static_assert(offsetof(
ActivityHeader, dropped) == MR_ACTIVITY_DROPPED);
180 uint32_t
GroupsFor(uint32_t threads, uint32_t perGroup) {
181 return std::max(1u, (threads + perGroup - 1) / perGroup);
189 template <
typename T>
191 const auto bytes = std::as_bytes(data);
193 void* mapped =
nullptr;
194 const D3D12_RANGE noRead{.Begin = 0, .End = 0};
195 if (!buffer || FAILED(buffer->Map(0, &noRead, &mapped)))
198 std::memcpy(mapped, bytes.data(), bytes.size());
199 buffer->Unmap(0,
nullptr);
204 bool WriteUpload(ID3D12Resource* upload, std::span<const std::byte> bytes) {
205 void* mapped =
nullptr;
206 const D3D12_RANGE noRead{.Begin = 0, .End = 0};
207 if (FAILED(upload->Map(0, &noRead, &mapped)))
210 std::memcpy(mapped, bytes.data(), bytes.size());
211 upload->Unmap(0,
nullptr);
218 ID3D12RootSignature* rootSignature,
222 return std::unexpected(bytecode.error());
226 return std::unexpected(std::format(
"多重解像度のパイプラインを作れない({})", path));
233 list->ResourceBarrier(1, &barrier);
250 if (
auto pipelines = result.
CreatePipelines(device, options); !pipelines)
251 return std::unexpected(pipelines.error());
253 if (
auto buffers = result.
CreateBuffers(device, table); !buffers)
254 return std::unexpected(buffers.error());
267 return std::unexpected(implicit.error());
269 m_implicit = std::make_unique<GpuMultiresImplicit>(std::move(*implicit));
283 return std::unexpected(
"多重解像度のルート署名を作れない");
286 auto wake = LoadComputePipeline(device,
m_rootSignature.Get(),
"sim/multires_step_wake.cso");
287 auto stepWait = LoadComputePipeline(device,
m_rootSignature.Get(),
"sim/multires_step_wait.cso");
288 auto expandedWait = LoadComputePipeline(device,
m_rootSignature.Get(),
"sim/multires_step_expanded_wait.cso");
289 for (
const auto* loaded : {&wake, &stepWait, &expandedWait}) {
291 return std::unexpected(loaded->error());
300 const char* path = tree ? TREE_SHADERS[pass] : CONDUCT_SHADERS[pass -
TREE_PASS_COUNT];
301 auto pipeline = LoadComputePipeline(device,
m_rootSignature.Get(), path);
303 return std::unexpected(pipeline.error());
310 return std::unexpected(library.error());
314 return std::unexpected(graph.error());
316 m_graph = std::make_unique<gpu::WorkGraph>(std::move(*graph));
318 m_graph->EntrypointIndex(L
"PullBackNode"),
m_graph->EntrypointIndex(L
"RemoveShadowNode")};
319 if (std::ranges::contains(
m_entries, UINT32_MAX))
320 return std::unexpected(
"multires_graph.cso に入口のノードが足りない");
332 const auto activityLibrary =
gpu::LoadShader(
"sim/multires_activity_graph.cso");
333 if (!activityLibrary)
334 return std::unexpected(activityLibrary.error());
337 L
"MultiresActivity");
339 return std::unexpected(activityGraph.error());
341 m_activityGraph = std::make_unique<gpu::WorkGraph>(std::move(*activityGraph));
346 return std::unexpected(
"multires_activity_graph.cso に入口のノードが足りない");
352 const auto library =
gpu::LoadShader(
"sim/multires_conduct_graph.cso");
354 return std::unexpected(library.error());
358 return std::unexpected(graph.error());
360 m_conductGraph = std::make_unique<gpu::WorkGraph>(std::move(*graph));
366 return std::unexpected(
"multires_conduct_graph.cso に入口のノードが足りない");
376 const std::array<uint64_t, BufferCount> sizes =
BufferSizes();
378 const uint64_t bytes = std::max<uint64_t>(sizes[i], 16);
383 return std::unexpected(
"多重解像度のバッファを作れない");
389 return std::unexpected(
"要求の写しのバッファを作れない");
392 for (ComPtr<ID3D12Resource>& buffer :
m_activity) {
395 return std::unexpected(
"活性の一覧のバッファを作れない");
401 return std::unexpected(
"活性の一覧の写しを作れない");
404 m_constants.graphInputLow =
static_cast<uint32_t
>(graphInput);
405 m_constants.graphInputHigh =
static_cast<uint32_t
>(graphInput >> 32);
408 CreateFilledUpload(device, std::span(table.
species)), CreateFilledUpload(device, std::span(table.
rules)),
409 CreateFilledUpload(device, std::span(table.
ruleIndex)), CreateFilledUpload(device, std::span(table.
rates))};
410 if (!std::ranges::all_of(
m_tables, [](
const auto& buffer) {
return buffer !=
nullptr; }))
411 return std::unexpected(
"反応の表のバッファを作れない");
413 const D3D12_QUERY_HEAP_DESC queryDesc{
414 .Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP, .Count =
MAX_TIMESTAMPS, .NodeMask = 0};
415 if (FAILED(device->CreateQueryHeap(&queryDesc, IID_PPV_ARGS(&
m_timestamps))))
416 return std::unexpected(
"タイムスタンプのヒープを作れない");
421 return std::unexpected(
"タイムスタンプの読み戻しを作れない");
427 std::array<uint64_t, BufferCount> sizes{};
431 sizes[
BufferCounters] = uint64_t{MR_COUNTER_COUNT} *
sizeof(uint32_t);
436 sizes[
BufferRequests] = uint64_t{MR_MAX_REQUESTS} *
sizeof(MrRequest);
437 sizes[
BufferStates] = uint64_t{MR_MAX_REQUESTS} *
sizeof(MrRequestState);
439 (
PageCount() * MR_BLOCK_CELLS * CONDUCT_DELTA_BYTES);
451 return GRAPH_INPUT_EXPAND_RECORDS + ((uint64_t{
m_capacity.worldBlocks} + 1) *
sizeof(uint32_t));
459 const auto writeList = [&](uint32_t headerOffset, uint64_t recordsOffset, uint32_t entry) {
460 const D3D12_NODE_GPU_INPUT header{
461 .EntrypointIndex = entry,
463 .Records = {.StartAddress = base + recordsOffset, .StrideInBytes =
sizeof(uint32_t)}};
464 std::memcpy(image.data() + headerOffset, &header,
sizeof(header));
465 const uint32_t emptyRecord = MR_NO_BLOCK;
466 std::memcpy(image.data() + recordsOffset, &emptyRecord,
sizeof(emptyRecord));
469 writeList(GRAPH_INPUT_EXPAND_HEADER, GRAPH_INPUT_EXPAND_RECORDS,
471 for (uint32_t i = 0; i < GRAPH_INPUT_CONDUCT_HEADERS.size(); ++i)
479 const std::span<const uint32_t> freeBlocks = std::span(nest.
freeBlocks).first(
m_capacity.worldBlocks);
480 const std::span<const uint32_t> freePages = std::span(nest.
freeBlocks).subspan(
m_capacity.worldBlocks);
481 std::vector<uint32_t> words;
483 words.insert(words.end(), freeBlocks.begin(), freeBlocks.end());
484 words.insert(words.end(), nest.
claims.begin(), nest.
claims.end());
485 words.insert(words.end(), nest.
index.begin(), nest.
index.end());
486 words.insert(words.end(), freePages.begin(), freePages.end());
488 std::vector<std::byte> image(words.size() *
sizeof(uint32_t));
489 std::memcpy(image.data(), words.data(), image.size());
495 return MR_ACTIVITY_RECORDS + (uint64_t{MrActivityCapacity(
m_capacity.worldBlocks)} *
sizeof(uint32_t));
500 const auto count =
static_cast<uint32_t
>(slots.size());
501 const ActivityHeader header{
503 .NumRecords = 1 + count,
504 .Records = {.StartAddress =
m_activity[list]->GetGPUVirtualAddress() + MR_ACTIVITY_RECORDS,
505 .StrideInBytes =
sizeof(uint32_t)}},
506 .reserved = 1 + count,
508 std::vector<uint32_t> records = {MR_NO_BLOCK};
509 records.insert(records.end(), slots.begin(), slots.end());
511 std::vector<std::byte> bytes(
sizeof(header) + (records.size() *
sizeof(uint32_t)));
512 std::memcpy(bytes.data(), &header,
sizeof(header));
513 std::memcpy(bytes.data() +
sizeof(header), records.data(), records.size() *
sizeof(uint32_t));
523 nest.
fractions.size() !=
size_t{m_capacity.fractions} * MR_BLOCK_CELLS ||
531 const std::array<std::span<const std::byte>,
BufferCount> sources = {
532 std::as_bytes(std::span(nest.
blocks)),
533 std::as_bytes(std::span(nest.
cells)),
534 std::as_bytes(std::span(nest.
fractions)),
535 std::as_bytes(std::span(nest.
counters)),
536 std::span(treeWords),
538 std::as_bytes(std::span(nest.
ledger)),
539 std::as_bytes(std::span(nest.
requests)),
542 std::span(graphInput)};
543 std::array<D3D12_RESOURCE_BARRIER, BufferCount> barriers{};
545 if (!WriteUpload(
m_uploads[i].Get(), sources[i]))
551 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
554 list->ResourceBarrier(
BufferCount, barriers.data());
557 const std::vector<uint32_t> seeds =
SeedSlots(nest);
558 if (seeds.size() + 1 > MrActivityCapacity(
m_capacity.worldBlocks))
564 std::vector<std::byte> staging(ACTIVITY_FIRST_OFFSET);
567 std::ranges::copy(empty, staging.begin() +
static_cast<ptrdiff_t
>(i * ACTIVITY_EMPTY_STRIDE));
570 staging.insert(staging.end(), first.begin(), first.end());
576 ACTIVITY_EMPTY_BYTES);
577 const std::array<D3D12_RESOURCE_BARRIER, ACTIVITY_LISTS> toUav = {
580 D3D12_RESOURCE_STATE_UNORDERED_ACCESS)};
589 static_assert(
sizeof(
RootConstants) == ROOT_CONSTANT_COUNT *
sizeof(uint32_t));
591 static_assert((UAV_COUNT * 2) + ROOT_CONSTANT_COUNT + 2 + (
TABLE_COUNT * 2) <= 64);
593 const uint32_t parameter = i < EXTERNAL_VIEW_FIRST ? i : i + 2;
594 list->SetComputeRootUnorderedAccessView(parameter,
m_buffers[i]->GetGPUVirtualAddress());
600 list->SetComputeRootUnorderedAccessView(EXTERNAL_VIEW_FIRST + i, view);
605 list->SetComputeRootUnorderedAccessView(ROOT_LAYOUT.
DebugRingIndex(), debugRing);
607 list->SetComputeRootShaderResourceView(ROOT_LAYOUT.
SrvIndex(i),
m_tables[i]->GetGPUVirtualAddress());
623 uint32_t entry,
const void* record, uint32_t recordBytes) {
631 uint32_t pass, uint32_t groupCount) {
635 list->Dispatch(groupCount, 1, 1);
642 if (requests.size() > MR_MAX_REQUESTS)
647 const auto count =
static_cast<uint32_t
>(requests.size());
648 void* mapped =
nullptr;
649 const D3D12_RANGE noRead{.Begin = 0, .End = 0};
653 auto* bytes =
static_cast<std::byte*
>(mapped) + offset;
654 std::memcpy(bytes, &count,
sizeof(count));
655 std::memcpy(bytes + 256, requests.data(), requests.size_bytes());
661 const std::array<D3D12_RESOURCE_BARRIER, 2> toCopy = {
662 gpu::Transition(requestBuffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST),
663 gpu::Transition(counters, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST)};
664 list->ResourceBarrier(
static_cast<UINT
>(toCopy.size()), toCopy.data());
666 list->CopyBufferRegion(requestBuffer, 0,
m_requestUpload.Get(), offset + 256, requests.size_bytes());
668 list->CopyBufferRegion(counters, uint64_t{MR_COUNTER_REQUESTS} *
sizeof(uint32_t),
m_requestUpload.Get(),
669 offset,
sizeof(uint32_t));
670 const std::array<D3D12_RESOURCE_BARRIER, 2> toUav = {
671 gpu::Transition(requestBuffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS),
672 gpu::Transition(counters, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS)};
673 list->ResourceBarrier(
static_cast<UINT
>(toUav.size()), toUav.data());
684 uint64_t tick,
const MrFoldTolerance& tolerance) {
698 uint64_t tick,
const MrFoldTolerance& tolerance) {
708 const uint32_t requestGroups = GroupsFor(MR_MAX_REQUESTS, TREE_THREADS);
715 const D3D12_RESOURCE_BARRIER toInput =
gpu::Transition(graphInput, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
716 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
717 list->ResourceBarrier(1, &toInput);
724 const D3D12_RESOURCE_BARRIER toUav =
gpu::Transition(graphInput, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
725 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
726 list->ResourceBarrier(1, &toUav);
737 uint32_t parentSlot, uint32_t firstChildSlot, uint32_t levelCount,
739 const std::array<int64_t, 3> coordinates = {point.
x, point.
y, point.
z};
740 for (
size_t axis = 0; axis < coordinates.size(); ++axis) {
741 const auto value =
static_cast<uint64_t
>(coordinates[axis]);
742 m_constants.point[axis * 2] =
static_cast<uint32_t
>(value);
743 m_constants.point[(axis * 2) + 1] =
static_cast<uint32_t
>(value >> 32);
747 const RefineRecord record{.request = MR_NO_BLOCK,
748 .parentSlot = parentSlot,
749 .childSlot = firstChildSlot,
750 .levelsLeft = levelCount,
751 .kind = MR_BLOCK_SHADOW,
753 DispatchGraph(list, debugRing, EntryRefine, &record,
sizeof(record));
757 uint32_t firstSlot, uint32_t levelCount) {
758 const ChainRecord record{.slot = firstSlot, .levelsLeft = levelCount};
759 DispatchGraph(list, debugRing, EntryRemoveShadow, &record,
sizeof(record));
763 uint32_t firstShadowSlot, uint32_t levelCount) {
764 const ChainRecord record{.slot = firstShadowSlot, .levelsLeft = levelCount};
765 DispatchGraph(list, debugRing, EntryPullBack, &record,
sizeof(record));
769 m_constants.seedLow =
static_cast<uint32_t
>(worldSeed);
770 m_constants.seedHigh =
static_cast<uint32_t
>(worldSeed >> 32);
772 m_constants.tickHigh =
static_cast<uint32_t
>(tick >> 32);
786 RecordWake(list, debugRing, STEP_FLAG_WAKE_SEEDS);
790 ID3D12Resource* output =
m_activity[next].Get();
793 const std::array<D3D12_RESOURCE_BARRIER, 2> before = {
794 gpu::Transition(output, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST),
796 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE)};
797 list->ResourceBarrier(
static_cast<UINT
>(before.size()), before.data());
798 list->CopyBufferRegion(output, 0,
m_activityUpload.Get(), uint64_t{next} * ACTIVITY_EMPTY_STRIDE,
799 ACTIVITY_EMPTY_BYTES);
800 const D3D12_RESOURCE_BARRIER outputToUav =
gpu::Transition(output, D3D12_RESOURCE_STATE_COPY_DEST,
801 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
802 list->ResourceBarrier(1, &outputToUav);
814 const D3D12_RESOURCE_BARRIER inputToUav =
gpu::Transition(input, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
815 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
816 list->ResourceBarrier(1, &inputToUav);
821 const ObserverRecord record{.grid = {
m_capacity.observerBlocks, 1, 1},
850 uint32_t extraFlags) {
871 list->Dispatch(std::max(1u,
m_capacity.worldBlocks), 1, 1);
876 uint32_t pass, uint32_t groupCount) {
880 list->Dispatch(groupCount, 1, 1);
893 for (uint32_t substep = 0; substep < substeps; ++substep) {
894 m_constants.stepFlags = SubcycleFlags(flags, options, substep);
896 if (substep + 1 < substeps)
918 m_implicit->Record(list, debugRing, *
this, options);
929 m_implicit->RecordAdmit(list, debugRing, *
this, options);
945 ID3D12Resource* wake =
m_activity[wakeList].Get();
946 const D3D12_RESOURCE_BARRIER toCopy =
gpu::Transition(wake, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
947 D3D12_RESOURCE_STATE_COPY_DEST);
948 list->ResourceBarrier(1, &toCopy);
949 list->CopyBufferRegion(wake, 0,
m_activityUpload.Get(), uint64_t{wakeList} * ACTIVITY_EMPTY_STRIDE,
950 ACTIVITY_EMPTY_BYTES);
951 const D3D12_RESOURCE_BARRIER toUav =
gpu::Transition(wake, D3D12_RESOURCE_STATE_COPY_DEST,
952 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
953 list->ResourceBarrier(1, &toUav);
959 const D3D12_RESOURCE_BARRIER toInput =
gpu::Transition(wake, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
960 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
961 list->ResourceBarrier(1, &toInput);
962 const uint32_t flags = std::exchange(
m_constants.stepFlags,
m_constants.stepFlags | STEP_FLAG_SUBSTEP_WAKE);
968 const D3D12_RESOURCE_BARRIER back =
gpu::Transition(wake, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
969 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
970 list->ResourceBarrier(1, &back);
978 const bool listed = (
m_constants.stepFlags & STEP_FLAG_LISTED) != 0;
979 const bool implicitApply = pass == ConductPassApply && (
m_constants.stepFlags & STEP_FLAG_IMPLICIT) != 0;
986 const D3D12_RESOURCE_BARRIER toInput =
gpu::Transition(graphInput, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
987 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
988 list->ResourceBarrier(1, &toInput);
993 const uint32_t header = GRAPH_INPUT_CONDUCT_HEADERS[pass - ConductPassPrepare];
996 const D3D12_RESOURCE_BARRIER toUav =
gpu::Transition(graphInput, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
997 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
998 list->ResourceBarrier(1, &toUav);
1018 const D3D12_RESOURCE_BARRIER toInput =
gpu::Transition(graphInput, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
1019 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
1020 list->ResourceBarrier(1, &toInput);
1025 const D3D12_RESOURCE_BARRIER toUav =
gpu::Transition(graphInput, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
1026 D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
1027 list->ResourceBarrier(1, &toUav);
1037 ID3D12PipelineState* pipeline, uint32_t groupCount,
1038 const std::array<uint32_t, 4>& external) {
1042 list->SetPipelineState(pipeline);
1044 list->Dispatch(groupCount, 1, 1);
1068 const std::array<std::span<std::byte>,
BufferLedger + 1> destinations = {
1069 std::as_writable_bytes(std::span(nest.
blocks)), std::as_writable_bytes(std::span(nest.
cells)),
1070 std::as_writable_bytes(std::span(nest.
fractions)), std::as_writable_bytes(std::span(nest.
counters)),
1071 std::as_writable_bytes(std::span(treeWords)), std::as_writable_bytes(std::span(nest.
freeFractions)),
1072 std::as_writable_bytes(std::span(nest.
ledger))};
1073 for (uint32_t i = 0; i < destinations.size(); ++i) {
1079 const uint32_t worldBlocks =
m_capacity.worldBlocks;
1080 const auto words = std::span(treeWords);
1081 const auto index = words.subspan(
size_t{worldBlocks} * 2,
m_capacity.indexEntries);
1082 const auto freePages = words.subspan((
size_t{worldBlocks} * 2) +
m_capacity.indexEntries);
1083 std::ranges::copy(words.first(worldBlocks), nest.
freeBlocks.begin());
1084 std::ranges::copy(freePages, nest.
freeBlocks.begin() + worldBlocks);
1085 std::ranges::copy(index, nest.
index.begin());
1093 return std::nullopt;
1095 ActivityHeader header{};
1096 std::memcpy(&header, bytes.data(),
sizeof(header));
1097 const uint32_t capacity = MrActivityCapacity(
m_capacity.worldBlocks);
1098 if (header.input.NumRecords == 0 || header.input.NumRecords > capacity)
1099 return std::nullopt;
1101 ActivitySeeds seeds{.slots = std::vector<uint32_t>(header.input.NumRecords - 1), .dropped = header.dropped};
1102 std::memcpy(seeds.
slots.data(), bytes.data() +
sizeof(header) +
sizeof(uint32_t),
1103 seeds.
slots.size() *
sizeof(uint32_t));
1104 std::ranges::sort(seeds.
slots);
1105 const auto duplicates = std::ranges::unique(seeds.
slots);
1106 seeds.
slots.erase(duplicates.begin(), duplicates.end());
1115 list->EndQuery(
m_timestamps.Get(), D3D12_QUERY_TYPE_TIMESTAMP, index);
static std::expected< WorkGraph, std::string > Create(ID3D12Device5 *device, ID3D12RootSignature *globalRootSignature, std::span< const std::byte > library, std::wstring_view programName)
static void DispatchFromCpu(ID3D12GraphicsCommandList10 *list, uint32_t entrypointIndex, const void *records, uint32_t recordCount, uint64_t recordStrideBytes)
static void DispatchFromGpu(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS nodeGpuInput)
static std::expected< GpuMultiresImplicit, std::string > Create(ID3D12Device5 *device, const GpuMultires &multires, const MultiresCapacity &capacity, const GpuMultiresImplicitLimits &limits)
RootConstants m_constants
static constexpr uint32_t CONDUCT_PASS_COUNT
std::array< uint32_t, 4 > m_entries
ComPtr< ID3D12RootSignature > m_rootSignature
GpuMultires & operator=(GpuMultires &&other) noexcept
void StampImplicitPhases(bool stamp)
void RecordQuietRequests(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint64_t tick)
ComPtr< ID3D12Resource > m_timestampReadback
bool m_activityGraphInitialized
void BindRoot(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing) const
uint64_t PageCount() const
void SetActivityProgram(ID3D12GraphicsCommandList10 *list)
ComPtr< ID3D12QueryHeap > m_timestamps
bool UseConductionGraph(bool use)
std::unique_ptr< gpu::WorkGraph > m_conductGraph
void SetTick(uint64_t worldSeed, uint64_t tick)
static constexpr uint32_t TREE_PASS_COUNT
uint64_t ConductRecordsOffset() const
void RecordExpandPages(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing)
ComPtr< ID3D12PipelineState > m_wakePipeline
static constexpr uint32_t TABLE_COUNT
std::array< ComPtr< ID3D12Resource >, BufferCount > m_readbacks
bool RecordRequests(ID3D12GraphicsCommandList10 *list, std::span< const multires::MrRequest > requests)
void RecordWake(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t extraFlags)
std::unique_ptr< gpu::WorkGraph > m_activityGraph
void RecordFoldPages(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint64_t tick)
void RecordConduction(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, const MultiresStepOptions &options, uint32_t wakeList)
std::array< ComPtr< ID3D12Resource >, TABLE_COUNT > m_tables
void RecordStepWait(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing)
std::vector< uint64_t > ReadTimestamps(uint32_t count) const
void SetGraphProgram(ID3D12GraphicsCommandList10 *list)
void SetExternalViews(D3D12_GPU_VIRTUAL_ADDRESS first, D3D12_GPU_VIRTUAL_ADDRESS second)
void RecordConductStage(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t pass)
void RecordRefineShadow(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t parentSlot, uint32_t firstChildSlot, uint32_t levelCount, const MultiresPoint &point)
static constexpr uint32_t MAX_TIMESTAMPS
bool Read(MultiresNest &nest) const
std::vector< std::byte > MakeTreeWordsImage(const MultiresNest &nest) const
std::array< uint64_t, BufferCount > BufferSizes() const
void RecordPullBack(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t firstShadowSlot, uint32_t levelCount)
bool m_conductGraphInitialized
void DispatchGraph(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t entry, const void *record, uint32_t recordBytes)
ComPtr< ID3D12Resource > m_activityReadback
ComPtr< ID3D12PipelineState > m_stepExpandedWaitPipeline
std::vector< std::byte > MakeActivityList(uint32_t list, std::span< const uint32_t > slots) const
std::array< ComPtr< ID3D12Resource >, BufferCount > m_uploads
void RecordImplicitConduction(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, const MultiresStepOptions &options)
ComPtr< ID3D12Resource > m_requestUpload
std::array< ComPtr< ID3D12Resource >, BufferCount > m_buffers
std::array< ComPtr< ID3D12Resource >, ACTIVITY_LISTS > m_activity
void RecordConductPass(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t pass, uint32_t groupCount)
uint32_t m_activityCurrent
void RecordExternalDispatch(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, ID3D12PipelineState *pipeline, uint32_t groupCount, const std::array< uint32_t, 4 > &external)
MultiresCapacity m_capacity
ComPtr< ID3D12PipelineState > m_stepWaitPipeline
static constexpr uint32_t ACTIVITY_LISTS
void RecordRemoveShadow(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t firstSlot, uint32_t levelCount)
std::vector< std::byte > MakeGraphInputImage() const
void RecordTimestamp(ID3D12GraphicsCommandList10 *list, uint32_t index)
std::array< uint32_t, 3 > m_activityEntries
void RecordStep(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint64_t worldSeed, uint64_t tick, const MultiresStepOptions &options={})
std::expected< void, std::string > CreateBuffers(ID3D12Device5 *device, const BakedReactionTable &table)
std::expected< void, std::string > CreatePipelines(ID3D12Device5 *device, const GpuMultiresOptions &options)
bool RecordUpload(ID3D12GraphicsCommandList10 *list, const MultiresNest &nest)
ComPtr< ID3D12Resource > m_activityUpload
uint32_t m_timestampCount
void RecordExpandPass(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing)
bool RecordStepActive(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint64_t worldSeed, uint64_t tick, const MultiresStepOptions &options={})
static std::expected< GpuMultires, std::string > Create(ID3D12Device5 *device, const BakedReactionTable &table, const MultiresCapacity &capacity, const GpuMultiresOptions &options={})
std::unique_ptr< GpuMultiresImplicit > m_implicit
void RecordSubstepEnd(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t wakeList)
std::unique_ptr< gpu::WorkGraph > m_graph
void RecordConductSubstep(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, const MultiresStepOptions &options)
std::array< uint32_t, 4 > m_conductEntries
std::optional< ActivitySeeds > ReadSeeds() const
void RecordProcessRequests(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing)
void RecordReadback(ID3D12GraphicsCommandList10 *list)
std::expected< void, std::string > EnableImplicitConduction(ID3D12Device5 *device, const GpuMultiresImplicitLimits &limits)
std::expected< void, std::string > CreateConductionGraph(ID3D12Device5 *device)
std::array< ComPtr< ID3D12PipelineState >, TREE_PASS_COUNT > m_treePipelines
uint64_t ActivityBytes() const
uint32_t m_requestUploadCursor
std::array< ComPtr< ID3D12PipelineState >, CONDUCT_PASS_COUNT > m_conductPipelines
std::array< D3D12_GPU_VIRTUAL_ADDRESS, 2 > m_externalViews
static constexpr uint32_t REQUEST_UPLOAD_SLOTS
GpuMultires(GpuMultires &&other) noexcept
void RecordTreePass(ID3D12GraphicsCommandList10 *list, D3D12_GPU_VIRTUAL_ADDRESS debugRing, uint32_t pass, uint32_t groupCount)
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)
D3D12_RESOURCE_BARRIER UavBarrier(ID3D12Resource *resource)
constexpr uint32_t STEP_SUBSTEP_SHIFT
constexpr uint32_t TREE_THREADS
constexpr uint32_t GRAPH_INPUT_EXPAND_HEADER
constexpr uint64_t ACTIVITY_FIRST_OFFSET
constexpr uint32_t MAX_GPU_IMPLICIT_GAP
constexpr uint32_t STEP_BASE_SHIFT
constexpr uint32_t STEP_FLAG_IMPLICIT
constexpr uint32_t GRAPH_INPUT_EXPAND_RECORDS
constexpr uint32_t GRAPH_INPUT_BYTES
ComPtr< ID3D12Resource > CreateFilledUpload(ID3D12Device *device, std::span< const T > data)
constexpr uint64_t ACTIVITY_EMPTY_BYTES
constexpr std::array< const char *, 12 > TREE_SHADERS
bool WriteUpload(ID3D12Resource *upload, std::span< const std::byte > bytes)
constexpr uint32_t GRAPH_INPUT_COARSEN_HEADER
constexpr uint32_t STEP_FLAG_CONDUCTION
constexpr uint32_t REFINE_RECORD_BYTES
constexpr uint64_t CONDUCT_MARK_BYTES
uint32_t ImplicitFlags(const MultiresStepOptions &options)
void UavBarrier(ID3D12GraphicsCommandList10 *list)
constexpr uint64_t ACTIVITY_EMPTY_STRIDE
constexpr uint64_t CONDUCT_DELTA_BYTES
constexpr uint32_t STEP_IMPLICIT_GAP_SHIFT
uint32_t GroupsFor(uint32_t threads, uint32_t perGroup)
constexpr std::array< const char *, 6 > CONDUCT_SHADERS
constexpr std::array< uint32_t, 4 > GRAPH_INPUT_CONDUCT_HEADERS
constexpr uint32_t STEP_GAP_SHIFT
constexpr uint32_t UAV_COUNT
uint32_t SubcycleFlags(uint32_t flags, const MultiresStepOptions &options, uint32_t substep)
constexpr uint32_t STEP_FLAG_LISTED
constexpr uint32_t EXTERNAL_VIEW_FIRST
constexpr uint32_t ROOT_CONSTANT_COUNT
constexpr uint32_t WAKE_THREADS
constexpr uint32_t ACTIVITY_VIEW
constexpr uint64_t REQUEST_UPLOAD_BYTES
constexpr uint32_t STEP_FLAG_SUBSTEP_WAKE
constexpr uint32_t GRAPH_INPUT_REFINE_HEADER
constexpr uint32_t STEP_FLAG_BITS
std::expected< ComPtr< ID3D12PipelineState >, std::string > LoadComputePipeline(ID3D12Device5 *device, ID3D12RootSignature *rootSignature, const char *path)
constexpr gpu::RootSignatureLayout ROOT_LAYOUT
constexpr uint32_t STEP_FLAG_WAKE_SEEDS
std::vector< uint32_t > SeedSlots(const MultiresNest &nest)
constexpr uint32_t MULTIRES_MAX_SUBCYCLE_GAP
MultiresNest MakeMultiresNest(const MultiresCapacity &capacity)
MultiresImplicitLimits GpuMultiresImplicitLimits
void Log(Channel channel, Level level, FormatWithLocation< std::type_identity_t< Args >... > pattern, Args &&... args)
uint32_t DebugRingIndex() const
uint32_t SrvIndex(uint32_t shaderRegister) const
uint32_t RootConstantIndex() const
std::vector< uint64_t > rates
std::vector< uint32_t > ruleIndex
std::vector< reaction::RxSpecies > species
std::vector< reaction::RxRule > rules
std::vector< uint32_t > slots
std::vector< uint8_t > seeds
std::vector< reaction::RxCell > cells
std::vector< uint32_t > index
std::vector< multires::MrBlock > blocks
std::vector< uint32_t > claims
std::vector< multires::MrFraction > fractions
std::vector< uint32_t > freeFractions
std::vector< uint64_t > ledger
std::vector< multires::MrRequest > requests
std::vector< uint32_t > freeBlocks
std::array< uint32_t, multires::MR_COUNTER_COUNT > counters
int32_t subcycleBaseLevel
std::array< uint32_t, 3 > grid