Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "mozilla/layers/CompositorManagerChild.h"
7 : #include "mozilla/layers/CompositorBridgeChild.h"
8 : #include "mozilla/layers/CompositorManagerParent.h"
9 : #include "mozilla/layers/CompositorThread.h"
10 : #include "mozilla/gfx/GPUProcessManager.h"
11 : #include "mozilla/dom/ContentChild.h" // for ContentChild
12 : #include "mozilla/dom/TabChild.h" // for TabChild
13 : #include "mozilla/dom/TabGroup.h" // for TabGroup
14 : #include "VsyncSource.h"
15 :
16 : namespace mozilla {
17 : namespace layers {
18 :
19 3 : StaticRefPtr<CompositorManagerChild> CompositorManagerChild::sInstance;
20 :
21 : /* static */ bool
22 2 : CompositorManagerChild::IsInitialized(base::ProcessId aGPUPid)
23 : {
24 2 : MOZ_ASSERT(NS_IsMainThread());
25 : // Since GPUChild and CompositorManagerChild will race on ActorDestroy, we
26 : // cannot know if the CompositorManagerChild is about to be released but has
27 : // yet to be. As such, we need to verify the GPU PID matches as well.
28 2 : return sInstance && sInstance->CanSend() && sInstance->OtherPid() == aGPUPid;
29 : }
30 :
31 : /* static */ bool
32 1 : CompositorManagerChild::InitSameProcess(uint32_t aNamespace)
33 : {
34 1 : MOZ_ASSERT(NS_IsMainThread());
35 1 : if (NS_WARN_IF(IsInitialized(base::GetCurrentProcId()))) {
36 0 : MOZ_ASSERT_UNREACHABLE("Already initialized same process");
37 : return false;
38 : }
39 :
40 : RefPtr<CompositorManagerParent> parent =
41 2 : CompositorManagerParent::CreateSameProcess();
42 2 : sInstance = new CompositorManagerChild(parent, aNamespace);
43 1 : return true;
44 : }
45 :
46 : /* static */ bool
47 2 : CompositorManagerChild::Init(Endpoint<PCompositorManagerChild>&& aEndpoint,
48 : uint32_t aNamespace)
49 : {
50 2 : MOZ_ASSERT(NS_IsMainThread());
51 2 : if (sInstance) {
52 : // Since GPUChild and CompositorManagerChild will race on ActorDestroy, we
53 : // cannot know if the CompositorManagerChild has yet to be released or not.
54 : // To avoid an unnecessary reinitialization, we verify the GPU PID actually
55 : // changed.
56 0 : MOZ_ASSERT(sInstance->mNamespace != aNamespace);
57 0 : MOZ_RELEASE_ASSERT(sInstance->OtherPid() != aEndpoint.OtherPid());
58 : }
59 :
60 4 : sInstance = new CompositorManagerChild(Move(aEndpoint), aNamespace);
61 2 : return sInstance->CanSend();
62 : }
63 :
64 : /* static */ void
65 0 : CompositorManagerChild::Shutdown()
66 : {
67 0 : MOZ_ASSERT(NS_IsMainThread());
68 0 : CompositorBridgeChild::ShutDown();
69 :
70 0 : if (!sInstance) {
71 0 : return;
72 : }
73 :
74 0 : sInstance->Close();
75 0 : sInstance = nullptr;
76 : }
77 :
78 : /* static */ bool
79 2 : CompositorManagerChild::CreateContentCompositorBridge(uint32_t aNamespace)
80 : {
81 2 : MOZ_ASSERT(NS_IsMainThread());
82 2 : if (NS_WARN_IF(!sInstance)) {
83 0 : return false;
84 : }
85 :
86 4 : CompositorBridgeOptions options = ContentCompositorOptions();
87 : PCompositorBridgeChild* pbridge =
88 2 : sInstance->SendPCompositorBridgeConstructor(options);
89 2 : if (NS_WARN_IF(!pbridge)) {
90 0 : return true;
91 : }
92 :
93 2 : auto bridge = static_cast<CompositorBridgeChild*>(pbridge);
94 2 : bridge->InitForContent(aNamespace);
95 2 : return true;
96 : }
97 :
98 : /* static */ already_AddRefed<CompositorBridgeChild>
99 0 : CompositorManagerChild::CreateWidgetCompositorBridge(uint64_t aProcessToken,
100 : LayerManager* aLayerManager,
101 : uint32_t aNamespace,
102 : CSSToLayoutDeviceScale aScale,
103 : const CompositorOptions& aOptions,
104 : bool aUseExternalSurfaceSize,
105 : const gfx::IntSize& aSurfaceSize)
106 : {
107 0 : MOZ_ASSERT(XRE_IsParentProcess());
108 0 : MOZ_ASSERT(NS_IsMainThread());
109 0 : if (NS_WARN_IF(!sInstance)) {
110 0 : return nullptr;
111 : }
112 :
113 : TimeDuration vsyncRate =
114 0 : gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().GetVsyncRate();
115 :
116 : CompositorBridgeOptions options =
117 0 : WidgetCompositorOptions(aScale, vsyncRate, aOptions,
118 0 : aUseExternalSurfaceSize, aSurfaceSize);
119 : PCompositorBridgeChild* pbridge =
120 0 : sInstance->SendPCompositorBridgeConstructor(options);
121 0 : if (NS_WARN_IF(!pbridge)) {
122 0 : return nullptr;
123 : }
124 :
125 : RefPtr<CompositorBridgeChild> bridge =
126 0 : static_cast<CompositorBridgeChild*>(pbridge);
127 0 : bridge->InitForWidget(aProcessToken, aLayerManager, aNamespace);
128 0 : return bridge.forget();
129 : }
130 :
131 : /* static */ already_AddRefed<CompositorBridgeChild>
132 1 : CompositorManagerChild::CreateSameProcessWidgetCompositorBridge(LayerManager* aLayerManager,
133 : uint32_t aNamespace)
134 : {
135 1 : MOZ_ASSERT(XRE_IsParentProcess());
136 1 : MOZ_ASSERT(NS_IsMainThread());
137 1 : if (NS_WARN_IF(!sInstance)) {
138 0 : return nullptr;
139 : }
140 :
141 2 : CompositorBridgeOptions options = SameProcessWidgetCompositorOptions();
142 : PCompositorBridgeChild* pbridge =
143 1 : sInstance->SendPCompositorBridgeConstructor(options);
144 1 : if (NS_WARN_IF(!pbridge)) {
145 0 : return nullptr;
146 : }
147 :
148 : RefPtr<CompositorBridgeChild> bridge =
149 2 : static_cast<CompositorBridgeChild*>(pbridge);
150 1 : bridge->InitForWidget(1, aLayerManager, aNamespace);
151 1 : return bridge.forget();
152 : }
153 :
154 1 : CompositorManagerChild::CompositorManagerChild(CompositorManagerParent* aParent,
155 1 : uint32_t aNamespace)
156 : : mCanSend(false)
157 : , mNamespace(aNamespace)
158 1 : , mResourceId(0)
159 : {
160 1 : MOZ_ASSERT(aParent);
161 :
162 1 : SetOtherProcessId(base::GetCurrentProcId());
163 1 : MessageLoop* loop = CompositorThreadHolder::Loop();
164 1 : ipc::MessageChannel* channel = aParent->GetIPCChannel();
165 1 : if (NS_WARN_IF(!Open(channel, loop, ipc::ChildSide))) {
166 0 : return;
167 : }
168 :
169 1 : mCanSend = true;
170 1 : AddRef();
171 1 : SetReplyTimeout();
172 : }
173 :
174 2 : CompositorManagerChild::CompositorManagerChild(Endpoint<PCompositorManagerChild>&& aEndpoint,
175 2 : uint32_t aNamespace)
176 : : mCanSend(false)
177 : , mNamespace(aNamespace)
178 2 : , mResourceId(0)
179 : {
180 2 : if (NS_WARN_IF(!aEndpoint.Bind(this))) {
181 0 : return;
182 : }
183 :
184 2 : mCanSend = true;
185 2 : AddRef();
186 2 : SetReplyTimeout();
187 : }
188 :
189 : void
190 0 : CompositorManagerChild::DeallocPCompositorManagerChild()
191 : {
192 0 : MOZ_ASSERT(!mCanSend);
193 0 : Release();
194 0 : }
195 :
196 : void
197 0 : CompositorManagerChild::ActorDestroy(ActorDestroyReason aReason)
198 : {
199 0 : mCanSend = false;
200 0 : if (sInstance == this) {
201 0 : sInstance = nullptr;
202 : }
203 0 : }
204 :
205 : PCompositorBridgeChild*
206 3 : CompositorManagerChild::AllocPCompositorBridgeChild(const CompositorBridgeOptions& aOptions)
207 : {
208 3 : CompositorBridgeChild* child = new CompositorBridgeChild(this);
209 3 : child->AddRef();
210 3 : return child;
211 : }
212 :
213 : bool
214 0 : CompositorManagerChild::DeallocPCompositorBridgeChild(PCompositorBridgeChild* aActor)
215 : {
216 0 : static_cast<CompositorBridgeChild*>(aActor)->Release();
217 0 : return true;
218 : }
219 :
220 : void
221 0 : CompositorManagerChild::HandleFatalError(const char* aName, const char* aMsg) const
222 : {
223 0 : dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
224 0 : }
225 :
226 : void
227 0 : CompositorManagerChild::ProcessingError(Result aCode, const char* aReason)
228 : {
229 0 : if (aCode != MsgDropped) {
230 0 : gfxDevCrash(gfx::LogReason::ProcessingError) << "Processing error in CompositorBridgeChild: " << int(aCode);
231 : }
232 0 : }
233 :
234 : already_AddRefed<nsIEventTarget>
235 64 : CompositorManagerChild::GetSpecificMessageEventTarget(const Message& aMsg)
236 : {
237 64 : if (aMsg.type() != PCompositorBridge::Msg_DidComposite__ID) {
238 7 : return nullptr;
239 : }
240 :
241 : uint64_t layersId;
242 57 : PickleIterator iter(aMsg);
243 57 : if (!IPC::ReadParam(&aMsg, &iter, &layersId)) {
244 0 : return nullptr;
245 : }
246 :
247 57 : TabChild* tabChild = TabChild::GetFrom(layersId);
248 57 : if (!tabChild) {
249 29 : return nullptr;
250 : }
251 :
252 28 : return do_AddRef(tabChild->TabGroup()->EventTargetFor(TaskCategory::Other));
253 : }
254 :
255 : void
256 3 : CompositorManagerChild::SetReplyTimeout()
257 : {
258 : #ifndef DEBUG
259 : // Add a timeout for release builds to kill GPU process when it hangs.
260 : // Don't apply timeout when using web render as it tend to timeout frequently.
261 : if (XRE_IsParentProcess() && !gfxVars::UseWebRender()) {
262 : int32_t timeout = gfxPrefs::GPUProcessIPCReplyTimeoutMs();
263 : SetReplyTimeoutMs(timeout);
264 : }
265 : #endif
266 3 : }
267 :
268 : bool
269 0 : CompositorManagerChild::ShouldContinueFromReplyTimeout()
270 : {
271 0 : if (XRE_IsParentProcess()) {
272 0 : gfxCriticalNote << "Killing GPU process due to IPC reply timeout";
273 0 : GPUProcessManager::Get()->KillProcess();
274 : }
275 0 : return false;
276 : }
277 :
278 : } // namespace layers
279 : } // namespace mozilla
|