Bug 1955005 - Make the old state transaction render immediately and offscreen. r=emilio

The main goal of this patch is to ensure that we render the snapshots as
soon as the transaction is received on the WebRender to prevent another
transaction within the same vsync interval from replacing the old
state's transaction before it has had a chance to produce the snapshots.

In addition, we produce the snapshots by generating a frame that isn't
presented to the window. This is to avoid potential vsync issues from
trying to present multiple times in the same interval and avoids a fair
amount of wasted work.

Differential Revision: https://phabricator.services.mozilla.com/D242358
This commit is contained in:
Nicolas Silva
2025-03-25 12:35:46 +00:00
parent b455b5a4a3
commit 1cf52d3337
13 changed files with 51 additions and 18 deletions

View File

@@ -53,7 +53,8 @@ parent:
bool containsSVGGroup,
VsyncId vsyncId, TimeStamp vsyncStartTime,
TimeStamp refreshStartTime, TimeStamp txnStartTime, nsCString txnURL, TimeStamp fwdTime,
CompositionPayload[] payloads);
CompositionPayload[] payloads,
bool renderOffscreen);
async EmptyTransaction(FocusTarget focusTarget,
MaybeTransactionData transationData,
OpDestroy[] toDestroy, uint64_t fwdTransactionId, TransactionId transactionId,

View File

@@ -106,7 +106,7 @@ void WebRenderBridgeChild::UpdateResources(
bool WebRenderBridgeChild::EndTransaction(
DisplayListData&& aDisplayListData, TransactionId aTransactionId,
bool aContainsSVGGroup, const mozilla::VsyncId& aVsyncId,
const mozilla::TimeStamp& aVsyncStartTime,
bool aRenderOffscreen, const mozilla::TimeStamp& aVsyncStartTime,
const mozilla::TimeStamp& aRefreshStartTime,
const mozilla::TimeStamp& aTxnStartTime, const nsCString& aTxnURL) {
MOZ_ASSERT(!mDestroyed);
@@ -126,7 +126,8 @@ bool WebRenderBridgeChild::EndTransaction(
bool ret = this->SendSetDisplayList(
std::move(aDisplayListData), mDestroyedActors, GetFwdTransactionId(),
aTransactionId, aContainsSVGGroup, aVsyncId, aVsyncStartTime,
aRefreshStartTime, aTxnStartTime, aTxnURL, fwdTime, payloads);
aRefreshStartTime, aTxnStartTime, aTxnURL, fwdTime, payloads,
aRenderOffscreen);
// With multiple render roots, we may not have sent all of our
// mParentCommands, so go ahead and go through our mParentCommands and ensure

View File

@@ -71,7 +71,7 @@ class WebRenderBridgeChild final : public PWebRenderBridgeChild,
void BeginTransaction();
bool EndTransaction(DisplayListData&& aDisplayListData,
TransactionId aTransactionId, bool aContainsSVGroup,
const mozilla::VsyncId& aVsyncId,
const mozilla::VsyncId& aVsyncId, bool aRenderOffscreen,
const mozilla::TimeStamp& aVsyncStartTime,
const mozilla::TimeStamp& aRefreshStartTime,
const mozilla::TimeStamp& aTxnStartTime,

View File

@@ -1188,7 +1188,8 @@ bool WebRenderBridgeParent::SetDisplayList(
bool WebRenderBridgeParent::ProcessDisplayListData(
DisplayListData& aDisplayList, wr::Epoch aWrEpoch,
const TimeStamp& aTxnStartTime, bool aValidTransaction) {
const TimeStamp& aTxnStartTime, bool aValidTransaction,
bool aRenderOffscreen, const VsyncId& aVsyncId) {
wr::TransactionBuilder txn(mApi, /* aUseSceneBuilderThread */ true,
mRemoteTextureTxnScheduler, mFwdTransactionId);
Maybe<wr::AutoTransactionSender> sender;
@@ -1215,6 +1216,13 @@ bool WebRenderBridgeParent::ProcessDisplayListData(
UpdateAPZScrollData(aWrEpoch, std::move(aDisplayList.mScrollData.ref()));
}
if (aRenderOffscreen) {
TimeStamp start = TimeStamp::Now();
txn.GenerateFrame(aVsyncId, false, wr::RenderReasons::SNAPSHOT);
wr::RenderThread::Get()->IncPendingFrameCount(mApi->GetId(), aVsyncId,
start);
}
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
sender.emplace(mApi, &txn);
bool success = true;
@@ -1242,7 +1250,8 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList(
const bool& aContainsSVGGroup, const VsyncId& aVsyncId,
const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
const TimeStamp& aTxnStartTime, const nsACString& aTxnURL,
const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads) {
const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads,
const bool& aRenderOffscreen) {
if (mDestroyed) {
for (const auto& op : aToDestroy) {
DestroyActor(op);
@@ -1282,8 +1291,9 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList(
}
bool validTransaction = aDisplayList.mIdNamespace == mIdNamespace;
bool success = ProcessDisplayListData(aDisplayList, wrEpoch, aTxnStartTime,
validTransaction);
bool success =
ProcessDisplayListData(aDisplayList, wrEpoch, aTxnStartTime,
validTransaction, aRenderOffscreen, aVsyncId);
if (!IsRootWebRenderBridgeParent()) {
aPayloads.AppendElement(

View File

@@ -120,8 +120,8 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
const bool& aContainsSVGGroup, const VsyncId& aVsyncId,
const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
const TimeStamp& aTxnStartTime, const nsACString& aTxnURL,
const TimeStamp& aFwdTime,
nsTArray<CompositionPayload>&& aPayloads) override;
const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads,
const bool& aRenderOffscreen) override;
mozilla::ipc::IPCResult RecvEmptyTransaction(
const FocusTarget& aFocusTarget,
Maybe<TransactionData>&& aTransactionData,
@@ -327,7 +327,8 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
bool ProcessDisplayListData(DisplayListData& aDisplayList, wr::Epoch aWrEpoch,
const TimeStamp& aTxnStartTime,
bool aValidTransaction);
bool aValidTransaction, bool aRenderOffscreen,
const VsyncId& aVsyncId);
bool SetDisplayList(const LayoutDeviceRect& aRect, ipc::ByteBuf&& aDLItems,
ipc::ByteBuf&& aDLCache, ipc::ByteBuf&& aSpatialTreeDL,

View File

@@ -331,7 +331,7 @@ bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) {
void WebRenderLayerManager::EndTransactionWithoutLayer(
nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
WrFiltersHolder&& aFilters, WebRenderBackgroundData* aBackground,
const double aGeckoDLBuildTime) {
const double aGeckoDLBuildTime, bool aRenderOffscreen) {
AUTO_PROFILER_TRACING_MARKER("Paint", "WrDisplayList", GRAPHICS);
auto clearTarget = MakeScopeExit([&] { mTarget = nullptr; });
@@ -460,7 +460,7 @@ void WebRenderLayerManager::EndTransactionWithoutLayer(
duration);
bool ret = WrBridge()->EndTransaction(
std::move(dlData), mLatestTransactionId, containsSVGGroup,
mTransactionIdAllocator->GetVsyncId(),
mTransactionIdAllocator->GetVsyncId(), aRenderOffscreen,
mTransactionIdAllocator->GetVsyncStart(), refreshStart,
mTransactionStart, mURL);
if (!ret) {

View File

@@ -87,7 +87,8 @@ class WebRenderLayerManager final : public WindowRenderer {
nsDisplayListBuilder* aDisplayListBuilder,
WrFiltersHolder&& aFilters,
WebRenderBackgroundData* aBackground,
const double aGeckoDLBuildTime);
const double aGeckoDLBuildTime,
bool aRenderOffscreen);
LayersBackend GetBackendType() override { return LayersBackend::LAYERS_WR; }
void GetBackendName(nsAString& name) override;

View File

@@ -6544,6 +6544,9 @@ void PresShell::PaintAndRequestComposite(nsView* aView, PaintFlags aFlags) {
if (aFlags & PaintFlags::PaintSyncDecodeImages) {
flags |= PaintInternalFlags::PaintSyncDecodeImages;
}
if (aFlags & PaintFlags::PaintCompositeOffscreen) {
flags |= PaintInternalFlags::PaintCompositeOffscreen;
}
PaintInternal(aView, flags);
}
@@ -6634,6 +6637,9 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
mIsFirstPaint = false;
}
const bool offscreen =
bool(aFlags & PaintInternalFlags::PaintCompositeOffscreen);
if (!renderer->BeginTransaction(url)) {
return;
}
@@ -6673,6 +6679,9 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
StaticPrefs::image_testing_decode_sync_enabled()) {
flags |= PaintFrameFlags::SyncDecodeImages;
}
if (aFlags & PaintInternalFlags::PaintCompositeOffscreen) {
flags |= PaintFrameFlags::CompositeOffscreen;
}
if (renderer->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
flags |= PaintFrameFlags::ForWebRender;
}
@@ -6695,8 +6704,8 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
WrFiltersHolder wrFilters;
layerManager->SetTransactionIdAllocator(presContext->RefreshDriver());
layerManager->EndTransactionWithoutLayer(nullptr, nullptr,
std::move(wrFilters), &data, 0);
layerManager->EndTransactionWithoutLayer(
nullptr, nullptr, std::move(wrFilters), &data, 0, offscreen);
return;
}

View File

@@ -192,6 +192,8 @@ enum class PaintFlags {
None = 0,
/* Sync-decode images. */
PaintSyncDecodeImages = 1 << 1,
/* Render without presenting to the window */
PaintCompositeOffscreen = 1 << 2,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PaintFlags)
@@ -202,6 +204,8 @@ enum class PaintInternalFlags {
PaintSyncDecodeImages = 1 << 1,
/* Composite layers to the window. */
PaintComposite = 1 << 2,
/* Render without presenting to the window */
PaintCompositeOffscreen = 1 << 3,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PaintInternalFlags)

View File

@@ -3267,6 +3267,9 @@ void nsLayoutUtils::PaintFrame(gfxContext* aRenderingContext, nsIFrame* aFrame,
PrintHitTestInfoStats(list);
}
#endif
if (aFlags & PaintFrameFlags::CompositeOffscreen) {
flags |= nsDisplayList::PAINT_COMPOSITE_OFFSCREEN;
}
TimeStamp paintStart = TimeStamp::Now();
list->PaintRoot(builder, aRenderingContext, flags, Some(geckoDLBuildTime));

View File

@@ -1124,6 +1124,7 @@ class nsLayoutUtils {
ForWebRender = 0x100,
UseHighQualityScaling = 0x200,
ResetViewportScrolling = 0x400,
CompositeOffscreen = 0x800,
};
/**

View File

@@ -2299,7 +2299,8 @@ void nsDisplayList::PaintRoot(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
wrManager->EndTransactionWithoutLayer(this, aBuilder,
std::move(wrFilters), nullptr,
aDisplayListBuildTime.valueOr(0.0));
aDisplayListBuildTime.valueOr(0.0),
aFlags & PAINT_COMPOSITE_OFFSCREEN);
}
if (presContext->RefreshDriver()->HasScheduleFlush()) {

View File

@@ -3259,7 +3259,8 @@ class nsDisplayList {
PAINT_DEFAULT = 0,
PAINT_USE_WIDGET_LAYERS = 0x01,
PAINT_EXISTING_TRANSACTION = 0x04,
PAINT_IDENTICAL_DISPLAY_LIST = 0x08
PAINT_IDENTICAL_DISPLAY_LIST = 0x08,
PAINT_COMPOSITE_OFFSCREEN = 0x10
};
void PaintRoot(nsDisplayListBuilder* aBuilder, gfxContext* aCtx,
uint32_t aFlags, Maybe<double> aDisplayListBuildTime);