17#include "common/multires_activity.hlsli"
21using namespace bicameral::multires;
37 const MrBlock& block = nest.
blocks[slot];
38 const uint32_t valueCell = MrFoldValueCell(block);
39 const RxCell value = valueCell < MR_BLOCK_CELLS ?
CellAt(nest, slot, valueCell) : RxMakeEmptyCell(0);
40 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index) {
41 if (!MrFoldsCell(block, value, index,
CellAt(nest, slot, index)))
50 MrBlock& block = nest.
blocks[slot];
53 block.page = MR_NO_PAGE;
54 nest.
counters[MR_COUNTER_FOLDED] += 1;
59 for (; bits != 0; --ledgerLevel) {
61 if (address == MR_NO_BLOCK) {
62 nest.
counters[MR_COUNTER_LEDGER_OUTSIDE] += 1;
66 uint64_t& value = nest.
ledger[address];
68 bits = value < bits ? uint64_t{1} << 61u : 0;
74 FX_ASSERT(units < MR_BLOCK_CELLS);
80 MrBlock& block = nest.
blocks[slot];
81 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index) {
84 for (uint32_t i = 0; i < fraction.speciesCount; ++i)
85 AddLedgerBits(nest, block.level, 1 + fraction.species[i], fraction.amounts[i]);
89 block.fraction = MR_NO_FRACTION;
94 MrBlock& block = nest.
blocks[slot];
95 if (block.activeTick == mark)
98 block.activeTick = mark;
99 nest.
counters[MR_COUNTER_SCHEDULED] += 1;
104 const MrBlock block = nest.
blocks[slot];
105 bool wakeSelf =
false;
106 for (uint32_t i = 0; i < MR_FACE_OCTANTS; ++i) {
107 const uint32_t child = block.children[MrNearOctant(face, i)];
108 if (child == MR_NO_BLOCK)
110 else if (remaining == 0)
111 nest.
counters[MR_COUNTER_WAKE_TOO_DEEP] += 1;
113 WakeFace(nest, child, face, remaining - 1, mark);
131 return RxComputeThermal(*
table, cell).temperature;
137 const MrFoldTolerance& tolerance) {
138 if (MrIsUniform(nest.
blocks[slot]))
141 const QuietLeafCells cells{.nest = &nest, .table = table, .slot = slot};
142 for (uint32_t group = 0; group < MR_OCTANT_CELLS; ++group) {
143 if (!MrCoarsenGroupWithin(cells, group, tolerance))
152 const MrFoldTolerance& tolerance) {
153 const uint64_t mark = MrChangeMark(tick);
155 MrBlock& block = nest.
blocks[slot];
156 if (MrNeedsQuietCheck(block, mark))
157 block.quietCheck = MrQuietCheckStamp(block.busyTick,
LeafCoarsenable(nest, table, slot, tolerance));
163 const MrFoldTolerance& tolerance) {
166 const CpuTree tree{.nest = &nest};
167 const uint64_t mark = MrChangeMark(tick);
168 uint32_t& count = nest.
counters[MR_COUNTER_REQUESTS];
170 if (!MrWantsQuietCoarsen(tree, slot, mark))
173 if (count == MR_MAX_REQUESTS) {
174 nest.
counters[MR_COUNTER_QUIET_DEFERRED] += 1;
178 nest.
requests[count++] = MrMakeQuietCoarsenRequest(nest.
blocks[slot]);
179 nest.
counters[MR_COUNTER_QUIET_REQUESTS] += 1;
185 const CpuTree tree{.nest = &nest};
186 const MrBlock block = nest.
blocks[slot];
187 Schedule(nest, slot, mark);
188 for (uint32_t check = 0; check < MR_WAKE_CHECKS; ++check) {
189 const uint32_t face = check % MR_FACES;
190 const MrWake wake = MrWakeAcross(tree, block, check / MR_FACES, face, nest.
capacity.
rootLevel);
191 if (wake.schedule != MR_NO_BLOCK)
192 Schedule(nest, wake.schedule, mark);
194 if (wake.descend != MR_NO_BLOCK)
195 WakeFace(nest, wake.descend, face, MR_MAX_WAKE_DEPTH, mark);
202 const uint32_t mark = MrActivityMark(tick);
206 const uint64_t changeMark = MrChangeMark(tick);
207 for (uint32_t slot = 0; slot < worldBlocks; ++slot) {
208 const MrBlock& block = nest.
blocks[slot];
209 const bool due = block.wakeTick <= changeMark;
210 if ((nest.
seeds[slot] != 0 || due) && block.kind == MR_BLOCK_REAL)
214 std::ranges::fill(nest.
seeds, uint8_t{0});
217 std::vector<uint8_t> stepped(nest.
blocks.size(), 0);
218 for (uint32_t slot = 0; slot < nest.
blocks.size(); ++slot)
219 stepped[slot] = slot >= worldBlocks || nest.
blocks[slot].activeTick == mark ? 1 : 0;
222 nest, table.
View(), stepped, worldSeed, tick, options, mark);
229 const uint64_t mark = MrChangeMark(tick);
231 if (!MrWantsFoldCheck(nest.
blocks[slot], mark))
234 const std::optional<RxCell> value = ExactFoldValue(nest, slot);
236 FoldPage(nest, slot, *value);
241 const MrFoldTolerance& tolerance) {
242 if (MrIsExactFold(tolerance)) {
248 const uint64_t mark = MrChangeMark(tick);
251 if (MrWantsFractionReturn(nest.
blocks[slot], mark))
252 ReturnFractionsToLedger(nest, slot);
254 const MrBlock& block = nest.
blocks[slot];
255 if (!MrWantsFoldCheck(block, mark))
260 const std::optional<RxCell> exact = ExactFoldValue(nest, slot);
262 FoldPage(nest, slot, *exact);
266 if (MrFoldValueCell(block) == MR_BLOCK_CELLS)
270 if (!MrFoldStatsWithin(stats, tolerance))
274 const MrFoldValue value = MrFoldStatsValue(stats);
275 AddFoldRemainder(nest, block.level, 0, value.energyRemainder);
276 for (uint32_t i = 0; i < stats.speciesCount; ++i)
277 AddFoldRemainder(nest, block.level, 1 + stats.species[i], value.amountRemainders[i]);
279 FoldPage(nest, slot, value.cell);
287 const MrBlock& block = nest.
blocks[slot];
288 MrFoldStats stats = MrMakeFoldStats();
289 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index) {
290 if (MrIsCoveredCell(block, index))
294 stats = MrAddFoldCell(stats, cell, RxComputeThermal(table, cell).temperature);
301 SubmitQuietRequests(nest,
nullptr, tick, MrExactFoldTolerance());
305 const MrFoldTolerance& tolerance) {
307 SubmitQuietRequests(nest, MrIsExactFold(tolerance) ?
nullptr : &view, tick, tolerance);
311 std::vector<uint32_t> slots;
313 const MrBlock& block = nest.
blocks[slot];
314 if (block.kind == MR_BLOCK_REAL && (nest.
seeds[slot] != 0 || block.wakeTick <= MrChangeMark(tick)))
315 slots.push_back(slot);
322 std::vector<uint32_t> slots;
323 for (uint32_t slot = 0; slot < nest.
seeds.size(); ++slot) {
324 if (nest.
seeds[slot] != 0)
325 slots.push_back(slot);
uint32_t & FreePageAt(MultiresNest &nest, uint32_t position)
void ReturnFractionsToLedger(MultiresNest &nest, uint32_t slot)
void SubmitQuietRequests(MultiresNest &nest, const ReactionTableView *table, uint64_t tick, const MrFoldTolerance &tolerance)
std::optional< RxCell > ExactFoldValue(MultiresNest &nest, uint32_t slot)
void AddFoldRemainder(MultiresNest &nest, int32_t level, uint32_t column, uint64_t units)
void FoldPage(MultiresNest &nest, uint32_t slot, const RxCell &value)
void WakeFace(MultiresNest &nest, uint32_t slot, uint32_t face, uint32_t remaining, uint32_t mark)
reaction::RxCell & UniformAt(MultiresNest &nest, uint32_t slot)
void AddLedgerBits(MultiresNest &nest, int32_t ledgerLevel, uint32_t column, uint64_t bits)
reaction::RxCell & CellAt(MultiresNest &nest, uint32_t slot, uint32_t index)
bool LeafCoarsenable(const MultiresNest &nest, const ReactionTableView *table, uint32_t slot, const MrFoldTolerance &tolerance)
void Schedule(MultiresNest &nest, uint32_t slot, uint32_t mark)
void CheckQuietLeaves(MultiresNest &nest, const ReactionTableView *table, uint64_t tick, const MrFoldTolerance &tolerance)
void WakeAround(MultiresNest &nest, uint32_t slot, uint32_t mark)
uint32_t & FreePageAt(MultiresNest &nest, uint32_t position)
std::vector< BlockStepResult > StepBlocks(MultiresNest &nest, const ReactionTableView &view, std::span< uint8_t > stepped, uint64_t worldSeed, uint64_t tick, const MultiresStepOptions &options, uint32_t wakeMark)
multires::MrFraction FractionAt(const MultiresNest &nest, uint32_t fractionSlot, uint32_t index)
void PokeBlock(MultiresNest &nest, uint32_t slot)
void RecordWaitResults(MultiresNest &nest, std::span< const BlockStepResult > results, uint64_t tick)
reaction::RxCell & UniformAt(MultiresNest &nest, uint32_t slot)
reaction::RxCell & CellAt(MultiresNest &nest, uint32_t slot, uint32_t index)
void FoldQuietPages(MultiresNest &nest, uint64_t tick)
std::vector< uint32_t > SeedSlots(const MultiresNest &nest)
MrFoldStats CollectFoldStats(const MultiresNest &nest, const ReactionTableView &table, uint32_t slot)
void SubmitQuietCoarsenRequests(MultiresNest &nest, uint64_t tick)
RxCell LoadNestCell(const MultiresNest &nest, uint32_t slot, uint32_t index)
std::vector< uint32_t > WaitSeedSlots(const MultiresNest &nest, uint64_t tick)
void StepActive(MultiresNest &nest, const BakedReactionTable &table, uint64_t worldSeed, uint64_t tick, const MultiresStepOptions &options)
ReactionTableView View() const
std::vector< uint8_t > seeds
MultiresCapacity capacity
std::vector< multires::MrBlock > blocks
std::vector< uint32_t > freeFractions
std::vector< uint64_t > ledger
std::vector< multires::MrRequest > requests
std::array< uint32_t, multires::MR_COUNTER_COUNT > counters
RxCell Cell(uint32_t index) const
const ReactionTableView * table
int32_t Temperature(const RxCell &cell) const
const MultiresNest * nest