Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile-time Schedule creation #138

Closed
Anders429 opened this issue Nov 10, 2022 · 3 comments
Closed

Compile-time Schedule creation #138

Anders429 opened this issue Nov 10, 2022 · 3 comments
Labels
A - Scheduling Area: Parallel scheduling of systems. C - Enhancement Category: New feature or request. F - rayon Feature: Parallel processing through the rayon library. P - Low Priority: Not particularly urgent. S - Needs Investigation Status: Further investigation is needed.

Comments

@Anders429
Copy link
Owner

This definitely needs investigation, but I think it might be possible.

Currently, Schedules are created at runtime using a schedule::Builder. This is how every other ECS that I've seen in Rust does it. It isn't really that much of an issue in practice, since the common practice is to build a Schedule once at the start of the program and then use it over and over again on every frame, but it does leave room for some inefficiency if, say, a user accidentally dropped and rebuilt the Schedule on every single frame.

The creation of a Schedule is deterministic. The Builder will always create stage breaks at the same places, and those stage breaks are easily seen by examining the Views of each System and ParSystem task.

With that in mind, it should be doable to generate the Schedule at compile time. The idea goes something like this:

  • Take as input a heterogeneous list of tasks. Tasks are defined as they are currently: an enum containing either a System or ParSystem, along with other commands like EndStage (equivalent to the Flush command currently in existence). The heterogeneous list could be constructed directly by a macro (see below).
  • This heterogeneous list of tasks can have an associated type, called Stages.
  • This is where some magic has to happen. The stages can be created automatically, depending on the current task's views and the previous task's views. If the current views are incompatible with the previous views in the stage, then a new stage is formed and the current task is put into there instead.
    • Note that this will involve some tricky type-level work. I'm not sure exactly how claims can be checked (or if it even is possible without type inequality, in which case this whole thing is bust).
  • Stages will be defined as a heterogeneous list of heterogeneous lists. Note that the order of tasks, as well as the order of stages, does matter down the line. However, there are ways to reverse heterogeneous lists fairly easily.
  • When EndStage tasks are encountered, the stage will need to be cut off automatically.

The ugly heterogeneous list and associated type calls can be hidden behind a nice pretty schedule! macro, which looks externally the same as the other heterogeneous list macros in the public API. It will basically desugar to (Task, (Task, (..., Null)))::Stages.

More investigation needs to be done to determine whether this is actually even possible.

@Anders429 Anders429 added C - Enhancement Category: New feature or request. S - Needs Investigation Status: Further investigation is needed. P - Low Priority: Not particularly urgent. F - rayon Feature: Parallel processing through the rayon library. A - Scheduling Area: Parallel scheduling of systems. labels Nov 10, 2022
@Anders429
Copy link
Owner Author

Claim checking may be able to be accomplished by Geting a type from one list in the other. Get can be implemented like this (which might already exist in the code base somewhere, hard to know for sure after all of the hlist madness that went down in #98 lol). I think unification of previous views in a stage can be done similarly, using associated types and either adding a view onto the list if it doesn't exist or just leaving it be if it already does exist (immutably, of course).

So the implementation could be something like: for each view in the current claims, check to see if the view exists in the new views. If it does, compare the claims like we currently do at run-time, setting a different associated type for each case. Then, create a new claims by unifying the new views into the previous claims, and go forward from there.

@Anders429
Copy link
Owner Author

Turns out the playground example I provided the other day doesn't actually work. The index can't be implied because it is actually ambiguous: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=b418da0d48426cce1e3778c1d7a73a9d

Not sure what to do at this point. I'm not sure there is actually a way to implement such a trait without being able to express type inequality somehow. There was some discussion about this in a frunk issue (lloydmeta/frunk#197) where they seemed to come to the same conclusion. This may not be possible until something like specialization is stable.

@Anders429
Copy link
Owner Author

This does seem to be possible, but it requires a Registry type R. The basic idea is to create an "inverse view" for each previous view by removing each viewed component from the registry. This can then be used to allow each new view to be consumed and evaluated properly. So there is no need for specialization, no need for negative impls, nothing.

I've got the type part of this done. I still need to do the reifying part, which I think should be straightforward. The main limitation here is that a registry will be required for reifying, just because the inverse list must be able to be created.

I will also define a macro for creating the schedule. This can be a nice and simple macro for creating a heterogeneous list, which is so satisfying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A - Scheduling Area: Parallel scheduling of systems. C - Enhancement Category: New feature or request. F - rayon Feature: Parallel processing through the rayon library. P - Low Priority: Not particularly urgent. S - Needs Investigation Status: Further investigation is needed.
Projects
None yet
Development

No branches or pull requests

1 participant