зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1125848 - Consolidate PCompositor's creation-destruction logic. r=sotaro
This commit is contained in:
Родитель
bd172b945d
Коммит
cb846d13d3
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/layers/CompositorChild.h"
|
||||
#include "mozilla/layers/CompositorParent.h"
|
||||
#include <stddef.h> // for size_t
|
||||
#include "ClientLayerManager.h" // for ClientLayerManager
|
||||
#include "base/message_loop.h" // for MessageLoop
|
||||
|
@ -39,19 +40,58 @@ Atomic<int32_t> CompositableForwarder::sSerialCounter(0);
|
|||
|
||||
CompositorChild::CompositorChild(ClientLayerManager *aLayerManager)
|
||||
: mLayerManager(aLayerManager)
|
||||
, mCanSend(true)
|
||||
, mCanSend(false)
|
||||
{
|
||||
}
|
||||
|
||||
CompositorChild::~CompositorChild()
|
||||
{
|
||||
if (mCanSend) {
|
||||
gfxCriticalError() << "CompositorChild was not deinitialized";
|
||||
}
|
||||
}
|
||||
|
||||
static void DeferredDestroyCompositor(nsRefPtr<CompositorParent> aCompositorParent,
|
||||
nsRefPtr<CompositorChild> aCompositorChild)
|
||||
{
|
||||
// Bug 848949 needs to be fixed before
|
||||
// we can close the channel properly
|
||||
//aCompositorChild->Close();
|
||||
}
|
||||
|
||||
void
|
||||
CompositorChild::Destroy()
|
||||
{
|
||||
mLayerManager->Destroy();
|
||||
mLayerManager = nullptr;
|
||||
// This must not be called from the destructor!
|
||||
MOZ_ASSERT(mRefCnt != 0);
|
||||
|
||||
if (!mCanSend) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCanSend = false;
|
||||
|
||||
// Destroying the layer manager may cause all sorts of things to happen, so
|
||||
// let's make sure there is still a reference to keep this alive whatever
|
||||
// happens.
|
||||
nsRefPtr<CompositorChild> selfRef = this;
|
||||
|
||||
SendWillStop();
|
||||
// The call just made to SendWillStop can result in IPC from the
|
||||
// CompositorParent to the CompositorChild (e.g. caused by the destruction
|
||||
// of shared memory). We need to ensure this gets processed by the
|
||||
// CompositorChild before it gets destroyed. It suffices to ensure that
|
||||
// events already in the MessageLoop get processed before the
|
||||
// CompositorChild is destroyed, so we add a task to the MessageLoop to
|
||||
// handle compositor desctruction.
|
||||
|
||||
// From now on the only message we can send is Stop.
|
||||
|
||||
if (mLayerManager) {
|
||||
mLayerManager->Destroy();
|
||||
mLayerManager = nullptr;
|
||||
}
|
||||
|
||||
// start from the end of the array because Destroy() can cause the
|
||||
// LayerTransactionChild to be removed from the array.
|
||||
for (int i = ManagedPLayerTransactionChild().Length() - 1; i >= 0; --i) {
|
||||
|
@ -59,8 +99,13 @@ CompositorChild::Destroy()
|
|||
static_cast<LayerTransactionChild*>(ManagedPLayerTransactionChild()[i]);
|
||||
layers->Destroy();
|
||||
}
|
||||
MOZ_ASSERT(!mCanSend);
|
||||
|
||||
SendStop();
|
||||
|
||||
// The DeferredDestroyCompositor task takes ownership of compositorParent and
|
||||
// will release them when it runs.
|
||||
MessageLoop::current()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(DeferredDestroyCompositor, mCompositorParent, selfRef));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -87,6 +132,8 @@ CompositorChild::Create(Transport* aTransport, ProcessId aOtherPid)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
child->mCanSend = true;
|
||||
|
||||
// We release this ref in ActorDestroy().
|
||||
sCompositor = child.forget().take();
|
||||
|
||||
|
@ -99,6 +146,18 @@ CompositorChild::Create(Transport* aTransport, ProcessId aOtherPid)
|
|||
return sCompositor;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorChild::OpenSameProcess(CompositorParent* aParent)
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
|
||||
mCompositorParent = aParent;
|
||||
mCanSend = Open(mCompositorParent->GetIPCChannel(),
|
||||
CompositorParent::CompositorLoop(),
|
||||
ipc::ChildSide);
|
||||
return mCanSend;
|
||||
}
|
||||
|
||||
/*static*/ CompositorChild*
|
||||
CompositorChild::Get()
|
||||
{
|
||||
|
@ -328,14 +387,7 @@ CompositorChild::ActorDestroy(ActorDestroyReason aWhy)
|
|||
NS_RUNTIMEABORT("ActorDestroy by IPC channel failure at CompositorChild");
|
||||
}
|
||||
#endif
|
||||
if (sCompositor) {
|
||||
sCompositor->Release();
|
||||
sCompositor = nullptr;
|
||||
}
|
||||
// We don't want to release the ref to sCompositor here, during
|
||||
// cleanup, because that will cause it to be deleted while it's
|
||||
// still being used. So defer the deletion to after it's not in
|
||||
// use.
|
||||
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableMethod(this, &CompositorChild::Release));
|
||||
|
@ -474,9 +526,6 @@ CompositorChild::CancelNotifyAfterRemotePaint(TabChild* aTabChild)
|
|||
bool
|
||||
CompositorChild::SendWillStop()
|
||||
{
|
||||
MOZ_ASSERT(mCanSend);
|
||||
// From now on the only two messages we can send are WillStop and Stop.
|
||||
mCanSend = false;
|
||||
return PCompositorChild::SendWillStop();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,12 @@ public:
|
|||
static PCompositorChild*
|
||||
Create(Transport* aTransport, ProcessId aOtherProcess);
|
||||
|
||||
/**
|
||||
* Initialize the CompositorChild and open the connection in the non-multi-process
|
||||
* case.
|
||||
*/
|
||||
bool OpenSameProcess(CompositorParent* aParent);
|
||||
|
||||
static CompositorChild* Get();
|
||||
|
||||
static bool ChildProcessHasCompositor() { return sCompositor != nullptr; }
|
||||
|
@ -168,6 +174,9 @@ private:
|
|||
void* aLayerTransactionChild);
|
||||
|
||||
nsRefPtr<ClientLayerManager> mLayerManager;
|
||||
// When not multi-process, hold a reference to the CompositorParent to keep it
|
||||
// alive. This reference should be null in multi-process.
|
||||
nsRefPtr<CompositorParent> mCompositorParent;
|
||||
|
||||
// The ViewID of the FrameMetrics is used as the key for this hash table.
|
||||
// While this should be safe to use since the ViewID is unique
|
||||
|
|
|
@ -181,41 +181,26 @@ nsBaseWidget::Shutdown()
|
|||
mShutdownObserver = nullptr;
|
||||
}
|
||||
|
||||
static void DeferredDestroyCompositor(nsRefPtr<CompositorParent> aCompositorParent,
|
||||
nsRefPtr<CompositorChild> aCompositorChild)
|
||||
{
|
||||
// Bug 848949 needs to be fixed before
|
||||
// we can close the channel properly
|
||||
//aCompositorChild->Close();
|
||||
}
|
||||
|
||||
void nsBaseWidget::DestroyCompositor()
|
||||
{
|
||||
if (mCompositorChild) {
|
||||
nsRefPtr<CompositorChild> compositorChild = mCompositorChild.forget();
|
||||
nsRefPtr<CompositorParent> compositorParent = mCompositorParent.forget();
|
||||
|
||||
compositorChild->SendWillStop();
|
||||
// New LayerManager, CompositorParent and CompositorChild might be created
|
||||
// as a result of internal GetLayerManager() call.
|
||||
compositorChild->Destroy();
|
||||
|
||||
// The call just made to SendWillStop can result in IPC from the
|
||||
// CompositorParent to the CompositorChild (e.g. caused by the destruction
|
||||
// of shared memory). We need to ensure this gets processed by the
|
||||
// CompositorChild before it gets destroyed. It suffices to ensure that
|
||||
// events already in the MessageLoop get processed before the
|
||||
// CompositorChild is destroyed, so we add a task to the MessageLoop to
|
||||
// handle compositor desctruction.
|
||||
|
||||
// The DefferedDestroyCompositor task takes ownership of compositorParent and
|
||||
// will release them when it runs.
|
||||
MessageLoop::current()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(DeferredDestroyCompositor, compositorParent,
|
||||
compositorChild));
|
||||
// XXX CompositorChild and CompositorParent might be re-created in
|
||||
// ClientLayerManager destructor. See bug 1133426.
|
||||
nsRefPtr<CompositorChild> compositorChild = mCompositorChild;
|
||||
nsRefPtr<CompositorParent> compositorParent = mCompositorParent;
|
||||
mCompositorChild->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void nsBaseWidget::DestroyLayerManager()
|
||||
{
|
||||
if (mLayerManager) {
|
||||
mLayerManager->Destroy();
|
||||
mLayerManager = nullptr;
|
||||
}
|
||||
DestroyCompositor();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
// nsBaseWidget destructor
|
||||
|
@ -228,11 +213,6 @@ nsBaseWidget::~nsBaseWidget()
|
|||
static_cast<BasicLayerManager*>(mLayerManager.get())->ClearRetainerWidget();
|
||||
}
|
||||
|
||||
if (mLayerManager) {
|
||||
mLayerManager->Destroy();
|
||||
mLayerManager = nullptr;
|
||||
}
|
||||
|
||||
if (mShutdownObserver) {
|
||||
// If the shutdown observer is currently processing observers,
|
||||
// then UnregisterShutdownObserver won't stop our Observer
|
||||
|
@ -242,7 +222,7 @@ nsBaseWidget::~nsBaseWidget()
|
|||
nsContentUtils::UnregisterShutdownObserver(mShutdownObserver);
|
||||
}
|
||||
|
||||
DestroyCompositor();
|
||||
DestroyLayerManager();
|
||||
|
||||
#ifdef NOISY_WIDGET_LEAKS
|
||||
gNumWidgets--;
|
||||
|
@ -1127,8 +1107,12 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
|
|||
MOZ_ASSERT(gfxPlatform::UsesOffMainThreadCompositing(),
|
||||
"This function assumes OMTC");
|
||||
|
||||
MOZ_ASSERT(!mCompositorParent,
|
||||
"Should have properly cleaned up the previous CompositorParent beforehand");
|
||||
MOZ_ASSERT(!mCompositorParent && !mCompositorChild,
|
||||
"Should have properly cleaned up the previous PCompositor pair beforehand");
|
||||
|
||||
if (mCompositorChild) {
|
||||
mCompositorChild->Destroy();
|
||||
}
|
||||
|
||||
// Recreating this is tricky, as we may still have an old and we need
|
||||
// to make sure it's properly destroyed by calling DestroyCompositor!
|
||||
|
@ -1141,11 +1125,9 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
|
|||
|
||||
CreateCompositorVsyncDispatcher();
|
||||
mCompositorParent = NewCompositorParent(aWidth, aHeight);
|
||||
MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
|
||||
nsRefPtr<ClientLayerManager> lm = new ClientLayerManager(this);
|
||||
MessageLoop *childMessageLoop = CompositorParent::CompositorLoop();
|
||||
mCompositorChild = new CompositorChild(lm);
|
||||
mCompositorChild->Open(parentChannel, childMessageLoop, ipc::ChildSide);
|
||||
mCompositorChild->OpenSameProcess(mCompositorParent);
|
||||
|
||||
// Make sure the parent knows it is same process.
|
||||
mCompositorParent->SetOtherProcessId(kCurrentProcessId);
|
||||
|
@ -1177,26 +1159,20 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
|
|||
backendHints, 0, &textureFactoryIdentifier, &success);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
ShadowLayerForwarder* lf = lm->AsShadowForwarder();
|
||||
if (!lf) {
|
||||
lm = nullptr;
|
||||
mCompositorChild = nullptr;
|
||||
return;
|
||||
}
|
||||
lf->SetShadowManager(shadowManager);
|
||||
lf->IdentifyTextureHost(textureFactoryIdentifier);
|
||||
ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
|
||||
WindowUsesOMTC();
|
||||
ShadowLayerForwarder* lf = lm->AsShadowForwarder();
|
||||
|
||||
mLayerManager = lm.forget();
|
||||
if (!success || !lf) {
|
||||
NS_WARNING("Failed to create an OMT compositor.");
|
||||
DestroyCompositor();
|
||||
return;
|
||||
}
|
||||
|
||||
NS_WARNING("Failed to create an OMT compositor.");
|
||||
DestroyCompositor();
|
||||
// Compositor child had the only reference to LayerManager and will have
|
||||
// deallocated it when being freed.
|
||||
lf->SetShadowManager(shadowManager);
|
||||
lf->IdentifyTextureHost(textureFactoryIdentifier);
|
||||
ImageBridgeChild::IdentifyCompositorTextureHost(textureFactoryIdentifier);
|
||||
WindowUsesOMTC();
|
||||
|
||||
mLayerManager = lm.forget();
|
||||
}
|
||||
|
||||
bool nsBaseWidget::ShouldUseOffMainThreadCompositing()
|
||||
|
|
|
@ -448,6 +448,7 @@ protected:
|
|||
* reached (This is the case with gtk2 for instance).
|
||||
*/
|
||||
void DestroyCompositor();
|
||||
void DestroyLayerManager();
|
||||
|
||||
nsIWidgetListener* mWidgetListener;
|
||||
nsIWidgetListener* mAttachedWidgetListener;
|
||||
|
|
|
@ -673,11 +673,7 @@ NS_METHOD nsWindow::Destroy()
|
|||
* On windows the LayerManagerOGL destructor wants the widget to be around for
|
||||
* cleanup. It also would like to have the HWND intact, so we nullptr it here.
|
||||
*/
|
||||
if (mLayerManager) {
|
||||
mLayerManager->Destroy();
|
||||
}
|
||||
mLayerManager = nullptr;
|
||||
DestroyCompositor();
|
||||
DestroyLayerManager();
|
||||
|
||||
/* We should clear our cached resources now and not wait for the GC to
|
||||
* delete the nsWindow. */
|
||||
|
@ -6544,10 +6540,7 @@ bool nsWindow::AutoErase(HDC dc)
|
|||
void
|
||||
nsWindow::ClearCompositor(nsWindow* aWindow)
|
||||
{
|
||||
if (aWindow->mLayerManager) {
|
||||
aWindow->mLayerManager = nullptr;
|
||||
aWindow->DestroyCompositor();
|
||||
}
|
||||
aWindow->DestroyLayerManager();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
Загрузка…
Ссылка в новой задаче