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 "mozilla/layers/CompositorManagerParent.h"
8 #include "mozilla/gfx/GPUParent.h"
9 #include "mozilla/layers/CompositorBridgeParent.h"
10 #include "mozilla/layers/CrossProcessCompositorBridgeParent.h"
11 #include "mozilla/layers/CompositorThread.h"
12 #include "mozilla/layers/SharedSurfacesParent.h"
13 #include "nsAutoPtr.h"
14 #include "VsyncSource.h"
15
16 namespace mozilla {
17 namespace layers {
18
19 StaticRefPtr<CompositorManagerParent> CompositorManagerParent::sInstance;
20 StaticMutex CompositorManagerParent::sMutex;
21
22 #ifdef COMPOSITOR_MANAGER_PARENT_EXPLICIT_SHUTDOWN
23 StaticAutoPtr<nsTArray<CompositorManagerParent*>>
24 CompositorManagerParent::sActiveActors;
25 #endif
26
27 /* static */ already_AddRefed<CompositorManagerParent>
CreateSameProcess()28 CompositorManagerParent::CreateSameProcess() {
29 MOZ_ASSERT(XRE_IsParentProcess());
30 MOZ_ASSERT(NS_IsMainThread());
31 StaticMutexAutoLock lock(sMutex);
32
33 // We are creating a manager for the UI process, inside the combined GPU/UI
34 // process. It is created more-or-less the same but we retain a reference to
35 // the parent to access state.
36 if (NS_WARN_IF(sInstance)) {
37 MOZ_ASSERT_UNREACHABLE("Already initialized");
38 return nullptr;
39 }
40
41 // The child is responsible for setting up the IPC channel in the same
42 // process case because if we open from the child perspective, we can do it
43 // on the main thread and complete before we return the manager handles.
44 RefPtr<CompositorManagerParent> parent = new CompositorManagerParent();
45 parent->SetOtherProcessId(base::GetCurrentProcId());
46 return parent.forget();
47 }
48
49 /* static */
Create(Endpoint<PCompositorManagerParent> && aEndpoint)50 bool CompositorManagerParent::Create(
51 Endpoint<PCompositorManagerParent>&& aEndpoint) {
52 MOZ_ASSERT(NS_IsMainThread());
53
54 // We are creating a manager for the another process, inside the GPU process
55 // (or UI process if it subsumbed the GPU process).
56 MOZ_ASSERT(aEndpoint.OtherPid() != base::GetCurrentProcId());
57
58 if (!CompositorThreadHolder::IsActive()) {
59 return false;
60 }
61
62 RefPtr<CompositorManagerParent> bridge = new CompositorManagerParent();
63
64 RefPtr<Runnable> runnable =
65 NewRunnableMethod<Endpoint<PCompositorManagerParent>&&>(
66 "CompositorManagerParent::Bind", bridge,
67 &CompositorManagerParent::Bind, Move(aEndpoint));
68 CompositorThreadHolder::Loop()->PostTask(runnable.forget());
69 return true;
70 }
71
72 /* static */ already_AddRefed<CompositorBridgeParent>
CreateSameProcessWidgetCompositorBridge(CSSToLayoutDeviceScale aScale,const CompositorOptions & aOptions,bool aUseExternalSurfaceSize,const gfx::IntSize & aSurfaceSize)73 CompositorManagerParent::CreateSameProcessWidgetCompositorBridge(
74 CSSToLayoutDeviceScale aScale, const CompositorOptions& aOptions,
75 bool aUseExternalSurfaceSize, const gfx::IntSize& aSurfaceSize) {
76 MOZ_ASSERT(XRE_IsParentProcess());
77 MOZ_ASSERT(NS_IsMainThread());
78
79 // When we are in a combined UI / GPU process, InProcessCompositorSession
80 // requires both the parent and child PCompositorBridge actors for its own
81 // construction, which is done on the main thread. Normally
82 // CompositorBridgeParent is created on the compositor thread via the IPDL
83 // plumbing (CompositorManagerParent::AllocPCompositorBridgeParent). Thus to
84 // actually get a reference to the parent, we would need to block on the
85 // compositor thread until it handles our constructor message. Because only
86 // one one IPDL constructor is permitted per parent and child protocol, we
87 // cannot make the normal case async and this case sync. Instead what we do
88 // is leave the constructor async (a boon to the content process setup) and
89 // create the parent ahead of time. It will pull the preinitialized parent
90 // from the queue when it receives the message and give that to IPDL.
91
92 // Note that the static mutex not only is used to protect sInstance, but also
93 // mPendingCompositorBridges.
94 StaticMutexAutoLock lock(sMutex);
95 if (NS_WARN_IF(!sInstance)) {
96 return nullptr;
97 }
98
99 TimeDuration vsyncRate = gfxPlatform::GetPlatform()
100 ->GetHardwareVsync()
101 ->GetGlobalDisplay()
102 .GetVsyncRate();
103
104 RefPtr<CompositorBridgeParent> bridge =
105 new CompositorBridgeParent(sInstance, aScale, vsyncRate, aOptions,
106 aUseExternalSurfaceSize, aSurfaceSize);
107
108 sInstance->mPendingCompositorBridges.AppendElement(bridge);
109 return bridge.forget();
110 }
111
CompositorManagerParent()112 CompositorManagerParent::CompositorManagerParent()
113 : mCompositorThreadHolder(CompositorThreadHolder::GetSingleton()) {}
114
~CompositorManagerParent()115 CompositorManagerParent::~CompositorManagerParent() {}
116
Bind(Endpoint<PCompositorManagerParent> && aEndpoint)117 void CompositorManagerParent::Bind(
118 Endpoint<PCompositorManagerParent>&& aEndpoint) {
119 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
120 if (NS_WARN_IF(!aEndpoint.Bind(this))) {
121 return;
122 }
123
124 BindComplete();
125 }
126
BindComplete()127 void CompositorManagerParent::BindComplete() {
128 // Add the IPDL reference to ourself, so we can't get freed until IPDL is
129 // done with us.
130 AddRef();
131
132 StaticMutexAutoLock lock(sMutex);
133 if (OtherPid() == base::GetCurrentProcId()) {
134 sInstance = this;
135 }
136
137 #ifdef COMPOSITOR_MANAGER_PARENT_EXPLICIT_SHUTDOWN
138 if (!sActiveActors) {
139 sActiveActors = new nsTArray<CompositorManagerParent*>();
140 }
141 sActiveActors->AppendElement(this);
142 #endif
143 }
144
ActorDestroy(ActorDestroyReason aReason)145 void CompositorManagerParent::ActorDestroy(ActorDestroyReason aReason) {
146 SharedSurfacesParent::DestroyProcess(OtherPid());
147
148 StaticMutexAutoLock lock(sMutex);
149 if (sInstance == this) {
150 sInstance = nullptr;
151 }
152 }
153
DeallocPCompositorManagerParent()154 void CompositorManagerParent::DeallocPCompositorManagerParent() {
155 MessageLoop::current()->PostTask(
156 NewRunnableMethod("layers::CompositorManagerParent::DeferredDestroy",
157 this, &CompositorManagerParent::DeferredDestroy));
158
159 #ifdef COMPOSITOR_MANAGER_PARENT_EXPLICIT_SHUTDOWN
160 StaticMutexAutoLock lock(sMutex);
161 if (sActiveActors) {
162 sActiveActors->RemoveElement(this);
163 }
164 #endif
165 Release();
166 }
167
DeferredDestroy()168 void CompositorManagerParent::DeferredDestroy() {
169 mCompositorThreadHolder = nullptr;
170 }
171
172 #ifdef COMPOSITOR_MANAGER_PARENT_EXPLICIT_SHUTDOWN
ShutdownInternal()173 /* static */ void CompositorManagerParent::ShutdownInternal() {
174 nsAutoPtr<nsTArray<CompositorManagerParent*>> actors;
175
176 // We move here because we may attempt to acquire the same lock during the
177 // destroy to remove the reference in sActiveActors.
178 {
179 StaticMutexAutoLock lock(sMutex);
180 actors = sActiveActors.forget();
181 }
182
183 if (actors) {
184 for (auto& actor : *actors) {
185 actor->Close();
186 }
187 }
188 }
189 #endif // COMPOSITOR_MANAGER_PARENT_EXPLICIT_SHUTDOWN
190
Shutdown()191 /* static */ void CompositorManagerParent::Shutdown() {
192 MOZ_ASSERT(NS_IsMainThread());
193
194 #ifdef COMPOSITOR_MANAGER_PARENT_EXPLICIT_SHUTDOWN
195 CompositorThreadHolder::Loop()->PostTask(NS_NewRunnableFunction(
196 "layers::CompositorManagerParent::Shutdown",
197 []() -> void { CompositorManagerParent::ShutdownInternal(); }));
198 #endif
199 }
200
AllocPCompositorBridgeParent(const CompositorBridgeOptions & aOpt)201 PCompositorBridgeParent* CompositorManagerParent::AllocPCompositorBridgeParent(
202 const CompositorBridgeOptions& aOpt) {
203 switch (aOpt.type()) {
204 case CompositorBridgeOptions::TContentCompositorOptions: {
205 CrossProcessCompositorBridgeParent* bridge =
206 new CrossProcessCompositorBridgeParent(this);
207 bridge->AddRef();
208 return bridge;
209 }
210 case CompositorBridgeOptions::TWidgetCompositorOptions: {
211 // Only the UI process is allowed to create widget compositors in the
212 // compositor process.
213 gfx::GPUParent* gpu = gfx::GPUParent::GetSingleton();
214 if (NS_WARN_IF(!gpu || OtherPid() != gpu->OtherPid())) {
215 MOZ_ASSERT_UNREACHABLE("Child cannot create widget compositor!");
216 break;
217 }
218
219 const WidgetCompositorOptions& opt = aOpt.get_WidgetCompositorOptions();
220 CompositorBridgeParent* bridge = new CompositorBridgeParent(
221 this, opt.scale(), opt.vsyncRate(), opt.options(),
222 opt.useExternalSurfaceSize(), opt.surfaceSize());
223 bridge->AddRef();
224 return bridge;
225 }
226 case CompositorBridgeOptions::TSameProcessWidgetCompositorOptions: {
227 // If the GPU and UI process are combined, we actually already created the
228 // CompositorBridgeParent, so we need to reuse that to inject it into the
229 // IPDL framework.
230 if (NS_WARN_IF(OtherPid() != base::GetCurrentProcId())) {
231 MOZ_ASSERT_UNREACHABLE("Child cannot create same process compositor!");
232 break;
233 }
234
235 // Note that the static mutex not only is used to protect sInstance, but
236 // also mPendingCompositorBridges.
237 StaticMutexAutoLock lock(sMutex);
238 MOZ_ASSERT(!mPendingCompositorBridges.IsEmpty());
239
240 CompositorBridgeParent* bridge = mPendingCompositorBridges[0];
241 bridge->AddRef();
242 mPendingCompositorBridges.RemoveElementAt(0);
243 return bridge;
244 }
245 default:
246 break;
247 }
248
249 return nullptr;
250 }
251
DeallocPCompositorBridgeParent(PCompositorBridgeParent * aActor)252 bool CompositorManagerParent::DeallocPCompositorBridgeParent(
253 PCompositorBridgeParent* aActor) {
254 static_cast<CompositorBridgeParentBase*>(aActor)->Release();
255 return true;
256 }
257
RecvAddSharedSurface(const wr::ExternalImageId & aId,const SurfaceDescriptorShared & aDesc)258 mozilla::ipc::IPCResult CompositorManagerParent::RecvAddSharedSurface(
259 const wr::ExternalImageId& aId, const SurfaceDescriptorShared& aDesc) {
260 SharedSurfacesParent::Add(aId, aDesc, OtherPid());
261 return IPC_OK();
262 }
263
RecvRemoveSharedSurface(const wr::ExternalImageId & aId)264 mozilla::ipc::IPCResult CompositorManagerParent::RecvRemoveSharedSurface(
265 const wr::ExternalImageId& aId) {
266 SharedSurfacesParent::Remove(aId);
267 return IPC_OK();
268 }
269
270 } // namespace layers
271 } // namespace mozilla
272