Skip to content
Flecs v4.1
pipeline.h
Go to the documentation of this file.
1/**
2 * @file addons/pipeline.h
3 * @brief Pipeline module.
4 *
5 * The pipeline module provides support for running systems automatically and
6 * on multiple threads. A pipeline is a collection of tags that can be added to
7 * systems. When run, a pipeline will query for all systems that have the tags
8 * that belong to a pipeline, and run them.
9 *
10 * The module defines a number of built-in tags (EcsPreUpdate, EcsOnUpdate,
11 * EcsPostUpdate, etc.) that are registered with the built-in pipeline. The
12 * built-in pipeline is run by default when calling ecs_progress(). An
13 * application can set a custom pipeline with the ecs_set_pipeline() function.
14 */
15
16#ifdef FLECS_PIPELINE
17
18/**
19 * @defgroup c_addons_pipeline Pipeline
20 * @ingroup c_addons
21 * Pipelines order and schedule systems for execution.
22 *
23 * @{
24 */
25
26#ifndef FLECS_MODULE
27#define FLECS_MODULE
28#endif
29
30#ifndef FLECS_SYSTEM
31#define FLECS_SYSTEM
32#endif
33
34#if !defined(FLECS_OS_API_IMPL) && !defined(FLECS_NO_OS_API_IMPL)
35#define FLECS_OS_API_IMPL
36#endif
37
38#ifndef FLECS_PIPELINE_H
39#define FLECS_PIPELINE_H
40
41#ifdef __cplusplus
42extern "C" {
43#endif
44
45#ifndef FLECS_LEGACY
46
47/** Convenience macro to create a forward-declared pipeline.
48 * Usage:
49 * @code
50 * ECS_DECLARE(MyPipeline);
51 * ECS_PIPELINE_DEFINE(world, MyPipeline, Update || Physics || Render)
52 * @endcode
53 */
54#define ECS_PIPELINE_DEFINE(world, id_, ...) \
55 { \
56 ecs_pipeline_desc_t desc = {0}; \
57 ecs_entity_desc_t edesc = {0}; \
58 edesc.id = id_;\
59 edesc.name = #id_;\
60 desc.entity = ecs_entity_init(world, &edesc);\
61 desc.query.expr = #__VA_ARGS__; \
62 id_ = ecs_pipeline_init(world, &desc); \
63 ecs_id(id_) = id_;\
64 } \
65 ecs_assert(id_ != 0, ECS_INVALID_PARAMETER, "failed to create pipeline");
66
67/** Convenience macro to create a pipeline.
68 * Usage:
69 * @code
70 * ECS_PIPELINE(world, MyPipeline, Update || Physics || Render)
71 * @endcode
72 *
73 */
74#define ECS_PIPELINE(world, id, ...) \
75 ecs_entity_t id = 0, ecs_id(id) = 0; ECS_PIPELINE_DEFINE(world, id, __VA_ARGS__);\
76 (void)id;\
77 (void)ecs_id(id);
78
79/** Convenience macro to create a pipeline.
80 * See ecs_pipeline_init().
81 */
82#define ecs_pipeline(world, ...)\
83 ecs_pipeline_init(world, &(ecs_pipeline_desc_t) __VA_ARGS__ )
84
85#endif
86
87/** Pipeline descriptor, used with ecs_pipeline_init(). */
88typedef struct ecs_pipeline_desc_t {
89 /** Existing entity to associate with the pipeline (optional). */
91
92 /** The pipeline query.
93 * Pipelines are queries that are matched with system entities. Pipeline
94 * queries are the same as regular queries, which means the same query rules
95 * apply. A common mistake is to try a pipeline that matches systems in a
96 * list of phases by specifying all the phases, like:
97 * OnUpdate, OnPhysics, OnRender
98 *
99 * That however creates a query that matches entities with OnUpdate _and_
100 * OnPhysics _and_ OnRender tags, which is likely undesired. Instead, a
101 * query could use the or operator to match a system that has one of the
102 * specified phases:
103 * OnUpdate || OnPhysics || OnRender
104 *
105 * This will return the correct set of systems, but they likely won't be in
106 * the correct order. To make sure systems are returned in the correct order,
107 * two query ordering features can be used:
108 * - group_by
109 * - order_by
110 *
111 * Take a look at the system manual for a more detailed explanation of
112 * how query features can be applied to pipelines, and how the built-in
113 * pipeline query works.
114 */
117
118/** Create a custom pipeline.
119 * If the descriptor specifies an existing entity, the entity must not already
120 * be associated with a pipeline. To replace an existing pipeline on an
121 * entity, use ecs_pipeline_update().
122 *
123 * @param world The world.
124 * @param desc The pipeline descriptor.
125 * @return The pipeline, 0 if failed.
126 */
127FLECS_API
129 ecs_world_t *world,
130 const ecs_pipeline_desc_t *desc);
131
132/** Replace the pipeline query on an existing entity.
133 * Removes the pipeline currently attached to the entity and creates a new one
134 * from the descriptor.
135 *
136 * @param world The world.
137 * @param pipeline The pipeline entity to update.
138 * @param desc The pipeline descriptor.
139 * @return The pipeline entity, or 0 if the operation failed.
140 */
141FLECS_API
143 ecs_world_t *world,
144 ecs_entity_t pipeline,
145 const ecs_pipeline_desc_t *desc);
146
147/** Set a custom pipeline.
148 * This operation sets the pipeline to run when ecs_progress() is invoked.
149 *
150 * @param world The world.
151 * @param pipeline The pipeline to set.
152 */
153FLECS_API
155 ecs_world_t *world,
156 ecs_entity_t pipeline);
157
158/** Get the current pipeline.
159 * This operation gets the current pipeline.
160 *
161 * @param world The world.
162 * @return The current pipeline.
163 */
164FLECS_API
166 const ecs_world_t *world);
167
168/** Progress a world.
169 * This operation progresses the world by running all systems that are both
170 * enabled and periodic on their matching entities.
171 *
172 * An application can pass a delta_time into the function, which is the time
173 * passed since the last frame. This value is passed to systems so they can
174 * update entity values proportional to the elapsed time since their last
175 * invocation.
176 *
177 * When an application passes 0 to delta_time, ecs_progress() will automatically
178 * measure the time passed since the last frame. If an application does not use
179 * time management, it should pass a non-zero value for delta_time (1.0 is
180 * recommended). That way, no time will be wasted measuring the time.
181 *
182 * @param world The world to progress.
183 * @param delta_time The time passed since the last frame.
184 * @return false if ecs_quit() has been called, true otherwise.
185 */
186FLECS_API
188 ecs_world_t *world,
189 ecs_ftime_t delta_time);
190
191/** Run pipeline.
192 * This will run all systems in the provided pipeline. This operation may be
193 * invoked from multiple threads, and only when staging is disabled, as the
194 * pipeline manages staging and, if necessary, synchronization between threads.
195 *
196 * If 0 is provided for the pipeline ID, the default pipeline will be run (this
197 * is either the built-in pipeline or the pipeline set with ecs_set_pipeline()).
198 *
199 * When using ecs_progress(), this operation will be invoked automatically for
200 * the default pipeline (either the built-in pipeline or the pipeline set with
201 * ecs_set_pipeline()). An application may run additional pipelines.
202 *
203 * @param world The world.
204 * @param pipeline The pipeline to run.
205 * @param delta_time The delta_time to pass to systems.
206 */
207FLECS_API
209 ecs_world_t *world,
210 ecs_entity_t pipeline,
211 ecs_ftime_t delta_time);
212
213
214////////////////////////////////////////////////////////////////////////////////
215//// Threading
216////////////////////////////////////////////////////////////////////////////////
217
218/** Set number of worker threads.
219 * Setting this value to a value higher than 1 will start that many threads and
220 * will cause systems to evenly distribute matched entities across threads. The
221 * operation may be called multiple times to reconfigure the number of threads
222 * used, but never while running a system or pipeline.
223 * Calling ecs_set_threads() will also end the use of task threads set up with
224 * ecs_set_task_threads() and vice-versa.
225 *
226 * @param world The world.
227 * @param threads The number of threads to create.
228 */
229FLECS_API
231 ecs_world_t *world,
232 int32_t threads);
233
234/** Set number of worker task threads.
235 * ecs_set_task_threads() is similar to ecs_set_threads(), except threads are treated
236 * as short-lived tasks and will be created and joined around each update of the world.
237 * Creation and joining of these tasks will use the os_api_t task APIs rather than
238 * the standard thread API functions, although they may be the same if desired.
239 * This function is useful for multithreading world updates using an external
240 * asynchronous job system rather than long-running threads by providing the APIs
241 * to create tasks for your job system and then wait on their conclusion.
242 * The operation may be called multiple times to reconfigure the number of task threads
243 * used, but never while running a system or pipeline.
244 * Calling ecs_set_task_threads() will also end the use of threads set up with
245 * ecs_set_threads() and vice-versa.
246 *
247 * @param world The world.
248 * @param task_threads The number of task threads to create.
249 */
250FLECS_API
252 ecs_world_t *world,
253 int32_t task_threads);
254
255/** Return true if task thread use has been requested.
256 *
257 * @param world The world.
258 * @return Whether the world is using task threads.
259 */
260FLECS_API
262 ecs_world_t *world);
263
264////////////////////////////////////////////////////////////////////////////////
265//// Module
266////////////////////////////////////////////////////////////////////////////////
267
268/** Pipeline module import function.
269 * Usage:
270 * @code
271 * ECS_IMPORT(world, FlecsPipeline)
272 * @endcode
273 *
274 * @param world The world.
275 */
276FLECS_API
278 ecs_world_t *world);
279
280#ifdef __cplusplus
281}
282#endif
283
284#endif
285
286/** @} */
287
288#endif
FLECS_API void ecs_set_threads(ecs_world_t *world, int32_t threads)
Set number of worker threads.
FLECS_API void ecs_set_pipeline(ecs_world_t *world, ecs_entity_t pipeline)
Set a custom pipeline.
FLECS_API ecs_entity_t ecs_get_pipeline(const ecs_world_t *world)
Get the current pipeline.
FLECS_API bool ecs_progress(ecs_world_t *world, ecs_ftime_t delta_time)
Progress a world.
FLECS_API void ecs_run_pipeline(ecs_world_t *world, ecs_entity_t pipeline, ecs_ftime_t delta_time)
Run pipeline.
FLECS_API ecs_entity_t ecs_pipeline_update(ecs_world_t *world, ecs_entity_t pipeline, const ecs_pipeline_desc_t *desc)
Replace the pipeline query on an existing entity.
FLECS_API bool ecs_using_task_threads(ecs_world_t *world)
Return true if task thread use has been requested.
FLECS_API void ecs_set_task_threads(ecs_world_t *world, int32_t task_threads)
Set number of worker task threads.
FLECS_API void FlecsPipelineImport(ecs_world_t *world)
Pipeline module import function.
FLECS_API ecs_entity_t ecs_pipeline_init(ecs_world_t *world, const ecs_pipeline_desc_t *desc)
Create a custom pipeline.
ecs_id_t ecs_entity_t
An entity identifier.
Definition flecs.h:395
struct ecs_world_t ecs_world_t
A world is the container for all ECS data and supporting features.
Definition flecs.h:439
#define ecs_ftime_t
Customizable precision for scalar time values.
Definition flecs.h:59
Pipeline descriptor, used with ecs_pipeline_init().
Definition pipeline.h:88
ecs_entity_t entity
Existing entity to associate with the pipeline (optional).
Definition pipeline.h:90
ecs_query_desc_t query
The pipeline query.
Definition pipeline.h:115
Used with ecs_query_init().
Definition flecs.h:1325