Bug 1690619 - Keep track of where the request to rendering something comes from. r=gfx-reviewers,mstange

This patch adds plumbing to keep track of why we request frames to be rendered.
This information is then displayed in gecko profile markers on the renderer thread as well as in profiler HUD counters (See "Render reasons" in profiler.rs).

Differential Revision: https://phabricator.services.mozilla.com/D127274
This commit is contained in:
Nicolas Silva 2021-10-05 12:54:39 +00:00
Родитель aef746fa2f
Коммит cb6ac0df62
45 изменённых файлов: 392 добавлений и 187 удалений

Просмотреть файл

@ -21,7 +21,7 @@ class CompositorController {
/** /**
* Ask the compositor to schedule a new composite. * Ask the compositor to schedule a new composite.
*/ */
virtual void ScheduleRenderOnCompositorThread() = 0; virtual void ScheduleRenderOnCompositorThread(wr::RenderReasons aReasons) = 0;
protected: protected:
virtual ~CompositorController() = default; virtual ~CompositorController() = default;

Просмотреть файл

@ -723,7 +723,8 @@ void APZCTreeManager::SampleForWebRender(const Maybe<VsyncId>& aVsyncId,
bool activeAnimations = AdvanceAnimationsInternal(lock, aSampleTime); bool activeAnimations = AdvanceAnimationsInternal(lock, aSampleTime);
if (activeAnimations && controller) { if (activeAnimations && controller) {
controller->ScheduleRenderOnCompositorThread(); controller->ScheduleRenderOnCompositorThread(
wr::RenderReasons::ANIMATED_PROPERTY);
} }
nsTArray<wr::WrTransformProperty> transforms; nsTArray<wr::WrTransformProperty> transforms;

Просмотреть файл

@ -4168,7 +4168,8 @@ const ScreenMargin AsyncPanZoomController::CalculatePendingDisplayPort(
void AsyncPanZoomController::ScheduleComposite() { void AsyncPanZoomController::ScheduleComposite() {
if (mCompositorController) { if (mCompositorController) {
mCompositorController->ScheduleRenderOnCompositorThread(); mCompositorController->ScheduleRenderOnCompositorThread(
wr::RenderReasons::APZ);
} }
} }

Просмотреть файл

@ -52,7 +52,7 @@ static bool ScheduleComposition(CompositableHost* aCompositable) {
if (!cp) { if (!cp) {
return false; return false;
} }
cp->ScheduleComposition(); cp->ScheduleComposition(wr::RenderReasons::ASYNC_IMAGE);
return true; return true;
} }

Просмотреть файл

@ -395,11 +395,12 @@ bool CompositorBridgeChild::SendAdoptChild(const LayersId& id) {
return PCompositorBridgeChild::SendAdoptChild(id); return PCompositorBridgeChild::SendAdoptChild(id);
} }
bool CompositorBridgeChild::SendFlushRendering() { bool CompositorBridgeChild::SendFlushRendering(
const wr::RenderReasons& aReasons) {
if (!mCanSend) { if (!mCanSend) {
return false; return false;
} }
return PCompositorBridgeChild::SendFlushRendering(); return PCompositorBridgeChild::SendFlushRendering(aReasons);
} }
bool CompositorBridgeChild::SendStartFrameTimeRecording( bool CompositorBridgeChild::SendStartFrameTimeRecording(

Просмотреть файл

@ -126,7 +126,7 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
bool SendResume(); bool SendResume();
bool SendResumeAsync(); bool SendResumeAsync();
bool SendAdoptChild(const LayersId& id); bool SendAdoptChild(const LayersId& id);
bool SendFlushRendering(); bool SendFlushRendering(const wr::RenderReasons& aReasons);
bool SendStartFrameTimeRecording(const int32_t& bufferSize, bool SendStartFrameTimeRecording(const int32_t& bufferSize,
uint32_t* startIndex); uint32_t* startIndex);
bool SendStopFrameTimeRecording(const uint32_t& startIndex, bool SendStopFrameTimeRecording(const uint32_t& startIndex,

Просмотреть файл

@ -505,31 +505,34 @@ CompositorBridgeParent::RecvWaitOnTransactionProcessed() {
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRendering() { mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRendering(
const wr::RenderReasons& aReasons) {
if (mWrBridge) { if (mWrBridge) {
mWrBridge->FlushRendering(); mWrBridge->FlushRendering(aReasons);
return IPC_OK(); return IPC_OK();
} }
if (mCompositorScheduler->NeedsComposite()) { if (mCompositorScheduler->NeedsComposite()) {
CancelCurrentCompositeTask(); CancelCurrentCompositeTask();
ForceComposeToTarget(nullptr); ForceComposeToTarget(aReasons, nullptr, nullptr);
} }
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRenderingAsync() { mozilla::ipc::IPCResult CompositorBridgeParent::RecvFlushRenderingAsync(
const wr::RenderReasons& aReasons) {
if (mWrBridge) { if (mWrBridge) {
mWrBridge->FlushRendering(false); mWrBridge->FlushRendering(aReasons, false);
return IPC_OK(); return IPC_OK();
} }
return RecvFlushRendering(); return RecvFlushRendering(aReasons);
} }
mozilla::ipc::IPCResult CompositorBridgeParent::RecvForcePresent() { mozilla::ipc::IPCResult CompositorBridgeParent::RecvForcePresent(
const wr::RenderReasons& aReasons) {
if (mWrBridge) { if (mWrBridge) {
mWrBridge->ScheduleForcedGenerateFrame(); mWrBridge->ScheduleForcedGenerateFrame(aReasons);
} }
return IPC_OK(); return IPC_OK();
} }
@ -576,11 +579,12 @@ void CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) {
&CompositorBridgeParent::DeferredDestroy)); &CompositorBridgeParent::DeferredDestroy));
} }
void CompositorBridgeParent::ScheduleRenderOnCompositorThread() { void CompositorBridgeParent::ScheduleRenderOnCompositorThread(
wr::RenderReasons aReasons) {
MOZ_ASSERT(CompositorThread()); MOZ_ASSERT(CompositorThread());
CompositorThread()->Dispatch( CompositorThread()->Dispatch(NewRunnableMethod<wr::RenderReasons>(
NewRunnableMethod("layers::CompositorBridgeParent::ScheduleComposition", "layers::CompositorBridgeParent::ScheduleComposition", this,
this, &CompositorBridgeParent::ScheduleComposition)); &CompositorBridgeParent::ScheduleComposition, aReasons));
} }
void CompositorBridgeParent::PauseComposition() { void CompositorBridgeParent::PauseComposition() {
@ -631,17 +635,18 @@ void CompositorBridgeParent::ResumeComposition() {
mPaused = false; mPaused = false;
Invalidate(); Invalidate();
mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr); mCompositorScheduler->ForceComposeToTarget(wr::RenderReasons::WIDGET, nullptr,
nullptr);
// if anyone's waiting to make sure that composition really got resumed, tell // if anyone's waiting to make sure that composition really got resumed, tell
// them // them
lock.NotifyAll(); lock.NotifyAll();
} }
void CompositorBridgeParent::ForceComposition() { void CompositorBridgeParent::ForceComposition(wr::RenderReasons aReasons) {
// Cancel the orientation changed state to force composition // Cancel the orientation changed state to force composition
mForceCompositionTask = nullptr; mForceCompositionTask = nullptr;
ScheduleRenderOnCompositorThread(); ScheduleRenderOnCompositorThread(aReasons);
} }
void CompositorBridgeParent::CancelCurrentCompositeTask() { void CompositorBridgeParent::CancelCurrentCompositeTask() {
@ -673,30 +678,31 @@ void CompositorBridgeParent::NotifyShadowTreeTransaction(
bool aScheduleComposite, uint32_t aPaintSequenceNumber, bool aScheduleComposite, uint32_t aPaintSequenceNumber,
bool aIsRepeatTransaction, bool aHitTestUpdate) { bool aIsRepeatTransaction, bool aHitTestUpdate) {
if (aScheduleComposite) { if (aScheduleComposite) {
ScheduleComposition(); ScheduleComposition(wr::RenderReasons::OTHER);
} }
} }
void CompositorBridgeParent::ScheduleComposition() { void CompositorBridgeParent::ScheduleComposition(wr::RenderReasons aReasons) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
if (mPaused) { if (mPaused) {
return; return;
} }
if (mWrBridge) { if (mWrBridge) {
mWrBridge->ScheduleGenerateFrame(); mWrBridge->ScheduleGenerateFrame(aReasons);
} else { } else {
mCompositorScheduler->ScheduleComposition(); mCompositorScheduler->ScheduleComposition(aReasons);
} }
} }
void CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget, void CompositorBridgeParent::ForceComposeToTarget(wr::RenderReasons aReasons,
DrawTarget* aTarget,
const gfx::IntRect* aRect) { const gfx::IntRect* aRect) {
AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget", GRAPHICS); AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget", GRAPHICS);
AutoRestore<bool> override(mOverrideComposeReadiness); AutoRestore<bool> override(mOverrideComposeReadiness);
mOverrideComposeReadiness = true; mOverrideComposeReadiness = true;
mCompositorScheduler->ForceComposeToTarget(aTarget, aRect); mCompositorScheduler->ForceComposeToTarget(aReasons, aTarget, aRect);
} }
PAPZCTreeManagerParent* CompositorBridgeParent::AllocPAPZCTreeManagerParent( PAPZCTreeManagerParent* CompositorBridgeParent::AllocPAPZCTreeManagerParent(
@ -837,7 +843,7 @@ bool CompositorBridgeParent::SetTestSampleTime(const LayersId& aId,
} }
if (mWrBridge) { if (mWrBridge) {
mWrBridge->FlushRendering(); mWrBridge->FlushRendering(wr::RenderReasons::TESTING);
return true; return true;
} }
@ -950,7 +956,7 @@ void CompositorBridgeParent::SetFixedLayerMargins(ScreenIntCoord aTop,
} }
Invalidate(); Invalidate();
ScheduleComposition(); ScheduleComposition(wr::RenderReasons::RESIZE);
} }
CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent( CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent(
@ -1003,7 +1009,7 @@ void CompositorBridgeParent::NotifyVsync(const VsyncEvent& aVsync,
/* static */ /* static */
void CompositorBridgeParent::ScheduleForcedComposition( void CompositorBridgeParent::ScheduleForcedComposition(
const LayersId& aLayersId) { const LayersId& aLayersId, wr::RenderReasons aReasons) {
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU); MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
@ -1019,9 +1025,9 @@ void CompositorBridgeParent::ScheduleForcedComposition(
} }
if (cbp->mWrBridge) { if (cbp->mWrBridge) {
cbp->mWrBridge->ScheduleForcedGenerateFrame(); cbp->mWrBridge->ScheduleForcedGenerateFrame(aReasons);
} else if (cbp->CanComposite()) { } else if (cbp->CanComposite()) {
cbp->mCompositorScheduler->ScheduleComposition(); cbp->mCompositorScheduler->ScheduleComposition(aReasons);
} }
} }
@ -1090,7 +1096,6 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild(
const LayersId& child) { const LayersId& child) {
RefPtr<APZUpdater> oldApzUpdater; RefPtr<APZUpdater> oldApzUpdater;
APZCTreeManagerParent* parent; APZCTreeManagerParent* parent;
bool scheduleComposition = false;
bool apzEnablementChanged = false; bool apzEnablementChanged = false;
RefPtr<WebRenderBridgeParent> childWrBridge; RefPtr<WebRenderBridgeParent> childWrBridge;
@ -1142,10 +1147,6 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvAdoptChild(
parent = sIndirectLayerTrees[child].mApzcTreeManagerParent; parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
} }
if (scheduleComposition) {
ScheduleComposition();
}
if (childWrBridge) { if (childWrBridge) {
MOZ_ASSERT(mWrBridge); MOZ_ASSERT(mWrBridge);
RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI(); RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI();
@ -1643,7 +1644,7 @@ void CompositorBridgeParent::NotifyDidSceneBuild(
if (mWrBridge) { if (mWrBridge) {
mWrBridge->NotifyDidSceneBuild(aInfo); mWrBridge->NotifyDidSceneBuild(aInfo);
} else { } else {
mCompositorScheduler->ScheduleComposition(); mCompositorScheduler->ScheduleComposition(wr::RenderReasons::SCENE);
} }
} }

Просмотреть файл

@ -178,7 +178,8 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
MOZ_CRASH("Should only be called on ContentCompositorBridgeParent."); MOZ_CRASH("Should only be called on ContentCompositorBridgeParent.");
} }
virtual void ForceComposeToTarget(gfx::DrawTarget* aTarget, virtual void ForceComposeToTarget(wr::RenderReasons aReasons,
gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect = nullptr) { const gfx::IntRect* aRect = nullptr) {
MOZ_CRASH(); MOZ_CRASH();
} }
@ -219,8 +220,10 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
PCompositorWidgetParent* aActor) = 0; PCompositorWidgetParent* aActor) = 0;
virtual mozilla::ipc::IPCResult RecvAdoptChild(const LayersId& id) = 0; virtual mozilla::ipc::IPCResult RecvAdoptChild(const LayersId& id) = 0;
virtual mozilla::ipc::IPCResult RecvFlushRenderingAsync() = 0; virtual mozilla::ipc::IPCResult RecvFlushRenderingAsync(
virtual mozilla::ipc::IPCResult RecvForcePresent() = 0; const wr::RenderReasons& aReasons) = 0;
virtual mozilla::ipc::IPCResult RecvForcePresent(
const wr::RenderReasons& aReasons) = 0;
virtual mozilla::ipc::IPCResult RecvBeginRecording( virtual mozilla::ipc::IPCResult RecvBeginRecording(
const TimeStamp& aRecordingStart, BeginRecordingResolver&& aResolve) = 0; const TimeStamp& aRecordingStart, BeginRecordingResolver&& aResolve) = 0;
virtual mozilla::ipc::IPCResult RecvEndRecordingToDisk( virtual mozilla::ipc::IPCResult RecvEndRecordingToDisk(
@ -241,7 +244,8 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
CompositorOptions* compositorOptions) = 0; CompositorOptions* compositorOptions) = 0;
virtual mozilla::ipc::IPCResult RecvNotifyChildRecreated( virtual mozilla::ipc::IPCResult RecvNotifyChildRecreated(
const LayersId& id, CompositorOptions* compositorOptions) = 0; const LayersId& id, CompositorOptions* compositorOptions) = 0;
virtual mozilla::ipc::IPCResult RecvFlushRendering() = 0; virtual mozilla::ipc::IPCResult RecvFlushRendering(
const wr::RenderReasons& aReasons) = 0;
virtual mozilla::ipc::IPCResult RecvWaitOnTransactionProcessed() = 0; virtual mozilla::ipc::IPCResult RecvWaitOnTransactionProcessed() = 0;
virtual mozilla::ipc::IPCResult RecvStartFrameTimeRecording( virtual mozilla::ipc::IPCResult RecvStartFrameTimeRecording(
const int32_t& bufferSize, uint32_t* startIndex) = 0; const int32_t& bufferSize, uint32_t* startIndex) = 0;
@ -308,10 +312,13 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
mozilla::ipc::IPCResult RecvNotifyChildRecreated( mozilla::ipc::IPCResult RecvNotifyChildRecreated(
const LayersId& child, CompositorOptions* aOptions) override; const LayersId& child, CompositorOptions* aOptions) override;
mozilla::ipc::IPCResult RecvAdoptChild(const LayersId& child) override; mozilla::ipc::IPCResult RecvAdoptChild(const LayersId& child) override;
mozilla::ipc::IPCResult RecvFlushRendering() override; mozilla::ipc::IPCResult RecvFlushRendering(
mozilla::ipc::IPCResult RecvFlushRenderingAsync() override; const wr::RenderReasons& aReasons) override;
mozilla::ipc::IPCResult RecvFlushRenderingAsync(
const wr::RenderReasons& aReasons) override;
mozilla::ipc::IPCResult RecvWaitOnTransactionProcessed() override; mozilla::ipc::IPCResult RecvWaitOnTransactionProcessed() override;
mozilla::ipc::IPCResult RecvForcePresent() override; mozilla::ipc::IPCResult RecvForcePresent(
const wr::RenderReasons& aReasons) override;
mozilla::ipc::IPCResult RecvStartFrameTimeRecording( mozilla::ipc::IPCResult RecvStartFrameTimeRecording(
const int32_t& aBufferSize, uint32_t* aOutStartIndex) override; const int32_t& aBufferSize, uint32_t* aOutStartIndex) override;
@ -408,9 +415,9 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
void AsyncRender(); void AsyncRender();
// Can be called from any thread // Can be called from any thread
void ScheduleRenderOnCompositorThread() override; void ScheduleRenderOnCompositorThread(wr::RenderReasons aReasons) override;
void ScheduleComposition(); void ScheduleComposition(wr::RenderReasons aReasons);
void NotifyShadowTreeTransaction(LayersId aId, bool aIsFirstPaint, void NotifyShadowTreeTransaction(LayersId aId, bool aIsFirstPaint,
const FocusTarget& aFocusTarget, const FocusTarget& aFocusTarget,
@ -426,7 +433,8 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
void ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig, void ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig,
bool aIsFirstPaint); bool aIsFirstPaint);
static void ScheduleForcedComposition(const LayersId& aLayersId); static void ScheduleForcedComposition(const LayersId& aLayersId,
wr::RenderReasons aReasons);
/** /**
* Returns the unique layer tree identifier that corresponds to the root * Returns the unique layer tree identifier that corresponds to the root
@ -526,7 +534,8 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
widget::CompositorWidget* GetWidget() { return mWidget; } widget::CompositorWidget* GetWidget() { return mWidget; }
virtual void ForceComposeToTarget( virtual void ForceComposeToTarget(
gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override; wr::RenderReasons aReasons, gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect = nullptr) override;
PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent( PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(
const LayersId& aLayersId) override; const LayersId& aLayersId) override;
@ -648,7 +657,7 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
bool IsPaused() { return mPaused; } bool IsPaused() { return mPaused; }
protected: protected:
void ForceComposition(); void ForceComposition(wr::RenderReasons aReasons);
void CancelCurrentCompositeTask(); void CancelCurrentCompositeTask();
/** /**

Просмотреть файл

@ -69,10 +69,12 @@ CompositorVsyncScheduler::CompositorVsyncScheduler(
mLastVsyncTime(TimeStamp::Now()), mLastVsyncTime(TimeStamp::Now()),
mLastVsyncOutputTime(TimeStamp::Now()), mLastVsyncOutputTime(TimeStamp::Now()),
mIsObservingVsync(false), mIsObservingVsync(false),
mRendersDelayedByVsyncReasons(wr::RenderReasons::NONE),
mVsyncNotificationsSkipped(0), mVsyncNotificationsSkipped(0),
mWidget(aWidget), mWidget(aWidget),
mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor"), mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor"),
mCurrentCompositeTask(nullptr), mCurrentCompositeTask(nullptr),
mCurrentCompositeTaskReasons(wr::RenderReasons::NONE),
mCurrentVRTaskMonitor("CurrentVRTaskMonitor"), mCurrentVRTaskMonitor("CurrentVRTaskMonitor"),
mCurrentVRTask(nullptr) { mCurrentVRTask(nullptr) {
mVsyncObserver = new Observer(this); mVsyncObserver = new Observer(this);
@ -108,13 +110,15 @@ void CompositorVsyncScheduler::Destroy() {
CancelCurrentVRTask(); CancelCurrentVRTask();
} }
void CompositorVsyncScheduler::PostCompositeTask( void CompositorVsyncScheduler::PostCompositeTask(const VsyncEvent& aVsyncEvent,
const VsyncEvent& aVsyncEvent) { wr::RenderReasons aReasons) {
MonitorAutoLock lock(mCurrentCompositeTaskMonitor); MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
mCurrentCompositeTaskReasons = mCurrentCompositeTaskReasons | aReasons;
if (mCurrentCompositeTask == nullptr && CompositorThread()) { if (mCurrentCompositeTask == nullptr && CompositorThread()) {
RefPtr<CancelableRunnable> task = NewCancelableRunnableMethod<VsyncEvent>( RefPtr<CancelableRunnable> task =
"layers::CompositorVsyncScheduler::Composite", this, NewCancelableRunnableMethod<VsyncEvent, wr::RenderReasons>(
&CompositorVsyncScheduler::Composite, aVsyncEvent); "layers::CompositorVsyncScheduler::Composite", this,
&CompositorVsyncScheduler::Composite, aVsyncEvent, aReasons);
mCurrentCompositeTask = task; mCurrentCompositeTask = task;
CompositorThread()->Dispatch(task.forget()); CompositorThread()->Dispatch(task.forget());
} }
@ -131,7 +135,7 @@ void CompositorVsyncScheduler::PostVRTask(TimeStamp aTimestamp) {
} }
} }
void CompositorVsyncScheduler::ScheduleComposition() { void CompositorVsyncScheduler::ScheduleComposition(wr::RenderReasons aReasons) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
if (!mVsyncObserver) { if (!mVsyncObserver) {
// Destroy was already called on this object. // Destroy was already called on this object.
@ -146,7 +150,7 @@ void CompositorVsyncScheduler::ScheduleComposition() {
if (mAsapScheduling) { if (mAsapScheduling) {
// Used only for performance testing purposes, and when recording/replaying // Used only for performance testing purposes, and when recording/replaying
// to ensure that graphics are up to date. // to ensure that graphics are up to date.
PostCompositeTask(vsyncEvent); PostCompositeTask(vsyncEvent, aReasons);
} else { } else {
if (!mCompositeRequestedAt) { if (!mCompositeRequestedAt) {
mCompositeRequestedAt = TimeStamp::Now(); mCompositeRequestedAt = TimeStamp::Now();
@ -157,7 +161,9 @@ void CompositorVsyncScheduler::ScheduleComposition() {
// through the main thread of the UI process. It's possible that // through the main thread of the UI process. It's possible that
// we're blocking there waiting on a composite, so schedule an initial // we're blocking there waiting on a composite, so schedule an initial
// one now to get things started. // one now to get things started.
PostCompositeTask(vsyncEvent); PostCompositeTask(vsyncEvent, aReasons);
} else {
mRendersDelayedByVsyncReasons = aReasons;
} }
} }
} }
@ -188,10 +194,10 @@ bool CompositorVsyncScheduler::NotifyVsync(const VsyncEvent& aVsync) {
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
gfx::VRManager* vm = gfx::VRManager::Get(); gfx::VRManager* vm = gfx::VRManager::Get();
if (!vm->IsPresenting()) { if (!vm->IsPresenting()) {
PostCompositeTask(aVsync); PostCompositeTask(aVsync, wr::RenderReasons::VSYNC);
} }
#else #else
PostCompositeTask(aVsync); PostCompositeTask(aVsync, wr::RenderReasons::VSYNC);
#endif // defined(MOZ_WIDGET_ANDROID) #endif // defined(MOZ_WIDGET_ANDROID)
PostVRTask(aVsync.mTime); PostVRTask(aVsync.mTime);
@ -208,22 +214,31 @@ void CompositorVsyncScheduler::CancelCurrentVRTask() {
} }
} }
void CompositorVsyncScheduler::CancelCurrentCompositeTask() { wr::RenderReasons CompositorVsyncScheduler::CancelCurrentCompositeTask() {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() ||
NS_IsMainThread()); NS_IsMainThread());
MonitorAutoLock lock(mCurrentCompositeTaskMonitor); MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
wr::RenderReasons canceledTaskRenderReasons = mCurrentCompositeTaskReasons;
mCurrentCompositeTaskReasons = wr::RenderReasons::NONE;
if (mCurrentCompositeTask) { if (mCurrentCompositeTask) {
mCurrentCompositeTask->Cancel(); mCurrentCompositeTask->Cancel();
mCurrentCompositeTask = nullptr; mCurrentCompositeTask = nullptr;
} }
return canceledTaskRenderReasons;
} }
void CompositorVsyncScheduler::Composite(const VsyncEvent& aVsyncEvent) { void CompositorVsyncScheduler::Composite(const VsyncEvent& aVsyncEvent,
wr::RenderReasons aReasons) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
MOZ_ASSERT(mVsyncSchedulerOwner); MOZ_ASSERT(mVsyncSchedulerOwner);
{ // scope lock { // scope lock
MonitorAutoLock lock(mCurrentCompositeTaskMonitor); MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
aReasons =
aReasons | mCurrentCompositeTaskReasons | mRendersDelayedByVsyncReasons;
mCurrentCompositeTaskReasons = wr::RenderReasons::NONE;
mRendersDelayedByVsyncReasons = wr::RenderReasons::NONE;
mCurrentCompositeTask = nullptr; mCurrentCompositeTask = nullptr;
} }
@ -253,7 +268,8 @@ void CompositorVsyncScheduler::Composite(const VsyncEvent& aVsyncEvent) {
mLastComposeTime = SampleTime::FromVsync(aVsyncEvent.mTime); mLastComposeTime = SampleTime::FromVsync(aVsyncEvent.mTime);
// Tell the owner to do a composite // Tell the owner to do a composite
mVsyncSchedulerOwner->CompositeToTarget(aVsyncEvent.mId, nullptr, nullptr); mVsyncSchedulerOwner->CompositeToTarget(aVsyncEvent.mId, aReasons, nullptr,
nullptr);
mVsyncNotificationsSkipped = 0; mVsyncNotificationsSkipped = 0;
@ -267,7 +283,8 @@ void CompositorVsyncScheduler::Composite(const VsyncEvent& aVsyncEvent) {
} }
} }
void CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, void CompositorVsyncScheduler::ForceComposeToTarget(wr::RenderReasons aReasons,
gfx::DrawTarget* aTarget,
const IntRect* aRect) { const IntRect* aRect) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
@ -289,7 +306,7 @@ void CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget,
mLastComposeTime = SampleTime::FromNow(); mLastComposeTime = SampleTime::FromNow();
MOZ_ASSERT(mVsyncSchedulerOwner); MOZ_ASSERT(mVsyncSchedulerOwner);
mVsyncSchedulerOwner->CompositeToTarget(VsyncId(), aTarget, aRect); mVsyncSchedulerOwner->CompositeToTarget(VsyncId(), aReasons, aTarget, aRect);
} }
bool CompositorVsyncScheduler::NeedsComposite() { bool CompositorVsyncScheduler::NeedsComposite() {
@ -300,8 +317,8 @@ bool CompositorVsyncScheduler::NeedsComposite() {
bool CompositorVsyncScheduler::FlushPendingComposite() { bool CompositorVsyncScheduler::FlushPendingComposite() {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
if (mCompositeRequestedAt) { if (mCompositeRequestedAt) {
CancelCurrentCompositeTask(); wr::RenderReasons reasons = CancelCurrentCompositeTask();
ForceComposeToTarget(nullptr, nullptr); ForceComposeToTarget(reasons, nullptr, nullptr);
return true; return true;
} }
return false; return false;

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/TimeStamp.h" // for TimeStamp #include "mozilla/TimeStamp.h" // for TimeStamp
#include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/layers/SampleTime.h" #include "mozilla/layers/SampleTime.h"
#include "mozilla/webrender/webrender_ffi.h"
#include "mozilla/VsyncDispatcher.h" #include "mozilla/VsyncDispatcher.h"
#include "mozilla/widget/CompositorWidget.h" #include "mozilla/widget/CompositorWidget.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
@ -60,12 +61,14 @@ class CompositorVsyncScheduler {
* composition soon (likely at the next vsync). This must be called on the * composition soon (likely at the next vsync). This must be called on the
* compositor thread. * compositor thread.
*/ */
void ScheduleComposition(); void ScheduleComposition(wr::RenderReasons aReasons);
/** /**
* Cancel any composite task that has been scheduled but hasn't run yet. * Cancel any composite task that has been scheduled but hasn't run yet.
*
* Returns the render reasons of the canceled task if any.
*/ */
void CancelCurrentCompositeTask(); wr::RenderReasons CancelCurrentCompositeTask();
/** /**
* Check if a composite is pending. This is generally true between a call * Check if a composite is pending. This is generally true between a call
@ -77,7 +80,8 @@ class CompositorVsyncScheduler {
* Force a composite to happen right away, without waiting for the next vsync. * Force a composite to happen right away, without waiting for the next vsync.
* This must be called on the compositor thread. * This must be called on the compositor thread.
*/ */
void ForceComposeToTarget(gfx::DrawTarget* aTarget, void ForceComposeToTarget(wr::RenderReasons aReasons,
gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect); const gfx::IntRect* aRect);
/** /**
@ -113,7 +117,8 @@ class CompositorVsyncScheduler {
// Post a task to run Composite() on the compositor thread, if there isn't // Post a task to run Composite() on the compositor thread, if there isn't
// such a task already queued. Can be called from any thread. // such a task already queued. Can be called from any thread.
void PostCompositeTask(const VsyncEvent& aVsyncEvent); void PostCompositeTask(const VsyncEvent& aVsyncEvent,
wr::RenderReasons aReasons);
// Post a task to run DispatchVREvents() on the VR thread, if there isn't // Post a task to run DispatchVREvents() on the VR thread, if there isn't
// such a task already queued. Can be called from any thread. // such a task already queued. Can be called from any thread.
@ -126,7 +131,7 @@ class CompositorVsyncScheduler {
// This gets run at vsync time and "does" a composite (which really means // This gets run at vsync time and "does" a composite (which really means
// update internal state and call the owner to do the composite). // update internal state and call the owner to do the composite).
void Composite(const VsyncEvent& aVsyncEvent); void Composite(const VsyncEvent& aVsyncEvent, wr::RenderReasons aReasons);
void ObserveVsync(); void ObserveVsync();
void UnobserveVsync(); void UnobserveVsync();
@ -155,6 +160,8 @@ class CompositorVsyncScheduler {
bool mAsapScheduling; bool mAsapScheduling;
bool mIsObservingVsync; bool mIsObservingVsync;
// Accessed on the compositor thread.
wr::RenderReasons mRendersDelayedByVsyncReasons;
TimeStamp mCompositeRequestedAt; TimeStamp mCompositeRequestedAt;
int32_t mVsyncNotificationsSkipped; int32_t mVsyncNotificationsSkipped;
widget::CompositorWidget* mWidget; widget::CompositorWidget* mWidget;
@ -162,6 +169,8 @@ class CompositorVsyncScheduler {
mozilla::Monitor mCurrentCompositeTaskMonitor; mozilla::Monitor mCurrentCompositeTaskMonitor;
RefPtr<CancelableRunnable> mCurrentCompositeTask; RefPtr<CancelableRunnable> mCurrentCompositeTask;
// Accessed on multiple threads, guarded by mCurrentCompositeTaskMonitor.
wr::RenderReasons mCurrentCompositeTaskReasons;
mozilla::Monitor mCurrentVRTaskMonitor; mozilla::Monitor mCurrentVRTaskMonitor;
RefPtr<CancelableRunnable> mCurrentVRTask; RefPtr<CancelableRunnable> mCurrentVRTask;

Просмотреть файл

@ -8,6 +8,7 @@
#define mozilla_layers_CompositorVsyncSchedulerOwner_h #define mozilla_layers_CompositorVsyncSchedulerOwner_h
#include "mozilla/VsyncDispatcher.h" #include "mozilla/VsyncDispatcher.h"
#include "mozilla/webrender/webrender_ffi.h"
namespace mozilla { namespace mozilla {
@ -21,7 +22,8 @@ class CompositorVsyncSchedulerOwner {
public: public:
virtual bool IsPendingComposite() = 0; virtual bool IsPendingComposite() = 0;
virtual void FinishPendingComposite() = 0; virtual void FinishPendingComposite() = 0;
virtual void CompositeToTarget(VsyncId aId, gfx::DrawTarget* aTarget, virtual void CompositeToTarget(VsyncId aId, wr::RenderReasons aReasons,
gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect = nullptr) = 0; const gfx::IntRect* aRect = nullptr) = 0;
virtual TimeDuration GetVsyncInterval() const = 0; virtual TimeDuration GetVsyncInterval() const = 0;
}; };

Просмотреть файл

@ -61,11 +61,17 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
mozilla::ipc::IPCResult RecvAdoptChild(const LayersId& child) override { mozilla::ipc::IPCResult RecvAdoptChild(const LayersId& child) override {
return IPC_FAIL_NO_REASON(this); return IPC_FAIL_NO_REASON(this);
} }
mozilla::ipc::IPCResult RecvFlushRendering() override { return IPC_OK(); } mozilla::ipc::IPCResult RecvFlushRendering(
mozilla::ipc::IPCResult RecvFlushRenderingAsync() override { const wr::RenderReasons&) override {
return IPC_OK();
}
mozilla::ipc::IPCResult RecvFlushRenderingAsync(
const wr::RenderReasons&) override {
return IPC_OK();
}
mozilla::ipc::IPCResult RecvForcePresent(const wr::RenderReasons&) override {
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult RecvForcePresent() override { return IPC_OK(); }
mozilla::ipc::IPCResult RecvWaitOnTransactionProcessed() override { mozilla::ipc::IPCResult RecvWaitOnTransactionProcessed() override {
return IPC_OK(); return IPC_OK();
} }

Просмотреть файл

@ -39,6 +39,7 @@ using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h"; using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::IdNamespace from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::IdNamespace from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::RenderReasons from "mozilla/webrender/webrender_ffi.h";
using base::ProcessId from "base/process.h"; using base::ProcessId from "base/process.h";
using mozilla::wr::MaybeExternalImageId from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::MaybeExternalImageId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::layers::LayersObserverEpoch from "mozilla/layers/LayersTypes.h"; using mozilla::layers::LayersObserverEpoch from "mozilla/layers/LayersTypes.h";
@ -176,18 +177,18 @@ parent:
// Make sure any pending composites are started immediately and // Make sure any pending composites are started immediately and
// block until they are completed. // block until they are completed.
sync FlushRendering(); sync FlushRendering(RenderReasons aReasons);
// Same as FlushRendering, but asynchronous, since not all platforms require // Same as FlushRendering, but asynchronous, since not all platforms require
// synchronous repaints on resize. // synchronous repaints on resize.
async FlushRenderingAsync(); async FlushRenderingAsync(RenderReasons aReasons);
// Make sure any pending composites have been received. // Make sure any pending composites have been received.
sync WaitOnTransactionProcessed(); sync WaitOnTransactionProcessed();
// Force an additional frame presentation to be executed. This is used to // Force an additional frame presentation to be executed. This is used to
// work around a windows presentation bug (See Bug 1232042) // work around a windows presentation bug (See Bug 1232042)
async ForcePresent(); async ForcePresent(RenderReasons aReasons);
sync StartFrameTimeRecording(int32_t bufferSize) sync StartFrameTimeRecording(int32_t bufferSize)
returns (uint32_t startIndex); returns (uint32_t startIndex);

Просмотреть файл

@ -22,6 +22,7 @@ using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h
using mozilla::layers::CompositionPayload from "mozilla/layers/LayersTypes.h"; using mozilla::layers::CompositionPayload from "mozilla/layers/LayersTypes.h";
using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h"; using mozilla::layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
using mozilla::wr::BuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h"; using mozilla::wr::BuiltDisplayListDescriptor from "mozilla/webrender/webrender_ffi.h";
using mozilla::wr::RenderReasons from "mozilla/webrender/webrender_ffi.h";
using mozilla::wr::IdNamespace from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::IdNamespace from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::MaybeIdNamespace from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::MaybeIdNamespace from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ExternalImageKeyPair from "mozilla/webrender/WebRenderTypes.h"; using mozilla::wr::ExternalImageKeyPair from "mozilla/webrender/WebRenderTypes.h";
@ -70,7 +71,7 @@ parent:
// Invalidate rendered frame // Invalidate rendered frame
async InvalidateRenderedFrame(); async InvalidateRenderedFrame();
// Schedule a composite if one isn't already scheduled. // Schedule a composite if one isn't already scheduled.
async ScheduleComposite(); async ScheduleComposite(RenderReasons aReasons);
// Save the frame capture to disk // Save the frame capture to disk
async Capture(); async Capture();

Просмотреть файл

@ -95,7 +95,7 @@ UiCompositorControllerParent::RecvInvalidateAndRender() {
mRootLayerTreeId); mRootLayerTreeId);
if (parent) { if (parent) {
parent->Invalidate(); parent->Invalidate();
parent->ScheduleComposition(); parent->ScheduleComposition(wr::RenderReasons::OTHER);
} }
return IPC_OK(); return IPC_OK();
} }
@ -141,7 +141,7 @@ UiCompositorControllerParent::RecvRequestScreenPixels() {
if (state && state->mWrBridge) { if (state && state->mWrBridge) {
state->mWrBridge->RequestScreenPixels(this); state->mWrBridge->RequestScreenPixels(this);
state->mWrBridge->ScheduleForcedGenerateFrame(); state->mWrBridge->ScheduleForcedGenerateFrame(wr::RenderReasons::OTHER);
} }
#endif // defined(MOZ_WIDGET_ANDROID) #endif // defined(MOZ_WIDGET_ANDROID)

Просмотреть файл

@ -338,6 +338,7 @@ WebRenderBridgeParent::WebRenderBridgeParent(
mScreenPixelsTarget(nullptr), mScreenPixelsTarget(nullptr),
#endif #endif
mBlobTileSize(256), mBlobTileSize(256),
mSkippedCompositeReasons(wr::RenderReasons::NONE),
mDestroyed(false), mDestroyed(false),
mReceivedDisplayList(false), mReceivedDisplayList(false),
mIsFirstPaint(true), mIsFirstPaint(true),
@ -963,7 +964,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvUpdateResources(
// There are resource updates, then we update Epoch of transaction. // There are resource updates, then we update Epoch of transaction.
txn.UpdateEpoch(mPipelineId, mWrEpoch); txn.UpdateEpoch(mPipelineId, mWrEpoch);
mAsyncImageManager->SetWillGenerateFrame(); mAsyncImageManager->SetWillGenerateFrame();
ScheduleGenerateFrame(); ScheduleGenerateFrame(wr::RenderReasons::RESOURCE_UPDATE);
} else { } else {
// If TransactionBuilder does not have resource updates nor display list, // If TransactionBuilder does not have resource updates nor display list,
// ScheduleGenerateFrame is not triggered via SceneBuilder and there is no // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no
@ -1413,6 +1414,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction(
UpdateAPZFocusState(aFocusTarget); UpdateAPZFocusState(aFocusTarget);
bool scheduleAnyComposite = false; bool scheduleAnyComposite = false;
wr::RenderReasons renderReasons = wr::RenderReasons::NONE;
if (aTransactionData) { if (aTransactionData) {
bool scheduleComposite = false; bool scheduleComposite = false;
@ -1425,6 +1427,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction(
return IPC_FAIL(this, "Failed to process empty transaction update."); return IPC_FAIL(this, "Failed to process empty transaction update.");
} }
scheduleAnyComposite = scheduleAnyComposite || scheduleComposite; scheduleAnyComposite = scheduleAnyComposite || scheduleComposite;
renderReasons |= wr::RenderReasons::RESOURCE_UPDATE;
} }
// If we are going to kick off a new composite as a result of this // If we are going to kick off a new composite as a result of this
@ -1446,7 +1449,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction(
/* aUseForTelemetry */ scheduleAnyComposite); /* aUseForTelemetry */ scheduleAnyComposite);
if (scheduleAnyComposite) { if (scheduleAnyComposite) {
ScheduleGenerateFrame(); ScheduleGenerateFrame(renderReasons);
} else if (sendDidComposite) { } else if (sendDidComposite) {
// The only thing in the pending transaction id queue should be the entry // The only thing in the pending transaction id queue should be the entry
// we just added, and now we're going to pretend we rendered it // we just added, and now we're going to pretend we rendered it
@ -1537,7 +1540,7 @@ bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: { case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: {
const OpUpdatedAsyncImagePipeline& op = const OpUpdatedAsyncImagePipeline& op =
cmd.get_OpUpdatedAsyncImagePipeline(); cmd.get_OpUpdatedAsyncImagePipeline();
aTxn.InvalidateRenderedFrame(); aTxn.InvalidateRenderedFrame(wr::RenderReasons::ASYNC_IMAGE);
mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn, mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn,
txnForImageBridge); txnForImageBridge);
break; break;
@ -1602,10 +1605,10 @@ void WebRenderBridgeParent::FlushSceneBuilds() {
// shouldn't be calling this function all that much in production so this // shouldn't be calling this function all that much in production so this
// is probably fine. If it becomes an issue we can add more state tracking // is probably fine. If it becomes an issue we can add more state tracking
// machinery to optimize it away. // machinery to optimize it away.
ScheduleGenerateFrame(); ScheduleGenerateFrame(wr::RenderReasons::FLUSH);
} }
void WebRenderBridgeParent::FlushFrameGeneration() { void WebRenderBridgeParent::FlushFrameGeneration(wr::RenderReasons aReasons) {
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
MOZ_ASSERT(IsRootWebRenderBridgeParent()); // This function is only useful on MOZ_ASSERT(IsRootWebRenderBridgeParent()); // This function is only useful on
// the root WRBP // the root WRBP
@ -1616,7 +1619,7 @@ void WebRenderBridgeParent::FlushFrameGeneration() {
mCompositorScheduler->CancelCurrentCompositeTask(); mCompositorScheduler->CancelCurrentCompositeTask();
// Update timestamp of scheduler for APZ and animation. // Update timestamp of scheduler for APZ and animation.
mCompositorScheduler->UpdateLastComposeTime(); mCompositorScheduler->UpdateLastComposeTime();
MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true); MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true, aReasons);
} }
} }
@ -1637,7 +1640,7 @@ void WebRenderBridgeParent::DisableNativeCompositor() {
// Disable WebRender's native compositor usage // Disable WebRender's native compositor usage
mApi->EnableNativeCompositor(false); mApi->EnableNativeCompositor(false);
// Ensure we generate and render a frame immediately. // Ensure we generate and render a frame immediately.
ScheduleForcedGenerateFrame(); ScheduleForcedGenerateFrame(wr::RenderReasons::CONFIG_CHANGE);
mDisablingNativeCompositor = true; mDisablingNativeCompositor = true;
} }
@ -1782,7 +1785,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
MOZ_ASSERT((uint32_t)(size.width * 4) == stride); MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
FlushSceneBuilds(); FlushSceneBuilds();
FlushFrameGeneration(); FlushFrameGeneration(wr::RenderReasons::SNAPSHOT);
mApi->Readback(start, size, bufferTexture->GetFormat(), mApi->Readback(start, size, bufferTexture->GetFormat(),
Range<uint8_t>(buffer, buffer_size), aNeedsYFlip); Range<uint8_t>(buffer, buffer_size), aNeedsYFlip);
@ -1923,7 +1926,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvClearCachedResources() {
mApi->SendTransaction(txn); mApi->SendTransaction(txn);
// Schedule generate frame to clean up Pipeline // Schedule generate frame to clean up Pipeline
ScheduleGenerateFrame(); ScheduleGenerateFrame(wr::RenderReasons::CLEAR_RESOURCES);
ClearAnimationResources(); ClearAnimationResources();
@ -1985,11 +1988,12 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvInvalidateRenderedFrame() {
wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
IsRootWebRenderBridgeParent()); IsRootWebRenderBridgeParent());
InvalidateRenderedFrame(); InvalidateRenderedFrame(wr::RenderReasons::WIDGET);
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvScheduleComposite() { mozilla::ipc::IPCResult WebRenderBridgeParent::RecvScheduleComposite(
const wr::RenderReasons& aReasons) {
LOG("WebRenderBridgeParent::RecvScheduleComposite() PipelineId %" PRIx64 LOG("WebRenderBridgeParent::RecvScheduleComposite() PipelineId %" PRIx64
" Id %" PRIx64 " root %d", " Id %" PRIx64 " root %d",
wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()),
@ -1997,27 +2001,29 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvScheduleComposite() {
// Caller of LayerManager::ScheduleComposite() expects that it trigger // Caller of LayerManager::ScheduleComposite() expects that it trigger
// composite. Then we do not want to skip generate frame. // composite. Then we do not want to skip generate frame.
ScheduleForcedGenerateFrame(); ScheduleForcedGenerateFrame(aReasons);
return IPC_OK(); return IPC_OK();
} }
void WebRenderBridgeParent::InvalidateRenderedFrame() { void WebRenderBridgeParent::InvalidateRenderedFrame(
wr::RenderReasons aReasons) {
if (mDestroyed) { if (mDestroyed) {
return; return;
} }
wr::TransactionBuilder fastTxn(mApi, /* aUseSceneBuilderThread */ false); wr::TransactionBuilder fastTxn(mApi, /* aUseSceneBuilderThread */ false);
fastTxn.InvalidateRenderedFrame(); fastTxn.InvalidateRenderedFrame(aReasons);
mApi->SendTransaction(fastTxn); mApi->SendTransaction(fastTxn);
} }
void WebRenderBridgeParent::ScheduleForcedGenerateFrame() { void WebRenderBridgeParent::ScheduleForcedGenerateFrame(
wr::RenderReasons aReasons) {
if (mDestroyed) { if (mDestroyed) {
return; return;
} }
InvalidateRenderedFrame(); InvalidateRenderedFrame(aReasons);
ScheduleGenerateFrame(); ScheduleGenerateFrame(aReasons);
} }
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvCapture() { mozilla::ipc::IPCResult WebRenderBridgeParent::RecvCapture() {
@ -2050,7 +2056,7 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSyncWithCompositor() {
FlushSceneBuilds(); FlushSceneBuilds();
if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) { if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
root->FlushFrameGeneration(); root->FlushFrameGeneration(wr::RenderReasons::CONTENT_SYNC);
} }
FlushFramePresentation(); FlushFramePresentation();
// Finally, we force the AsyncImagePipelineManager to handle all the // Finally, we force the AsyncImagePipelineManager to handle all the
@ -2194,12 +2200,14 @@ void WebRenderBridgeParent::CompositeIfNeeded() {
if (mSkippedComposite) { if (mSkippedComposite) {
mSkippedComposite = false; mSkippedComposite = false;
if (mCompositorScheduler) { if (mCompositorScheduler) {
mCompositorScheduler->ScheduleComposition(); mCompositorScheduler->ScheduleComposition(mSkippedCompositeReasons);
} }
mSkippedCompositeReasons = wr::RenderReasons::NONE;
} }
} }
void WebRenderBridgeParent::CompositeToTarget(VsyncId aId, void WebRenderBridgeParent::CompositeToTarget(VsyncId aId,
wr::RenderReasons aReasons,
gfx::DrawTarget* aTarget, gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect) { const gfx::IntRect* aRect) {
// This function should only get called in the root WRBP // This function should only get called in the root WRBP
@ -2235,6 +2243,7 @@ void WebRenderBridgeParent::CompositeToTarget(VsyncId aId,
wr::RenderThread::Get()->TooManyPendingFrames(mApi->GetId())) { wr::RenderThread::Get()->TooManyPendingFrames(mApi->GetId())) {
// Render thread is busy, try next time. // Render thread is busy, try next time.
mSkippedComposite = true; mSkippedComposite = true;
mSkippedCompositeReasons = mSkippedCompositeReasons | aReasons;
ResetPreviousSampleTime(); ResetPreviousSampleTime();
// Record that we skipped presenting a frame for // Record that we skipped presenting a frame for
@ -2251,7 +2260,7 @@ void WebRenderBridgeParent::CompositeToTarget(VsyncId aId,
} }
mCompositionOpportunityId = mCompositionOpportunityId.Next(); mCompositionOpportunityId = mCompositionOpportunityId.Next();
MaybeGenerateFrame(aId, /* aForceGenerateFrame */ false); MaybeGenerateFrame(aId, /* aForceGenerateFrame */ false, aReasons);
} }
TimeDuration WebRenderBridgeParent::GetVsyncInterval() const { TimeDuration WebRenderBridgeParent::GetVsyncInterval() const {
@ -2264,7 +2273,8 @@ TimeDuration WebRenderBridgeParent::GetVsyncInterval() const {
} }
void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId, void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
bool aForceGenerateFrame) { bool aForceGenerateFrame,
wr::RenderReasons aReasons) {
// This function should only get called in the root WRBP // This function should only get called in the root WRBP
MOZ_ASSERT(IsRootWebRenderBridgeParent()); MOZ_ASSERT(IsRootWebRenderBridgeParent());
LOG("WebRenderBridgeParent::MaybeGenerateFrame() PipelineId %" PRIx64 LOG("WebRenderBridgeParent::MaybeGenerateFrame() PipelineId %" PRIx64
@ -2304,7 +2314,7 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
// Trigger another CompositeToTarget() call because there might be another // Trigger another CompositeToTarget() call because there might be another
// frame that we want to generate after this one. // frame that we want to generate after this one.
// It will check if we actually want to generate the frame or not. // It will check if we actually want to generate the frame or not.
mCompositorScheduler->ScheduleComposition(); mCompositorScheduler->ScheduleComposition(aReasons);
} }
bool generateFrame = mAsyncImageManager->GetAndResetWillGenerateFrame() || bool generateFrame = mAsyncImageManager->GetAndResetWillGenerateFrame() ||
@ -2321,7 +2331,7 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
if (sampler->HasAnimations()) { if (sampler->HasAnimations()) {
ScheduleGenerateFrame(); ScheduleGenerateFrame(wr::RenderReasons::ANIMATED_PROPERTY);
} }
} }
@ -2336,7 +2346,7 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
#endif #endif
MOZ_ASSERT(generateFrame); MOZ_ASSERT(generateFrame);
fastTxn.GenerateFrame(aId); fastTxn.GenerateFrame(aId, aReasons);
mApi->SendTransaction(fastTxn); mApi->SendTransaction(fastTxn);
#if defined(MOZ_WIDGET_ANDROID) #if defined(MOZ_WIDGET_ANDROID)
@ -2352,7 +2362,7 @@ void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
mDisablingNativeCompositor = false; mDisablingNativeCompositor = false;
// Ensure we generate and render a frame immediately. // Ensure we generate and render a frame immediately.
ScheduleForcedGenerateFrame(); ScheduleForcedGenerateFrame(aReasons);
} }
} }
@ -2406,7 +2416,7 @@ void WebRenderBridgeParent::NotifyDidSceneBuild(
mMostRecentComposite >= lastVsync || mMostRecentComposite >= lastVsync ||
((TimeStamp::Now() - lastVsync).ToMilliseconds() > ((TimeStamp::Now() - lastVsync).ToMilliseconds() >
StaticPrefs::gfx_webrender_late_scenebuild_threshold())) { StaticPrefs::gfx_webrender_late_scenebuild_threshold())) {
mCompositorScheduler->ScheduleComposition(); mCompositorScheduler->ScheduleComposition(wr::RenderReasons::SCENE);
return; return;
} }
@ -2425,13 +2435,14 @@ void WebRenderBridgeParent::NotifyDidSceneBuild(
// we did all of display list building and scene building within the // we did all of display list building and scene building within the
// threshold), then don't do an early composite. // threshold), then don't do an early composite.
if (startId == lastVsyncId) { if (startId == lastVsyncId) {
mCompositorScheduler->ScheduleComposition(); mCompositorScheduler->ScheduleComposition(wr::RenderReasons::SCENE);
return; return;
} }
} }
} }
CompositeToTarget(mCompositorScheduler->GetLastVsyncId(), nullptr, nullptr); CompositeToTarget(mCompositorScheduler->GetLastVsyncId(),
wr::RenderReasons::SCENE, nullptr, nullptr);
} }
static Telemetry::HistogramID GetHistogramId(const bool aIsLargePaint, static Telemetry::HistogramID GetHistogramId(const bool aIsLargePaint,
@ -2555,14 +2566,15 @@ LayersId WebRenderBridgeParent::GetLayersId() const {
return wr::AsLayersId(mPipelineId); return wr::AsLayersId(mPipelineId);
} }
void WebRenderBridgeParent::ScheduleGenerateFrame() { void WebRenderBridgeParent::ScheduleGenerateFrame(wr::RenderReasons aReasons) {
if (mCompositorScheduler) { if (mCompositorScheduler) {
mAsyncImageManager->SetWillGenerateFrame(); mAsyncImageManager->SetWillGenerateFrame();
mCompositorScheduler->ScheduleComposition(); mCompositorScheduler->ScheduleComposition(aReasons);
} }
} }
void WebRenderBridgeParent::FlushRendering(bool aWaitForPresent) { void WebRenderBridgeParent::FlushRendering(wr::RenderReasons aReasons,
bool aWaitForPresent) {
if (mDestroyed) { if (mDestroyed) {
return; return;
} }
@ -2570,7 +2582,7 @@ void WebRenderBridgeParent::FlushRendering(bool aWaitForPresent) {
// This gets called during e.g. window resizes, so we need to flush the // This gets called during e.g. window resizes, so we need to flush the
// scene (which has the display list at the new window size). // scene (which has the display list at the new window size).
FlushSceneBuilds(); FlushSceneBuilds();
FlushFrameGeneration(); FlushFrameGeneration(aReasons);
if (aWaitForPresent) { if (aWaitForPresent) {
FlushFramePresentation(); FlushFramePresentation();
} }
@ -2616,7 +2628,7 @@ bool WebRenderBridgeParent::Resume() {
} }
// Ensure we generate and render a frame immediately. // Ensure we generate and render a frame immediately.
ScheduleForcedGenerateFrame(); ScheduleForcedGenerateFrame(wr::RenderReasons::WIDGET);
return true; return true;
} }
@ -2633,7 +2645,7 @@ void WebRenderBridgeParent::ClearResources() {
wr::Epoch wrEpoch = GetNextWrEpoch(); wr::Epoch wrEpoch = GetNextWrEpoch();
mReceivedDisplayList = false; mReceivedDisplayList = false;
// Schedule generate frame to clean up Pipeline // Schedule generate frame to clean up Pipeline
ScheduleGenerateFrame(); ScheduleGenerateFrame(wr::RenderReasons::CLEAR_RESOURCES);
// WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction. // WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction.
for (const auto& entry : mTextureHosts) { for (const auto& entry : mTextureHosts) {

Просмотреть файл

@ -143,7 +143,8 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
mozilla::ipc::IPCResult RecvClearCachedResources() override; mozilla::ipc::IPCResult RecvClearCachedResources() override;
mozilla::ipc::IPCResult RecvInvalidateRenderedFrame() override; mozilla::ipc::IPCResult RecvInvalidateRenderedFrame() override;
mozilla::ipc::IPCResult RecvScheduleComposite() override; mozilla::ipc::IPCResult RecvScheduleComposite(
const wr::RenderReasons& aReasons) override;
mozilla::ipc::IPCResult RecvCapture() override; mozilla::ipc::IPCResult RecvCapture() override;
mozilla::ipc::IPCResult RecvStartCaptureSequence( mozilla::ipc::IPCResult RecvStartCaptureSequence(
const nsCString& path, const uint32_t& aFlags) override; const nsCString& path, const uint32_t& aFlags) override;
@ -182,7 +183,8 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
// CompositorVsyncSchedulerOwner // CompositorVsyncSchedulerOwner
bool IsPendingComposite() override { return false; } bool IsPendingComposite() override { return false; }
void FinishPendingComposite() override {} void FinishPendingComposite() override {}
void CompositeToTarget(VsyncId aId, gfx::DrawTarget* aTarget, void CompositeToTarget(VsyncId aId, wr::RenderReasons aReasons,
gfx::DrawTarget* aTarget,
const gfx::IntRect* aRect = nullptr) override; const gfx::IntRect* aRect = nullptr) override;
TimeDuration GetVsyncInterval() const override; TimeDuration GetVsyncInterval() const override;
@ -240,7 +242,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
return aFontKey.mNamespace == mIdNamespace; return aFontKey.mNamespace == mIdNamespace;
} }
void FlushRendering(bool aWaitForPresent = true); void FlushRendering(wr::RenderReasons aReasons, bool aWaitForPresent = true);
/** /**
* Schedule generating WebRender frame definitely at next composite timing. * Schedule generating WebRender frame definitely at next composite timing.
@ -253,7 +255,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
* Call CompositorVsyncScheduler::ScheduleComposition() directly, if we just * Call CompositorVsyncScheduler::ScheduleComposition() directly, if we just
* want to trigger AsyncImagePipelines update checks. * want to trigger AsyncImagePipelines update checks.
*/ */
void ScheduleGenerateFrame(); void ScheduleGenerateFrame(wr::RenderReasons aReason);
/** /**
* Invalidate rendered frame. * Invalidate rendered frame.
@ -261,7 +263,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
* WebRender could skip frame rendering if there is no update. * WebRender could skip frame rendering if there is no update.
* This function is used to force invalidating even when there is no update. * This function is used to force invalidating even when there is no update.
*/ */
void InvalidateRenderedFrame(); void InvalidateRenderedFrame(wr::RenderReasons aReasons);
/** /**
* Schedule forced frame rendering at next composite timing. * Schedule forced frame rendering at next composite timing.
@ -269,7 +271,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
* WebRender could skip frame rendering if there is no update. * WebRender could skip frame rendering if there is no update.
* This function is used to force rendering even when there is no update. * This function is used to force rendering even when there is no update.
*/ */
void ScheduleForcedGenerateFrame(); void ScheduleForcedGenerateFrame(wr::RenderReasons aReasons);
void NotifyDidSceneBuild(RefPtr<const wr::WebRenderPipelineInfo> aInfo); void NotifyDidSceneBuild(RefPtr<const wr::WebRenderPipelineInfo> aInfo);
@ -412,10 +414,11 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
void RollbackWrEpoch(); void RollbackWrEpoch();
void FlushSceneBuilds(); void FlushSceneBuilds();
void FlushFrameGeneration(); void FlushFrameGeneration(wr::RenderReasons aReasons);
void FlushFramePresentation(); void FlushFramePresentation();
void MaybeGenerateFrame(VsyncId aId, bool aForceGenerateFrame); void MaybeGenerateFrame(VsyncId aId, bool aForceGenerateFrame,
wr::RenderReasons aReasons);
VsyncId GetVsyncIdForEpoch(const wr::Epoch& aEpoch) { VsyncId GetVsyncIdForEpoch(const wr::Epoch& aEpoch) {
for (auto& id : mPendingTransactionIds) { for (auto& id : mPendingTransactionIds) {
@ -504,6 +507,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
#endif #endif
uint32_t mBoolParameterBits; uint32_t mBoolParameterBits;
uint16_t mBlobTileSize; uint16_t mBlobTileSize;
wr::RenderReasons mSkippedCompositeReasons;
bool mDestroyed; bool mDestroyed;
bool mReceivedDisplayList; bool mReceivedDisplayList;
bool mIsFirstPaint; bool mIsFirstPaint;

Просмотреть файл

@ -69,7 +69,8 @@ void WebRenderImageHost::UseTextureHost(
for (const auto& it : mWrBridges) { for (const auto& it : mWrBridges) {
RefPtr<WebRenderBridgeParent> wrBridge = it.second->WrBridge(); RefPtr<WebRenderBridgeParent> wrBridge = it.second->WrBridge();
if (wrBridge && wrBridge->CompositorScheduler()) { if (wrBridge && wrBridge->CompositorScheduler()) {
wrBridge->CompositorScheduler()->ScheduleComposition(); wrBridge->CompositorScheduler()->ScheduleComposition(
wr::RenderReasons::ASYNC_IMAGE);
} }
} }
} }

Просмотреть файл

@ -685,7 +685,7 @@ void WebRenderLayerManager::RemoveDidCompositeObserver(
mDidCompositeObservers.RemoveElement(aObserver); mDidCompositeObservers.RemoveElement(aObserver);
} }
void WebRenderLayerManager::FlushRendering() { void WebRenderLayerManager::FlushRendering(wr::RenderReasons aReasons) {
CompositorBridgeChild* cBridge = GetCompositorBridgeChild(); CompositorBridgeChild* cBridge = GetCompositorBridgeChild();
if (!cBridge) { if (!cBridge) {
return; return;
@ -696,15 +696,19 @@ void WebRenderLayerManager::FlushRendering() {
// might happen. // might happen.
bool resizing = mWidget && mWidget->IsResizingNativeWidget().valueOr(true); bool resizing = mWidget && mWidget->IsResizingNativeWidget().valueOr(true);
if (resizing) {
aReasons = aReasons | wr::RenderReasons::RESIZE;
}
// Limit async FlushRendering to !resizing and Win DComp. // Limit async FlushRendering to !resizing and Win DComp.
// XXX relax the limitation // XXX relax the limitation
if (WrBridge()->GetCompositorUseDComp() && !resizing) { if (WrBridge()->GetCompositorUseDComp() && !resizing) {
cBridge->SendFlushRenderingAsync(); cBridge->SendFlushRenderingAsync(aReasons);
} else if (mWidget->SynchronouslyRepaintOnResize() || } else if (mWidget->SynchronouslyRepaintOnResize() ||
StaticPrefs::layers_force_synchronous_resize()) { StaticPrefs::layers_force_synchronous_resize()) {
cBridge->SendFlushRendering(); cBridge->SendFlushRendering(aReasons);
} else { } else {
cBridge->SendFlushRenderingAsync(); cBridge->SendFlushRenderingAsync(aReasons);
} }
} }
@ -731,8 +735,8 @@ void WebRenderLayerManager::SendInvalidRegion(const nsIntRegion& aRegion) {
} }
} }
void WebRenderLayerManager::ScheduleComposite() { void WebRenderLayerManager::ScheduleComposite(wr::RenderReasons aReasons) {
WrBridge()->SendScheduleComposite(); WrBridge()->SendScheduleComposite(aReasons);
} }
already_AddRefed<PersistentBufferProvider> already_AddRefed<PersistentBufferProvider>

Просмотреть файл

@ -110,12 +110,12 @@ class WebRenderLayerManager final : public WindowRenderer {
void AddDidCompositeObserver(DidCompositeObserver* aObserver); void AddDidCompositeObserver(DidCompositeObserver* aObserver);
void RemoveDidCompositeObserver(DidCompositeObserver* aObserver); void RemoveDidCompositeObserver(DidCompositeObserver* aObserver);
void FlushRendering() override; void FlushRendering(wr::RenderReasons aReasons) override;
void WaitOnTransactionProcessed() override; void WaitOnTransactionProcessed() override;
void SendInvalidRegion(const nsIntRegion& aRegion); void SendInvalidRegion(const nsIntRegion& aRegion);
void ScheduleComposite(); void ScheduleComposite(wr::RenderReasons aReasons);
void SetNeedsComposite(bool aNeedsComposite) { void SetNeedsComposite(bool aNeedsComposite) {
mNeedsComposite = aNeedsComposite; mNeedsComposite = aNeedsComposite;

Просмотреть файл

@ -145,6 +145,10 @@ template <>
struct ParamTraits<mozilla::wr::ExternalImageKeyPair> struct ParamTraits<mozilla::wr::ExternalImageKeyPair>
: public PlainOldDataSerializer<mozilla::wr::ExternalImageKeyPair> {}; : public PlainOldDataSerializer<mozilla::wr::ExternalImageKeyPair> {};
template <>
struct ParamTraits<mozilla::wr::RenderReasons>
: public PlainOldDataSerializer<mozilla::wr::RenderReasons> {};
} // namespace IPC } // namespace IPC
#endif // GFX_WEBRENDERMESSAGEUTILS_H #endif // GFX_WEBRENDERMESSAGEUTILS_H

Просмотреть файл

@ -1234,17 +1234,19 @@ void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
std::move(evt)); std::move(evt));
} }
static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId) { static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,
wr::RenderReasons aReasons) {
RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers:: RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId); CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
if (cbp) { if (cbp) {
cbp->ScheduleComposition(); cbp->ScheduleComposition(aReasons);
} }
} }
void wr_schedule_render(mozilla::wr::WrWindowId aWindowId) { void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
wr::RenderReasons aReasons) {
layers::CompositorThread()->Dispatch(NewRunnableFunction( layers::CompositorThread()->Dispatch(NewRunnableFunction(
"NotifyScheduleRender", &NotifyScheduleRender, aWindowId)); "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons));
} }
static void NotifyDidSceneBuild( static void NotifyDidSceneBuild(

Просмотреть файл

@ -276,12 +276,13 @@ void TransactionBuilder::ClearDisplayList(Epoch aEpoch,
wr_transaction_clear_display_list(mTxn, aEpoch, aPipelineId); wr_transaction_clear_display_list(mTxn, aEpoch, aPipelineId);
} }
void TransactionBuilder::GenerateFrame(const VsyncId& aVsyncId) { void TransactionBuilder::GenerateFrame(const VsyncId& aVsyncId,
wr_transaction_generate_frame(mTxn, aVsyncId.mId); wr::RenderReasons aReasons) {
wr_transaction_generate_frame(mTxn, aVsyncId.mId, aReasons);
} }
void TransactionBuilder::InvalidateRenderedFrame() { void TransactionBuilder::InvalidateRenderedFrame(wr::RenderReasons aReasons) {
wr_transaction_invalidate_rendered_frame(mTxn); wr_transaction_invalidate_rendered_frame(mTxn, aReasons);
} }
bool TransactionBuilder::IsEmpty() const { bool TransactionBuilder::IsEmpty() const {

Просмотреть файл

@ -119,9 +119,9 @@ class TransactionBuilder final {
void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId aPipeline); void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId aPipeline);
void GenerateFrame(const VsyncId& aVsyncId); void GenerateFrame(const VsyncId& aVsyncId, wr::RenderReasons aReasons);
void InvalidateRenderedFrame(); void InvalidateRenderedFrame(wr::RenderReasons aReasons);
void SetDocumentView(const LayoutDeviceIntRect& aDocRect); void SetDocumentView(const LayoutDeviceIntRect& aDocRect);

Просмотреть файл

@ -530,7 +530,7 @@ extern "C" {
fn wr_notifier_new_frame_ready(window_id: WrWindowId); fn wr_notifier_new_frame_ready(window_id: WrWindowId);
fn wr_notifier_nop_frame_done(window_id: WrWindowId); fn wr_notifier_nop_frame_done(window_id: WrWindowId);
fn wr_notifier_external_event(window_id: WrWindowId, raw_event: usize); fn wr_notifier_external_event(window_id: WrWindowId, raw_event: usize);
fn wr_schedule_render(window_id: WrWindowId); fn wr_schedule_render(window_id: WrWindowId, reasons: RenderReasons);
// NOTE: This moves away from pipeline_info. // NOTE: This moves away from pipeline_info.
fn wr_finished_scene_build(window_id: WrWindowId, pipeline_info: &mut WrPipelineInfo); fn wr_finished_scene_build(window_id: WrWindowId, pipeline_info: &mut WrPipelineInfo);
@ -986,7 +986,7 @@ impl SceneBuilderHooks for APZCallbacks {
} }
fn post_resource_update(&self, _document_ids: &Vec<DocumentId>) { fn post_resource_update(&self, _document_ids: &Vec<DocumentId>) {
unsafe { wr_schedule_render(self.window_id) } unsafe { wr_schedule_render(self.window_id, RenderReasons::POST_RESOURCE_UPDATES_HOOK) }
unsafe { unsafe {
gecko_profiler_end_marker(b"SceneBuilding\0".as_ptr() as *const c_char); gecko_profiler_end_marker(b"SceneBuilding\0".as_ptr() as *const c_char);
} }
@ -1872,13 +1872,13 @@ pub extern "C" fn wr_transaction_set_document_view(txn: &mut Transaction, doc_re
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn wr_transaction_generate_frame(txn: &mut Transaction, id: u64) { pub extern "C" fn wr_transaction_generate_frame(txn: &mut Transaction, id: u64, reasons: RenderReasons) {
txn.generate_frame(id); txn.generate_frame(id, reasons);
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn wr_transaction_invalidate_rendered_frame(txn: &mut Transaction) { pub extern "C" fn wr_transaction_invalidate_rendered_frame(txn: &mut Transaction, reasons: RenderReasons) {
txn.invalidate_rendered_frame(); txn.invalidate_rendered_frame(reasons);
} }
fn wr_animation_properties_into_vec<T>( fn wr_animation_properties_into_vec<T>(

Просмотреть файл

@ -487,7 +487,7 @@ fn main() {
); );
} }
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
// Tick the compositor (in this sample, we don't block on UI events) // Tick the compositor (in this sample, we don't block on UI events)
@ -534,7 +534,7 @@ fn main() {
} }
} }
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
current_epoch.0 += 1; current_epoch.0 += 1;
time += 0.001; time += 0.001;

Просмотреть файл

@ -200,7 +200,7 @@ impl Example for App {
colors: vec![], colors: vec![],
}, },
); );
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
} }
_ => (), _ => (),

