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