VideoBridgeChild.cpp (5617B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "VideoBridgeChild.h" 8 #include "VideoBridgeParent.h" 9 #include "CompositorThread.h" 10 #include "mozilla/dom/ContentChild.h" 11 #include "mozilla/ipc/Endpoint.h" 12 #include "mozilla/StaticMutex.h" 13 #include "transport/runnable_utils.h" 14 #include "SynchronousTask.h" 15 16 namespace mozilla { 17 namespace layers { 18 19 // Singleton 20 static StaticMutex sVideoBridgeLock MOZ_UNANNOTATED; 21 StaticRefPtr<VideoBridgeChild> sVideoBridge; 22 23 /* static */ 24 void VideoBridgeChild::StartupForGPUProcess() { 25 ipc::Endpoint<PVideoBridgeParent> parentPipe; 26 ipc::Endpoint<PVideoBridgeChild> childPipe; 27 28 PVideoBridge::CreateEndpoints(ipc::EndpointProcInfo::Current(), 29 ipc::EndpointProcInfo::Current(), &parentPipe, 30 &childPipe); 31 32 VideoBridgeChild::Open(std::move(childPipe)); 33 VideoBridgeParent::Open(std::move(parentPipe), VideoBridgeSource::GpuProcess); 34 } 35 36 /* static */ 37 void VideoBridgeChild::Open(Endpoint<PVideoBridgeChild>&& aEndpoint) { 38 StaticMutexAutoLock lock(sVideoBridgeLock); 39 MOZ_ASSERT(!sVideoBridge || !sVideoBridge->CanSend()); 40 sVideoBridge = new VideoBridgeChild(); 41 42 if (!aEndpoint.Bind(sVideoBridge)) { 43 // We can't recover from this. 44 MOZ_CRASH("Failed to bind VideoBridgeChild to endpoint"); 45 } 46 } 47 48 /* static */ 49 void VideoBridgeChild::Shutdown() { 50 StaticMutexAutoLock lock(sVideoBridgeLock); 51 if (sVideoBridge) { 52 sVideoBridge->Close(); 53 sVideoBridge = nullptr; 54 } 55 } 56 57 VideoBridgeChild::VideoBridgeChild() 58 : mThread(GetCurrentSerialEventTarget()), mCanSend(true) {} 59 60 VideoBridgeChild::~VideoBridgeChild() = default; 61 62 VideoBridgeChild* VideoBridgeChild::GetSingleton() { 63 StaticMutexAutoLock lock(sVideoBridgeLock); 64 return sVideoBridge; 65 } 66 67 bool VideoBridgeChild::AllocUnsafeShmem(size_t aSize, ipc::Shmem* aShmem) { 68 if (!mThread->IsOnCurrentThread()) { 69 return DispatchAllocShmemInternal(aSize, aShmem, true); // true: unsafe 70 } 71 72 if (!CanSend()) { 73 return false; 74 } 75 76 return PVideoBridgeChild::AllocUnsafeShmem(aSize, aShmem); 77 } 78 79 bool VideoBridgeChild::AllocShmem(size_t aSize, ipc::Shmem* aShmem) { 80 MOZ_ASSERT(CanSend()); 81 return PVideoBridgeChild::AllocShmem(aSize, aShmem); 82 } 83 84 void VideoBridgeChild::ProxyAllocShmemNow(SynchronousTask* aTask, size_t aSize, 85 ipc::Shmem* aShmem, bool aUnsafe, 86 bool* aSuccess) { 87 AutoCompleteTask complete(aTask); 88 89 if (!CanSend()) { 90 return; 91 } 92 93 bool ok = false; 94 if (aUnsafe) { 95 ok = AllocUnsafeShmem(aSize, aShmem); 96 } else { 97 ok = AllocShmem(aSize, aShmem); 98 } 99 *aSuccess = ok; 100 } 101 102 bool VideoBridgeChild::DispatchAllocShmemInternal(size_t aSize, 103 ipc::Shmem* aShmem, 104 bool aUnsafe) { 105 SynchronousTask task("AllocatorProxy alloc"); 106 107 bool success = false; 108 RefPtr<Runnable> runnable = WrapRunnable( 109 RefPtr<VideoBridgeChild>(this), &VideoBridgeChild::ProxyAllocShmemNow, 110 &task, aSize, aShmem, aUnsafe, &success); 111 GetThread()->Dispatch(runnable.forget()); 112 113 task.Wait(); 114 115 return success; 116 } 117 118 void VideoBridgeChild::ProxyDeallocShmemNow(SynchronousTask* aTask, 119 ipc::Shmem* aShmem, bool* aResult) { 120 AutoCompleteTask complete(aTask); 121 122 if (!CanSend()) { 123 return; 124 } 125 *aResult = DeallocShmem(*aShmem); 126 } 127 128 bool VideoBridgeChild::DeallocShmem(ipc::Shmem& aShmem) { 129 if (GetThread()->IsOnCurrentThread()) { 130 if (!CanSend()) { 131 return false; 132 } 133 return PVideoBridgeChild::DeallocShmem(aShmem); 134 } 135 136 SynchronousTask task("AllocatorProxy Dealloc"); 137 bool result = false; 138 139 RefPtr<Runnable> runnable = WrapRunnable( 140 RefPtr<VideoBridgeChild>(this), &VideoBridgeChild::ProxyDeallocShmemNow, 141 &task, &aShmem, &result); 142 GetThread()->Dispatch(runnable.forget()); 143 144 task.Wait(); 145 return result; 146 } 147 148 PTextureChild* VideoBridgeChild::AllocPTextureChild( 149 const SurfaceDescriptor&, ReadLockDescriptor&, const LayersBackend&, 150 const TextureFlags&, const dom::ContentParentId& aContentId, 151 const uint64_t& aSerial) { 152 MOZ_ASSERT(CanSend()); 153 return TextureClient::CreateIPDLActor(); 154 } 155 156 bool VideoBridgeChild::DeallocPTextureChild(PTextureChild* actor) { 157 return TextureClient::DestroyIPDLActor(actor); 158 } 159 160 void VideoBridgeChild::ActorDestroy(ActorDestroyReason aWhy) { 161 mCanSend = false; 162 } 163 164 PTextureChild* VideoBridgeChild::CreateTexture( 165 const SurfaceDescriptor& aSharedData, ReadLockDescriptor&& aReadLock, 166 LayersBackend aLayersBackend, TextureFlags aFlags, 167 const dom::ContentParentId& aContentId, uint64_t aSerial, 168 wr::MaybeExternalImageId& aExternalImageId) { 169 MOZ_ASSERT(CanSend()); 170 return SendPTextureConstructor(aSharedData, std::move(aReadLock), 171 aLayersBackend, aFlags, aContentId, aSerial); 172 } 173 174 bool VideoBridgeChild::IsSameProcess() const { 175 return OtherPid() == base::GetCurrentProcId(); 176 } 177 178 void VideoBridgeChild::HandleFatalError(const char* aMsg) { 179 dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherChildID()); 180 } 181 182 mozilla::ipc::IPCResult VideoBridgeChild::RecvPing(PingResolver&& aResolver) { 183 aResolver(void_t{}); 184 return IPC_OK(); 185 } 186 187 } // namespace layers 188 } // namespace mozilla