/src/mozilla-central/gfx/layers/ipc/CompositorBridgeParent.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/CompositorBridgeParent.h" |
8 | | |
9 | | #include <stdio.h> // for fprintf, stdout |
10 | | #include <stdint.h> // for uint64_t |
11 | | #include <map> // for _Rb_tree_iterator, etc |
12 | | #include <utility> // for pair |
13 | | |
14 | | #include "apz/src/APZCTreeManager.h" // for APZCTreeManager |
15 | | #include "LayerTransactionParent.h" // for LayerTransactionParent |
16 | | #include "RenderTrace.h" // for RenderTraceLayers |
17 | | #include "base/message_loop.h" // for MessageLoop |
18 | | #include "base/process.h" // for ProcessId |
19 | | #include "base/task.h" // for CancelableTask, etc |
20 | | #include "base/thread.h" // for Thread |
21 | | #include "gfxContext.h" // for gfxContext |
22 | | #include "gfxPlatform.h" // for gfxPlatform |
23 | | #include "TreeTraversal.h" // for ForEachNode |
24 | | #ifdef MOZ_WIDGET_GTK |
25 | | #include "gfxPlatformGtk.h" // for gfxPlatform |
26 | | #endif |
27 | | #include "gfxPrefs.h" // for gfxPrefs |
28 | | #include "mozilla/AutoRestore.h" // for AutoRestore |
29 | | #include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown |
30 | | #include "mozilla/DebugOnly.h" // for DebugOnly |
31 | | #include "mozilla/dom/ContentParent.h" |
32 | | #include "mozilla/dom/TabParent.h" |
33 | | #include "mozilla/gfx/2D.h" // for DrawTarget |
34 | | #include "mozilla/gfx/GPUChild.h" // for GfxPrefValue |
35 | | #include "mozilla/gfx/Point.h" // for IntSize |
36 | | #include "mozilla/gfx/Rect.h" // for IntSize |
37 | | #include "mozilla/gfx/gfxVars.h" // for gfxVars |
38 | | #include "VRManager.h" // for VRManager |
39 | | #include "mozilla/ipc/Transport.h" // for Transport |
40 | | #include "mozilla/gfx/gfxVars.h" |
41 | | #include "mozilla/gfx/GPUParent.h" |
42 | | #include "mozilla/layers/AnimationHelper.h" // for CompositorAnimationStorage |
43 | | #include "mozilla/layers/APZCTreeManagerParent.h" // for APZCTreeManagerParent |
44 | | #include "mozilla/layers/APZSampler.h" // for APZSampler |
45 | | #include "mozilla/layers/APZThreadUtils.h" // for APZThreadUtils |
46 | | #include "mozilla/layers/APZUpdater.h" // for APZUpdater |
47 | | #include "mozilla/layers/AsyncCompositionManager.h" |
48 | | #include "mozilla/layers/BasicCompositor.h" // for BasicCompositor |
49 | | #include "mozilla/layers/Compositor.h" // for Compositor |
50 | | #include "mozilla/layers/CompositorManagerParent.h" // for CompositorManagerParent |
51 | | #include "mozilla/layers/CompositorOGL.h" // for CompositorOGL |
52 | | #include "mozilla/layers/CompositorThread.h" |
53 | | #include "mozilla/layers/CompositorTypes.h" |
54 | | #include "mozilla/layers/CompositorVsyncScheduler.h" |
55 | | #include "mozilla/layers/CrossProcessCompositorBridgeParent.h" |
56 | | #include "mozilla/layers/FrameUniformityData.h" |
57 | | #include "mozilla/layers/ImageBridgeParent.h" |
58 | | #include "mozilla/layers/LayerManagerComposite.h" |
59 | | #include "mozilla/layers/LayerManagerMLGPU.h" |
60 | | #include "mozilla/layers/LayerTreeOwnerTracker.h" |
61 | | #include "mozilla/layers/LayersTypes.h" |
62 | | #include "mozilla/layers/PLayerTransactionParent.h" |
63 | | #include "mozilla/layers/RemoteContentController.h" |
64 | | #include "mozilla/layers/WebRenderBridgeParent.h" |
65 | | #include "mozilla/layers/AsyncImagePipelineManager.h" |
66 | | #include "mozilla/layout/RenderFrameParent.h" |
67 | | #include "mozilla/webrender/WebRenderAPI.h" |
68 | | #include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService |
69 | | #include "mozilla/mozalloc.h" // for operator new, etc |
70 | | #include "mozilla/Telemetry.h" |
71 | | #ifdef MOZ_WIDGET_GTK |
72 | | #include "basic/X11BasicCompositor.h" // for X11BasicCompositor |
73 | | #endif |
74 | | #include "nsCOMPtr.h" // for already_AddRefed |
75 | | #include "nsDebug.h" // for NS_ASSERTION, etc |
76 | | #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc |
77 | | #include "nsIWidget.h" // for nsIWidget |
78 | | #include "nsTArray.h" // for nsTArray |
79 | | #include "nsThreadUtils.h" // for NS_IsMainThread |
80 | | #include "nsXULAppAPI.h" // for XRE_GetIOMessageLoop |
81 | | #ifdef XP_WIN |
82 | | #include "mozilla/layers/CompositorD3D11.h" |
83 | | #include "mozilla/widget/WinCompositorWidget.h" |
84 | | #endif |
85 | | #include "GeckoProfiler.h" |
86 | | #include "mozilla/ipc/ProtocolTypes.h" |
87 | | #include "mozilla/Unused.h" |
88 | | #include "mozilla/Hal.h" |
89 | | #include "mozilla/HalTypes.h" |
90 | | #include "mozilla/StaticPtr.h" |
91 | | #include "mozilla/Telemetry.h" |
92 | | #ifdef MOZ_GECKO_PROFILER |
93 | | # include "ProfilerMarkerPayload.h" |
94 | | #endif |
95 | | #include "mozilla/VsyncDispatcher.h" |
96 | | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
97 | | # include "VsyncSource.h" |
98 | | #endif |
99 | | #include "mozilla/widget/CompositorWidget.h" |
100 | | #ifdef MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING |
101 | | # include "mozilla/widget/CompositorWidgetParent.h" |
102 | | #endif |
103 | | #ifdef XP_WIN |
104 | | # include "mozilla/gfx/DeviceManagerDx.h" |
105 | | #endif |
106 | | |
107 | | #include "LayerScope.h" |
108 | | |
109 | | namespace mozilla { |
110 | | |
111 | | namespace layers { |
112 | | |
113 | | using namespace mozilla::ipc; |
114 | | using namespace mozilla::gfx; |
115 | | using namespace std; |
116 | | |
117 | | using base::ProcessId; |
118 | | using base::Thread; |
119 | | |
120 | | |
121 | | /// Equivalent to asserting CompositorThreadHolder::IsInCompositorThread with the |
122 | | /// addition that it doesn't assert if the compositor thread holder is already gone |
123 | | /// during late shutdown. |
124 | | static void AssertIsInCompositorThread() |
125 | 0 | { |
126 | 0 | MOZ_RELEASE_ASSERT(!CompositorThread() || |
127 | 0 | CompositorThreadHolder::IsInCompositorThread()); |
128 | 0 | } |
129 | | |
130 | | CompositorBridgeParentBase::CompositorBridgeParentBase(CompositorManagerParent* aManager) |
131 | | : mCanSend(true) |
132 | | , mCompositorManager(aManager) |
133 | 0 | { |
134 | 0 | } |
135 | | |
136 | | CompositorBridgeParentBase::~CompositorBridgeParentBase() |
137 | 0 | { |
138 | 0 | } |
139 | | |
140 | | ProcessId |
141 | | CompositorBridgeParentBase::GetChildProcessId() |
142 | 0 | { |
143 | 0 | return OtherPid(); |
144 | 0 | } |
145 | | |
146 | | void |
147 | | CompositorBridgeParentBase::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId) |
148 | 0 | { |
149 | 0 | RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture); |
150 | 0 | if (!texture) { |
151 | 0 | return; |
152 | 0 | } |
153 | 0 | |
154 | 0 | if (!(texture->GetFlags() & TextureFlags::RECYCLE)) { |
155 | 0 | return; |
156 | 0 | } |
157 | 0 | |
158 | 0 | uint64_t textureId = TextureHost::GetTextureSerial(aTexture); |
159 | 0 | mPendingAsyncMessage.push_back( |
160 | 0 | OpNotifyNotUsed(textureId, aTransactionId)); |
161 | 0 | } |
162 | | |
163 | | void |
164 | | CompositorBridgeParentBase::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage) |
165 | 0 | { |
166 | 0 | Unused << SendParentAsyncMessages(aMessage); |
167 | 0 | } |
168 | | |
169 | | bool |
170 | | CompositorBridgeParentBase::AllocShmem(size_t aSize, |
171 | | ipc::SharedMemory::SharedMemoryType aType, |
172 | | ipc::Shmem* aShmem) |
173 | 0 | { |
174 | 0 | return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem); |
175 | 0 | } |
176 | | |
177 | | bool |
178 | | CompositorBridgeParentBase::AllocUnsafeShmem(size_t aSize, |
179 | | ipc::SharedMemory::SharedMemoryType aType, |
180 | | ipc::Shmem* aShmem) |
181 | 0 | { |
182 | 0 | return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem); |
183 | 0 | } |
184 | | |
185 | | void |
186 | | CompositorBridgeParentBase::DeallocShmem(ipc::Shmem& aShmem) |
187 | 0 | { |
188 | 0 | PCompositorBridgeParent::DeallocShmem(aShmem); |
189 | 0 | } |
190 | | |
191 | | static inline MessageLoop* |
192 | | CompositorLoop() |
193 | 0 | { |
194 | 0 | return CompositorThreadHolder::Loop(); |
195 | 0 | } |
196 | | |
197 | | base::ProcessId |
198 | | CompositorBridgeParentBase::RemotePid() |
199 | 0 | { |
200 | 0 | return OtherPid(); |
201 | 0 | } |
202 | | |
203 | | bool |
204 | | CompositorBridgeParentBase::StartSharingMetrics(ipc::SharedMemoryBasic::Handle aHandle, |
205 | | CrossProcessMutexHandle aMutexHandle, |
206 | | LayersId aLayersId, |
207 | | uint32_t aApzcId) |
208 | 0 | { |
209 | 0 | if (!CompositorThreadHolder::IsInCompositorThread()) { |
210 | 0 | MOZ_ASSERT(CompositorLoop()); |
211 | 0 | CompositorLoop()->PostTask( |
212 | 0 | NewRunnableMethod<ipc::SharedMemoryBasic::Handle, |
213 | 0 | CrossProcessMutexHandle, |
214 | 0 | LayersId, |
215 | 0 | uint32_t>( |
216 | 0 | "layers::CompositorBridgeParent::StartSharingMetrics", |
217 | 0 | this, |
218 | 0 | &CompositorBridgeParentBase::StartSharingMetrics, |
219 | 0 | aHandle, aMutexHandle, aLayersId, aApzcId)); |
220 | 0 | return true; |
221 | 0 | } |
222 | 0 |
|
223 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
224 | 0 | if (!mCanSend) { |
225 | 0 | return false; |
226 | 0 | } |
227 | 0 | return PCompositorBridgeParent::SendSharedCompositorFrameMetrics( |
228 | 0 | aHandle, aMutexHandle, aLayersId, aApzcId); |
229 | 0 | } |
230 | | |
231 | | bool |
232 | | CompositorBridgeParentBase::StopSharingMetrics(FrameMetrics::ViewID aScrollId, |
233 | | uint32_t aApzcId) |
234 | 0 | { |
235 | 0 | if (!CompositorThreadHolder::IsInCompositorThread()) { |
236 | 0 | MOZ_ASSERT(CompositorLoop()); |
237 | 0 | CompositorLoop()->PostTask( |
238 | 0 | NewRunnableMethod<FrameMetrics::ViewID, uint32_t>( |
239 | 0 | "layers::CompositorBridgeParent::StopSharingMetrics", |
240 | 0 | this, |
241 | 0 | &CompositorBridgeParentBase::StopSharingMetrics, |
242 | 0 | aScrollId, aApzcId)); |
243 | 0 | return true; |
244 | 0 | } |
245 | 0 |
|
246 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
247 | 0 | if (!mCanSend) { |
248 | 0 | return false; |
249 | 0 | } |
250 | 0 | return PCompositorBridgeParent::SendReleaseSharedCompositorFrameMetrics( |
251 | 0 | aScrollId, aApzcId); |
252 | 0 | } |
253 | | |
254 | | CompositorBridgeParent::LayerTreeState::LayerTreeState() |
255 | | : mApzcTreeManagerParent(nullptr) |
256 | | , mParent(nullptr) |
257 | | , mLayerManager(nullptr) |
258 | | , mCrossProcessParent(nullptr) |
259 | | , mLayerTree(nullptr) |
260 | | , mUpdatedPluginDataAvailable(false) |
261 | 0 | { |
262 | 0 | } |
263 | | |
264 | | CompositorBridgeParent::LayerTreeState::~LayerTreeState() |
265 | 0 | { |
266 | 0 | if (mController) { |
267 | 0 | mController->Destroy(); |
268 | 0 | } |
269 | 0 | } |
270 | | |
271 | | typedef map<LayersId, CompositorBridgeParent::LayerTreeState> LayerTreeMap; |
272 | | LayerTreeMap sIndirectLayerTrees; |
273 | | StaticAutoPtr<mozilla::Monitor> sIndirectLayerTreesLock; |
274 | | |
275 | | static void EnsureLayerTreeMapReady() |
276 | 0 | { |
277 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
278 | 0 | if (!sIndirectLayerTreesLock) { |
279 | 0 | sIndirectLayerTreesLock = new Monitor("IndirectLayerTree"); |
280 | 0 | mozilla::ClearOnShutdown(&sIndirectLayerTreesLock); |
281 | 0 | } |
282 | 0 | } |
283 | | |
284 | | template <typename Lambda> |
285 | | inline void |
286 | | CompositorBridgeParent::ForEachIndirectLayerTree(const Lambda& aCallback) |
287 | 0 | { |
288 | 0 | sIndirectLayerTreesLock->AssertCurrentThreadOwns(); |
289 | 0 | for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end(); it++) { |
290 | 0 | LayerTreeState* state = &it->second; |
291 | 0 | if (state->mParent == this) { |
292 | 0 | aCallback(state, it->first); |
293 | 0 | } |
294 | 0 | } |
295 | 0 | } Unexecuted instantiation: Unified_cpp_gfx_layers8.cpp:void mozilla::layers::CompositorBridgeParent::ForEachIndirectLayerTree<mozilla::layers::CompositorBridgeParent::StopAndClearResources()::$_0>(mozilla::layers::CompositorBridgeParent::StopAndClearResources()::$_0 const&) Unexecuted instantiation: Unified_cpp_gfx_layers8.cpp:void mozilla::layers::CompositorBridgeParent::ForEachIndirectLayerTree<mozilla::layers::CompositorBridgeParent::StopAndClearResources()::$_1>(mozilla::layers::CompositorBridgeParent::StopAndClearResources()::$_1 const&) Unexecuted instantiation: Unified_cpp_gfx_layers8.cpp:void mozilla::layers::CompositorBridgeParent::ForEachIndirectLayerTree<mozilla::layers::CompositorBridgeParent::NotifyPipelineRendered(mozilla::wr::PipelineId const&, mozilla::wr::Epoch const&, mozilla::TimeStamp&, mozilla::TimeStamp&)::$_4>(mozilla::layers::CompositorBridgeParent::NotifyPipelineRendered(mozilla::wr::PipelineId const&, mozilla::wr::Epoch const&, mozilla::TimeStamp&, mozilla::TimeStamp&)::$_4 const&) Unexecuted instantiation: Unified_cpp_gfx_layers8.cpp:void mozilla::layers::CompositorBridgeParent::ForEachIndirectLayerTree<mozilla::layers::CompositorBridgeParent::NotifyDidComposite(mozilla::layers::TransactionId, mozilla::TimeStamp&, mozilla::TimeStamp&)::$_5>(mozilla::layers::CompositorBridgeParent::NotifyDidComposite(mozilla::layers::TransactionId, mozilla::TimeStamp&, mozilla::TimeStamp&)::$_5 const&) Unexecuted instantiation: Unified_cpp_gfx_layers8.cpp:void mozilla::layers::CompositorBridgeParent::ForEachIndirectLayerTree<mozilla::layers::CompositorBridgeParent::InvalidateRemoteLayers()::$_6>(mozilla::layers::CompositorBridgeParent::InvalidateRemoteLayers()::$_6 const&) |
296 | | |
297 | | /** |
298 | | * A global map referencing each compositor by ID. |
299 | | * |
300 | | * This map is used by the ImageBridge protocol to trigger |
301 | | * compositions without having to keep references to the |
302 | | * compositor |
303 | | */ |
304 | | typedef map<uint64_t,CompositorBridgeParent*> CompositorMap; |
305 | | static StaticAutoPtr<CompositorMap> sCompositorMap; |
306 | | |
307 | | void |
308 | | CompositorBridgeParent::Setup() |
309 | 0 | { |
310 | 0 | EnsureLayerTreeMapReady(); |
311 | 0 |
|
312 | 0 | MOZ_ASSERT(!sCompositorMap); |
313 | 0 | sCompositorMap = new CompositorMap; |
314 | 0 | } |
315 | | |
316 | | void |
317 | | CompositorBridgeParent::FinishShutdown() |
318 | 0 | { |
319 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
320 | 0 |
|
321 | 0 | if (sCompositorMap) { |
322 | 0 | MOZ_ASSERT(sCompositorMap->empty()); |
323 | 0 | sCompositorMap = nullptr; |
324 | 0 | } |
325 | 0 |
|
326 | 0 | // TODO: this should be empty by now... |
327 | 0 | sIndirectLayerTrees.clear(); |
328 | 0 | } |
329 | | |
330 | | #ifdef COMPOSITOR_PERFORMANCE_WARNING |
331 | | static int32_t |
332 | | CalculateCompositionFrameRate() |
333 | | { |
334 | | // Used when layout.frame_rate is -1. Needs to be kept in sync with |
335 | | // DEFAULT_FRAME_RATE in nsRefreshDriver.cpp. |
336 | | // TODO: This should actually return the vsync rate. |
337 | | const int32_t defaultFrameRate = 60; |
338 | | int32_t compositionFrameRatePref = gfxPrefs::LayersCompositionFrameRate(); |
339 | | if (compositionFrameRatePref < 0) { |
340 | | // Use the same frame rate for composition as for layout. |
341 | | int32_t layoutFrameRatePref = gfxPrefs::LayoutFrameRate(); |
342 | | if (layoutFrameRatePref < 0) { |
343 | | // TODO: The main thread frame scheduling code consults the actual |
344 | | // monitor refresh rate in this case. We should do the same. |
345 | | return defaultFrameRate; |
346 | | } |
347 | | return layoutFrameRatePref; |
348 | | } |
349 | | return compositionFrameRatePref; |
350 | | } |
351 | | #endif |
352 | | |
353 | | CompositorBridgeParent::CompositorBridgeParent(CompositorManagerParent* aManager, |
354 | | CSSToLayoutDeviceScale aScale, |
355 | | const TimeDuration& aVsyncRate, |
356 | | const CompositorOptions& aOptions, |
357 | | bool aUseExternalSurfaceSize, |
358 | | const gfx::IntSize& aSurfaceSize) |
359 | | : CompositorBridgeParentBase(aManager) |
360 | | , mWidget(nullptr) |
361 | | , mScale(aScale) |
362 | | , mVsyncRate(aVsyncRate) |
363 | | , mPendingTransaction{0} |
364 | | , mPaused(false) |
365 | | , mUseExternalSurfaceSize(aUseExternalSurfaceSize) |
366 | | , mEGLSurfaceSize(aSurfaceSize) |
367 | | , mOptions(aOptions) |
368 | | , mPauseCompositionMonitor("PauseCompositionMonitor") |
369 | | , mResumeCompositionMonitor("ResumeCompositionMonitor") |
370 | | , mCompositorBridgeID(0) |
371 | | , mRootLayerTreeID{0} |
372 | | , mOverrideComposeReadiness(false) |
373 | | , mForceCompositionTask(nullptr) |
374 | | , mCompositorScheduler(nullptr) |
375 | | , mAnimationStorage(nullptr) |
376 | | , mPaintTime(TimeDuration::Forever()) |
377 | | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
378 | | , mLastPluginUpdateLayerTreeId{0} |
379 | | , mDeferPluginWindows(false) |
380 | | , mPluginWindowsHidden(false) |
381 | | #endif |
382 | 0 | { |
383 | 0 | } |
384 | | |
385 | | void |
386 | | CompositorBridgeParent::InitSameProcess(widget::CompositorWidget* aWidget, |
387 | | const LayersId& aLayerTreeId) |
388 | 0 | { |
389 | 0 | MOZ_ASSERT(XRE_IsParentProcess() || recordreplay::IsRecordingOrReplaying()); |
390 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
391 | 0 |
|
392 | 0 | mWidget = aWidget; |
393 | 0 | mRootLayerTreeID = aLayerTreeId; |
394 | 0 |
|
395 | 0 | Initialize(); |
396 | 0 | } |
397 | | |
398 | | mozilla::ipc::IPCResult |
399 | | CompositorBridgeParent::RecvInitialize(const LayersId& aRootLayerTreeId) |
400 | 0 | { |
401 | 0 | MOZ_ASSERT(XRE_IsGPUProcess()); |
402 | 0 |
|
403 | 0 | mRootLayerTreeID = aRootLayerTreeId; |
404 | 0 |
|
405 | 0 | Initialize(); |
406 | 0 | return IPC_OK(); |
407 | 0 | } |
408 | | |
409 | | void |
410 | | CompositorBridgeParent::Initialize() |
411 | 0 | { |
412 | 0 | MOZ_ASSERT(CompositorThread(), |
413 | 0 | "The compositor thread must be Initialized before instanciating a CompositorBridgeParent."); |
414 | 0 |
|
415 | 0 | if (mOptions.UseAPZ()) { |
416 | 0 | MOZ_ASSERT(!mApzcTreeManager); |
417 | 0 | MOZ_ASSERT(!mApzSampler); |
418 | 0 | MOZ_ASSERT(!mApzUpdater); |
419 | 0 | mApzcTreeManager = new APZCTreeManager(mRootLayerTreeID); |
420 | 0 | mApzSampler = new APZSampler(mApzcTreeManager, mOptions.UseWebRender()); |
421 | 0 | mApzUpdater = new APZUpdater(mApzcTreeManager, mOptions.UseWebRender()); |
422 | 0 | } |
423 | 0 |
|
424 | 0 | mPaused = mOptions.InitiallyPaused(); |
425 | 0 |
|
426 | 0 | mCompositorBridgeID = 0; |
427 | 0 | // FIXME: This holds on the the fact that right now the only thing that |
428 | 0 | // can destroy this instance is initialized on the compositor thread after |
429 | 0 | // this task has been processed. |
430 | 0 | MOZ_ASSERT(CompositorLoop()); |
431 | 0 | CompositorLoop()->PostTask(NewRunnableFunction("AddCompositorRunnable", |
432 | 0 | &AddCompositor, |
433 | 0 | this, &mCompositorBridgeID)); |
434 | 0 |
|
435 | 0 |
|
436 | 0 | { // scope lock |
437 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
438 | 0 | sIndirectLayerTrees[mRootLayerTreeID].mParent = this; |
439 | 0 | } |
440 | 0 |
|
441 | 0 | LayerScope::SetPixelScale(mScale.scale); |
442 | 0 |
|
443 | 0 | if (!mOptions.UseWebRender()) { |
444 | 0 | mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget); |
445 | 0 | } |
446 | 0 | } |
447 | | |
448 | | LayersId |
449 | | CompositorBridgeParent::RootLayerTreeId() |
450 | 0 | { |
451 | 0 | MOZ_ASSERT(mRootLayerTreeID.IsValid()); |
452 | 0 | return mRootLayerTreeID; |
453 | 0 | } |
454 | | |
455 | | CompositorBridgeParent::~CompositorBridgeParent() |
456 | 0 | { |
457 | 0 | InfallibleTArray<PTextureParent*> textures; |
458 | 0 | ManagedPTextureParent(textures); |
459 | 0 | // We expect all textures to be destroyed by now. |
460 | 0 | MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0); |
461 | 0 | for (unsigned int i = 0; i < textures.Length(); ++i) { |
462 | 0 | RefPtr<TextureHost> tex = TextureHost::AsTextureHost(textures[i]); |
463 | 0 | tex->DeallocateDeviceData(); |
464 | 0 | } |
465 | 0 | } |
466 | | |
467 | | void |
468 | | CompositorBridgeParent::ForceIsFirstPaint() |
469 | 0 | { |
470 | 0 | mCompositionManager->ForceIsFirstPaint(); |
471 | 0 | } |
472 | | |
473 | | void |
474 | | CompositorBridgeParent::StopAndClearResources() |
475 | 0 | { |
476 | 0 | if (mForceCompositionTask) { |
477 | 0 | mForceCompositionTask->Cancel(); |
478 | 0 | mForceCompositionTask = nullptr; |
479 | 0 | } |
480 | 0 |
|
481 | 0 | mPaused = true; |
482 | 0 |
|
483 | 0 | // We need to clear the APZ tree before we destroy the WebRender API below, |
484 | 0 | // because in the case of async scene building that will shut down the updater |
485 | 0 | // thread and we need to run the task before that happens. |
486 | 0 | MOZ_ASSERT((mApzSampler != nullptr) == (mApzcTreeManager != nullptr)); |
487 | 0 | MOZ_ASSERT((mApzUpdater != nullptr) == (mApzcTreeManager != nullptr)); |
488 | 0 | if (mApzUpdater) { |
489 | 0 | mApzSampler = nullptr; |
490 | 0 | mApzUpdater->ClearTree(mRootLayerTreeID); |
491 | 0 | mApzUpdater = nullptr; |
492 | 0 | mApzcTreeManager = nullptr; |
493 | 0 | } |
494 | 0 |
|
495 | 0 | // Ensure that the layer manager is destroyed before CompositorBridgeChild. |
496 | 0 | if (mLayerManager) { |
497 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
498 | 0 | ForEachIndirectLayerTree([this] (LayerTreeState* lts, LayersId) -> void { |
499 | 0 | mLayerManager->ClearCachedResources(lts->mRoot); |
500 | 0 | lts->mLayerManager = nullptr; |
501 | 0 | lts->mParent = nullptr; |
502 | 0 | }); |
503 | 0 | mLayerManager->Destroy(); |
504 | 0 | mLayerManager = nullptr; |
505 | 0 | mCompositionManager = nullptr; |
506 | 0 | } |
507 | 0 |
|
508 | 0 | if (mWrBridge) { |
509 | 0 | // Ensure we are not holding the sIndirectLayerTreesLock when destroying |
510 | 0 | // the WebRenderBridgeParent instances because it may block on WR. |
511 | 0 | std::vector<RefPtr<WebRenderBridgeParent>> indirectBridgeParents; |
512 | 0 | { // scope lock |
513 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
514 | 0 | ForEachIndirectLayerTree([&] (LayerTreeState* lts, LayersId) -> void { |
515 | 0 | if (lts->mWrBridge) { |
516 | 0 | indirectBridgeParents.emplace_back(lts->mWrBridge.forget()); |
517 | 0 | } |
518 | 0 | lts->mParent = nullptr; |
519 | 0 | }); |
520 | 0 | } |
521 | 0 | for (const RefPtr<WebRenderBridgeParent>& bridge : indirectBridgeParents) { |
522 | 0 | bridge->Destroy(); |
523 | 0 | } |
524 | 0 | indirectBridgeParents.clear(); |
525 | 0 |
|
526 | 0 | // Ensure we are not holding the sIndirectLayerTreesLock here because we |
527 | 0 | // are going to block on WR threads in order to shut it down properly. |
528 | 0 | mWrBridge->Destroy(); |
529 | 0 | mWrBridge = nullptr; |
530 | 0 | if (mAsyncImageManager) { |
531 | 0 | mAsyncImageManager->Destroy(); |
532 | 0 | // WebRenderAPI should be already destructed |
533 | 0 | mAsyncImageManager = nullptr; |
534 | 0 | } |
535 | 0 | } |
536 | 0 |
|
537 | 0 | if (mCompositor) { |
538 | 0 | mCompositor->DetachWidget(); |
539 | 0 | mCompositor->Destroy(); |
540 | 0 | mCompositor = nullptr; |
541 | 0 | } |
542 | 0 |
|
543 | 0 | // This must be destroyed now since it accesses the widget. |
544 | 0 | if (mCompositorScheduler) { |
545 | 0 | mCompositorScheduler->Destroy(); |
546 | 0 | mCompositorScheduler = nullptr; |
547 | 0 | } |
548 | 0 |
|
549 | 0 | // After this point, it is no longer legal to access the widget. |
550 | 0 | mWidget = nullptr; |
551 | 0 |
|
552 | 0 | // Clear mAnimationStorage here to ensure that the compositor thread |
553 | 0 | // still exists when we destroy it. |
554 | 0 | mAnimationStorage = nullptr; |
555 | 0 | } |
556 | | |
557 | | mozilla::ipc::IPCResult |
558 | | CompositorBridgeParent::RecvWillClose() |
559 | 0 | { |
560 | 0 | StopAndClearResources(); |
561 | 0 | // Once we get the WillClose message, the client side is going to go away |
562 | 0 | // soon and we can't be guaranteed that sending messages will work. |
563 | 0 | mCanSend = false; |
564 | 0 | return IPC_OK(); |
565 | 0 | } |
566 | | |
567 | | void CompositorBridgeParent::DeferredDestroy() |
568 | 0 | { |
569 | 0 | MOZ_ASSERT(!NS_IsMainThread()); |
570 | 0 | mSelfRef = nullptr; |
571 | 0 | } |
572 | | |
573 | | mozilla::ipc::IPCResult |
574 | | CompositorBridgeParent::RecvPause() |
575 | 0 | { |
576 | 0 | PauseComposition(); |
577 | 0 | return IPC_OK(); |
578 | 0 | } |
579 | | |
580 | | mozilla::ipc::IPCResult |
581 | | CompositorBridgeParent::RecvResume() |
582 | 0 | { |
583 | 0 | ResumeComposition(); |
584 | 0 | return IPC_OK(); |
585 | 0 | } |
586 | | |
587 | | mozilla::ipc::IPCResult |
588 | | CompositorBridgeParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot, |
589 | | const gfx::IntRect& aRect) |
590 | 0 | { |
591 | 0 | RefPtr<DrawTarget> target = GetDrawTargetForDescriptor(aInSnapshot, gfx::BackendType::CAIRO); |
592 | 0 | MOZ_ASSERT(target); |
593 | 0 | if (!target) { |
594 | 0 | // We kill the content process rather than have it continue with an invalid |
595 | 0 | // snapshot, that may be too harsh and we could decide to return some sort |
596 | 0 | // of error to the child process and let it deal with it... |
597 | 0 | return IPC_FAIL_NO_REASON(this); |
598 | 0 | } |
599 | 0 | ForceComposeToTarget(target, &aRect); |
600 | 0 | return IPC_OK(); |
601 | 0 | } |
602 | | |
603 | | mozilla::ipc::IPCResult |
604 | | CompositorBridgeParent::RecvWaitOnTransactionProcessed() |
605 | 0 | { |
606 | 0 | return IPC_OK(); |
607 | 0 | } |
608 | | |
609 | | mozilla::ipc::IPCResult |
610 | | CompositorBridgeParent::RecvFlushRendering() |
611 | 0 | { |
612 | 0 | if (mWrBridge) { |
613 | 0 | mWrBridge->FlushRendering(); |
614 | 0 | return IPC_OK(); |
615 | 0 | } |
616 | 0 |
|
617 | 0 | if (mCompositorScheduler->NeedsComposite()) { |
618 | 0 | CancelCurrentCompositeTask(); |
619 | 0 | ForceComposeToTarget(nullptr); |
620 | 0 | } |
621 | 0 | return IPC_OK(); |
622 | 0 | } |
623 | | |
624 | | mozilla::ipc::IPCResult |
625 | | CompositorBridgeParent::RecvFlushRenderingAsync() |
626 | 0 | { |
627 | 0 | if (mWrBridge) { |
628 | 0 | mWrBridge->FlushRendering(false); |
629 | 0 | return IPC_OK(); |
630 | 0 | } |
631 | 0 |
|
632 | 0 | return RecvFlushRendering(); |
633 | 0 | } |
634 | | |
635 | | mozilla::ipc::IPCResult |
636 | | CompositorBridgeParent::RecvForcePresent() |
637 | 0 | { |
638 | 0 | if (mWrBridge) { |
639 | 0 | mWrBridge->ScheduleGenerateFrame(); |
640 | 0 | } |
641 | 0 | // During the shutdown sequence mLayerManager may be null |
642 | 0 | if (mLayerManager) { |
643 | 0 | mLayerManager->ForcePresent(); |
644 | 0 | } |
645 | 0 | return IPC_OK(); |
646 | 0 | } |
647 | | |
648 | | mozilla::ipc::IPCResult |
649 | | CompositorBridgeParent::RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) |
650 | 0 | { |
651 | 0 | if (mLayerManager) { |
652 | 0 | mLayerManager->AddInvalidRegion(aRegion); |
653 | 0 | } |
654 | 0 | return IPC_OK(); |
655 | 0 | } |
656 | | |
657 | | void |
658 | | CompositorBridgeParent::Invalidate() |
659 | 0 | { |
660 | 0 | if (mLayerManager) { |
661 | 0 | mLayerManager->InvalidateAll(); |
662 | 0 | } |
663 | 0 | } |
664 | | |
665 | | mozilla::ipc::IPCResult |
666 | | CompositorBridgeParent::RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) |
667 | 0 | { |
668 | 0 | if (mLayerManager) { |
669 | 0 | *aOutStartIndex = mLayerManager->StartFrameTimeRecording(aBufferSize); |
670 | 0 | } else if (mWrBridge) { |
671 | 0 | *aOutStartIndex = mWrBridge->StartFrameTimeRecording(aBufferSize); |
672 | 0 | } else { |
673 | 0 | *aOutStartIndex = 0; |
674 | 0 | } |
675 | 0 | return IPC_OK(); |
676 | 0 | } |
677 | | |
678 | | mozilla::ipc::IPCResult |
679 | | CompositorBridgeParent::RecvStopFrameTimeRecording(const uint32_t& aStartIndex, |
680 | | InfallibleTArray<float>* intervals) |
681 | 0 | { |
682 | 0 | if (mLayerManager) { |
683 | 0 | mLayerManager->StopFrameTimeRecording(aStartIndex, *intervals); |
684 | 0 | } else if (mWrBridge) { |
685 | 0 | mWrBridge->StopFrameTimeRecording(aStartIndex, *intervals); |
686 | 0 | } |
687 | 0 | return IPC_OK(); |
688 | 0 | } |
689 | | |
690 | | void |
691 | | CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) |
692 | 0 | { |
693 | 0 | mCanSend = false; |
694 | 0 |
|
695 | 0 | StopAndClearResources(); |
696 | 0 |
|
697 | 0 | RemoveCompositor(mCompositorBridgeID); |
698 | 0 |
|
699 | 0 | mCompositionManager = nullptr; |
700 | 0 |
|
701 | 0 | { // scope lock |
702 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
703 | 0 | sIndirectLayerTrees.erase(mRootLayerTreeID); |
704 | 0 | } |
705 | 0 |
|
706 | 0 | // There are chances that the ref count reaches zero on the main thread shortly |
707 | 0 | // after this function returns while some ipdl code still needs to run on |
708 | 0 | // this thread. |
709 | 0 | // We must keep the compositor parent alive untill the code handling message |
710 | 0 | // reception is finished on this thread. |
711 | 0 | mSelfRef = this; |
712 | 0 | MessageLoop::current()->PostTask( |
713 | 0 | NewRunnableMethod("layers::CompositorBridgeParent::DeferredDestroy", |
714 | 0 | this, |
715 | 0 | &CompositorBridgeParent::DeferredDestroy)); |
716 | 0 | } |
717 | | |
718 | | void |
719 | | CompositorBridgeParent::ScheduleRenderOnCompositorThread() |
720 | 0 | { |
721 | 0 | MOZ_ASSERT(CompositorLoop()); |
722 | 0 | CompositorLoop()->PostTask( |
723 | 0 | NewRunnableMethod("layers::CompositorBridgeParent::ScheduleComposition", |
724 | 0 | this, |
725 | 0 | &CompositorBridgeParent::ScheduleComposition)); |
726 | 0 | } |
727 | | |
728 | | void |
729 | | CompositorBridgeParent::InvalidateOnCompositorThread() |
730 | 0 | { |
731 | 0 | MOZ_ASSERT(CompositorLoop()); |
732 | 0 | CompositorLoop()->PostTask( |
733 | 0 | NewRunnableMethod("layers::CompositorBridgeParent::Invalidate", |
734 | 0 | this, |
735 | 0 | &CompositorBridgeParent::Invalidate)); |
736 | 0 | } |
737 | | |
738 | | void |
739 | | CompositorBridgeParent::PauseComposition() |
740 | 0 | { |
741 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(), |
742 | 0 | "PauseComposition() can only be called on the compositor thread"); |
743 | 0 |
|
744 | 0 | MonitorAutoLock lock(mPauseCompositionMonitor); |
745 | 0 |
|
746 | 0 | if (!mPaused) { |
747 | 0 | mPaused = true; |
748 | 0 |
|
749 | 0 | if (mCompositor) { |
750 | 0 | mCompositor->Pause(); |
751 | 0 | } else if (mWrBridge) { |
752 | 0 | mWrBridge->Pause(); |
753 | 0 | } |
754 | 0 | TimeStamp now = TimeStamp::Now(); |
755 | 0 | DidComposite(now, now); |
756 | 0 | } |
757 | 0 |
|
758 | 0 | // if anyone's waiting to make sure that composition really got paused, tell them |
759 | 0 | lock.NotifyAll(); |
760 | 0 | } |
761 | | |
762 | | void |
763 | | CompositorBridgeParent::ResumeComposition() |
764 | 0 | { |
765 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(), |
766 | 0 | "ResumeComposition() can only be called on the compositor thread"); |
767 | 0 |
|
768 | 0 | MonitorAutoLock lock(mResumeCompositionMonitor); |
769 | 0 |
|
770 | 0 | bool resumed = mOptions.UseWebRender() ? mWrBridge->Resume() : mCompositor->Resume(); |
771 | 0 | if (!resumed) { |
772 | | #ifdef MOZ_WIDGET_ANDROID |
773 | | // We can't get a surface. This could be because the activity changed between |
774 | | // the time resume was scheduled and now. |
775 | | __android_log_print(ANDROID_LOG_INFO, "CompositorBridgeParent", "Unable to renew compositor surface; remaining in paused state"); |
776 | | #endif |
777 | | lock.NotifyAll(); |
778 | 0 | return; |
779 | 0 | } |
780 | 0 |
|
781 | 0 | mPaused = false; |
782 | 0 |
|
783 | 0 | Invalidate(); |
784 | 0 | mCompositorScheduler->ForceComposeToTarget(nullptr, nullptr); |
785 | 0 |
|
786 | 0 | // if anyone's waiting to make sure that composition really got resumed, tell them |
787 | 0 | lock.NotifyAll(); |
788 | 0 | } |
789 | | |
790 | | void |
791 | | CompositorBridgeParent::ForceComposition() |
792 | 0 | { |
793 | 0 | // Cancel the orientation changed state to force composition |
794 | 0 | mForceCompositionTask = nullptr; |
795 | 0 | ScheduleRenderOnCompositorThread(); |
796 | 0 | } |
797 | | |
798 | | void |
799 | | CompositorBridgeParent::CancelCurrentCompositeTask() |
800 | 0 | { |
801 | 0 | mCompositorScheduler->CancelCurrentCompositeTask(); |
802 | 0 | } |
803 | | |
804 | | void |
805 | | CompositorBridgeParent::SetEGLSurfaceSize(int width, int height) |
806 | 0 | { |
807 | 0 | NS_ASSERTION(mUseExternalSurfaceSize, "Compositor created without UseExternalSurfaceSize provided"); |
808 | 0 | mEGLSurfaceSize.SizeTo(width, height); |
809 | 0 | if (mCompositor) { |
810 | 0 | mCompositor->SetDestinationSurfaceSize(gfx::IntSize(mEGLSurfaceSize.width, mEGLSurfaceSize.height)); |
811 | 0 | } |
812 | 0 | } |
813 | | |
814 | | void |
815 | | CompositorBridgeParent::ResumeCompositionAndResize(int width, int height) |
816 | 0 | { |
817 | 0 | SetEGLSurfaceSize(width, height); |
818 | 0 | ResumeComposition(); |
819 | 0 | } |
820 | | |
821 | | /* |
822 | | * This will execute a pause synchronously, waiting to make sure that the compositor |
823 | | * really is paused. |
824 | | */ |
825 | | void |
826 | | CompositorBridgeParent::SchedulePauseOnCompositorThread() |
827 | 0 | { |
828 | 0 | MonitorAutoLock lock(mPauseCompositionMonitor); |
829 | 0 |
|
830 | 0 | MOZ_ASSERT(CompositorLoop()); |
831 | 0 | CompositorLoop()->PostTask( |
832 | 0 | NewRunnableMethod("layers::CompositorBridgeParent::PauseComposition", |
833 | 0 | this, |
834 | 0 | &CompositorBridgeParent::PauseComposition)); |
835 | 0 |
|
836 | 0 | // Wait until the pause has actually been processed by the compositor thread |
837 | 0 | lock.Wait(); |
838 | 0 | } |
839 | | |
840 | | bool |
841 | | CompositorBridgeParent::ScheduleResumeOnCompositorThread() |
842 | 0 | { |
843 | 0 | MonitorAutoLock lock(mResumeCompositionMonitor); |
844 | 0 |
|
845 | 0 | MOZ_ASSERT(CompositorLoop()); |
846 | 0 | CompositorLoop()->PostTask( |
847 | 0 | NewRunnableMethod("layers::CompositorBridgeParent::ResumeComposition", |
848 | 0 | this, |
849 | 0 | &CompositorBridgeParent::ResumeComposition)); |
850 | 0 |
|
851 | 0 | // Wait until the resume has actually been processed by the compositor thread |
852 | 0 | lock.Wait(); |
853 | 0 |
|
854 | 0 | return !mPaused; |
855 | 0 | } |
856 | | |
857 | | bool |
858 | | CompositorBridgeParent::ScheduleResumeOnCompositorThread(int width, int height) |
859 | 0 | { |
860 | 0 | MonitorAutoLock lock(mResumeCompositionMonitor); |
861 | 0 |
|
862 | 0 | MOZ_ASSERT(CompositorLoop()); |
863 | 0 | CompositorLoop()->PostTask(NewRunnableMethod<int, int>( |
864 | 0 | "layers::CompositorBridgeParent::ResumeCompositionAndResize", |
865 | 0 | this, |
866 | 0 | &CompositorBridgeParent::ResumeCompositionAndResize, |
867 | 0 | width, |
868 | 0 | height)); |
869 | 0 |
|
870 | 0 | // Wait until the resume has actually been processed by the compositor thread |
871 | 0 | lock.Wait(); |
872 | 0 |
|
873 | 0 | return !mPaused; |
874 | 0 | } |
875 | | |
876 | | void |
877 | | CompositorBridgeParent::ScheduleTask(already_AddRefed<CancelableRunnable> task, int time) |
878 | 0 | { |
879 | 0 | if (time == 0) { |
880 | 0 | MessageLoop::current()->PostTask(std::move(task)); |
881 | 0 | } else { |
882 | 0 | MessageLoop::current()->PostDelayedTask(std::move(task), time); |
883 | 0 | } |
884 | 0 | } |
885 | | |
886 | | void |
887 | | CompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree, |
888 | | const TimeDuration& aPaintTime) |
889 | 0 | { |
890 | 0 | // We get a lot of paint timings for things with empty transactions. |
891 | 0 | if (!mLayerManager || aPaintTime.ToMilliseconds() < 1.0) { |
892 | 0 | return; |
893 | 0 | } |
894 | 0 | |
895 | 0 | mLayerManager->SetPaintTime(aPaintTime); |
896 | 0 | } |
897 | | |
898 | | void |
899 | | CompositorBridgeParent::NotifyShadowTreeTransaction(LayersId aId, bool aIsFirstPaint, |
900 | | const FocusTarget& aFocusTarget, |
901 | | bool aScheduleComposite, uint32_t aPaintSequenceNumber, |
902 | | bool aIsRepeatTransaction, bool aHitTestUpdate) |
903 | 0 | { |
904 | 0 | if (!aIsRepeatTransaction && |
905 | 0 | mLayerManager && |
906 | 0 | mLayerManager->GetRoot()) { |
907 | 0 | // Process plugin data here to give time for them to update before the next |
908 | 0 | // composition. |
909 | 0 | bool pluginsUpdatedFlag = true; |
910 | 0 | AutoResolveRefLayers resolve(mCompositionManager, this, nullptr, |
911 | 0 | &pluginsUpdatedFlag); |
912 | 0 |
|
913 | 0 | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
914 | 0 | // If plugins haven't been updated, stop waiting. |
915 | 0 | if (!pluginsUpdatedFlag) { |
916 | 0 | mWaitForPluginsUntil = TimeStamp(); |
917 | 0 | mHaveBlockedForPlugins = false; |
918 | 0 | } |
919 | 0 | #endif |
920 | 0 |
|
921 | 0 | if (mApzUpdater) { |
922 | 0 | mApzUpdater->UpdateFocusState(mRootLayerTreeID, aId, aFocusTarget); |
923 | 0 | if (aHitTestUpdate) { |
924 | 0 | mApzUpdater->UpdateHitTestingTree(mRootLayerTreeID, |
925 | 0 | mLayerManager->GetRoot(), aIsFirstPaint, aId, aPaintSequenceNumber); |
926 | 0 | } |
927 | 0 | } |
928 | 0 |
|
929 | 0 | mLayerManager->NotifyShadowTreeTransaction(); |
930 | 0 | } |
931 | 0 | if (aScheduleComposite) { |
932 | 0 | ScheduleComposition(); |
933 | 0 | } |
934 | 0 | } |
935 | | |
936 | | void |
937 | | CompositorBridgeParent::ScheduleComposition() |
938 | 0 | { |
939 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
940 | 0 | if (mPaused) { |
941 | 0 | return; |
942 | 0 | } |
943 | 0 | |
944 | 0 | if (mWrBridge) { |
945 | 0 | mWrBridge->ScheduleGenerateFrame(); |
946 | 0 | } else { |
947 | 0 | mCompositorScheduler->ScheduleComposition(); |
948 | 0 | } |
949 | 0 | } |
950 | | |
951 | | // Go down the composite layer tree, setting properties to match their |
952 | | // content-side counterparts. |
953 | | /* static */ void |
954 | | CompositorBridgeParent::SetShadowProperties(Layer* aLayer) |
955 | 0 | { |
956 | 0 | ForEachNode<ForwardIterator>( |
957 | 0 | aLayer, |
958 | 0 | [] (Layer *layer) |
959 | 0 | { |
960 | 0 | if (Layer* maskLayer = layer->GetMaskLayer()) { |
961 | 0 | SetShadowProperties(maskLayer); |
962 | 0 | } |
963 | 0 | for (size_t i = 0; i < layer->GetAncestorMaskLayerCount(); i++) { |
964 | 0 | SetShadowProperties(layer->GetAncestorMaskLayerAt(i)); |
965 | 0 | } |
966 | 0 |
|
967 | 0 | // FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate. |
968 | 0 | HostLayer* layerCompositor = layer->AsHostLayer(); |
969 | 0 | // Set the layerComposite's base transform to the layer's base transform. |
970 | 0 | AnimationArray& animations = layer->GetAnimations(); |
971 | 0 | // If there is any animation, the animation value will override |
972 | 0 | // non-animated value later, so we don't need to set the non-animated |
973 | 0 | // value here. |
974 | 0 | if (animations.IsEmpty()) { |
975 | 0 | layerCompositor->SetShadowBaseTransform(layer->GetBaseTransform()); |
976 | 0 | layerCompositor->SetShadowTransformSetByAnimation(false); |
977 | 0 | layerCompositor->SetShadowOpacity(layer->GetOpacity()); |
978 | 0 | layerCompositor->SetShadowOpacitySetByAnimation(false); |
979 | 0 | } |
980 | 0 | layerCompositor->SetShadowVisibleRegion(layer->GetVisibleRegion()); |
981 | 0 | layerCompositor->SetShadowClipRect(layer->GetClipRect()); |
982 | 0 | } |
983 | 0 | ); |
984 | 0 | } |
985 | | |
986 | | void |
987 | | CompositorBridgeParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRect) |
988 | 0 | { |
989 | 0 | AUTO_PROFILER_TRACING("Paint", "Composite"); |
990 | 0 | AUTO_PROFILER_LABEL("CompositorBridgeParent::CompositeToTarget", GRAPHICS); |
991 | 0 |
|
992 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(), |
993 | 0 | "Composite can only be called on the compositor thread"); |
994 | 0 | TimeStamp start = TimeStamp::Now(); |
995 | 0 |
|
996 | 0 | if (!CanComposite()) { |
997 | 0 | TimeStamp end = TimeStamp::Now(); |
998 | 0 | DidComposite(start, end); |
999 | 0 | return; |
1000 | 0 | } |
1001 | 0 | |
1002 | 0 | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
1003 | 0 | if (!mWaitForPluginsUntil.IsNull() && |
1004 | 0 | mWaitForPluginsUntil > start) { |
1005 | 0 | mHaveBlockedForPlugins = true; |
1006 | 0 | ScheduleComposition(); |
1007 | 0 | return; |
1008 | 0 | } |
1009 | 0 | #endif |
1010 | 0 | |
1011 | 0 | /* |
1012 | 0 | * AutoResolveRefLayers handles two tasks related to Windows and Linux |
1013 | 0 | * plugin window management: |
1014 | 0 | * 1) calculating if we have remote content in the view. If we do not have |
1015 | 0 | * remote content, all plugin windows for this CompositorBridgeParent (window) |
1016 | 0 | * can be hidden since we do not support plugins in chrome when running |
1017 | 0 | * under e10s. |
1018 | 0 | * 2) Updating plugin position, size, and clip. We do this here while the |
1019 | 0 | * remote layer tree is hooked up to to chrome layer tree. This is needed |
1020 | 0 | * since plugin clipping can depend on chrome (for example, due to tab modal |
1021 | 0 | * prompts). Updates in step 2 are applied via an async ipc message sent |
1022 | 0 | * to the main thread. |
1023 | 0 | */ |
1024 | 0 | bool hasRemoteContent = false; |
1025 | 0 | bool updatePluginsFlag = true; |
1026 | 0 | AutoResolveRefLayers resolve(mCompositionManager, this, |
1027 | 0 | &hasRemoteContent, |
1028 | 0 | &updatePluginsFlag); |
1029 | 0 |
|
1030 | 0 | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
1031 | 0 | // We do not support plugins in local content. When switching tabs |
1032 | 0 | // to local pages, hide every plugin associated with the window. |
1033 | 0 | if (!hasRemoteContent && gfxVars::BrowserTabsRemoteAutostart() && |
1034 | 0 | mCachedPluginData.Length()) { |
1035 | 0 | Unused << SendHideAllPlugins(GetWidget()->GetWidgetKey()); |
1036 | 0 | mCachedPluginData.Clear(); |
1037 | 0 | } |
1038 | 0 | #endif |
1039 | 0 |
|
1040 | 0 | if (aTarget) { |
1041 | 0 | mLayerManager->BeginTransactionWithDrawTarget(aTarget, *aRect); |
1042 | 0 | } else { |
1043 | 0 | mLayerManager->BeginTransaction(); |
1044 | 0 | } |
1045 | 0 |
|
1046 | 0 | SetShadowProperties(mLayerManager->GetRoot()); |
1047 | 0 |
|
1048 | 0 | if (mForceCompositionTask && !mOverrideComposeReadiness) { |
1049 | 0 | if (mCompositionManager->ReadyForCompose()) { |
1050 | 0 | mForceCompositionTask->Cancel(); |
1051 | 0 | mForceCompositionTask = nullptr; |
1052 | 0 | } else { |
1053 | 0 | return; |
1054 | 0 | } |
1055 | 0 | } |
1056 | 0 | |
1057 | 0 | mCompositionManager->ComputeRotation(); |
1058 | 0 |
|
1059 | 0 | TimeStamp time = mTestTime.valueOr(mCompositorScheduler->GetLastComposeTime()); |
1060 | 0 | bool requestNextFrame = mCompositionManager->TransformShadowTree(time, mVsyncRate); |
1061 | 0 |
|
1062 | 0 | // Don't eagerly schedule new compositions here when recording or replaying. |
1063 | 0 | // Recording/replaying processes schedule composites at the top of the main |
1064 | 0 | // thread's event loop rather than via PVsync, which can cause the composites |
1065 | 0 | // scheduled here to pile up without any drawing actually happening. |
1066 | 0 | if (requestNextFrame && !recordreplay::IsRecordingOrReplaying()) { |
1067 | 0 | ScheduleComposition(); |
1068 | 0 | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
1069 | 0 | // If we have visible windowed plugins then we need to wait for content (and |
1070 | 0 | // then the plugins) to have been updated by the active animation. |
1071 | 0 | if (!mPluginWindowsHidden && mCachedPluginData.Length()) { |
1072 | 0 | mWaitForPluginsUntil = mCompositorScheduler->GetLastComposeTime() + (mVsyncRate * 2); |
1073 | 0 | } |
1074 | 0 | #endif |
1075 | 0 | } |
1076 | 0 |
|
1077 | 0 | RenderTraceLayers(mLayerManager->GetRoot(), "0000"); |
1078 | 0 |
|
1079 | | #ifdef MOZ_DUMP_PAINTING |
1080 | | if (gfxPrefs::DumpHostLayers()) { |
1081 | | printf_stderr("Painting --- compositing layer tree:\n"); |
1082 | | mLayerManager->Dump(/* aSorted = */ true); |
1083 | | } |
1084 | | #endif |
1085 | | mLayerManager->SetDebugOverlayWantsNextFrame(false); |
1086 | 0 | mLayerManager->EndTransaction(time); |
1087 | 0 |
|
1088 | 0 | if (!aTarget) { |
1089 | 0 | TimeStamp end = TimeStamp::Now(); |
1090 | 0 | DidComposite(start, end); |
1091 | 0 | } |
1092 | 0 |
|
1093 | 0 | // We're not really taking advantage of the stored composite-again-time here. |
1094 | 0 | // We might be able to skip the next few composites altogether. However, |
1095 | 0 | // that's a bit complex to implement and we'll get most of the advantage |
1096 | 0 | // by skipping compositing when we detect there's nothing invalid. This is why |
1097 | 0 | // we do "composite until" rather than "composite again at". |
1098 | 0 | // |
1099 | 0 | // TODO(bug 1328602) Figure out what we should do here with the render thread. |
1100 | 0 | if (!mLayerManager->GetCompositeUntilTime().IsNull() || |
1101 | 0 | mLayerManager->DebugOverlayWantsNextFrame()) |
1102 | 0 | { |
1103 | 0 | ScheduleComposition(); |
1104 | 0 | } |
1105 | 0 |
|
1106 | | #ifdef COMPOSITOR_PERFORMANCE_WARNING |
1107 | | TimeDuration executionTime = TimeStamp::Now() - mCompositorScheduler->GetLastComposeTime(); |
1108 | | TimeDuration frameBudget = TimeDuration::FromMilliseconds(15); |
1109 | | int32_t frameRate = CalculateCompositionFrameRate(); |
1110 | | if (frameRate > 0) { |
1111 | | frameBudget = TimeDuration::FromSeconds(1.0 / frameRate); |
1112 | | } |
1113 | | if (executionTime > frameBudget) { |
1114 | | printf_stderr("Compositor: Composite execution took %4.1f ms\n", |
1115 | | executionTime.ToMilliseconds()); |
1116 | | } |
1117 | | #endif |
1118 | |
|
1119 | 0 | // 0 -> Full-tilt composite |
1120 | 0 | if (gfxPrefs::LayersCompositionFrameRate() == 0 || |
1121 | 0 | mLayerManager->AlwaysScheduleComposite()) |
1122 | 0 | { |
1123 | 0 | // Special full-tilt composite mode for performance testing |
1124 | 0 | ScheduleComposition(); |
1125 | 0 | } |
1126 | 0 |
|
1127 | 0 | // TODO(bug 1328602) Need an equivalent that works with the rende thread. |
1128 | 0 | mLayerManager->SetCompositionTime(TimeStamp()); |
1129 | 0 |
|
1130 | 0 | mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME, start); |
1131 | 0 | } |
1132 | | |
1133 | | mozilla::ipc::IPCResult |
1134 | | CompositorBridgeParent::RecvRemotePluginsReady() |
1135 | 0 | { |
1136 | 0 | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
1137 | 0 | mWaitForPluginsUntil = TimeStamp(); |
1138 | 0 | if (mHaveBlockedForPlugins) { |
1139 | 0 | mHaveBlockedForPlugins = false; |
1140 | 0 | ForceComposeToTarget(nullptr); |
1141 | 0 | } else { |
1142 | 0 | ScheduleComposition(); |
1143 | 0 | } |
1144 | 0 | return IPC_OK(); |
1145 | | #else |
1146 | | MOZ_ASSERT_UNREACHABLE("CompositorBridgeParent::RecvRemotePluginsReady calls " |
1147 | | "unexpected on this platform."); |
1148 | | return IPC_FAIL_NO_REASON(this); |
1149 | | #endif |
1150 | | } |
1151 | | |
1152 | | void |
1153 | | CompositorBridgeParent::ForceComposeToTarget(DrawTarget* aTarget, const gfx::IntRect* aRect) |
1154 | 0 | { |
1155 | 0 | AUTO_PROFILER_LABEL("CompositorBridgeParent::ForceComposeToTarget", GRAPHICS); |
1156 | 0 |
|
1157 | 0 | AutoRestore<bool> override(mOverrideComposeReadiness); |
1158 | 0 | mOverrideComposeReadiness = true; |
1159 | 0 | mCompositorScheduler->ForceComposeToTarget(aTarget, aRect); |
1160 | 0 | } |
1161 | | |
1162 | | PAPZCTreeManagerParent* |
1163 | | CompositorBridgeParent::AllocPAPZCTreeManagerParent(const LayersId& aLayersId) |
1164 | 0 | { |
1165 | 0 | // This should only ever get called in the GPU process. |
1166 | 0 | MOZ_ASSERT(XRE_IsGPUProcess()); |
1167 | 0 | // We should only ever get this if APZ is enabled in this compositor. |
1168 | 0 | MOZ_ASSERT(mOptions.UseAPZ()); |
1169 | 0 | // The mApzcTreeManager and mApzUpdater should have been created via RecvInitialize() |
1170 | 0 | MOZ_ASSERT(mApzcTreeManager); |
1171 | 0 | MOZ_ASSERT(mApzUpdater); |
1172 | 0 | // The main process should pass in 0 because we assume mRootLayerTreeID |
1173 | 0 | MOZ_ASSERT(!aLayersId.IsValid()); |
1174 | 0 |
|
1175 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1176 | 0 | CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID]; |
1177 | 0 | MOZ_ASSERT(state.mParent.get() == this); |
1178 | 0 | MOZ_ASSERT(!state.mApzcTreeManagerParent); |
1179 | 0 | state.mApzcTreeManagerParent = new APZCTreeManagerParent(mRootLayerTreeID, mApzcTreeManager, mApzUpdater); |
1180 | 0 |
|
1181 | 0 | return state.mApzcTreeManagerParent; |
1182 | 0 | } |
1183 | | |
1184 | | bool |
1185 | | CompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) |
1186 | 0 | { |
1187 | 0 | delete aActor; |
1188 | 0 | return true; |
1189 | 0 | } |
1190 | | |
1191 | | void |
1192 | | CompositorBridgeParent::AllocateAPZCTreeManagerParent(const MonitorAutoLock& aProofOfLayerTreeStateLock, |
1193 | | const LayersId& aLayersId, |
1194 | | LayerTreeState& aState) |
1195 | 0 | { |
1196 | 0 | MOZ_ASSERT(aState.mParent == this); |
1197 | 0 | MOZ_ASSERT(mApzcTreeManager); |
1198 | 0 | MOZ_ASSERT(mApzUpdater); |
1199 | 0 | MOZ_ASSERT(!aState.mApzcTreeManagerParent); |
1200 | 0 | aState.mApzcTreeManagerParent = new APZCTreeManagerParent(aLayersId, mApzcTreeManager, mApzUpdater); |
1201 | 0 | } |
1202 | | |
1203 | | PAPZParent* |
1204 | | CompositorBridgeParent::AllocPAPZParent(const LayersId& aLayersId) |
1205 | 0 | { |
1206 | 0 | // The main process should pass in 0 because we assume mRootLayerTreeID |
1207 | 0 | MOZ_ASSERT(!aLayersId.IsValid()); |
1208 | 0 |
|
1209 | 0 | RemoteContentController* controller = new RemoteContentController(); |
1210 | 0 |
|
1211 | 0 | // Increment the controller's refcount before we return it. This will keep the |
1212 | 0 | // controller alive until it is released by IPDL in DeallocPAPZParent. |
1213 | 0 | controller->AddRef(); |
1214 | 0 |
|
1215 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1216 | 0 | CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID]; |
1217 | 0 | MOZ_ASSERT(!state.mController); |
1218 | 0 | state.mController = controller; |
1219 | 0 |
|
1220 | 0 | return controller; |
1221 | 0 | } |
1222 | | |
1223 | | bool |
1224 | | CompositorBridgeParent::DeallocPAPZParent(PAPZParent* aActor) |
1225 | 0 | { |
1226 | 0 | RemoteContentController* controller = static_cast<RemoteContentController*>(aActor); |
1227 | 0 | controller->Release(); |
1228 | 0 | return true; |
1229 | 0 | } |
1230 | | |
1231 | | #if defined(MOZ_WIDGET_ANDROID) |
1232 | | AndroidDynamicToolbarAnimator* |
1233 | | CompositorBridgeParent::GetAndroidDynamicToolbarAnimator() |
1234 | | { |
1235 | | return mApzcTreeManager ? mApzcTreeManager->GetAndroidDynamicToolbarAnimator() : nullptr; |
1236 | | } |
1237 | | #endif |
1238 | | |
1239 | | RefPtr<APZSampler> |
1240 | | CompositorBridgeParent::GetAPZSampler() |
1241 | 0 | { |
1242 | 0 | return mApzSampler; |
1243 | 0 | } |
1244 | | |
1245 | | RefPtr<APZUpdater> |
1246 | | CompositorBridgeParent::GetAPZUpdater() |
1247 | 0 | { |
1248 | 0 | return mApzUpdater; |
1249 | 0 | } |
1250 | | |
1251 | | CompositorBridgeParent* |
1252 | | CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(const LayersId& aLayersId) |
1253 | 0 | { |
1254 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1255 | 0 | return sIndirectLayerTrees[aLayersId].mParent; |
1256 | 0 | } |
1257 | | |
1258 | | /*static*/ RefPtr<CompositorBridgeParent> |
1259 | | CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(const wr::WindowId& aWindowId) |
1260 | 0 | { |
1261 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1262 | 0 | for (auto it = sIndirectLayerTrees.begin(); it != sIndirectLayerTrees.end(); it++) { |
1263 | 0 | LayerTreeState* state = &it->second; |
1264 | 0 | if (!state->mWrBridge) { |
1265 | 0 | continue; |
1266 | 0 | } |
1267 | 0 | // state->mWrBridge might be a root WebRenderBridgeParent or one of a content |
1268 | 0 | // process, but in either case the state->mParent will be the same. So we |
1269 | 0 | // don't need to distinguish between the two. |
1270 | 0 | if (RefPtr<wr::WebRenderAPI> api = state->mWrBridge->GetWebRenderAPI()) { |
1271 | 0 | if (api->GetId() == aWindowId) { |
1272 | 0 | return state->mParent; |
1273 | 0 | } |
1274 | 0 | } |
1275 | 0 | } |
1276 | 0 | return nullptr; |
1277 | 0 | } |
1278 | | |
1279 | | bool |
1280 | | CompositorBridgeParent::CanComposite() |
1281 | 0 | { |
1282 | 0 | return mLayerManager && |
1283 | 0 | mLayerManager->GetRoot() && |
1284 | 0 | !mPaused; |
1285 | 0 | } |
1286 | | |
1287 | | void |
1288 | | CompositorBridgeParent::ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig, |
1289 | | bool aIsFirstPaint) |
1290 | 0 | { |
1291 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
1292 | 0 |
|
1293 | 0 | if (!aIsFirstPaint && |
1294 | 0 | !mCompositionManager->IsFirstPaint() && |
1295 | 0 | mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) { |
1296 | 0 | if (mForceCompositionTask != nullptr) { |
1297 | 0 | mForceCompositionTask->Cancel(); |
1298 | 0 | } |
1299 | 0 | RefPtr<CancelableRunnable> task = NewCancelableRunnableMethod( |
1300 | 0 | "layers::CompositorBridgeParent::ForceComposition", |
1301 | 0 | this, |
1302 | 0 | &CompositorBridgeParent::ForceComposition); |
1303 | 0 | mForceCompositionTask = task; |
1304 | 0 | ScheduleTask(task.forget(), gfxPrefs::OrientationSyncMillis()); |
1305 | 0 | } |
1306 | 0 | } |
1307 | | |
1308 | | void |
1309 | | CompositorBridgeParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, |
1310 | | const TransactionInfo& aInfo, |
1311 | | bool aHitTestUpdate) |
1312 | 0 | { |
1313 | 0 | const TargetConfig& targetConfig = aInfo.targetConfig(); |
1314 | 0 |
|
1315 | 0 | ScheduleRotationOnCompositorThread(targetConfig, aInfo.isFirstPaint()); |
1316 | 0 |
|
1317 | 0 | // Instruct the LayerManager to update its render bounds now. Since all the orientation |
1318 | 0 | // change, dimension change would be done at the stage, update the size here is free of |
1319 | 0 | // race condition. |
1320 | 0 | mLayerManager->UpdateRenderBounds(targetConfig.naturalBounds()); |
1321 | 0 | mLayerManager->SetRegionToClear(targetConfig.clearRegion()); |
1322 | 0 | if (mLayerManager->GetCompositor()) { |
1323 | 0 | mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation()); |
1324 | 0 | } |
1325 | 0 |
|
1326 | 0 | mCompositionManager->Updated(aInfo.isFirstPaint(), targetConfig); |
1327 | 0 | Layer* root = aLayerTree->GetRoot(); |
1328 | 0 | mLayerManager->SetRoot(root); |
1329 | 0 |
|
1330 | 0 | if (mApzUpdater && !aInfo.isRepeatTransaction()) { |
1331 | 0 | mApzUpdater->UpdateFocusState(mRootLayerTreeID, |
1332 | 0 | mRootLayerTreeID, |
1333 | 0 | aInfo.focusTarget()); |
1334 | 0 |
|
1335 | 0 | if (aHitTestUpdate) { |
1336 | 0 | AutoResolveRefLayers resolve(mCompositionManager); |
1337 | 0 |
|
1338 | 0 | mApzUpdater->UpdateHitTestingTree( |
1339 | 0 | mRootLayerTreeID, root, aInfo.isFirstPaint(), |
1340 | 0 | mRootLayerTreeID, aInfo.paintSequenceNumber()); |
1341 | 0 | } |
1342 | 0 | } |
1343 | 0 |
|
1344 | 0 | // The transaction ID might get reset to 1 if the page gets reloaded, see |
1345 | 0 | // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41 |
1346 | 0 | // Otherwise, it should be continually increasing. |
1347 | 0 | MOZ_ASSERT(aInfo.id() == TransactionId{1} || aInfo.id() > mPendingTransaction); |
1348 | 0 | mPendingTransaction = aInfo.id(); |
1349 | 0 | mRefreshStartTime = aInfo.refreshStart(); |
1350 | 0 | mTxnStartTime = aInfo.transactionStart(); |
1351 | 0 | mFwdTime = aInfo.fwdTime(); |
1352 | 0 |
|
1353 | 0 | if (root) { |
1354 | 0 | SetShadowProperties(root); |
1355 | 0 | } |
1356 | 0 | if (aInfo.scheduleComposite()) { |
1357 | 0 | ScheduleComposition(); |
1358 | 0 | if (mPaused) { |
1359 | 0 | TimeStamp now = TimeStamp::Now(); |
1360 | 0 | DidComposite(now, now); |
1361 | 0 | } |
1362 | 0 | } |
1363 | 0 | mLayerManager->NotifyShadowTreeTransaction(); |
1364 | 0 | } |
1365 | | |
1366 | | void |
1367 | | CompositorBridgeParent::ScheduleComposite(LayerTransactionParent* aLayerTree) |
1368 | 0 | { |
1369 | 0 | ScheduleComposition(); |
1370 | 0 | } |
1371 | | |
1372 | | bool |
1373 | | CompositorBridgeParent::SetTestSampleTime(const LayersId& aId, |
1374 | | const TimeStamp& aTime) |
1375 | 0 | { |
1376 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
1377 | 0 |
|
1378 | 0 | if (aTime.IsNull()) { |
1379 | 0 | return false; |
1380 | 0 | } |
1381 | 0 | |
1382 | 0 | mTestTime = Some(aTime); |
1383 | 0 |
|
1384 | 0 | if (mWrBridge) { |
1385 | 0 | mWrBridge->FlushRendering(); |
1386 | 0 | return true; |
1387 | 0 | } |
1388 | 0 | |
1389 | 0 | bool testComposite = mCompositionManager && |
1390 | 0 | mCompositorScheduler->NeedsComposite(); |
1391 | 0 |
|
1392 | 0 | // Update but only if we were already scheduled to animate |
1393 | 0 | if (testComposite) { |
1394 | 0 | AutoResolveRefLayers resolve(mCompositionManager); |
1395 | 0 | bool requestNextFrame = mCompositionManager->TransformShadowTree(aTime, mVsyncRate); |
1396 | 0 | if (!requestNextFrame) { |
1397 | 0 | CancelCurrentCompositeTask(); |
1398 | 0 | // Pretend we composited in case someone is wating for this event. |
1399 | 0 | TimeStamp now = TimeStamp::Now(); |
1400 | 0 | DidComposite(now, now); |
1401 | 0 | } |
1402 | 0 | } |
1403 | 0 |
|
1404 | 0 | return true; |
1405 | 0 | } |
1406 | | |
1407 | | void |
1408 | | CompositorBridgeParent::LeaveTestMode(const LayersId& aId) |
1409 | 0 | { |
1410 | 0 | mTestTime = Nothing(); |
1411 | 0 | } |
1412 | | |
1413 | | void |
1414 | | CompositorBridgeParent::ApplyAsyncProperties(LayerTransactionParent* aLayerTree, |
1415 | | TransformsToSkip aSkip) |
1416 | 0 | { |
1417 | 0 | // NOTE: This should only be used for testing. For example, when mTestTime is |
1418 | 0 | // non-empty, or when called from test-only methods like |
1419 | 0 | // LayerTransactionParent::RecvGetAnimationTransform. |
1420 | 0 |
|
1421 | 0 | // Synchronously update the layer tree |
1422 | 0 | if (aLayerTree->GetRoot()) { |
1423 | 0 | AutoResolveRefLayers resolve(mCompositionManager); |
1424 | 0 | SetShadowProperties(mLayerManager->GetRoot()); |
1425 | 0 |
|
1426 | 0 | TimeStamp time = mTestTime.valueOr(mCompositorScheduler->GetLastComposeTime()); |
1427 | 0 | bool requestNextFrame = |
1428 | 0 | mCompositionManager->TransformShadowTree(time, mVsyncRate, aSkip); |
1429 | 0 | if (!requestNextFrame) { |
1430 | 0 | CancelCurrentCompositeTask(); |
1431 | 0 | // Pretend we composited in case someone is waiting for this event. |
1432 | 0 | TimeStamp now = TimeStamp::Now(); |
1433 | 0 | DidComposite(now, now); |
1434 | 0 | } |
1435 | 0 | } |
1436 | 0 | } |
1437 | | |
1438 | | CompositorAnimationStorage* |
1439 | | CompositorBridgeParent::GetAnimationStorage() |
1440 | 0 | { |
1441 | 0 | if (!mAnimationStorage) { |
1442 | 0 | mAnimationStorage = new CompositorAnimationStorage(); |
1443 | 0 | } |
1444 | 0 | return mAnimationStorage; |
1445 | 0 | } |
1446 | | |
1447 | | mozilla::ipc::IPCResult |
1448 | | CompositorBridgeParent::RecvGetFrameUniformity(FrameUniformityData* aOutData) |
1449 | 0 | { |
1450 | 0 | mCompositionManager->GetFrameUniformity(aOutData); |
1451 | 0 | return IPC_OK(); |
1452 | 0 | } |
1453 | | |
1454 | | void |
1455 | | CompositorBridgeParent::SetTestAsyncScrollOffset( |
1456 | | const LayersId& aLayersId, |
1457 | | const FrameMetrics::ViewID& aScrollId, |
1458 | | const CSSPoint& aPoint) |
1459 | 0 | { |
1460 | 0 | if (mApzUpdater) { |
1461 | 0 | MOZ_ASSERT(aLayersId.IsValid()); |
1462 | 0 | mApzUpdater->SetTestAsyncScrollOffset(aLayersId, aScrollId, aPoint); |
1463 | 0 | } |
1464 | 0 | } |
1465 | | |
1466 | | void |
1467 | | CompositorBridgeParent::SetTestAsyncZoom( |
1468 | | const LayersId& aLayersId, |
1469 | | const FrameMetrics::ViewID& aScrollId, |
1470 | | const LayerToParentLayerScale& aZoom) |
1471 | 0 | { |
1472 | 0 | if (mApzUpdater) { |
1473 | 0 | MOZ_ASSERT(aLayersId.IsValid()); |
1474 | 0 | mApzUpdater->SetTestAsyncZoom(aLayersId, aScrollId, aZoom); |
1475 | 0 | } |
1476 | 0 | } |
1477 | | |
1478 | | void |
1479 | | CompositorBridgeParent::FlushApzRepaints(const LayersId& aLayersId) |
1480 | 0 | { |
1481 | 0 | MOZ_ASSERT(mApzcTreeManager); |
1482 | 0 | MOZ_ASSERT(mApzUpdater); |
1483 | 0 | MOZ_ASSERT(aLayersId.IsValid()); |
1484 | 0 | RefPtr<CompositorBridgeParent> self = this; |
1485 | 0 | mApzUpdater->RunOnControllerThread(aLayersId, NS_NewRunnableFunction( |
1486 | 0 | "layers::CompositorBridgeParent::FlushApzRepaints", |
1487 | 0 | [=]() { self->mApzcTreeManager->FlushApzRepaints(aLayersId); })); |
1488 | 0 | } |
1489 | | |
1490 | | void |
1491 | | CompositorBridgeParent::GetAPZTestData(const LayersId& aLayersId, |
1492 | | APZTestData* aOutData) |
1493 | 0 | { |
1494 | 0 | if (mApzUpdater) { |
1495 | 0 | MOZ_ASSERT(aLayersId.IsValid()); |
1496 | 0 | mApzUpdater->GetAPZTestData(aLayersId, aOutData); |
1497 | 0 | } |
1498 | 0 | } |
1499 | | |
1500 | | void |
1501 | | CompositorBridgeParent::SetConfirmedTargetAPZC(const LayersId& aLayersId, |
1502 | | const uint64_t& aInputBlockId, |
1503 | | const nsTArray<ScrollableLayerGuid>& aTargets) |
1504 | 0 | { |
1505 | 0 | if (!mApzcTreeManager || !mApzUpdater) { |
1506 | 0 | return; |
1507 | 0 | } |
1508 | 0 | // Need to specifically bind this since it's overloaded. |
1509 | 0 | void (APZCTreeManager::*setTargetApzcFunc) |
1510 | 0 | (uint64_t, const nsTArray<ScrollableLayerGuid>&) = |
1511 | 0 | &APZCTreeManager::SetTargetAPZC; |
1512 | 0 | RefPtr<Runnable> task = |
1513 | 0 | NewRunnableMethod<uint64_t, |
1514 | 0 | StoreCopyPassByConstLRef<nsTArray<ScrollableLayerGuid>>>( |
1515 | 0 | "layers::CompositorBridgeParent::SetConfirmedTargetAPZC", |
1516 | 0 | mApzcTreeManager.get(), |
1517 | 0 | setTargetApzcFunc, |
1518 | 0 | aInputBlockId, |
1519 | 0 | aTargets); |
1520 | 0 | mApzUpdater->RunOnControllerThread(aLayersId, task.forget()); |
1521 | 0 | } |
1522 | | |
1523 | | void |
1524 | | CompositorBridgeParent::InitializeLayerManager(const nsTArray<LayersBackend>& aBackendHints) |
1525 | 0 | { |
1526 | 0 | NS_ASSERTION(!mLayerManager, "Already initialised mLayerManager"); |
1527 | 0 | NS_ASSERTION(!mCompositor, "Already initialised mCompositor"); |
1528 | 0 |
|
1529 | 0 | if (!InitializeAdvancedLayers(aBackendHints, nullptr)) { |
1530 | 0 | mCompositor = NewCompositor(aBackendHints); |
1531 | 0 | if (!mCompositor) { |
1532 | 0 | return; |
1533 | 0 | } |
1534 | 0 | mLayerManager = new LayerManagerComposite(mCompositor); |
1535 | 0 | } |
1536 | 0 | mLayerManager->SetCompositorBridgeID(mCompositorBridgeID); |
1537 | 0 |
|
1538 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1539 | 0 | sIndirectLayerTrees[mRootLayerTreeID].mLayerManager = mLayerManager; |
1540 | 0 | } |
1541 | | |
1542 | | bool |
1543 | | CompositorBridgeParent::InitializeAdvancedLayers(const nsTArray<LayersBackend>& aBackendHints, |
1544 | | TextureFactoryIdentifier* aOutIdentifier) |
1545 | 0 | { |
1546 | | #ifdef XP_WIN |
1547 | | if (!mOptions.UseAdvancedLayers()) { |
1548 | | return false; |
1549 | | } |
1550 | | |
1551 | | // Currently LayerManagerMLGPU hardcodes a D3D11 device, so we reject using |
1552 | | // AL if LAYERS_D3D11 isn't in the backend hints. |
1553 | | if (!aBackendHints.Contains(LayersBackend::LAYERS_D3D11)) { |
1554 | | return false; |
1555 | | } |
1556 | | |
1557 | | RefPtr<LayerManagerMLGPU> manager = new LayerManagerMLGPU(mWidget); |
1558 | | if (!manager->Initialize()) { |
1559 | | return false; |
1560 | | } |
1561 | | |
1562 | | if (aOutIdentifier) { |
1563 | | *aOutIdentifier = manager->GetTextureFactoryIdentifier(); |
1564 | | } |
1565 | | mLayerManager = manager; |
1566 | | return true; |
1567 | | #else |
1568 | | return false; |
1569 | 0 | #endif |
1570 | 0 | } |
1571 | | |
1572 | | RefPtr<Compositor> |
1573 | | CompositorBridgeParent::NewCompositor(const nsTArray<LayersBackend>& aBackendHints) |
1574 | 0 | { |
1575 | 0 | for (size_t i = 0; i < aBackendHints.Length(); ++i) { |
1576 | 0 | RefPtr<Compositor> compositor; |
1577 | 0 | if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL) { |
1578 | 0 | compositor = new CompositorOGL(this, |
1579 | 0 | mWidget, |
1580 | 0 | mEGLSurfaceSize.width, |
1581 | 0 | mEGLSurfaceSize.height, |
1582 | 0 | mUseExternalSurfaceSize); |
1583 | 0 | } else if (aBackendHints[i] == LayersBackend::LAYERS_BASIC) { |
1584 | 0 | #ifdef MOZ_WIDGET_GTK |
1585 | 0 | if (gfxVars::UseXRender()) { |
1586 | 0 | compositor = new X11BasicCompositor(this, mWidget); |
1587 | 0 | } else |
1588 | 0 | #endif |
1589 | 0 | { |
1590 | 0 | compositor = new BasicCompositor(this, mWidget); |
1591 | 0 | } |
1592 | | #ifdef XP_WIN |
1593 | | } else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11) { |
1594 | | compositor = new CompositorD3D11(this, mWidget); |
1595 | | #endif |
1596 | | } |
1597 | 0 | nsCString failureReason; |
1598 | 0 |
|
1599 | 0 | // Some software GPU emulation implementations will happily try to create |
1600 | 0 | // unreasonably big surfaces and then fail in awful ways. |
1601 | 0 | // Let's at least limit this to the default max texture size we use for content, |
1602 | 0 | // anything larger than that will fail to render on the content side anyway. |
1603 | 0 | // We can revisit this value and make it even tighter if need be. |
1604 | 0 | const int max_fb_size = 32767; |
1605 | 0 | const LayoutDeviceIntSize size = mWidget->GetClientSize(); |
1606 | 0 | if (size.width > max_fb_size || size.height > max_fb_size) { |
1607 | 0 | failureReason = "FEATURE_FAILURE_MAX_FRAMEBUFFER_SIZE"; |
1608 | 0 | return nullptr; |
1609 | 0 | } |
1610 | 0 | |
1611 | 0 | MOZ_ASSERT(!gfxVars::UseWebRender() || aBackendHints[i] == LayersBackend::LAYERS_BASIC); |
1612 | 0 | if (compositor && compositor->Initialize(&failureReason)) { |
1613 | 0 | if (failureReason.IsEmpty()){ |
1614 | 0 | failureReason = "SUCCESS"; |
1615 | 0 | } |
1616 | 0 |
|
1617 | 0 | // should only report success here |
1618 | 0 | if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL){ |
1619 | 0 | Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID, failureReason); |
1620 | 0 | } |
1621 | | #ifdef XP_WIN |
1622 | | else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11){ |
1623 | | Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID, failureReason); |
1624 | | } |
1625 | | #endif |
1626 | |
|
1627 | 0 | return compositor; |
1628 | 0 | } |
1629 | 0 |
|
1630 | 0 | // report any failure reasons here |
1631 | 0 | if (aBackendHints[i] == LayersBackend::LAYERS_OPENGL){ |
1632 | 0 | gfxCriticalNote << "[OPENGL] Failed to init compositor with reason: " |
1633 | 0 | << failureReason.get(); |
1634 | 0 | Telemetry::Accumulate(Telemetry::OPENGL_COMPOSITING_FAILURE_ID, failureReason); |
1635 | 0 | } |
1636 | | #ifdef XP_WIN |
1637 | | else if (aBackendHints[i] == LayersBackend::LAYERS_D3D11){ |
1638 | | gfxCriticalNote << "[D3D11] Failed to init compositor with reason: " |
1639 | | << failureReason.get(); |
1640 | | Telemetry::Accumulate(Telemetry::D3D11_COMPOSITING_FAILURE_ID, failureReason); |
1641 | | } |
1642 | | #endif |
1643 | | } |
1644 | 0 |
|
1645 | 0 | return nullptr; |
1646 | 0 | } |
1647 | | |
1648 | | PLayerTransactionParent* |
1649 | | CompositorBridgeParent::AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints, |
1650 | | const LayersId& aId) |
1651 | 0 | { |
1652 | 0 | MOZ_ASSERT(!aId.IsValid()); |
1653 | 0 |
|
1654 | 0 | InitializeLayerManager(aBackendHints); |
1655 | 0 |
|
1656 | 0 | if (!mLayerManager) { |
1657 | 0 | NS_WARNING("Failed to initialise Compositor"); |
1658 | 0 | LayerTransactionParent* p = new LayerTransactionParent(/* aManager */ nullptr, this, /* aAnimStorage */ nullptr, mRootLayerTreeID, mVsyncRate); |
1659 | 0 | p->AddIPDLReference(); |
1660 | 0 | return p; |
1661 | 0 | } |
1662 | 0 |
|
1663 | 0 | mCompositionManager = new AsyncCompositionManager(this, mLayerManager); |
1664 | 0 |
|
1665 | 0 | LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, GetAnimationStorage(), mRootLayerTreeID, mVsyncRate); |
1666 | 0 | p->AddIPDLReference(); |
1667 | 0 | return p; |
1668 | 0 | } |
1669 | | |
1670 | | bool |
1671 | | CompositorBridgeParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor) |
1672 | 0 | { |
1673 | 0 | static_cast<LayerTransactionParent*>(actor)->ReleaseIPDLReference(); |
1674 | 0 | return true; |
1675 | 0 | } |
1676 | | |
1677 | | CompositorBridgeParent* CompositorBridgeParent::GetCompositorBridgeParent(uint64_t id) |
1678 | 0 | { |
1679 | 0 | AssertIsInCompositorThread(); |
1680 | 0 | CompositorMap::iterator it = sCompositorMap->find(id); |
1681 | 0 | return it != sCompositorMap->end() ? it->second : nullptr; |
1682 | 0 | } |
1683 | | |
1684 | | void CompositorBridgeParent::AddCompositor(CompositorBridgeParent* compositor, uint64_t* outID) |
1685 | 0 | { |
1686 | 0 | AssertIsInCompositorThread(); |
1687 | 0 |
|
1688 | 0 | static uint64_t sNextID = 1; |
1689 | 0 |
|
1690 | 0 | ++sNextID; |
1691 | 0 | (*sCompositorMap)[sNextID] = compositor; |
1692 | 0 | *outID = sNextID; |
1693 | 0 | } |
1694 | | |
1695 | | CompositorBridgeParent* CompositorBridgeParent::RemoveCompositor(uint64_t id) |
1696 | 0 | { |
1697 | 0 | AssertIsInCompositorThread(); |
1698 | 0 |
|
1699 | 0 | CompositorMap::iterator it = sCompositorMap->find(id); |
1700 | 0 | if (it == sCompositorMap->end()) { |
1701 | 0 | return nullptr; |
1702 | 0 | } |
1703 | 0 | CompositorBridgeParent *retval = it->second; |
1704 | 0 | sCompositorMap->erase(it); |
1705 | 0 | return retval; |
1706 | 0 | } |
1707 | | |
1708 | | void |
1709 | | CompositorBridgeParent::NotifyVsync(const TimeStamp& aTimeStamp, const LayersId& aLayersId) |
1710 | 0 | { |
1711 | 0 | MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU); |
1712 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
1713 | 0 |
|
1714 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1715 | 0 | auto it = sIndirectLayerTrees.find(aLayersId); |
1716 | 0 | if (it == sIndirectLayerTrees.end()) |
1717 | 0 | return; |
1718 | 0 | |
1719 | 0 | CompositorBridgeParent* cbp = it->second.mParent; |
1720 | 0 | if (!cbp || !cbp->mWidget) |
1721 | 0 | return; |
1722 | 0 | |
1723 | 0 | RefPtr<VsyncObserver> obs = cbp->mWidget->GetVsyncObserver(); |
1724 | 0 | if (!obs) |
1725 | 0 | return; |
1726 | 0 | |
1727 | 0 | obs->NotifyVsync(aTimeStamp); |
1728 | 0 | } |
1729 | | |
1730 | | mozilla::ipc::IPCResult |
1731 | | CompositorBridgeParent::RecvNotifyChildCreated(const LayersId& child, |
1732 | | CompositorOptions* aOptions) |
1733 | 0 | { |
1734 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1735 | 0 | NotifyChildCreated(child); |
1736 | 0 | *aOptions = mOptions; |
1737 | 0 | return IPC_OK(); |
1738 | 0 | } |
1739 | | |
1740 | | mozilla::ipc::IPCResult |
1741 | | CompositorBridgeParent::RecvNotifyChildRecreated(const LayersId& aChild, |
1742 | | CompositorOptions* aOptions) |
1743 | 0 | { |
1744 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1745 | 0 |
|
1746 | 0 | if (sIndirectLayerTrees.find(aChild) != sIndirectLayerTrees.end()) { |
1747 | 0 | NS_WARNING("Invalid to register the same layer tree twice"); |
1748 | 0 | return IPC_FAIL_NO_REASON(this); |
1749 | 0 | } |
1750 | 0 |
|
1751 | 0 | NotifyChildCreated(aChild); |
1752 | 0 | *aOptions = mOptions; |
1753 | 0 | return IPC_OK(); |
1754 | 0 | } |
1755 | | |
1756 | | void |
1757 | | CompositorBridgeParent::NotifyChildCreated(LayersId aChild) |
1758 | 0 | { |
1759 | 0 | sIndirectLayerTreesLock->AssertCurrentThreadOwns(); |
1760 | 0 | sIndirectLayerTrees[aChild].mParent = this; |
1761 | 0 | sIndirectLayerTrees[aChild].mLayerManager = mLayerManager; |
1762 | 0 | } |
1763 | | |
1764 | | mozilla::ipc::IPCResult |
1765 | | CompositorBridgeParent::RecvMapAndNotifyChildCreated(const LayersId& aChild, |
1766 | | const base::ProcessId& aOwnerPid, |
1767 | | CompositorOptions* aOptions) |
1768 | 0 | { |
1769 | 0 | // We only use this message when the remote compositor is in the GPU process. |
1770 | 0 | // It is harmless to call it, though. |
1771 | 0 | MOZ_ASSERT(XRE_IsGPUProcess()); |
1772 | 0 |
|
1773 | 0 | LayerTreeOwnerTracker::Get()->Map(aChild, aOwnerPid); |
1774 | 0 |
|
1775 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1776 | 0 | NotifyChildCreated(aChild); |
1777 | 0 | *aOptions = mOptions; |
1778 | 0 | return IPC_OK(); |
1779 | 0 | } |
1780 | | |
1781 | | mozilla::ipc::IPCResult |
1782 | | CompositorBridgeParent::RecvAdoptChild(const LayersId& child) |
1783 | 0 | { |
1784 | 0 | RefPtr<APZUpdater> oldApzUpdater; |
1785 | 0 | APZCTreeManagerParent* parent; |
1786 | 0 | bool scheduleComposition = false; |
1787 | 0 | RefPtr<CrossProcessCompositorBridgeParent> cpcp; |
1788 | 0 | RefPtr<WebRenderBridgeParent> childWrBridge; |
1789 | 0 |
|
1790 | 0 | { // scope lock |
1791 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1792 | 0 | // If child is already belong to this CompositorBridgeParent, |
1793 | 0 | // no need to handle adopting child. |
1794 | 0 | if (sIndirectLayerTrees[child].mParent == this) { |
1795 | 0 | return IPC_OK(); |
1796 | 0 | } |
1797 | 0 |
|
1798 | 0 | if (sIndirectLayerTrees[child].mParent) { |
1799 | 0 | // We currently don't support adopting children from one compositor to |
1800 | 0 | // another if the two compositors don't have the same options. |
1801 | 0 | MOZ_ASSERT(sIndirectLayerTrees[child].mParent->mOptions == mOptions); |
1802 | 0 | oldApzUpdater = sIndirectLayerTrees[child].mParent->mApzUpdater; |
1803 | 0 | } |
1804 | 0 | NotifyChildCreated(child); |
1805 | 0 | if (sIndirectLayerTrees[child].mLayerTree) { |
1806 | 0 | sIndirectLayerTrees[child].mLayerTree->SetLayerManager(mLayerManager, GetAnimationStorage()); |
1807 | 0 | // Trigger composition to handle a case that mLayerTree was not composited yet |
1808 | 0 | // by previous CompositorBridgeParent, since nsRefreshDriver might wait composition complete. |
1809 | 0 | scheduleComposition = true; |
1810 | 0 | } |
1811 | 0 | if (mWrBridge) { |
1812 | 0 | childWrBridge = sIndirectLayerTrees[child].mWrBridge; |
1813 | 0 | cpcp = sIndirectLayerTrees[child].mCrossProcessParent; |
1814 | 0 | } |
1815 | 0 | parent = sIndirectLayerTrees[child].mApzcTreeManagerParent; |
1816 | 0 | } |
1817 | 0 |
|
1818 | 0 | if (scheduleComposition) { |
1819 | 0 | ScheduleComposition(); |
1820 | 0 | } |
1821 | 0 |
|
1822 | 0 | if (childWrBridge) { |
1823 | 0 | MOZ_ASSERT(mWrBridge); |
1824 | 0 | RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI(); |
1825 | 0 | api = api->Clone(); |
1826 | 0 | wr::Epoch newEpoch = childWrBridge->UpdateWebRender(mWrBridge->CompositorScheduler(), |
1827 | 0 | api, |
1828 | 0 | mWrBridge->AsyncImageManager(), |
1829 | 0 | GetAnimationStorage(), |
1830 | 0 | mWrBridge->GetTextureFactoryIdentifier()); |
1831 | 0 | // Pretend we composited, since parent CompositorBridgeParent was replaced. |
1832 | 0 | TimeStamp now = TimeStamp::Now(); |
1833 | 0 | NotifyPipelineRendered(childWrBridge->PipelineId(), newEpoch, now, now); |
1834 | 0 | } |
1835 | 0 |
|
1836 | 0 | if (oldApzUpdater) { |
1837 | 0 | // We don't support moving a child from an APZ-enabled compositor to a |
1838 | 0 | // APZ-disabled compositor. The mOptions assertion above should already |
1839 | 0 | // ensure this, since APZ-ness is one of the things in mOptions. Note |
1840 | 0 | // however it is possible for mApzUpdater to be non-null here with |
1841 | 0 | // oldApzUpdater null, because the child may not have been previously |
1842 | 0 | // composited. |
1843 | 0 | MOZ_ASSERT(mApzUpdater); |
1844 | 0 | } |
1845 | 0 | if (mApzUpdater) { |
1846 | 0 | if (parent) { |
1847 | 0 | MOZ_ASSERT(mApzcTreeManager); |
1848 | 0 | parent->ChildAdopted(mApzcTreeManager, mApzUpdater); |
1849 | 0 | } |
1850 | 0 | mApzUpdater->NotifyLayerTreeAdopted(child, oldApzUpdater); |
1851 | 0 | } |
1852 | 0 | return IPC_OK(); |
1853 | 0 | } |
1854 | | |
1855 | | PWebRenderBridgeParent* |
1856 | | CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId, |
1857 | | const LayoutDeviceIntSize& aSize, |
1858 | | TextureFactoryIdentifier* aTextureFactoryIdentifier, |
1859 | | wr::IdNamespace* aIdNamespace) |
1860 | 0 | { |
1861 | | #ifndef MOZ_BUILD_WEBRENDER |
1862 | | // Extra guard since this in the parent process and we don't want a malicious |
1863 | | // child process invoking this codepath before it's ready |
1864 | | MOZ_RELEASE_ASSERT(false); |
1865 | | #endif |
1866 | 0 | MOZ_ASSERT(wr::AsLayersId(aPipelineId) == mRootLayerTreeID); |
1867 | 0 | MOZ_ASSERT(!mWrBridge); |
1868 | 0 | MOZ_ASSERT(!mCompositor); |
1869 | 0 | MOZ_ASSERT(!mCompositorScheduler); |
1870 | 0 | MOZ_ASSERT(mWidget); |
1871 | 0 |
|
1872 | 0 | RefPtr<widget::CompositorWidget> widget = mWidget; |
1873 | 0 | wr::WrWindowId windowId = wr::NewWindowId(); |
1874 | 0 | if (mApzUpdater) { |
1875 | 0 | // If APZ is enabled, we need to register the APZ updater with the window id |
1876 | 0 | // before the updater thread is created in WebRenderAPI::Create, so |
1877 | 0 | // that the callback from the updater thread can find the right APZUpdater. |
1878 | 0 | mApzUpdater->SetWebRenderWindowId(windowId); |
1879 | 0 | } |
1880 | 0 | if (mApzSampler) { |
1881 | 0 | // Same as for mApzUpdater, but for the sampler thread. |
1882 | 0 | mApzSampler->SetWebRenderWindowId(windowId); |
1883 | 0 | } |
1884 | 0 | RefPtr<wr::WebRenderAPI> api = wr::WebRenderAPI::Create(this, std::move(widget), windowId, aSize); |
1885 | 0 | if (!api) { |
1886 | 0 | mWrBridge = WebRenderBridgeParent::CreateDestroyed(aPipelineId); |
1887 | 0 | mWrBridge.get()->AddRef(); // IPDL reference |
1888 | 0 | *aIdNamespace = mWrBridge->GetIdNamespace(); |
1889 | 0 | *aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE); |
1890 | 0 | return mWrBridge; |
1891 | 0 | } |
1892 | 0 | mAsyncImageManager = new AsyncImagePipelineManager(api->Clone()); |
1893 | 0 | RefPtr<AsyncImagePipelineManager> asyncMgr = mAsyncImageManager; |
1894 | 0 | wr::TransactionBuilder txn; |
1895 | 0 | txn.SetRootPipeline(aPipelineId); |
1896 | 0 | api->SendTransaction(txn); |
1897 | 0 | RefPtr<CompositorAnimationStorage> animStorage = GetAnimationStorage(); |
1898 | 0 | mWrBridge = new WebRenderBridgeParent(this, aPipelineId, mWidget, nullptr, std::move(api), std::move(asyncMgr), std::move(animStorage), mVsyncRate); |
1899 | 0 | mWrBridge.get()->AddRef(); // IPDL reference |
1900 | 0 |
|
1901 | 0 | *aIdNamespace = mWrBridge->GetIdNamespace(); |
1902 | 0 | mCompositorScheduler = mWrBridge->CompositorScheduler(); |
1903 | 0 | MOZ_ASSERT(mCompositorScheduler); |
1904 | 0 | { // scope lock |
1905 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1906 | 0 | MOZ_ASSERT(sIndirectLayerTrees[mRootLayerTreeID].mWrBridge == nullptr); |
1907 | 0 | sIndirectLayerTrees[mRootLayerTreeID].mWrBridge = mWrBridge; |
1908 | 0 | } |
1909 | 0 | *aTextureFactoryIdentifier = mWrBridge->GetTextureFactoryIdentifier(); |
1910 | 0 | return mWrBridge; |
1911 | 0 | } |
1912 | | |
1913 | | bool |
1914 | | CompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) |
1915 | 0 | { |
1916 | | #ifndef MOZ_BUILD_WEBRENDER |
1917 | | // Extra guard since this in the parent process and we don't want a malicious |
1918 | | // child process invoking this codepath before it's ready |
1919 | | MOZ_RELEASE_ASSERT(false); |
1920 | | #endif |
1921 | | WebRenderBridgeParent* parent = static_cast<WebRenderBridgeParent*>(aActor); |
1922 | 0 | { |
1923 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1924 | 0 | auto it = sIndirectLayerTrees.find(wr::AsLayersId(parent->PipelineId())); |
1925 | 0 | if (it != sIndirectLayerTrees.end()) { |
1926 | 0 | it->second.mWrBridge = nullptr; |
1927 | 0 | } |
1928 | 0 | } |
1929 | 0 | parent->Release(); // IPDL reference |
1930 | 0 | return true; |
1931 | 0 | } |
1932 | | |
1933 | | void |
1934 | | CompositorBridgeParent::NotifyMemoryPressure() |
1935 | 0 | { |
1936 | 0 | if (mWrBridge) { |
1937 | 0 | RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI(); |
1938 | 0 | if (api) { |
1939 | 0 | api->NotifyMemoryPressure(); |
1940 | 0 | } |
1941 | 0 | } |
1942 | 0 | } |
1943 | | |
1944 | | void |
1945 | | CompositorBridgeParent::AccumulateMemoryReport(wr::MemoryReport* aReport) |
1946 | 0 | { |
1947 | 0 | if (mWrBridge) { |
1948 | 0 | RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI(); |
1949 | 0 | if (api) { |
1950 | 0 | api->AccumulateMemoryReport(aReport); |
1951 | 0 | } |
1952 | 0 | } |
1953 | 0 | } |
1954 | | |
1955 | | RefPtr<WebRenderBridgeParent> |
1956 | | CompositorBridgeParent::GetWebRenderBridgeParent() const |
1957 | 0 | { |
1958 | 0 | return mWrBridge; |
1959 | 0 | } |
1960 | | |
1961 | | Maybe<TimeStamp> |
1962 | | CompositorBridgeParent::GetTestingTimeStamp() const |
1963 | 0 | { |
1964 | 0 | return mTestTime; |
1965 | 0 | } |
1966 | | |
1967 | | void |
1968 | | EraseLayerState(LayersId aId) |
1969 | 0 | { |
1970 | 0 | RefPtr<APZUpdater> apz; |
1971 | 0 |
|
1972 | 0 | { // scope lock |
1973 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
1974 | 0 | auto iter = sIndirectLayerTrees.find(aId); |
1975 | 0 | if (iter != sIndirectLayerTrees.end()) { |
1976 | 0 | CompositorBridgeParent* parent = iter->second.mParent; |
1977 | 0 | if (parent) { |
1978 | 0 | apz = parent->GetAPZUpdater(); |
1979 | 0 | } |
1980 | 0 | sIndirectLayerTrees.erase(iter); |
1981 | 0 | } |
1982 | 0 | } |
1983 | 0 |
|
1984 | 0 | if (apz) { |
1985 | 0 | apz->NotifyLayerTreeRemoved(aId); |
1986 | 0 | } |
1987 | 0 | } |
1988 | | |
1989 | | /*static*/ void |
1990 | | CompositorBridgeParent::DeallocateLayerTreeId(LayersId aId) |
1991 | 0 | { |
1992 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
1993 | 0 | // Here main thread notifies compositor to remove an element from |
1994 | 0 | // sIndirectLayerTrees. This removed element might be queried soon. |
1995 | 0 | // Checking the elements of sIndirectLayerTrees exist or not before using. |
1996 | 0 | if (!CompositorLoop()) { |
1997 | 0 | gfxCriticalError() << "Attempting to post to a invalid Compositor Loop"; |
1998 | 0 | return; |
1999 | 0 | } |
2000 | 0 | CompositorLoop()->PostTask(NewRunnableFunction("EraseLayerStateRunnable", |
2001 | 0 | &EraseLayerState, aId)); |
2002 | 0 | } |
2003 | | |
2004 | | static void |
2005 | | UpdateControllerForLayersId(LayersId aLayersId, |
2006 | | GeckoContentController* aController) |
2007 | 0 | { |
2008 | 0 | // Adopt ref given to us by SetControllerForLayerTree() |
2009 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2010 | 0 | sIndirectLayerTrees[aLayersId].mController = |
2011 | 0 | already_AddRefed<GeckoContentController>(aController); |
2012 | 0 | } |
2013 | | |
2014 | | ScopedLayerTreeRegistration::ScopedLayerTreeRegistration(APZCTreeManager* aApzctm, |
2015 | | LayersId aLayersId, |
2016 | | Layer* aRoot, |
2017 | | GeckoContentController* aController) |
2018 | | : mLayersId(aLayersId) |
2019 | 0 | { |
2020 | 0 | EnsureLayerTreeMapReady(); |
2021 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2022 | 0 | sIndirectLayerTrees[aLayersId].mRoot = aRoot; |
2023 | 0 | sIndirectLayerTrees[aLayersId].mController = aController; |
2024 | 0 | } |
2025 | | |
2026 | | ScopedLayerTreeRegistration::~ScopedLayerTreeRegistration() |
2027 | 0 | { |
2028 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2029 | 0 | sIndirectLayerTrees.erase(mLayersId); |
2030 | 0 | } |
2031 | | |
2032 | | /*static*/ void |
2033 | | CompositorBridgeParent::SetControllerForLayerTree(LayersId aLayersId, |
2034 | | GeckoContentController* aController) |
2035 | 0 | { |
2036 | 0 | // This ref is adopted by UpdateControllerForLayersId(). |
2037 | 0 | aController->AddRef(); |
2038 | 0 | CompositorLoop()->PostTask(NewRunnableFunction("UpdateControllerForLayersIdRunnable", |
2039 | 0 | &UpdateControllerForLayersId, |
2040 | 0 | aLayersId, |
2041 | 0 | aController)); |
2042 | 0 | } |
2043 | | |
2044 | | /*static*/ already_AddRefed<IAPZCTreeManager> |
2045 | | CompositorBridgeParent::GetAPZCTreeManager(LayersId aLayersId) |
2046 | 0 | { |
2047 | 0 | EnsureLayerTreeMapReady(); |
2048 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2049 | 0 | LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aLayersId); |
2050 | 0 | if (sIndirectLayerTrees.end() == cit) { |
2051 | 0 | return nullptr; |
2052 | 0 | } |
2053 | 0 | LayerTreeState* lts = &cit->second; |
2054 | 0 |
|
2055 | 0 | RefPtr<IAPZCTreeManager> apzctm = lts->mParent |
2056 | 0 | ? lts->mParent->mApzcTreeManager.get() |
2057 | 0 | : nullptr; |
2058 | 0 | return apzctm.forget(); |
2059 | 0 | } |
2060 | | |
2061 | | #if defined(MOZ_GECKO_PROFILER) |
2062 | | static void |
2063 | | InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp) |
2064 | 0 | { |
2065 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
2066 | 0 | profiler_add_marker( |
2067 | 0 | "VsyncTimestamp", |
2068 | 0 | MakeUnique<VsyncMarkerPayload>(aVsyncTimestamp)); |
2069 | 0 | } |
2070 | | #endif |
2071 | | |
2072 | | /*static */ void |
2073 | | CompositorBridgeParent::PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp) |
2074 | 0 | { |
2075 | 0 | #if defined(MOZ_GECKO_PROFILER) |
2076 | 0 | // Called in the vsync thread |
2077 | 0 | if (profiler_is_active() && CompositorThreadHolder::IsActive()) { |
2078 | 0 | CompositorLoop()->PostTask( |
2079 | 0 | NewRunnableFunction("InsertVsyncProfilerMarkerRunnable", InsertVsyncProfilerMarker, |
2080 | 0 | aVsyncTimestamp)); |
2081 | 0 | } |
2082 | 0 | #endif |
2083 | 0 | } |
2084 | | |
2085 | | widget::PCompositorWidgetParent* |
2086 | | CompositorBridgeParent::AllocPCompositorWidgetParent(const CompositorWidgetInitData& aInitData) |
2087 | 0 | { |
2088 | 0 | #if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING) |
2089 | 0 | if (mWidget) { |
2090 | 0 | // Should not create two widgets on the same compositor. |
2091 | 0 | return nullptr; |
2092 | 0 | } |
2093 | 0 | |
2094 | 0 | widget::CompositorWidgetParent* widget = |
2095 | 0 | new widget::CompositorWidgetParent(aInitData, mOptions); |
2096 | 0 | widget->AddRef(); |
2097 | 0 |
|
2098 | | #ifdef XP_WIN |
2099 | | if (mOptions.UseWebRender() && DeviceManagerDx::Get()->CanUseDComp()) { |
2100 | | widget->AsWindows()->EnsureCompositorWindow(); |
2101 | | } |
2102 | | #endif |
2103 | |
|
2104 | 0 | // Sending the constructor acts as initialization as well. |
2105 | 0 | mWidget = widget; |
2106 | 0 | return widget; |
2107 | | #else |
2108 | | return nullptr; |
2109 | | #endif |
2110 | | } |
2111 | | |
2112 | | bool |
2113 | | CompositorBridgeParent::DeallocPCompositorWidgetParent(PCompositorWidgetParent* aActor) |
2114 | 0 | { |
2115 | 0 | #if defined(MOZ_WIDGET_SUPPORTS_OOP_COMPOSITING) |
2116 | 0 | static_cast<widget::CompositorWidgetParent*>(aActor)->Release(); |
2117 | 0 | return true; |
2118 | | #else |
2119 | | return false; |
2120 | | #endif |
2121 | | } |
2122 | | |
2123 | | bool |
2124 | | CompositorBridgeParent::IsPendingComposite() |
2125 | 0 | { |
2126 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
2127 | 0 | if (!mCompositor) { |
2128 | 0 | return false; |
2129 | 0 | } |
2130 | 0 | return mCompositor->IsPendingComposite(); |
2131 | 0 | } |
2132 | | |
2133 | | void |
2134 | | CompositorBridgeParent::FinishPendingComposite() |
2135 | 0 | { |
2136 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
2137 | 0 | if (!mCompositor) { |
2138 | 0 | return; |
2139 | 0 | } |
2140 | 0 | return mCompositor->FinishPendingComposite(); |
2141 | 0 | } |
2142 | | |
2143 | | CompositorController* |
2144 | | CompositorBridgeParent::LayerTreeState::GetCompositorController() const |
2145 | 0 | { |
2146 | 0 | return mParent; |
2147 | 0 | } |
2148 | | |
2149 | | MetricsSharingController* |
2150 | | CompositorBridgeParent::LayerTreeState::CrossProcessSharingController() const |
2151 | 0 | { |
2152 | 0 | return mCrossProcessParent; |
2153 | 0 | } |
2154 | | |
2155 | | MetricsSharingController* |
2156 | | CompositorBridgeParent::LayerTreeState::InProcessSharingController() const |
2157 | 0 | { |
2158 | 0 | return mParent; |
2159 | 0 | } |
2160 | | |
2161 | | void |
2162 | | CompositorBridgeParent::DidComposite(LayersId aId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) |
2163 | 0 | { |
2164 | 0 | MOZ_ASSERT(aId == mRootLayerTreeID); |
2165 | 0 | DidComposite(aCompositeStart, aCompositeEnd); |
2166 | 0 | } |
2167 | | |
2168 | | void |
2169 | | CompositorBridgeParent::DidComposite(TimeStamp& aCompositeStart, |
2170 | | TimeStamp& aCompositeEnd) |
2171 | 0 | { |
2172 | 0 | if (mWrBridge) { |
2173 | 0 | MOZ_ASSERT(false); // This should never get called for a WR compositor |
2174 | 0 | } else { |
2175 | 0 | NotifyDidComposite(mPendingTransaction, aCompositeStart, aCompositeEnd); |
2176 | | #if defined(ENABLE_FRAME_LATENCY_LOG) |
2177 | | if (mPendingTransaction.IsValid()) { |
2178 | | if (mRefreshStartTime) { |
2179 | | int32_t latencyMs = lround((aCompositeEnd - mRefreshStartTime).ToMilliseconds()); |
2180 | | printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this); |
2181 | | } |
2182 | | if (mFwdTime) { |
2183 | | int32_t latencyMs = lround((aCompositeEnd - mFwdTime).ToMilliseconds()); |
2184 | | printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this); |
2185 | | } |
2186 | | } |
2187 | | mRefreshStartTime = TimeStamp(); |
2188 | | mTxnStartTime = TimeStamp(); |
2189 | | mFwdTime = TimeStamp(); |
2190 | | #endif |
2191 | | mPendingTransaction = TransactionId{0}; |
2192 | 0 | } |
2193 | 0 | } |
2194 | | |
2195 | | void |
2196 | | CompositorBridgeParent::NotifyPipelineRendered(const wr::PipelineId& aPipelineId, |
2197 | | const wr::Epoch& aEpoch, |
2198 | | TimeStamp& aCompositeStart, |
2199 | | TimeStamp& aCompositeEnd) |
2200 | 0 | { |
2201 | 0 | if (!mWrBridge) { |
2202 | 0 | return; |
2203 | 0 | } |
2204 | 0 | |
2205 | 0 | if (mWrBridge->PipelineId() == aPipelineId) { |
2206 | 0 | mWrBridge->RemoveEpochDataPriorTo(aEpoch); |
2207 | 0 |
|
2208 | 0 | if (!mPaused) { |
2209 | 0 | TransactionId transactionId = mWrBridge->FlushTransactionIdsForEpoch(aEpoch, aCompositeEnd); |
2210 | 0 | Unused << SendDidComposite(LayersId{0}, transactionId, aCompositeStart, aCompositeEnd); |
2211 | 0 |
|
2212 | 0 | nsTArray<ImageCompositeNotificationInfo> notifications; |
2213 | 0 | mWrBridge->ExtractImageCompositeNotifications(¬ifications); |
2214 | 0 | if (!notifications.IsEmpty()) { |
2215 | 0 | Unused << ImageBridgeParent::NotifyImageComposites(notifications); |
2216 | 0 | } |
2217 | 0 | } |
2218 | 0 | return; |
2219 | 0 | } |
2220 | 0 |
|
2221 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2222 | 0 | ForEachIndirectLayerTree([&] (LayerTreeState* lts, const LayersId& aLayersId) -> void { |
2223 | 0 | if (lts->mCrossProcessParent && |
2224 | 0 | lts->mWrBridge && |
2225 | 0 | lts->mWrBridge->PipelineId() == aPipelineId) { |
2226 | 0 |
|
2227 | 0 | lts->mWrBridge->RemoveEpochDataPriorTo(aEpoch); |
2228 | 0 |
|
2229 | 0 | if (!mPaused) { |
2230 | 0 | CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent; |
2231 | 0 | TransactionId transactionId = lts->mWrBridge->FlushTransactionIdsForEpoch(aEpoch, aCompositeEnd); |
2232 | 0 | Unused << cpcp->SendDidComposite(aLayersId, transactionId, aCompositeStart, aCompositeEnd); |
2233 | 0 | } |
2234 | 0 | } |
2235 | 0 | }); |
2236 | 0 | } |
2237 | | |
2238 | | RefPtr<AsyncImagePipelineManager> |
2239 | | CompositorBridgeParent::GetAsyncImagePipelineManager() const |
2240 | 0 | { |
2241 | 0 | return mAsyncImageManager; |
2242 | 0 | } |
2243 | | |
2244 | | void |
2245 | | CompositorBridgeParent::NotifyDidComposite(TransactionId aTransactionId, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) |
2246 | 0 | { |
2247 | 0 | MOZ_ASSERT(!mWrBridge); // We should be going through NotifyPipelineRendered instead |
2248 | 0 |
|
2249 | 0 | Unused << SendDidComposite(LayersId{0}, aTransactionId, aCompositeStart, aCompositeEnd); |
2250 | 0 |
|
2251 | 0 | if (mLayerManager) { |
2252 | 0 | nsTArray<ImageCompositeNotificationInfo> notifications; |
2253 | 0 | mLayerManager->ExtractImageCompositeNotifications(¬ifications); |
2254 | 0 | if (!notifications.IsEmpty()) { |
2255 | 0 | Unused << ImageBridgeParent::NotifyImageComposites(notifications); |
2256 | 0 | } |
2257 | 0 | } |
2258 | 0 |
|
2259 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2260 | 0 | ForEachIndirectLayerTree([&] (LayerTreeState* lts, const LayersId& aLayersId) -> void { |
2261 | 0 | if (lts->mCrossProcessParent && lts->mParent == this) { |
2262 | 0 | CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent; |
2263 | 0 | cpcp->DidCompositeLocked(aLayersId, aCompositeStart, aCompositeEnd); |
2264 | 0 | } |
2265 | 0 | }); |
2266 | 0 | } |
2267 | | |
2268 | | void |
2269 | | CompositorBridgeParent::InvalidateRemoteLayers() |
2270 | 0 | { |
2271 | 0 | MOZ_ASSERT(CompositorLoop() == MessageLoop::current()); |
2272 | 0 |
|
2273 | 0 | Unused << PCompositorBridgeParent::SendInvalidateLayers(LayersId{0}); |
2274 | 0 |
|
2275 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2276 | 0 | ForEachIndirectLayerTree([] (LayerTreeState* lts, const LayersId& aLayersId) -> void { |
2277 | 0 | if (lts->mCrossProcessParent) { |
2278 | 0 | CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent; |
2279 | 0 | Unused << cpcp->SendInvalidateLayers(aLayersId); |
2280 | 0 | } |
2281 | 0 | }); |
2282 | 0 | } |
2283 | | |
2284 | | void |
2285 | | UpdateIndirectTree(LayersId aId, Layer* aRoot, const TargetConfig& aTargetConfig) |
2286 | 0 | { |
2287 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2288 | 0 | sIndirectLayerTrees[aId].mRoot = aRoot; |
2289 | 0 | sIndirectLayerTrees[aId].mTargetConfig = aTargetConfig; |
2290 | 0 | } |
2291 | | |
2292 | | /* static */ CompositorBridgeParent::LayerTreeState* |
2293 | | CompositorBridgeParent::GetIndirectShadowTree(LayersId aId) |
2294 | 0 | { |
2295 | 0 | // Only the compositor thread should use this method variant |
2296 | 0 | MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); |
2297 | 0 |
|
2298 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2299 | 0 | LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId); |
2300 | 0 | if (sIndirectLayerTrees.end() == cit) { |
2301 | 0 | return nullptr; |
2302 | 0 | } |
2303 | 0 | return &cit->second; |
2304 | 0 | } |
2305 | | |
2306 | | /* static */ bool |
2307 | | CompositorBridgeParent::CallWithIndirectShadowTree(LayersId aId, |
2308 | | const std::function<void(CompositorBridgeParent::LayerTreeState&)>& aFunc) |
2309 | 0 | { |
2310 | 0 | // Note that this does not make things universally threadsafe just because the |
2311 | 0 | // sIndirectLayerTreesLock mutex is held. This is because the compositor |
2312 | 0 | // thread can mutate the LayerTreeState outside the lock. It does however |
2313 | 0 | // ensure that the *storage* for the LayerTreeState remains stable, since we |
2314 | 0 | // should always hold the lock when adding/removing entries to the map. |
2315 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2316 | 0 | LayerTreeMap::iterator cit = sIndirectLayerTrees.find(aId); |
2317 | 0 | if (sIndirectLayerTrees.end() == cit) { |
2318 | 0 | return false; |
2319 | 0 | } |
2320 | 0 | aFunc(cit->second); |
2321 | 0 | return true; |
2322 | 0 | } |
2323 | | |
2324 | | static CompositorBridgeParent::LayerTreeState* |
2325 | | GetStateForRoot(LayersId aContentLayersId, const MonitorAutoLock& aProofOfLock) |
2326 | 0 | { |
2327 | 0 | CompositorBridgeParent::LayerTreeState* state = nullptr; |
2328 | 0 | LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aContentLayersId); |
2329 | 0 | if (sIndirectLayerTrees.end() != itr) { |
2330 | 0 | state = &itr->second; |
2331 | 0 | } |
2332 | 0 |
|
2333 | 0 | // |state| is the state for the content process, but we want the APZCTMParent |
2334 | 0 | // for the parent process owning that content process. So we have to jump to |
2335 | 0 | // the LayerTreeState for the root layer tree id for that layer tree, and use |
2336 | 0 | // the mApzcTreeManagerParent from that. This should also work with nested |
2337 | 0 | // content processes, because RootLayerTreeId() will bypass any intermediate |
2338 | 0 | // processes' ids and go straight to the root. |
2339 | 0 | if (state) { |
2340 | 0 | LayersId rootLayersId = state->mParent->RootLayerTreeId(); |
2341 | 0 | itr = sIndirectLayerTrees.find(rootLayersId); |
2342 | 0 | state = (sIndirectLayerTrees.end() != itr) ? &itr->second : nullptr; |
2343 | 0 | } |
2344 | 0 |
|
2345 | 0 | return state; |
2346 | 0 | } |
2347 | | |
2348 | | /* static */ APZCTreeManagerParent* |
2349 | | CompositorBridgeParent::GetApzcTreeManagerParentForRoot(LayersId aContentLayersId) |
2350 | 0 | { |
2351 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2352 | 0 | CompositorBridgeParent::LayerTreeState* state = |
2353 | 0 | GetStateForRoot(aContentLayersId, lock); |
2354 | 0 | return state ? state->mApzcTreeManagerParent : nullptr; |
2355 | 0 | } |
2356 | | |
2357 | | /* static */ GeckoContentController* |
2358 | | CompositorBridgeParent::GetGeckoContentControllerForRoot(LayersId aContentLayersId) |
2359 | 0 | { |
2360 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2361 | 0 | CompositorBridgeParent::LayerTreeState* state = |
2362 | 0 | GetStateForRoot(aContentLayersId, lock); |
2363 | 0 | return state ? state->mController.get() : nullptr; |
2364 | 0 | } |
2365 | | |
2366 | | PTextureParent* |
2367 | | CompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData, |
2368 | | const ReadLockDescriptor& aReadLock, |
2369 | | const LayersBackend& aLayersBackend, |
2370 | | const TextureFlags& aFlags, |
2371 | | const LayersId& aId, |
2372 | | const uint64_t& aSerial, |
2373 | | const wr::MaybeExternalImageId& aExternalImageId) |
2374 | 0 | { |
2375 | 0 | return TextureHost::CreateIPDLActor(this, aSharedData, aReadLock, aLayersBackend, aFlags, aSerial, aExternalImageId); |
2376 | 0 | } |
2377 | | |
2378 | | bool |
2379 | | CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) |
2380 | 0 | { |
2381 | 0 | return TextureHost::DestroyIPDLActor(actor); |
2382 | 0 | } |
2383 | | |
2384 | | bool |
2385 | | CompositorBridgeParent::IsSameProcess() const |
2386 | 0 | { |
2387 | 0 | return OtherPid() == base::GetCurrentProcId(); |
2388 | 0 | } |
2389 | | |
2390 | | void |
2391 | | CompositorBridgeParent::NotifyWebRenderError(wr::WebRenderError aError) |
2392 | 0 | { |
2393 | 0 | MOZ_ASSERT(CompositorLoop() == MessageLoop::current()); |
2394 | 0 | Unused << SendNotifyWebRenderError(aError); |
2395 | 0 | } |
2396 | | |
2397 | | void |
2398 | | CompositorBridgeParent::NotifyWebRenderContextPurge() |
2399 | 0 | { |
2400 | 0 | MOZ_ASSERT(CompositorLoop() == MessageLoop::current()); |
2401 | 0 | RefPtr<wr::WebRenderAPI> api = mWrBridge->GetWebRenderAPI(); |
2402 | 0 | api->ClearAllCaches(); |
2403 | 0 | } |
2404 | | |
2405 | | #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
2406 | | //#define PLUGINS_LOG(...) printf_stderr("CP [%s]: ", __FUNCTION__); |
2407 | | // printf_stderr(__VA_ARGS__); |
2408 | | // printf_stderr("\n"); |
2409 | | #define PLUGINS_LOG(...) |
2410 | | |
2411 | | bool |
2412 | | CompositorBridgeParent::UpdatePluginWindowState(LayersId aId) |
2413 | 0 | { |
2414 | 0 | MonitorAutoLock lock(*sIndirectLayerTreesLock); |
2415 | 0 | CompositorBridgeParent::LayerTreeState& lts = sIndirectLayerTrees[aId]; |
2416 | 0 | if (!lts.mParent) { |
2417 | 0 | PLUGINS_LOG("[%" PRIu64 "] layer tree compositor parent pointer is null", aId); |
2418 | 0 | return false; |
2419 | 0 | } |
2420 | 0 | |
2421 | 0 | // Check if this layer tree has received any shadow layer updates |
2422 | 0 | if (!lts.mUpdatedPluginDataAvailable) { |
2423 | 0 | PLUGINS_LOG("[%" PRIu64 "] no plugin data", aId); |
2424 | 0 | return false; |
2425 | 0 | } |
2426 | 0 | |
2427 | 0 | // pluginMetricsChanged tracks whether we need to send plugin update |
2428 | 0 | // data to the main thread. If we do we'll have to block composition, |
2429 | 0 | // which we want to avoid if at all possible. |
2430 | 0 | bool pluginMetricsChanged = false; |
2431 | 0 |
|
2432 | 0 | // Same layer tree checks |
2433 | 0 | if (mLastPluginUpdateLayerTreeId == aId) { |
2434 | 0 | // no plugin data and nothing has changed, bail. |
2435 | 0 | if (!mCachedPluginData.Length() && !lts.mPluginData.Length()) { |
2436 | 0 | PLUGINS_LOG("[%" PRIu64 "] no data, no changes", aId); |
2437 | 0 | return false; |
2438 | 0 | } |
2439 | 0 | |
2440 | 0 | if (mCachedPluginData.Length() == lts.mPluginData.Length()) { |
2441 | 0 | // check for plugin data changes |
2442 | 0 | for (uint32_t idx = 0; idx < lts.mPluginData.Length(); idx++) { |
2443 | 0 | if (!(mCachedPluginData[idx] == lts.mPluginData[idx])) { |
2444 | 0 | pluginMetricsChanged = true; |
2445 | 0 | break; |
2446 | 0 | } |
2447 | 0 | } |
2448 | 0 | } else { |
2449 | 0 | // array lengths don't match, need to update |
2450 | 0 | pluginMetricsChanged = true; |
2451 | 0 | } |
2452 | 0 | } else { |
2453 | 0 | // exchanging layer trees, we need to update |
2454 | 0 | pluginMetricsChanged = true; |
2455 | 0 | } |
2456 | 0 |
|
2457 | 0 | // Check if plugin windows are currently hidden due to scrolling |
2458 | 0 | if (mDeferPluginWindows) { |
2459 | 0 | PLUGINS_LOG("[%" PRIu64 "] suppressing", aId); |
2460 | 0 | return false; |
2461 | 0 | } |
2462 | 0 | |
2463 | 0 | // If the plugin windows were hidden but now are not, we need to force |
2464 | 0 | // update the metrics to make sure they are visible again. |
2465 | 0 | if (mPluginWindowsHidden) { |
2466 | 0 | PLUGINS_LOG("[%" PRIu64 "] re-showing", aId); |
2467 | 0 | mPluginWindowsHidden = false; |
2468 | 0 | pluginMetricsChanged = true; |
2469 | 0 | } |
2470 | 0 |
|
2471 | 0 | if (!lts.mPluginData.Length()) { |
2472 | 0 | // Don't hide plugins if the previous remote layer tree didn't contain any. |
2473 | 0 | if (!mCachedPluginData.Length()) { |
2474 | 0 | PLUGINS_LOG("[%" PRIu64 "] nothing to hide", aId); |
2475 | 0 | return false; |
2476 | 0 | } |
2477 | 0 | |
2478 | 0 | uintptr_t parentWidget = GetWidget()->GetWidgetKey(); |
2479 | 0 |
|
2480 | 0 | // We will pass through here in cases where the previous shadow layer |
2481 | 0 | // tree contained visible plugins and the new tree does not. All we need |
2482 | 0 | // to do here is hide the plugins for the old tree, so don't waste time |
2483 | 0 | // calculating clipping. |
2484 | 0 | mPluginsLayerOffset = nsIntPoint(0,0); |
2485 | 0 | mPluginsLayerVisibleRegion.SetEmpty(); |
2486 | 0 | Unused << lts.mParent->SendHideAllPlugins(parentWidget); |
2487 | 0 | lts.mUpdatedPluginDataAvailable = false; |
2488 | 0 | PLUGINS_LOG("[%" PRIu64 "] hide all", aId); |
2489 | 0 | } else { |
2490 | 0 | // Retrieve the offset and visible region of the layer that hosts |
2491 | 0 | // the plugins, CompositorBridgeChild needs these in calculating proper |
2492 | 0 | // plugin clipping. |
2493 | 0 | LayerTransactionParent* layerTree = lts.mLayerTree; |
2494 | 0 | Layer* contentRoot = layerTree->GetRoot(); |
2495 | 0 | if (contentRoot) { |
2496 | 0 | nsIntPoint offset; |
2497 | 0 | nsIntRegion visibleRegion; |
2498 | 0 | if (contentRoot->GetVisibleRegionRelativeToRootLayer(visibleRegion, |
2499 | 0 | &offset)) { |
2500 | 0 | // Check to see if these values have changed, if so we need to |
2501 | 0 | // update plugin window position within the window. |
2502 | 0 | if (!pluginMetricsChanged && |
2503 | 0 | mPluginsLayerVisibleRegion == visibleRegion && |
2504 | 0 | mPluginsLayerOffset == offset) { |
2505 | 0 | PLUGINS_LOG("[%" PRIu64 "] no change", aId); |
2506 | 0 | return false; |
2507 | 0 | } |
2508 | 0 | mPluginsLayerOffset = offset; |
2509 | 0 | mPluginsLayerVisibleRegion = visibleRegion; |
2510 | 0 | Unused << lts.mParent->SendUpdatePluginConfigurations( |
2511 | 0 | LayoutDeviceIntPoint::FromUnknownPoint(offset), |
2512 | 0 | LayoutDeviceIntRegion::FromUnknownRegion(visibleRegion), |
2513 | 0 | lts.mPluginData); |
2514 | 0 | lts.mUpdatedPluginDataAvailable = false; |
2515 | 0 | PLUGINS_LOG("[%" PRIu64 "] updated", aId); |
2516 | 0 | } else { |
2517 | 0 | PLUGINS_LOG("[%" PRIu64 "] no visibility data", aId); |
2518 | 0 | return false; |
2519 | 0 | } |
2520 | 0 | } else { |
2521 | 0 | PLUGINS_LOG("[%" PRIu64 "] no content root", aId); |
2522 | 0 | return false; |
2523 | 0 | } |
2524 | 0 | } |
2525 | 0 | |
2526 | 0 | mLastPluginUpdateLayerTreeId = aId; |
2527 | 0 | mCachedPluginData = lts.mPluginData; |
2528 | 0 | return true; |
2529 | 0 | } |
2530 | | |
2531 | | void |
2532 | | CompositorBridgeParent::ScheduleShowAllPluginWindows() |
2533 | 0 | { |
2534 | 0 | MOZ_ASSERT(CompositorLoop()); |
2535 | 0 | CompositorLoop()->PostTask( |
2536 | 0 | NewRunnableMethod("layers::CompositorBridgeParent::ShowAllPluginWindows", |
2537 | 0 | this, |
2538 | 0 | &CompositorBridgeParent::ShowAllPluginWindows)); |
2539 | 0 | } |
2540 | | |
2541 | | void |
2542 | | CompositorBridgeParent::ShowAllPluginWindows() |
2543 | 0 | { |
2544 | 0 | MOZ_ASSERT(!NS_IsMainThread()); |
2545 | 0 | mDeferPluginWindows = false; |
2546 | 0 | ScheduleComposition(); |
2547 | 0 | } |
2548 | | |
2549 | | void |
2550 | | CompositorBridgeParent::ScheduleHideAllPluginWindows() |
2551 | 0 | { |
2552 | 0 | MOZ_ASSERT(CompositorLoop()); |
2553 | 0 | CompositorLoop()->PostTask( |
2554 | 0 | NewRunnableMethod("layers::CompositorBridgeParent::HideAllPluginWindows", |
2555 | 0 | this, |
2556 | 0 | &CompositorBridgeParent::HideAllPluginWindows)); |
2557 | 0 | } |
2558 | | |
2559 | | void |
2560 | | CompositorBridgeParent::HideAllPluginWindows() |
2561 | 0 | { |
2562 | 0 | MOZ_ASSERT(!NS_IsMainThread()); |
2563 | 0 | // No plugins in the cache implies no plugins to manage |
2564 | 0 | // in this content. |
2565 | 0 | if (!mCachedPluginData.Length() || mDeferPluginWindows) { |
2566 | 0 | return; |
2567 | 0 | } |
2568 | 0 | |
2569 | 0 | uintptr_t parentWidget = GetWidget()->GetWidgetKey(); |
2570 | 0 |
|
2571 | 0 | mDeferPluginWindows = true; |
2572 | 0 | mPluginWindowsHidden = true; |
2573 | 0 |
|
2574 | | #if defined(XP_WIN) |
2575 | | // We will get an async reply that this has happened and then send hide. |
2576 | | mWaitForPluginsUntil = TimeStamp::Now() + mVsyncRate; |
2577 | | Unused << SendCaptureAllPlugins(parentWidget); |
2578 | | #else |
2579 | | Unused << SendHideAllPlugins(parentWidget); |
2580 | 0 | ScheduleComposition(); |
2581 | 0 | #endif |
2582 | 0 | } |
2583 | | #endif // #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) |
2584 | | |
2585 | | mozilla::ipc::IPCResult |
2586 | | CompositorBridgeParent::RecvAllPluginsCaptured() |
2587 | 0 | { |
2588 | | #if defined(XP_WIN) |
2589 | | mWaitForPluginsUntil = TimeStamp(); |
2590 | | mHaveBlockedForPlugins = false; |
2591 | | ForceComposeToTarget(nullptr); |
2592 | | Unused << SendHideAllPlugins(GetWidget()->GetWidgetKey()); |
2593 | | return IPC_OK(); |
2594 | | #else |
2595 | 0 | MOZ_ASSERT_UNREACHABLE( |
2596 | 0 | "CompositorBridgeParent::RecvAllPluginsCaptured calls unexpected."); |
2597 | 0 | return IPC_FAIL_NO_REASON(this); |
2598 | 0 | #endif |
2599 | 0 | } |
2600 | | |
2601 | | } // namespace layers |
2602 | | } // namespace mozilla |