Bicameral Engine
GPU-resident engine for a magic-research open-world game
Loading...
Searching...
No Matches
multires_nest_internal.h
Go to the documentation of this file.
1// multires_nest_internal.h — multires_nest.cpp・multires_tree.cpp・multires_activity.cpp・multires_conduction.cpp・lab_box.cpp が共有する、配列の読み書きと 1 刻みの小さな道具(bicameral_multires の外からは使わない)。
2#pragma once
3
4#include <cstddef>
5#include <cstdint>
6#include <span>
7#include <vector>
8
9#include "common/multires_conduction.hlsli"
10#include "sim/multires_nest.h"
11
13
14 // multires_activity.hlsli の Tree の約束(索引で引く)
15 struct CpuTree {
16 const MultiresNest* nest = nullptr;
17
18 [[nodiscard]] multires::MrBlock Block(uint32_t slot) const { return nest->blocks[slot]; }
19
20 [[nodiscard]] uint32_t Lookup(int32_t level, int64_t originX, int64_t originY, int64_t originZ) const {
21 return LookupBlock(*nest, level, originX, originY, originZ);
22 }
23 };
24
25 // --- セル(nest.cells = [一様の値 × 枠][頁 × 512]。T-0102)---
26
27 inline reaction::RxCell& UniformAt(MultiresNest& nest, uint32_t slot) {
28 return nest.cells[slot];
29 }
30
31 inline const reaction::RxCell& UniformAt(const MultiresNest& nest, uint32_t slot) {
32 return nest.cells[slot];
33 }
34
35 inline reaction::RxCell& PageCellAt(MultiresNest& nest, uint32_t page, uint32_t index) {
36 return nest.cells[nest.blocks.size() + (size_t{page} * multires::MR_BLOCK_CELLS) + index];
37 }
38
39 // 頁を持つ枠のセル
40 inline reaction::RxCell& CellAt(MultiresNest& nest, uint32_t slot, uint32_t index) {
41 FX_ASSERT(!multires::MrIsUniform(nest.blocks[slot]));
42
43 return PageCellAt(nest, nest.blocks[slot].page, index);
44 }
45
46 // 世界の頁の空きのスタック(nest.freeBlocks の後ろ)
47 inline uint32_t& FreePageAt(MultiresNest& nest, uint32_t position) {
48 return nest.freeBlocks[size_t{nest.capacity.worldBlocks} + position];
49 }
50
51 // 空きのスタックの上から頁を 1 つ取る(呼ぶ側が空きを確かめる)
52 inline uint32_t PopPage(MultiresNest& nest) {
53 FX_ASSERT(nest.counters[multires::MR_COUNTER_FREE_PAGES] > 0);
54
55 return FreePageAt(nest, --nest.counters[multires::MR_COUNTER_FREE_PAGES]);
56 }
57
58 // 端数(枠が無ければ空)
59 inline multires::MrFraction FractionAt(const MultiresNest& nest, uint32_t fractionSlot, uint32_t index) {
60 if (fractionSlot == multires::MR_NO_FRACTION)
61 return multires::MrMakeEmptyFraction();
62
63 return nest.fractions[(size_t{fractionSlot} * multires::MR_BLOCK_CELLS) + index];
64 }
65
66 inline void SetFraction(MultiresNest& nest, uint32_t fractionSlot, uint32_t index,
67 const multires::MrFraction& fraction) {
68 nest.fractions[(size_t{fractionSlot} * multires::MR_BLOCK_CELLS) + index] = fraction;
69 }
70
71 // 刻む中で頁に広げたい(MR_PAGE_WANTED)世界のブロックに、枠の順で頁を配って一様の値で埋める。
72 // 頁が足りなければ一様に戻して数え、種にする(次の刻みにまた試す)。広げた枠を枠の順に返す(multires_nest.cpp。T-0102)
73 std::vector<uint32_t> ExpandWantedPages(MultiresNest& nest);
74
75 // 頁のセルの nest.cells の添字
76 inline size_t PageCellAddress(const MultiresNest& nest, uint32_t page, uint32_t index) {
77 return nest.blocks.size() + (size_t{page} * multires::MR_BLOCK_CELLS) + index;
78 }
79
80 // --- 1 刻み(multires_nest.cpp の StepBlocks。StepNest と StepActive が使う)---
81
83 bool changed = false; // セル(か端数)が 1 つでも変わった
84 bool expanded = false; // この刻みに一様から頁に広げた
85
86 // --- 待ちの丸め(T-0115)---
87 bool evaluated = false; // 反応を評価した(wakeTick を求め直した)
88 uint64_t wakeTick = reaction::RX_WAIT_NEVER; // 評価したセルの次に評価の要る刻みの印の最小
89 };
90
91 // 待ちの丸め(T-0115): 刻む前に、つつかれたままのブロックを「刻み tick の直前に変わった」印にし、すぐ評価する(StepNest と StepActive で同じ)
92 void ResolvePokes(MultiresNest& nest, uint64_t tick);
93
94 // 待ちの丸め(T-0115): 刻んだ結果を見出しに書く。変わった・頁に広げたブロックは busyTick = この刻みの印・次の刻みに評価、
95 // 評価して変わらなければ wakeTick = 求めた最小(StepNest と StepActive で同じ)
96 void RecordWaitResults(MultiresNest& nest, std::span<const BlockStepResult> results, uint64_t tick);
97
98 // stepped(枠ごとの 0 / 1)のブロックを 1 刻み: 一様なブロックは変わる時だけ頁に広げ(枠の順。足りなければ刻まずに種にする)、
99 // options.conduction なら熱の伝導の変化を足してから反応を進める。伝導で変化を受け取ったブロックは stepped でなくても変わる。結果は枠ごと。
100 // 伝導を小刻みに分ける時(T-0108)、wakeMark が 0 でなければ(活性)、小刻みで変わったブロックの面の隣にその印を付けて
101 // 以後の小刻みから刻む(stepped を書き足す)。0 なら(全部を刻む)起こさない
102 std::vector<BlockStepResult> StepBlocks(MultiresNest& nest, const ReactionTableView& view,
103 std::span<uint8_t> stepped, uint64_t worldSeed, uint64_t tick,
104 const MultiresStepOptions& options, uint32_t wakeMark);
105
106 // 伝導の変化をセル(と端数)に足す。端数の枠が無いブロックへの変化は整数の単位だけ(multires_nest.cpp)
107 void ApplyEnergyDelta(MultiresNest& nest, uint32_t slot, uint32_t index, reaction::RxCell& cell,
108 const multires::MrEnergyDelta& delta);
109
110 // 枠 slot の本物のブロックの面の隣(八分の一ごと。細かい側へは面をたどる)に刻む印 mark を付ける(multires_activity.cpp の
111 // 種の起こし方と同じ。忙しさの印は変えない。T-0108 の小刻みで変わったブロックに使う)
112 void WakeAround(MultiresNest& nest, uint32_t slot, uint32_t mark);
113
114 // --- 熱の伝導(multires_conduction.cpp。T-0019・T-0108)---
115
116 // 刻みの初めの論理のセルの熱(初めて読んだ時に作る)。一様なブロックは覆われていないセルが全部同じなので枠ごとに 1 つ
117 // (読むのは刻むセルと、その面の先の覆われていないセルだけ)。頁に広げても論理のセルは変わらないので使い回せる。
118 // 小刻み(T-0108)でセルが変わったブロックは Invalidate で作り直させる
120 public:
121 CellThermals(const MultiresNest& nest, const ReactionTableView& view);
122
123 [[nodiscard]] multires::MrThermal At(uint32_t slot, uint32_t index);
124 void Invalidate(uint32_t slot);
125
126 private:
129 std::vector<multires::MrThermal> m_values; // 枠ごとに [セル × 512][一様の値]
130 std::vector<uint8_t> m_known;
131 };
132
133 // 刻むブロック(stepped)のセルの面の流れを調べ、流れのある一様なブロック(自分の面か、細かい側から送られてくる面)に MR_PAGE_WANTED を付ける。
134 // 粗い側で端数が要るブロックの印(枠ごとの 0 / 1)を返す。面の係数は options の小刻みの 1 回分(T-0108)
135 std::vector<uint8_t> MarkConductionWants(MultiresNest& nest, CellThermals& thermals,
136 std::span<const uint8_t> stepped, const MultiresStepOptions& options);
137
138 // 端数が要るブロックに端数の枠を枠の順に配り(足りなければ数える)、刻むブロック(凍らせたものを除く)のセルの面の流れを
139 // 頁のセルの添字(PageCellAddress)ごとの変化 deltas に足す。凍らせたブロックとの面は流れない
140 // implicitBlocks = MarkImplicitBlocks の印(陰解法で解くブロックは流れを計算せず、それと同じレベルの面も計算しない。T-0178)
141 void ComputeConduction(MultiresNest& nest, CellThermals& thermals, std::span<const uint8_t> stepped,
142 std::span<const uint8_t> frozen, std::span<const uint8_t> wantsFraction,
143 std::span<const uint8_t> implicitBlocks, const MultiresStepOptions& options,
144 std::span<multires::MrEnergyDelta> deltas);
145
146 // 細かいレベルの熱の陰解法(T-0119。multires_implicit_conduction.cpp): 流れを計算する側が基準より細かい面を全部、陰解法の 1 刻みで解き、
147 // 変化を deltas に足す(端数の枠は ComputeConduction が配った後)。陰解法の系に入れるブロックか(陽解法はそのブロックの面を計算しない)
148 [[nodiscard]] bool InImplicitConduction(const MultiresNest& nest, uint32_t slot,
149 const MultiresStepOptions& options);
150 // この刻みに陰解法の系に入れるブロックの印(枠ごとの 0 / 1。T-0178): 入れられる(頁があり凍っていない)基準より細かいブロックを
151 // 枠の順に、系の大きさが options.implicitLimits の予算に入る所まで。入らなかったブロックはこの刻み陽解法(Q22 の案 A)
152 [[nodiscard]] std::vector<uint8_t> MarkImplicitBlocks(MultiresNest& nest, CellThermals& thermals,
153 std::span<const uint8_t> frozen,
154 const MultiresStepOptions& options);
155 [[nodiscard]] bool IsImplicitBlock(std::span<const uint8_t> implicitBlocks, uint32_t slot);
156 void AddImplicitConduction(MultiresNest& nest, CellThermals& thermals, std::span<const uint8_t> frozen,
157 std::span<const uint8_t> implicitBlocks, const MultiresStepOptions& options,
158 std::span<multires::MrEnergyDelta> deltas);
159
160 // 伝導の小刻み(T-0108)を最後の 1 回の手前まで進め、最後の小刻みの変化を返す(呼ぶ側が反応と一緒に足す。分けない時は T-0019 と同じ順)。
161 // 途中で変化を足したブロックは results の changed に、頁に広げたブロックは expanded に書く(multires_conduction.cpp)
162 std::vector<multires::MrEnergyDelta> StepConduction(MultiresNest& nest, const ReactionTableView& view,
163 std::span<uint8_t> stepped, const MultiresStepOptions& options,
164 uint32_t wakeMark, std::span<BlockStepResult> results);
165
166 // 一様で頁に広げたい(MR_PAGE_WANTED)ブロックに頁を配り、足りなかったブロック(この刻み・小刻みは凍らせる)の印を返す。
167 // 広げたブロックは results の expanded に書く(multires_nest.cpp)
168 std::vector<uint8_t> ExpandForStep(MultiresNest& nest, std::span<BlockStepResult> results);
169
170 // 木を変えたブロックをつつく: 活性の種にし、忙しさの印を「つつかれた」にする(T-0100・T-0101)
171 inline void PokeBlock(MultiresNest& nest, uint32_t slot) {
172 nest.seeds[slot] = 1;
173 nest.blocks[slot].busyTick = multires::MR_BUSY_POKED;
174 }
175
176} // namespace bicameral::sim::nest_detail
CellThermals(const MultiresNest &nest, const ReactionTableView &view)
std::vector< multires::MrThermal > m_values
multires::MrThermal At(uint32_t slot, uint32_t index)
CellThermals(const MultiresNest &nest, const ReactionTableView &view)
size_t PageCellAddress(const MultiresNest &nest, uint32_t page, uint32_t index)
void ComputeConduction(MultiresNest &nest, CellThermals &thermals, std::span< const uint8_t > stepped, std::span< const uint8_t > frozen, std::span< const uint8_t > wantsFraction, std::span< const uint8_t > implicitBlocks, const MultiresStepOptions &options, std::span< MrEnergyDelta > deltas)
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)
std::vector< uint8_t > ExpandForStep(MultiresNest &nest, std::span< BlockStepResult > results)
std::vector< uint32_t > ExpandWantedPages(MultiresNest &nest)
std::vector< uint8_t > MarkImplicitBlocks(MultiresNest &nest, CellThermals &thermals, std::span< const uint8_t > frozen, const MultiresStepOptions &options)
void RecordWaitResults(MultiresNest &nest, std::span< const BlockStepResult > results, uint64_t tick)
std::vector< uint8_t > MarkConductionWants(MultiresNest &nest, CellThermals &thermals, std::span< const uint8_t > stepped, const MultiresStepOptions &options)
reaction::RxCell & UniformAt(MultiresNest &nest, uint32_t slot)
void ApplyEnergyDelta(MultiresNest &nest, uint32_t slot, uint32_t index, RxCell &cell, const MrEnergyDelta &delta)
bool InImplicitConduction(const MultiresNest &nest, uint32_t slot, const MultiresStepOptions &options)
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)
std::vector< MrEnergyDelta > StepConduction(MultiresNest &nest, const ReactionTableView &view, std::span< uint8_t > stepped, const MultiresStepOptions &options, uint32_t wakeMark, std::span< BlockStepResult > results)
void ResolvePokes(MultiresNest &nest, uint64_t tick)
reaction::RxCell & CellAt(MultiresNest &nest, uint32_t slot, uint32_t index)
bool IsImplicitBlock(std::span< const uint8_t > implicitBlocks, uint32_t slot)
void AddImplicitConduction(MultiresNest &nest, CellThermals &thermals, std::span< const uint8_t > frozen, std::span< const uint8_t > implicitBlocks, const MultiresStepOptions &options, std::span< MrEnergyDelta > deltas)
uint32_t LookupBlock(const MultiresNest &nest, int32_t level, int64_t originX, int64_t originY, int64_t originZ)
std::vector< uint8_t > seeds
std::vector< reaction::RxCell > cells
std::vector< multires::MrBlock > blocks
std::vector< multires::MrFraction > fractions
std::vector< uint32_t > freeBlocks
std::array< uint32_t, multires::MR_COUNTER_COUNT > counters
uint32_t Lookup(int32_t level, int64_t originX, int64_t originY, int64_t originZ) const
multires::MrBlock Block(uint32_t slot) const