Skip to content

Commit

Permalink
Support sending displayDidRefresh at DisplayLink update with site iso…
Browse files Browse the repository at this point in the history
…lation.

https://bugs.webkit.org/show_bug.cgi?id=260674
<rdar://problem/114402070>

Reviewed by Alex Christensen.

We currently always send displayDidRefresh for subframes immediately, instead of waiting for the next DisplayLink update.

This keeps a set of remote frames, tracking what the current CommitLayerTreeMessageState is for each of them separately.
When the displayDidRefresh call comes from DisplayLink, we iterate the set, sending the message onto the web process
for each remote frame that is waiting for one.

* Source/WebKit/UIProcess/DrawingAreaProxy.h:
(WebKit::DrawingAreaProxy::addRemotePageDrawingAreaProxy):
(WebKit::DrawingAreaProxy::removeRemotePageDrawingAreaProxy):
* Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.h:
(WebKit::RemoteLayerTreeDrawingAreaProxy::nextLayerTreeTransactionID const):
(WebKit::RemoteLayerTreeDrawingAreaProxy::lastCommittedLayerTreeTransactionID const):
* Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm:
(WebKit::RemoteLayerTreeDrawingAreaProxy::addRemotePageDrawingAreaProxy):
(WebKit::RemoteLayerTreeDrawingAreaProxy::removeRemotePageDrawingAreaProxy):
(WebKit::RemoteLayerTreeDrawingAreaProxy::processStateForConnection):
(WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTreeNotTriggered):
(WebKit::RemoteLayerTreeDrawingAreaProxy::willCommitLayerTree):
(WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree):
(WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTreeTransaction):
(WebKit::RemoteLayerTreeDrawingAreaProxy::asyncSetLayerContents):
(WebKit::RemoteLayerTreeDrawingAreaProxy::maybePauseDisplayRefreshCallbacks):
(WebKit::RemoteLayerTreeDrawingAreaProxy::didRefreshDisplay):
(WebKit::RemoteLayerTreeDrawingAreaProxy::waitForDidUpdateActivityState):
(WebKit::RemoteLayerTreeDrawingAreaProxy::hideContentUntilPendingUpdate):
* Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeDrawingAreaProxyIOS.mm:
(-[WKDisplayLinkHandler displayLinkFired:]):
(-[WKDisplayLinkHandler timerFired]):
* Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeDrawingAreaProxyMac.h:
* Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteLayerTreeDrawingAreaProxyMac.mm:
(WebKit::RemoteLayerTreeDisplayLinkClient::displayLinkFired):
(WebKit::RemoteLayerTreeDrawingAreaProxyMac::didRefreshDisplay):
* Source/WebKit/UIProcess/RemotePageDrawingAreaProxy.cpp:
(WebKit::RemotePageDrawingAreaProxy::RemotePageDrawingAreaProxy):
(WebKit::RemotePageDrawingAreaProxy::~RemotePageDrawingAreaProxy):
* Source/WebKit/UIProcess/RemotePageDrawingAreaProxy.h:
(WebKit::RemotePageDrawingAreaProxy::process):

Canonical link: https://commits.webkit.org/267270@main
  • Loading branch information
