Line data Source code
1 : /* vim: set ts=2 sw=2 et tw=80: */
2 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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 "VsyncSource.h"
13 :
14 : namespace mozilla {
15 : namespace layers {
16 :
17 3 : StaticRefPtr<CompositorManagerParent> CompositorManagerParent::sInstance;
18 3 : StaticMutex CompositorManagerParent::sMutex;
19 :
20 : /* static */ already_AddRefed<CompositorManagerParent>
21 1 : CompositorManagerParent::CreateSameProcess()
22 : {
23 1 : MOZ_ASSERT(XRE_IsParentProcess());
24 1 : MOZ_ASSERT(NS_IsMainThread());
25 2 : StaticMutexAutoLock lock(sMutex);
26 :
27 : // We are creating a manager for the UI process, inside the combined GPU/UI
28 : // process. It is created more-or-less the same but we retain a reference to
29 : // the parent to access state.
30 1 : if (NS_WARN_IF(sInstance)) {
31 0 : MOZ_ASSERT_UNREACHABLE("Already initialized");
32 : return nullptr;
33 : }
34 :
35 : // The child is responsible for setting up the IPC channel in the same
36 : // process case because if we open from the child perspective, we can do it
37 : // on the main thread and complete before we return the manager handles.
38 2 : RefPtr<CompositorManagerParent> parent = new CompositorManagerParent();
39 1 : parent->SetOtherProcessId(base::GetCurrentProcId());
40 :
41 : // CompositorManagerParent::Bind would normally add a reference for IPDL but
42 : // we don't use that in the same process case.
43 1 : parent.get()->AddRef();
44 1 : sInstance = parent;
45 1 : return parent.forget();
46 : }
47 :
48 : /* static */ void
49 2 : CompositorManagerParent::Create(Endpoint<PCompositorManagerParent>&& aEndpoint)
50 : {
51 2 : MOZ_ASSERT(NS_IsMainThread());
52 :
53 : // We are creating a manager for the another process, inside the GPU process
54 : // (or UI process if it subsumbed the GPU process).
55 2 : MOZ_ASSERT(aEndpoint.OtherPid() != base::GetCurrentProcId());
56 :
57 4 : RefPtr<CompositorManagerParent> bridge = new CompositorManagerParent();
58 :
59 4 : RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PCompositorManagerParent>&&>(
60 : "CompositorManagerParent::Bind",
61 : bridge,
62 : &CompositorManagerParent::Bind,
63 6 : Move(aEndpoint));
64 2 : CompositorThreadHolder::Loop()->PostTask(runnable.forget());
65 2 : }
66 :
67 : /* static */ already_AddRefed<CompositorBridgeParent>
68 1 : CompositorManagerParent::CreateSameProcessWidgetCompositorBridge(CSSToLayoutDeviceScale aScale,
69 : const CompositorOptions& aOptions,
70 : bool aUseExternalSurfaceSize,
71 : const gfx::IntSize& aSurfaceSize)
72 : {
73 1 : MOZ_ASSERT(XRE_IsParentProcess());
74 1 : MOZ_ASSERT(NS_IsMainThread());
75 :
76 : // When we are in a combined UI / GPU process, InProcessCompositorSession
77 : // requires both the parent and child PCompositorBridge actors for its own
78 : // construction, which is done on the main thread. Normally
79 : // CompositorBridgeParent is created on the compositor thread via the IPDL
80 : // plumbing (CompositorManagerParent::AllocPCompositorBridgeParent). Thus to
81 : // actually get a reference to the parent, we would need to block on the
82 : // compositor thread until it handles our constructor message. Because only
83 : // one one IPDL constructor is permitted per parent and child protocol, we
84 : // cannot make the normal case async and this case sync. Instead what we do
85 : // is leave the constructor async (a boon to the content process setup) and
86 : // create the parent ahead of time. It will pull the preinitialized parent
87 : // from the queue when it receives the message and give that to IPDL.
88 :
89 : // Note that the static mutex not only is used to protect sInstance, but also
90 : // mPendingCompositorBridges.
91 2 : StaticMutexAutoLock lock(sMutex);
92 1 : if (NS_WARN_IF(!sInstance)) {
93 0 : return nullptr;
94 : }
95 :
96 : TimeDuration vsyncRate =
97 1 : gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate();
98 :
99 : RefPtr<CompositorBridgeParent> bridge =
100 : new CompositorBridgeParent(sInstance, aScale, vsyncRate, aOptions,
101 3 : aUseExternalSurfaceSize, aSurfaceSize);
102 :
103 1 : sInstance->mPendingCompositorBridges.AppendElement(bridge);
104 1 : return bridge.forget();
105 : }
106 :
107 3 : CompositorManagerParent::CompositorManagerParent()
108 3 : : mCompositorThreadHolder(CompositorThreadHolder::GetSingleton())
109 : {
110 3 : }
111 :
112 0 : CompositorManagerParent::~CompositorManagerParent()
113 : {
114 0 : }
115 :
116 : void
117 2 : CompositorManagerParent::Bind(Endpoint<PCompositorManagerParent>&& aEndpoint)
118 : {
119 2 : MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
120 2 : if (NS_WARN_IF(!aEndpoint.Bind(this))) {
121 0 : return;
122 : }
123 :
124 : // Add the IPDL reference to ourself, so we can't get freed until IPDL is
125 : // done with us.
126 2 : AddRef();
127 : }
128 :
129 : void
130 0 : CompositorManagerParent::ActorDestroy(ActorDestroyReason aReason)
131 : {
132 0 : StaticMutexAutoLock lock(sMutex);
133 0 : if (sInstance == this) {
134 0 : sInstance = nullptr;
135 : }
136 0 : }
137 :
138 : void
139 0 : CompositorManagerParent::DeallocPCompositorManagerParent()
140 : {
141 0 : Release();
142 0 : }
143 :
144 : PCompositorBridgeParent*
145 2 : CompositorManagerParent::AllocPCompositorBridgeParent(const CompositorBridgeOptions& aOpt)
146 : {
147 2 : switch (aOpt.type()) {
148 : case CompositorBridgeOptions::TContentCompositorOptions: {
149 : CrossProcessCompositorBridgeParent* bridge =
150 1 : new CrossProcessCompositorBridgeParent(this);
151 1 : bridge->AddRef();
152 1 : return bridge;
153 : }
154 : case CompositorBridgeOptions::TWidgetCompositorOptions: {
155 : // Only the UI process is allowed to create widget compositors in the
156 : // compositor process.
157 0 : gfx::GPUParent* gpu = gfx::GPUParent::GetSingleton();
158 0 : if (NS_WARN_IF(!gpu || OtherPid() != gpu->OtherPid())) {
159 0 : MOZ_ASSERT_UNREACHABLE("Child cannot create widget compositor!");
160 : break;
161 : }
162 :
163 0 : const WidgetCompositorOptions& opt = aOpt.get_WidgetCompositorOptions();
164 : CompositorBridgeParent* bridge =
165 0 : new CompositorBridgeParent(this, opt.scale(), opt.vsyncRate(),
166 0 : opt.options(), opt.useExternalSurfaceSize(),
167 0 : opt.surfaceSize());
168 0 : bridge->AddRef();
169 0 : return bridge;
170 : }
171 : case CompositorBridgeOptions::TSameProcessWidgetCompositorOptions: {
172 : // If the GPU and UI process are combined, we actually already created the
173 : // CompositorBridgeParent, so we need to reuse that to inject it into the
174 : // IPDL framework.
175 1 : if (NS_WARN_IF(OtherPid() != base::GetCurrentProcId())) {
176 0 : MOZ_ASSERT_UNREACHABLE("Child cannot create same process compositor!");
177 : break;
178 : }
179 :
180 : // Note that the static mutex not only is used to protect sInstance, but
181 : // also mPendingCompositorBridges.
182 2 : StaticMutexAutoLock lock(sMutex);
183 1 : MOZ_ASSERT(!mPendingCompositorBridges.IsEmpty());
184 :
185 1 : CompositorBridgeParent* bridge = mPendingCompositorBridges[0];
186 1 : bridge->AddRef();
187 1 : mPendingCompositorBridges.RemoveElementAt(0);
188 1 : return bridge;
189 : }
190 : default:
191 0 : break;
192 : }
193 :
194 0 : return nullptr;
195 : }
196 :
197 : bool
198 0 : CompositorManagerParent::DeallocPCompositorBridgeParent(PCompositorBridgeParent* aActor)
199 : {
200 0 : static_cast<CompositorBridgeParentBase*>(aActor)->Release();
201 0 : return true;
202 : }
203 :
204 : } // namespace layers
205 : } // namespace mozilla
|