10#include "common/multires_activity.hlsli"
14using namespace bicameral::multires;
36 const MrBlock& block = nest.
blocks[slot];
37 const uint32_t home = MrIndexHome(block.level, block.originX, block.originY, block.originZ,
41 if (entry != MR_INDEX_EMPTY)
48 nest.
counters[MR_COUNTER_INDEX_FULL] += 1;
52 const MrBlock& block = nest.
blocks[slot];
53 const uint32_t home = MrIndexHome(block.level, block.originX, block.originY, block.originZ,
57 if (entry == MR_INDEX_EMPTY)
63 entry = MR_INDEX_TOMBSTONE;
64 nest.
counters[MR_COUNTER_TOMBSTONES] += 1;
71 void Release(MrRequestState& state, uint32_t fractionSlot) {
72 FX_ASSERT(state.releaseCount < MR_MAX_RELEASES);
73 state.releases[state.releaseCount] = fractionSlot;
74 state.releaseCount += 1;
78 return nest.
freeBlocks[state.blockBase - 1 - i];
82 FX_ASSERT(i < state.pageNeed);
84 return FreePageAt(nest, state.pageBase - 1 - i);
88 if (i >= state.fractionNeed)
89 return MR_NO_FRACTION;
97 const MrRequest& request = nest.
requests[i];
98 MrRequestState& state = nest.
states[i];
101 nest, rootLevel, MrBlockOriginOf(MrCoarserCoordinate(request.x, request.level, rootLevel)),
102 MrBlockOriginOf(MrCoarserCoordinate(request.y, request.level, rootLevel)),
103 MrBlockOriginOf(MrCoarserCoordinate(request.z, request.level, rootLevel)));
104 if (root == MR_NO_BLOCK) {
105 state.status = MR_STATUS_INVALID;
110 uint32_t deepest = root;
111 while (nest.
blocks[deepest].level < request.level) {
112 const MrBlock& block = nest.
blocks[deepest];
114 child = block.children[MrOctantOfPoint(block, request.x, request.y, request.z, request.level)];
115 if (child == MR_NO_BLOCK)
121 const int32_t deepestLevel = nest.
blocks[deepest].level;
122 if (deepestLevel == request.level) {
123 state.status = MR_STATUS_ALREADY;
127 state.target = deepest;
128 state.claimSlot = deepest;
129 state.levels = std::min(
static_cast<uint32_t
>(request.level - deepestLevel), MR_MAX_CHAIN_LEVELS);
130 nest.
claims[deepest] = std::min(nest.
claims[deepest], i);
134 MrChildren children{};
135 for (uint32_t j = 0; j < MR_CHILDREN_PER_CELL; ++j) {
136 const uint32_t index = MrChildCell(local, j);
137 children.cells[j] =
LoadNestCell(nest, childSlot, index);
138 children.fractions[j] =
FractionAt(nest, fractionSlot, index);
146 const uint32_t fractionSlot = nest.
blocks[childSlot].fraction;
147 for (uint32_t local = 0; local < MR_OCTANT_CELLS; ++local) {
148 if (!MrCoarsenFits(
GatherChildren(nest, childSlot, fractionSlot, local)))
156 const MrRequest& request = nest.
requests[i];
157 MrRequestState& state = nest.
states[i];
158 const uint32_t slot =
LookupBlock(nest, request.level, MrBlockOriginOf(request.x),
159 MrBlockOriginOf(request.y), MrBlockOriginOf(request.z));
160 if (slot == MR_NO_BLOCK || nest.
blocks[slot].parent == MR_NO_BLOCK || MrHasRealChild(nest.
blocks[slot])) {
161 state.status = MR_STATUS_INVALID;
167 MrBlock& block = nest.
blocks[slot];
168 block.quietCheck = MrQuietCheckStamp(block.busyTick,
false);
169 state.status = MR_STATUS_SPECIES_FULL;
173 const uint32_t parent = nest.
blocks[slot].parent;
175 state.claimSlot = parent;
180 const MrRequest& request = nest.
requests[i];
181 nest.
states[i] = MrMakeRequestState();
183 if (span < 0 || span >
static_cast<int32_t
>(MR_MAX_LEVEL_SPAN)) {
184 nest.
states[i].status = MR_STATUS_INVALID;
188 if (request.op == MR_REQUEST_REFINE)
190 else if (request.op == MR_REQUEST_COARSEN)
193 nest.
states[i].status = MR_STATUS_INVALID;
199 MrRequestState& state = nest.
states[i];
200 if (state.status != MR_STATUS_PENDING)
203 const bool coarsen = nest.
requests[i].op == MR_REQUEST_COARSEN;
204 const bool lost = nest.
claims[state.claimSlot] != i;
205 const bool targetTaken = coarsen && nest.
claims[state.target] != MR_NO_CLAIM;
206 if (lost || targetTaken) {
207 state.status = MR_STATUS_CONFLICT;
212 const uint32_t parent = nest.
blocks[state.target].parent;
213 state.fractionNeed = nest.
blocks[parent].fraction == MR_NO_FRACTION ? 1 : 0;
214 state.pageNeed = MrCoarsenPageNeed(nest.
blocks[state.target],
UniformAt(nest, state.target),
220 state.blockNeed = state.levels;
221 state.fractionNeed = nest.
blocks[state.target].fraction != MR_NO_FRACTION ? state.levels : 0;
222 state.pageNeed = MrIsUniform(nest.
blocks[state.target]) ? 0 : state.levels;
228 const uint32_t freeBlocks = nest.
counters[MR_COUNTER_FREE_BLOCKS];
229 const uint32_t freeFractions = nest.
counters[MR_COUNTER_FREE_FRACTIONS];
230 const uint32_t freePages = nest.
counters[MR_COUNTER_FREE_PAGES];
231 uint32_t blockSum = 0;
232 uint32_t fractionSum = 0;
233 uint32_t pageSum = 0;
234 uint32_t grantedBlocks = 0;
235 uint32_t grantedFractions = 0;
236 uint32_t grantedPages = 0;
237 for (uint32_t i = 0; i < count; ++i) {
238 MrRequestState& state = nest.
states[i];
239 if (state.status != MR_STATUS_PENDING)
242 const uint32_t blockBase = freeBlocks - blockSum;
243 const uint32_t fractionBase = freeFractions - fractionSum;
244 const uint32_t pageBase = freePages - pageSum;
245 blockSum += state.blockNeed;
246 fractionSum += state.fractionNeed;
247 pageSum += state.pageNeed;
248 if (blockSum > freeBlocks || fractionSum > freeFractions || pageSum > freePages) {
249 state.status = MR_STATUS_NO_SPACE;
253 state.status = MR_STATUS_GRANTED;
254 state.blockBase = blockBase;
255 state.fractionBase = fractionBase;
256 state.pageBase = pageBase;
257 grantedBlocks = blockSum;
258 grantedFractions = fractionSum;
259 grantedPages = pageSum;
262 nest.
counters[MR_COUNTER_FREE_BLOCKS] = freeBlocks - grantedBlocks;
263 nest.
counters[MR_COUNTER_FREE_FRACTIONS] = freeFractions - grantedFractions;
264 nest.
counters[MR_COUNTER_FREE_PAGES] = freePages - grantedPages;
270 const MrRequest& request = nest.
requests[i];
271 MrRequestState& state = nest.
states[i];
272 const uint32_t childSlot =
PoppedBlock(nest, state, depth);
274 MrBlock& parent = nest.
blocks[parentSlot];
275 const uint32_t octant = MrOctantOfPoint(parent, request.x, request.y, request.z, request.level);
276 const bool uniform = MrIsUniform(parent);
277 const uint32_t childPage = uniform ? MR_NO_PAGE :
PoppedPage(nest, state, depth);
280 bool octantFraction =
false;
281 bool restFraction =
false;
282 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index) {
283 const bool nonzero = !MrFractionIsZero(
FractionAt(nest, parent.fraction, index));
284 const bool covered = MrOctantOfCell(index) == octant;
285 octantFraction |= nonzero && covered;
286 restFraction |= nonzero && !covered;
289 FX_ASSERT(!octantFraction || candidate != MR_NO_FRACTION);
290 const uint32_t childFraction = octantFraction ? candidate : MR_NO_FRACTION;
296 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index) {
297 const uint32_t parentCell = MrParentCellOfChild(octant, index);
301 if (childFraction != MR_NO_FRACTION)
306 for (uint32_t local = 0; local < MR_OCTANT_CELLS; ++local) {
307 const uint32_t index = MrOctantCell(octant, local);
309 CellAt(nest, parentSlot, index) = RxMakeEmptyCell(0);
311 if (parent.fraction != MR_NO_FRACTION)
312 SetFraction(nest, parent.fraction, index, MrMakeEmptyFraction());
316 if (candidate != MR_NO_FRACTION && childFraction == MR_NO_FRACTION)
319 if (parent.fraction != MR_NO_FRACTION && !restFraction) {
320 Release(state, parent.fraction);
321 parent.fraction = MR_NO_FRACTION;
324 parent.children[octant] = childSlot;
325 nest.
blocks[childSlot] = MrMakeChildBlock(parent, parentSlot, octant, MR_BLOCK_REAL, childFraction,
337 uint32_t parent = nest.
states[i].target;
338 for (uint32_t depth = 0; depth < nest.
states[i].levels; ++depth) {
348 if (address == MR_NO_BLOCK) {
349 nest.
counters[MR_COUNTER_LEDGER_OUTSIDE] += 1;
353 nest.
ledger[address] += lostBits;
357 nest.
counters[MR_COUNTER_LOST] += result.lostCount;
358 nest.
counters[MR_COUNTER_OVERFLOW] += result.overflowCount;
359 if (result.energyLostBits != 0)
360 AddToLedger(nest, childLevel, 0, result.energyLostBits);
362 for (uint32_t k = 0; k < result.lostSpeciesCount; ++k)
363 AddToLedger(nest, childLevel, 1 + result.lostSpecies[k], result.lostBits[k]);
367 MrRequestState& state = nest.
states[i];
368 const uint32_t childSlot = state.target;
369 const MrBlock child = nest.
blocks[childSlot];
370 MrBlock& parent = nest.
blocks[child.parent];
373 std::array<MrCoarsened, MR_OCTANT_CELLS> results{};
374 bool octantFraction =
false;
375 for (uint32_t local = 0; local < MR_OCTANT_CELLS; ++local) {
376 results[local] = MrCoarsenCell(
GatherChildren(nest, childSlot, child.fraction, local));
378 octantFraction |= !MrFractionIsZero(results[local].fraction);
382 if (state.pageNeed != 0) {
383 const uint32_t page =
PoppedPage(nest, state, 0);
384 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index)
385 PageCellAt(nest, page, index) = MrUniformCell(parent,
UniformAt(nest, child.parent), index);
391 bool restFraction =
false;
393 if (parent.fraction == MR_NO_FRACTION) {
394 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index)
395 SetFraction(nest, newFraction, index, MrMakeEmptyFraction());
396 parent.fraction = newFraction;
399 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index) {
400 if (MrOctantOfCell(index) != child.parentOctant)
401 restFraction |= !MrFractionIsZero(
FractionAt(nest, parent.fraction, index));
404 for (uint32_t local = 0; local < MR_OCTANT_CELLS; ++local) {
405 const uint32_t index = MrOctantCell(child.parentOctant, local);
406 if (!MrIsUniform(parent))
407 CellAt(nest, child.parent, index) = results[local].cell;
409 SetFraction(nest, parent.fraction, index, results[local].fraction);
413 if (!octantFraction && !restFraction) {
414 Release(state, parent.fraction);
415 parent.fraction = MR_NO_FRACTION;
418 if (child.fraction != MR_NO_FRACTION)
419 Release(state, child.fraction);
421 state.releaseBlock = childSlot;
422 if (!MrIsUniform(child))
423 state.releasePage = child.page;
425 parent.children[child.parentOctant] = MR_NO_BLOCK;
427 nest.
blocks[childSlot] = MrMakeUnusedBlock();
434 for (uint32_t i = 0; i < count; ++i) {
435 const MrRequestState& state = nest.
states[i];
436 if (state.claimSlot != MR_NO_CLAIM)
437 nest.
claims[state.claimSlot] = MR_NO_CLAIM;
439 nest.
counters[MrStatusCounter(state.status)] += 1;
440 if (state.status != MR_STATUS_GRANTED)
443 for (uint32_t k = 0; k < state.releaseCount; ++k)
446 if (state.releaseBlock != MR_NO_BLOCK)
449 if (state.releasePage != MR_NO_PAGE)
455 nest.
counters[MR_COUNTER_REBUILD_INDEX] = rebuild ? 1 : 0;
457 nest.
counters[MR_COUNTER_TOMBSTONES] = 0;
459 nest.
counters[MR_COUNTER_REQUESTS] = 0;
465 std::span<const RxCell> cells) {
466 FX_ASSERT(cells.size() == MR_BLOCK_CELLS);
467 FX_ASSERT(nest.
counters[MR_COUNTER_FREE_BLOCKS] > 0);
470 MrBlock block = MrMakeUnusedBlock();
471 block.originX = originX;
472 block.originY = originY;
473 block.originZ = originZ;
475 block.kind = MR_BLOCK_REAL;
478 const bool uniform = std::ranges::all_of(cells, [&](
const RxCell& cell) {
return MrSameCell(cell, cells[0]); });
480 UniformAt(nest, slot) = cells[0];
483 for (uint32_t index = 0; index < MR_BLOCK_CELLS; ++index)
484 PageCellAt(nest, block.page, index) = cells[index];
487 nest.
blocks[slot] = block;
488 IndexInsert(nest, slot);
495 uint32_t& count = nest.
counters[MR_COUNTER_REQUESTS];
496 FX_ASSERT(count + requests.size() <= MR_MAX_REQUESTS);
497 for (
const MrRequest& request : requests)
502 const uint32_t count = nest.
counters[MR_COUNTER_REQUESTS];
503 for (uint32_t i = 0; i < count; ++i)
506 for (uint32_t i = 0; i < count; ++i)
509 Allocate(nest, count);
510 for (uint32_t i = 0; i < count; ++i) {
511 if (nest.
states[i].status != MR_STATUS_GRANTED)
514 if (nest.
requests[i].op == MR_REQUEST_REFINE)
515 ApplyRefine(nest, i);
517 ApplyCoarsen(nest, i);
520 ReleaseAll(nest, count);
521 if (nest.
counters[MR_COUNTER_REBUILD_INDEX] != 0)
526 const uint32_t home = MrIndexHome(level, originX, originY, originZ, nest.
capacity.
indexEntries);
528 const uint32_t entry = nest.
index[(home + probe) & IndexMask(nest)];
529 if (entry == MR_INDEX_EMPTY)
532 if (entry != MR_INDEX_TOMBSTONE && MrBlockHasKey(nest.
blocks[entry], level, originX, originY, originZ))
540 std::ranges::fill(nest.
index, MR_INDEX_EMPTY);
542 if (nest.
blocks[slot].kind == MR_BLOCK_REAL)
543 IndexInsert(nest, slot);
void ResolveCoarsen(MultiresNest &nest, uint32_t i)
void RefineRequestLevel(MultiresNest &nest, uint32_t i, uint32_t depth, uint32_t parentSlot)
void ApplyCoarsen(MultiresNest &nest, uint32_t i)
uint32_t PoppedBlock(const MultiresNest &nest, const MrRequestState &state, uint32_t i)
void ResolveRefine(MultiresNest &nest, uint32_t i)
uint32_t & FreePageAt(MultiresNest &nest, uint32_t position)
uint32_t IndexMask(const MultiresNest &nest)
void IndexInsert(MultiresNest &nest, uint32_t slot)
void Settle(MultiresNest &nest, uint32_t i)
multires::MrFraction FractionAt(const MultiresNest &nest, uint32_t fractionSlot, uint32_t index)
void Release(MrRequestState &state, uint32_t fractionSlot)
MrChildren GatherChildren(const MultiresNest &nest, uint32_t childSlot, uint32_t fractionSlot, uint32_t local)
void Allocate(MultiresNest &nest, uint32_t count)
void IndexRemove(MultiresNest &nest, uint32_t slot)
void PokeBlock(MultiresNest &nest, uint32_t slot)
uint32_t PoppedFraction(const MultiresNest &nest, const MrRequestState &state, uint32_t i)
bool CoarsenFits(const MultiresNest &nest, uint32_t childSlot)
void ApplyRefine(MultiresNest &nest, uint32_t i)
uint32_t PoppedPage(MultiresNest &nest, const MrRequestState &state, uint32_t i)
reaction::RxCell & UniformAt(MultiresNest &nest, uint32_t slot)
void RecordCoarsened(MultiresNest &nest, const MrCoarsened &result, int32_t childLevel)
reaction::RxCell & PageCellAt(MultiresNest &nest, uint32_t page, uint32_t index)
void SetFraction(MultiresNest &nest, uint32_t fractionSlot, uint32_t index, const multires::MrFraction &fraction)
void Resolve(MultiresNest &nest, uint32_t i)
void AddToLedger(MultiresNest &nest, int32_t level, uint32_t column, uint32_t lostBits)
void ReleaseAll(MultiresNest &nest, uint32_t count)
reaction::RxCell & CellAt(MultiresNest &nest, uint32_t slot, uint32_t index)
uint32_t & FreePageAt(MultiresNest &nest, uint32_t position)
multires::MrFraction FractionAt(const MultiresNest &nest, uint32_t fractionSlot, uint32_t index)
void PokeBlock(MultiresNest &nest, uint32_t slot)
reaction::RxCell & UniformAt(MultiresNest &nest, uint32_t slot)
reaction::RxCell & PageCellAt(MultiresNest &nest, uint32_t page, uint32_t index)
void SetFraction(MultiresNest &nest, uint32_t fractionSlot, uint32_t index, const multires::MrFraction &fraction)
uint32_t PopPage(MultiresNest &nest)
reaction::RxCell & CellAt(MultiresNest &nest, uint32_t slot, uint32_t index)
void SubmitRequests(MultiresNest &nest, std::span< const multires::MrRequest > requests)
void RebuildIndex(MultiresNest &nest)
RxCell LoadNestCell(const MultiresNest &nest, uint32_t slot, uint32_t index)
uint32_t LookupBlock(const MultiresNest &nest, int32_t level, int64_t originX, int64_t originY, int64_t originZ)
void ProcessRequests(MultiresNest &nest)
uint32_t PlaceRootBlock(MultiresNest &nest, int64_t originX, int64_t originY, int64_t originZ, std::span< const reaction::RxCell > cells)
std::vector< uint32_t > index
MultiresCapacity capacity
std::vector< multires::MrRequestState > states
std::vector< multires::MrBlock > blocks
std::vector< uint32_t > claims
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