| author | Matt Woodrow <mwoodrow@mozilla.com> |
| Tue, 08 Nov 2016 15:21:35 +1300 | |
| changeset 321732 | 95ab9f05b980662a420d6d664c1996c0dfb8e4c8 |
| parent 321731 | c6d5c06685a248fd8eaa01d695e4509392db9209 |
| child 321733 | d76e0d2be865f40a4bf86fddd1d5430f74b7b5bf |
| push id | 83661 |
| push user | mwoodrow@mozilla.com |
| push date | Wed, 09 Nov 2016 02:49:51 +0000 |
| treeherder | mozilla-inbound@d76e0d2be865 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | dvander |
| bugs | 1315510 |
| milestone | 52.0a1 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -20,16 +20,17 @@ #include "mozilla/LookAndFeel.h" #include "mozilla/Preferences.h" #include "mozilla/ProcessHangMonitorIPC.h" #include "mozilla/Unused.h" #include "mozilla/devtools/HeapSnapshotTempFileHelperChild.h" #include "mozilla/docshell/OfflineCacheUpdateChild.h" #include "mozilla/dom/ContentBridgeChild.h" #include "mozilla/dom/ContentBridgeParent.h" +#include "mozilla/dom/VideoDecoderManagerChild.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/DataTransfer.h" #include "mozilla/dom/DOMStorageIPC.h" #include "mozilla/dom/ExternalHelperAppChild.h" #include "mozilla/dom/FlyWebPublishedServerIPC.h" #include "mozilla/dom/GetFilesHelper.h" #include "mozilla/dom/PCrashReporterChild.h" #include "mozilla/dom/ProcessGlobal.h" @@ -1176,34 +1177,37 @@ ContentChild::RecvGMPsChanged(nsTArray<G { GeckoMediaPluginServiceChild::UpdateGMPCapabilities(Move(capabilities)); return true; } bool ContentChild::RecvInitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, - Endpoint<PVRManagerChild>&& aVRBridge) + Endpoint<PVRManagerChild>&& aVRBridge, + Endpoint<PVideoDecoderManagerChild>&& aVideoManager) { if (!CompositorBridgeChild::InitForContent(Move(aCompositor))) { return false; } if (!ImageBridgeChild::InitForContent(Move(aImageBridge))) { return false; } if (!gfx::VRManagerChild::InitForContent(Move(aVRBridge))) { return false; } + VideoDecoderManagerChild::InitForContent(Move(aVideoManager)); return true; } bool ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, - Endpoint<PVRManagerChild>&& aVRBridge) + Endpoint<PVRManagerChild>&& aVRBridge, + Endpoint<PVideoDecoderManagerChild>&& aVideoManager) { nsTArray<RefPtr<TabChild>> tabs = TabChild::GetAll(); // Zap all the old layer managers we have lying around. for (const auto& tabChild : tabs) { if (tabChild->LayersId()) { tabChild->InvalidateLayers(); } @@ -1221,16 +1225,18 @@ ContentChild::RecvReinitRendering(Endpoi } // Establish new PLayerTransactions. for (const auto& tabChild : tabs) { if (tabChild->LayersId()) { tabChild->ReinitRendering(); } } + + VideoDecoderManagerChild::InitForContent(Move(aVideoManager)); return true; } PBackgroundChild* ContentChild::AllocPBackgroundChild(Transport* aTransport, ProcessId aOtherProcess) { return BackgroundChild::Alloc(aTransport, aOtherProcess);
--- a/dom/ipc/ContentChild.h +++ b/dom/ipc/ContentChild.h @@ -164,23 +164,25 @@ public: bool RecvGMPsChanged(nsTArray<GMPCapabilityData>&& capabilities) override; bool RecvInitRendering( Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, - Endpoint<PVRManagerChild>&& aVRBridge) override; + Endpoint<PVRManagerChild>&& aVRBridge, + Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override; bool RecvReinitRendering( Endpoint<PCompositorBridgeChild>&& aCompositor, Endpoint<PImageBridgeChild>&& aImageBridge, - Endpoint<PVRManagerChild>&& aVRBridge) override; + Endpoint<PVRManagerChild>&& aVRBridge, + Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override; PProcessHangMonitorChild* AllocPProcessHangMonitorChild(Transport* aTransport, ProcessId aOtherProcess) override; virtual bool RecvSetProcessSandbox(const MaybeFileDesc& aBroker) override; PBackgroundChild*
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1022,23 +1022,16 @@ ContentParent::RecvFindPlugins(const uin nsresult* aRv, nsTArray<PluginTag>* aPlugins, uint32_t* aNewPluginEpoch) { *aRv = mozilla::plugins::FindPluginsForContent(aPluginEpoch, aPlugins, aNewPluginEpoch); return true; } -bool -ContentParent::RecvInitVideoDecoderManager(Endpoint<PVideoDecoderManagerChild>* aEndpoint) -{ - GPUProcessManager::Get()->CreateContentVideoDecoderManager(OtherPid(), aEndpoint); - return true; -} - /*static*/ TabParent* ContentParent::CreateBrowserOrApp(const TabContext& aContext, Element* aFrameElement, ContentParent* aOpenerContentParent, bool aFreshProcess) { PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); @@ -2222,28 +2215,31 @@ ContentParent::InitInternal(ProcessPrior // on demand.) bool useOffMainThreadCompositing = !!CompositorThreadHolder::Loop(); if (useOffMainThreadCompositing) { GPUProcessManager* gpm = GPUProcessManager::Get(); Endpoint<PCompositorBridgeChild> compositor; Endpoint<PImageBridgeChild> imageBridge; Endpoint<PVRManagerChild> vrBridge; + Endpoint<PVideoDecoderManagerChild> videoManager; DebugOnly<bool> opened = gpm->CreateContentBridges( OtherPid(), &compositor, &imageBridge, - &vrBridge); + &vrBridge, + &videoManager); MOZ_ASSERT(opened); Unused << SendInitRendering( Move(compositor), Move(imageBridge), - Move(vrBridge)); + Move(vrBridge), + Move(videoManager)); gpm->AddListener(this); } } if (gAppData) { // Sending all information to content process. Unused << SendAppInit(); @@ -2378,28 +2374,31 @@ ContentParent::RecvGetGfxVars(Infallible void ContentParent::OnCompositorUnexpectedShutdown() { GPUProcessManager* gpm = GPUProcessManager::Get(); Endpoint<PCompositorBridgeChild> compositor; Endpoint<PImageBridgeChild> imageBridge; Endpoint<PVRManagerChild> vrBridge; + Endpoint<PVideoDecoderManagerChild> videoManager; DebugOnly<bool> opened = gpm->CreateContentBridges( OtherPid(), &compositor, &imageBridge, - &vrBridge); + &vrBridge, + &videoManager); MOZ_ASSERT(opened); Unused << SendReinitRendering( Move(compositor), Move(imageBridge), - Move(vrBridge)); + Move(vrBridge), + Move(videoManager)); } void ContentParent::OnVarChanged(const GfxVarUpdate& aVar) { if (!mIPCOpen) { return; }
--- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -257,18 +257,16 @@ public: virtual bool RecvGetBlocklistState(const uint32_t& aPluginId, uint32_t* aIsBlocklisted) override; virtual bool RecvFindPlugins(const uint32_t& aPluginEpoch, nsresult* aRv, nsTArray<PluginTag>* aPlugins, uint32_t* aNewPluginEpoch) override; - virtual bool RecvInitVideoDecoderManager(Endpoint<PVideoDecoderManagerChild>* endpoint) override; - virtual bool RecvUngrabPointer(const uint32_t& aTime) override; virtual bool RecvRemovePermission(const IPC::Principal& aPrincipal, const nsCString& aPermissionType, nsresult* aRv) override; NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ContentParent, nsIObserver)
--- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -424,25 +424,27 @@ both: async PWebBrowserPersistDocument(nullable PBrowser aBrowser, uint64_t aOuterWindowID); child: // Give the content process its endpoints to the compositor. async InitRendering( Endpoint<PCompositorBridgeChild> compositor, Endpoint<PImageBridgeChild> imageBridge, - Endpoint<PVRManagerChild> vr); + Endpoint<PVRManagerChild> vr, + Endpoint<PVideoDecoderManagerChild> video); // Re-create the rendering stack using the given endpoints. This is sent // after the compositor process has crashed. The new endpoints may be to a // newly launched GPU process, or the compositor thread of the UI process. async ReinitRendering( Endpoint<PCompositorBridgeChild> compositor, Endpoint<PImageBridgeChild> bridge, - Endpoint<PVRManagerChild> vr); + Endpoint<PVRManagerChild> vr, + Endpoint<PVideoDecoderManagerChild> video); /** * Enable system-level sandboxing features, if available. Can * usually only be performed zero or one times. The child may * abnormally exit if this fails; the details are OS-specific. */ async SetProcessSandbox(MaybeFileDesc aBroker); @@ -737,18 +739,16 @@ parent: async PJavaScript(); async PRemoteSpellcheckEngine(); async PDeviceStorageRequest(DeviceStorageParams params); sync PCrashReporter(NativeThreadId tid, uint32_t processType); - sync InitVideoDecoderManager() returns (Endpoint<PVideoDecoderManagerChild> endpoint); - /** * Is this token compatible with the provided version? * * |version| The offered version to test * Returns |True| if the offered version is compatible */ sync NSSU2FTokenIsCompatibleVersion(nsString version) returns (bool result);
--- a/dom/media/ipc/RemoteVideoDecoder.cpp +++ b/dom/media/ipc/RemoteVideoDecoder.cpp @@ -4,16 +4,17 @@ * 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 "RemoteVideoDecoder.h" #include "VideoDecoderChild.h" #include "VideoDecoderManagerChild.h" #include "mozilla/layers/TextureClient.h" #include "base/thread.h" #include "MediaInfo.h" +#include "MediaPrefs.h" #include "ImageContainer.h" namespace mozilla { namespace dom { using base::Thread; using namespace ipc; using namespace layers; @@ -142,17 +143,18 @@ PlatformDecoderModule::ConversionRequire RemoteDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const { return mWrapped->DecoderNeedsConversion(aConfig); } already_AddRefed<MediaDataDecoder> RemoteDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) { - if (!aParams.mKnowsCompositor || + if (!MediaPrefs::PDMUseGPUDecoder() || + !aParams.mKnowsCompositor || aParams.mKnowsCompositor->GetTextureFactoryIdentifier().mParentProcessType != GeckoProcessType_GPU) { return nullptr; } MediaDataDecoderCallback* callback = aParams.mCallback; MOZ_ASSERT(callback->OnReaderTaskQueue()); RefPtr<RemoteVideoDecoder> object = new RemoteVideoDecoder(callback);
--- a/dom/media/ipc/VideoDecoderChild.cpp +++ b/dom/media/ipc/VideoDecoderChild.cpp @@ -98,34 +98,45 @@ VideoDecoderChild::RecvInitFailed(const mInitPromise.Reject(aReason, __func__); return true; } void VideoDecoderChild::ActorDestroy(ActorDestroyReason aWhy) { if (aWhy == AbnormalShutdown) { - if (mInitialized) { - mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); - } else { - mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); - } + // Defer reporting an error until we've recreated the manager so that + // it'll be safe for MediaFormatReader to recreate decoders + RefPtr<VideoDecoderChild> ref = this; + GetManager()->RunWhenRecreated(NS_NewRunnableFunction([=]() { + if (ref->mInitialized) { + ref->mCallback->Error(NS_ERROR_DOM_MEDIA_DECODE_ERR); + } else { + ref->mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_DECODE_ERR, __func__); + } + })); } mCanSend = false; } void VideoDecoderChild::InitIPDL(MediaDataDecoderCallback* aCallback, const VideoInfo& aVideoInfo, layers::KnowsCompositor* aKnowsCompositor) { RefPtr<VideoDecoderManagerChild> manager = VideoDecoderManagerChild::GetSingleton(); - if (!manager) { + // If the manager isn't available, then don't initialize mIPDLSelfRef and leave + // us in an error state. We'll then immediately reject the promise when Init() + // is called and the caller can try again. Hopefully by then the new manager is + // ready, or we've notified the caller of it being no longer available. + // If not, then the cycle repeats until we're ready. + if (!manager || !manager->CanSend()) { return; } + mIPDLSelfRef = this; mCallback = aCallback; mVideoInfo = aVideoInfo; mKnowsCompositor = aKnowsCompositor; if (manager->SendPVideoDecoderConstructor(this)) { mCanSend = true; } } @@ -145,96 +156,99 @@ VideoDecoderChild::IPDLActorDestroyed() } // MediaDataDecoder methods RefPtr<MediaDataDecoder::InitPromise> VideoDecoderChild::Init() { AssertOnManagerThread(); - if (!mCanSend || !SendInit(mVideoInfo, mKnowsCompositor->GetTextureFactoryIdentifier())) { + + if (!mIPDLSelfRef) { return MediaDataDecoder::InitPromise::CreateAndReject( - NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); + NS_ERROR_DOM_MEDIA_DECODE_ERR, __func__); + } + // If we failed to send this, then we'll still resolve the Init promise + // as ActorDestroy handles it. + if (mCanSend) { + SendInit(mVideoInfo, mKnowsCompositor->GetTextureFactoryIdentifier()); } return mInitPromise.Ensure(__func__); } void VideoDecoderChild::Input(MediaRawData* aSample) { AssertOnManagerThread(); if (!mCanSend) { - mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); return; } // TODO: It would be nice to add an allocator method to // MediaDataDecoder so that the demuxer could write directly // into shmem rather than requiring a copy here. Shmem buffer; if (!AllocShmem(aSample->Size(), Shmem::SharedMemory::TYPE_BASIC, &buffer)) { - mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + mCallback->Error(NS_ERROR_DOM_MEDIA_DECODE_ERR); return; } memcpy(buffer.get<uint8_t>(), aSample->Data(), aSample->Size()); MediaRawDataIPDL sample(MediaDataIPDL(aSample->mOffset, aSample->mTime, aSample->mTimecode, aSample->mDuration, aSample->mFrames, aSample->mKeyframe), buffer); - if (!SendInput(sample)) { - mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); - } + SendInput(sample); } void VideoDecoderChild::Flush() { AssertOnManagerThread(); - if (!mCanSend || !SendFlush()) { - mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + if (mCanSend) { + SendFlush(); } } void VideoDecoderChild::Drain() { AssertOnManagerThread(); - if (!mCanSend || !SendDrain()) { - mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + if (mCanSend) { + SendDrain(); } } void VideoDecoderChild::Shutdown() { AssertOnManagerThread(); - if (!mCanSend || !SendShutdown()) { - mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + if (mCanSend) { + SendShutdown(); } mInitialized = false; } bool VideoDecoderChild::IsHardwareAccelerated(nsACString& aFailureReason) const { aFailureReason = mHardwareAcceleratedReason; return mIsHardwareAccelerated; } void VideoDecoderChild::SetSeekThreshold(const media::TimeUnit& aTime) { AssertOnManagerThread(); - if (!mCanSend || !SendSetSeekThreshold(aTime.ToMicroseconds())) { - mCallback->Error(NS_ERROR_DOM_MEDIA_FATAL_ERR); + if (mCanSend) { + SendSetSeekThreshold(aTime.ToMicroseconds()); } } void VideoDecoderChild::AssertOnManagerThread() { MOZ_ASSERT(NS_GetCurrentThread() == mThread); }
--- a/dom/media/ipc/VideoDecoderManagerChild.cpp +++ b/dom/media/ipc/VideoDecoderManagerChild.cpp @@ -8,109 +8,98 @@ #include "mozilla/dom/ContentChild.h" #include "MediaPrefs.h" #include "nsThreadUtils.h" #include "mozilla/gfx/2D.h" #include "mozilla/ipc/ProtocolUtils.h" #include "mozilla/layers/SynchronousTask.h" #include "mozilla/gfx/DataSurfaceHelpers.h" #include "mozilla/layers/ISurfaceAllocator.h" +#include "base/task.h" namespace mozilla { namespace dom { using namespace ipc; using namespace layers; using namespace gfx; // Only modified on the main-thread StaticRefPtr<nsIThread> sVideoDecoderChildThread; StaticRefPtr<AbstractThread> sVideoDecoderChildAbstractThread; // Only accessed from sVideoDecoderChildThread static StaticRefPtr<VideoDecoderManagerChild> sDecoderManager; +static UniquePtr<nsTArray<RefPtr<Runnable>>> sRecreateTasks; /* static */ void -VideoDecoderManagerChild::Initialize() +VideoDecoderManagerChild::InitializeThread() { MOZ_ASSERT(NS_IsMainThread()); - MediaPrefs::GetSingleton(); - -#ifdef XP_WIN - if (!MediaPrefs::PDMUseGPUDecoder()) { - return; - } - - // Can't run remote video decoding in the parent process. - if (!ContentChild::GetSingleton()) { - return; - } - if (!sVideoDecoderChildThread) { RefPtr<nsIThread> childThread; nsresult rv = NS_NewNamedThread("VideoChild", getter_AddRefs(childThread)); NS_ENSURE_SUCCESS_VOID(rv); sVideoDecoderChildThread = childThread; sVideoDecoderChildAbstractThread = AbstractThread::CreateXPCOMThreadWrapper(childThread, false); + + sRecreateTasks = MakeUnique<nsTArray<RefPtr<Runnable>>>(); } -#else - return; -#endif +} +/* static */ void +VideoDecoderManagerChild::InitForContent(Endpoint<PVideoDecoderManagerChild>&& aVideoManager) +{ + InitializeThread(); + sVideoDecoderChildThread->Dispatch(NewRunnableFunction(&Open, Move(aVideoManager)), NS_DISPATCH_NORMAL); } /* static */ void VideoDecoderManagerChild::Shutdown() { MOZ_ASSERT(NS_IsMainThread()); if (sVideoDecoderChildThread) { sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([]() { - if (sDecoderManager) { + if (sDecoderManager && sDecoderManager->CanSend()) { sDecoderManager->Close(); sDecoderManager = nullptr; } }), NS_DISPATCH_NORMAL); sVideoDecoderChildAbstractThread = nullptr; sVideoDecoderChildThread->Shutdown(); sVideoDecoderChildThread = nullptr; + + sRecreateTasks = nullptr; } } +void +VideoDecoderManagerChild::RunWhenRecreated(already_AddRefed<Runnable> aTask) +{ + MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread()); + + // If we've already been recreated, then run the task immediately. + if (sDecoderManager && sDecoderManager != this && sDecoderManager->CanSend()) { + RefPtr<Runnable> task = aTask; + task->Run(); + } else { + sRecreateTasks->AppendElement(aTask); + } +} + + /* static */ VideoDecoderManagerChild* VideoDecoderManagerChild::GetSingleton() { MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread()); - - if (!sDecoderManager || !sDecoderManager->mCanSend) { - RefPtr<VideoDecoderManagerChild> manager; - - NS_DispatchToMainThread(NS_NewRunnableFunction([&]() { - Endpoint<PVideoDecoderManagerChild> endpoint; - if (!ContentChild::GetSingleton()->SendInitVideoDecoderManager(&endpoint)) { - return; - } - - if (!endpoint.IsValid()) { - return; - } - - manager = new VideoDecoderManagerChild(); - - RefPtr<Runnable> task = NewRunnableMethod<Endpoint<PVideoDecoderManagerChild>&&>( - manager, &VideoDecoderManagerChild::Open, Move(endpoint)); - sVideoDecoderChildThread->Dispatch(task.forget(), NS_DISPATCH_NORMAL); - }), NS_DISPATCH_SYNC); - - sDecoderManager = manager; - } return sDecoderManager; } /* static */ nsIThread* VideoDecoderManagerChild::GetManagerThread() { return sVideoDecoderChildThread; } @@ -133,43 +122,66 @@ VideoDecoderManagerChild::DeallocPVideoD VideoDecoderChild* child = static_cast<VideoDecoderChild*>(actor); child->IPDLActorDestroyed(); return true; } void VideoDecoderManagerChild::Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint) { - if (!aEndpoint.Bind(this)) { - return; + // Make sure we always dispatch everything in sRecreateTasks, even if we + // fail since this is as close to being recreated as we will ever be. + sDecoderManager = nullptr; + if (aEndpoint.IsValid()) { + RefPtr<VideoDecoderManagerChild> manager = new VideoDecoderManagerChild(); + if (aEndpoint.Bind(manager)) { + sDecoderManager = manager; + manager->InitIPDL(); + } } - AddRef(); + for (Runnable* task : *sRecreateTasks) { + task->Run(); + } + sRecreateTasks->Clear(); +} + +void +VideoDecoderManagerChild::InitIPDL() +{ mCanSend = true; + mIPDLSelfRef = this; } void VideoDecoderManagerChild::ActorDestroy(ActorDestroyReason aWhy) { mCanSend = false; } void VideoDecoderManagerChild::DeallocPVideoDecoderManagerChild() { - Release(); + mIPDLSelfRef = nullptr; +} + +bool +VideoDecoderManagerChild::CanSend() +{ + MOZ_ASSERT(NS_GetCurrentThread() == GetManagerThread()); + return mCanSend; } bool VideoDecoderManagerChild::DeallocShmem(mozilla::ipc::Shmem& aShmem) { if (NS_GetCurrentThread() != sVideoDecoderChildThread) { RefPtr<VideoDecoderManagerChild> self = this; mozilla::ipc::Shmem shmem = aShmem; sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([self, shmem]() { - if (self->mCanSend) { + if (self->CanSend()) { mozilla::ipc::Shmem shmemCopy = shmem; self->DeallocShmem(shmemCopy); } }), NS_DISPATCH_NORMAL); return true; } return PVideoDecoderManagerChild::DeallocShmem(aShmem); } @@ -202,17 +214,17 @@ VideoDecoderManagerChild::Readback(const // loop while it waits. This function can be called from JS and we // don't want that to happen. SynchronousTask task("Readback sync"); RefPtr<VideoDecoderManagerChild> ref = this; SurfaceDescriptor sd; sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([&]() { AutoCompleteTask complete(&task); - if (ref->mCanSend) { + if (ref->CanSend()) { ref->SendReadback(aSD, &sd); } }), NS_DISPATCH_NORMAL); task.Wait(); if (!IsSurfaceDescriptorValid(sd)) { return nullptr; @@ -234,17 +246,17 @@ VideoDecoderManagerChild::Readback(const } void VideoDecoderManagerChild::DeallocateSurfaceDescriptorGPUVideo(const SurfaceDescriptorGPUVideo& aSD) { RefPtr<VideoDecoderManagerChild> ref = this; SurfaceDescriptorGPUVideo sd = Move(aSD); sVideoDecoderChildThread->Dispatch(NS_NewRunnableFunction([ref, sd]() { - if (ref->mCanSend) { + if (ref->CanSend()) { ref->SendDeallocateSurfaceDescriptorGPUVideo(sd); } }), NS_DISPATCH_NORMAL); } void VideoDecoderManagerChild::HandleFatalError(const char* aName, const char* aMsg) const {
--- a/dom/media/ipc/VideoDecoderManagerChild.h +++ b/dom/media/ipc/VideoDecoderManagerChild.h @@ -46,35 +46,50 @@ public: return PVideoDecoderManagerChild::AllocUnsafeShmem(aSize, aShmType, aShmem); } // Can be called from any thread, dispatches the request to the IPDL thread internally // and will be ignored if the IPDL actor has been destroyed. bool DeallocShmem(mozilla::ipc::Shmem& aShmem) override; // Main thread only - static void Initialize(); + static void InitForContent(Endpoint<PVideoDecoderManagerChild>&& aVideoManager); static void Shutdown(); + // Run aTask (on the manager thread) when we next attempt to create a new manager + // (even if creation fails). Intended to be called from ActorDestroy when we get + // notified that the old manager is being destroyed. + // Can only be called from the manager thread. + void RunWhenRecreated(already_AddRefed<Runnable> aTask); + + bool CanSend(); + protected: + void InitIPDL(); + void ActorDestroy(ActorDestroyReason aWhy) override; void DeallocPVideoDecoderManagerChild() override; void HandleFatalError(const char* aName, const char* aMsg) const override; PVideoDecoderChild* AllocPVideoDecoderChild() override; bool DeallocPVideoDecoderChild(PVideoDecoderChild* actor) override; private: + // Main thread only + static void InitializeThread(); + VideoDecoderManagerChild() : mCanSend(false) {} ~VideoDecoderManagerChild() {} - void Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint); + static void Open(Endpoint<PVideoDecoderManagerChild>&& aEndpoint); + + RefPtr<VideoDecoderManagerChild> mIPDLSelfRef; // Should only ever be accessed on the manager thread. bool mCanSend; }; } // namespace dom } // namespace mozilla
--- a/gfx/ipc/GPUProcessManager.cpp +++ b/gfx/ipc/GPUProcessManager.cpp @@ -24,16 +24,17 @@ #include "nsContentUtils.h" #include "VRManagerChild.h" #include "VRManagerParent.h" #include "VsyncBridgeChild.h" #include "VsyncIOThreadHolder.h" #include "VsyncSource.h" #include "mozilla/dom/VideoDecoderManagerChild.h" #include "mozilla/dom/VideoDecoderManagerParent.h" +#include "MediaPrefs.h" namespace mozilla { namespace gfx { using namespace mozilla::layers; static StaticAutoPtr<GPUProcessManager> sSingleton; @@ -539,24 +540,28 @@ GPUProcessManager::CreateRemoteSession(n return nullptr; #endif } bool GPUProcessManager::CreateContentBridges(base::ProcessId aOtherProcess, ipc::Endpoint<PCompositorBridgeChild>* aOutCompositor, ipc::Endpoint<PImageBridgeChild>* aOutImageBridge, - ipc::Endpoint<PVRManagerChild>* aOutVRBridge) + ipc::Endpoint<PVRManagerChild>* aOutVRBridge, + ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager) { if (!CreateContentCompositorBridge(aOtherProcess, aOutCompositor) || !CreateContentImageBridge(aOtherProcess, aOutImageBridge) || !CreateContentVRManager(aOtherProcess, aOutVRBridge)) { return false; } + // VideoDeocderManager is only supported in the GPU process, so we allow this to be + // fallible. + CreateContentVideoDecoderManager(aOtherProcess, aOutVideoManager); return true; } bool GPUProcessManager::CreateContentCompositorBridge(base::ProcessId aOtherProcess, ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint) { EnsureGPUReady(); @@ -662,41 +667,41 @@ GPUProcessManager::CreateContentVRManage return false; } } *aOutEndpoint = Move(childPipe); return true; } -bool +void GPUProcessManager::CreateContentVideoDecoderManager(base::ProcessId aOtherProcess, ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndpoint) { - if (!mGPUChild) { - return false; + if (!mGPUChild || !MediaPrefs::PDMUseGPUDecoder()) { + return; } ipc::Endpoint<dom::PVideoDecoderManagerParent> parentPipe; ipc::Endpoint<dom::PVideoDecoderManagerChild> childPipe; nsresult rv = dom::PVideoDecoderManager::CreateEndpoints( mGPUChild->OtherPid(), aOtherProcess, &parentPipe, &childPipe); if (NS_FAILED(rv)) { gfxCriticalNote << "Could not create content video decoder: " << hexa(int(rv)); - return false; + return; } mGPUChild->SendNewContentVideoDecoderManager(Move(parentPipe)); *aOutEndpoint = Move(childPipe); - return true; + return; } already_AddRefed<IAPZCTreeManager> GPUProcessManager::GetAPZCTreeManagerForLayers(uint64_t aLayersId) { return CompositorBridgeParent::GetAPZCTreeManager(aLayersId); }
--- a/gfx/ipc/GPUProcessManager.h +++ b/gfx/ipc/GPUProcessManager.h @@ -87,19 +87,18 @@ public: bool aUseAPZ, bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize); bool CreateContentBridges( base::ProcessId aOtherProcess, ipc::Endpoint<PCompositorBridgeChild>* aOutCompositor, ipc::Endpoint<PImageBridgeChild>* aOutImageBridge, - ipc::Endpoint<PVRManagerChild>* aOutVRBridge); - bool CreateContentVideoDecoderManager(base::ProcessId aOtherProcess, - ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndPoint); + ipc::Endpoint<PVRManagerChild>* aOutVRBridge, + ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager); // This returns a reference to the APZCTreeManager to which // pan/zoom-related events can be sent. already_AddRefed<IAPZCTreeManager> GetAPZCTreeManagerForLayers(uint64_t aLayersId); // Maps the layer tree and process together so that aOwningPID is allowed // to access aLayersId across process. void MapLayerTreeId(uint64_t aLayersId, base::ProcessId aOwningId); @@ -155,16 +154,18 @@ private: void OnXPCOMShutdown(); bool CreateContentCompositorBridge(base::ProcessId aOtherProcess, ipc::Endpoint<PCompositorBridgeChild>* aOutEndpoint); bool CreateContentImageBridge(base::ProcessId aOtherProcess, ipc::Endpoint<PImageBridgeChild>* aOutEndpoint); bool CreateContentVRManager(base::ProcessId aOtherProcess, ipc::Endpoint<PVRManagerChild>* aOutEndpoint); + void CreateContentVideoDecoderManager(base::ProcessId aOtherProcess, + ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutEndPoint); // Called from RemoteCompositorSession. We track remote sessions so we can // notify their owning widgets that the session must be restarted. void RegisterSession(RemoteCompositorSession* aSession); void UnregisterSession(RemoteCompositorSession* aSession); private: GPUProcessManager();
--- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -62,17 +62,16 @@ #include "DOMStorageObserver.h" #include "CacheObserver.h" #include "DisplayItemClip.h" #include "ActiveLayerTracker.h" #include "CounterStyleManager.h" #include "FrameLayerBuilder.h" #include "AnimationCommon.h" #include "LayerAnimationInfo.h" -#include "mozilla/dom/VideoDecoderManagerChild.h" #include "AudioChannelService.h" #include "mozilla/dom/PromiseDebugging.h" #include "mozilla/dom/WebCryptoThreadPool.h" #ifdef MOZ_XUL #include "nsXULPopupManager.h" #include "nsXULContentUtils.h" @@ -297,18 +296,16 @@ nsLayoutStatics::Initialize() #ifdef DEBUG nsStyleContext::Initialize(); mozilla::LayerAnimationInfo::Initialize(); #endif MediaDecoder::InitStatics(); - VideoDecoderManagerChild::Initialize(); - PromiseDebugging::Init(); mozilla::dom::devicestorage::DeviceStorageStatics::Initialize(); mozilla::dom::WebCryptoThreadPool::Initialize(); // NB: We initialize servo in nsAppRunner.cpp, because we need to do it after // creating the hidden DOM window to support some current stylo hacks. We