Просмотреть файл

@ -214,7 +214,7 @@ pub fn main_wrapper<E: Example>(
builder.end(), builder.end(),
); );
txn.set_root_pipeline(pipeline_id); txn.set_root_pipeline(pipeline_id);
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
println!("Entering event loop"); println!("Entering event loop");
@ -303,7 +303,7 @@ pub fn main_wrapper<E: Example>(
layout_size, layout_size,
builder.end(), builder.end(),
); );
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
} }
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);

Просмотреть файл

@ -124,7 +124,7 @@ impl Example for App {
doc.content_rect.size(), doc.content_rect.size(),
builder.end(), builder.end(),
); );
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
api.send_transaction(doc.id, txn); api.send_transaction(doc.id, txn);
} }
} }

Просмотреть файл

@ -104,7 +104,7 @@ impl Example for App {
&DirtyRect::All, &DirtyRect::All,
); );
let mut txn = Transaction::new(); let mut txn = Transaction::new();
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
api.send_transaction(document_id, txn); api.send_transaction(document_id, txn);
} }
_ => {} _ => {}

Просмотреть файл

@ -284,7 +284,7 @@ impl Window {
builder.end(), builder.end(),
); );
txn.set_root_pipeline(self.pipeline_id); txn.set_root_pipeline(self.pipeline_id);
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
api.send_transaction(self.document_id, txn); api.send_transaction(self.document_id, txn);
renderer.update(); renderer.update();

