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

Refactor event-loop processing model to perform rendering as a task #10007

Merged
merged 17 commits into from
Jan 31, 2024

Conversation

noamr
Copy link
Collaborator

@noamr noamr commented Dec 19, 2023

Instead of "updating the rendering" after each task, we wait for rendering opportunities in parallel, and post a special task to update the rendering. This is more in line with existing implementations, and fixes weird cases where e.g. a microtrask queue can run without a current task.

See #9824
(Not a behavior change)


💥 Error: Wattsi server error 💥

PR Preview failed to build. (Last tried on Jan 31, 2024, 2:53 AM UTC).

More

PR Preview relies on a number of web services to run. There seems to be an issue with the following one:

🚨 Wattsi Server - Wattsi Server is the web service used to build the WHATWG HTML spec.

🔗 Related URL

error code: 524

If you don't have enough information above to solve the error by yourself (or to understand to which web service the error is related to, if any), please file an issue.

@noamr noamr changed the title WIP render as task Refactor event-loop processing model to perform rendering as a task Dec 19, 2023
Copy link
Member

@Kaiido Kaiido left a comment

Choose a reason for hiding this comment

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

Thanks for this, this seems closer to the observed behavior indeed.
I just have a few (non-authoritative) small notes regarding the design, but it seems to work well overall.

@smaug----
Copy link

FWIW, this seems relatively close to what Gecko does, or perhaps I should say very close.

Copy link
Member

@Kaiido Kaiido left a comment

Choose a reason for hiding this comment

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

For the little it's worth, LGTM now.

I just wonder if we should have WPTests for this?
You said in #9824 that the fact it's a task is visible through the longtask-timing API, and we can probably add a small test that the timestamp is correctly updated after a long task (testing for the race-condition case), but maybe it's already there, I must admit I didn't check yet.
WDYT?

@noamr
Copy link
Collaborator Author

noamr commented Dec 22, 2023

For the little it's worth, LGTM now.

I just wonder if we should have WPTests for this? You said in #9824 that the fact it's a task is visible through the longtask-timing API, and we can probably add a small test that the timestamp is correctly updated after a long task (testing for the race-condition case), but maybe it's already there, I must admit I didn't check yet. WDYT?

It's already there! I actually became interested in fixing this after finding out that this test passes but shouldn't:
https://wpt.fyi/results/longtask-timing/longtask-in-raf.html

@Kaiido
Copy link
Member

Kaiido commented Dec 22, 2023

Ah great.
But it just crossed my mind that maybe the Worker event-loop's update the rendering may also need the same refactor?

@noamr
Copy link
Collaborator Author

noamr commented Dec 22, 2023

Ah great. But it just crossed my mind that maybe the Worker event-loop's update the rendering may also need the same refactor?

Workers don't update the rendering.

@Kaiido
Copy link
Member

Kaiido commented Dec 23, 2023

Workers don't update the rendering.

Oh, yes they do. That's how we do update the placeholder <canvas> of an OffscreenCanvas that lives in a Worker.

However the implications for a Worker are a bit different in that close() is supposed to discard all queued tasks, but that'd would be problematic for the update the rendering tasks, as we actually probably want the update the rendering to happen in such case, or at least a lighter version of it without rAF callbacks like Firefox currently does: https://glitch.com/edit/#!/raf-in-closing-worker 1. This will become even more problematic once #9979 lands (if it ever lands...), but the current status is not interoperable anyway, so you can probably simply move the worker's update the rendering along with the window's one without much issue, and we'll handle the problematic cases later on separately.

But if you don't feel confident doing it here, I guess that can also be tackled in a follow-up PR, though I should note (mostly as a reminder to myself) that at least in #9979 I was expecting the link to update the rendering would encompass both the window and worker event-loops versions, which is not the case anymore with the changes here.

Footnotes

  1. In case the editor fails to open, the output is at https://raf-in-closing-worker.glitch.me/

@noamr
Copy link
Collaborator Author

noamr commented Dec 23, 2023

Workers don't update the rendering.

Oh, yes they do. That's how we do update the placeholder <canvas> of an OffscreenCanvas that lives in a Worker.

However the implications for a Worker are a bit different in that close() is supposed to discard all queued tasks, but that'd would be problematic for the update the rendering tasks, as we actually probably want the update the rendering to happen in such case, or at least a lighter version of it without rAF callbacks like Firefox currently does: https://glitch.com/edit/#!/raf-in-closing-worker 1. This will become even more problematic once #9979 lands (if it ever lands...), but the current status is not interoperable anyway, so you can probably simply move the worker's update the rendering along with the window's one without much issue, and we'll handle the problematic cases later on separately.

But if you don't feel confident doing it here, I guess that can also be tackled in a follow-up PR, though I should note (mostly as a reminder to myself) that at least in #9979 I was expecting the link to update the rendering would encompass both the window and worker event-loops versions, which is not the case anymore with the changes here.

Footnotes

  1. In case the editor fails to open, the output is at https://raf-in-closing-worker.glitch.me/

Oh yes, the update-canvas-from-worker thing. I think we should do that in a follow up.

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

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

This is a tough one...

Copy link
Collaborator Author

@noamr noamr left a comment

Choose a reason for hiding this comment

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

Thanks, it's a tough one indeed... Fixed some and commented on some.

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

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

Thanks for all the work here! I did a final round of nit-fixing and formatting, and will now merge.

@domenic domenic merged commit 8c489cb into whatwg:main Jan 31, 2024
2 checks passed
kalenikaliaksandr added a commit to kalenikaliaksandr/ladybird that referenced this pull request Oct 3, 2024
Implements whatwg/html#10007 which basically
moves style, layout and painting from HTML processing task into HTML
task with "rendering" source.

