@@ -10,6 +10,64 @@ import HAL;
1010using namespace HAL ;
1111
1212
13+ // Precompiled-graph structs, defined early so PipelineBase can expose them.
14+ // They only depend on ResourceID / PassID from the includes above.
15+ export namespace FrameGraph
16+ {
17+ // A pass's static declaration of one resource it touches, from the SIG
18+ // PassNode block: the resource id plus whether the pass declares [Write] on
19+ // it. Emitted per-pass as Context::resource_accesses[].
20+ struct ResourceAccess
21+ {
22+ ResourceID id;
23+ bool write;
24+ };
25+
26+ // A reference to a pass in precompiled state data: the pass type plus, for
27+ // [Multiple] passes, which instance (0 otherwise).
28+ struct PassRef
29+ {
30+ PassID id;
31+ uint32_t index;
32+ };
33+
34+ // One precomputed RW-state in a pipeline's per-resource timeline (mirrors a
35+ // runtime ResourceRWState): whether it's a write, and the passes in it.
36+ struct PrecompiledState
37+ {
38+ bool write;
39+ std::span<const PassRef> passes;
40+ };
41+
42+ // A pipeline's precomputed timeline for one resource version: the ordered
43+ // states it passes through. Emitted per-pipeline as resource_infos[]. A
44+ // recreate() produces a new chain version of the same id — chain_index
45+ // selects which ResourceAllocInfo in the resource's chain this timeline maps
46+ // to (0 = the original create). This is a template — at runtime disabled
47+ // passes are pruned and cross-pipeline timelines concatenated in add order.
48+ struct PrecompiledResourceInfo
49+ {
50+ ResourceID id;
51+ uint32_t chain_index;
52+ std::span<const PrecompiledState> states;
53+ };
54+
55+ // A precomputed pass instance in a pipeline: its type, [Multiple] instance,
56+ // queue (compute vs direct/graphics), and its prev-pass dependency edges —
57+ // derived at codegen time from the per-resource state timelines (the static
58+ // equivalent of resolve_dependencies). Emitted per-pipeline as
59+ // precompiled_passes[]. Also a template: disabled passes are pruned at
60+ // runtime and cross-pipeline edges resolved at add time.
61+ struct PrecompiledPass
62+ {
63+ PassID id;
64+ uint32_t index; // [Multiple] instance (0 otherwise)
65+ bool compute; // queue: compute if true, else direct/graphics
66+ std::span<const PassRef> prev_passes;
67+ };
68+ }
69+
70+
1371namespace Pipelines
1472{
1573
@@ -19,6 +77,10 @@ public:
1977 virtual ~PipelineBase () = default ;
2078 virtual std::span<const wchar_t * const > GetUsedPassNamesList () const = 0;
2179 virtual std::span<const wchar_t * const > GetUsedResourcesList () const = 0;
80+
81+ // Precomputed per-resource RW-state timelines and per-pass dependency data.
82+ virtual std::span<const FrameGraph::PrecompiledResourceInfo> GetResourceInfos () const = 0;
83+ virtual std::span<const FrameGraph::PrecompiledPass> GetPrecompiledPasses () const = 0;
2284};
2385
2486}
@@ -62,55 +124,6 @@ public:
62124
63125 constexpr ResourceFlags WRITEABLE_FLAGS =ResourceFlags::CopyDest | ResourceFlags::UnorderedAccess | ResourceFlags::RenderTarget | ResourceFlags::DepthStencil;// | ResourceFlags::GenCPU;
64126
65- // A pass's static declaration of one resource it touches, from the SIG
66- // PassNode block: the resource id plus whether the pass declares [Write] on
67- // it. Emitted per-pass as Context::resource_accesses[].
68- struct ResourceAccess
69- {
70- ResourceID id;
71- bool write;
72- };
73-
74- // A reference to a pass in precompiled state data: the pass type plus, for
75- // [Multiple] passes, which instance (0 otherwise).
76- struct PassRef
77- {
78- PassID id;
79- uint32_t index;
80- };
81-
82- // One precomputed RW-state in a pipeline's per-resource timeline (mirrors a
83- // runtime ResourceRWState): whether it's a write, and the passes in it.
84- struct PrecompiledState
85- {
86- bool write;
87- std::span<const PassRef> passes;
88- };
89-
90- // A pipeline's precomputed timeline for one resource: the ordered states it
91- // passes through. Emitted per-pipeline as resource_infos[]. This is a
92- // template — at runtime disabled passes are pruned and cross-pipeline
93- // timelines concatenated in pipeline-add order.
94- struct PrecompiledResourceInfo
95- {
96- ResourceID id;
97- std::span<const PrecompiledState> states;
98- };
99-
100- // A precomputed pass instance in a pipeline: its type, [Multiple] instance,
101- // queue (compute vs direct/graphics), and its prev-pass dependency edges —
102- // derived at codegen time from the per-resource state timelines (the static
103- // equivalent of resolve_dependencies). Emitted per-pipeline as
104- // precompiled_passes[]. Also a template: disabled passes are pruned at
105- // runtime and cross-pipeline edges resolved at add time.
106- struct PrecompiledPass
107- {
108- PassID id;
109- uint32_t index; // [Multiple] instance (0 otherwise)
110- bool compute; // queue: compute if true, else direct/graphics
111- std::span<const PassRef> prev_passes;
112- };
113-
114127 // struct BufferDesc
115128 // {
116129 // size_t size;
@@ -205,16 +218,70 @@ public:
205218 // happen single-threaded after the setup/append phase joins.
206219 concurrent_vector<Pass*> passes;
207220
208- concurrent_vector<Pass*> compute;
209- concurrent_vector<Pass*> graphics;
210-
211-
212221 HAL ::SubResourcesGPU merged_read_state;
213222
214223 SyncState from;
215224 SyncState to;
216225 };
217226
227+ // A resource version's RW-state timeline. Cursor-based like ResourceChain:
228+ // the state slots — and each slot's passes / merged_read_state buffers —
229+ // persist across frames. reset_frame() only rewinds the cursor and push()
230+ // reuses a slot (clearing passes keeps its storage, so reserve() is a no-op
231+ // once it's large enough), so we don't reallocate the per-state vectors
232+ // every frame. Exposes a vector-like read interface for the many consumers.
233+ struct StateTimeline
234+ {
235+ std::vector<ResourceRWState> items;
236+ size_t count = 0 ;
237+
238+ void reset_frame () { count = 0 ; }
239+
240+ bool empty () const { return count == 0 ; }
241+ size_t size () const { return count; }
242+
243+ ResourceRWState& operator [](size_t i) { return items[i]; }
244+ const ResourceRWState& operator [](size_t i) const { return items[i]; }
245+ ResourceRWState& front () { return items[0 ]; }
246+ const ResourceRWState& front () const { return items[0 ]; }
247+ ResourceRWState& back () { return items[count - 1 ]; }
248+ const ResourceRWState& back () const { return items[count - 1 ]; }
249+
250+ ResourceRWState* begin () { return items.data (); }
251+ ResourceRWState* end () { return items.data () + count; }
252+ const ResourceRWState* begin () const { return items.data (); }
253+ const ResourceRWState* end () const { return items.data () + count; }
254+
255+ // Append a new state, reusing a persisted slot's storage when available.
256+ ResourceRWState& push (bool write, size_t reserve_n)
257+ {
258+ if (count >= items.size ())
259+ items.emplace_back ();
260+ ResourceRWState& s = items[count++];
261+ s.write = write;
262+ s.passes .clear (); // keeps the concurrent_vector's storage
263+ s.passes .reserve (reserve_n); // no-op once large enough
264+ s.from .reset ();
265+ s.to .reset ();
266+ s.merged_read_state .subres .clear ();
267+ return s;
268+ }
269+
270+ // Stable removal that keeps removed slots' storage in items for reuse.
271+ template <class Pred >
272+ void remove_if (Pred pred)
273+ {
274+ size_t w = 0 ;
275+ for (size_t r = 0 ; r < count; ++r)
276+ if (!pred (items[r]))
277+ {
278+ if (w != r) std::swap (items[w], items[r]);
279+ ++w;
280+ }
281+ count = w;
282+ }
283+ };
284+
218285 struct ResourceAllocInfo
219286 {
220287 ResourceID id = ResourceID::Count;
@@ -242,8 +309,7 @@ public:
242309
243310 bool is_new = false ;
244311 bool resource_just_created = true ;
245- std::vector<ResourceRWState> states;
246- int last_writer;
312+ StateTimeline states;
247313 size_t max_passes = 0 ; // upper bound on passes per state, known from Pass::id assignment
248314 // compile
249315
@@ -279,7 +345,6 @@ public:
279345
280346
281347 void add_pass (Pass* pass, ResourceFlags flags);
282- void resolve_dependencies (std::vector<std::pair<Pass*, Pass*>>& edges);
283348 void reset (size_t max_passes);
284349
285350 void remove_inactive ();
@@ -518,6 +583,12 @@ public:
518583 ResourceAllocInfo& active () { return items[pos]; }
519584 const ResourceAllocInfo& active () const { return items[pos]; }
520585
586+ // Number of chain versions active this frame (0 if not created), and
587+ // direct access to a specific version. Used to map a precomputed
588+ // resource timeline's chain_index to its ResourceAllocInfo.
589+ size_t active_count () const { return created_this_frame ? pos + 1 : 0 ; }
590+ ResourceAllocInfo& at (size_t i) { return items[i]; }
591+
521592 auto active_span ()
522593 {
523594 size_t n = std::min (pos + 1 , items.size ());
@@ -568,6 +639,12 @@ public:
568639 // iterate only what matters instead of rescanning all of alloc_resources.
569640 std::vector<ResourceAllocInfo*> enabled_resources;
570641
642+ // Builds each resource's RW-state timeline after all setups have run —
643+ // from the added pipelines' precomputed resource_infos (recreate chains
644+ // fall back to add_pass). Setup itself only records resource desc/flags
645+ // and what each pass touched (used.resources / used.resource_flags).
646+ void build_resource_states ();
647+
571648 // Persistent pass cache, indexed by PassID (+ index for [Multiple] passes),
572649 // so library passes are reused frame to frame instead of reallocated. Only
573650 // covers add_library_pass — the raw add_pass<T>(name, ...) path has no PassID
@@ -745,9 +822,6 @@ public:
745822 SyncState sync_state_with_self;
746823
747824
748- std::unordered_set<Pass*> prev_passes;
749-
750- std::unordered_set<Pass*> next_passes;
751825 std::future<void > render_task;
752826 std::future<void > compile_task;
753827
@@ -972,6 +1046,10 @@ public:
9721046 void set_pipeline (Pipelines::PipelineBase* p);
9731047 Pipelines::PipelineBase* get_pipeline () const ;
9741048
1049+ // All pipelines added this frame, in add order (for concatenating their
1050+ // precomputed per-resource timelines). Cleared in reset().
1051+ std::vector<Pipelines::PipelineBase*> added_pipelines;
1052+
9751053 private:
9761054 Pipelines::PipelineBase* current_pipeline = nullptr ;
9771055 public:
0 commit comments