Просмотреть файл

@ -190,7 +190,7 @@ impl Example for App {
ExternalScrollId(EXT_SCROLL_ID_CONTENT, PipelineId::dummy()), ExternalScrollId(EXT_SCROLL_ID_CONTENT, PipelineId::dummy()),
ScrollClamping::ToContentBounds, ScrollClamping::ToContentBounds,
); );
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
} }
} }
winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => { winit::WindowEvent::CursorMoved { position: LogicalPosition { x, y }, .. } => {
@ -211,7 +211,7 @@ impl Example for App {
ScrollClamping::ToContentBounds, ScrollClamping::ToContentBounds,
); );
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::empty());
} }
winit::WindowEvent::MouseInput { .. } => { winit::WindowEvent::MouseInput { .. } => {
let results = api.hit_test( let results = api.hit_test(

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ColorF, DocumentId, ExternalImageId, PrimitiveFlags, Parameter}; use api::{ColorF, DocumentId, ExternalImageId, PrimitiveFlags, Parameter, RenderReasons};
use api::{ImageFormat, NotificationRequest, Shadow, FilterOp, ImageBufferKind}; use api::{ImageFormat, NotificationRequest, Shadow, FilterOp, ImageBufferKind};
use api::units::*; use api::units::*;
use api; use api;
@ -653,6 +653,7 @@ pub struct RenderedDocument {
pub frame: Frame, pub frame: Frame,
pub is_new_scene: bool, pub is_new_scene: bool,
pub profile: TransactionProfile, pub profile: TransactionProfile,
pub render_reasons: RenderReasons,
pub frame_stats: Option<FullFrameStats> pub frame_stats: Option<FullFrameStats>
} }

Просмотреть файл

@ -93,6 +93,8 @@ static PROFILER_PRESETS: &'static[(&'static str, &'static str)] = &[
(&"Interners", "Interned primitives,Interned clips,Interned pictures,Interned text runs,Interned normal borders,Interned image borders,Interned images,Interned YUV images,Interned line decorations,Interned linear gradients,Interned radial gradients,Interned conic gradients,Interned filter data,Interned backdrops"), (&"Interners", "Interned primitives,Interned clips,Interned pictures,Interned text runs,Interned normal borders,Interned image borders,Interned images,Interned YUV images,Interned line decorations,Interned linear gradients,Interned radial gradients,Interned conic gradients,Interned filter data,Interned backdrops"),
// Gpu sampler queries (need the pref gfx.webrender.debug.gpu-sampler-queries). // Gpu sampler queries (need the pref gfx.webrender.debug.gpu-sampler-queries).
(&"GPU samplers", &"Alpha targets samplers,Transparent pass samplers,Opaque pass samplers,Total samplers"), (&"GPU samplers", &"Alpha targets samplers,Transparent pass samplers,Opaque pass samplers,Total samplers"),
(&"Render reasons", &"Reason scene, Reason animated propert, Reason resource update, Reason async image, Reason clear resources, Reason APZ, Reason resize, Reason widget, Reason cache flush, Reason snapshot, Reason resource hook, Reason config change, Reason content sync, Reason flush, Reason vsync, Reason testing, Reason other"),
]; ];
fn find_preset(name: &str) -> Option<&'static str> { fn find_preset(name: &str) -> Option<&'static str> {
@ -231,7 +233,26 @@ pub const DEPTH_TARGETS_MEM: usize = 100;
pub const SHADER_BUILD_TIME: usize = 101; pub const SHADER_BUILD_TIME: usize = 101;
pub const NUM_PROFILER_EVENTS: usize = 102; pub const RENDER_REASON_FIRST: usize = 102;
pub const RENDER_REASON_SCENE: usize = 102;
pub const RENDER_REASON_ANIMATED_PROPERTY: usize = 103;
pub const RENDER_REASON_RESOURCE_UPDATE: usize = 104;
pub const RENDER_REASON_ASYNC_IMAGE: usize = 105;
pub const RENDER_REASON_CLEAR_RESOURCES: usize = 106;
pub const RENDER_REASON_APZ: usize = 107;
pub const RENDER_REASON_RESIZE: usize = 108;
pub const RENDER_REASON_WIDGET: usize = 109;
pub const RENDER_REASON_TEXTURE_CACHE_FLUSH: usize = 110;
pub const RENDER_REASON_SNAPSHOT: usize = 111;
pub const RENDER_REASON_POST_RESOURCE_UPDATE_HOOKS: usize = 112;
pub const RENDER_REASON_CONFIG_CHANGE: usize = 113;
pub const RENDER_REASON_CONTENT_SYNC: usize = 114;
pub const RENDER_REASON_FLUSH: usize = 115;
pub const RENDER_REASON_TESTING: usize = 116;
pub const RENDER_REASON_OTHER: usize = 117;
pub const RENDER_REASON_VSYNC: usize = 118;
pub const NUM_PROFILER_EVENTS: usize = 119;
pub struct Profiler { pub struct Profiler {
counters: Vec<Counter>, counters: Vec<Counter>,
@ -386,6 +407,25 @@ impl Profiler {
float("Depth targets mem", "MB", DEPTH_TARGETS_MEM, Expected::none()), float("Depth targets mem", "MB", DEPTH_TARGETS_MEM, Expected::none()),
float("Shader build time", "ms", SHADER_BUILD_TIME, Expected::none()), float("Shader build time", "ms", SHADER_BUILD_TIME, Expected::none()),
// We use the expected range to highlight render reasons that are happening.
float("Reason scene", "", RENDER_REASON_SCENE, expected(0.0..0.01)),
float("Reason animated propert", "", RENDER_REASON_ANIMATED_PROPERTY, expected(0.0..0.01)),
float("Reason resource update", "", RENDER_REASON_RESOURCE_UPDATE, expected(0.0..0.01)),
float("Reason async image", "", RENDER_REASON_ASYNC_IMAGE, expected(0.0..0.01)),
float("Reason clear resources", "", RENDER_REASON_CLEAR_RESOURCES, expected(0.0..0.01)),
float("Reason APZ", "", RENDER_REASON_APZ, expected(0.0..0.01)),
float("Reason resize", "", RENDER_REASON_RESIZE, expected(0.0..0.01)),
float("Reason widget", "", RENDER_REASON_WIDGET, expected(0.0..0.01)),
float("Reason texture cache flush", "", RENDER_REASON_TEXTURE_CACHE_FLUSH, expected(0.0..0.01)),
float("Reason snapshot", "", RENDER_REASON_SNAPSHOT, expected(0.0..0.01)),
float("Reason resource hook", "", RENDER_REASON_POST_RESOURCE_UPDATE_HOOKS, expected(0.0..0.01)),
float("Reason config change", "", RENDER_REASON_CONFIG_CHANGE, expected(0.0..0.01)),
float("Reason content sync", "", RENDER_REASON_CONTENT_SYNC, expected(0.0..0.01)),
float("Reason flush", "", RENDER_REASON_FLUSH, expected(0.0..0.01)),
float("Reason testing", "", RENDER_REASON_TESTING, expected(0.0..0.01)),
float("Reason other", "", RENDER_REASON_OTHER, expected(0.0..0.01)),
float("On vsync", "", RENDER_REASON_VSYNC, expected(0.0..0.01)),
]; ];
let mut counters = Vec::with_capacity(profile_counters.len()); let mut counters = Vec::with_capacity(profile_counters.len());

Просмотреть файл

@ -21,7 +21,7 @@ use crate::api::{DocumentId, PipelineId, PropertyBindingId, PropertyBindingKey,
use crate::api::{HitTestResult, HitTesterRequest, ApiHitTester, PropertyValue, DynamicProperties}; use crate::api::{HitTestResult, HitTesterRequest, ApiHitTester, PropertyValue, DynamicProperties};
use crate::api::{ScrollClamping, TileSize, NotificationRequest, DebugFlags}; use crate::api::{ScrollClamping, TileSize, NotificationRequest, DebugFlags};
use crate::api::{GlyphDimensionRequest, GlyphIndexRequest, GlyphIndex, GlyphDimensions}; use crate::api::{GlyphDimensionRequest, GlyphIndexRequest, GlyphIndex, GlyphDimensions};
use crate::api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation}; use crate::api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation, RenderReasons};
use crate::api::DEFAULT_TILE_SIZE; use crate::api::DEFAULT_TILE_SIZE;
use crate::api::units::*; use crate::api::units::*;
use crate::api_resources::ApiResources; use crate::api_resources::ApiResources;
@ -174,6 +174,9 @@ pub struct Transaction {
pub invalidate_rendered_frame: bool, pub invalidate_rendered_frame: bool,
low_priority: bool, low_priority: bool,
///
pub render_reasons: RenderReasons,
} }
impl Transaction { impl Transaction {
@ -188,6 +191,7 @@ impl Transaction {
generate_frame: GenerateFrame::No, generate_frame: GenerateFrame::No,
invalidate_rendered_frame: false, invalidate_rendered_frame: false,
low_priority: false, low_priority: false,
render_reasons: RenderReasons::empty(),
} }
} }
@ -358,8 +362,9 @@ impl Transaction {
/// as to when happened. /// as to when happened.
/// ///
/// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready /// [notifier]: trait.RenderNotifier.html#tymethod.new_frame_ready
pub fn generate_frame(&mut self, id: u64) { pub fn generate_frame(&mut self, id: u64, reasons: RenderReasons) {
self.generate_frame = GenerateFrame::Yes{ id }; self.generate_frame = GenerateFrame::Yes{ id };
self.render_reasons |= reasons;
} }
/// Invalidate rendered frame. It ensure that frame will be rendered during /// Invalidate rendered frame. It ensure that frame will be rendered during
@ -368,8 +373,9 @@ impl Transaction {
/// But there are cases that needs to force rendering. /// But there are cases that needs to force rendering.
/// - Content of image is updated by reusing same ExternalImageId. /// - Content of image is updated by reusing same ExternalImageId.
/// - Platform requests it if pixels become stale (like wakeup from standby). /// - Platform requests it if pixels become stale (like wakeup from standby).
pub fn invalidate_rendered_frame(&mut self) { pub fn invalidate_rendered_frame(&mut self, reasons: RenderReasons) {
self.invalidate_rendered_frame = true; self.invalidate_rendered_frame = true;
self.render_reasons |= reasons
} }
/// Reset the list of animated property bindings that should be used to resolve /// Reset the list of animated property bindings that should be used to resolve
@ -412,6 +418,7 @@ impl Transaction {
blob_requests: Vec::new(), blob_requests: Vec::new(),
rasterized_blobs: Vec::new(), rasterized_blobs: Vec::new(),
profile: TransactionProfile::new(), profile: TransactionProfile::new(),
render_reasons: self.render_reasons,
}) })
} }
@ -597,6 +604,8 @@ pub struct TransactionMsg {
pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>, pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>,
/// Collect various data along the rendering pipeline to display it in the embedded profiler. /// Collect various data along the rendering pipeline to display it in the embedded profiler.
pub profile: TransactionProfile, pub profile: TransactionProfile,
/// Keep track of who asks rendering to happen.
pub render_reasons: RenderReasons,
} }
impl fmt::Debug for TransactionMsg { impl fmt::Debug for TransactionMsg {
@ -1219,6 +1228,7 @@ impl RenderApi {
blob_requests: Vec::new(), blob_requests: Vec::new(),
rasterized_blobs: Vec::new(), rasterized_blobs: Vec::new(),
profile: TransactionProfile::new(), profile: TransactionProfile::new(),
render_reasons: RenderReasons::empty(),
}) })
} }

