Bug 1317893 - Add CompositorVsyncScheduler to WebRenderBridgeParent r=kats
This commit is contained in:
@@ -282,308 +282,6 @@ CalculateCompositionFrameRate()
|
||||
}
|
||||
#endif
|
||||
|
||||
CompositorVsyncScheduler::Observer::Observer(CompositorVsyncScheduler* aOwner)
|
||||
: mMutex("CompositorVsyncScheduler.Observer.Mutex")
|
||||
, mOwner(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
CompositorVsyncScheduler::Observer::~Observer()
|
||||
{
|
||||
MOZ_ASSERT(!mOwner);
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorVsyncScheduler::Observer::NotifyVsync(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mOwner) {
|
||||
return false;
|
||||
}
|
||||
return mOwner->NotifyVsync(aVsyncTimestamp);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::Observer::Destroy()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mOwner = nullptr;
|
||||
}
|
||||
|
||||
CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent,
|
||||
widget::CompositorWidget* aWidget)
|
||||
: mCompositorBridgeParent(aCompositorBridgeParent)
|
||||
, mLastCompose(TimeStamp::Now())
|
||||
, mIsObservingVsync(false)
|
||||
, mNeedsComposite(0)
|
||||
, mVsyncNotificationsSkipped(0)
|
||||
, mWidget(aWidget)
|
||||
, mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
|
||||
, mCurrentCompositeTask(nullptr)
|
||||
, mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor")
|
||||
, mSetNeedsCompositeTask(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread() || XRE_GetProcessType() == GeckoProcessType_GPU);
|
||||
mVsyncObserver = new Observer(this);
|
||||
|
||||
// mAsapScheduling is set on the main thread during init,
|
||||
// but is only accessed after on the compositor thread.
|
||||
mAsapScheduling = gfxPrefs::LayersCompositionFrameRate() == 0 ||
|
||||
gfxPlatform::IsInLayoutAsapMode();
|
||||
}
|
||||
|
||||
CompositorVsyncScheduler::~CompositorVsyncScheduler()
|
||||
{
|
||||
MOZ_ASSERT(!mIsObservingVsync);
|
||||
MOZ_ASSERT(!mVsyncObserver);
|
||||
// The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
|
||||
mCompositorBridgeParent = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::Destroy()
|
||||
{
|
||||
if (!mVsyncObserver) {
|
||||
// Destroy was already called on this object.
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
UnobserveVsync();
|
||||
mVsyncObserver->Destroy();
|
||||
mVsyncObserver = nullptr;
|
||||
|
||||
CancelCurrentSetNeedsCompositeTask();
|
||||
CancelCurrentCompositeTask();
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::PostCompositeTask(TimeStamp aCompositeTimestamp)
|
||||
{
|
||||
// can be called from the compositor or vsync thread
|
||||
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
|
||||
if (mCurrentCompositeTask == nullptr && CompositorThreadHolder::Loop()) {
|
||||
RefPtr<CancelableRunnable> task =
|
||||
NewCancelableRunnableMethod<TimeStamp>(this, &CompositorVsyncScheduler::Composite,
|
||||
aCompositeTimestamp);
|
||||
mCurrentCompositeTask = task;
|
||||
ScheduleTask(task.forget(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ScheduleComposition()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
if (mAsapScheduling) {
|
||||
// Used only for performance testing purposes
|
||||
PostCompositeTask(TimeStamp::Now());
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
} else if (mNeedsComposite >= 2 && mIsObservingVsync) {
|
||||
// uh-oh, we already requested a composite at least twice so far, and a
|
||||
// composite hasn't happened yet. It is possible that the vsync observation
|
||||
// is blocked on the main thread, so let's just composite ASAP and not
|
||||
// wait for the vsync. Note that this should only ever happen on Fennec
|
||||
// because there content runs in the same process as the compositor, and so
|
||||
// content can actually block the main thread in this process.
|
||||
PostCompositeTask(TimeStamp::Now());
|
||||
#endif
|
||||
} else {
|
||||
SetNeedsComposite();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::CancelCurrentSetNeedsCompositeTask()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
|
||||
if (mSetNeedsCompositeTask) {
|
||||
mSetNeedsCompositeTask->Cancel();
|
||||
mSetNeedsCompositeTask = nullptr;
|
||||
}
|
||||
mNeedsComposite = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Potential performance heuristics:
|
||||
* If a composite takes 17 ms, do we composite ASAP or wait until next vsync?
|
||||
* If a layer transaction comes after vsync, do we composite ASAP or wait until
|
||||
* next vsync?
|
||||
* How many skipped vsync events until we stop listening to vsync events?
|
||||
*/
|
||||
void
|
||||
CompositorVsyncScheduler::SetNeedsComposite()
|
||||
{
|
||||
if (!CompositorThreadHolder::IsInCompositorThread()) {
|
||||
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
|
||||
RefPtr<CancelableRunnable> task =
|
||||
NewCancelableRunnableMethod(this, &CompositorVsyncScheduler::SetNeedsComposite);
|
||||
mSetNeedsCompositeTask = task;
|
||||
ScheduleTask(task.forget(), 0);
|
||||
return;
|
||||
} else {
|
||||
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
|
||||
mSetNeedsCompositeTask = nullptr;
|
||||
}
|
||||
|
||||
mNeedsComposite++;
|
||||
if (!mIsObservingVsync && mNeedsComposite) {
|
||||
ObserveVsync();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorVsyncScheduler::NotifyVsync(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
// Called from the vsync dispatch thread. When in the GPU Process, that's
|
||||
// the same as the compositor thread.
|
||||
MOZ_ASSERT_IF(XRE_IsParentProcess(), !CompositorThreadHolder::IsInCompositorThread());
|
||||
MOZ_ASSERT_IF(XRE_GetProcessType() == GeckoProcessType_GPU, CompositorThreadHolder::IsInCompositorThread());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
PostCompositeTask(aVsyncTimestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::CancelCurrentCompositeTask()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || NS_IsMainThread());
|
||||
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
|
||||
if (mCurrentCompositeTask) {
|
||||
mCurrentCompositeTask->Cancel();
|
||||
mCurrentCompositeTask = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::Composite(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
{
|
||||
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
|
||||
mCurrentCompositeTask = nullptr;
|
||||
}
|
||||
|
||||
if ((aVsyncTimestamp < mLastCompose) && !mAsapScheduling) {
|
||||
// We can sometimes get vsync timestamps that are in the past
|
||||
// compared to the last compose with force composites.
|
||||
// In those cases, wait until the next vsync;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCompositorBridgeParent);
|
||||
if (!mAsapScheduling && mCompositorBridgeParent->IsPendingComposite()) {
|
||||
// If previous composite is still on going, finish it and does a next
|
||||
// composite in a next vsync.
|
||||
mCompositorBridgeParent->FinishPendingComposite();
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchTouchEvents(aVsyncTimestamp);
|
||||
DispatchVREvents(aVsyncTimestamp);
|
||||
|
||||
if (mNeedsComposite || mAsapScheduling) {
|
||||
mNeedsComposite = 0;
|
||||
mLastCompose = aVsyncTimestamp;
|
||||
ComposeToTarget(nullptr);
|
||||
mVsyncNotificationsSkipped = 0;
|
||||
|
||||
TimeDuration compositeFrameTotal = TimeStamp::Now() - aVsyncTimestamp;
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::COMPOSITE_FRAME_ROUNDTRIP_TIME,
|
||||
compositeFrameTotal.ToMilliseconds());
|
||||
} else if (mVsyncNotificationsSkipped++ > gfxPrefs::CompositorUnobserveCount()) {
|
||||
UnobserveVsync();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::OnForceComposeToTarget()
|
||||
{
|
||||
/**
|
||||
* bug 1138502 - There are cases such as during long-running window resizing events
|
||||
* where we receive many sync RecvFlushComposites. We also get vsync notifications which
|
||||
* will increment mVsyncNotificationsSkipped because a composite just occurred. After
|
||||
* enough vsyncs and RecvFlushComposites occurred, we will disable vsync. Then at the next
|
||||
* ScheduleComposite, we will enable vsync, then get a RecvFlushComposite, which will
|
||||
* force us to unobserve vsync again. On some platforms, enabling/disabling vsync is not
|
||||
* free and this oscillating behavior causes a performance hit. In order to avoid this problem,
|
||||
* we reset the mVsyncNotificationsSkipped counter to keep vsync enabled.
|
||||
*/
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
mVsyncNotificationsSkipped = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
OnForceComposeToTarget();
|
||||
mLastCompose = TimeStamp::Now();
|
||||
ComposeToTarget(aTarget, aRect);
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorVsyncScheduler::NeedsComposite()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
return mNeedsComposite;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ObserveVsync()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
mWidget->ObserveVsync(mVsyncObserver);
|
||||
mIsObservingVsync = true;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::UnobserveVsync()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
mWidget->ObserveVsync(nullptr);
|
||||
mIsObservingVsync = false;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::DispatchVREvents(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
|
||||
VRManager* vm = VRManager::Get();
|
||||
vm->NotifyVsync(aVsyncTimestamp);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ScheduleTask(already_AddRefed<CancelableRunnable> aTask,
|
||||
int aTime)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::Loop());
|
||||
MOZ_ASSERT(aTime >= 0);
|
||||
CompositorThreadHolder::Loop()->PostDelayedTask(Move(aTask), aTime);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ResumeComposition()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
mLastCompose = TimeStamp::Now();
|
||||
ComposeToTarget(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
MOZ_ASSERT(mCompositorBridgeParent);
|
||||
mCompositorBridgeParent->CompositeToTarget(aTarget, aRect);
|
||||
}
|
||||
|
||||
static inline MessageLoop*
|
||||
CompositorLoop()
|
||||
{
|
||||
@@ -1854,7 +1552,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const uint64_t& aPipelineId,
|
||||
|
||||
RefPtr<gl::GLContext> glc(gl::GLContextProvider::CreateForCompositorWidget(mWidget, true));
|
||||
RefPtr<Compositor> compositor = new WebRenderCompositorOGL(glc.get());
|
||||
WebRenderBridgeParent* parent = new WebRenderBridgeParent(aPipelineId,
|
||||
WebRenderBridgeParent* parent = new WebRenderBridgeParent(nullptr, aPipelineId,
|
||||
&aResourcePath, mWidget, glc.get(), nullptr, compositor.get());
|
||||
parent->AddRef(); // IPDL reference
|
||||
MonitorAutoLock lock(*sIndirectLayerTreesLock);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
#include "mozilla/layers/CompositorController.h"
|
||||
#include "mozilla/layers/CompositorVsyncScheduler.h"
|
||||
#include "mozilla/layers/GeckoContentController.h"
|
||||
#include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
|
||||
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
|
||||
@@ -37,7 +38,6 @@
|
||||
#include "mozilla/widget/CompositorWidget.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
#include "mozilla/VsyncDispatcher.h"
|
||||
|
||||
class MessageLoop;
|
||||
class nsIWidget;
|
||||
@@ -83,91 +83,6 @@ private:
|
||||
uint64_t mLayersId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages the vsync (de)registration and tracking on behalf of the
|
||||
* compositor when it need to paint.
|
||||
* Turns vsync notifications into scheduled composites.
|
||||
**/
|
||||
class CompositorVsyncScheduler
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncScheduler)
|
||||
|
||||
public:
|
||||
explicit CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent,
|
||||
widget::CompositorWidget* aWidget);
|
||||
|
||||
bool NotifyVsync(TimeStamp aVsyncTimestamp);
|
||||
void SetNeedsComposite();
|
||||
void OnForceComposeToTarget();
|
||||
|
||||
void ScheduleTask(already_AddRefed<CancelableRunnable>, int);
|
||||
void ResumeComposition();
|
||||
void ComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
|
||||
void PostCompositeTask(TimeStamp aCompositeTimestamp);
|
||||
void Destroy();
|
||||
void ScheduleComposition();
|
||||
void CancelCurrentCompositeTask();
|
||||
bool NeedsComposite();
|
||||
void Composite(TimeStamp aVsyncTimestamp);
|
||||
void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect);
|
||||
|
||||
const TimeStamp& GetLastComposeTime()
|
||||
{
|
||||
return mLastCompose;
|
||||
}
|
||||
|
||||
#ifdef COMPOSITOR_PERFORMANCE_WARNING
|
||||
const TimeStamp& GetExpectedComposeStartTime()
|
||||
{
|
||||
return mExpectedComposeStartTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
virtual ~CompositorVsyncScheduler();
|
||||
|
||||
void NotifyCompositeTaskExecuted();
|
||||
void ObserveVsync();
|
||||
void UnobserveVsync();
|
||||
void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
|
||||
void DispatchVREvents(TimeStamp aVsyncTimestamp);
|
||||
void CancelCurrentSetNeedsCompositeTask();
|
||||
|
||||
class Observer final : public VsyncObserver
|
||||
{
|
||||
public:
|
||||
explicit Observer(CompositorVsyncScheduler* aOwner);
|
||||
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
|
||||
void Destroy();
|
||||
private:
|
||||
virtual ~Observer();
|
||||
|
||||
Mutex mMutex;
|
||||
// Hold raw pointer to avoid mutual reference.
|
||||
CompositorVsyncScheduler* mOwner;
|
||||
};
|
||||
|
||||
CompositorBridgeParent* mCompositorBridgeParent;
|
||||
TimeStamp mLastCompose;
|
||||
|
||||
#ifdef COMPOSITOR_PERFORMANCE_WARNING
|
||||
TimeStamp mExpectedComposeStartTime;
|
||||
#endif
|
||||
|
||||
bool mAsapScheduling;
|
||||
bool mIsObservingVsync;
|
||||
uint32_t mNeedsComposite;
|
||||
int32_t mVsyncNotificationsSkipped;
|
||||
widget::CompositorWidget* mWidget;
|
||||
RefPtr<CompositorVsyncScheduler::Observer> mVsyncObserver;
|
||||
|
||||
mozilla::Monitor mCurrentCompositeTaskMonitor;
|
||||
RefPtr<CancelableRunnable> mCurrentCompositeTask;
|
||||
|
||||
mozilla::Monitor mSetNeedsCompositeMonitor;
|
||||
RefPtr<CancelableRunnable> mSetNeedsCompositeTask;
|
||||
};
|
||||
|
||||
class CompositorBridgeParentBase : public PCompositorBridgeParent,
|
||||
public HostIPCAllocator,
|
||||
public ShmemAllocator,
|
||||
@@ -234,8 +149,8 @@ public:
|
||||
|
||||
class CompositorBridgeParent final : public CompositorBridgeParentBase
|
||||
, public CompositorController
|
||||
, public CompositorVsyncSchedulerOwner
|
||||
{
|
||||
friend class CompositorVsyncScheduler;
|
||||
friend class CompositorThreadHolder;
|
||||
friend class InProcessCompositorSession;
|
||||
friend class gfx::GPUProcessManager;
|
||||
@@ -578,7 +493,6 @@ protected:
|
||||
bool* aSuccess) override;
|
||||
virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers) override;
|
||||
virtual void ScheduleTask(already_AddRefed<CancelableRunnable>, int);
|
||||
void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
|
||||
|
||||
void SetEGLSurfaceSize(int width, int height);
|
||||
|
||||
@@ -589,8 +503,11 @@ protected:
|
||||
void ForceComposition();
|
||||
void CancelCurrentCompositeTask();
|
||||
void Invalidate();
|
||||
bool IsPendingComposite();
|
||||
void FinishPendingComposite();
|
||||
|
||||
// CompositorVsyncSchedulerOwner
|
||||
bool IsPendingComposite() override;
|
||||
void FinishPendingComposite() override;
|
||||
void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override;
|
||||
|
||||
RefPtr<Compositor> NewCompositor(const nsTArray<LayersBackend>& aBackendHints);
|
||||
void ResetCompositorTask(const nsTArray<LayersBackend>& aBackendHints,
|
||||
|
||||
347
gfx/layers/ipc/CompositorVsyncScheduler.cpp
Normal file
347
gfx/layers/ipc/CompositorVsyncScheduler.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=2 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
#include "mozilla/layers/CompositorVsyncScheduler.h"
|
||||
|
||||
#include <stdio.h> // for fprintf, stdout
|
||||
#include <stdint.h> // for uint64_t
|
||||
#include "base/task.h" // for CancelableTask, etc
|
||||
#include "base/thread.h" // for Thread
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
#include "gfxPlatformGtk.h" // for gfxPlatform
|
||||
#endif
|
||||
#include "gfxPrefs.h" // for gfxPrefs
|
||||
#include "mozilla/AutoRestore.h" // for AutoRestore
|
||||
#include "mozilla/DebugOnly.h" // for DebugOnly
|
||||
#include "mozilla/gfx/2D.h" // for DrawTarget
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/gfx/Rect.h" // for IntSize
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_ASSERTION, etc
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsIWidget.h" // for nsIWidget
|
||||
#include "nsThreadUtils.h" // for NS_IsMainThread
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/VsyncDispatcher.h"
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
|
||||
#include "VsyncSource.h"
|
||||
#endif
|
||||
#include "mozilla/widget/CompositorWidget.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace layers {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using namespace std;
|
||||
|
||||
CompositorVsyncScheduler::Observer::Observer(CompositorVsyncScheduler* aOwner)
|
||||
: mMutex("CompositorVsyncScheduler.Observer.Mutex")
|
||||
, mOwner(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
CompositorVsyncScheduler::Observer::~Observer()
|
||||
{
|
||||
MOZ_ASSERT(!mOwner);
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorVsyncScheduler::Observer::NotifyVsync(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (!mOwner) {
|
||||
return false;
|
||||
}
|
||||
return mOwner->NotifyVsync(aVsyncTimestamp);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::Observer::Destroy()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mOwner = nullptr;
|
||||
}
|
||||
|
||||
CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorVsyncSchedulerOwner* aVsyncSchedulerOwner,
|
||||
widget::CompositorWidget* aWidget)
|
||||
: mVsyncSchedulerOwner(aVsyncSchedulerOwner)
|
||||
, mLastCompose(TimeStamp::Now())
|
||||
, mIsObservingVsync(false)
|
||||
, mNeedsComposite(0)
|
||||
, mVsyncNotificationsSkipped(0)
|
||||
, mWidget(aWidget)
|
||||
, mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor")
|
||||
, mCurrentCompositeTask(nullptr)
|
||||
, mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor")
|
||||
, mSetNeedsCompositeTask(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread() || XRE_GetProcessType() == GeckoProcessType_GPU);
|
||||
mVsyncObserver = new Observer(this);
|
||||
|
||||
// mAsapScheduling is set on the main thread during init,
|
||||
// but is only accessed after on the compositor thread.
|
||||
mAsapScheduling = gfxPrefs::LayersCompositionFrameRate() == 0 ||
|
||||
gfxPlatform::IsInLayoutAsapMode();
|
||||
}
|
||||
|
||||
CompositorVsyncScheduler::~CompositorVsyncScheduler()
|
||||
{
|
||||
MOZ_ASSERT(!mIsObservingVsync);
|
||||
MOZ_ASSERT(!mVsyncObserver);
|
||||
// The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners
|
||||
mVsyncSchedulerOwner = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::Destroy()
|
||||
{
|
||||
if (!mVsyncObserver) {
|
||||
// Destroy was already called on this object.
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
UnobserveVsync();
|
||||
mVsyncObserver->Destroy();
|
||||
mVsyncObserver = nullptr;
|
||||
|
||||
CancelCurrentSetNeedsCompositeTask();
|
||||
CancelCurrentCompositeTask();
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::PostCompositeTask(TimeStamp aCompositeTimestamp)
|
||||
{
|
||||
// can be called from the compositor or vsync thread
|
||||
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
|
||||
if (mCurrentCompositeTask == nullptr && CompositorThreadHolder::Loop()) {
|
||||
RefPtr<CancelableRunnable> task =
|
||||
NewCancelableRunnableMethod<TimeStamp>(this, &CompositorVsyncScheduler::Composite,
|
||||
aCompositeTimestamp);
|
||||
mCurrentCompositeTask = task;
|
||||
ScheduleTask(task.forget(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ScheduleComposition()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
if (mAsapScheduling) {
|
||||
// Used only for performance testing purposes
|
||||
PostCompositeTask(TimeStamp::Now());
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
} else if (mNeedsComposite >= 2 && mIsObservingVsync) {
|
||||
// uh-oh, we already requested a composite at least twice so far, and a
|
||||
// composite hasn't happened yet. It is possible that the vsync observation
|
||||
// is blocked on the main thread, so let's just composite ASAP and not
|
||||
// wait for the vsync. Note that this should only ever happen on Fennec
|
||||
// because there content runs in the same process as the compositor, and so
|
||||
// content can actually block the main thread in this process.
|
||||
PostCompositeTask(TimeStamp::Now());
|
||||
#endif
|
||||
} else {
|
||||
SetNeedsComposite();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::CancelCurrentSetNeedsCompositeTask()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
|
||||
if (mSetNeedsCompositeTask) {
|
||||
mSetNeedsCompositeTask->Cancel();
|
||||
mSetNeedsCompositeTask = nullptr;
|
||||
}
|
||||
mNeedsComposite = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Potential performance heuristics:
|
||||
* If a composite takes 17 ms, do we composite ASAP or wait until next vsync?
|
||||
* If a layer transaction comes after vsync, do we composite ASAP or wait until
|
||||
* next vsync?
|
||||
* How many skipped vsync events until we stop listening to vsync events?
|
||||
*/
|
||||
void
|
||||
CompositorVsyncScheduler::SetNeedsComposite()
|
||||
{
|
||||
if (!CompositorThreadHolder::IsInCompositorThread()) {
|
||||
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
|
||||
RefPtr<CancelableRunnable> task =
|
||||
NewCancelableRunnableMethod(this, &CompositorVsyncScheduler::SetNeedsComposite);
|
||||
mSetNeedsCompositeTask = task;
|
||||
ScheduleTask(task.forget(), 0);
|
||||
return;
|
||||
} else {
|
||||
MonitorAutoLock lock(mSetNeedsCompositeMonitor);
|
||||
mSetNeedsCompositeTask = nullptr;
|
||||
}
|
||||
|
||||
mNeedsComposite++;
|
||||
if (!mIsObservingVsync && mNeedsComposite) {
|
||||
ObserveVsync();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorVsyncScheduler::NotifyVsync(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
// Called from the vsync dispatch thread. When in the GPU Process, that's
|
||||
// the same as the compositor thread.
|
||||
MOZ_ASSERT_IF(XRE_IsParentProcess(), !CompositorThreadHolder::IsInCompositorThread());
|
||||
MOZ_ASSERT_IF(XRE_GetProcessType() == GeckoProcessType_GPU, CompositorThreadHolder::IsInCompositorThread());
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
PostCompositeTask(aVsyncTimestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::CancelCurrentCompositeTask()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() || NS_IsMainThread());
|
||||
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
|
||||
if (mCurrentCompositeTask) {
|
||||
mCurrentCompositeTask->Cancel();
|
||||
mCurrentCompositeTask = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::Composite(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
{
|
||||
MonitorAutoLock lock(mCurrentCompositeTaskMonitor);
|
||||
mCurrentCompositeTask = nullptr;
|
||||
}
|
||||
|
||||
if ((aVsyncTimestamp < mLastCompose) && !mAsapScheduling) {
|
||||
// We can sometimes get vsync timestamps that are in the past
|
||||
// compared to the last compose with force composites.
|
||||
// In those cases, wait until the next vsync;
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mVsyncSchedulerOwner);
|
||||
if (!mAsapScheduling && mVsyncSchedulerOwner->IsPendingComposite()) {
|
||||
// If previous composite is still on going, finish it and does a next
|
||||
// composite in a next vsync.
|
||||
mVsyncSchedulerOwner->FinishPendingComposite();
|
||||
return;
|
||||
}
|
||||
|
||||
DispatchTouchEvents(aVsyncTimestamp);
|
||||
DispatchVREvents(aVsyncTimestamp);
|
||||
|
||||
if (mNeedsComposite || mAsapScheduling) {
|
||||
mNeedsComposite = 0;
|
||||
mLastCompose = aVsyncTimestamp;
|
||||
ComposeToTarget(nullptr);
|
||||
mVsyncNotificationsSkipped = 0;
|
||||
|
||||
TimeDuration compositeFrameTotal = TimeStamp::Now() - aVsyncTimestamp;
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::COMPOSITE_FRAME_ROUNDTRIP_TIME,
|
||||
compositeFrameTotal.ToMilliseconds());
|
||||
} else if (mVsyncNotificationsSkipped++ > gfxPrefs::CompositorUnobserveCount()) {
|
||||
UnobserveVsync();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::OnForceComposeToTarget()
|
||||
{
|
||||
/**
|
||||
* bug 1138502 - There are cases such as during long-running window resizing events
|
||||
* where we receive many sync RecvFlushComposites. We also get vsync notifications which
|
||||
* will increment mVsyncNotificationsSkipped because a composite just occurred. After
|
||||
* enough vsyncs and RecvFlushComposites occurred, we will disable vsync. Then at the next
|
||||
* ScheduleComposite, we will enable vsync, then get a RecvFlushComposite, which will
|
||||
* force us to unobserve vsync again. On some platforms, enabling/disabling vsync is not
|
||||
* free and this oscillating behavior causes a performance hit. In order to avoid this problem,
|
||||
* we reset the mVsyncNotificationsSkipped counter to keep vsync enabled.
|
||||
*/
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
mVsyncNotificationsSkipped = 0;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ForceComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
OnForceComposeToTarget();
|
||||
mLastCompose = TimeStamp::Now();
|
||||
ComposeToTarget(aTarget, aRect);
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorVsyncScheduler::NeedsComposite()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
return mNeedsComposite;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ObserveVsync()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
mWidget->ObserveVsync(mVsyncObserver);
|
||||
mIsObservingVsync = true;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::UnobserveVsync()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
mWidget->ObserveVsync(nullptr);
|
||||
mIsObservingVsync = false;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::DispatchTouchEvents(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::DispatchVREvents(TimeStamp aVsyncTimestamp)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
|
||||
VRManager* vm = VRManager::Get();
|
||||
vm->NotifyVsync(aVsyncTimestamp);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ScheduleTask(already_AddRefed<CancelableRunnable> aTask,
|
||||
int aTime)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::Loop());
|
||||
MOZ_ASSERT(aTime >= 0);
|
||||
CompositorThreadHolder::Loop()->PostDelayedTask(Move(aTask), aTime);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ResumeComposition()
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
mLastCompose = TimeStamp::Now();
|
||||
ComposeToTarget(nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
CompositorVsyncScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const IntRect* aRect)
|
||||
{
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
|
||||
MOZ_ASSERT(mVsyncSchedulerOwner);
|
||||
mVsyncSchedulerOwner->CompositeToTarget(aTarget, aRect);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
131
gfx/layers/ipc/CompositorVsyncScheduler.h
Normal file
131
gfx/layers/ipc/CompositorVsyncScheduler.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* 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/. */
|
||||
|
||||
#ifndef mozilla_layers_CompositorVsyncScheduler_h
|
||||
#define mozilla_layers_CompositorVsyncScheduler_h
|
||||
|
||||
#include <stdint.h> // for uint64_t
|
||||
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/Monitor.h" // for Monitor
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/TimeStamp.h" // for TimeStamp
|
||||
#include "mozilla/gfx/Point.h" // for IntSize
|
||||
#include "mozilla/VsyncDispatcher.h"
|
||||
#include "mozilla/widget/CompositorWidget.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
|
||||
class MessageLoop;
|
||||
class nsIWidget;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CancelableRunnable;
|
||||
|
||||
namespace gfx {
|
||||
class DrawTarget;
|
||||
} // namespace gfx
|
||||
|
||||
namespace layers {
|
||||
|
||||
class CompositorVsyncSchedulerOwner
|
||||
{
|
||||
public:
|
||||
virtual bool IsPendingComposite() = 0;
|
||||
virtual void FinishPendingComposite() = 0;
|
||||
virtual void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages the vsync (de)registration and tracking on behalf of the
|
||||
* compositor when it need to paint.
|
||||
* Turns vsync notifications into scheduled composites.
|
||||
**/
|
||||
class CompositorVsyncScheduler
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncScheduler)
|
||||
|
||||
public:
|
||||
explicit CompositorVsyncScheduler(CompositorVsyncSchedulerOwner* aVsyncSchedulerOwner,
|
||||
widget::CompositorWidget* aWidget);
|
||||
|
||||
bool NotifyVsync(TimeStamp aVsyncTimestamp);
|
||||
void SetNeedsComposite();
|
||||
void OnForceComposeToTarget();
|
||||
|
||||
void ScheduleTask(already_AddRefed<CancelableRunnable>, int);
|
||||
void ResumeComposition();
|
||||
void ComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr);
|
||||
void PostCompositeTask(TimeStamp aCompositeTimestamp);
|
||||
void Destroy();
|
||||
void ScheduleComposition();
|
||||
void CancelCurrentCompositeTask();
|
||||
bool NeedsComposite();
|
||||
void Composite(TimeStamp aVsyncTimestamp);
|
||||
void ForceComposeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect);
|
||||
|
||||
const TimeStamp& GetLastComposeTime()
|
||||
{
|
||||
return mLastCompose;
|
||||
}
|
||||
|
||||
#ifdef COMPOSITOR_PERFORMANCE_WARNING
|
||||
const TimeStamp& GetExpectedComposeStartTime()
|
||||
{
|
||||
return mExpectedComposeStartTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
virtual ~CompositorVsyncScheduler();
|
||||
|
||||
void NotifyCompositeTaskExecuted();
|
||||
void ObserveVsync();
|
||||
void UnobserveVsync();
|
||||
void DispatchTouchEvents(TimeStamp aVsyncTimestamp);
|
||||
void DispatchVREvents(TimeStamp aVsyncTimestamp);
|
||||
void CancelCurrentSetNeedsCompositeTask();
|
||||
|
||||
class Observer final : public VsyncObserver
|
||||
{
|
||||
public:
|
||||
explicit Observer(CompositorVsyncScheduler* aOwner);
|
||||
virtual bool NotifyVsync(TimeStamp aVsyncTimestamp) override;
|
||||
void Destroy();
|
||||
private:
|
||||
virtual ~Observer();
|
||||
|
||||
Mutex mMutex;
|
||||
// Hold raw pointer to avoid mutual reference.
|
||||
CompositorVsyncScheduler* mOwner;
|
||||
};
|
||||
|
||||
CompositorVsyncSchedulerOwner* mVsyncSchedulerOwner;
|
||||
TimeStamp mLastCompose;
|
||||
|
||||
#ifdef COMPOSITOR_PERFORMANCE_WARNING
|
||||
TimeStamp mExpectedComposeStartTime;
|
||||
#endif
|
||||
|
||||
bool mAsapScheduling;
|
||||
bool mIsObservingVsync;
|
||||
uint32_t mNeedsComposite;
|
||||
int32_t mVsyncNotificationsSkipped;
|
||||
widget::CompositorWidget* mWidget;
|
||||
RefPtr<CompositorVsyncScheduler::Observer> mVsyncObserver;
|
||||
|
||||
mozilla::Monitor mCurrentCompositeTaskMonitor;
|
||||
RefPtr<CancelableRunnable> mCurrentCompositeTask;
|
||||
|
||||
mozilla::Monitor mSetNeedsCompositeMonitor;
|
||||
RefPtr<CancelableRunnable> mSetNeedsCompositeTask;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_layers_CompositorVsyncScheduler_h
|
||||
@@ -269,7 +269,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const uint64_t&
|
||||
WebRenderBridgeParent* root = sIndirectLayerTrees[cbp->RootLayerTreeId()].mWRBridge.get();
|
||||
|
||||
WebRenderBridgeParent* parent = new WebRenderBridgeParent(
|
||||
aPipelineId, nullptr, nullptr, root->GLContext(), root->WindowState(), root->Compositor());
|
||||
root, aPipelineId, nullptr, nullptr, root->GLContext(), root->WindowState(), root->Compositor());
|
||||
parent->AddRef(); // IPDL reference
|
||||
sIndirectLayerTrees[aPipelineId].mWRBridge = parent;
|
||||
|
||||
|
||||
@@ -168,6 +168,7 @@ EXPORTS.mozilla.layers += [
|
||||
'ipc/CompositorBridgeChild.h',
|
||||
'ipc/CompositorBridgeParent.h',
|
||||
'ipc/CompositorThread.h',
|
||||
'ipc/CompositorVsyncScheduler.h',
|
||||
'ipc/CrossProcessCompositorBridgeParent.h',
|
||||
'ipc/ImageBridgeChild.h',
|
||||
'ipc/ImageBridgeParent.h',
|
||||
@@ -341,6 +342,7 @@ UNIFIED_SOURCES += [
|
||||
'ipc/CompositorBridgeChild.cpp',
|
||||
'ipc/CompositorBridgeParent.cpp',
|
||||
'ipc/CompositorThread.cpp',
|
||||
'ipc/CompositorVsyncScheduler.cpp',
|
||||
'ipc/CrossProcessCompositorBridgeParent.cpp',
|
||||
'ipc/ImageBridgeChild.cpp',
|
||||
'ipc/ImageBridgeParent.cpp',
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
WebRenderBridgeParent::WebRenderBridgeParent(const uint64_t& aPipelineId,
|
||||
WebRenderBridgeParent::WebRenderBridgeParent(WebRenderBridgeParent* aParent,
|
||||
const uint64_t& aPipelineId,
|
||||
const nsString* aResourcePath,
|
||||
widget::CompositorWidget* aWidget,
|
||||
gl::GLContext* aGlContext,
|
||||
wrwindowstate* aWrWindowState,
|
||||
layers::Compositor* aCompositor)
|
||||
: mPipelineId(aPipelineId)
|
||||
: mParent(aParent)
|
||||
, mPipelineId(aPipelineId)
|
||||
, mWidget(aWidget)
|
||||
, mWRState(nullptr)
|
||||
, mGLContext(aGlContext)
|
||||
@@ -38,6 +40,9 @@ WebRenderBridgeParent::WebRenderBridgeParent(const uint64_t& aPipelineId,
|
||||
mWRWindowState = wr_init_window(mPipelineId,
|
||||
NS_ConvertUTF16toUTF8(*aResourcePath).get());
|
||||
}
|
||||
if (mWidget) {
|
||||
mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
@@ -65,6 +70,11 @@ WebRenderBridgeParent::RecvDestroy()
|
||||
// the compositor ref and needs to destroy it.
|
||||
mCompositor->Destroy();
|
||||
}
|
||||
if (mCompositorScheduler) {
|
||||
mCompositorScheduler->Destroy();
|
||||
mCompositorScheduler = nullptr;
|
||||
}
|
||||
mParent = nullptr;
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
@@ -109,17 +119,6 @@ WebRenderBridgeParent::RecvDPBegin(const uint32_t& aWidth,
|
||||
bool* aOutSuccess)
|
||||
{
|
||||
MOZ_ASSERT(mWRState);
|
||||
if (mWidget) {
|
||||
mozilla::widget::WidgetRenderingContext widgetContext;
|
||||
#if defined(XP_MACOSX)
|
||||
widgetContext.mGL = mGLContext;
|
||||
#endif
|
||||
if (!mWidget->PreRender(&widgetContext)) {
|
||||
*aOutSuccess = false;
|
||||
return IPC_OK();
|
||||
}
|
||||
}
|
||||
mGLContext->MakeCurrent();
|
||||
wr_dp_begin(mWRWindowState, mWRState, aWidth, aHeight);
|
||||
*aOutSuccess = true;
|
||||
return IPC_OK();
|
||||
@@ -161,19 +160,37 @@ WebRenderBridgeParent::RecvDPEnd(InfallibleTArray<WebRenderCommand>&& commands)
|
||||
NS_RUNTIMEABORT("not reached");
|
||||
}
|
||||
}
|
||||
mGLContext->MakeCurrent();
|
||||
wr_dp_end(mWRWindowState, mWRState);
|
||||
mGLContext->SwapBuffers();
|
||||
if (mWidget) {
|
||||
ScheduleComposition();
|
||||
DeleteOldImages();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect)
|
||||
{
|
||||
if (aTarget) {
|
||||
// XXX Add compositing to DrawTarget
|
||||
return;
|
||||
}
|
||||
if (!mWidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWRState);
|
||||
{
|
||||
mozilla::widget::WidgetRenderingContext widgetContext;
|
||||
#if defined(XP_MACOSX)
|
||||
widgetContext.mGL = mGLContext;
|
||||
#endif
|
||||
mWidget->PostRender(&widgetContext);
|
||||
if (!mWidget->PreRender(&widgetContext)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DeleteOldImages();
|
||||
return IPC_OK();
|
||||
mGLContext->MakeCurrent();
|
||||
wr_composite(mWRWindowState);
|
||||
mGLContext->SwapBuffers();
|
||||
}
|
||||
|
||||
WebRenderBridgeParent::~WebRenderBridgeParent()
|
||||
@@ -189,5 +206,15 @@ WebRenderBridgeParent::DeleteOldImages()
|
||||
mKeysToDelete.clear();
|
||||
}
|
||||
|
||||
void
|
||||
WebRenderBridgeParent::ScheduleComposition()
|
||||
{
|
||||
if (mWidget) {
|
||||
mCompositorScheduler->ScheduleComposition();
|
||||
} else {
|
||||
mParent->ScheduleComposition();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define mozilla_layers_WebRenderBridgeParent_h
|
||||
|
||||
#include "GLContextProvider.h"
|
||||
#include "mozilla/layers/CompositorVsyncScheduler.h"
|
||||
#include "mozilla/layers/PWebRenderBridgeParent.h"
|
||||
#include "mozilla/layers/WebRenderTypes.h"
|
||||
|
||||
@@ -26,11 +27,13 @@ namespace layers {
|
||||
class Compositor;
|
||||
|
||||
class WebRenderBridgeParent final : public PWebRenderBridgeParent
|
||||
, public CompositorVsyncSchedulerOwner
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderBridgeParent)
|
||||
|
||||
public:
|
||||
WebRenderBridgeParent(const uint64_t& aPipelineId,
|
||||
WebRenderBridgeParent(WebRenderBridgeParent* aParent,
|
||||
const uint64_t& aPipelineId,
|
||||
const nsString* aResourcePath,
|
||||
widget::CompositorWidget* aWidget,
|
||||
gl::GLContext* aGlContext,
|
||||
@@ -63,17 +66,25 @@ public:
|
||||
|
||||
void ActorDestroy(ActorDestroyReason aWhy) override {}
|
||||
|
||||
// CompositorVsyncSchedulerOwner
|
||||
bool IsPendingComposite() override { return false; }
|
||||
void FinishPendingComposite() override { }
|
||||
void CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect = nullptr) override;
|
||||
|
||||
protected:
|
||||
virtual ~WebRenderBridgeParent();
|
||||
void DeleteOldImages();
|
||||
|
||||
void ScheduleComposition();
|
||||
private:
|
||||
// XXX remove mParent in Bug 1317935
|
||||
RefPtr<WebRenderBridgeParent> mParent;
|
||||
uint64_t mPipelineId;
|
||||
RefPtr<widget::CompositorWidget> mWidget;
|
||||
wrstate* mWRState;
|
||||
RefPtr<gl::GLContext> mGLContext;
|
||||
wrwindowstate* mWRWindowState;
|
||||
RefPtr<layers::Compositor> mCompositor;
|
||||
RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
|
||||
std::vector<WRImageKey> mKeysToDelete;
|
||||
};
|
||||
|
||||
|
||||
@@ -375,17 +375,13 @@ pub extern fn wr_dp_end(window: &mut WrWindowState, state: &mut WrState) {
|
||||
fb.root_dl_builder.finalize(),
|
||||
fb.auxiliary_lists_builder.finalize()
|
||||
);
|
||||
|
||||
gl::clear(gl::COLOR_BUFFER_BIT);
|
||||
window.renderer.update();
|
||||
|
||||
window.renderer.render(window.size);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn wr_composite(window: &mut WrWindowState) {
|
||||
window.api.generate_frame();
|
||||
|
||||
gl::clear(gl::COLOR_BUFFER_BIT);
|
||||
window.renderer.update();
|
||||
window.renderer.render(window.size);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user