diff --git a/en/Building_a_Simple_Engine/Engine_Architecture/05_rendering_pipeline.adoc b/en/Building_a_Simple_Engine/Engine_Architecture/05_rendering_pipeline.adoc index b9a07d37..bf342079 100644 --- a/en/Building_a_Simple_Engine/Engine_Architecture/05_rendering_pipeline.adoc +++ b/en/Building_a_Simple_Engine/Engine_Architecture/05_rendering_pipeline.adoc @@ -234,8 +234,20 @@ Now we implement the core algorithmic logic that analyzes pass dependencies and // Track which pass produces each resource (write-after-write dependencies) std::unordered_map resourceWriters; + // Resource Production Registration + // Register every pass's outputs *before* looking at any inputs, in its own pass over + // `passes`. Producers and consumers can appear in any order in the `passes` vector - + // a pass added later might produce a resource a pass added earlier consumes - so + // dependency discovery below must not assume producers come first positionally. + for (size_t i = 0; i < passes.size(); ++i) { + for (const auto& output : passes[i].outputs) { + resourceWriters[output] = i; // Record this pass as producer + } + } + // Dependency Discovery Through Resource Usage Analysis - // Analyze each pass to determine data flow relationships + // Now that every producer is known, analyze each pass's inputs to determine data flow + // relationships, regardless of where the producer sits in the passes vector. for (size_t i = 0; i < passes.size(); ++i) { const auto& pass = passes[i]; @@ -248,11 +260,6 @@ Now we implement the core algorithmic logic that analyzes pass dependencies and dependents[it->second].push_back(i); // Producer has this as dependent } } - - // Register output production - subsequent passes may depend on these - for (const auto& output : pass.outputs) { - resourceWriters[output] = i; // Record this pass as producer - } } // Topological Sort for Optimal Execution Order @@ -272,9 +279,10 @@ Now we implement the core algorithmic logic that analyzes pass dependencies and inStack[node] = true; // Mark as currently being processed - // Recursively process all dependent passes first (post-order traversal) - for (auto dependent : dependents[node]) { - visit(dependent); + // Recursively process all passes this one depends on first (post-order traversal), + // so a producer is always pushed onto executionOrder before its consumers. + for (auto dependency : dependencies[node]) { + visit(dependency); } inStack[node] = false; // Remove from current path