Просмотреть файл

@ -12,7 +12,7 @@ use api::{DebugFlags, BlobImageHandler, Parameter, BoolParameter};
use api::{DocumentId, ExternalScrollId, HitTestResult}; use api::{DocumentId, ExternalScrollId, HitTestResult};
use api::{IdNamespace, PipelineId, RenderNotifier, ScrollClamping}; use api::{IdNamespace, PipelineId, RenderNotifier, ScrollClamping};
use api::{NotificationRequest, Checkpoint, QualitySettings}; use api::{NotificationRequest, Checkpoint, QualitySettings};
use api::{PrimitiveKeyKind}; use api::{PrimitiveKeyKind, RenderReasons};
use api::units::*; use api::units::*;
use api::channel::{single_msg_channel, Sender, Receiver}; use api::channel::{single_msg_channel, Sender, Receiver};
#[cfg(any(feature = "capture", feature = "replay"))] #[cfg(any(feature = "capture", feature = "replay"))]
@ -436,7 +436,8 @@ impl Document {
debug_flags: DebugFlags, debug_flags: DebugFlags,
tile_cache_logger: &mut TileCacheLogger, tile_cache_logger: &mut TileCacheLogger,
tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>, tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
frame_stats: Option<FullFrameStats> frame_stats: Option<FullFrameStats>,
render_reasons: RenderReasons,
) -> RenderedDocument { ) -> RenderedDocument {
let frame_build_start_time = precise_time_ns(); let frame_build_start_time = precise_time_ns();
@ -487,7 +488,8 @@ impl Document {
frame, frame,
is_new_scene, is_new_scene,
profile: self.profile.take_and_reset(), profile: self.profile.take_and_reset(),
frame_stats: frame_stats frame_stats: frame_stats,
render_reasons,
} }
} }
@ -862,6 +864,7 @@ impl RenderBackend {
txn.frame_ops.take(), txn.frame_ops.take(),
txn.notifications.take(), txn.notifications.take(),
txn.render_frame, txn.render_frame,
RenderReasons::SCENE,
None, None,
txn.invalidate_rendered_frame, txn.invalidate_rendered_frame,
frame_counter, frame_counter,
@ -1204,6 +1207,7 @@ impl RenderBackend {
txn.frame_ops.take(), txn.frame_ops.take(),
txn.notifications.take(), txn.notifications.take(),
txn.generate_frame.as_bool(), txn.generate_frame.as_bool(),
txn.render_reasons,
txn.generate_frame.id(), txn.generate_frame.id(),
txn.invalidate_rendered_frame, txn.invalidate_rendered_frame,
frame_counter, frame_counter,
@ -1241,6 +1245,7 @@ impl RenderBackend {
Vec::default(), Vec::default(),
Vec::default(), Vec::default(),
false, false,
RenderReasons::empty(),
None, None,
false, false,
frame_counter, frame_counter,
@ -1261,6 +1266,7 @@ impl RenderBackend {
mut frame_ops: Vec<FrameMsg>, mut frame_ops: Vec<FrameMsg>,
mut notifications: Vec<NotificationRequest>, mut notifications: Vec<NotificationRequest>,
mut render_frame: bool, mut render_frame: bool,
render_reasons: RenderReasons,
generated_frame_id: Option<u64>, generated_frame_id: Option<u64>,
invalidate_rendered_frame: bool, invalidate_rendered_frame: bool,
frame_counter: &mut u32, frame_counter: &mut u32,
@ -1352,7 +1358,8 @@ impl RenderBackend {
self.debug_flags, self.debug_flags,
&mut self.tile_cache_logger, &mut self.tile_cache_logger,
&mut self.tile_caches, &mut self.tile_caches,
frame_stats frame_stats,
render_reasons,
); );
debug!("generated frame for document {:?} with {} passes", debug!("generated frame for document {:?} with {} passes",
@ -1544,6 +1551,7 @@ impl RenderBackend {
&mut self.tile_cache_logger, &mut self.tile_cache_logger,
&mut self.tile_caches, &mut self.tile_caches,
None, None,
RenderReasons::empty(),
); );
// After we rendered the frames, there are pending updates to both // After we rendered the frames, there are pending updates to both
// GPU cache and resources. Instead of serializing them, we are going to make sure // GPU cache and resources. Instead of serializing them, we are going to make sure
@ -1814,7 +1822,13 @@ impl RenderBackend {
let msg_publish = ResultMsg::PublishDocument( let msg_publish = ResultMsg::PublishDocument(
id, id,
RenderedDocument { frame, is_new_scene: true, profile: TransactionProfile::new(), frame_stats: None }, RenderedDocument {
frame,
is_new_scene: true,
profile: TransactionProfile::new(),
render_reasons: RenderReasons::empty(),
frame_stats: None,
},
self.resource_cache.pending_updates(), self.resource_cache.pending_updates(),
); );
self.result_tx.send(msg_publish).unwrap(); self.result_tx.send(msg_publish).unwrap();

Просмотреть файл

@ -35,7 +35,7 @@
//! calling `DrawTarget::to_framebuffer_rect` //! calling `DrawTarget::to_framebuffer_rect`
use api::{BlobImageHandler, ColorF, ColorU, MixBlendMode}; use api::{BlobImageHandler, ColorF, ColorU, MixBlendMode};
use api::{DocumentId, Epoch, ExternalImageHandler}; use api::{DocumentId, Epoch, ExternalImageHandler, RenderReasons};
use api::CrashAnnotator; use api::CrashAnnotator;
#[cfg(feature = "replay")] #[cfg(feature = "replay")]
use api::ExternalImageId; use api::ExternalImageId;
@ -1502,6 +1502,7 @@ impl Renderer {
doc.profile.merge(&mut prev_doc.profile); doc.profile.merge(&mut prev_doc.profile);
if prev_doc.frame.must_be_drawn() { if prev_doc.frame.must_be_drawn() {
prev_doc.render_reasons |= RenderReasons::TEXTURE_CACHE_FLUSH;
self.render_impl( self.render_impl(
document_id, document_id,
&mut prev_doc, &mut prev_doc,
@ -2092,6 +2093,31 @@ impl Renderer {
self.profiler.update_frame_stats(stats); self.profiler.update_frame_stats(stats);
} }
// Turn the render reasons bitflags into something we can see in the profiler.
// For now this is just a binary yes/no for each bit, which means that when looking
// at "Render reasons" in the profiler HUD the average view indicates the proportion
// of frames that had the bit set over a half second window whereas max shows whether
// the bit as been set at least once during that time window.
// We could implement better ways to visualize this information.
let add_markers = thread_is_being_profiled();
for i in 0..RenderReasons::NUM_BITS {
let counter = profiler::RENDER_REASON_FIRST + i as usize;
let mut val = 0.0;
let reason_bit = RenderReasons::from_bits_truncate(1 << i);
if active_doc.render_reasons.contains(reason_bit) {
val = 1.0;
if add_markers {
let event_str = format!("Render reason {:?}", reason_bit);
if let Ok(event_str) = std::ffi::CString::new(&event_str[..]) {
add_event_marker(event_str.as_c_str());
}
}
}
self.profile.set(counter, val);
}
active_doc.render_reasons = RenderReasons::empty();
self.texture_resolver.update_profile(&mut self.profile); self.texture_resolver.update_profile(&mut self.profile);
// Note: this clears the values in self.profile. // Note: this clears the values in self.profile.

Просмотреть файл

@ -524,6 +524,42 @@ pub enum BoolParameter {
DrawCallsForTextureCopy = 3, DrawCallsForTextureCopy = 3,
} }
bitflags! {
/// Flags to track why we are rendering.
#[repr(C)]
#[derive(Default, Deserialize, MallocSizeOf, Serialize)]
pub struct RenderReasons: u32 {
/// Equivalent of empty() for the C++ side.
const NONE = 0;
const SCENE = 1 << 0;
const ANIMATED_PROPERTY = 1 << 1;
const RESOURCE_UPDATE = 1 << 2;
const ASYNC_IMAGE = 1 << 3;
const CLEAR_RESOURCES = 1 << 4;
const APZ = 1 << 5;
/// Window resize
const RESIZE = 1 << 6;
/// Various widget-related reasons
const WIDGET = 1 << 7;
/// See Frame::must_be_drawn
const TEXTURE_CACHE_FLUSH = 1 << 8;
const SNAPSHOT = 1 << 9;
const POST_RESOURCE_UPDATES_HOOK = 1 << 10;
const CONFIG_CHANGE = 1 << 11;
const CONTENT_SYNC = 1 << 12;
const FLUSH = 1 << 13;
const TESTING = 1 << 14;
const OTHER = 1 << 15;
/// Vsync isn't actually "why" we render but it can be useful
/// to see which frames were driven by the vsync scheduler so
/// we store a bit for it.
const VSYNC = 1 << 16;
}
}
impl RenderReasons {
pub const NUM_BITS: u32 = 17;
}
bitflags! { bitflags! {
/// Flags to enable/disable various builtin debugging tools. /// Flags to enable/disable various builtin debugging tools.

Просмотреть файл

@ -106,7 +106,7 @@ impl<'a> RawtestHarness<'a> {
); );
epoch.0 += 1; epoch.0 += 1;
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::TESTING);
self.wrench.api.send_transaction(self.wrench.document_id, txn); self.wrench.api.send_transaction(self.wrench.document_id, txn);
} }
@ -1252,7 +1252,7 @@ impl<'a> RawtestHarness<'a> {
layout_size, layout_size,
builder.end(), builder.end(),
); );
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::TESTING);
self.wrench.api.send_transaction(self.wrench.document_id, txn); self.wrench.api.send_transaction(self.wrench.document_id, txn);
@ -1287,7 +1287,7 @@ impl<'a> RawtestHarness<'a> {
// 6. rebuild the scene and compare again // 6. rebuild the scene and compare again
let mut txn = Transaction::new(); let mut txn = Transaction::new();
txn.set_root_pipeline(captured.root_pipeline_id.unwrap()); txn.set_root_pipeline(captured.root_pipeline_id.unwrap());
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::TESTING);
self.wrench.api.send_transaction(captured.document_id, txn); self.wrench.api.send_transaction(captured.document_id, txn);
let pixels2 = self.render_and_get_pixels(window_rect); let pixels2 = self.render_and_get_pixels(window_rect);
self.compare_pixels(pixels0, pixels2, window_rect.size()); self.compare_pixels(pixels0, pixels2, window_rect.size());
@ -1319,7 +1319,7 @@ impl<'a> RawtestHarness<'a> {
layout_size, layout_size,
builder.end(), builder.end(),
); );
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::TESTING);
self.wrench.api.send_transaction(doc_id, txn); self.wrench.api.send_transaction(doc_id, txn);
// Ensure we get a notification from rendering the above, even though // Ensure we get a notification from rendering the above, even though

Просмотреть файл

@ -580,7 +580,7 @@ impl Wrench {
txn.scroll_node_with_id(*offset, *id, ScrollClamping::NoClamping); txn.scroll_node_with_id(*offset, *id, ScrollClamping::NoClamping);
} }
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::TESTING);
self.api.send_transaction(self.document_id, txn); self.api.send_transaction(self.document_id, txn);
} }
@ -601,7 +601,7 @@ impl Wrench {
pub fn refresh(&mut self) { pub fn refresh(&mut self) {
self.begin_frame(); self.begin_frame();
let mut txn = Transaction::new(); let mut txn = Transaction::new();
txn.generate_frame(0); txn.generate_frame(0, RenderReasons::TESTING);
self.api.send_transaction(self.document_id, txn); self.api.send_transaction(self.document_id, txn);
} }

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef MOZILLA_PAINTING_WINDOWRENDERER_H #ifndef MOZILLA_PAINTING_WINDOWRENDERER_H
#define MOZILLA_PAINTING_WINDOWRENDERER_H #define MOZILLA_PAINTING_WINDOWRENDERER_H
#include "mozilla/webrender/webrender_ffi.h"
#include "mozilla/layers/LayersTypes.h" #include "mozilla/layers/LayersTypes.h"
#include "mozilla/dom/Animation.h" // for Animation #include "mozilla/dom/Animation.h" // for Animation
#include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid, ScrollableLayerGuid::ViewID #include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid, ScrollableLayerGuid::ViewID
@ -164,7 +165,7 @@ class WindowRenderer : public FrameRecorder {
* Note: This may sychronously wait on a remote compositor * Note: This may sychronously wait on a remote compositor
* to complete rendering. * to complete rendering.
*/ */
virtual void FlushRendering() {} virtual void FlushRendering(wr::RenderReasons aReasons) {}
/** /**
* Make sure that the previous transaction has been * Make sure that the previous transaction has been

Просмотреть файл

@ -311,7 +311,7 @@ void nsViewManager::Refresh(nsView* aView,
#endif #endif
WindowRenderer* renderer = widget->GetWindowRenderer(); WindowRenderer* renderer = widget->GetWindowRenderer();
if (!renderer->NeedsWidgetInvalidation()) { if (!renderer->NeedsWidgetInvalidation()) {
renderer->FlushRendering(); renderer->FlushRendering(wr::RenderReasons::WIDGET);
} else { } else {
presShell->SyncPaintFallback(aView); presShell->SyncPaintFallback(aView);
} }

Просмотреть файл

@ -3591,7 +3591,7 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
} }
if (knowsCompositor && layerManager && layerManager->NeedsComposite()) { if (knowsCompositor && layerManager && layerManager->NeedsComposite()) {
layerManager->ScheduleComposite(); layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
layerManager->SetNeedsComposite(false); layerManager->SetNeedsComposite(false);
} }
@ -3863,7 +3863,7 @@ gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
// frame, and its contents might be incorrect. See bug 1280653 comment 7 // frame, and its contents might be incorrect. See bug 1280653 comment 7
// and comment 10. Specifically we must ensure we recomposite the frame // and comment 10. Specifically we must ensure we recomposite the frame
// as soon as possible to avoid the corrupted frame being displayed. // as soon as possible to avoid the corrupted frame being displayed.
GetWindowRenderer()->FlushRendering(); GetWindowRenderer()->FlushRendering(wr::RenderReasons::WIDGET);
return FALSE; return FALSE;
} }
@ -6042,7 +6042,7 @@ void nsWindow::ResumeCompositorHiddenWindow() {
mCompositorState = COMPOSITOR_ENABLED; mCompositorState = COMPOSITOR_ENABLED;
remoteRenderer->SendResumeAsync(); remoteRenderer->SendResumeAsync();
} }
remoteRenderer->SendForcePresent(); remoteRenderer->SendForcePresent(wr::RenderReasons::WIDGET);
} }
} }
@ -6158,7 +6158,7 @@ void nsWindow::ResumeCompositor() {
if (remoteRenderer) { if (remoteRenderer) {
mCompositorState = COMPOSITOR_ENABLED; mCompositorState = COMPOSITOR_ENABLED;
remoteRenderer->SendResumeAsync(); remoteRenderer->SendResumeAsync();
remoteRenderer->SendForcePresent(); remoteRenderer->SendForcePresent(wr::RenderReasons::WIDGET);
} }
} }

Просмотреть файл

@ -206,7 +206,7 @@ void CompositorWidgetParent::UpdateCompositorWnd(const HWND aCompositorWnd,
// Schedule composition after ::SetParent() call in parent // Schedule composition after ::SetParent() call in parent
// process. // process.
layers::CompositorBridgeParent::ScheduleForcedComposition( layers::CompositorBridgeParent::ScheduleForcedComposition(
self->mRootLayerTreeID.ref()); self->mRootLayerTreeID.ref(), wr::RenderReasons::WIDGET);
} }
}, },
[self](const mozilla::ipc::ResponseRejectReason&) {}); [self](const mozilla::ipc::ResponseRejectReason&) {});

Просмотреть файл

@ -127,7 +127,7 @@ nsIWidgetListener* nsWindow::GetPaintListener() {
void nsWindow::ForcePresent() { void nsWindow::ForcePresent() {
if (mResizeState != RESIZING) { if (mResizeState != RESIZING) {
if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) { if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
remoteRenderer->SendForcePresent(); remoteRenderer->SendForcePresent(wr::RenderReasons::WIDGET);
} }
} }
} }
@ -190,7 +190,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) {
!mBounds.IsEqualEdges(mLastPaintBounds)) { !mBounds.IsEqualEdges(mLastPaintBounds)) {
// Do an early async composite so that we at least have something on the // Do an early async composite so that we at least have something on the
// screen in the right place, even if the content is out of date. // screen in the right place, even if the content is out of date.
layerManager->ScheduleComposite(); layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
} }
mLastPaintBounds = mBounds; mLastPaintBounds = mBounds;
@ -256,7 +256,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) {
} }
if (knowsCompositor && layerManager && layerManager->NeedsComposite()) { if (knowsCompositor && layerManager && layerManager->NeedsComposite()) {
layerManager->ScheduleComposite(); layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
layerManager->SetNeedsComposite(false); layerManager->SetNeedsComposite(false);
} }