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

Support for OffscreenCanvas in Web Workers #5168

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

michaelfranzl
Copy link

@michaelfranzl michaelfranzl commented Mar 19, 2023

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.

@willeastcott willeastcott added feature request area: graphics Graphics related issue release: next minor Ticket marked for the next minor release labels Mar 19, 2023
src/core/platform.js Outdated Show resolved Hide resolved
@@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

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

Couple of issues here:

  1. DOMRect isn't available in Node.js so this causes the unit tests to fail.
  2. This function is called every frame so this will be generating garbage. Probably not a significant amount - just pointing it out.

Copy link
Author

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 .

@@ -87,6 +87,13 @@ const platform = {
*/
browser: environment === 'browser',

/**
* Convenience boolean indicating whether we're running in a Web Worker
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* Convenience boolean indicating whether we're running in a Web Worker
* Convenience boolean indicating whether we're running in a Web Worker.

Comment on lines +457 to +458
this.clientRect.width = this.canvas.width;
this.clientRect.height = this.canvas.height;
Copy link
Contributor

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...

Copy link
Author

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:

  1. Change CameraComponent#screenToWorld and CameraComponent#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.
  2. Pass the canvas screen dimensions into the Application constructor (and require that the canvas is not scaled after).
  3. Leave the implementation as it is and require that OffscreenCanvas not be scaled by CSS when CameraComponent#screenToWorld and CameraComponent#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.

Copy link
Contributor

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?

@GSterbrant GSterbrant added the open source contribution Issues related to contributions from people outside the PlayCanvas team label May 12, 2023
@mvaligursky mvaligursky removed the release: next minor Ticket marked for the next minor release label Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: graphics Graphics related issue feature request open source contribution Issues related to contributions from people outside the PlayCanvas team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Investigate implementation of OffscreenCanvas API
5 participants