The biggest difference is that now we no longer schedule HTML event loop
processing whenever we might need a repaint, but instead queue a global
rendering task 60 times per second that will check if any documents
need a style/layout/paint update.

That is a great simplification of our repaint scheduling model. Before
we had:
- Optional timer that schedules animation updates 60 hz
- Optional timer that schedules rAF updates
- PaintWhenReady state to schedule a paint if navigable doesn't have a
  rendering opportunity on the last event loop iteration

Now all that is gone and replaced with a single timer that drives
repainting at 60 hz and we don't have to worry about excessive repaints.

In the future, hard-coded 60 hz refresh interval could be replaced with
CADisplayLink on macOS and similar API on linux to drive repainting in
synchronization with display's refresh rate.
kalenikaliaksandr added a commit to kalenikaliaksandr/ladybird that referenced this pull request Oct 3, 2024
Implements whatwg/html#10007 which basically
moves style, layout and painting from HTML processing task into HTML
task with "rendering" source.

The biggest difference is that now we no longer schedule HTML event loop
processing whenever we might need a repaint, but instead queue a global
rendering task 60 times per second that will check if any documents
need a style/layout/paint update.

That is a great simplification of our repaint scheduling model. Before
we had:
- Optional timer that schedules animation updates 60 hz
- Optional timer that schedules rAF updates
- PaintWhenReady state to schedule a paint if navigable doesn't have a
  rendering opportunity on the last event loop iteration

Now all that is gone and replaced with a single timer that drives
repainting at 60 hz and we don't have to worry about excessive repaints.

In the future, hard-coded 60 hz refresh interval could be replaced with
CADisplayLink on macOS and similar API on linux to drive repainting in
synchronization with display's refresh rate.
kalenikaliaksandr added a commit to kalenikaliaksandr/ladybird that referenced this pull request Oct 3, 2024
Implements whatwg/html#10007 which basically
moves style, layout and painting from HTML processing task into HTML
task with "rendering" source.

The biggest difference is that now we no longer schedule HTML event loop
processing whenever we might need a repaint, but instead queue a global
rendering task 60 times per second that will check if any documents
need a style/layout/paint update.

That is a great simplification of our repaint scheduling model. Before
we had:
- Optional timer that schedules animation updates 60 hz
- Optional timer that schedules rAF updates
- PaintWhenReady state to schedule a paint if navigable doesn't have a
  rendering opportunity on the last event loop iteration

Now all that is gone and replaced with a single timer that drives
repainting at 60 hz and we don't have to worry about excessive repaints.

In the future, hard-coded 60 hz refresh interval could be replaced with
CADisplayLink on macOS and similar API on linux to drive repainting in
synchronization with display's refresh rate.
awesomekling pushed a commit to LadybirdBrowser/ladybird that referenced this pull request Oct 4, 2024
Implements whatwg/html#10007 which basically
moves style, layout and painting from HTML processing task into HTML
task with "rendering" source.

The biggest difference is that now we no longer schedule HTML event loop
processing whenever we might need a repaint, but instead queue a global
rendering task 60 times per second that will check if any documents
need a style/layout/paint update.

That is a great simplification of our repaint scheduling model. Before
we had:
- Optional timer that schedules animation updates 60 hz
- Optional timer that schedules rAF updates
- PaintWhenReady state to schedule a paint if navigable doesn't have a
  rendering opportunity on the last event loop iteration

Now all that is gone and replaced with a single timer that drives
repainting at 60 hz and we don't have to worry about excessive repaints.

In the future, hard-coded 60 hz refresh interval could be replaced with
CADisplayLink on macOS and similar API on linux to drive repainting in
synchronization with display's refresh rate.
rmg-x pushed a commit to rmg-x/ladybird that referenced this pull request Oct 4, 2024
Implements whatwg/html#10007 which basically
moves style, layout and painting from HTML processing task into HTML
task with "rendering" source.

The biggest difference is that now we no longer schedule HTML event loop
processing whenever we might need a repaint, but instead queue a global
rendering task 60 times per second that will check if any documents
need a style/layout/paint update.

That is a great simplification of our repaint scheduling model. Before
we had:
- Optional timer that schedules animation updates 60 hz
- Optional timer that schedules rAF updates
- PaintWhenReady state to schedule a paint if navigable doesn't have a
  rendering opportunity on the last event loop iteration

Now all that is gone and replaced with a single timer that drives
repainting at 60 hz and we don't have to worry about excessive repaints.

In the future, hard-coded 60 hz refresh interval could be replaced with
CADisplayLink on macOS and similar API on linux to drive repainting in
synchronization with display's refresh rate.
ebanner pushed a commit to ebanner/ladybird that referenced this pull request Oct 15, 2024
Implements whatwg/html#10007 which basically
moves style, layout and painting from HTML processing task into HTML
task with "rendering" source.

The biggest difference is that now we no longer schedule HTML event loop
processing whenever we might need a repaint, but instead queue a global
rendering task 60 times per second that will check if any documents
need a style/layout/paint update.

That is a great simplification of our repaint scheduling model. Before
we had:
- Optional timer that schedules animation updates 60 hz
- Optional timer that schedules rAF updates
- PaintWhenReady state to schedule a paint if navigable doesn't have a
  rendering opportunity on the last event loop iteration

Now all that is gone and replaced with a single timer that drives
repainting at 60 hz and we don't have to worry about excessive repaints.

In the future, hard-coded 60 hz refresh interval could be replaced with
CADisplayLink on macOS and similar API on linux to drive repainting in
synchronization with display's refresh rate.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

4 participants