mattwoodrow committed Aug 25, 2023
1 parent f93b5aa commit f754a3d
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 54 deletions.
4 changes: 4 additions & 0 deletions Source/WebKit/UIProcess/DrawingAreaProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ using PlatformDisplayID = uint32_t;
namespace WebKit {

class LayerTreeContext;
class RemotePageDrawingAreaProxy;
class WebPageProxy;
class WebProcessProxy;

Expand Down Expand Up @@ -132,6 +133,9 @@ class DrawingAreaProxy : public IPC::MessageReceiver {
// IPC::MessageReceiver
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;

virtual void addRemotePageDrawingAreaProxy(RemotePageDrawingAreaProxy&) { }
virtual void removeRemotePageDrawingAreaProxy(RemotePageDrawingAreaProxy&) { }

protected:
DrawingAreaProxy(DrawingAreaType, WebPageProxy&);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@
#include <WebCore/FloatPoint.h>
#include <WebCore/IntPoint.h>
#include <WebCore/IntSize.h>
#include <wtf/WeakHashMap.h>

namespace WebKit {

class RemoteScrollingCoordinatorProxy;
class RemoteLayerTreeTransaction;
class RemotePageDrawingAreaProxy;
class RemoteScrollingCoordinatorProxy;
class RemoteScrollingCoordinatorProxy;
class RemoteScrollingCoordinatorTransaction;

Expand All @@ -55,8 +57,9 @@ class RemoteLayerTreeDrawingAreaProxy : public DrawingAreaProxy {
void acceleratedAnimationDidStart(WebCore::PlatformLayerIdentifier, const String& key, MonotonicTime startTime);
void acceleratedAnimationDidEnd(WebCore::PlatformLayerIdentifier, const String& key);

TransactionID nextLayerTreeTransactionID() const { return m_pendingLayerTreeTransactionID.next(); }
TransactionID lastCommittedLayerTreeTransactionID() const { return m_transactionIDForPendingCACommit; }
// FIXME(site-isolation): These always return the root's IDs. Is that ok?
TransactionID nextLayerTreeTransactionID() const { return m_webPageProxyProcessState.pendingLayerTreeTransactionID.next(); }
TransactionID lastCommittedLayerTreeTransactionID() const { return m_webPageProxyProcessState.transactionIDForPendingCACommit; }

virtual void didRefreshDisplay();
virtual void setDisplayLinkWantsFullSpeedUpdates(bool) { }
Expand Down Expand Up @@ -107,13 +110,25 @@ class RemoteLayerTreeDrawingAreaProxy : public DrawingAreaProxy {

WebCore::FloatPoint indicatorLocation() const;

void addRemotePageDrawingAreaProxy(RemotePageDrawingAreaProxy&) final;
void removeRemotePageDrawingAreaProxy(RemotePageDrawingAreaProxy&) final;

// IPC::MessageReceiver
void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final;

// Message handlers
// FIXME(site-isolation): We really want a Connection parameter to all of these (including
// on the DrawingAreaProxy base class), and make sure we filter them
// appropriately. Can we enforce that?

// FIXME(site-isolation): We currently allow this from any subframe process and it overwrites
// the main frame's request. We should either ignore subframe requests, or
// properly track all the requested and filter displayDidRefresh callback rates
// per-frame.
virtual void setPreferredFramesPerSecond(WebCore::FramesPerSecond) { }
void willCommitLayerTree(TransactionID);
void commitLayerTreeNotTriggered(TransactionID);

void willCommitLayerTree(IPC::Connection&, TransactionID);
void commitLayerTreeNotTriggered(IPC::Connection&, TransactionID);
void commitLayerTree(IPC::Connection&, const Vector<std::pair<RemoteLayerTreeTransaction, RemoteScrollingCoordinatorTransaction>>&);
void commitLayerTreeTransaction(IPC::Connection&, const RemoteLayerTreeTransaction&, const RemoteScrollingCoordinatorTransaction&);
virtual void didCommitLayerTree(IPC::Connection&, const RemoteLayerTreeTransaction&, const RemoteScrollingCoordinatorTransaction&) { }
Expand All @@ -130,7 +145,25 @@ class RemoteLayerTreeDrawingAreaProxy : public DrawingAreaProxy {
// displayDidRefresh, otherwise we mark it as missed and send
// it when commitLayerTree does arrive).
enum CommitLayerTreeMessageState { CommitLayerTreePending, NeedsDisplayDidRefresh, MissedCommit, Idle };
CommitLayerTreeMessageState m_commitLayerTreeMessageState { Idle };
struct ProcessState {
CommitLayerTreeMessageState commitLayerTreeMessageState { Idle };
TransactionID lastLayerTreeTransactionID;
TransactionID pendingLayerTreeTransactionID;
#if ASSERT_ENABLED
TransactionID lastVisibleTransactionID;
#endif
TransactionID transactionIDForPendingCACommit;
TransactionID transactionIDForUnhidingContent;
ActivityStateChangeID activityStateChangeID { ActivityStateChangeAsynchronous };
};

ProcessState& processStateForConnection(IPC::Connection&);
void didRefreshDisplay(IPC::Connection*);
void didRefreshDisplay(ProcessState&, IPC::Connection&);
bool maybePauseDisplayRefreshCallbacks();

ProcessState m_webPageProxyProcessState;
WeakHashMap<RemotePageDrawingAreaProxy, ProcessState> m_remotePageProcessState;

WebCore::IntSize m_lastSentSize;
WebCore::IntSize m_lastSentMinimumSizeForAutoLayout;
Expand All @@ -139,15 +172,6 @@ class RemoteLayerTreeDrawingAreaProxy : public DrawingAreaProxy {
std::unique_ptr<RemoteLayerTreeHost> m_debugIndicatorLayerTreeHost;
RetainPtr<CALayer> m_tileMapHostLayer;
RetainPtr<CALayer> m_exposedRectIndicatorLayer;

TransactionID m_pendingLayerTreeTransactionID;
TransactionID m_lastLayerTreeTransactionID;
#if ASSERT_ENABLED
TransactionID m_lastVisibleTransactionID;
#endif
TransactionID m_transactionIDForPendingCACommit;
TransactionID m_transactionIDForUnhidingContent;
ActivityStateChangeID m_activityStateChangeID { ActivityStateChangeAsynchronous };

unsigned m_countOfTransactionsWithNonEmptyLayerChanges { 0 };
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#import "Logging.h"
#import "MessageSenderInlines.h"
#import "RemoteLayerTreeDrawingAreaProxyMessages.h"
#import "RemotePageDrawingAreaProxy.h"
#import "RemotePageProxy.h"
#import "RemoteScrollingCoordinatorProxy.h"
#import "RemoteScrollingCoordinatorTransaction.h"
Expand Down Expand Up @@ -74,6 +75,17 @@
return { names };
}

void RemoteLayerTreeDrawingAreaProxy::addRemotePageDrawingAreaProxy(RemotePageDrawingAreaProxy& proxy)
{
m_remotePageProcessState.add(proxy, ProcessState { });
}

void RemoteLayerTreeDrawingAreaProxy::removeRemotePageDrawingAreaProxy(RemotePageDrawingAreaProxy& proxy)
{
ASSERT(m_remotePageProcessState.contains(proxy));
m_remotePageProcessState.remove(proxy);
}

std::unique_ptr<RemoteLayerTreeHost> RemoteLayerTreeDrawingAreaProxy::detachRemoteLayerTreeHost()
{
m_remoteLayerTreeHost->detachFromDrawingArea();
Expand Down Expand Up @@ -137,26 +149,41 @@
}, m_identifier);
}

void RemoteLayerTreeDrawingAreaProxy::commitLayerTreeNotTriggered(TransactionID nextCommitTransactionID)
RemoteLayerTreeDrawingAreaProxy::ProcessState& RemoteLayerTreeDrawingAreaProxy::processStateForConnection(IPC::Connection& connection)
{
if (nextCommitTransactionID <= m_lastLayerTreeTransactionID) {
LOG_WITH_STREAM(RemoteLayerTree, stream << "RemoteLayerTreeDrawingAreaProxy::commitLayerTreeNotTriggered nextCommitTransactionID=" << nextCommitTransactionID << ") already obsoleted by m_lastLayerTreeTransactionID=" << m_lastLayerTreeTransactionID);
for (auto pair : m_remotePageProcessState) {
if (pair.key.process().hasConnection() && pair.key.process().connection() == &connection)
return pair.value;
}

ASSERT(m_webPageProxy.process().hasConnection() && &connection == m_webPageProxy.process().connection());
return m_webPageProxyProcessState;
}

void RemoteLayerTreeDrawingAreaProxy::commitLayerTreeNotTriggered(IPC::Connection& connection, TransactionID nextCommitTransactionID)
{
ProcessState& state = processStateForConnection(connection);
if (nextCommitTransactionID <= state.lastLayerTreeTransactionID) {
LOG_WITH_STREAM(RemoteLayerTree, stream << "RemoteLayerTreeDrawingAreaProxy::commitLayerTreeNotTriggered nextCommitTransactionID=" << nextCommitTransactionID << ") already obsoleted by m_lastLayerTreeTransactionID=" << state.lastLayerTreeTransactionID);
return;
}

m_commitLayerTreeMessageState = Idle;
pauseDisplayRefreshCallbacks();
state.commitLayerTreeMessageState = Idle;

maybePauseDisplayRefreshCallbacks();

#if ENABLE(ASYNC_SCROLLING)
m_webPageProxy.scrollingCoordinatorProxy()->applyScrollingTreeLayerPositionsAfterCommit();
#endif
}

void RemoteLayerTreeDrawingAreaProxy::willCommitLayerTree(TransactionID transactionID)
void RemoteLayerTreeDrawingAreaProxy::willCommitLayerTree(IPC::Connection& connection, TransactionID transactionID)
{
if (transactionID <= m_lastLayerTreeTransactionID)
ProcessState& state = processStateForConnection(connection);
if (transactionID <= state.lastLayerTreeTransactionID)
return;

m_pendingLayerTreeTransactionID = transactionID;
state.pendingLayerTreeTransactionID = transactionID;
}

void RemoteLayerTreeDrawingAreaProxy::commitLayerTree(IPC::Connection& connection, const Vector<std::pair<RemoteLayerTreeTransaction, RemoteScrollingCoordinatorTransaction>>& transactions)
Expand All @@ -182,25 +209,32 @@
// prematurely drop the only reference to them, and `inUse` will be wrong for a brief window.
if (!sendRights.isEmpty())
[CATransaction addCommitHandler:[sendRights = WTFMove(sendRights)]() { } forPhase:kCATransactionPhasePostCommit];

ProcessState& state = processStateForConnection(connection);
if (std::exchange(state.commitLayerTreeMessageState, NeedsDisplayDidRefresh) == MissedCommit)
didRefreshDisplay(&connection);

scheduleDisplayRefreshCallbacks();
}

void RemoteLayerTreeDrawingAreaProxy::commitLayerTreeTransaction(IPC::Connection& connection, const RemoteLayerTreeTransaction& layerTreeTransaction, const RemoteScrollingCoordinatorTransaction& scrollingTreeTransaction)
{
TraceScope tracingScope(CommitLayerTreeStart, CommitLayerTreeEnd);
ProcessState& state = processStateForConnection(connection);

LOG_WITH_STREAM(RemoteLayerTree, stream << "RemoteLayerTreeDrawingAreaProxy::commitLayerTree transaction:" << layerTreeTransaction.description());
LOG_WITH_STREAM(RemoteLayerTree, stream << "RemoteLayerTreeDrawingAreaProxy::commitLayerTree scrolling tree:" << scrollingTreeTransaction.description());

m_lastLayerTreeTransactionID = layerTreeTransaction.transactionID();
if (m_pendingLayerTreeTransactionID < m_lastLayerTreeTransactionID)
m_pendingLayerTreeTransactionID = m_lastLayerTreeTransactionID;
state.lastLayerTreeTransactionID = layerTreeTransaction.transactionID();
if (state.pendingLayerTreeTransactionID < state.lastLayerTreeTransactionID)
state.pendingLayerTreeTransactionID = state.lastLayerTreeTransactionID;

bool didUpdateEditorState { false };
if (layerTreeTransaction.isMainFrameProcessTransaction()) {
ASSERT(layerTreeTransaction.transactionID() == m_lastVisibleTransactionID.next());
m_transactionIDForPendingCACommit = layerTreeTransaction.transactionID();
m_activityStateChangeID = layerTreeTransaction.activityStateChangeID();
ASSERT(layerTreeTransaction.transactionID() == state.lastVisibleTransactionID.next());
state.transactionIDForPendingCACommit = layerTreeTransaction.transactionID();
state.activityStateChangeID = layerTreeTransaction.activityStateChangeID();

didUpdateEditorState = layerTreeTransaction.hasEditorState() && m_webPageProxy.updateEditorState(layerTreeTransaction.editorState(), WebPageProxy::ShouldMergeVisualEditorState::Yes);
}

Expand All @@ -213,7 +247,7 @@
++m_countOfTransactionsWithNonEmptyLayerChanges;

if (m_remoteLayerTreeHost->updateLayerTree(layerTreeTransaction)) {
if (layerTreeTransaction.transactionID() >= m_transactionIDForUnhidingContent)
if (layerTreeTransaction.transactionID() >= state.transactionIDForUnhidingContent)
m_webPageProxy.setRemoteLayerTreeRootNode(m_remoteLayerTreeHost->rootNode());
else
m_remoteLayerTreeHost->detachRootLayer();
Expand Down Expand Up @@ -265,13 +299,6 @@

m_webPageProxy.layerTreeCommitComplete();

if (!layerTreeTransaction.isMainFrameProcessTransaction())
connection.send(Messages::DrawingArea::DisplayDidRefresh(), m_identifier);
else if (std::exchange(m_commitLayerTreeMessageState, NeedsDisplayDidRefresh) == MissedCommit)
didRefreshDisplay();

scheduleDisplayRefreshCallbacks();

if (didUpdateEditorState)
m_webPageProxy.dispatchDidUpdateEditorState();

Expand Down Expand Up @@ -419,30 +446,67 @@
}
}

bool RemoteLayerTreeDrawingAreaProxy::maybePauseDisplayRefreshCallbacks()
{
if (m_webPageProxyProcessState.commitLayerTreeMessageState == NeedsDisplayDidRefresh)
return false;

for (auto pair : m_remotePageProcessState) {
if (pair.value.commitLayerTreeMessageState == NeedsDisplayDidRefresh)
return false;
}

pauseDisplayRefreshCallbacks();
return true;
}

void RemoteLayerTreeDrawingAreaProxy::didRefreshDisplay()
{
if (!m_webPageProxy.hasRunningProcess())
return;
didRefreshDisplay(nullptr);
}

if (m_commitLayerTreeMessageState != NeedsDisplayDidRefresh) {
if (m_commitLayerTreeMessageState == CommitLayerTreePending)
m_commitLayerTreeMessageState = MissedCommit;
pauseDisplayRefreshCallbacks();
void RemoteLayerTreeDrawingAreaProxy::didRefreshDisplay(ProcessState& state, IPC::Connection& connection)
{
if (state.commitLayerTreeMessageState != NeedsDisplayDidRefresh) {
if (state.commitLayerTreeMessageState == CommitLayerTreePending)
state.commitLayerTreeMessageState = MissedCommit;
return;
}

m_commitLayerTreeMessageState = CommitLayerTreePending;

m_webPageProxy.scrollingCoordinatorProxy()->sendScrollingTreeNodeDidScroll();
state.commitLayerTreeMessageState = CommitLayerTreePending;

if (m_webPageProxy.process().connection() == &connection)
m_webPageProxy.scrollingCoordinatorProxy()->sendScrollingTreeNodeDidScroll();

// Waiting for CA to commit is insufficient, because the render server can still be
// using our backing store. We can improve this by waiting for the render server to commit
// if we find API to do so, but for now we will make extra buffers if need be.
m_webPageProxy.send(Messages::DrawingArea::DisplayDidRefresh(), m_identifier);
connection.send(Messages::DrawingArea::DisplayDidRefresh(), m_identifier);

#if ASSERT_ENABLED
m_lastVisibleTransactionID = m_transactionIDForPendingCACommit;
state.lastVisibleTransactionID = state.transactionIDForPendingCACommit;
#endif
}

void RemoteLayerTreeDrawingAreaProxy::didRefreshDisplay(IPC::Connection* connection)
{
if (!m_webPageProxy.hasRunningProcess())
return;

if (maybePauseDisplayRefreshCallbacks())
return;

if (connection) {
ProcessState& state = processStateForConnection(*connection);
didRefreshDisplay(state, *connection);
} else {
if (m_webPageProxy.process().hasConnection())
didRefreshDisplay(m_webPageProxyProcessState, *m_webPageProxy.process().connection());
for (auto pair : m_remotePageProcessState) {
if (pair.key.process().hasConnection())
didRefreshDisplay(pair.value, *pair.key.process().connection());
}
}

m_webPageProxy.didUpdateActivityState();
}
Expand All @@ -451,10 +515,15 @@
{
ASSERT(activityStateChangeID != ActivityStateChangeAsynchronous);

if (!process.hasConnection())
return;

ProcessState& state = processStateForConnection(*process.connection());

// We must send the didUpdate message before blocking on the next commit, otherwise
// we can be guaranteed that the next commit won't come until after the waitForAndDispatchImmediately times out.
if (m_commitLayerTreeMessageState == NeedsDisplayDidRefresh)
didRefreshDisplay();
if (state.commitLayerTreeMessageState == NeedsDisplayDidRefresh)
didRefreshDisplay(process.connection());

static Seconds activityStateUpdateTimeout = [] {
if (id value = [[NSUserDefaults standardUserDefaults] objectForKey:@"WebKitOverrideActivityStateUpdateTimeout"])
Expand All @@ -465,14 +534,14 @@
WeakPtr weakThis { *this };
auto startTime = MonotonicTime::now();
while (process.connection()->waitForAndDispatchImmediately<Messages::RemoteLayerTreeDrawingAreaProxy::CommitLayerTree>(m_identifier, activityStateUpdateTimeout - (MonotonicTime::now() - startTime), IPC::WaitForOption::InterruptWaitingIfSyncMessageArrives) == IPC::Error::NoError) {
if (!weakThis || activityStateChangeID == ActivityStateChangeAsynchronous || activityStateChangeID <= m_activityStateChangeID)
if (!weakThis || activityStateChangeID == ActivityStateChangeAsynchronous || activityStateChangeID <= state.activityStateChangeID)
return;
}
}

void RemoteLayerTreeDrawingAreaProxy::hideContentUntilPendingUpdate()
{
m_transactionIDForUnhidingContent = nextLayerTreeTransactionID();
m_webPageProxyProcessState.transactionIDForUnhidingContent = nextLayerTreeTransactionID();
m_remoteLayerTreeHost->detachRootLayer();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ - (void)displayLinkFired:(CADisplayLink *)sender
- (void)timerFired
{
ASSERT(isUIThread());
_drawingAreaProxy->didRefreshDisplay();
_drawingAreaProxy->didRefreshDisplay(nullptr);
}
#endif // ENABLE(TIMER_DRIVEN_DISPLAY_REFRESH_FOR_TESTING)

Expand Down
3 changes: 3 additions & 0 deletions Source/WebKit/UIProcess/RemotePageDrawingAreaProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ RemotePageDrawingAreaProxy::RemotePageDrawingAreaProxy(DrawingAreaProxy& drawing
{
for (auto& name : m_names)
process.addMessageReceiver(name, m_identifier, *this);
drawingArea.addRemotePageDrawingAreaProxy(*this);
}

RemotePageDrawingAreaProxy::~RemotePageDrawingAreaProxy()
{
for (auto& name : m_names)
m_process->removeMessageReceiver(name, m_identifier);
if (m_drawingArea)
m_drawingArea->removeRemotePageDrawingAreaProxy(*this);
}

void RemotePageDrawingAreaProxy::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
Expand Down
Loading

0 comments on commit f754a3d

Please sign in to comment.