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
Support for OffscreenCanvas in Web Workers #5168
base: main
Are you sure you want to change the base?
Support for OffscreenCanvas in Web Workers #5168
Conversation
@@ -444,7 +444,7 @@ class GraphicsDevice extends EventHandler { | |||
} | |||
|
|||
updateClientRect() { | |||
this.clientRect = this.canvas.getBoundingClientRect(); | |||
this.clientRect = new DOMRect(0, 0, this.canvas.width, this.canvas.height); |
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.
Couple of issues here:
DOMRect
isn't available in Node.js so this causes the unit tests to fail.- This function is called every frame so this will be generating garbage. Probably not a significant amount - just pointing it out.
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 just pushed a commit with an alternative implementation which will generate no garbage and also works in Node.js: It's now a public class field (better for performance because "hidden class"). It's a simple object with properties width
and height
. From reviewing the code base, I can say that only width
and height
are used, and not x
and y
. The only reference is in src/framework/components/camera/component.js .
src/core/platform.js
Outdated
@@ -87,6 +87,13 @@ const platform = { | |||
*/ | |||
browser: environment === 'browser', | |||
|
|||
/** | |||
* Convenience boolean indicating whether we're running in a Web Worker |
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.
* Convenience boolean indicating whether we're running in a Web Worker | |
* Convenience boolean indicating whether we're running in a Web Worker. |
this.clientRect.width = this.canvas.width; | ||
this.clientRect.height = this.canvas.height; |
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.
My guess is that the canvas.width
and canvas.height
properties are the pixel resolution of the canvas, whereas getBoundingClientRect
would return the CSS width and height (see devicePixelRatio for more details). So I would imagine CameraComponent#worldToScreen
and CameraComponent#screenToWorld
would break if the canvas pixel resolution does not match the CSS resolution. Maybe needs this.canvas.style.width
instead? So parseInt(this.canvas.style.width, 10)
. But I'm not sure if that would work in all circumstances...
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.
Unfortunately it would not work. Because Web Workers don't do the page layout, they are unaware of el.getBoundingClientRect()
, el.style
, getComputedStyle(el)
et al. Only the main/rendering thread knows about layout dimensions and coordinates of mouse button clicks.
Therefore I can think right now of the following independent options:
- Change
CameraComponent#screenToWorld
andCameraComponent#worldToScreen
to accept normalized coordinates for the mouse clicks. i.e. let the user do the division of the mouse click coordinates by the canvas screen dimensions, of which they have full knowledge. - Pass the canvas screen dimensions into the
Application
constructor (and require that the canvas is not scaled after). - Leave the implementation as it is and require that
OffscreenCanvas
not be scaled by CSS whenCameraComponent#screenToWorld
andCameraComponent#worldToScreen
are to be used.
I can't judge what would be suitable for the project, but option 3 would be least amount of work while still being correct for the general use case.
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.
option 3 seems to be the best fit for now. also, may I enquiry if there's anything else prevent this from being merged to main?
Fixes #2481
This probably needs the development of a minimal example (and perhaps automatic tests). Since this is my first contribution, please advise on how to proceed.
I'm happy to discuss and improve the implementation if needed.
I confirm I have read the contributing guidelines and signed the Contributor License Agreement.