/src/mozilla-central/gfx/layers/ipc/CompositorBridgeChild.cpp
Line | Count | Source (jump to first uncovered line) |
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/CompositorBridgeChild.h" |
8 | | #include "mozilla/layers/CompositorBridgeParent.h" |
9 | | #include "mozilla/layers/CompositorThread.h" |
10 | | #include <stddef.h> // for size_t |
11 | | #include "ClientLayerManager.h" // for ClientLayerManager |
12 | | #include "base/message_loop.h" // for MessageLoop |
13 | | #include "base/task.h" // for NewRunnableMethod, etc |
14 | | #include "gfxPrefs.h" |
15 | | #include "mozilla/dom/TabGroup.h" |
16 | | #include "mozilla/layers/CompositorManagerChild.h" |
17 | | #include "mozilla/layers/ImageBridgeChild.h" |
18 | | #include "mozilla/layers/APZChild.h" |
19 | | #include "mozilla/layers/IAPZCTreeManager.h" |
20 | | #include "mozilla/layers/APZCTreeManagerChild.h" |
21 | | #include "mozilla/layers/LayerTransactionChild.h" |
22 | | #include "mozilla/layers/PaintThread.h" |
23 | | #include "mozilla/layers/PLayerTransactionChild.h" |
24 | | #include "mozilla/layers/PTextureChild.h" |
25 | | #include "mozilla/layers/TextureClient.h" // for TextureClient |
26 | | #include "mozilla/layers/TextureClientPool.h" // for TextureClientPool |
27 | | #include "mozilla/layers/WebRenderBridgeChild.h" |
28 | | #include "mozilla/layers/SyncObject.h" // for SyncObjectClient |
29 | | #include "mozilla/gfx/gfxVars.h" |
30 | | #include "mozilla/gfx/GPUProcessManager.h" |
31 | | #include "mozilla/gfx/Logging.h" |
32 | | #include "mozilla/mozalloc.h" // for operator new, etc |
33 | | #include "mozilla/Telemetry.h" |
34 | | #include "nsAutoPtr.h" |
35 | | #include "nsDebug.h" // for NS_WARNING |
36 | | #include "nsIObserver.h" // for nsIObserver |
37 | | #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc |
38 | | #include "nsTArray.h" // for nsTArray, nsTArray_Impl |
39 | | #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop, etc |
40 | | #include "FrameLayerBuilder.h" |
41 | | #include "mozilla/dom/TabChild.h" |
42 | | #include "mozilla/dom/TabParent.h" |
43 | | #include "mozilla/dom/ContentChild.h" |
44 | | #include "mozilla/Unused.h" |
45 | | #include "mozilla/DebugOnly.h" |
46 | | #if defined(XP_WIN) |
47 | | #include "WinUtils.h" |
48 | | #endif |
49 | | #include "mozilla/widget/CompositorWidget.h" |
50 | | #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING |
51 | | # include "mozilla/widget/CompositorWidgetChild.h" |
52 | | #endif |
53 | | #include "VsyncSource.h" |
54 | | |
55 | | using mozilla::layers::LayerTransactionChild; |
56 | | using mozilla::dom::TabChildBase; |
57 | | using mozilla::Unused; |
58 | | using mozilla::gfx::GPUProcessManager; |
59 | | |
60 | | namespace mozilla { |
61 | | namespace layers { |
62 | | |
63 | | static int sShmemCreationCounter = 0; |
64 | | |
65 | | static void ResetShmemCounter() |
66 | 0 | { |
67 | 0 | sShmemCreationCounter = 0; |
68 | 0 | } |
69 | | |
70 | | static void ShmemAllocated(CompositorBridgeChild* aProtocol) |
71 | 0 | { |
72 | 0 | sShmemCreationCounter++; |
73 | 0 | if (sShmemCreationCounter > 256) { |
74 | 0 | aProtocol->SendSyncWithCompositor(); |
75 | 0 | ResetShmemCounter(); |
76 | 0 | MOZ_PERFORMANCE_WARNING("gfx", "The number of shmem allocations is too damn high!"); |
77 | 0 | } |
78 | 0 | } |
79 | | |
80 | | static StaticRefPtr<CompositorBridgeChild> sCompositorBridge; |
81 | | |
82 | | Atomic<int32_t> KnowsCompositor::sSerialCounter(0); |
83 | | |
84 | | CompositorBridgeChild::CompositorBridgeChild(CompositorManagerChild *aManager) |
85 | | : mCompositorManager(aManager) |
86 | | , mIdNamespace(0) |
87 | | , mResourceId(0) |
88 | | , mCanSend(false) |
89 | | , mActorDestroyed(false) |
90 | | , mFwdTransactionId(0) |
91 | | , mMessageLoop(MessageLoop::current()) |
92 | | , mProcessToken(0) |
93 | | , mSectionAllocator(nullptr) |
94 | | , mPaintLock("CompositorBridgeChild.mPaintLock") |
95 | | , mTotalAsyncPaints(0) |
96 | | , mOutstandingAsyncPaints(0) |
97 | | , mOutstandingAsyncEndTransaction(false) |
98 | | , mIsDelayingForAsyncPaints(false) |
99 | | , mSlowFlushCount(0) |
100 | | , mTotalFlushCount(0) |
101 | 0 | { |
102 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
103 | 0 | } |
104 | | |
105 | | CompositorBridgeChild::~CompositorBridgeChild() |
106 | 0 | { |
107 | 0 | if (mCanSend) { |
108 | 0 | gfxCriticalError() << "CompositorBridgeChild was not deinitialized"; |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | | bool |
113 | | CompositorBridgeChild::IsSameProcess() const |
114 | 0 | { |
115 | 0 | return OtherPid() == base::GetCurrentProcId(); |
116 | 0 | } |
117 | | |
118 | | void |
119 | | CompositorBridgeChild::AfterDestroy() |
120 | 0 | { |
121 | 0 | // Note that we cannot rely upon mCanSend here because we already set that to |
122 | 0 | // false to prevent normal IPDL calls from being made after SendWillClose. |
123 | 0 | // The only time we should not issue Send__delete__ is if the actor is already |
124 | 0 | // destroyed, e.g. the compositor process crashed. |
125 | 0 | if (!mActorDestroyed) { |
126 | 0 | Send__delete__(this); |
127 | 0 | mActorDestroyed = true; |
128 | 0 | } |
129 | 0 |
|
130 | 0 | if (sCompositorBridge == this) { |
131 | 0 | sCompositorBridge = nullptr; |
132 | 0 | } |
133 | 0 | } |
134 | | |
135 | | void |
136 | | CompositorBridgeChild::Destroy() |
137 | 0 | { |
138 | 0 | // This must not be called from the destructor! |
139 | 0 | mTexturesWaitingRecycled.clear(); |
140 | 0 |
|
141 | 0 | // Destroying the layer manager may cause all sorts of things to happen, so |
142 | 0 | // let's make sure there is still a reference to keep this alive whatever |
143 | 0 | // happens. |
144 | 0 | RefPtr<CompositorBridgeChild> selfRef = this; |
145 | 0 |
|
146 | 0 | for (size_t i = 0; i < mTexturePools.Length(); i++) { |
147 | 0 | mTexturePools[i]->Destroy(); |
148 | 0 | } |
149 | 0 |
|
150 | 0 | if (mSectionAllocator) { |
151 | 0 | delete mSectionAllocator; |
152 | 0 | mSectionAllocator = nullptr; |
153 | 0 | } |
154 | 0 |
|
155 | 0 | if (mLayerManager) { |
156 | 0 | mLayerManager->Destroy(); |
157 | 0 | mLayerManager = nullptr; |
158 | 0 | } |
159 | 0 |
|
160 | 0 | // Flush async paints before we destroy texture data. |
161 | 0 | FlushAsyncPaints(); |
162 | 0 |
|
163 | 0 | if (!mCanSend) { |
164 | 0 | // We may have already called destroy but still have lingering references |
165 | 0 | // or CompositorBridgeChild::ActorDestroy was called. Ensure that we do our |
166 | 0 | // post destroy clean up no matter what. It is safe to call multiple times. |
167 | 0 | MessageLoop::current()->PostTask(NewRunnableMethod( |
168 | 0 | "CompositorBridgeChild::AfterDestroy", |
169 | 0 | selfRef, &CompositorBridgeChild::AfterDestroy)); |
170 | 0 | return; |
171 | 0 | } |
172 | 0 | |
173 | 0 | AutoTArray<PLayerTransactionChild*, 16> transactions; |
174 | 0 | ManagedPLayerTransactionChild(transactions); |
175 | 0 | for (int i = transactions.Length() - 1; i >= 0; --i) { |
176 | 0 | RefPtr<LayerTransactionChild> layers = |
177 | 0 | static_cast<LayerTransactionChild*>(transactions[i]); |
178 | 0 | layers->Destroy(); |
179 | 0 | } |
180 | 0 |
|
181 | 0 | AutoTArray<PWebRenderBridgeChild*, 16> wrBridges; |
182 | 0 | ManagedPWebRenderBridgeChild(wrBridges); |
183 | 0 | for (int i = wrBridges.Length() - 1; i >= 0; --i) { |
184 | 0 | RefPtr<WebRenderBridgeChild> wrBridge = |
185 | 0 | static_cast<WebRenderBridgeChild*>(wrBridges[i]); |
186 | 0 | wrBridge->Destroy(/* aIsSync */ false); |
187 | 0 | } |
188 | 0 |
|
189 | 0 | const ManagedContainer<PTextureChild>& textures = ManagedPTextureChild(); |
190 | 0 | for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) { |
191 | 0 | RefPtr<TextureClient> texture = TextureClient::AsTextureClient(iter.Get()->GetKey()); |
192 | 0 |
|
193 | 0 | if (texture) { |
194 | 0 | texture->Destroy(); |
195 | 0 | } |
196 | 0 | } |
197 | 0 |
|
198 | 0 | SendWillClose(); |
199 | 0 | mCanSend = false; |
200 | 0 |
|
201 | 0 | // We no longer care about unexpected shutdowns, in the remote process case. |
202 | 0 | mProcessToken = 0; |
203 | 0 |
|
204 | 0 | // The call just made to SendWillClose can result in IPC from the |
205 | 0 | // CompositorBridgeParent to the CompositorBridgeChild (e.g. caused by the destruction |
206 | 0 | // of shared memory). We need to ensure this gets processed by the |
207 | 0 | // CompositorBridgeChild before it gets destroyed. It suffices to ensure that |
208 | 0 | // events already in the MessageLoop get processed before the |
209 | 0 | // CompositorBridgeChild is destroyed, so we add a task to the MessageLoop to |
210 | 0 | // handle compositor destruction. |
211 | 0 |
|
212 | 0 | // From now on we can't send any message message. |
213 | 0 | MessageLoop::current()->PostTask(NewRunnableMethod( |
214 | 0 | "CompositorBridgeChild::AfterDestroy", |
215 | 0 | selfRef, &CompositorBridgeChild::AfterDestroy)); |
216 | 0 | } |
217 | | |
218 | | // static |
219 | | void |
220 | | CompositorBridgeChild::ShutDown() |
221 | 0 | { |
222 | 0 | if (sCompositorBridge) { |
223 | 0 | sCompositorBridge->Destroy(); |
224 | 0 | SpinEventLoopUntil([&]() { return !sCompositorBridge; }); |
225 | 0 | } |
226 | 0 | } |
227 | | |
228 | | bool |
229 | | CompositorBridgeChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID aId, |
230 | | FrameMetrics& aFrame) |
231 | 0 | { |
232 | 0 | SharedFrameMetricsData* data = mFrameMetricsTable.Get(aId); |
233 | 0 | if (data) { |
234 | 0 | data->CopyFrameMetrics(&aFrame); |
235 | 0 | return true; |
236 | 0 | } |
237 | 0 | return false; |
238 | 0 | } |
239 | | |
240 | | void |
241 | | CompositorBridgeChild::InitForContent(uint32_t aNamespace) |
242 | 0 | { |
243 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
244 | 0 | MOZ_ASSERT(aNamespace); |
245 | 0 |
|
246 | 0 | if (RefPtr<CompositorBridgeChild> old = sCompositorBridge.forget()) { |
247 | 0 | // Note that at this point, ActorDestroy may not have been called yet, |
248 | 0 | // meaning mCanSend is still true. In this case we will try to send a |
249 | 0 | // synchronous WillClose message to the parent, and will certainly get |
250 | 0 | // a false result and a MsgDropped processing error. This is okay. |
251 | 0 | old->Destroy(); |
252 | 0 | } |
253 | 0 |
|
254 | 0 | mCanSend = true; |
255 | 0 | mIdNamespace = aNamespace; |
256 | 0 | sCompositorBridge = this; |
257 | 0 | } |
258 | | |
259 | | void |
260 | | CompositorBridgeChild::InitForWidget(uint64_t aProcessToken, |
261 | | LayerManager* aLayerManager, |
262 | | uint32_t aNamespace) |
263 | 0 | { |
264 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
265 | 0 | MOZ_ASSERT(aProcessToken); |
266 | 0 | MOZ_ASSERT(aLayerManager); |
267 | 0 | MOZ_ASSERT(aNamespace); |
268 | 0 |
|
269 | 0 | mCanSend = true; |
270 | 0 | mProcessToken = aProcessToken; |
271 | 0 | mLayerManager = aLayerManager; |
272 | 0 | mIdNamespace = aNamespace; |
273 | 0 | } |
274 | | |
275 | | /*static*/ CompositorBridgeChild* |
276 | | CompositorBridgeChild::Get() |
277 | 0 | { |
278 | 0 | // This is only expected to be used in child processes. While the parent |
279 | 0 | // process does have CompositorBridgeChild instances, it has _multiple_ (one |
280 | 0 | // per window), and therefore there is no global singleton available. |
281 | 0 | MOZ_ASSERT(!XRE_IsParentProcess()); |
282 | 0 | return sCompositorBridge; |
283 | 0 | } |
284 | | |
285 | | // static |
286 | | bool |
287 | | CompositorBridgeChild::ChildProcessHasCompositorBridge() |
288 | 0 | { |
289 | 0 | return sCompositorBridge != nullptr; |
290 | 0 | } |
291 | | |
292 | | /* static */ bool |
293 | | CompositorBridgeChild::CompositorIsInGPUProcess() |
294 | 0 | { |
295 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
296 | 0 |
|
297 | 0 | if (XRE_IsParentProcess()) { |
298 | 0 | return !!GPUProcessManager::Get()->GetGPUChild(); |
299 | 0 | } |
300 | 0 | |
301 | 0 | MOZ_ASSERT(XRE_IsContentProcess()); |
302 | 0 | CompositorBridgeChild* bridge = CompositorBridgeChild::Get(); |
303 | 0 | if (!bridge) { |
304 | 0 | return false; |
305 | 0 | } |
306 | 0 | |
307 | 0 | return bridge->OtherPid() != dom::ContentChild::GetSingleton()->OtherPid(); |
308 | 0 | } |
309 | | |
310 | | PLayerTransactionChild* |
311 | | CompositorBridgeChild::AllocPLayerTransactionChild(const nsTArray<LayersBackend>& aBackendHints, const LayersId& aId) |
312 | 0 | { |
313 | 0 | LayerTransactionChild* c = new LayerTransactionChild(aId); |
314 | 0 | c->AddIPDLReference(); |
315 | 0 |
|
316 | 0 | TabChild* tabChild = TabChild::GetFrom(c->GetId()); |
317 | 0 |
|
318 | 0 | // Do the DOM Labeling. |
319 | 0 | if (tabChild) { |
320 | 0 | nsCOMPtr<nsIEventTarget> target = |
321 | 0 | tabChild->TabGroup()->EventTargetFor(TaskCategory::Other); |
322 | 0 | SetEventTargetForActor(c, target); |
323 | 0 | MOZ_ASSERT(c->GetActorEventTarget()); |
324 | 0 | } |
325 | 0 |
|
326 | 0 | return c; |
327 | 0 | } |
328 | | |
329 | | bool |
330 | | CompositorBridgeChild::DeallocPLayerTransactionChild(PLayerTransactionChild* actor) |
331 | 0 | { |
332 | 0 | LayersId childId = static_cast<LayerTransactionChild*>(actor)->GetId(); |
333 | 0 | ClearSharedFrameMetricsData(childId); |
334 | 0 | static_cast<LayerTransactionChild*>(actor)->ReleaseIPDLReference(); |
335 | 0 | return true; |
336 | 0 | } |
337 | | |
338 | | mozilla::ipc::IPCResult |
339 | | CompositorBridgeChild::RecvInvalidateLayers(const LayersId& aLayersId) |
340 | 0 | { |
341 | 0 | if (mLayerManager) { |
342 | 0 | MOZ_ASSERT(!aLayersId.IsValid()); |
343 | 0 | FrameLayerBuilder::InvalidateAllLayers(mLayerManager); |
344 | 0 | } else if (aLayersId.IsValid()) { |
345 | 0 | if (dom::TabChild* child = dom::TabChild::GetFrom(aLayersId)) { |
346 | 0 | child->InvalidateLayers(); |
347 | 0 | } |
348 | 0 | } |
349 | 0 | return IPC_OK(); |
350 | 0 | } |
351 | | |
352 | | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
353 | | static void CalculatePluginClip(const LayoutDeviceIntRect& aBounds, |
354 | | const nsTArray<LayoutDeviceIntRect>& aPluginClipRects, |
355 | | const LayoutDeviceIntPoint& aContentOffset, |
356 | | const LayoutDeviceIntRegion& aParentLayerVisibleRegion, |
357 | | nsTArray<LayoutDeviceIntRect>& aResult, |
358 | | LayoutDeviceIntRect& aVisibleBounds, |
359 | | bool& aPluginIsVisible) |
360 | 0 | { |
361 | 0 | aPluginIsVisible = true; |
362 | 0 | LayoutDeviceIntRegion contentVisibleRegion; |
363 | 0 | // aPluginClipRects (plugin widget origin) - contains *visible* rects |
364 | 0 | for (uint32_t idx = 0; idx < aPluginClipRects.Length(); idx++) { |
365 | 0 | LayoutDeviceIntRect rect = aPluginClipRects[idx]; |
366 | 0 | // shift to content origin |
367 | 0 | rect.MoveBy(aBounds.X(), aBounds.Y()); |
368 | 0 | // accumulate visible rects |
369 | 0 | contentVisibleRegion.OrWith(rect); |
370 | 0 | } |
371 | 0 | // apply layers clip (window origin) |
372 | 0 | LayoutDeviceIntRegion region = aParentLayerVisibleRegion; |
373 | 0 | region.MoveBy(-aContentOffset.x, -aContentOffset.y); |
374 | 0 | contentVisibleRegion.AndWith(region); |
375 | 0 | if (contentVisibleRegion.IsEmpty()) { |
376 | 0 | aPluginIsVisible = false; |
377 | 0 | return; |
378 | 0 | } |
379 | 0 | // shift to plugin widget origin |
380 | 0 | contentVisibleRegion.MoveBy(-aBounds.X(), -aBounds.Y()); |
381 | 0 | for (auto iter = contentVisibleRegion.RectIter(); !iter.Done(); iter.Next()) { |
382 | 0 | const LayoutDeviceIntRect& rect = iter.Get(); |
383 | 0 | aResult.AppendElement(rect); |
384 | 0 | aVisibleBounds.UnionRect(aVisibleBounds, rect); |
385 | 0 | } |
386 | 0 | } |
387 | | #endif |
388 | | |
389 | | mozilla::ipc::IPCResult |
390 | | CompositorBridgeChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint& aContentOffset, |
391 | | const LayoutDeviceIntRegion& aParentLayerVisibleRegion, |
392 | | nsTArray<PluginWindowData>&& aPlugins) |
393 | 0 | { |
394 | | #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) |
395 | | MOZ_ASSERT_UNREACHABLE("CompositorBridgeChild::RecvUpdatePluginConfigurations" |
396 | | " calls unexpected on this platform."); |
397 | | return IPC_FAIL_NO_REASON(this); |
398 | | #else |
399 | | // Now that we are on the main thread, update plugin widget config. |
400 | 0 | // This should happen a little before we paint to the screen assuming |
401 | 0 | // the main thread is running freely. |
402 | 0 | DebugOnly<nsresult> rv; |
403 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
404 | 0 |
|
405 | 0 | // Tracks visible plugins we update, so we can hide any plugins we don't. |
406 | 0 | nsTArray<uintptr_t> visiblePluginIds; |
407 | 0 | nsIWidget* parent = nullptr; |
408 | 0 | for (uint32_t pluginsIdx = 0; pluginsIdx < aPlugins.Length(); pluginsIdx++) { |
409 | 0 | nsIWidget* widget = |
410 | 0 | nsIWidget::LookupRegisteredPluginWindow(aPlugins[pluginsIdx].windowId()); |
411 | 0 | if (!widget) { |
412 | 0 | NS_WARNING("Unexpected, plugin id not found!"); |
413 | 0 | continue; |
414 | 0 | } |
415 | 0 | if (!parent) { |
416 | 0 | parent = widget->GetParent(); |
417 | 0 | } |
418 | 0 | bool isVisible = aPlugins[pluginsIdx].visible(); |
419 | 0 | if (widget && !widget->Destroyed()) { |
420 | 0 | LayoutDeviceIntRect bounds; |
421 | 0 | LayoutDeviceIntRect visibleBounds; |
422 | 0 | // If the plugin is visible update it's geometry. |
423 | 0 | if (isVisible) { |
424 | 0 | // Set bounds (content origin) |
425 | 0 | bounds = aPlugins[pluginsIdx].bounds(); |
426 | 0 | nsTArray<LayoutDeviceIntRect> rectsOut; |
427 | 0 | // This call may change the value of isVisible |
428 | 0 | CalculatePluginClip(bounds, aPlugins[pluginsIdx].clip(), |
429 | 0 | aContentOffset, |
430 | 0 | aParentLayerVisibleRegion, |
431 | 0 | rectsOut, visibleBounds, isVisible); |
432 | 0 | // content clipping region (widget origin) |
433 | 0 | rv = widget->SetWindowClipRegion(rectsOut, false); |
434 | 0 | NS_ASSERTION(NS_SUCCEEDED(rv), "widget call failure"); |
435 | 0 | // This will trigger a browser window paint event for areas uncovered |
436 | 0 | // by a child window move, and will call invalidate on the plugin |
437 | 0 | // parent window which the browser owns. The latter gets picked up in |
438 | 0 | // our OnPaint handler and forwarded over to the plugin process async. |
439 | 0 | widget->Resize(aContentOffset.x + bounds.X(), |
440 | 0 | aContentOffset.y + bounds.Y(), |
441 | 0 | bounds.Width(), bounds.Height(), true); |
442 | 0 | } |
443 | 0 |
|
444 | 0 | widget->Enable(isVisible); |
445 | 0 |
|
446 | 0 | // visible state - updated after clipping, prior to invalidating |
447 | 0 | widget->Show(isVisible); |
448 | 0 |
|
449 | 0 | // Handle invalidation, this can be costly, avoid if it is not needed. |
450 | 0 | if (isVisible) { |
451 | 0 | // invalidate region (widget origin) |
452 | | #if defined(XP_WIN) |
453 | | // Work around for flash's crummy sandbox. See bug 762948. This call |
454 | | // digs down into the window hirearchy, invalidating regions on |
455 | | // windows owned by other processes. |
456 | | mozilla::widget::WinUtils::InvalidatePluginAsWorkaround( |
457 | | widget, visibleBounds); |
458 | | #else |
459 | | widget->Invalidate(visibleBounds); |
460 | 0 | #endif |
461 | 0 | visiblePluginIds.AppendElement(aPlugins[pluginsIdx].windowId()); |
462 | 0 | } |
463 | 0 | } |
464 | 0 | } |
465 | 0 | // Any plugins we didn't update need to be hidden, as they are |
466 | 0 | // not associated with visible content. |
467 | 0 | nsIWidget::UpdateRegisteredPluginWindowVisibility((uintptr_t)parent, visiblePluginIds); |
468 | 0 | if (!mCanSend) { |
469 | 0 | return IPC_OK(); |
470 | 0 | } |
471 | 0 | SendRemotePluginsReady(); |
472 | 0 | return IPC_OK(); |
473 | 0 | #endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) |
474 | 0 | } |
475 | | |
476 | | #if defined(XP_WIN) |
477 | | static void |
478 | | ScheduleSendAllPluginsCaptured(CompositorBridgeChild* aThis, MessageLoop* aLoop) |
479 | | { |
480 | | aLoop->PostTask(NewNonOwningRunnableMethod( |
481 | | "CompositorBridgeChild::SendAllPluginsCaptured", |
482 | | aThis, &CompositorBridgeChild::SendAllPluginsCaptured)); |
483 | | } |
484 | | #endif |
485 | | |
486 | | mozilla::ipc::IPCResult |
487 | | CompositorBridgeChild::RecvCaptureAllPlugins(const uintptr_t& aParentWidget) |
488 | 0 | { |
489 | | #if defined(XP_WIN) |
490 | | MOZ_ASSERT(NS_IsMainThread()); |
491 | | nsIWidget::CaptureRegisteredPlugins(aParentWidget); |
492 | | |
493 | | // Bounce the call to SendAllPluginsCaptured off the ImageBridgeChild loop, |
494 | | // to make sure that the image updates on that thread have been processed. |
495 | | ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( |
496 | | NewRunnableFunction("ScheduleSendAllPluginsCapturedRunnable", |
497 | | &ScheduleSendAllPluginsCaptured, this, |
498 | | MessageLoop::current())); |
499 | | return IPC_OK(); |
500 | | #else |
501 | 0 | MOZ_ASSERT_UNREACHABLE( |
502 | 0 | "CompositorBridgeChild::RecvCaptureAllPlugins calls unexpected."); |
503 | 0 | return IPC_FAIL_NO_REASON(this); |
504 | 0 | #endif |
505 | 0 | } |
506 | | |
507 | | mozilla::ipc::IPCResult |
508 | | CompositorBridgeChild::RecvHideAllPlugins(const uintptr_t& aParentWidget) |
509 | 0 | { |
510 | | #if !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) |
511 | | MOZ_ASSERT_UNREACHABLE("CompositorBridgeChild::RecvHideAllPlugins calls " |
512 | | "unexpected on this platform."); |
513 | | return IPC_FAIL_NO_REASON(this); |
514 | | #else |
515 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
516 | 0 | nsTArray<uintptr_t> list; |
517 | 0 | nsIWidget::UpdateRegisteredPluginWindowVisibility(aParentWidget, list); |
518 | 0 | if (!mCanSend) { |
519 | 0 | return IPC_OK(); |
520 | 0 | } |
521 | 0 | SendRemotePluginsReady(); |
522 | 0 | return IPC_OK(); |
523 | 0 | #endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) |
524 | 0 | } |
525 | | |
526 | | mozilla::ipc::IPCResult |
527 | | CompositorBridgeChild::RecvDidComposite(const LayersId& aId, |
528 | | const TransactionId& aTransactionId, |
529 | | const TimeStamp& aCompositeStart, |
530 | | const TimeStamp& aCompositeEnd) |
531 | 0 | { |
532 | 0 | // Hold a reference to keep texture pools alive. See bug 1387799 |
533 | 0 | AutoTArray<RefPtr<TextureClientPool>,2> texturePools = mTexturePools; |
534 | 0 |
|
535 | 0 | if (mLayerManager) { |
536 | 0 | MOZ_ASSERT(!aId.IsValid()); |
537 | 0 | MOZ_ASSERT(mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT || |
538 | 0 | mLayerManager->GetBackendType() == LayersBackend::LAYERS_WR); |
539 | 0 | // Hold a reference to keep LayerManager alive. See Bug 1242668. |
540 | 0 | RefPtr<LayerManager> m = mLayerManager; |
541 | 0 | m->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd); |
542 | 0 | } else if (aId.IsValid()) { |
543 | 0 | RefPtr<dom::TabChild> child = dom::TabChild::GetFrom(aId); |
544 | 0 | if (child) { |
545 | 0 | child->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd); |
546 | 0 | } |
547 | 0 | } |
548 | 0 |
|
549 | 0 | for (size_t i = 0; i < texturePools.Length(); i++) { |
550 | 0 | texturePools[i]->ReturnDeferredClients(); |
551 | 0 | } |
552 | 0 |
|
553 | 0 | return IPC_OK(); |
554 | 0 | } |
555 | | |
556 | | |
557 | | void |
558 | | CompositorBridgeChild::ActorDestroy(ActorDestroyReason aWhy) |
559 | 0 | { |
560 | 0 | if (aWhy == AbnormalShutdown) { |
561 | 0 | // If the parent side runs into a problem then the actor will be destroyed. |
562 | 0 | // There is nothing we can do in the child side, here sets mCanSend as false. |
563 | 0 | gfxCriticalNote << "Receive IPC close with reason=AbnormalShutdown"; |
564 | 0 | } |
565 | 0 |
|
566 | 0 | { |
567 | 0 | // We take the lock to update these fields, since they are read from the |
568 | 0 | // paint thread. We don't need the lock to init them, since that happens |
569 | 0 | // on the main thread before the paint thread can ever grab a reference |
570 | 0 | // to the CompositorBridge object. |
571 | 0 | // |
572 | 0 | // Note that it is useful to take this lock for one other reason: It also |
573 | 0 | // tells us whether GetIPCChannel is safe to call. If we access the IPC |
574 | 0 | // channel within this lock, when mCanSend is true, then we know it has not |
575 | 0 | // been zapped by IPDL. |
576 | 0 | MonitorAutoLock lock(mPaintLock); |
577 | 0 | mCanSend = false; |
578 | 0 | mActorDestroyed = true; |
579 | 0 | } |
580 | 0 |
|
581 | 0 | if (mProcessToken && XRE_IsParentProcess()) { |
582 | 0 | GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken); |
583 | 0 | } |
584 | 0 | } |
585 | | |
586 | | mozilla::ipc::IPCResult |
587 | | CompositorBridgeChild::RecvSharedCompositorFrameMetrics( |
588 | | const mozilla::ipc::SharedMemoryBasic::Handle& metrics, |
589 | | const CrossProcessMutexHandle& handle, |
590 | | const LayersId& aLayersId, |
591 | | const uint32_t& aAPZCId) |
592 | 0 | { |
593 | 0 | SharedFrameMetricsData* data = new SharedFrameMetricsData( |
594 | 0 | metrics, handle, aLayersId, aAPZCId); |
595 | 0 | mFrameMetricsTable.Put(data->GetViewID(), data); |
596 | 0 | return IPC_OK(); |
597 | 0 | } |
598 | | |
599 | | mozilla::ipc::IPCResult |
600 | | CompositorBridgeChild::RecvReleaseSharedCompositorFrameMetrics( |
601 | | const ViewID& aId, |
602 | | const uint32_t& aAPZCId) |
603 | 0 | { |
604 | 0 | if (auto entry = mFrameMetricsTable.Lookup(aId)) { |
605 | 0 | // The SharedFrameMetricsData may have been removed previously if |
606 | 0 | // a SharedFrameMetricsData with the same ViewID but later APZCId had |
607 | 0 | // been store and over wrote it. |
608 | 0 | if (entry.Data()->GetAPZCId() == aAPZCId) { |
609 | 0 | entry.Remove(); |
610 | 0 | } |
611 | 0 | } |
612 | 0 | return IPC_OK(); |
613 | 0 | } |
614 | | |
615 | | CompositorBridgeChild::SharedFrameMetricsData::SharedFrameMetricsData( |
616 | | const ipc::SharedMemoryBasic::Handle& metrics, |
617 | | const CrossProcessMutexHandle& handle, |
618 | | const LayersId& aLayersId, |
619 | | const uint32_t& aAPZCId) |
620 | | : mMutex(nullptr) |
621 | | , mLayersId(aLayersId) |
622 | | , mAPZCId(aAPZCId) |
623 | 0 | { |
624 | 0 | mBuffer = new ipc::SharedMemoryBasic; |
625 | 0 | mBuffer->SetHandle(metrics, ipc::SharedMemory::RightsReadOnly); |
626 | 0 | mBuffer->Map(sizeof(FrameMetrics)); |
627 | 0 | mMutex = new CrossProcessMutex(handle); |
628 | 0 | MOZ_COUNT_CTOR(SharedFrameMetricsData); |
629 | 0 | } |
630 | | |
631 | | CompositorBridgeChild::SharedFrameMetricsData::~SharedFrameMetricsData() |
632 | 0 | { |
633 | 0 | // When the hash table deletes the class, delete |
634 | 0 | // the shared memory and mutex. |
635 | 0 | delete mMutex; |
636 | 0 | mBuffer = nullptr; |
637 | 0 | MOZ_COUNT_DTOR(SharedFrameMetricsData); |
638 | 0 | } |
639 | | |
640 | | void |
641 | | CompositorBridgeChild::SharedFrameMetricsData::CopyFrameMetrics(FrameMetrics* aFrame) |
642 | 0 | { |
643 | 0 | const FrameMetrics* frame = |
644 | 0 | static_cast<const FrameMetrics*>(mBuffer->memory()); |
645 | 0 | MOZ_ASSERT(frame); |
646 | 0 | mMutex->Lock(); |
647 | 0 | *aFrame = *frame; |
648 | 0 | mMutex->Unlock(); |
649 | 0 | } |
650 | | |
651 | | FrameMetrics::ViewID |
652 | | CompositorBridgeChild::SharedFrameMetricsData::GetViewID() |
653 | 0 | { |
654 | 0 | const FrameMetrics* frame = |
655 | 0 | static_cast<const FrameMetrics*>(mBuffer->memory()); |
656 | 0 | MOZ_ASSERT(frame); |
657 | 0 | // Not locking to read of mScrollId since it should not change after being |
658 | 0 | // initially set. |
659 | 0 | return frame->GetScrollId(); |
660 | 0 | } |
661 | | |
662 | | LayersId |
663 | | CompositorBridgeChild::SharedFrameMetricsData::GetLayersId() const |
664 | 0 | { |
665 | 0 | return mLayersId; |
666 | 0 | } |
667 | | |
668 | | uint32_t |
669 | | CompositorBridgeChild::SharedFrameMetricsData::GetAPZCId() |
670 | 0 | { |
671 | 0 | return mAPZCId; |
672 | 0 | } |
673 | | |
674 | | |
675 | | mozilla::ipc::IPCResult |
676 | | CompositorBridgeChild::RecvRemotePaintIsReady() |
677 | 0 | { |
678 | 0 | // Used on the content thread, this bounces the message to the |
679 | 0 | // TabParent (via the TabChild) if the notification was previously requested. |
680 | 0 | // XPCOM gives a soup of compiler errors when trying to do_QueryReference |
681 | 0 | // so I'm using static_cast<> |
682 | 0 | MOZ_LAYERS_LOG(("[RemoteGfx] CompositorBridgeChild received RemotePaintIsReady")); |
683 | 0 | RefPtr<nsISupports> iTabChildBase(do_QueryReferent(mWeakTabChild)); |
684 | 0 | if (!iTabChildBase) { |
685 | 0 | MOZ_LAYERS_LOG(("[RemoteGfx] Note: TabChild was released before RemotePaintIsReady. " |
686 | 0 | "MozAfterRemotePaint will not be sent to listener.")); |
687 | 0 | return IPC_OK(); |
688 | 0 | } |
689 | 0 | TabChildBase* tabChildBase = static_cast<TabChildBase*>(iTabChildBase.get()); |
690 | 0 | TabChild* tabChild = static_cast<TabChild*>(tabChildBase); |
691 | 0 | MOZ_ASSERT(tabChild); |
692 | 0 | Unused << tabChild->SendRemotePaintIsReady(); |
693 | 0 | mWeakTabChild = nullptr; |
694 | 0 | return IPC_OK(); |
695 | 0 | } |
696 | | |
697 | | |
698 | | void |
699 | | CompositorBridgeChild::RequestNotifyAfterRemotePaint(TabChild* aTabChild) |
700 | 0 | { |
701 | 0 | MOZ_ASSERT(aTabChild, "NULL TabChild not allowed in CompositorBridgeChild::RequestNotifyAfterRemotePaint"); |
702 | 0 | mWeakTabChild = do_GetWeakReference( static_cast<dom::TabChildBase*>(aTabChild) ); |
703 | 0 | if (!mCanSend) { |
704 | 0 | return; |
705 | 0 | } |
706 | 0 | Unused << SendRequestNotifyAfterRemotePaint(); |
707 | 0 | } |
708 | | |
709 | | void |
710 | | CompositorBridgeChild::CancelNotifyAfterRemotePaint(TabChild* aTabChild) |
711 | 0 | { |
712 | 0 | RefPtr<nsISupports> iTabChildBase(do_QueryReferent(mWeakTabChild)); |
713 | 0 | if (!iTabChildBase) { |
714 | 0 | return; |
715 | 0 | } |
716 | 0 | TabChildBase* tabChildBase = static_cast<TabChildBase*>(iTabChildBase.get()); |
717 | 0 | TabChild* tabChild = static_cast<TabChild*>(tabChildBase); |
718 | 0 | if (tabChild == aTabChild) { |
719 | 0 | mWeakTabChild = nullptr; |
720 | 0 | } |
721 | 0 | } |
722 | | |
723 | | bool |
724 | | CompositorBridgeChild::SendWillClose() |
725 | 0 | { |
726 | 0 | MOZ_RELEASE_ASSERT(mCanSend); |
727 | 0 | return PCompositorBridgeChild::SendWillClose(); |
728 | 0 | } |
729 | | |
730 | | bool |
731 | | CompositorBridgeChild::SendPause() |
732 | 0 | { |
733 | 0 | if (!mCanSend) { |
734 | 0 | return false; |
735 | 0 | } |
736 | 0 | return PCompositorBridgeChild::SendPause(); |
737 | 0 | } |
738 | | |
739 | | bool |
740 | | CompositorBridgeChild::SendResume() |
741 | 0 | { |
742 | 0 | if (!mCanSend) { |
743 | 0 | return false; |
744 | 0 | } |
745 | 0 | return PCompositorBridgeChild::SendResume(); |
746 | 0 | } |
747 | | |
748 | | bool |
749 | | CompositorBridgeChild::SendNotifyChildCreated(const LayersId& id, |
750 | | CompositorOptions* aOptions) |
751 | 0 | { |
752 | 0 | if (!mCanSend) { |
753 | 0 | return false; |
754 | 0 | } |
755 | 0 | return PCompositorBridgeChild::SendNotifyChildCreated(id, aOptions); |
756 | 0 | } |
757 | | |
758 | | bool |
759 | | CompositorBridgeChild::SendAdoptChild(const LayersId& id) |
760 | 0 | { |
761 | 0 | if (!mCanSend) { |
762 | 0 | return false; |
763 | 0 | } |
764 | 0 | return PCompositorBridgeChild::SendAdoptChild(id); |
765 | 0 | } |
766 | | |
767 | | bool |
768 | | CompositorBridgeChild::SendMakeSnapshot(const SurfaceDescriptor& inSnapshot, const gfx::IntRect& dirtyRect) |
769 | 0 | { |
770 | 0 | if (!mCanSend) { |
771 | 0 | return false; |
772 | 0 | } |
773 | 0 | return PCompositorBridgeChild::SendMakeSnapshot(inSnapshot, dirtyRect); |
774 | 0 | } |
775 | | |
776 | | bool |
777 | | CompositorBridgeChild::SendFlushRendering() |
778 | 0 | { |
779 | 0 | if (!mCanSend) { |
780 | 0 | return false; |
781 | 0 | } |
782 | 0 | return PCompositorBridgeChild::SendFlushRendering(); |
783 | 0 | } |
784 | | |
785 | | bool |
786 | | CompositorBridgeChild::SendStartFrameTimeRecording(const int32_t& bufferSize, uint32_t* startIndex) |
787 | 0 | { |
788 | 0 | if (!mCanSend) { |
789 | 0 | return false; |
790 | 0 | } |
791 | 0 | return PCompositorBridgeChild::SendStartFrameTimeRecording(bufferSize, startIndex); |
792 | 0 | } |
793 | | |
794 | | bool |
795 | | CompositorBridgeChild::SendStopFrameTimeRecording(const uint32_t& startIndex, nsTArray<float>* intervals) |
796 | 0 | { |
797 | 0 | if (!mCanSend) { |
798 | 0 | return false; |
799 | 0 | } |
800 | 0 | return PCompositorBridgeChild::SendStopFrameTimeRecording(startIndex, intervals); |
801 | 0 | } |
802 | | |
803 | | bool |
804 | | CompositorBridgeChild::SendNotifyRegionInvalidated(const nsIntRegion& region) |
805 | 0 | { |
806 | 0 | if (!mCanSend) { |
807 | 0 | return false; |
808 | 0 | } |
809 | 0 | return PCompositorBridgeChild::SendNotifyRegionInvalidated(region); |
810 | 0 | } |
811 | | |
812 | | bool |
813 | | CompositorBridgeChild::SendRequestNotifyAfterRemotePaint() |
814 | 0 | { |
815 | 0 | if (!mCanSend) { |
816 | 0 | return false; |
817 | 0 | } |
818 | 0 | return PCompositorBridgeChild::SendRequestNotifyAfterRemotePaint(); |
819 | 0 | } |
820 | | |
821 | | bool |
822 | | CompositorBridgeChild::SendAllPluginsCaptured() |
823 | 0 | { |
824 | 0 | if (!mCanSend) { |
825 | 0 | return false; |
826 | 0 | } |
827 | 0 | return PCompositorBridgeChild::SendAllPluginsCaptured(); |
828 | 0 | } |
829 | | |
830 | | PTextureChild* |
831 | | CompositorBridgeChild::AllocPTextureChild(const SurfaceDescriptor&, |
832 | | const ReadLockDescriptor&, |
833 | | const LayersBackend&, |
834 | | const TextureFlags&, |
835 | | const LayersId&, |
836 | | const uint64_t& aSerial, |
837 | | const wr::MaybeExternalImageId& aExternalImageId) |
838 | 0 | { |
839 | 0 | return TextureClient::CreateIPDLActor(); |
840 | 0 | } |
841 | | |
842 | | bool |
843 | | CompositorBridgeChild::DeallocPTextureChild(PTextureChild* actor) |
844 | 0 | { |
845 | 0 | return TextureClient::DestroyIPDLActor(actor); |
846 | 0 | } |
847 | | |
848 | | mozilla::ipc::IPCResult |
849 | | CompositorBridgeChild::RecvParentAsyncMessages(InfallibleTArray<AsyncParentMessageData>&& aMessages) |
850 | 0 | { |
851 | 0 | for (AsyncParentMessageArray::index_type i = 0; i < aMessages.Length(); ++i) { |
852 | 0 | const AsyncParentMessageData& message = aMessages[i]; |
853 | 0 |
|
854 | 0 | switch (message.type()) { |
855 | 0 | case AsyncParentMessageData::TOpNotifyNotUsed: { |
856 | 0 | const OpNotifyNotUsed& op = message.get_OpNotifyNotUsed(); |
857 | 0 | NotifyNotUsed(op.TextureId(), op.fwdTransactionId()); |
858 | 0 | break; |
859 | 0 | } |
860 | 0 | default: |
861 | 0 | NS_ERROR("unknown AsyncParentMessageData type"); |
862 | 0 | return IPC_FAIL_NO_REASON(this); |
863 | 0 | } |
864 | 0 | } |
865 | 0 | return IPC_OK(); |
866 | 0 | } |
867 | | |
868 | | mozilla::ipc::IPCResult |
869 | | CompositorBridgeChild::RecvObserveLayersUpdate(const LayersId& aLayersId, |
870 | | const LayersObserverEpoch& aEpoch, |
871 | | const bool& aActive) |
872 | 0 | { |
873 | 0 | // This message is sent via the window compositor, not the tab compositor - |
874 | 0 | // however it still has a layers id. |
875 | 0 | MOZ_ASSERT(aLayersId.IsValid()); |
876 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
877 | 0 |
|
878 | 0 | if (RefPtr<dom::TabParent> tab = dom::TabParent::GetTabParentFromLayersId(aLayersId)) { |
879 | 0 | tab->LayerTreeUpdate(aEpoch, aActive); |
880 | 0 | } |
881 | 0 | return IPC_OK(); |
882 | 0 | } |
883 | | |
884 | | mozilla::ipc::IPCResult |
885 | | CompositorBridgeChild::RecvNotifyWebRenderError(const WebRenderError& aError) |
886 | 0 | { |
887 | 0 | MOZ_ASSERT(XRE_IsParentProcess()); |
888 | 0 | GPUProcessManager::Get()->NotifyWebRenderError(aError); |
889 | 0 | return IPC_OK(); |
890 | 0 | } |
891 | | |
892 | | void |
893 | | CompositorBridgeChild::HoldUntilCompositableRefReleasedIfNecessary(TextureClient* aClient) |
894 | 0 | { |
895 | 0 | if (!aClient) { |
896 | 0 | return; |
897 | 0 | } |
898 | 0 | |
899 | 0 | if (!(aClient->GetFlags() & TextureFlags::RECYCLE)) { |
900 | 0 | return; |
901 | 0 | } |
902 | 0 | |
903 | 0 | aClient->SetLastFwdTransactionId(GetFwdTransactionId()); |
904 | 0 | mTexturesWaitingRecycled.emplace(aClient->GetSerial(), aClient); |
905 | 0 | } |
906 | | |
907 | | void |
908 | | CompositorBridgeChild::NotifyNotUsed(uint64_t aTextureId, uint64_t aFwdTransactionId) |
909 | 0 | { |
910 | 0 | auto it = mTexturesWaitingRecycled.find(aTextureId); |
911 | 0 | if (it != mTexturesWaitingRecycled.end()) { |
912 | 0 | if (aFwdTransactionId < it->second->GetLastFwdTransactionId()) { |
913 | 0 | // Released on host side, but client already requested newer use texture. |
914 | 0 | return; |
915 | 0 | } |
916 | 0 | mTexturesWaitingRecycled.erase(it); |
917 | 0 | } |
918 | 0 | } |
919 | | |
920 | | void |
921 | | CompositorBridgeChild::CancelWaitForRecycle(uint64_t aTextureId) |
922 | 0 | { |
923 | 0 | mTexturesWaitingRecycled.erase(aTextureId); |
924 | 0 | } |
925 | | |
926 | | TextureClientPool* |
927 | | CompositorBridgeChild::GetTexturePool(KnowsCompositor* aAllocator, |
928 | | SurfaceFormat aFormat, |
929 | | TextureFlags aFlags) |
930 | 0 | { |
931 | 0 | for (size_t i = 0; i < mTexturePools.Length(); i++) { |
932 | 0 | if (mTexturePools[i]->GetBackend() == aAllocator->GetCompositorBackendType() && |
933 | 0 | mTexturePools[i]->GetMaxTextureSize() == aAllocator->GetMaxTextureSize() && |
934 | 0 | mTexturePools[i]->GetFormat() == aFormat && |
935 | 0 | mTexturePools[i]->GetFlags() == aFlags) { |
936 | 0 | return mTexturePools[i]; |
937 | 0 | } |
938 | 0 | } |
939 | 0 |
|
940 | 0 | mTexturePools.AppendElement( |
941 | 0 | new TextureClientPool(aAllocator->GetCompositorBackendType(), |
942 | 0 | aAllocator->SupportsTextureDirectMapping(), |
943 | 0 | aAllocator->GetMaxTextureSize(), |
944 | 0 | aFormat, |
945 | 0 | gfx::gfxVars::TileSize(), |
946 | 0 | aFlags, |
947 | 0 | gfxPrefs::LayersTilePoolShrinkTimeout(), |
948 | 0 | gfxPrefs::LayersTilePoolClearTimeout(), |
949 | 0 | gfxPrefs::LayersTileInitialPoolSize(), |
950 | 0 | gfxPrefs::LayersTilePoolUnusedSize(), |
951 | 0 | this)); |
952 | 0 |
|
953 | 0 | return mTexturePools.LastElement(); |
954 | 0 | } |
955 | | |
956 | | void |
957 | | CompositorBridgeChild::HandleMemoryPressure() |
958 | 0 | { |
959 | 0 | for (size_t i = 0; i < mTexturePools.Length(); i++) { |
960 | 0 | mTexturePools[i]->Clear(); |
961 | 0 | } |
962 | 0 | } |
963 | | |
964 | | void |
965 | | CompositorBridgeChild::ClearTexturePool() |
966 | 0 | { |
967 | 0 | for (size_t i = 0; i < mTexturePools.Length(); i++) { |
968 | 0 | mTexturePools[i]->Clear(); |
969 | 0 | } |
970 | 0 | } |
971 | | |
972 | | FixedSizeSmallShmemSectionAllocator* |
973 | | CompositorBridgeChild::GetTileLockAllocator() |
974 | 0 | { |
975 | 0 | if (!IPCOpen()) { |
976 | 0 | return nullptr; |
977 | 0 | } |
978 | 0 | |
979 | 0 | if (!mSectionAllocator) { |
980 | 0 | mSectionAllocator = new FixedSizeSmallShmemSectionAllocator(this); |
981 | 0 | } |
982 | 0 | return mSectionAllocator; |
983 | 0 | } |
984 | | |
985 | | PTextureChild* |
986 | | CompositorBridgeChild::CreateTexture(const SurfaceDescriptor& aSharedData, |
987 | | const ReadLockDescriptor& aReadLock, |
988 | | LayersBackend aLayersBackend, |
989 | | TextureFlags aFlags, |
990 | | uint64_t aSerial, |
991 | | wr::MaybeExternalImageId& aExternalImageId, |
992 | | nsIEventTarget* aTarget) |
993 | 0 | { |
994 | 0 | PTextureChild* textureChild = AllocPTextureChild( |
995 | 0 | aSharedData, aReadLock, aLayersBackend, aFlags, LayersId{0} /* FIXME */, aSerial, aExternalImageId); |
996 | 0 |
|
997 | 0 | // Do the DOM labeling. |
998 | 0 | if (aTarget) { |
999 | 0 | SetEventTargetForActor(textureChild, aTarget); |
1000 | 0 | } |
1001 | 0 |
|
1002 | 0 | return SendPTextureConstructor( |
1003 | 0 | textureChild, aSharedData, aReadLock, aLayersBackend, aFlags, LayersId{0} /* FIXME? */, aSerial, aExternalImageId); |
1004 | 0 | } |
1005 | | |
1006 | | bool |
1007 | | CompositorBridgeChild::AllocUnsafeShmem(size_t aSize, |
1008 | | ipc::SharedMemory::SharedMemoryType aType, |
1009 | | ipc::Shmem* aShmem) |
1010 | 0 | { |
1011 | 0 | ShmemAllocated(this); |
1012 | 0 | return PCompositorBridgeChild::AllocUnsafeShmem(aSize, aType, aShmem); |
1013 | 0 | } |
1014 | | |
1015 | | bool |
1016 | | CompositorBridgeChild::AllocShmem(size_t aSize, |
1017 | | ipc::SharedMemory::SharedMemoryType aType, |
1018 | | ipc::Shmem* aShmem) |
1019 | 0 | { |
1020 | 0 | ShmemAllocated(this); |
1021 | 0 | return PCompositorBridgeChild::AllocShmem(aSize, aType, aShmem); |
1022 | 0 | } |
1023 | | |
1024 | | bool |
1025 | | CompositorBridgeChild::DeallocShmem(ipc::Shmem& aShmem) |
1026 | 0 | { |
1027 | 0 | if (!mCanSend) { |
1028 | 0 | return false; |
1029 | 0 | } |
1030 | 0 | return PCompositorBridgeChild::DeallocShmem(aShmem); |
1031 | 0 | } |
1032 | | |
1033 | | widget::PCompositorWidgetChild* |
1034 | | CompositorBridgeChild::AllocPCompositorWidgetChild(const CompositorWidgetInitData& aInitData) |
1035 | 0 | { |
1036 | 0 | // We send the constructor manually. |
1037 | 0 | MOZ_CRASH("Should not be called"); |
1038 | 0 | return nullptr; |
1039 | 0 | } |
1040 | | |
1041 | | bool |
1042 | | CompositorBridgeChild::DeallocPCompositorWidgetChild(PCompositorWidgetChild* aActor) |
1043 | 0 | { |
1044 | 0 | #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING |
1045 | 0 | delete aActor; |
1046 | 0 | return true; |
1047 | | #else |
1048 | | return false; |
1049 | | #endif |
1050 | | } |
1051 | | |
1052 | | PAPZCTreeManagerChild* |
1053 | | CompositorBridgeChild::AllocPAPZCTreeManagerChild(const LayersId& aLayersId) |
1054 | 0 | { |
1055 | 0 | APZCTreeManagerChild* child = new APZCTreeManagerChild(); |
1056 | 0 | child->AddRef(); |
1057 | 0 | if (aLayersId.IsValid()) { |
1058 | 0 | TabChild* tabChild = TabChild::GetFrom(aLayersId); |
1059 | 0 | if (tabChild) { |
1060 | 0 | SetEventTargetForActor( |
1061 | 0 | child, tabChild->TabGroup()->EventTargetFor(TaskCategory::Other)); |
1062 | 0 | MOZ_ASSERT(child->GetActorEventTarget()); |
1063 | 0 | } |
1064 | 0 | } |
1065 | 0 |
|
1066 | 0 | return child; |
1067 | 0 | } |
1068 | | |
1069 | | PAPZChild* |
1070 | | CompositorBridgeChild::AllocPAPZChild(const LayersId& aLayersId) |
1071 | 0 | { |
1072 | 0 | // We send the constructor manually. |
1073 | 0 | MOZ_CRASH("Should not be called"); |
1074 | 0 | return nullptr; |
1075 | 0 | } |
1076 | | |
1077 | | bool |
1078 | | CompositorBridgeChild::DeallocPAPZChild(PAPZChild* aActor) |
1079 | 0 | { |
1080 | 0 | delete aActor; |
1081 | 0 | return true; |
1082 | 0 | } |
1083 | | |
1084 | | bool |
1085 | | CompositorBridgeChild::DeallocPAPZCTreeManagerChild(PAPZCTreeManagerChild* aActor) |
1086 | 0 | { |
1087 | 0 | APZCTreeManagerChild* parent = static_cast<APZCTreeManagerChild*>(aActor); |
1088 | 0 | parent->Release(); |
1089 | 0 | return true; |
1090 | 0 | } |
1091 | | |
1092 | | void |
1093 | | CompositorBridgeChild::WillEndTransaction() |
1094 | 0 | { |
1095 | 0 | ResetShmemCounter(); |
1096 | 0 | } |
1097 | | |
1098 | | PWebRenderBridgeChild* |
1099 | | CompositorBridgeChild::AllocPWebRenderBridgeChild(const wr::PipelineId& aPipelineId, |
1100 | | const LayoutDeviceIntSize&, |
1101 | | TextureFactoryIdentifier*, |
1102 | | wr::IdNamespace *aIdNamespace) |
1103 | 0 | { |
1104 | 0 | WebRenderBridgeChild* child = new WebRenderBridgeChild(aPipelineId); |
1105 | 0 | child->AddIPDLReference(); |
1106 | 0 | return child; |
1107 | 0 | } |
1108 | | |
1109 | | bool |
1110 | | CompositorBridgeChild::DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActor) |
1111 | 0 | { |
1112 | 0 | WebRenderBridgeChild* child = static_cast<WebRenderBridgeChild*>(aActor); |
1113 | 0 | ClearSharedFrameMetricsData(wr::AsLayersId(child->GetPipeline())); |
1114 | 0 | child->ReleaseIPDLReference(); |
1115 | 0 | return true; |
1116 | 0 | } |
1117 | | |
1118 | | void |
1119 | | CompositorBridgeChild::ClearSharedFrameMetricsData(LayersId aLayersId) |
1120 | 0 | { |
1121 | 0 | for (auto iter = mFrameMetricsTable.Iter(); !iter.Done(); iter.Next()) { |
1122 | 0 | nsAutoPtr<SharedFrameMetricsData>& data = iter.Data(); |
1123 | 0 | if (data->GetLayersId() == aLayersId) { |
1124 | 0 | iter.Remove(); |
1125 | 0 | } |
1126 | 0 | } |
1127 | 0 | } |
1128 | | |
1129 | | uint64_t |
1130 | | CompositorBridgeChild::GetNextResourceId() |
1131 | 0 | { |
1132 | 0 | ++mResourceId; |
1133 | 0 | MOZ_RELEASE_ASSERT(mResourceId != UINT32_MAX); |
1134 | 0 |
|
1135 | 0 | uint64_t id = mIdNamespace; |
1136 | 0 | id = (id << 32) | mResourceId; |
1137 | 0 |
|
1138 | 0 | return id; |
1139 | 0 | } |
1140 | | |
1141 | | wr::MaybeExternalImageId |
1142 | | CompositorBridgeChild::GetNextExternalImageId() |
1143 | 0 | { |
1144 | 0 | return Some(wr::ToExternalImageId(GetNextResourceId())); |
1145 | 0 | } |
1146 | | |
1147 | | wr::PipelineId |
1148 | | CompositorBridgeChild::GetNextPipelineId() |
1149 | 0 | { |
1150 | 0 | return wr::AsPipelineId(GetNextResourceId()); |
1151 | 0 | } |
1152 | | |
1153 | | void |
1154 | | CompositorBridgeChild::FlushAsyncPaints() |
1155 | 0 | { |
1156 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1157 | 0 |
|
1158 | 0 | Maybe<TimeStamp> start; |
1159 | 0 | if (XRE_IsContentProcess() && gfx::gfxVars::UseOMTP()) { |
1160 | 0 | start = Some(TimeStamp::Now()); |
1161 | 0 | } |
1162 | 0 |
|
1163 | 0 | { |
1164 | 0 | MonitorAutoLock lock(mPaintLock); |
1165 | 0 | while (mOutstandingAsyncPaints > 0 || mOutstandingAsyncEndTransaction) { |
1166 | 0 | lock.Wait(); |
1167 | 0 | } |
1168 | 0 |
|
1169 | 0 | // It's now safe to free any TextureClients that were used during painting. |
1170 | 0 | mTextureClientsForAsyncPaint.Clear(); |
1171 | 0 | } |
1172 | 0 |
|
1173 | 0 | if (start) { |
1174 | 0 | float ms = (TimeStamp::Now() - start.value()).ToMilliseconds(); |
1175 | 0 |
|
1176 | 0 | // Anything above 200us gets recorded. |
1177 | 0 | if (ms >= 0.2) { |
1178 | 0 | mSlowFlushCount++; |
1179 | 0 | Telemetry::Accumulate(Telemetry::GFX_OMTP_PAINT_WAIT_TIME, int32_t(ms)); |
1180 | 0 | } |
1181 | 0 | mTotalFlushCount++; |
1182 | 0 |
|
1183 | 0 | double ratio = double(mSlowFlushCount) / double(mTotalFlushCount); |
1184 | 0 | Telemetry::ScalarSet(Telemetry::ScalarID::GFX_OMTP_PAINT_WAIT_RATIO, |
1185 | 0 | uint32_t(ratio * 100 * 100)); |
1186 | 0 | } |
1187 | 0 | } |
1188 | | |
1189 | | void |
1190 | | CompositorBridgeChild::NotifyBeginAsyncPaint(PaintTask* aTask) |
1191 | 0 | { |
1192 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1193 | 0 |
|
1194 | 0 | MonitorAutoLock lock(mPaintLock); |
1195 | 0 |
|
1196 | 0 | if (mTotalAsyncPaints == 0) { |
1197 | 0 | mAsyncTransactionBegin = TimeStamp::Now(); |
1198 | 0 | } |
1199 | 0 | mTotalAsyncPaints += 1; |
1200 | 0 |
|
1201 | 0 | // We must not be waiting for paints or buffer copying to complete yet. This |
1202 | 0 | // would imply we started a new paint without waiting for a previous one, which |
1203 | 0 | // could lead to incorrect rendering or IPDL deadlocks. |
1204 | 0 | MOZ_ASSERT(!mIsDelayingForAsyncPaints); |
1205 | 0 |
|
1206 | 0 | mOutstandingAsyncPaints++; |
1207 | 0 |
|
1208 | 0 | // Mark texture clients that they are being used for async painting, and |
1209 | 0 | // make sure we hold them alive on the main thread. |
1210 | 0 | for (auto& client : aTask->mClients) { |
1211 | 0 | client->AddPaintThreadRef(); |
1212 | 0 | mTextureClientsForAsyncPaint.AppendElement(client); |
1213 | 0 | }; |
1214 | 0 | } |
1215 | | |
1216 | | // Must only be called from the paint thread. Notifies the CompositorBridge |
1217 | | // that the paint thread has finished an asynchronous paint request. |
1218 | | bool |
1219 | | CompositorBridgeChild::NotifyFinishedAsyncWorkerPaint(PaintTask* aTask) |
1220 | 0 | { |
1221 | 0 | MOZ_ASSERT(PaintThread::Get()->IsOnPaintWorkerThread()); |
1222 | 0 |
|
1223 | 0 | MonitorAutoLock lock(mPaintLock); |
1224 | 0 | mOutstandingAsyncPaints--; |
1225 | 0 |
|
1226 | 0 | for (auto& client : aTask->mClients) { |
1227 | 0 | client->DropPaintThreadRef(); |
1228 | 0 | }; |
1229 | 0 | aTask->DropTextureClients(); |
1230 | 0 |
|
1231 | 0 | // If the main thread has completed queuing work and this was the |
1232 | 0 | // last paint, then it is time to end the layer transaction and sync |
1233 | 0 | return mOutstandingAsyncEndTransaction && mOutstandingAsyncPaints == 0; |
1234 | 0 | } |
1235 | | |
1236 | | bool |
1237 | | CompositorBridgeChild::NotifyBeginAsyncEndLayerTransaction(SyncObjectClient* aSyncObject) |
1238 | 0 | { |
1239 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1240 | 0 | MonitorAutoLock lock(mPaintLock); |
1241 | 0 |
|
1242 | 0 | MOZ_ASSERT(!mOutstandingAsyncEndTransaction); |
1243 | 0 | mOutstandingAsyncEndTransaction = true; |
1244 | 0 | mOutstandingAsyncSyncObject = aSyncObject; |
1245 | 0 | return mOutstandingAsyncPaints == 0; |
1246 | 0 | } |
1247 | | |
1248 | | void |
1249 | | CompositorBridgeChild::NotifyFinishedAsyncEndLayerTransaction() |
1250 | 0 | { |
1251 | 0 | MOZ_ASSERT(PaintThread::Get()->IsOnPaintWorkerThread()); |
1252 | 0 |
|
1253 | 0 | if (mOutstandingAsyncSyncObject) { |
1254 | 0 | mOutstandingAsyncSyncObject->Synchronize(); |
1255 | 0 | mOutstandingAsyncSyncObject = nullptr; |
1256 | 0 | } |
1257 | 0 |
|
1258 | 0 | MonitorAutoLock lock(mPaintLock); |
1259 | 0 |
|
1260 | 0 | if (mTotalAsyncPaints > 0) { |
1261 | 0 | float tenthMs = (TimeStamp::Now() - mAsyncTransactionBegin).ToMilliseconds() * 10; |
1262 | 0 | Telemetry::Accumulate(Telemetry::GFX_OMTP_PAINT_TASK_COUNT, int32_t(mTotalAsyncPaints)); |
1263 | 0 | Telemetry::Accumulate(Telemetry::GFX_OMTP_PAINT_TIME, int32_t(tenthMs)); |
1264 | 0 | mTotalAsyncPaints = 0; |
1265 | 0 | } |
1266 | 0 |
|
1267 | 0 | // Since this should happen after ALL paints are done and |
1268 | 0 | // at the end of a transaction, this should always be true. |
1269 | 0 | MOZ_RELEASE_ASSERT(mOutstandingAsyncPaints == 0); |
1270 | 0 | MOZ_ASSERT(mOutstandingAsyncEndTransaction); |
1271 | 0 |
|
1272 | 0 | mOutstandingAsyncEndTransaction = false; |
1273 | 0 |
|
1274 | 0 | // It's possible that we painted so fast that the main thread never reached |
1275 | 0 | // the code that starts delaying messages. If so, mIsDelayingForAsyncPaints will be |
1276 | 0 | // false, and we can safely return. |
1277 | 0 | if (mIsDelayingForAsyncPaints) { |
1278 | 0 | ResumeIPCAfterAsyncPaint(); |
1279 | 0 | } |
1280 | 0 |
|
1281 | 0 | // Notify the main thread in case it's blocking. We do this unconditionally |
1282 | 0 | // to avoid deadlocking. |
1283 | 0 | lock.Notify(); |
1284 | 0 | } |
1285 | | |
1286 | | void |
1287 | | CompositorBridgeChild::ResumeIPCAfterAsyncPaint() |
1288 | 0 | { |
1289 | 0 | // Note: the caller is responsible for holding the lock. |
1290 | 0 | mPaintLock.AssertCurrentThreadOwns(); |
1291 | 0 | MOZ_ASSERT(PaintThread::Get()->IsOnPaintWorkerThread()); |
1292 | 0 | MOZ_ASSERT(mOutstandingAsyncPaints == 0); |
1293 | 0 | MOZ_ASSERT(!mOutstandingAsyncEndTransaction); |
1294 | 0 | MOZ_ASSERT(mIsDelayingForAsyncPaints); |
1295 | 0 |
|
1296 | 0 | mIsDelayingForAsyncPaints = false; |
1297 | 0 |
|
1298 | 0 | // It's also possible that the channel has shut down already. |
1299 | 0 | if (!mCanSend || mActorDestroyed) { |
1300 | 0 | return; |
1301 | 0 | } |
1302 | 0 | |
1303 | 0 | GetIPCChannel()->StopPostponingSends(); |
1304 | 0 | } |
1305 | | |
1306 | | void |
1307 | | CompositorBridgeChild::PostponeMessagesIfAsyncPainting() |
1308 | 0 | { |
1309 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1310 | 0 |
|
1311 | 0 | MonitorAutoLock lock(mPaintLock); |
1312 | 0 |
|
1313 | 0 | MOZ_ASSERT(!mIsDelayingForAsyncPaints); |
1314 | 0 |
|
1315 | 0 | // We need to wait for async paints and the async end transaction as |
1316 | 0 | // it will do texture synchronization |
1317 | 0 | if (mOutstandingAsyncPaints > 0 || mOutstandingAsyncEndTransaction) { |
1318 | 0 | mIsDelayingForAsyncPaints = true; |
1319 | 0 | GetIPCChannel()->BeginPostponingSends(); |
1320 | 0 | } |
1321 | 0 | } |
1322 | | |
1323 | | } // namespace layers |
1324 | | } // namespace mozilla |