8void PointGraph::invalidateTopology(
const std::string& changedNode) {
9 for (
auto it = executionPlans_.begin(); it != executionPlans_.end();) {
10 const auto&
nodes = it->second->topologicalOrder;
11 if (std::find(
nodes.begin(),
nodes.end(), changedNode) ==
nodes.end()) {
15 if (executionPlan_ == it->second) executionPlan_.reset();
16 std::erase(executionPlanRecency_, it->first);
17 it = executionPlans_.erase(it);
21Result<void> PointGraph::compileExecutionPlan(
const std::string& outputId) {
22 if (
const auto found = executionPlans_.find(outputId);
found != executionPlans_.end()) {
23 executionPlan_ =
found->second;
24 std::erase(executionPlanRecency_, outputId);
25 executionPlanRecency_.push_back(outputId);
28 executionPlan_.reset();
31 std::unordered_map<std::string, int> states;
32 std::function<Result<void>(
const std::string&)> visit = [&](
const std::string&
id) -> Result<void> {
34 if (states[
id] == 1) {
38 const auto found = nodes_.find(
id);
39 if (
found == nodes_.end()) {
49 found->second.operation +
" requires input " + std::to_string(
input) +
": " +
id,
50 id, {},
"procgen.pointGraph"));
52 auto result = visit(
found->second.inputs[
input]);
53 if (!result.ok())
return result;
56 plan.topologicalOrder.push_back(
id);
59 auto visited = visit(outputId);
60 if (!visited.ok())
return visited;
62 std::unordered_map<std::string, std::vector<std::string>> consumers;
63 for (
const std::string&
id : plan.topologicalOrder) {
64 const Node&
node = nodes_.at(
id);
68 std::unordered_map<std::string, bool> assigned;
69 for (
const std::string&
id : plan.topologicalOrder) {
70 if (assigned[
id])
continue;
71 ExecutionSegment segment;
72 segment.nodes.push_back(
id);
75 while (segment.nodes.size() < 4 && nodes_.at(
cursor).operation ==
"transform" &&
76 consumers[
cursor].size() == 1) {
77 const std::string&
next = consumers[
cursor].front();
78 if (assigned[next] || nodes_.at(next).operation !=
"transform")
break;
79 segment.nodes.push_back(next);
80 assigned[
next] =
true;
83 segment.gpuTransformChain = segment.nodes.size() >= 2 && nodes_.at(
id).operation ==
"transform";
84 const std::size_t segmentIndex = plan.segments.size();
85 if (segment.gpuTransformChain) plan.segmentByOutput.emplace(segment.nodes.back(), segmentIndex);
86 plan.segments.push_back(std::move(segment));
88 executionPlan_ = std::make_shared<const ExecutionPlan>(std::move(plan));
89 executionPlans_.emplace(outputId, executionPlan_);
90 executionPlanRecency_.push_back(outputId);
91 constexpr std::size_t maximumCachedPlans = 16;
92 if (executionPlanRecency_.size() > maximumCachedPlans) {
93 executionPlans_.erase(executionPlanRecency_.front());
94 executionPlanRecency_.erase(executionPlanRecency_.begin());
96 ++executionPlanBuildCount_;
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
static Result success(T value)
Construct a successful result owning value.
static Result failure(Status status)
Construct a failed result from a structured status.
static int getOperationInputCount(const std::string &operation)
Returns the operation input count.
constexpr HexDirection next(HexDirection d) noexcept
The next direction clockwise (NW wraps to NE).