/src/mozilla-central/gfx/layers/client/ClientLayerManager.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 "ClientLayerManager.h" |
8 | | #include "GeckoProfiler.h" // for AUTO_PROFILER_LABEL |
9 | | #include "gfxEnv.h" // for gfxEnv |
10 | | #include "gfxPrefs.h" // for gfxPrefs::LayersTile... |
11 | | #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
12 | | #include "mozilla/Hal.h" |
13 | | #include "mozilla/dom/TabChild.h" // for TabChild |
14 | | #include "mozilla/dom/TabGroup.h" // for TabGroup |
15 | | #include "mozilla/hal_sandbox/PHal.h" // for ScreenConfiguration |
16 | | #include "mozilla/layers/CompositableClient.h" |
17 | | #include "mozilla/layers/CompositorBridgeChild.h" // for CompositorBridgeChild |
18 | | #include "mozilla/layers/FrameUniformityData.h" |
19 | | #include "mozilla/layers/ISurfaceAllocator.h" |
20 | | #include "mozilla/layers/LayersMessages.h" // for EditReply, etc |
21 | | #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor |
22 | | #include "mozilla/layers/LayerTransactionChild.h" |
23 | | #include "mozilla/layers/PersistentBufferProvider.h" |
24 | | #include "mozilla/layers/SyncObject.h" |
25 | | #include "ClientReadbackLayer.h" // for ClientReadbackLayer |
26 | | #include "nsAString.h" |
27 | | #include "nsDisplayList.h" |
28 | | #include "nsIWidgetListener.h" |
29 | | #include "nsTArray.h" // for AutoTArray |
30 | | #include "nsXULAppAPI.h" // for XRE_GetProcessType, etc |
31 | | #include "TiledLayerBuffer.h" |
32 | | #include "FrameLayerBuilder.h" // for FrameLayerbuilder |
33 | | #ifdef MOZ_WIDGET_ANDROID |
34 | | #include "AndroidBridge.h" |
35 | | #include "LayerMetricsWrapper.h" |
36 | | #endif |
37 | | #ifdef XP_WIN |
38 | | #include "mozilla/gfx/DeviceManagerDx.h" |
39 | | #include "gfxDWriteFonts.h" |
40 | | #endif |
41 | | |
42 | | namespace mozilla { |
43 | | namespace layers { |
44 | | |
45 | | using namespace mozilla::gfx; |
46 | | |
47 | | ClientLayerManager::ClientLayerManager(nsIWidget* aWidget) |
48 | | : mPhase(PHASE_NONE) |
49 | | , mWidget(aWidget) |
50 | | , mPaintedLayerCallback(nullptr) |
51 | | , mPaintedLayerCallbackData(nullptr) |
52 | | , mLatestTransactionId{0} |
53 | | , mLastPaintTime(TimeDuration::Forever()) |
54 | | , mTargetRotation(ROTATION_0) |
55 | | , mRepeatTransaction(false) |
56 | | , mIsRepeatTransaction(false) |
57 | | , mTransactionIncomplete(false) |
58 | | , mCompositorMightResample(false) |
59 | | , mNeedsComposite(false) |
60 | | , mQueuedAsyncPaints(false) |
61 | | , mPaintSequenceNumber(0) |
62 | | , mForwarder(new ShadowLayerForwarder(this)) |
63 | 0 | { |
64 | 0 | MOZ_COUNT_CTOR(ClientLayerManager); |
65 | 0 | mMemoryPressureObserver = MemoryPressureObserver::Create(this); |
66 | 0 | } |
67 | | |
68 | | |
69 | | ClientLayerManager::~ClientLayerManager() |
70 | 0 | { |
71 | 0 | mMemoryPressureObserver->Unregister(); |
72 | 0 | ClearCachedResources(); |
73 | 0 | // Stop receiveing AsyncParentMessage at Forwarder. |
74 | 0 | // After the call, the message is directly handled by LayerTransactionChild. |
75 | 0 | // Basically this function should be called in ShadowLayerForwarder's |
76 | 0 | // destructor. But when the destructor is triggered by |
77 | 0 | // CompositorBridgeChild::Destroy(), the destructor can not handle it correctly. |
78 | 0 | // See Bug 1000525. |
79 | 0 | mForwarder->StopReceiveAsyncParentMessge(); |
80 | 0 | mRoot = nullptr; |
81 | 0 |
|
82 | 0 | MOZ_COUNT_DTOR(ClientLayerManager); |
83 | 0 | } |
84 | | |
85 | | void |
86 | | ClientLayerManager::Destroy() |
87 | 0 | { |
88 | 0 | // It's important to call ClearCachedResource before Destroy because the |
89 | 0 | // former will early-return if the later has already run. |
90 | 0 | ClearCachedResources(); |
91 | 0 | LayerManager::Destroy(); |
92 | 0 |
|
93 | 0 | if (mTransactionIdAllocator) { |
94 | 0 | // Make sure to notify the refresh driver just in case it's waiting on a |
95 | 0 | // pending transaction. Do this at the top of the event loop so we don't |
96 | 0 | // cause a paint to occur during compositor shutdown. |
97 | 0 | RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator; |
98 | 0 | TransactionId id = mLatestTransactionId; |
99 | 0 |
|
100 | 0 | RefPtr<Runnable> task = NS_NewRunnableFunction( |
101 | 0 | "TransactionIdAllocator::NotifyTransactionCompleted", |
102 | 0 | [allocator, id] () -> void { |
103 | 0 | allocator->NotifyTransactionCompleted(id); |
104 | 0 | }); |
105 | 0 | NS_DispatchToMainThread(task.forget()); |
106 | 0 | } |
107 | 0 |
|
108 | 0 | // Forget the widget pointer in case we outlive our owning widget. |
109 | 0 | mWidget = nullptr; |
110 | 0 | } |
111 | | |
112 | | TabGroup* |
113 | | ClientLayerManager::GetTabGroup() |
114 | 0 | { |
115 | 0 | if (mWidget) { |
116 | 0 | if (TabChild* tabChild = mWidget->GetOwningTabChild()) { |
117 | 0 | return tabChild->TabGroup(); |
118 | 0 | } |
119 | 0 | } |
120 | 0 | return nullptr; |
121 | 0 | } |
122 | | |
123 | | int32_t |
124 | | ClientLayerManager::GetMaxTextureSize() const |
125 | 0 | { |
126 | 0 | return mForwarder->GetMaxTextureSize(); |
127 | 0 | } |
128 | | |
129 | | void |
130 | | ClientLayerManager::SetDefaultTargetConfiguration(BufferMode aDoubleBuffering, |
131 | | ScreenRotation aRotation) |
132 | 0 | { |
133 | 0 | mTargetRotation = aRotation; |
134 | 0 | } |
135 | | |
136 | | void |
137 | | ClientLayerManager::SetRoot(Layer* aLayer) |
138 | 0 | { |
139 | 0 | if (mRoot != aLayer) { |
140 | 0 | // Have to hold the old root and its children in order to |
141 | 0 | // maintain the same view of the layer tree in this process as |
142 | 0 | // the parent sees. Otherwise layers can be destroyed |
143 | 0 | // mid-transaction and bad things can happen (v. bug 612573) |
144 | 0 | if (mRoot) { |
145 | 0 | Hold(mRoot); |
146 | 0 | } |
147 | 0 | mForwarder->SetRoot(Hold(aLayer)); |
148 | 0 | NS_ASSERTION(aLayer, "Root can't be null"); |
149 | 0 | NS_ASSERTION(aLayer->Manager() == this, "Wrong manager"); |
150 | 0 | NS_ASSERTION(InConstruction(), "Only allowed in construction phase"); |
151 | 0 | mRoot = aLayer; |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | | void |
156 | | ClientLayerManager::Mutated(Layer* aLayer) |
157 | 0 | { |
158 | 0 | LayerManager::Mutated(aLayer); |
159 | 0 |
|
160 | 0 | NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase"); |
161 | 0 | mForwarder->Mutated(Hold(aLayer)); |
162 | 0 | } |
163 | | |
164 | | void |
165 | | ClientLayerManager::MutatedSimple(Layer* aLayer) |
166 | 0 | { |
167 | 0 | LayerManager::MutatedSimple(aLayer); |
168 | 0 |
|
169 | 0 | NS_ASSERTION(InConstruction() || InDrawing(), "wrong phase"); |
170 | 0 | mForwarder->MutatedSimple(Hold(aLayer)); |
171 | 0 | } |
172 | | |
173 | | already_AddRefed<ReadbackLayer> |
174 | | ClientLayerManager::CreateReadbackLayer() |
175 | 0 | { |
176 | 0 | RefPtr<ReadbackLayer> layer = new ClientReadbackLayer(this); |
177 | 0 | return layer.forget(); |
178 | 0 | } |
179 | | |
180 | | bool |
181 | | ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget) |
182 | 0 | { |
183 | | #ifdef MOZ_DUMP_PAINTING |
184 | | // When we are dump painting, we expect to be able to read the contents of |
185 | | // compositable clients from previous paints inside this layer transaction |
186 | | // before we flush async paints in EndTransactionInternal. |
187 | | // So to work around this flush async paints now. |
188 | | if (gfxEnv::DumpPaint()) { |
189 | | FlushAsyncPaints(); |
190 | | } |
191 | | #endif |
192 | |
|
193 | 0 | MOZ_ASSERT(mForwarder, "ClientLayerManager::BeginTransaction without forwarder"); |
194 | 0 | if (!mForwarder->IPCOpen()) { |
195 | 0 | gfxCriticalNote << "ClientLayerManager::BeginTransaction with IPC channel down. GPU process may have died."; |
196 | 0 | return false; |
197 | 0 | } |
198 | 0 |
|
199 | 0 | mInTransaction = true; |
200 | 0 | mTransactionStart = TimeStamp::Now(); |
201 | 0 |
|
202 | 0 | #ifdef MOZ_LAYERS_HAVE_LOG |
203 | 0 | MOZ_LAYERS_LOG(("[----- BeginTransaction")); |
204 | 0 | Log(); |
205 | 0 | #endif |
206 | 0 |
|
207 | 0 | NS_ASSERTION(!InTransaction(), "Nested transactions not allowed"); |
208 | 0 | mPhase = PHASE_CONSTRUCTION; |
209 | 0 |
|
210 | 0 | MOZ_ASSERT(mKeepAlive.IsEmpty(), "uncommitted txn?"); |
211 | 0 |
|
212 | 0 | // If the last transaction was incomplete (a failed DoEmptyTransaction), |
213 | 0 | // don't signal a new transaction to ShadowLayerForwarder. Carry on adding |
214 | 0 | // to the previous transaction. |
215 | 0 | hal::ScreenOrientation orientation; |
216 | 0 | if (dom::TabChild* window = mWidget->GetOwningTabChild()) { |
217 | 0 | orientation = window->GetOrientation(); |
218 | 0 | } else { |
219 | 0 | hal::ScreenConfiguration currentConfig; |
220 | 0 | hal::GetCurrentScreenConfiguration(¤tConfig); |
221 | 0 | orientation = currentConfig.orientation(); |
222 | 0 | } |
223 | 0 | LayoutDeviceIntRect targetBounds = mWidget->GetNaturalBounds(); |
224 | 0 | targetBounds.MoveTo(0, 0); |
225 | 0 | mForwarder->BeginTransaction(targetBounds.ToUnknownRect(), mTargetRotation, |
226 | 0 | orientation); |
227 | 0 |
|
228 | 0 | // If we're drawing on behalf of a context with async pan/zoom |
229 | 0 | // enabled, then the entire buffer of painted layers might be |
230 | 0 | // composited (including resampling) asynchronously before we get |
231 | 0 | // a chance to repaint, so we have to ensure that it's all valid |
232 | 0 | // and not rotated. |
233 | 0 | // |
234 | 0 | // Desktop does not support async zoom yet, so we ignore this for those |
235 | 0 | // platforms. |
236 | | #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_UIKIT) |
237 | | if (mWidget && mWidget->GetOwningTabChild()) { |
238 | | mCompositorMightResample = AsyncPanZoomEnabled(); |
239 | | } |
240 | | #endif |
241 | |
|
242 | 0 | // If we have a non-default target, we need to let our shadow manager draw |
243 | 0 | // to it. This will happen at the end of the transaction. |
244 | 0 | if (aTarget && XRE_IsParentProcess()) { |
245 | 0 | mShadowTarget = aTarget; |
246 | 0 | } else { |
247 | 0 | NS_ASSERTION(!aTarget, |
248 | 0 | "Content-process ClientLayerManager::BeginTransactionWithTarget not supported"); |
249 | 0 | } |
250 | 0 |
|
251 | 0 | // If this is a new paint, increment the paint sequence number. |
252 | 0 | if (!mIsRepeatTransaction) { |
253 | 0 | // Increment the paint sequence number even if test logging isn't |
254 | 0 | // enabled in this process; it may be enabled in the parent process, |
255 | 0 | // and the parent process expects unique sequence numbers. |
256 | 0 | ++mPaintSequenceNumber; |
257 | 0 | if (gfxPrefs::APZTestLoggingEnabled()) { |
258 | 0 | mApzTestData.StartNewPaint(mPaintSequenceNumber); |
259 | 0 | } |
260 | 0 | } |
261 | 0 | return true; |
262 | 0 | } |
263 | | |
264 | | bool |
265 | | ClientLayerManager::BeginTransaction() |
266 | 0 | { |
267 | 0 | return BeginTransactionWithTarget(nullptr); |
268 | 0 | } |
269 | | |
270 | | bool |
271 | | ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback, |
272 | | void* aCallbackData, |
273 | | EndTransactionFlags) |
274 | 0 | { |
275 | 0 | // This just causes the compositor to check whether the GPU is done with its |
276 | 0 | // textures or not and unlock them if it is. This helps us avoid the case |
277 | 0 | // where we take a long time painting asynchronously, turn IPC back on at |
278 | 0 | // the end of that, and then have to wait for the compositor to to get into |
279 | 0 | // TiledLayerBufferComposite::UseTiles before getting a response. |
280 | 0 | if (mForwarder) { |
281 | 0 | mForwarder->UpdateTextureLocks(); |
282 | 0 | } |
283 | 0 |
|
284 | 0 | // Wait for any previous async paints to complete before starting to paint again. |
285 | 0 | // Do this outside the profiler and telemetry block so this doesn't count as time |
286 | 0 | // spent rasterizing. |
287 | 0 | { |
288 | 0 | PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::FlushRasterization); |
289 | 0 | FlushAsyncPaints(); |
290 | 0 | } |
291 | 0 |
|
292 | 0 | PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Rasterization); |
293 | 0 | AUTO_PROFILER_TRACING("Paint", "Rasterize"); |
294 | 0 |
|
295 | 0 | Maybe<TimeStamp> startTime; |
296 | 0 | if (gfxPrefs::LayersDrawFPS()) { |
297 | 0 | startTime = Some(TimeStamp::Now()); |
298 | 0 | } |
299 | 0 |
|
300 | 0 | AUTO_PROFILER_LABEL("ClientLayerManager::EndTransactionInternal", GRAPHICS); |
301 | 0 |
|
302 | 0 | #ifdef MOZ_LAYERS_HAVE_LOG |
303 | 0 | MOZ_LAYERS_LOG((" ----- (beginning paint)")); |
304 | 0 | Log(); |
305 | 0 | #endif |
306 | 0 |
|
307 | 0 | NS_ASSERTION(InConstruction(), "Should be in construction phase"); |
308 | 0 | mPhase = PHASE_DRAWING; |
309 | 0 |
|
310 | 0 | ClientLayer* root = ClientLayer::ToClientLayer(GetRoot()); |
311 | 0 |
|
312 | 0 | mTransactionIncomplete = false; |
313 | 0 | mQueuedAsyncPaints = false; |
314 | 0 |
|
315 | 0 | // Apply pending tree updates before recomputing effective |
316 | 0 | // properties. |
317 | 0 | GetRoot()->ApplyPendingUpdatesToSubtree(); |
318 | 0 |
|
319 | 0 | mPaintedLayerCallback = aCallback; |
320 | 0 | mPaintedLayerCallbackData = aCallbackData; |
321 | 0 |
|
322 | 0 | GetRoot()->ComputeEffectiveTransforms(Matrix4x4()); |
323 | 0 |
|
324 | 0 | // Skip the painting if the device is in device-reset status. |
325 | 0 | if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) { |
326 | 0 | if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) { |
327 | 0 | TimeStamp start = TimeStamp::Now(); |
328 | 0 | root->RenderLayer(); |
329 | 0 | mLastPaintTime = TimeStamp::Now() - start; |
330 | 0 | } else { |
331 | 0 | root->RenderLayer(); |
332 | 0 | } |
333 | 0 | } else { |
334 | 0 | gfxCriticalNote << "LayerManager::EndTransaction skip RenderLayer()."; |
335 | 0 | } |
336 | 0 |
|
337 | 0 | if (!mRepeatTransaction && !GetRoot()->GetInvalidRegion().IsEmpty()) { |
338 | 0 | GetRoot()->Mutated(); |
339 | 0 | } |
340 | 0 |
|
341 | 0 | if (!mIsRepeatTransaction) { |
342 | 0 | mAnimationReadyTime = TimeStamp::Now(); |
343 | 0 | GetRoot()->StartPendingAnimations(mAnimationReadyTime); |
344 | 0 | } |
345 | 0 |
|
346 | 0 | mPaintedLayerCallback = nullptr; |
347 | 0 | mPaintedLayerCallbackData = nullptr; |
348 | 0 |
|
349 | 0 | // Go back to the construction phase if the transaction isn't complete. |
350 | 0 | // Layout will update the layer tree and call EndTransaction(). |
351 | 0 | mPhase = mTransactionIncomplete ? PHASE_CONSTRUCTION : PHASE_NONE; |
352 | 0 |
|
353 | 0 | NS_ASSERTION(!aCallback || !mTransactionIncomplete, |
354 | 0 | "If callback is not null, transaction must be complete"); |
355 | 0 |
|
356 | 0 | if (gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) { |
357 | 0 | FrameLayerBuilder::InvalidateAllLayers(this); |
358 | 0 | } |
359 | 0 |
|
360 | 0 | if (startTime) { |
361 | 0 | PaintTiming& pt = mForwarder->GetPaintTiming(); |
362 | 0 | pt.rasterMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds(); |
363 | 0 | } |
364 | 0 |
|
365 | 0 | return !mTransactionIncomplete; |
366 | 0 | } |
367 | | |
368 | | void |
369 | | ClientLayerManager::StorePluginWidgetConfigurations(const nsTArray<nsIWidget::Configuration>& aConfigurations) |
370 | 0 | { |
371 | 0 | if (mForwarder) { |
372 | 0 | mForwarder->StorePluginWidgetConfigurations(aConfigurations); |
373 | 0 | } |
374 | 0 | } |
375 | | |
376 | | void |
377 | | ClientLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback, |
378 | | void* aCallbackData, |
379 | | EndTransactionFlags aFlags) |
380 | 0 | { |
381 | 0 | if (!mForwarder->IPCOpen()) { |
382 | 0 | mInTransaction = false; |
383 | 0 | return; |
384 | 0 | } |
385 | 0 | |
386 | 0 | if (mWidget) { |
387 | 0 | mWidget->PrepareWindowEffects(); |
388 | 0 | } |
389 | 0 | EndTransactionInternal(aCallback, aCallbackData, aFlags); |
390 | 0 | ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE)); |
391 | 0 |
|
392 | 0 | if (mRepeatTransaction) { |
393 | 0 | mRepeatTransaction = false; |
394 | 0 | mIsRepeatTransaction = true; |
395 | 0 |
|
396 | 0 | // BeginTransaction will reset the transaction start time, but we |
397 | 0 | // would like to keep the original time for telemetry purposes. |
398 | 0 | TimeStamp transactionStart = mTransactionStart; |
399 | 0 | if (BeginTransaction()) { |
400 | 0 | mTransactionStart = transactionStart; |
401 | 0 | ClientLayerManager::EndTransaction(aCallback, aCallbackData, aFlags); |
402 | 0 | } |
403 | 0 |
|
404 | 0 | mIsRepeatTransaction = false; |
405 | 0 | } else { |
406 | 0 | MakeSnapshotIfRequired(); |
407 | 0 | } |
408 | 0 |
|
409 | 0 | mInTransaction = false; |
410 | 0 | mTransactionStart = TimeStamp(); |
411 | 0 | } |
412 | | |
413 | | bool |
414 | | ClientLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) |
415 | 0 | { |
416 | 0 | mInTransaction = false; |
417 | 0 |
|
418 | 0 | if (!mRoot || !mForwarder->IPCOpen()) { |
419 | 0 | return false; |
420 | 0 | } |
421 | 0 | |
422 | 0 | if (!EndTransactionInternal(nullptr, nullptr, aFlags)) { |
423 | 0 | // Return without calling ForwardTransaction. This leaves the |
424 | 0 | // ShadowLayerForwarder transaction open; the following |
425 | 0 | // EndTransaction will complete it. |
426 | 0 | if (PaintThread::Get() && mQueuedAsyncPaints) { |
427 | 0 | PaintThread::Get()->QueueEndLayerTransaction(nullptr); |
428 | 0 | } |
429 | 0 | return false; |
430 | 0 | } |
431 | 0 | if (mWidget) { |
432 | 0 | mWidget->PrepareWindowEffects(); |
433 | 0 | } |
434 | 0 | ForwardTransaction(!(aFlags & END_NO_REMOTE_COMPOSITE)); |
435 | 0 | MakeSnapshotIfRequired(); |
436 | 0 | return true; |
437 | 0 | } |
438 | | |
439 | | CompositorBridgeChild * |
440 | | ClientLayerManager::GetRemoteRenderer() |
441 | 0 | { |
442 | 0 | if (!mWidget) { |
443 | 0 | return nullptr; |
444 | 0 | } |
445 | 0 | |
446 | 0 | return mWidget->GetRemoteRenderer(); |
447 | 0 | } |
448 | | |
449 | | CompositorBridgeChild* |
450 | | ClientLayerManager::GetCompositorBridgeChild() |
451 | 0 | { |
452 | 0 | if (!XRE_IsParentProcess() && !recordreplay::IsRecordingOrReplaying()) { |
453 | 0 | return CompositorBridgeChild::Get(); |
454 | 0 | } |
455 | 0 | return GetRemoteRenderer(); |
456 | 0 | } |
457 | | |
458 | | void |
459 | | ClientLayerManager::FlushAsyncPaints() |
460 | 0 | { |
461 | 0 | AUTO_PROFILER_LABEL("ClientLayerManager::FlushAsyncPaints", GRAPHICS); |
462 | 0 |
|
463 | 0 | CompositorBridgeChild* cbc = GetCompositorBridgeChild(); |
464 | 0 | if (cbc) { |
465 | 0 | cbc->FlushAsyncPaints(); |
466 | 0 | } |
467 | 0 | } |
468 | | |
469 | | void |
470 | | ClientLayerManager::ScheduleComposite() |
471 | 0 | { |
472 | 0 | mForwarder->ScheduleComposite(); |
473 | 0 | } |
474 | | |
475 | | void |
476 | | ClientLayerManager::DidComposite(TransactionId aTransactionId, |
477 | | const TimeStamp& aCompositeStart, |
478 | | const TimeStamp& aCompositeEnd) |
479 | 0 | { |
480 | 0 | if (!mWidget) { |
481 | 0 | // When recording/replaying this manager may have already been destroyed. |
482 | 0 | MOZ_ASSERT(recordreplay::IsRecordingOrReplaying()); |
483 | 0 | return; |
484 | 0 | } |
485 | 0 |
|
486 | 0 | // Notifying the observers may tick the refresh driver which can cause |
487 | 0 | // a lot of different things to happen that may affect the lifetime of |
488 | 0 | // this layer manager. So let's make sure this object stays alive until |
489 | 0 | // the end of the method invocation. |
490 | 0 | RefPtr<ClientLayerManager> selfRef = this; |
491 | 0 |
|
492 | 0 | // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow |
493 | 0 | // layers transaction. |
494 | 0 | if (aTransactionId.IsValid()) { |
495 | 0 | nsIWidgetListener *listener = mWidget->GetWidgetListener(); |
496 | 0 | if (listener) { |
497 | 0 | listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd); |
498 | 0 | } |
499 | 0 | listener = mWidget->GetAttachedWidgetListener(); |
500 | 0 | if (listener) { |
501 | 0 | listener->DidCompositeWindow(aTransactionId, aCompositeStart, aCompositeEnd); |
502 | 0 | } |
503 | 0 | if (mTransactionIdAllocator) { |
504 | 0 | mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId); |
505 | 0 | } |
506 | 0 | } |
507 | 0 |
|
508 | 0 | // These observers fire whether or not we were in a transaction. |
509 | 0 | for (size_t i = 0; i < mDidCompositeObservers.Length(); i++) { |
510 | 0 | mDidCompositeObservers[i]->DidComposite(); |
511 | 0 | } |
512 | 0 | } |
513 | | |
514 | | void |
515 | | ClientLayerManager::GetCompositorSideAPZTestData(APZTestData* aData) const |
516 | 0 | { |
517 | 0 | if (mForwarder->HasShadowManager()) { |
518 | 0 | if (!mForwarder->GetShadowManager()->SendGetAPZTestData(aData)) { |
519 | 0 | NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed"); |
520 | 0 | } |
521 | 0 | } |
522 | 0 | } |
523 | | |
524 | | void |
525 | | ClientLayerManager::SetTransactionIdAllocator(TransactionIdAllocator* aAllocator) |
526 | 0 | { |
527 | 0 | // When changing the refresh driver, the previous refresh driver may never |
528 | 0 | // receive updates of pending transactions it's waiting for. So clear the |
529 | 0 | // waiting state before assigning another refresh driver. |
530 | 0 | if (mTransactionIdAllocator && (aAllocator != mTransactionIdAllocator)) { |
531 | 0 | mTransactionIdAllocator->ClearPendingTransactions(); |
532 | 0 |
|
533 | 0 | // We should also reset the transaction id of the new allocator to previous |
534 | 0 | // allocator's last transaction id, so that completed transactions for |
535 | 0 | // previous allocator will be ignored and won't confuse the new allocator. |
536 | 0 | if (aAllocator) { |
537 | 0 | aAllocator->ResetInitialTransactionId(mTransactionIdAllocator->LastTransactionId()); |
538 | 0 | } |
539 | 0 | } |
540 | 0 |
|
541 | 0 | mTransactionIdAllocator = aAllocator; |
542 | 0 | } |
543 | | |
544 | | float |
545 | | ClientLayerManager::RequestProperty(const nsAString& aProperty) |
546 | 0 | { |
547 | 0 | if (mForwarder->HasShadowManager()) { |
548 | 0 | float value; |
549 | 0 | if (!mForwarder->GetShadowManager()->SendRequestProperty(nsString(aProperty), &value)) { |
550 | 0 | NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed"); |
551 | 0 | } |
552 | 0 | return value; |
553 | 0 | } |
554 | 0 | return -1; |
555 | 0 | } |
556 | | |
557 | | void |
558 | | ClientLayerManager::StartNewRepaintRequest(SequenceNumber aSequenceNumber) |
559 | 0 | { |
560 | 0 | if (gfxPrefs::APZTestLoggingEnabled()) { |
561 | 0 | mApzTestData.StartNewRepaintRequest(aSequenceNumber); |
562 | 0 | } |
563 | 0 | } |
564 | | |
565 | | void |
566 | | ClientLayerManager::GetFrameUniformity(FrameUniformityData* aOutData) |
567 | 0 | { |
568 | 0 | MOZ_ASSERT(XRE_IsParentProcess(), "Frame Uniformity only supported in parent process"); |
569 | 0 |
|
570 | 0 | if (HasShadowManager()) { |
571 | 0 | CompositorBridgeChild* child = GetRemoteRenderer(); |
572 | 0 | child->SendGetFrameUniformity(aOutData); |
573 | 0 | return; |
574 | 0 | } |
575 | 0 | |
576 | 0 | return LayerManager::GetFrameUniformity(aOutData); |
577 | 0 | } |
578 | | |
579 | | void |
580 | | ClientLayerManager::MakeSnapshotIfRequired() |
581 | 0 | { |
582 | 0 | if (!mShadowTarget) { |
583 | 0 | return; |
584 | 0 | } |
585 | 0 | if (mWidget) { |
586 | 0 | if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) { |
587 | 0 | // The compositor doesn't draw to a different sized surface |
588 | 0 | // when there's a rotation. Instead we rotate the result |
589 | 0 | // when drawing into dt |
590 | 0 | LayoutDeviceIntRect outerBounds = mWidget->GetBounds(); |
591 | 0 |
|
592 | 0 | IntRect bounds = ToOutsideIntRect(mShadowTarget->GetClipExtents()); |
593 | 0 | if (mTargetRotation) { |
594 | 0 | bounds = |
595 | 0 | RotateRect(bounds, outerBounds.ToUnknownRect(), mTargetRotation); |
596 | 0 | } |
597 | 0 |
|
598 | 0 | SurfaceDescriptor inSnapshot; |
599 | 0 | if (!bounds.IsEmpty() && |
600 | 0 | mForwarder->AllocSurfaceDescriptor(bounds.Size(), |
601 | 0 | gfxContentType::COLOR_ALPHA, |
602 | 0 | &inSnapshot)) { |
603 | 0 |
|
604 | 0 | // Make a copy of |inSnapshot| because the call to send it over IPC |
605 | 0 | // will call forget() on the Shmem inside, and zero it out. |
606 | 0 | SurfaceDescriptor outSnapshot = inSnapshot; |
607 | 0 |
|
608 | 0 | if (remoteRenderer->SendMakeSnapshot(inSnapshot, bounds)) { |
609 | 0 | RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(outSnapshot); |
610 | 0 | DrawTarget* dt = mShadowTarget->GetDrawTarget(); |
611 | 0 |
|
612 | 0 | Rect dstRect(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height()); |
613 | 0 | Rect srcRect(0, 0, bounds.Width(), bounds.Height()); |
614 | 0 |
|
615 | 0 | gfx::Matrix rotate = |
616 | 0 | ComputeTransformForUnRotation(outerBounds.ToUnknownRect(), |
617 | 0 | mTargetRotation); |
618 | 0 |
|
619 | 0 | gfx::Matrix oldMatrix = dt->GetTransform(); |
620 | 0 | dt->SetTransform(rotate * oldMatrix); |
621 | 0 | dt->DrawSurface(surf, dstRect, srcRect, |
622 | 0 | DrawSurfaceOptions(), |
623 | 0 | DrawOptions(1.0f, CompositionOp::OP_OVER)); |
624 | 0 | dt->SetTransform(oldMatrix); |
625 | 0 | } |
626 | 0 | mForwarder->DestroySurfaceDescriptor(&outSnapshot); |
627 | 0 | } |
628 | 0 | } |
629 | 0 | } |
630 | 0 | mShadowTarget = nullptr; |
631 | 0 | } |
632 | | |
633 | | void |
634 | | ClientLayerManager::FlushRendering() |
635 | 0 | { |
636 | 0 | if (mWidget) { |
637 | 0 | if (CompositorBridgeChild* remoteRenderer = mWidget->GetRemoteRenderer()) { |
638 | 0 | if (mWidget->SynchronouslyRepaintOnResize() || gfxPrefs::LayersForceSynchronousResize()) { |
639 | 0 | remoteRenderer->SendFlushRendering(); |
640 | 0 | } else { |
641 | 0 | remoteRenderer->SendFlushRenderingAsync(); |
642 | 0 | } |
643 | 0 | } |
644 | 0 | } |
645 | 0 | } |
646 | | |
647 | | void |
648 | | ClientLayerManager::WaitOnTransactionProcessed() |
649 | 0 | { |
650 | 0 | CompositorBridgeChild* remoteRenderer = GetCompositorBridgeChild(); |
651 | 0 | if (remoteRenderer) { |
652 | 0 | remoteRenderer->SendWaitOnTransactionProcessed(); |
653 | 0 | } |
654 | 0 | } |
655 | | void |
656 | | ClientLayerManager::UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier& aNewIdentifier) |
657 | 0 | { |
658 | 0 | mForwarder->IdentifyTextureHost(aNewIdentifier); |
659 | 0 | } |
660 | | |
661 | | void |
662 | | ClientLayerManager::SendInvalidRegion(const nsIntRegion& aRegion) |
663 | 0 | { |
664 | 0 | if (mWidget) { |
665 | 0 | if (CompositorBridgeChild* remoteRenderer = mWidget->GetRemoteRenderer()) { |
666 | 0 | remoteRenderer->SendNotifyRegionInvalidated(aRegion); |
667 | 0 | } |
668 | 0 | } |
669 | 0 | } |
670 | | |
671 | | uint32_t |
672 | | ClientLayerManager::StartFrameTimeRecording(int32_t aBufferSize) |
673 | 0 | { |
674 | 0 | CompositorBridgeChild* renderer = GetRemoteRenderer(); |
675 | 0 | if (renderer) { |
676 | 0 | uint32_t startIndex; |
677 | 0 | renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex); |
678 | 0 | return startIndex; |
679 | 0 | } |
680 | 0 | return -1; |
681 | 0 | } |
682 | | |
683 | | void |
684 | | ClientLayerManager::StopFrameTimeRecording(uint32_t aStartIndex, |
685 | | nsTArray<float>& aFrameIntervals) |
686 | 0 | { |
687 | 0 | CompositorBridgeChild* renderer = GetRemoteRenderer(); |
688 | 0 | if (renderer) { |
689 | 0 | renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals); |
690 | 0 | } |
691 | 0 | } |
692 | | |
693 | | void |
694 | | ClientLayerManager::ForwardTransaction(bool aScheduleComposite) |
695 | 0 | { |
696 | 0 | AUTO_PROFILER_TRACING("Paint", "ForwardTransaction"); |
697 | 0 | TimeStamp start = TimeStamp::Now(); |
698 | 0 |
|
699 | 0 | // Skip the synchronization for buffer since we also skip the painting during |
700 | 0 | // device-reset status. With OMTP, we have to wait for async paints |
701 | 0 | // before we synchronize and it's done on the paint thread. |
702 | 0 | RefPtr<SyncObjectClient> syncObject = nullptr; |
703 | 0 | if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) { |
704 | 0 | if (mForwarder->GetSyncObject() && |
705 | 0 | mForwarder->GetSyncObject()->IsSyncObjectValid()) { |
706 | 0 | syncObject = mForwarder->GetSyncObject(); |
707 | 0 | } |
708 | 0 | } |
709 | 0 |
|
710 | 0 | // If there were async paints queued, then we need to notify the paint thread |
711 | 0 | // that we finished queuing async paints so it can schedule a runnable after |
712 | 0 | // all async painting is finished to do a texture sync and unblock the main |
713 | 0 | // thread if it is waiting before doing a new layer transaction. |
714 | 0 | if (mQueuedAsyncPaints) { |
715 | 0 | MOZ_ASSERT(PaintThread::Get()); |
716 | 0 | PaintThread::Get()->QueueEndLayerTransaction(syncObject); |
717 | 0 | } else if (syncObject) { |
718 | 0 | syncObject->Synchronize(); |
719 | 0 | } |
720 | 0 |
|
721 | 0 | mPhase = PHASE_FORWARD; |
722 | 0 |
|
723 | 0 | mLatestTransactionId = mTransactionIdAllocator->GetTransactionId(!mIsRepeatTransaction); |
724 | 0 | TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart(); |
725 | 0 |
|
726 | 0 | if (gfxPrefs::AlwaysPaint() && XRE_IsContentProcess()) { |
727 | 0 | mForwarder->SendPaintTime(mLatestTransactionId, mLastPaintTime); |
728 | 0 | } |
729 | 0 |
|
730 | 0 | // forward this transaction's changeset to our LayerManagerComposite |
731 | 0 | bool sent = false; |
732 | 0 | bool ok = mForwarder->EndTransaction( |
733 | 0 | mRegionToClear, mLatestTransactionId, aScheduleComposite, |
734 | 0 | mPaintSequenceNumber, mIsRepeatTransaction, |
735 | 0 | refreshStart, mTransactionStart, |
736 | 0 | &sent); |
737 | 0 | if (ok) { |
738 | 0 | if (sent) { |
739 | 0 | mNeedsComposite = false; |
740 | 0 | } |
741 | 0 | } else if (HasShadowManager()) { |
742 | 0 | NS_WARNING("failed to forward Layers transaction"); |
743 | 0 | } |
744 | 0 |
|
745 | 0 | if (!sent) { |
746 | 0 | // Clear the transaction id so that it doesn't get returned |
747 | 0 | // unless we forwarded to somewhere that doesn't actually |
748 | 0 | // have a compositor. |
749 | 0 | mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId); |
750 | 0 | } |
751 | 0 |
|
752 | 0 | mPhase = PHASE_NONE; |
753 | 0 |
|
754 | 0 | // this may result in Layers being deleted, which results in |
755 | 0 | // PLayer::Send__delete__() and DeallocShmem() |
756 | 0 | mKeepAlive.Clear(); |
757 | 0 |
|
758 | 0 | TabChild* window = mWidget ? mWidget->GetOwningTabChild() : nullptr; |
759 | 0 | if (window) { |
760 | 0 | TimeStamp end = TimeStamp::Now(); |
761 | 0 | window->DidRequestComposite(start, end); |
762 | 0 | } |
763 | 0 | } |
764 | | |
765 | | ShadowableLayer* |
766 | | ClientLayerManager::Hold(Layer* aLayer) |
767 | 0 | { |
768 | 0 | MOZ_ASSERT(HasShadowManager(), |
769 | 0 | "top-level tree, no shadow tree to remote to"); |
770 | 0 |
|
771 | 0 | ShadowableLayer* shadowable = ClientLayer::ToClientLayer(aLayer); |
772 | 0 | MOZ_ASSERT(shadowable, "trying to remote an unshadowable layer"); |
773 | 0 |
|
774 | 0 | mKeepAlive.AppendElement(aLayer); |
775 | 0 | return shadowable; |
776 | 0 | } |
777 | | |
778 | | bool |
779 | | ClientLayerManager::IsCompositingCheap() |
780 | 0 | { |
781 | 0 | // Whether compositing is cheap depends on the parent backend. |
782 | 0 | return mForwarder->mShadowManager && |
783 | 0 | LayerManager::IsCompositingCheap(mForwarder->GetCompositorBackendType()); |
784 | 0 | } |
785 | | |
786 | | bool |
787 | | ClientLayerManager::AreComponentAlphaLayersEnabled() |
788 | 0 | { |
789 | 0 | return GetCompositorBackendType() != LayersBackend::LAYERS_BASIC && |
790 | 0 | AsShadowForwarder()->SupportsComponentAlpha() && |
791 | 0 | LayerManager::AreComponentAlphaLayersEnabled(); |
792 | 0 | } |
793 | | |
794 | | void |
795 | | ClientLayerManager::SetIsFirstPaint() |
796 | 0 | { |
797 | 0 | mForwarder->SetIsFirstPaint(); |
798 | 0 | } |
799 | | |
800 | | void |
801 | | ClientLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget) |
802 | 0 | { |
803 | 0 | mForwarder->SetFocusTarget(aFocusTarget); |
804 | 0 | } |
805 | | |
806 | | void |
807 | | ClientLayerManager::ClearCachedResources(Layer* aSubtree) |
808 | 0 | { |
809 | 0 | if (mDestroyed) { |
810 | 0 | // ClearCachedResource was already called by ClientLayerManager::Destroy |
811 | 0 | return; |
812 | 0 | } |
813 | 0 | MOZ_ASSERT(!HasShadowManager() || !aSubtree); |
814 | 0 | mForwarder->ClearCachedResources(); |
815 | 0 | if (aSubtree) { |
816 | 0 | ClearLayer(aSubtree); |
817 | 0 | } else if (mRoot) { |
818 | 0 | ClearLayer(mRoot); |
819 | 0 | } |
820 | 0 | } |
821 | | |
822 | | void |
823 | | ClientLayerManager::OnMemoryPressure(MemoryPressureReason aWhy) |
824 | 0 | { |
825 | 0 | if (mRoot) { |
826 | 0 | HandleMemoryPressureLayer(mRoot); |
827 | 0 | } |
828 | 0 |
|
829 | 0 | if (GetCompositorBridgeChild()) { |
830 | 0 | GetCompositorBridgeChild()->HandleMemoryPressure(); |
831 | 0 | } |
832 | 0 | } |
833 | | |
834 | | void |
835 | | ClientLayerManager::ClearLayer(Layer* aLayer) |
836 | 0 | { |
837 | 0 | aLayer->ClearCachedResources(); |
838 | 0 | for (Layer* child = aLayer->GetFirstChild(); child; |
839 | 0 | child = child->GetNextSibling()) { |
840 | 0 | ClearLayer(child); |
841 | 0 | } |
842 | 0 | } |
843 | | |
844 | | void |
845 | | ClientLayerManager::HandleMemoryPressureLayer(Layer* aLayer) |
846 | 0 | { |
847 | 0 | ClientLayer::ToClientLayer(aLayer)->HandleMemoryPressure(); |
848 | 0 | for (Layer* child = aLayer->GetFirstChild(); child; |
849 | 0 | child = child->GetNextSibling()) { |
850 | 0 | HandleMemoryPressureLayer(child); |
851 | 0 | } |
852 | 0 | } |
853 | | |
854 | | void |
855 | | ClientLayerManager::GetBackendName(nsAString& aName) |
856 | 0 | { |
857 | 0 | switch (mForwarder->GetCompositorBackendType()) { |
858 | 0 | case LayersBackend::LAYERS_NONE: aName.AssignLiteral("None"); return; |
859 | 0 | case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return; |
860 | 0 | case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return; |
861 | 0 | case LayersBackend::LAYERS_D3D11: { |
862 | | #ifdef XP_WIN |
863 | | if (DeviceManagerDx::Get()->IsWARP()) { |
864 | | aName.AssignLiteral("Direct3D 11 WARP"); |
865 | | } else { |
866 | | aName.AssignLiteral("Direct3D 11"); |
867 | | } |
868 | | #endif |
869 | | return; |
870 | 0 | } |
871 | 0 | default: MOZ_CRASH("Invalid backend"); |
872 | 0 | } |
873 | 0 | } |
874 | | |
875 | | bool |
876 | | ClientLayerManager::AsyncPanZoomEnabled() const |
877 | 0 | { |
878 | 0 | return mWidget && mWidget->AsyncPanZoomEnabled(); |
879 | 0 | } |
880 | | |
881 | | void |
882 | | ClientLayerManager::SetLayersObserverEpoch(LayersObserverEpoch aEpoch) |
883 | 0 | { |
884 | 0 | mForwarder->SetLayersObserverEpoch(aEpoch); |
885 | 0 | } |
886 | | |
887 | | void |
888 | | ClientLayerManager::AddDidCompositeObserver(DidCompositeObserver* aObserver) |
889 | 0 | { |
890 | 0 | if (!mDidCompositeObservers.Contains(aObserver)) { |
891 | 0 | mDidCompositeObservers.AppendElement(aObserver); |
892 | 0 | } |
893 | 0 | } |
894 | | |
895 | | void |
896 | | ClientLayerManager::RemoveDidCompositeObserver(DidCompositeObserver* aObserver) |
897 | 0 | { |
898 | 0 | mDidCompositeObservers.RemoveElement(aObserver); |
899 | 0 | } |
900 | | |
901 | | already_AddRefed<PersistentBufferProvider> |
902 | | ClientLayerManager::CreatePersistentBufferProvider(const gfx::IntSize& aSize, |
903 | | gfx::SurfaceFormat aFormat) |
904 | 0 | { |
905 | 0 | // Don't use a shared buffer provider if compositing is considered "not cheap" |
906 | 0 | // because the canvas will most likely be flattened into a thebes layer instead |
907 | 0 | // of being sent to the compositor, in which case rendering into shared memory |
908 | 0 | // is wasteful. |
909 | 0 | if (IsCompositingCheap() && |
910 | 0 | gfxPrefs::PersistentBufferProviderSharedEnabled()) { |
911 | 0 | RefPtr<PersistentBufferProvider> provider |
912 | 0 | = PersistentBufferProviderShared::Create(aSize, aFormat, AsShadowForwarder()); |
913 | 0 | if (provider) { |
914 | 0 | return provider.forget(); |
915 | 0 | } |
916 | 0 | } |
917 | 0 | |
918 | 0 | return LayerManager::CreatePersistentBufferProvider(aSize, aFormat); |
919 | 0 | } |
920 | | |
921 | | |
922 | | ClientLayer::~ClientLayer() |
923 | 0 | { |
924 | 0 | MOZ_COUNT_DTOR(ClientLayer); |
925 | 0 | } |
926 | | |
927 | | } // namespace layers |
928 | | } // namespace mozilla |