-
Notifications
You must be signed in to change notification settings - Fork 35
Improve potential for generating multiple animation frames in parallel #87
Comments
Here are the relevant IRC log discussions: |
I think we should go ahead an introduce a mode where the animator has to explicitly declare that it has Here is some example API: registerAnimator('my-statefull-effect', class {
// This ensures the engine produces frame in order.
// hasState is false by default which allows multiple frames to be produced in parallel and animator
// to be destroyed/migrated without needing to move state around worklet instances.
static hasState = true;
animate(currentTime, effects) {
const delta = currentTime - this.lastTime;
this.lastTime = currentTime;
this.acceleration += Math.random();
this.velocity += this.acceleration * delta;
effects[0].localTime = this.velocity * currentTime;
}
}); |
@asajeffrey, this is different from the speculative execution we discussed, but I'd be interested in hearing your thoughts on this proposal. |
Hmm, interesting... One possible API for stateful animators would be to provide an explicit state object, and in the API say that it might be deep cloned at any point (e.g. when context switching to a different thread). |
@asajeffrey we have been thinking about similar mechanism for stateful animator but with a callback instead. Rather than a explicit object that may be deep cloned at "any point" we have been favoring a One advantage of callback is that the animator does not have to maintain the state object all the time but only when we are migrating between contexts. I expect migrations to be infrequent in which case this can lead to a more optimal outcome. I suppose if we have an state object then its existence can also play the role of BTW, it was implied in original comment but I want to make it explicit that I think it is best to treat |
I like having an explicit state object. If the developer stores nothing in that state then we assume that since it is okay to shut down and resume their animation with no state that it should also be okay to speculatively execute on future values (until doing so results in state being used at which point we have to stop, destroy the speculative animation, and restart it at the point before it became stateful). The nice thing about this is that the developer doesn't have to think about whether their animation is stateful upfront, and could even have animations that transition between being stateful and stateless based on inputs (e.g. stateful while an object has momentum, stateless when it comes to rest). |
I wonder if we need an explicit flag or whether we can look at the shape of the passed-in animator to determine if it is stateful or stateless. e.g. looking at the length of the constructor function: // Stateful
registerAnimator('stateful', class {
constructor(options, state) {
}
animate(currentTime, effect) {
}
});
// Stateless
registerAnimator('stateless', class {
constructor(options) {
}
animate(currentTime, effect) {
}
}); e.g. differentiate between function objects and generic objects // Stateful
registerAnimator('stateful', class {
constructor(options, state) {
}
animate(currentTime, effect) {
}
});
// Stateless
registerAnimator('stateless', (currentTime, effect) => {
// ...
}); Or we could possibly even do both of the above. |
The beginning of the IRC discussion on this topic, during which IRC went down and caused state loss, was this: See the rest of the IRC log<dael> Topic: Animation Worklets<majidvp> https://github.com//issues/87 <dael> majidvp: Right now when you have an animation worklets everything you register is considered stateful. Some of the effects you don't need to have local state. If your animation doesn't need local state it's good to know. <dael> majidvp: When it's stateful you need to go in sequence. <dael> majidvp: Ask was to be able to make the distinction explicit. <dael> majidvp: Proposal from astearns was to have a state object. This is similar to layout API and caching property. <astearns> s/astearns/asajeffrey/ <astearns> (I think) <dael> majidvp: Proposal is to have a state object on the animation which the impl uses to 1) if the state object is available it means it's stateful and not a pure animation and 2) previously we had an onDestroy callback which allowed the animation to serialize. This proposal allows us to get rid of that callback. We can just serialize the state and move it when going between. <dael> smfr: Seems odd to have the state...Once you computed the state the first time you might want it to be read only <dael> flackr: If you want that you should pass that in rather then computing it. i'ts a static input. <dael> shane: Is that too restrictive? <dael> flackr: Maybe? If you had a state that didn't change regularly you could imagine allowing parallel execution until state changes. I don't know if that's a common use case. <dael> majidvp: If you have a state it means we opt you out of run in parallel. Could be possible we have a state and until it changes you're in parallel. Let's be more conservitive and if there are use cases we can relax. <dael> flackr: Only concern with relaxing is detecting the state change. You have to detect or have an API to say I changed. <dael> majidvp: Initial version was to have a state boolean which would indicate if it allows parallel execution. We can do something like that in the future with the boolean <dael> smfr: isStateful is a better description the hasState <dael> majidvp: Current proposal is if the state object exists it means it's stateful, not sue isSateful or hasState. <dael> smfr: Can you show us the API? <dael> majidvp: First argument to the consctructor. <dael> majidvp: It would make sure that if you have an actual state you set it on the state object so when you move between global context you keep your state. If we kill your instance your state sticks. <dael> majidvp: You can hold onto your state. <dael> birtles: You look at length of constructor funciton? <dael> majidvp: Every time we animate you we call the state getter. If that provides an object that's your state and it means you're stateful. Every time we destroy the global scope that state will be passed in to you <dael> majidvp: It's only when you register the animation. First time you're called it's null, as we animate you can change. <dael> birtles: If you're looking at length of constructor I understand that, but how do you know. <dael> majidvp: You're looking at spec, this is a proposal. You get the state and the options. <dael> birtles: The difference between an animator and a pure animator is clear to anyone that works in React. <dael> shane: It's an import and distinction too. <dael> shane: Maybe an flag is acceptable <dael> majidvp: One thing about taking this flag is it can change over time. YOu start as stateless and at some point you do have a state from that point on you're stable. <dael> shane: Can you clear state? <dael> majidvp: Yes. <dael> shane: This would be useful with impl a state machine. You can make a decision about what the next animation is. <dael> birtles: What if you have several frames at ones and one is stable. <dael> shane: You're stateless if it's many frames. If one frame is stateful it stops there. <dael> majidvp: The example from Jan. they run in parallel and if they see state they can't treat it the same. <dael> birtles: They're saying it's not impl-able. You're either stateful or stateless, choose one. <dael> majidvp: Personally I'm fine for it to be static. Most of the use cases weren't specifically stafefull or stateless, but it did change. <dael> flackr: Let's say we go with something static now, how may it change? <dael> shane: If you register yourself as stateful or stateless you can register yourself as auto and change. <dael> flackr: Right thing to do is statis route until we have feedback. <dael> majidvp: iStateful is the proposed name? <dael> smfr: Yeah. <dael> shane: Do we want State or Stateful? <dael> majidvp: It would be a static property on the animator class. <dael> birtles: In the current spec you ask to register a function and that will change you pass something else? <dbaron> shane: It should be enum values so it's extensible. <dael> majidvp: It's a function callback. It's a class similar to Paint. This is a class that implements callback interface. In the class there's a static property of isStateless <dael> birtles: I'm wondering if we can just look at functions <dael> majidvp: My understanding is that there is slighly different syntax for stateful and stateless. If you're stateful component it's a class. <dael> majidvp: I think in this case static attribute on the class seems usable enough <dael> shane: Makes it explicit <dael> majidvp: There's nothing like this on other spec where we can extend <dael> Rossen: What did we narrow down tp? <dael> Rossen: Do we keep going with isStateful? <dael> majidvp: I think it was have explicit attribute on the class, I don't know what hte name should be. If you want an enum stateful isn't a good name. <dael> majidvp: An enum is the right idea, I'll bikeshed the name on the issue. <dael> Rossen: WE want to have the state state on the class, name pending bikeshed. <dael> Rossen: Objections? <dael> birtles: I'd like to look at other options. I'm not 100% sure we need the attribute. <dael> shane: If we want to preserve possibility of switching we need it. <dael> birtles: I think there's more enquery to do. <dael> Rossen: Before we resolve on the big issue, we can resolve on having the state always be one by construction. Either always stateful or not. <dael> Rossen: For now we're not allowing a dynamic state. Let's resolve on that and then figure out if we need to expose it. <dael> Rossen: Objections to not having a dynamic ability on animations, they're either stateful or not. <dael> RESOLVED: not have a dynamic ability on animations, they're either stateful or not. <dael> Rossen: Do we need to expose this is the next question. <dael> majidvp: We want to give author a way to differentiate between the two. I'm in favor of exposing and letting authors say what their animation is. Mechanism I'm impartial. WE can have the bool on the class, we can have different parent classes. <dael> Rossen: Because you're basing things on the fact that people can take advantage of this performance, can you give us an example of that? <dael> majidvp: If you want to impl parallax. It doesn't have state, just translates input to state. If we say it's stateless the browser can produce more animations and avoid running JS. <dael> majidvp: It's more obvious when anmation is time based. In one animation worklet you run the thread once and get multiple frames. For stateful you can't do that because producing one frame might not be there in the next seq. You're losing some performance benefit. <dael> majidvp: Our impl doesn't run in parallel. <dael> Rossen: By construction you're impl will know if it's stateless or stable <dael> majidvp: How would you know. <dael> smfr: Pasing state in constructor. <dael> Rossen: Oh. So we resolved by construction they are stateful or stateless So you know if this is one or the other. You don't need to ask anymore. Attribute you'd need in case you change your mind, but I don't see anything dynamic. <dael> flackr: How do you construct it? <dael> Rossen: You tell me. <dael> flackr: This was a static class to say. <dael> majidvp: Other option would be construction for worklet takes in a state object that's passed into an animation instance. If it's undefined or null it's stateless. <dael> Rossen: Yeah. <dael> majidvp: We have an opbect called options. We use it to pass things the animation needs to know. It's similar. I wouldn't mind that. <dael> Rossen: That way everyone is kind of happy. birtles is happier. <dael> birtles: I was looking for other options, but yeah. I put on the issues two other things about the constructor. May be other possiblilites with switching. Connection closed unexpectedly: Server going down <surma> \o/ <dael> majidvp: You don't have to provide when you do the animation that you have 2 arguments it's stateful <TabAtkins> esprehn: Can you op rossen or astearns and de-op yourself? <RRSAgent> logging to https://www.w3.org/2018/04/09-houdini-irc You invited logbot to join #houdini <dael> majidvp: birtles proposal in the issue is nice and ergonomic. If it has 2 arguments it means second is tate <dael> majidvp: Number of arguments. <dbaron> Topic: Animation Worklets, continued <dael> iank_: You can't look at the shape of arguments. |
The rest of the discussion ended with one resolution:
See the full IRC log<dbaron> Topic: Animation Worklets, continued<dael> iank_: You can't look at the shape of arguments. <dael> Rossen: Your versioning becomes crazy. <dael> birtles: It's common in JS libraries. <dbaron> github: https://github.com//issues/87 <dael> iank_: Are you switching inside of native code here? <dael> iank_: When you call the register animation, you're looking for arguments, that doesn't work. That's not failable. <dael> birtles: Call .legth <dael> majidvp: If you call .length it gives you number of required params <dael> majidvp: If you have opional parameters, in webIDL at least. <dael> birtles: There's another option further down <dael> majidvp: I don't think second is possible. Can you differentiate between class and function? <dael> TabAtkins: No, class returns a fuction <dael> smfr: I think check is constructbale? <dael> majidvp: Any is constructable <dael> gsnedders: Not in webIDL <dael> majidvp: This is user provided. <dael> birtles: Point I was trying to make is that we don't nec need an attribute. <gsnedders> gsnedders: then it does have construct <dael> Rossen: Checking number of arguments is defined. You can check the length. <dael> shane: I think there is a more desciplined argument about having it as a param because it's clear to people making the code. <dael> birtles: I think it's quite intuitive to check the callback function <dael> Rossen: One of the versioning schemas we have in our API is based on number of parameters <dael> shane: It's a technique. But we're designing an API. It's bad design to change fundimentally different behaviors based on magic. <fremy> q+ <dael> birtles: I hear you, but I see it so much I think it's idomatic. <Rossen> a/in our API is based/in our ABI is based/ <dael> fremy: Relying on number or arguments is a problem when you need state and it's in the constructor...people use [missed] and if you don't put something in the argument it throws an error. Also if we ever need a 3rd argument in the future you're screwed. Maybe we have a default value so if you have that you don't need to do anything special. <dbaron> Topic: Animation Worklets, continued <fremy> q- <dbaron> github: https://github.com//issues/87 <dael> iank_: It works on top of the class, but if you extend something it doesn't work. <dael> majidvp: Number of arguments works in webIDL because it has syntax to say which params are optional. normal JS doesn't have that concept. When you call a function at run time you know # arguments passed through. You use that to choose one behavior or another. As an engine I think you'll have a hard time. <dael> shane: THe experiment from iank_ shows you can't do it at top level. <dael> birtles: I'm not sure we want to decide now, it's discussion to have. <dael> Rossen: One of the things...the whole discussion was do we need the attribute or not. <dael> shane: Isn't going back to the issue likely to push it to the WICG? <dael> birtles: We can take it offline. <dael> shane: F2F is when we do things in person. <dael> birtles: WEdnesday afternoon, then, during the breakout? <dael> shane: You want to think about it more. <dael> Rossen: Let's summarize. we don't want the attribute. To avoid that we can pass the info throught he param list and base the statefulness on that. That was mildly argued against since it's not clean design from internal API, though it's common for JS developers. <dael> Rossen: We can resolve on nothing and keep the param for now, or we fast forward and resolve on the parameter and then bring other ways to do this if it's hard to impl or bad behavior. <dbaron> FWIW, IRC bot issues: https://github.com/dbaron/wgmeeting-github-ircbot/issues/27 and https://github.com/dbaron/wgmeeting-github-ircbot/issues/28 <dael> Rossen: What do we want to do. Stay with static or number of param on construction <dael> smfr: Two super classes was an option. <dael> majidvp: We haven't discussed that <dael> flackr: If statefullness defaulted to stateless when not spec you get behavior that you want. <dael> majidvp: Which is a good default to have <dael> shane: There's no signal it's a sure thing. I think you're expecting a state and it doesn't appear. I think being explicit is more clear. <dael> flackr: You could throw if there is no state. <dael> shane: That would be okay....it covers knowledge. <dael> Rossen: Going back to three choices, I liked the 3rd, have the stateful and stateless classes. It makes it one or the other and satisfies the pushback against the attribute. <dael> Rossen: Going forward if we discuss again and have something better we can re-discuss. But let's not lose the opportunity to resolve <dael> majidvp: The super class if you want to allow dynamic it doesn't allow for that <dael> shane: Not just a third class? <dael> majidvp: Okay....you're using a heavy hammer for something that could be an attribute. Attributes are very common. <dael> shane: If thre's a state object and you're in stateless version it's there. If you do have the hybrid later you can have explicit functions for switching. <dael> Rossen: You can always have a conversion function based on object data <dael> majidvp: Okay...that's not bad. I buy having the state object as a super class and then have setters. <dael> Rossen: Other opinions? <dael> Rossen: Objections to introducing 2 classes as a mean to listing stateful and stateless types? <dael> RESOLVED: introduce 2 classes as a mean to listing stateful and stateless types |
This issue was moved to w3c/css-houdini-drafts#812 |
(Note: Issue was created based on feedback from Houdini Paris F2F - irc logs)
There is interest in improving opportunities for user-agent to generate more animation frames in
parallel. Current API only allows running individual animators in parallel but there are still
potential to do more. For example it is useful to generate multiple frames for the same
animations in parallel an/or ahead of time.
Pure Effects
If an animation is pure (i.e., has no internal state), then it is possible to
generate multiple frames for it in parallel by passing new input and recording the output.
Here are few improvements to the API that leverage this:
Introduce a mode (maybe this should be the default) where animator is assumed to be pure. We can enforce this via the same mechanisms that is used for paint worklet e.g., random assignments to global scope and dropping the animator object. (Strawman API: https://gist.github.com/anonymous/e22250dbdfa92da59508a220b8087d9d)
Enable even more effects to be written in this mode. For example if we expose scroll velocity and acceleration then a lots of existing effects don't need to have to keep state to compute it.
Additional idea - Speculative execution
Browsers can also speculatively run an animator in parallel as if it is pure and then fallback to normal operation if they detect a conflict.
The text was updated successfully, but these errors were encountered: