-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
Optimize vsync #2451
Optimize vsync #2451
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -756,7 +756,7 @@ export class Resources { | |
(newScrollHeight - state./*OK*/scrollHeight)); | ||
} | ||
}, | ||
}); | ||
}, {}); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,18 +69,40 @@ export class Vsync { | |
*/ | ||
this.tasks_ = []; | ||
|
||
/** | ||
* Double buffer for tasks. | ||
* @private {!Array<!VsyncTaskSpecDef>} | ||
*/ | ||
this.nextTasks_ = []; | ||
|
||
/** | ||
* States for tasks in the next frame in the same order. | ||
* @private {!Array<!VsyncStateDef>} | ||
*/ | ||
this.states_ = []; | ||
|
||
/** | ||
* Double buffer for states. | ||
* @private {!Array<!VsyncStateDef>} | ||
*/ | ||
this.nextStates_ = []; | ||
|
||
/** | ||
* Whether a new animation frame has been scheduled. | ||
* @private {boolean} | ||
*/ | ||
this.scheduled_ = false; | ||
|
||
/** | ||
* @private {?Promise} | ||
*/ | ||
this.nextFramePromise_ = null; | ||
|
||
/** | ||
* @private {?function()} | ||
*/ | ||
this.nextFrameResolver_ = null; | ||
|
||
/** @const {!Function} */ | ||
this.boundRunScheduledTasks_ = this.runScheduledTasks_.bind(this); | ||
|
||
|
@@ -103,11 +125,11 @@ export class Vsync { | |
* will be undefined. | ||
* | ||
* @param {!VsyncTaskSpecDef} task | ||
* @param {!VsyncStateDef=} opt_state | ||
* @param {VsyncStateDef=} opt_state | ||
*/ | ||
run(task, opt_state) { | ||
this.tasks_.push(task); | ||
this.states_.push(opt_state || {}); | ||
this.states_.push(opt_state); | ||
this.schedule_(); | ||
} | ||
|
||
|
@@ -123,16 +145,12 @@ export class Vsync { | |
* @return {!Promise} | ||
*/ | ||
runPromise(task, opt_state) { | ||
return new Promise(resolve => { | ||
this.run({ | ||
measure: state => { | ||
task.measure(state); | ||
}, | ||
mutate: state => { | ||
task.mutate(state); | ||
resolve(); | ||
}, | ||
}, opt_state); | ||
this.run(task, opt_state); | ||
if (this.nextFramePromise_) { | ||
return this.nextFramePromise_; | ||
} | ||
return this.nextFramePromise_ = new Promise(resolve => { | ||
this.nextFrameResolver_ = resolve; | ||
}); | ||
} | ||
|
||
|
@@ -152,7 +170,10 @@ export class Vsync { | |
* @param {function()} mutator | ||
*/ | ||
mutate(mutator) { | ||
this.run({mutate: mutator}); | ||
this.run({ | ||
measure: undefined, // For uniform hidden class. | ||
mutate: mutator, | ||
}); | ||
} | ||
|
||
/** | ||
|
@@ -161,11 +182,9 @@ export class Vsync { | |
* @return {!Promise} | ||
*/ | ||
mutatePromise(mutator) { | ||
return new Promise(resolve => { | ||
this.mutate(() => { | ||
mutator(); | ||
resolve(); | ||
}); | ||
return this.runPromise({ | ||
measure: undefined, | ||
mutate: mutator, | ||
}); | ||
} | ||
|
||
|
@@ -174,7 +193,10 @@ export class Vsync { | |
* @param {function()} measurer | ||
*/ | ||
measure(measurer) { | ||
this.run({measure: measurer}); | ||
this.run({ | ||
measure: measurer, | ||
mutate: undefined, // For uniform hidden class. | ||
}); | ||
} | ||
|
||
/** | ||
|
@@ -294,11 +316,14 @@ export class Vsync { | |
*/ | ||
runScheduledTasks_() { | ||
this.scheduled_ = false; | ||
// TODO(malteubl) Avoid array allocation with a double buffer. | ||
const tasks = this.tasks_; | ||
const states = this.states_; | ||
this.tasks_ = []; | ||
this.states_ = []; | ||
const resolver = this.nextFrameResolver_; | ||
this.nextFrameResolver_ = null; | ||
this.nextFramePromise_ = null; | ||
// Double buffering | ||
this.tasks_ = this.nextTasks_; | ||
this.states_ = this.nextStates_; | ||
for (let i = 0; i < tasks.length; i++) { | ||
if (tasks[i].measure) { | ||
tasks[i].measure(states[i]); | ||
|
@@ -309,6 +334,14 @@ export class Vsync { | |
tasks[i].mutate(states[i]); | ||
} | ||
} | ||
// Swap last arrays into double buffer. | ||
this.nextTasks_ = tasks; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand the point of having There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ha, I totally read this backwards (as in you're truncating the old |
||
this.nextStates_ = states; | ||
this.nextTasks_.length = 0; | ||
this.nextStates_.length = 0; | ||
if (resolver) { | ||
resolver(); | ||
} | ||
} | ||
|
||
/** | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a sizable change to the API. I'd expect something would break. I definitely see some places where default
opt_state
is used.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation states otherwise. No tests fail. Do you have a pointer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found 2 places. Fixed them up.
This API sucks. Should have just let measure return an object.