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

[CoordinatedGraphics] Provide scheduled display-update events for better scrolling handling #10259

Conversation

zdobersek
Copy link
Contributor

@zdobersek zdobersek commented Feb 17, 2023

06b9ec1

[CoordinatedGraphics] Provide scheduled display-update events for better scrolling handling
https://bugs.webkit.org/show_bug.cgi?id=252467

Reviewed by Carlos Garcia Campos.

In ThreadedCompositor, a timer is established on the composition thread that is
used to mimic display updates at the desired update frequency. This is necessary
in order to provide opportunities for update producers like the scrolling thread
to actually enact the desired composition changes, like scrolling, independently
of the main thread.

The timer is put on the composition thread, matching the compositing-thread
update timer in priority. Its delay is based on the established frequency of the
display updates.

ThreadedCompositor::displayUpdateFired() method is added and is dispatched upon
every firing of the timer. It notifies the scrolling thread(s) for the given
display ID through the EventDispatcher instance on the WebProcess singleton,
and the next firing of the timer is then scheduled.

When ThreadedCompositor enters into the composition phase, the display update
timer is stopped, and the displayUpdateFired() dispatcher is invoked manually
when the frame-complete signal is returned from the embedder's environment. This
allows aligning the display update timer with the environment's vsync signals
without disturbing the composition itself.

The target update frequency logic is pulled from ThreadedDisplayRefreshMonitor
into ThreadedCompositor, with the desired DisplayUpdate object now also kept in
that class. In order for ThreadedDisplayRefreshMonitor to use a sensible
DisplayUpdate object for each of its own dispatches, the DisplayUpdate object
is passed through the requiresDisplayRefreshCallback() method to the monitor,
where it's then stored for next invocation on the main thread, if it occurs.

ScrollingTreeNicosia::applyLayerPositionsInternal() override is provided,
establishing an update scope when running on the scrolling thread. This will
cause the applied positions to actually go through composition whenever the
scrolling is being handled on the scrolling thread, meaning outside of the usual
update process.

* Source/WebCore/page/scrolling/nicosia/ScrollingTreeNicosia.cpp:
(WebCore::ScrollingTreeNicosia::applyLayerPositionsInternal):
* Source/WebCore/page/scrolling/nicosia/ScrollingTreeNicosia.h:
* Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp:
(WebKit::m_displayRefreshMonitor):
(WebKit::ThreadedCompositor::renderLayerTree):
(WebKit::ThreadedCompositor::sceneUpdateFinished):
(WebKit::ThreadedCompositor::frameComplete):
(WebKit::ThreadedCompositor::targetRefreshRateDidChange):
(WebKit::ThreadedCompositor::displayUpdateFired):
* Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h:
* Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp:
(WebKit::ThreadedDisplayRefreshMonitor::ThreadedDisplayRefreshMonitor):
(WebKit::ThreadedDisplayRefreshMonitor::requiresDisplayRefreshCallback):
(WebKit::ThreadedDisplayRefreshMonitor::invalidate):
(WebKit::ThreadedDisplayRefreshMonitor::displayRefreshCallback):
(WebKit::ThreadedDisplayRefreshMonitor::setTargetRefreshRate): Deleted.
* Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.h:
* Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp:
(WebKit::LayerTreeHost::displayDidRefresh):

Canonical link: https://commits.webkit.org/261124@main

3817582

Misc iOS, tvOS & watchOS macOS Linux Windows
βœ… πŸ§ͺ style βœ… πŸ›  ios   πŸ›  mac   πŸ›  wpe   πŸ›  wincairo
βœ… πŸ§ͺ bindings βœ… πŸ›  ios-sim βœ… πŸ›  mac-AS-debug ❌ πŸ§ͺ wpe-wk2
βœ… πŸ§ͺ webkitperl   πŸ§ͺ ios-wk2   πŸ§ͺ api-mac βœ… πŸ›  gtk
  πŸ§ͺ api-ios   πŸ§ͺ mac-wk1 βœ… πŸ§ͺ gtk-wk2
  πŸ›  tv   πŸ§ͺ mac-wk2   πŸ§ͺ api-gtk
βœ… πŸ›  tv-sim   πŸ§ͺ mac-AS-debug-wk2
βœ… πŸ›  watch   πŸ§ͺ mac-wk2-stress
βœ… πŸ›  πŸ§ͺ merge   πŸ›  watch-sim

@zdobersek zdobersek self-assigned this Feb 17, 2023
@zdobersek zdobersek added the New Bugs Unclassified bugs are placed in this component until the correct component can be determined. label Feb 17, 2023
@zdobersek zdobersek marked this pull request as draft February 18, 2023 10:02
@zdobersek zdobersek force-pushed the eng/CoordinatedGraphics-Provide-scheduled-display-update-events-for-better-scrolling-handling branch from 8bbed56 to c086f4f Compare February 27, 2023 17:12
@zdobersek zdobersek force-pushed the eng/CoordinatedGraphics-Provide-scheduled-display-update-events-for-better-scrolling-handling branch from c086f4f to cde889c Compare March 1, 2023 09:53
@zdobersek zdobersek marked this pull request as ready for review March 1, 2023 10:06
{
m_display.displayUpdate = m_display.displayUpdate.nextUpdate();

WebProcess::singleton().eventDispatcher().notifyScrollingTreesDisplayDidRefresh(m_display.displayID);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did you remove the Client::displayDidRefresh? EventDispatcher::notifyScrollingTreesDisplayDidRefresh iterates all scrolling trees to notify that a display has been refreshed. Every tree checks if its displayID matches the given one. This is required when there's a global display notifying about a refresh, but in our case we have one display refresh monitor with its own displayID for every threaded compositor. So, we know what tree we wat to notify without having to iterate all trees.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is called from the composition thread, so LayerTreeHost::displayDidRefresh() ends up loading the Page's ScrollingCoordinator and then its ScrollingTree from a non-main thread.

Using EventDispatcher avoids that, and it locks over the scrolling trees that are registered and unregistered on the main thread, so no threading problems.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, in that case I would add:

void EventDispatcher::notifyWebPageScrollingTreeDisplayDidRefresh(WebPage& page, PlatformDisplayID displayID);

And call it from LayerTreeHost::displayDidRefresh. This avoids the tree iteration, fixes the threading issues and doesn't use WebProcess API from Shared.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I assume you would want to short-cut to the ScrollingTree in the new EventDispatcher method, through the WebPage. But that still operates on that WebPage on a non-main thread, so threading problems would remain.

Calling ThreadedScrollingTree::displayDidRefresh() on every scrolling tree isn't ideal, and it can be improved, but I don't see it as critical.

Copy link
Contributor

Choose a reason for hiding this comment

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

It would be just getting the identifier that is the key of the trees map. Anyway, it's not critical since in most of the cases there's only one page per process. But still I prefer to call the dispatcher from LayerTreeHost::displayDidRefresh, which is in WebProcess layer too. At some point we should move the threaded compositor code from Shared to WebProcess and stop pretending it's shared, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I'm adding back LayerTreeHost::displayDidRefresh.

@zdobersek zdobersek force-pushed the eng/CoordinatedGraphics-Provide-scheduled-display-update-events-for-better-scrolling-handling branch from cde889c to 9f44e64 Compare March 2, 2023 12:18
Copy link
Contributor

@carlosgcampos carlosgcampos left a comment

Choose a reason for hiding this comment

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

I still get some blocks, but less often, so let's try this. Thanks!

@zdobersek zdobersek force-pushed the eng/CoordinatedGraphics-Provide-scheduled-display-update-events-for-better-scrolling-handling branch from 9f44e64 to 3817582 Compare March 3, 2023 08:02
@zdobersek zdobersek added the merge-queue Applied to send a pull request to merge-queue label Mar 3, 2023
…ter scrolling handling

https://bugs.webkit.org/show_bug.cgi?id=252467

Reviewed by Carlos Garcia Campos.

In ThreadedCompositor, a timer is established on the composition thread that is
used to mimic display updates at the desired update frequency. This is necessary
in order to provide opportunities for update producers like the scrolling thread
to actually enact the desired composition changes, like scrolling, independently
of the main thread.

The timer is put on the composition thread, matching the compositing-thread
update timer in priority. Its delay is based on the established frequency of the
display updates.

ThreadedCompositor::displayUpdateFired() method is added and is dispatched upon
every firing of the timer. It notifies the scrolling thread(s) for the given
display ID through the EventDispatcher instance on the WebProcess singleton,
and the next firing of the timer is then scheduled.

When ThreadedCompositor enters into the composition phase, the display update
timer is stopped, and the displayUpdateFired() dispatcher is invoked manually
when the frame-complete signal is returned from the embedder's environment. This
allows aligning the display update timer with the environment's vsync signals
without disturbing the composition itself.

The target update frequency logic is pulled from ThreadedDisplayRefreshMonitor
into ThreadedCompositor, with the desired DisplayUpdate object now also kept in
that class. In order for ThreadedDisplayRefreshMonitor to use a sensible
DisplayUpdate object for each of its own dispatches, the DisplayUpdate object
is passed through the requiresDisplayRefreshCallback() method to the monitor,
where it's then stored for next invocation on the main thread, if it occurs.

ScrollingTreeNicosia::applyLayerPositionsInternal() override is provided,
establishing an update scope when running on the scrolling thread. This will
cause the applied positions to actually go through composition whenever the
scrolling is being handled on the scrolling thread, meaning outside of the usual
update process.

* Source/WebCore/page/scrolling/nicosia/ScrollingTreeNicosia.cpp:
(WebCore::ScrollingTreeNicosia::applyLayerPositionsInternal):
* Source/WebCore/page/scrolling/nicosia/ScrollingTreeNicosia.h:
* Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.cpp:
(WebKit::m_displayRefreshMonitor):
(WebKit::ThreadedCompositor::renderLayerTree):
(WebKit::ThreadedCompositor::sceneUpdateFinished):
(WebKit::ThreadedCompositor::frameComplete):
(WebKit::ThreadedCompositor::targetRefreshRateDidChange):
(WebKit::ThreadedCompositor::displayUpdateFired):
* Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedCompositor.h:
* Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.cpp:
(WebKit::ThreadedDisplayRefreshMonitor::ThreadedDisplayRefreshMonitor):
(WebKit::ThreadedDisplayRefreshMonitor::requiresDisplayRefreshCallback):
(WebKit::ThreadedDisplayRefreshMonitor::invalidate):
(WebKit::ThreadedDisplayRefreshMonitor::displayRefreshCallback):
(WebKit::ThreadedDisplayRefreshMonitor::setTargetRefreshRate): Deleted.
* Source/WebKit/Shared/CoordinatedGraphics/threadedcompositor/ThreadedDisplayRefreshMonitor.h:
* Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp:
(WebKit::LayerTreeHost::displayDidRefresh):

Canonical link: https://commits.webkit.org/261124@main
@webkit-early-warning-system webkit-early-warning-system force-pushed the eng/CoordinatedGraphics-Provide-scheduled-display-update-events-for-better-scrolling-handling branch from 3817582 to 06b9ec1 Compare March 3, 2023 09:21
@webkit-commit-queue
Copy link
Collaborator

Committed 261124@main (06b9ec1): https://commits.webkit.org/261124@main

Reviewed commits have been landed. Closing PR #10259 and removing active labels.

@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label Mar 3, 2023
@webkit-early-warning-system webkit-early-warning-system merged commit 06b9ec1 into WebKit:main Mar 3, 2023
@zdobersek zdobersek deleted the eng/CoordinatedGraphics-Provide-scheduled-display-update-events-for-better-scrolling-handling branch March 3, 2023 09:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
New Bugs Unclassified bugs are placed in this component until the correct component can be determined.
Projects
None yet
4 participants