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

WebGLAnimation: Convert to es6 class #20070

Closed

Conversation

ianpurvis
Copy link
Contributor

Supports #19986

@ianpurvis
Copy link
Contributor Author

Looks like some e2e tests failed... I'll check it out.

@DefinitelyMaybe DefinitelyMaybe mentioned this pull request Aug 13, 2020
43 tasks
@mrdoob
Copy link
Owner

mrdoob commented Aug 14, 2020

Moving internal vars to the module scope eliminates binding issues, but I am not sure they are safe there...

What happens if there are two instances of WebGLAnimation?
Wouldn't context, isAnimating, ... be overwritten?

@ianpurvis
Copy link
Contributor Author

Moving internal vars to the module scope eliminates binding issues, but I am not sure they are safe there...

What happens if there are two instances of WebGLAnimation?
Wouldn't context, isAnimating, ... be overwritten?

Thanks... in my heart I knew it was wrong 😆

I found a safe solution, we can do a one-time bind to this in the constructor:

constructor() {

	this._context = null;
	this._isAnimating = false;
	this._animationLoop = null;
	this._requestId = null;

	// Re-bind the prototype function so that `this` can be used with rAF:
	this._onAnimationFrame = this._onAnimationFrame.bind( this );

}

  Fixes unbound requestAnimationFrame callbacks
@ianpurvis ianpurvis force-pushed the renderers-webgl-animation-es6-class branch from c9f2106 to 77a26dd Compare August 14, 2020 14:02
@mrdoob
Copy link
Owner

mrdoob commented Aug 16, 2020

Now that I know how Symbols work, I think this is the approach I find less weird...

const _context = Symbol( '_context' );
const _isAnimating = Symbol( '_isAnimating' );
const _animationLoop = Symbol( '_animationLoop' );
const _requestId = Symbol( '_requestId' );
const _onAnimationFrame = Symbol( '_onAnimationFrame' );

class WebGLAnimation {

	constructor() {

		this[ _context ] = null;
		this[ _isAnimating ] = false;
		this[ _animationLoop ] = null;
		this[ _requestId ] = null;

		const scope = this;

		this[ _onAnimationFrame ] = function ( time, frame ) {

			scope[ _animationLoop ]( time, frame );

			scope[ _requestId ] = scope[ _context ].requestAnimationFrame( scope[ _onAnimationFrame ] );

		};

	}

	start() {

		if ( this[ _isAnimating ] === true ) return;
		if ( this[ _animationLoop ] === null ) return;

		this[ _requestId ] = this[ _context ].requestAnimationFrame( this[ _onAnimationFrame ] );

		this[ _isAnimating ] = true;

	}

	stop() {

		this[ _context ].cancelAnimationFrame( this[ _requestId ] );

		this[ _isAnimating ] = false;

	}

	setAnimationLoop( callback ) {

		this[ _animationLoop ] = callback;

	}

	setContext( value ) {

		this[ _context ] = value;

	}

}

export { WebGLAnimation };

IE11 doesn't support Symbol though. But, I guess we could turn Symbol( '_context' ) to '_context' at build time and pollute the API in three.js and three.min.js 🤷‍♂️

And, in a distant future... going from this[ _context ] to this.#context would be fairly straightforward.

@mrdoob
Copy link
Owner

mrdoob commented Aug 16, 2020

I do not know what are the performance implications of using Symbol though.

@ianpurvis
Copy link
Contributor Author

👍 👍 I think that should work, I'll glitch a benchmark so that we can start looking at performance.

@ianpurvis
Copy link
Contributor Author

ianpurvis commented Aug 19, 2020

Alright, hopefully this is a decent starting point! https://button-knotty-tugboat.glitch.me

I was able to get some coverage on macOS and iOS... Looks like Chrome and iOS Safari handle all the es6 techniques pretty evenly. Interestingly, desktop Safari actually favors the symbol and string techniques. But Firefox penalizes both of those techniques heavily.

Chrome 84.0.4147.125 on OS X 10.15.6 64-bit
Running 4 tests in random order...
🏋️ incrementScopedVar x 162,183,036 ops/sec ±0.24% (66 runs sampled)
🏋️ incrementPropViaSymbol x 473,961,157 ops/sec ±1.05% (64 runs sampled)
🏋️ incrementPropViaString x 476,167,672 ops/sec ±0.25% (63 runs sampled)
🏋️ incrementPropDirectly x 477,688,995 ops/sec ±0.24% (63 runs sampled)
💪 Fastest is incrementPropDirectly, incrementPropViaString.

Safari 13.1.2 on OS X 10.15.6
Running 4 tests in random order...
🏋️ incrementScopedVar x 508,801,361 ops/sec ±2.10% (56 runs sampled)
🏋️ incrementPropDirectly x 598,270,143 ops/sec ±0.50% (65 runs sampled)
🏋️ incrementPropViaString x 666,520,642 ops/sec ±0.31% (62 runs sampled)
🏋️ incrementPropViaSymbol x 668,056,577 ops/sec ±0.30% (64 runs sampled)
💪 Fastest is incrementPropViaSymbol, incrementPropViaString.

Firefox 79.0 on OS X 10.15
Running 4 tests in random order...
🏋️ incrementScopedVar x 405,513,980 ops/sec ±1.30% (64 runs sampled)
🏋️ incrementPropViaString x 125,742,749 ops/sec ±0.27% (66 runs sampled)
🏋️ incrementPropDirectly x 600,459,804 ops/sec ±3.99% (61 runs sampled)
🏋️ incrementPropViaSymbol x 124,670,980 ops/sec ±0.24% (67 runs sampled)
💪 Fastest is incrementPropDirectly.

Safari 14.0 on Apple iPhone (iOS 14.0)
Running 4 tests in random order...
🏋️ incrementScopedVar x 217,876,111 ops/sec ±2.29% (59 runs sampled)
🏋️ incrementPropDirectly x 216,502,987 ops/sec ±0.98% (60 runs sampled)
🏋️ incrementPropViaString x 212,062,590 ops/sec ±0.45% (60 runs sampled)
🏋️ incrementPropViaSymbol x 212,841,235 ops/sec ±0.38% (62 runs sampled)
💪 Fastest is incrementPropDirectly.

@ianpurvis
Copy link
Contributor Author

Quick heads-up, I moved that benchmark to here and added the WeakMap technique and also the constructor-scoped var technique for completeness. I also started a different benchmark for testing performance when calling_onAnimationFrame with rAF. Feel free to remix as needed or let me know if you want access to edit at the source

@mrdoob mrdoob added this to the r121 milestone Aug 23, 2020
@mrdoob mrdoob modified the milestones: r121, r122 Sep 29, 2020
@mrdoob mrdoob modified the milestones: r122, r123 Oct 28, 2020
@mrdoob mrdoob modified the milestones: r123, r124 Nov 25, 2020
@mrdoob mrdoob modified the milestones: r124, r125 Dec 24, 2020
@mrdoob mrdoob modified the milestones: r125, r126 Jan 27, 2021
Copy link
Collaborator

@Mugen87 Mugen87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mrdoob According to the discussion in #21235, the PR looks good.

@mrdoob mrdoob modified the milestones: r126, r127 Feb 23, 2021
@mrdoob mrdoob modified the milestones: r127, r128 Mar 30, 2021
@Mugen87 Mugen87 removed this from the r128 milestone Apr 16, 2021
@Mugen87
Copy link
Collaborator

Mugen87 commented Apr 16, 2021

Closing. We've agreed in #19986 to not change/refactor the code in src/renderers/webgl.

@Mugen87 Mugen87 closed this Apr 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants