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 "WebRenderLayerManager.h"
8
9 #include "Layers.h"
10
11 #include "GeckoProfiler.h"
12 #include "mozilla/StaticPrefs_apz.h"
13 #include "mozilla/StaticPrefs_layers.h"
14 #include "mozilla/dom/BrowserChild.h"
15 #include "mozilla/gfx/DrawEventRecorder.h"
16 #include "mozilla/gfx/gfxVars.h"
17 #include "mozilla/layers/CompositorBridgeChild.h"
18 #include "mozilla/layers/StackingContextHelper.h"
19 #include "mozilla/layers/TextureClient.h"
20 #include "mozilla/layers/TransactionIdAllocator.h"
21 #include "mozilla/layers/WebRenderBridgeChild.h"
22 #include "mozilla/layers/UpdateImageHelper.h"
23 #include "nsDisplayList.h"
24 #include "nsLayoutUtils.h"
25 #include "WebRenderCanvasRenderer.h"
26 #include "LayerUserData.h"
27
28 #ifdef XP_WIN
29 # include "gfxDWriteFonts.h"
30 # include "mozilla/WindowsProcessMitigations.h"
31 #endif
32
33 namespace mozilla {
34
35 using namespace gfx;
36
37 namespace layers {
38
WebRenderLayerManager(nsIWidget * aWidget)39 WebRenderLayerManager::WebRenderLayerManager(nsIWidget* aWidget)
40 : mWidget(aWidget),
41 mLatestTransactionId{0},
42 mNeedsComposite(false),
43 mIsFirstPaint(false),
44 mDestroyed(false),
45 mTarget(nullptr),
46 mPaintSequenceNumber(0),
47 mWebRenderCommandBuilder(this) {
48 MOZ_COUNT_CTOR(WebRenderLayerManager);
49 mStateManager.mLayerManager = this;
50
51 if (XRE_IsContentProcess() &&
52 StaticPrefs::gfx_webrender_enable_item_cache_AtStartup()) {
53 static const size_t kInitialCacheSize = 1024;
54 static const size_t kMaximumCacheSize = 10240;
55
56 mDisplayItemCache.SetCapacity(kInitialCacheSize, kMaximumCacheSize);
57 }
58 }
59
AsKnowsCompositor()60 KnowsCompositor* WebRenderLayerManager::AsKnowsCompositor() { return mWrChild; }
61
Initialize(PCompositorBridgeChild * aCBChild,wr::PipelineId aLayersId,TextureFactoryIdentifier * aTextureFactoryIdentifier,nsCString & aError)62 bool WebRenderLayerManager::Initialize(
63 PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId,
64 TextureFactoryIdentifier* aTextureFactoryIdentifier, nsCString& aError) {
65 MOZ_ASSERT(mWrChild == nullptr);
66 MOZ_ASSERT(aTextureFactoryIdentifier);
67
68 // When we fail to initialize WebRender, it is useful to know if it has ever
69 // succeeded, or if this is the first attempt.
70 static bool hasInitialized = false;
71
72 WindowKind windowKind;
73 if (mWidget->WindowType() != eWindowType_popup) {
74 windowKind = WindowKind::MAIN;
75 } else {
76 windowKind = WindowKind::SECONDARY;
77 }
78
79 LayoutDeviceIntSize size = mWidget->GetClientSize();
80 // Check widget size
81 if (size.width < 0 || size.width > wr::MAX_RENDER_TASK_SIZE ||
82 size.height < 0 || size.height > wr::MAX_RENDER_TASK_SIZE) {
83 gfxCriticalNoteOnce << "Widget size is not valid " << size
84 << " isParent: " << XRE_IsParentProcess();
85 }
86
87 PWebRenderBridgeChild* bridge =
88 aCBChild->SendPWebRenderBridgeConstructor(aLayersId, size, windowKind);
89 if (!bridge) {
90 // This should only fail if we attempt to access a layer we don't have
91 // permission for, or more likely, the GPU process crashed again during
92 // reinitialization. We can expect to be notified again to reinitialize
93 // (which may or may not be using WebRender).
94 gfxCriticalNote << "Failed to create WebRenderBridgeChild.";
95 aError.Assign(hasInitialized
96 ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL_POST"_ns
97 : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL_FIRST"_ns);
98 return false;
99 }
100
101 TextureFactoryIdentifier textureFactoryIdentifier;
102 wr::MaybeIdNamespace idNamespace;
103 // Sync ipc
104 if (!bridge->SendEnsureConnected(&textureFactoryIdentifier, &idNamespace,
105 &aError)) {
106 gfxCriticalNote << "Failed as lost WebRenderBridgeChild.";
107 aError.Assign(hasInitialized
108 ? "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_POST"_ns
109 : "FEATURE_FAILURE_WEBRENDER_INITIALIZE_SYNC_FIRST"_ns);
110 return false;
111 }
112
113 if (textureFactoryIdentifier.mParentBackend == LayersBackend::LAYERS_NONE ||
114 idNamespace.isNothing()) {
115 gfxCriticalNote << "Failed to connect WebRenderBridgeChild.";
116 aError.Append(hasInitialized ? "_POST"_ns : "_FIRST"_ns);
117 return false;
118 }
119
120 mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
121 WrBridge()->SetWebRenderLayerManager(this);
122 WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
123 WrBridge()->SetNamespace(idNamespace.ref());
124 *aTextureFactoryIdentifier = textureFactoryIdentifier;
125
126 mDLBuilder = MakeUnique<wr::DisplayListBuilder>(
127 WrBridge()->GetPipeline(), WrBridge()->GetWebRenderBackend());
128
129 hasInitialized = true;
130 return true;
131 }
132
Destroy()133 void WebRenderLayerManager::Destroy() { DoDestroy(/* aIsSync */ false); }
134
DoDestroy(bool aIsSync)135 void WebRenderLayerManager::DoDestroy(bool aIsSync) {
136 MOZ_ASSERT(NS_IsMainThread());
137
138 if (IsDestroyed()) {
139 return;
140 }
141
142 mDLBuilder = nullptr;
143 mUserData.Destroy();
144 mPartialPrerenderedAnimations.Clear();
145
146 mStateManager.Destroy();
147
148 if (WrBridge()) {
149 WrBridge()->Destroy(aIsSync);
150 }
151
152 mWebRenderCommandBuilder.Destroy();
153
154 if (mTransactionIdAllocator) {
155 // Make sure to notify the refresh driver just in case it's waiting on a
156 // pending transaction. Do this at the top of the event loop so we don't
157 // cause a paint to occur during compositor shutdown.
158 RefPtr<TransactionIdAllocator> allocator = mTransactionIdAllocator;
159 TransactionId id = mLatestTransactionId;
160
161 RefPtr<Runnable> task = NS_NewRunnableFunction(
162 "TransactionIdAllocator::NotifyTransactionCompleted",
163 [allocator, id]() -> void {
164 allocator->ClearPendingTransactions();
165 allocator->NotifyTransactionCompleted(id);
166 });
167 NS_DispatchToMainThread(task.forget());
168 }
169
170 // Forget the widget pointer in case we outlive our owning widget.
171 mWidget = nullptr;
172 mDestroyed = true;
173 }
174
~WebRenderLayerManager()175 WebRenderLayerManager::~WebRenderLayerManager() {
176 Destroy();
177 MOZ_COUNT_DTOR(WebRenderLayerManager);
178 }
179
GetCompositorBridgeChild()180 CompositorBridgeChild* WebRenderLayerManager::GetCompositorBridgeChild() {
181 return WrBridge()->GetCompositorBridgeChild();
182 }
183
GetBackendName(nsAString & name)184 void WebRenderLayerManager::GetBackendName(nsAString& name) {
185 if (WrBridge()->UsingSoftwareWebRenderD3D11()) {
186 name.AssignLiteral("WebRender (Software D3D11)");
187 } else if (WrBridge()->UsingSoftwareWebRenderOpenGL()) {
188 name.AssignLiteral("WebRender (Software OpenGL)");
189 } else if (WrBridge()->UsingSoftwareWebRender()) {
190 name.AssignLiteral("WebRender (Software)");
191 } else {
192 name.AssignLiteral("WebRender");
193 }
194 }
195
StartFrameTimeRecording(int32_t aBufferSize)196 uint32_t WebRenderLayerManager::StartFrameTimeRecording(int32_t aBufferSize) {
197 CompositorBridgeChild* renderer = GetCompositorBridgeChild();
198 if (renderer) {
199 uint32_t startIndex;
200 renderer->SendStartFrameTimeRecording(aBufferSize, &startIndex);
201 return startIndex;
202 }
203 return -1;
204 }
205
StopFrameTimeRecording(uint32_t aStartIndex,nsTArray<float> & aFrameIntervals)206 void WebRenderLayerManager::StopFrameTimeRecording(
207 uint32_t aStartIndex, nsTArray<float>& aFrameIntervals) {
208 CompositorBridgeChild* renderer = GetCompositorBridgeChild();
209 if (renderer) {
210 renderer->SendStopFrameTimeRecording(aStartIndex, &aFrameIntervals);
211 }
212 }
213
TakeCompositionPayloads(nsTArray<CompositionPayload> & aPayloads)214 void WebRenderLayerManager::TakeCompositionPayloads(
215 nsTArray<CompositionPayload>& aPayloads) {
216 aPayloads.Clear();
217
218 std::swap(mPayload, aPayloads);
219 }
220
BeginTransactionWithTarget(gfxContext * aTarget,const nsCString & aURL)221 bool WebRenderLayerManager::BeginTransactionWithTarget(gfxContext* aTarget,
222 const nsCString& aURL) {
223 mTarget = aTarget;
224 return BeginTransaction(aURL);
225 }
226
BeginTransaction(const nsCString & aURL)227 bool WebRenderLayerManager::BeginTransaction(const nsCString& aURL) {
228 if (!WrBridge()->IPCOpen()) {
229 gfxCriticalNote << "IPC Channel is already torn down unexpectedly\n";
230 return false;
231 }
232
233 mTransactionStart = TimeStamp::Now();
234 mURL = aURL;
235
236 // Increment the paint sequence number even if test logging isn't
237 // enabled in this process; it may be enabled in the parent process,
238 // and the parent process expects unique sequence numbers.
239 ++mPaintSequenceNumber;
240 if (StaticPrefs::apz_test_logging_enabled()) {
241 mApzTestData.StartNewPaint(mPaintSequenceNumber);
242 }
243 return true;
244 }
245
EndEmptyTransaction(EndTransactionFlags aFlags)246 bool WebRenderLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags) {
247 // If we haven't sent a display list (since creation or since the last time we
248 // sent ClearDisplayList to the parent) then we can't do an empty transaction
249 // because the parent doesn't have a display list for us and we need to send a
250 // display list first.
251 if (!WrBridge()->GetSentDisplayList()) {
252 return false;
253 }
254
255 mDisplayItemCache.SkipWaitingForPartialDisplayList();
256
257 // Since we don't do repeat transactions right now, just set the time
258 mAnimationReadyTime = TimeStamp::Now();
259
260 mLatestTransactionId =
261 mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
262
263 if (aFlags & EndTransactionFlags::END_NO_COMPOSITE &&
264 !mWebRenderCommandBuilder.NeedsEmptyTransaction()) {
265 if (mPendingScrollUpdates.IsEmpty()) {
266 MOZ_ASSERT(!mTarget);
267 WrBridge()->SendSetFocusTarget(mFocusTarget);
268 // Revoke TransactionId to trigger next paint.
269 mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
270 mLatestTransactionId = mLatestTransactionId.Prev();
271 return true;
272 }
273 }
274
275 LayoutDeviceIntSize size = mWidget->GetClientSize();
276 WrBridge()->BeginTransaction();
277
278 mWebRenderCommandBuilder.EmptyTransaction();
279
280 // Get the time of when the refresh driver start its tick (if available),
281 // otherwise use the time of when LayerManager::BeginTransaction was called.
282 TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
283 if (!refreshStart) {
284 refreshStart = mTransactionStart;
285 }
286
287 // Skip the synchronization for buffer since we also skip the painting during
288 // device-reset status.
289 if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
290 if (WrBridge()->GetSyncObject() &&
291 WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
292 WrBridge()->GetSyncObject()->Synchronize();
293 }
294 }
295
296 GetCompositorBridgeChild()->EndCanvasTransaction();
297
298 Maybe<TransactionData> transactionData;
299 if (mStateManager.mAsyncResourceUpdates || !mPendingScrollUpdates.IsEmpty() ||
300 WrBridge()->HasWebRenderParentCommands()) {
301 transactionData.emplace();
302 transactionData->mIdNamespace = WrBridge()->GetNamespace();
303 transactionData->mPaintSequenceNumber = mPaintSequenceNumber;
304 if (mStateManager.mAsyncResourceUpdates) {
305 mStateManager.mAsyncResourceUpdates->Flush(
306 transactionData->mResourceUpdates, transactionData->mSmallShmems,
307 transactionData->mLargeShmems);
308 }
309 transactionData->mScrollUpdates = std::move(mPendingScrollUpdates);
310 for (const auto& scrollId : transactionData->mScrollUpdates.Keys()) {
311 nsLayoutUtils::NotifyPaintSkipTransaction(/*scroll id=*/scrollId);
312 }
313 }
314
315 Maybe<wr::IpcResourceUpdateQueue> nothing;
316 WrBridge()->EndEmptyTransaction(mFocusTarget, std::move(transactionData),
317 mLatestTransactionId,
318 mTransactionIdAllocator->GetVsyncId(),
319 mTransactionIdAllocator->GetVsyncStart(),
320 refreshStart, mTransactionStart, mURL);
321 mTransactionStart = TimeStamp();
322
323 MakeSnapshotIfRequired(size);
324 return true;
325 }
326
EndTransactionWithoutLayer(nsDisplayList * aDisplayList,nsDisplayListBuilder * aDisplayListBuilder,WrFiltersHolder && aFilters,WebRenderBackgroundData * aBackground,const double aGeckoDLBuildTime)327 void WebRenderLayerManager::EndTransactionWithoutLayer(
328 nsDisplayList* aDisplayList, nsDisplayListBuilder* aDisplayListBuilder,
329 WrFiltersHolder&& aFilters, WebRenderBackgroundData* aBackground,
330 const double aGeckoDLBuildTime) {
331 AUTO_PROFILER_TRACING_MARKER("Paint", "RenderLayers", GRAPHICS);
332
333 // Since we don't do repeat transactions right now, just set the time
334 mAnimationReadyTime = TimeStamp::Now();
335
336 WrBridge()->BeginTransaction();
337
338 LayoutDeviceIntSize size = mWidget->GetClientSize();
339
340 mDLBuilder->Begin(&mDisplayItemCache);
341
342 wr::IpcResourceUpdateQueue resourceUpdates(WrBridge());
343 wr::usize builderDumpIndex = 0;
344 bool containsSVGGroup = false;
345 bool dumpEnabled =
346 mWebRenderCommandBuilder.ShouldDumpDisplayList(aDisplayListBuilder);
347 Maybe<AutoDisplayItemCacheSuppressor> cacheSuppressor;
348 if (dumpEnabled) {
349 cacheSuppressor.emplace(&mDisplayItemCache);
350 printf_stderr("-- WebRender display list build --\n");
351 }
352
353 if (XRE_IsContentProcess() &&
354 StaticPrefs::gfx_webrender_debug_dl_dump_content_serialized()) {
355 mDLBuilder->DumpSerializedDisplayList();
356 }
357
358 if (aDisplayList) {
359 MOZ_ASSERT(aDisplayListBuilder && !aBackground);
360 mDisplayItemCache.SetDisplayList(aDisplayListBuilder, aDisplayList);
361
362 mWebRenderCommandBuilder.BuildWebRenderCommands(
363 *mDLBuilder, resourceUpdates, aDisplayList, aDisplayListBuilder,
364 mScrollData, std::move(aFilters));
365
366 aDisplayListBuilder->NotifyAndClearScrollFrames();
367
368 builderDumpIndex = mWebRenderCommandBuilder.GetBuilderDumpIndex();
369 containsSVGGroup = mWebRenderCommandBuilder.GetContainsSVGGroup();
370 } else {
371 // ViewToPaint does not have frame yet, then render only background clolor.
372 MOZ_ASSERT(!aDisplayListBuilder && aBackground);
373 aBackground->AddWebRenderCommands(*mDLBuilder);
374 if (dumpEnabled) {
375 printf_stderr("(no display list; background only)\n");
376 builderDumpIndex =
377 mDLBuilder->Dump(/*indent*/ 1, Some(builderDumpIndex), Nothing());
378 }
379 }
380
381 mWidget->AddWindowOverlayWebRenderCommands(WrBridge(), *mDLBuilder,
382 resourceUpdates);
383 if (dumpEnabled) {
384 printf_stderr("(window overlay)\n");
385 Unused << mDLBuilder->Dump(/*indent*/ 1, Some(builderDumpIndex), Nothing());
386 }
387
388 if (AsyncPanZoomEnabled()) {
389 if (mIsFirstPaint) {
390 mScrollData.SetIsFirstPaint();
391 mIsFirstPaint = false;
392 }
393 mScrollData.SetPaintSequenceNumber(mPaintSequenceNumber);
394 if (dumpEnabled) {
395 std::stringstream str;
396 str << mScrollData;
397 print_stderr(str);
398 }
399 }
400
401 // Since we're sending a full mScrollData that will include the new scroll
402 // offsets, and we can throw away the pending scroll updates we had kept for
403 // an empty transaction.
404 auto scrollIdsUpdated = ClearPendingScrollInfoUpdate();
405 for (ScrollableLayerGuid::ViewID update : scrollIdsUpdated) {
406 nsLayoutUtils::NotifyPaintSkipTransaction(update);
407 }
408
409 mLatestTransactionId =
410 mTransactionIdAllocator->GetTransactionId(/*aThrottle*/ true);
411
412 // Get the time of when the refresh driver start its tick (if available),
413 // otherwise use the time of when LayerManager::BeginTransaction was called.
414 TimeStamp refreshStart = mTransactionIdAllocator->GetTransactionStart();
415 if (!refreshStart) {
416 refreshStart = mTransactionStart;
417 }
418
419 if (mStateManager.mAsyncResourceUpdates) {
420 if (resourceUpdates.IsEmpty()) {
421 resourceUpdates.ReplaceResources(
422 std::move(mStateManager.mAsyncResourceUpdates.ref()));
423 } else {
424 WrBridge()->UpdateResources(mStateManager.mAsyncResourceUpdates.ref());
425 }
426 mStateManager.mAsyncResourceUpdates.reset();
427 }
428 mStateManager.DiscardImagesInTransaction(resourceUpdates);
429
430 WrBridge()->RemoveExpiredFontKeys(resourceUpdates);
431
432 // Skip the synchronization for buffer since we also skip the painting during
433 // device-reset status.
434 if (!gfxPlatform::GetPlatform()->DidRenderingDeviceReset()) {
435 if (WrBridge()->GetSyncObject() &&
436 WrBridge()->GetSyncObject()->IsSyncObjectValid()) {
437 WrBridge()->GetSyncObject()->Synchronize();
438 }
439 }
440
441 GetCompositorBridgeChild()->EndCanvasTransaction();
442
443 {
444 AUTO_PROFILER_TRACING_MARKER("Paint", "ForwardDPTransaction", GRAPHICS);
445 DisplayListData dlData;
446 mDLBuilder->End(dlData);
447 resourceUpdates.Flush(dlData.mResourceUpdates, dlData.mSmallShmems,
448 dlData.mLargeShmems);
449 dlData.mRect =
450 LayoutDeviceRect(LayoutDevicePoint(), LayoutDeviceSize(size));
451 dlData.mScrollData.emplace(std::move(mScrollData));
452 dlData.mDLDesc.gecko_display_list_type =
453 aDisplayListBuilder && aDisplayListBuilder->PartialBuildFailed()
454 ? wr::GeckoDisplayListType::Full(aGeckoDLBuildTime)
455 : wr::GeckoDisplayListType::Partial(aGeckoDLBuildTime);
456
457 bool ret = WrBridge()->EndTransaction(
458 std::move(dlData), mLatestTransactionId, containsSVGGroup,
459 mTransactionIdAllocator->GetVsyncId(),
460 mTransactionIdAllocator->GetVsyncStart(), refreshStart,
461 mTransactionStart, mURL);
462 if (!ret) {
463 // Failed to send display list, reset display item cache state.
464 mDisplayItemCache.Clear();
465 }
466
467 WrBridge()->SendSetFocusTarget(mFocusTarget);
468 mFocusTarget = FocusTarget();
469 }
470
471 // Discard animations after calling WrBridge()->EndTransaction().
472 // It updates mWrEpoch in WebRenderBridgeParent. The updated mWrEpoch is
473 // necessary for deleting animations at the correct time.
474 mStateManager.DiscardCompositorAnimations();
475
476 mTransactionStart = TimeStamp();
477
478 MakeSnapshotIfRequired(size);
479 mNeedsComposite = false;
480 }
481
SetFocusTarget(const FocusTarget & aFocusTarget)482 void WebRenderLayerManager::SetFocusTarget(const FocusTarget& aFocusTarget) {
483 mFocusTarget = aFocusTarget;
484 }
485
AsyncPanZoomEnabled() const486 bool WebRenderLayerManager::AsyncPanZoomEnabled() const {
487 return mWidget->AsyncPanZoomEnabled();
488 }
489
MakeSnapshotIfRequired(LayoutDeviceIntSize aSize)490 void WebRenderLayerManager::MakeSnapshotIfRequired(LayoutDeviceIntSize aSize) {
491 if (!mTarget || aSize.IsEmpty()) {
492 return;
493 }
494
495 // XXX Add other TextureData supports.
496 // Only BufferTexture is supported now.
497
498 // TODO: fixup for proper surface format.
499 // The GLES spec only guarantees that RGBA can be used with glReadPixels,
500 // so on Android we use RGBA.
501 SurfaceFormat format =
502 #ifdef MOZ_WIDGET_ANDROID
503 SurfaceFormat::R8G8B8A8;
504 #else
505 SurfaceFormat::B8G8R8A8;
506 #endif
507 RefPtr<TextureClient> texture = TextureClient::CreateForRawBufferAccess(
508 WrBridge(), format, aSize.ToUnknownSize(), BackendType::SKIA,
509 TextureFlags::SNAPSHOT);
510 if (!texture) {
511 return;
512 }
513
514 texture->InitIPDLActor(WrBridge());
515 if (!texture->GetIPDLActor()) {
516 return;
517 }
518
519 IntRect bounds = ToOutsideIntRect(mTarget->GetClipExtents());
520 bool needsYFlip = false;
521 if (!WrBridge()->SendGetSnapshot(texture->GetIPDLActor(), &needsYFlip)) {
522 return;
523 }
524
525 TextureClientAutoLock autoLock(texture, OpenMode::OPEN_READ_ONLY);
526 if (!autoLock.Succeeded()) {
527 return;
528 }
529 RefPtr<DrawTarget> drawTarget = texture->BorrowDrawTarget();
530 if (!drawTarget || !drawTarget->IsValid()) {
531 return;
532 }
533 RefPtr<SourceSurface> snapshot = drawTarget->Snapshot();
534 /*
535 static int count = 0;
536 char filename[100];
537 snprintf(filename, 100, "output%d.png", count++);
538 printf_stderr("Writing to :%s\n", filename);
539 gfxUtils::WriteAsPNG(snapshot, filename);
540 */
541
542 Rect dst(bounds.X(), bounds.Y(), bounds.Width(), bounds.Height());
543 Rect src(0, 0, bounds.Width(), bounds.Height());
544
545 Matrix m;
546 if (needsYFlip) {
547 m = Matrix::Scaling(1.0, -1.0).PostTranslate(0.0, aSize.height);
548 }
549 SurfacePattern pattern(snapshot, ExtendMode::CLAMP, m);
550 DrawTarget* dt = mTarget->GetDrawTarget();
551 MOZ_RELEASE_ASSERT(dt);
552 dt->FillRect(dst, pattern);
553
554 mTarget = nullptr;
555 }
556
DiscardImages()557 void WebRenderLayerManager::DiscardImages() {
558 wr::IpcResourceUpdateQueue resources(WrBridge());
559 mStateManager.DiscardImagesInTransaction(resources);
560 WrBridge()->UpdateResources(resources);
561 }
562
DiscardLocalImages()563 void WebRenderLayerManager::DiscardLocalImages() {
564 mStateManager.DiscardLocalImages();
565 }
566
SetLayersObserverEpoch(LayersObserverEpoch aEpoch)567 void WebRenderLayerManager::SetLayersObserverEpoch(LayersObserverEpoch aEpoch) {
568 if (WrBridge()->IPCOpen()) {
569 WrBridge()->SendSetLayersObserverEpoch(aEpoch);
570 }
571 }
572
DidComposite(TransactionId aTransactionId,const mozilla::TimeStamp & aCompositeStart,const mozilla::TimeStamp & aCompositeEnd)573 void WebRenderLayerManager::DidComposite(
574 TransactionId aTransactionId, const mozilla::TimeStamp& aCompositeStart,
575 const mozilla::TimeStamp& aCompositeEnd) {
576 if (IsDestroyed()) {
577 return;
578 }
579
580 MOZ_ASSERT(mWidget);
581
582 // Notifying the observers may tick the refresh driver which can cause
583 // a lot of different things to happen that may affect the lifetime of
584 // this layer manager. So let's make sure this object stays alive until
585 // the end of the method invocation.
586 RefPtr<WebRenderLayerManager> selfRef = this;
587
588 // |aTransactionId| will be > 0 if the compositor is acknowledging a shadow
589 // layers transaction.
590 if (aTransactionId.IsValid()) {
591 nsIWidgetListener* listener = mWidget->GetWidgetListener();
592 if (listener) {
593 listener->DidCompositeWindow(aTransactionId, aCompositeStart,
594 aCompositeEnd);
595 }
596 listener = mWidget->GetAttachedWidgetListener();
597 if (listener) {
598 listener->DidCompositeWindow(aTransactionId, aCompositeStart,
599 aCompositeEnd);
600 }
601 if (mTransactionIdAllocator) {
602 mTransactionIdAllocator->NotifyTransactionCompleted(aTransactionId);
603 }
604 }
605 }
606
ClearCachedResources()607 void WebRenderLayerManager::ClearCachedResources() {
608 if (!WrBridge()->IPCOpen()) {
609 gfxCriticalNote << "IPC Channel is already torn down unexpectedly\n";
610 return;
611 }
612 WrBridge()->BeginClearCachedResources();
613 // We flush any pending async resource updates before we clear the display
614 // list items because some resources (e.g. images) might be shared between
615 // multiple layer managers, not get freed here, and we want to keep their
616 // states consistent.
617 mStateManager.FlushAsyncResourceUpdates();
618 mWebRenderCommandBuilder.ClearCachedResources();
619 DiscardImages();
620 mStateManager.ClearCachedResources();
621 WrBridge()->EndClearCachedResources();
622 }
623
WrUpdated()624 void WebRenderLayerManager::WrUpdated() {
625 ClearAsyncAnimations();
626 mStateManager.mAsyncResourceUpdates.reset();
627 mWebRenderCommandBuilder.ClearCachedResources();
628 DiscardLocalImages();
629 mDisplayItemCache.Clear();
630
631 if (mWidget) {
632 if (dom::BrowserChild* browserChild = mWidget->GetOwningBrowserChild()) {
633 browserChild->SchedulePaint();
634 }
635 }
636 }
637
UpdateTextureFactoryIdentifier(const TextureFactoryIdentifier & aNewIdentifier)638 void WebRenderLayerManager::UpdateTextureFactoryIdentifier(
639 const TextureFactoryIdentifier& aNewIdentifier) {
640 WrBridge()->IdentifyTextureHost(aNewIdentifier);
641 }
642
GetTextureFactoryIdentifier()643 TextureFactoryIdentifier WebRenderLayerManager::GetTextureFactoryIdentifier() {
644 return WrBridge()->GetTextureFactoryIdentifier();
645 }
646
SetTransactionIdAllocator(TransactionIdAllocator * aAllocator)647 void WebRenderLayerManager::SetTransactionIdAllocator(
648 TransactionIdAllocator* aAllocator) {
649 // When changing the refresh driver, the previous refresh driver may never
650 // receive updates of pending transactions it's waiting for. So clear the
651 // waiting state before assigning another refresh driver.
652 if (mTransactionIdAllocator && (aAllocator != mTransactionIdAllocator)) {
653 mTransactionIdAllocator->ClearPendingTransactions();
654
655 // We should also reset the transaction id of the new allocator to previous
656 // allocator's last transaction id, so that completed transactions for
657 // previous allocator will be ignored and won't confuse the new allocator.
658 if (aAllocator) {
659 aAllocator->ResetInitialTransactionId(
660 mTransactionIdAllocator->LastTransactionId());
661 }
662 }
663
664 mTransactionIdAllocator = aAllocator;
665 }
666
GetLastTransactionId()667 TransactionId WebRenderLayerManager::GetLastTransactionId() {
668 return mLatestTransactionId;
669 }
670
FlushRendering(wr::RenderReasons aReasons)671 void WebRenderLayerManager::FlushRendering(wr::RenderReasons aReasons) {
672 CompositorBridgeChild* cBridge = GetCompositorBridgeChild();
673 if (!cBridge) {
674 return;
675 }
676 MOZ_ASSERT(mWidget);
677
678 // If value of IsResizingNativeWidget() is nothing, we assume that resizing
679 // might happen.
680 bool resizing = mWidget && mWidget->IsResizingNativeWidget().valueOr(true);
681
682 if (resizing) {
683 aReasons = aReasons | wr::RenderReasons::RESIZE;
684 }
685
686 // Limit async FlushRendering to !resizing and Win DComp.
687 // XXX relax the limitation
688 if (WrBridge()->GetCompositorUseDComp() && !resizing) {
689 cBridge->SendFlushRenderingAsync(aReasons);
690 } else if (mWidget->SynchronouslyRepaintOnResize() ||
691 StaticPrefs::layers_force_synchronous_resize()) {
692 cBridge->SendFlushRendering(aReasons);
693 } else {
694 cBridge->SendFlushRenderingAsync(aReasons);
695 }
696 }
697
WaitOnTransactionProcessed()698 void WebRenderLayerManager::WaitOnTransactionProcessed() {
699 CompositorBridgeChild* bridge = GetCompositorBridgeChild();
700 if (bridge) {
701 bridge->SendWaitOnTransactionProcessed();
702 }
703 }
704
SendInvalidRegion(const nsIntRegion & aRegion)705 void WebRenderLayerManager::SendInvalidRegion(const nsIntRegion& aRegion) {
706 // XXX Webrender does not support invalid region yet.
707
708 #ifdef XP_WIN
709 // When DWM is disabled, each window does not have own back buffer. They would
710 // paint directly to a buffer that was to be displayed by the video card.
711 // WM_PAINT via SendInvalidRegion() requests necessary re-paint.
712 const bool needsInvalidate = !gfx::gfxVars::DwmCompositionEnabled();
713 #else
714 const bool needsInvalidate = true;
715 #endif
716 if (needsInvalidate && WrBridge()) {
717 WrBridge()->SendInvalidateRenderedFrame();
718 }
719 }
720
ScheduleComposite(wr::RenderReasons aReasons)721 void WebRenderLayerManager::ScheduleComposite(wr::RenderReasons aReasons) {
722 WrBridge()->SendScheduleComposite(aReasons);
723 }
724
725 already_AddRefed<PersistentBufferProvider>
CreatePersistentBufferProvider(const gfx::IntSize & aSize,gfx::SurfaceFormat aFormat)726 WebRenderLayerManager::CreatePersistentBufferProvider(
727 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) {
728 if (!gfxPlatform::UseRemoteCanvas()) {
729 #ifdef XP_WIN
730 // Any kind of hardware acceleration is incompatible with Win32k Lockdown
731 // We don't initialize devices here so that PersistentBufferProviderShared
732 // will fall back to using a piece of shared memory as a backing for the
733 // canvas
734 if (!IsWin32kLockedDown()) {
735 gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
736 }
737 #else
738 gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
739 #endif
740 }
741
742 RefPtr<PersistentBufferProvider> provider =
743 PersistentBufferProviderShared::Create(aSize, aFormat,
744 AsKnowsCompositor());
745 if (provider) {
746 return provider.forget();
747 }
748
749 return WindowRenderer::CreatePersistentBufferProvider(aSize, aFormat);
750 }
751
ClearAsyncAnimations()752 void WebRenderLayerManager::ClearAsyncAnimations() {
753 mStateManager.ClearAsyncAnimations();
754 }
755
WrReleasedImages(const nsTArray<wr::ExternalImageKeyPair> & aPairs)756 void WebRenderLayerManager::WrReleasedImages(
757 const nsTArray<wr::ExternalImageKeyPair>& aPairs) {
758 mStateManager.WrReleasedImages(aPairs);
759 }
760
GetFrameUniformity(FrameUniformityData * aOutData)761 void WebRenderLayerManager::GetFrameUniformity(FrameUniformityData* aOutData) {
762 WrBridge()->SendGetFrameUniformity(aOutData);
763 }
764
765 /*static*/
LayerUserDataDestroy(void * data)766 void WebRenderLayerManager::LayerUserDataDestroy(void* data) {
767 delete static_cast<LayerUserData*>(data);
768 }
769
RemoveUserData(void * aKey)770 UniquePtr<LayerUserData> WebRenderLayerManager::RemoveUserData(void* aKey) {
771 UniquePtr<LayerUserData> d(static_cast<LayerUserData*>(
772 mUserData.Remove(static_cast<gfx::UserDataKey*>(aKey))));
773 return d;
774 }
775
776 std::unordered_set<ScrollableLayerGuid::ViewID>
ClearPendingScrollInfoUpdate()777 WebRenderLayerManager::ClearPendingScrollInfoUpdate() {
778 std::unordered_set<ScrollableLayerGuid::ViewID> scrollIds(
779 mPendingScrollUpdates.Keys().cbegin(),
780 mPendingScrollUpdates.Keys().cend());
781 mPendingScrollUpdates.Clear();
782 return scrollIds;
783 }
784
785 } // namespace layers
786 } // namespace mozilla
787