WebRenderBridgeParent.cpp (102905B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/layers/WebRenderBridgeParent.h" 8 9 #include "mozmemory.h" 10 #include "CompositableHost.h" 11 #include "gfxEnv.h" 12 #include "gfxPlatform.h" 13 #include "gfxOTSUtils.h" 14 #include "GeckoProfiler.h" 15 #include "GLContext.h" 16 #include "GLContextProvider.h" 17 #include "GLLibraryLoader.h" 18 #include "nsExceptionHandler.h" 19 #include "mozilla/Range.h" 20 #include "mozilla/EnumeratedRange.h" 21 #include "mozilla/StaticPrefs_gfx.h" 22 #include "mozilla/StaticPrefs_webgl.h" 23 #include "mozilla/UniquePtr.h" 24 #include "mozilla/gfx/gfxVars.h" 25 #include "mozilla/gfx/GPUParent.h" 26 #include "mozilla/glean/GfxMetrics.h" 27 #include "mozilla/layers/AnimationHelper.h" 28 #include "mozilla/layers/APZSampler.h" 29 #include "mozilla/layers/APZUpdater.h" 30 #include "mozilla/layers/Compositor.h" 31 #include "mozilla/layers/CompositorBridgeParent.h" 32 #include "mozilla/layers/CompositorAnimationStorage.h" 33 #include "mozilla/layers/CompositorThread.h" 34 #include "mozilla/layers/CompositorVsyncScheduler.h" 35 #include "mozilla/layers/ImageBridgeParent.h" 36 #include "mozilla/layers/ImageDataSerializer.h" 37 #include "mozilla/layers/IpcResourceUpdateQueue.h" 38 #include "mozilla/layers/OMTASampler.h" 39 #include "mozilla/layers/RemoteTextureMap.h" 40 #include "mozilla/layers/SharedSurfacesParent.h" 41 #include "mozilla/layers/TextureHost.h" 42 #include "mozilla/layers/AsyncImagePipelineManager.h" 43 #include "mozilla/layers/UiCompositorControllerParent.h" 44 #include "mozilla/layers/WebRenderImageHost.h" 45 #include "mozilla/layers/WebRenderTextureHost.h" 46 #include "mozilla/ProfilerMarkerTypes.h" 47 #include "mozilla/TimeStamp.h" 48 #include "mozilla/webrender/RenderTextureHostSWGL.h" 49 #include "mozilla/webrender/RenderThread.h" 50 #include "mozilla/widget/CompositorWidget.h" 51 52 #ifdef XP_WIN 53 # include "mozilla/gfx/DeviceManagerDx.h" 54 # include "mozilla/widget/WinCompositorWidget.h" 55 #endif 56 #if defined(MOZ_WIDGET_GTK) 57 # include "mozilla/widget/GtkCompositorWidget.h" 58 #endif 59 60 bool is_in_main_thread() { return NS_IsMainThread(); } 61 62 bool is_in_compositor_thread() { 63 return mozilla::layers::CompositorThreadHolder::IsInCompositorThread(); 64 } 65 66 bool is_in_render_thread() { 67 return mozilla::wr::RenderThread::IsInRenderThread(); 68 } 69 70 bool gecko_profiler_thread_is_being_profiled() { 71 return profiler_thread_is_being_profiled(ThreadProfilingFeatures::Any); 72 } 73 74 bool is_glcontext_gles(void* const glcontext_ptr) { 75 MOZ_RELEASE_ASSERT(glcontext_ptr); 76 return reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr)->IsGLES(); 77 } 78 79 bool is_glcontext_angle(void* glcontext_ptr) { 80 MOZ_ASSERT(glcontext_ptr); 81 82 mozilla::gl::GLContext* glcontext = 83 reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr); 84 if (!glcontext) { 85 return false; 86 } 87 return glcontext->IsANGLE(); 88 } 89 90 const char* gfx_wr_resource_path_override() { 91 return gfxPlatform::WebRenderResourcePathOverride(); 92 } 93 94 bool gfx_wr_use_optimized_shaders() { 95 return mozilla::gfx::gfxVars::UseWebRenderOptimizedShaders(); 96 } 97 98 void gfx_critical_note(const char* msg) { gfxCriticalNote << msg; } 99 100 void gfx_critical_error(const char* msg) { gfxCriticalError() << msg; } 101 102 void gecko_printf_stderr_output(const char* msg) { printf_stderr("%s\n", msg); } 103 104 void* get_proc_address_from_glcontext(void* glcontext_ptr, 105 const char* procname) { 106 mozilla::gl::GLContext* glcontext = 107 reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr); 108 MOZ_ASSERT(glcontext); 109 if (!glcontext) { 110 return nullptr; 111 } 112 const auto& loader = glcontext->GetSymbolLoader(); 113 MOZ_ASSERT(loader); 114 115 const auto ret = loader->GetProcAddress(procname); 116 return reinterpret_cast<void*>(ret); 117 } 118 119 static CrashReporter::Annotation FromWrCrashAnnotation( 120 mozilla::wr::CrashAnnotation aAnnotation) { 121 switch (aAnnotation) { 122 case mozilla::wr::CrashAnnotation::CompileShader: 123 return CrashReporter::Annotation::GraphicsCompileShader; 124 case mozilla::wr::CrashAnnotation::DrawShader: 125 return CrashReporter::Annotation::GraphicsDrawShader; 126 case mozilla::wr::CrashAnnotation::FontFile: 127 return CrashReporter::Annotation::GraphicsFontFile; 128 default: 129 MOZ_ASSERT_UNREACHABLE("Unhandled annotation!"); 130 return CrashReporter::Annotation::Count; 131 } 132 } 133 134 extern "C" { 135 136 void gfx_wr_set_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation, 137 const char* aValue) { 138 MOZ_ASSERT(aValue); 139 140 auto annotation = FromWrCrashAnnotation(aAnnotation); 141 if (annotation == CrashReporter::Annotation::Count) { 142 return; 143 } 144 145 CrashReporter::RecordAnnotationCString(annotation, aValue); 146 } 147 148 void gfx_wr_clear_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation) { 149 auto annotation = FromWrCrashAnnotation(aAnnotation); 150 if (annotation == CrashReporter::Annotation::Count) { 151 return; 152 } 153 154 CrashReporter::UnrecordAnnotation(annotation); 155 } 156 } 157 158 namespace mozilla::gfx { 159 wr::PipelineId GetTemporaryWebRenderPipelineId(wr::PipelineId aMainPipeline); 160 } 161 162 namespace mozilla::layers { 163 164 using namespace mozilla::gfx; 165 166 #ifdef MOZ_MEMORY 167 static bool sAllocAsjustmentTaskCancelled = false; 168 static bool sIncreasedDirtyPageThreshold = false; 169 170 static void ResetDirtyPageModifier(); 171 172 static void ScheduleResetMaxDirtyPageModifier() { 173 NS_DelayedDispatchToCurrentThread( 174 NewRunnableFunction("ResetDirtyPageModifier", &ResetDirtyPageModifier), 175 100 // In ms. 176 ); 177 } 178 179 static void NeedIncreasedMaxDirtyPageModifier() { 180 if (sIncreasedDirtyPageThreshold) { 181 sAllocAsjustmentTaskCancelled = true; 182 return; 183 } 184 185 moz_set_max_dirty_page_modifier(3); 186 sIncreasedDirtyPageThreshold = true; 187 188 ScheduleResetMaxDirtyPageModifier(); 189 } 190 191 static void ResetDirtyPageModifier() { 192 if (!sIncreasedDirtyPageThreshold) { 193 return; 194 } 195 196 if (sAllocAsjustmentTaskCancelled) { 197 sAllocAsjustmentTaskCancelled = false; 198 ScheduleResetMaxDirtyPageModifier(); 199 return; 200 } 201 202 moz_set_max_dirty_page_modifier(0); 203 204 wr::RenderThread* renderThread = wr::RenderThread::Get(); 205 if (renderThread) { 206 renderThread->NotifyIdle(); 207 } 208 209 jemalloc_free_excess_dirty_pages(); 210 211 sIncreasedDirtyPageThreshold = false; 212 } 213 #else 214 // Don't bother doing anything of the memory allocator doesn't support this. 215 static void NeedIncreasedMaxDirtyPageModifier() {} 216 #endif 217 218 LazyLogModule gWebRenderBridgeParentLog("WebRenderBridgeParent"); 219 #define LOG(...) \ 220 MOZ_LOG(gWebRenderBridgeParentLog, LogLevel::Debug, (__VA_ARGS__)) 221 222 class ScheduleObserveLayersUpdate : public wr::NotificationHandler { 223 public: 224 ScheduleObserveLayersUpdate(RefPtr<CompositorBridgeParentBase> aBridge, 225 LayersId aLayersId, bool aIsActive) 226 : mBridge(std::move(aBridge)), 227 mLayersId(aLayersId), 228 mIsActive(aIsActive) {} 229 230 void Notify(wr::Checkpoint) override { 231 CompositorThread()->Dispatch(NewRunnableMethod<LayersId, int>( 232 "ObserveLayersUpdate", mBridge, 233 &CompositorBridgeParentBase::ObserveLayersUpdate, mLayersId, 234 mIsActive)); 235 } 236 237 protected: 238 RefPtr<CompositorBridgeParentBase> mBridge; 239 LayersId mLayersId; 240 bool mIsActive; 241 }; 242 243 class SceneBuiltNotification : public wr::NotificationHandler { 244 public: 245 SceneBuiltNotification(WebRenderBridgeParent* aParent, wr::Epoch aEpoch, 246 TimeStamp aTxnStartTime) 247 : mParent(aParent), mEpoch(aEpoch), mTxnStartTime(aTxnStartTime) {} 248 249 void Notify(wr::Checkpoint) override { 250 auto startTime = this->mTxnStartTime; 251 RefPtr<WebRenderBridgeParent> parent = mParent; 252 wr::Epoch epoch = mEpoch; 253 CompositorThread()->Dispatch(NS_NewRunnableFunction( 254 "SceneBuiltNotificationRunnable", [parent, epoch, startTime]() { 255 auto endTime = TimeStamp::Now(); 256 if (profiler_thread_is_being_profiled_for_markers()) { 257 PROFILER_MARKER("CONTENT_FULL_PAINT_TIME", GRAPHICS, 258 MarkerTiming::Interval(startTime, endTime), 259 ContentBuildMarker); 260 } 261 mozilla::glean::gfx_content::full_paint_time.AccumulateRawDuration( 262 endTime - startTime); 263 parent->NotifySceneBuiltForEpoch(epoch, endTime); 264 })); 265 } 266 267 protected: 268 RefPtr<WebRenderBridgeParent> mParent; 269 wr::Epoch mEpoch; 270 TimeStamp mTxnStartTime; 271 }; 272 273 class WebRenderBridgeParent::ScheduleSharedSurfaceRelease final 274 : public wr::NotificationHandler { 275 public: 276 explicit ScheduleSharedSurfaceRelease(WebRenderBridgeParent* aWrBridge) 277 : mWrBridge(aWrBridge), mSurfaces(20) {} 278 279 ~ScheduleSharedSurfaceRelease() override { 280 if (!mSurfaces.IsEmpty()) { 281 MOZ_ASSERT_UNREACHABLE("Unreleased surfaces!"); 282 gfxCriticalNote << "ScheduleSharedSurfaceRelease destroyed non-empty"; 283 NotifyInternal(/* aFromCheckpoint */ false); 284 } 285 } 286 287 void Add(const wr::ImageKey& aKey, const wr::ExternalImageId& aId) { 288 mSurfaces.AppendElement(wr::ExternalImageKeyPair{aKey, aId}); 289 } 290 291 void Notify(wr::Checkpoint) override { 292 NotifyInternal(/* aFromCheckpoint */ true); 293 } 294 295 private: 296 void NotifyInternal(bool aFromCheckpoint) { 297 CompositorThread()->Dispatch( 298 NewRunnableMethod<nsTArray<wr::ExternalImageKeyPair>, bool>( 299 "ObserveSharedSurfaceRelease", mWrBridge, 300 &WebRenderBridgeParent::ObserveSharedSurfaceRelease, 301 std::move(mSurfaces), aFromCheckpoint)); 302 } 303 304 RefPtr<WebRenderBridgeParent> mWrBridge; 305 nsTArray<wr::ExternalImageKeyPair> mSurfaces; 306 }; 307 308 class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender final { 309 public: 310 explicit AutoWebRenderBridgeParentAsyncMessageSender( 311 WebRenderBridgeParent* aWebRenderBridgeParent, 312 nsTArray<OpDestroy>* aDestroyActors = nullptr) 313 : mWebRenderBridgeParent(aWebRenderBridgeParent), 314 mActorsToDestroy(aDestroyActors) { 315 mWebRenderBridgeParent->SetAboutToSendAsyncMessages(); 316 } 317 318 ~AutoWebRenderBridgeParentAsyncMessageSender() { 319 mWebRenderBridgeParent->SendPendingAsyncMessages(); 320 if (mActorsToDestroy) { 321 // Destroy the actors after sending the async messages because the latter 322 // may contain references to some actors. 323 for (const auto& op : *mActorsToDestroy) { 324 mWebRenderBridgeParent->DestroyActor(op); 325 } 326 } 327 } 328 329 private: 330 WebRenderBridgeParent* mWebRenderBridgeParent; 331 nsTArray<OpDestroy>* mActorsToDestroy; 332 }; 333 334 WebRenderBridgeParent::WebRenderBridgeParent( 335 CompositorBridgeParentBase* aCompositorBridge, 336 const wr::PipelineId& aPipelineId, widget::CompositorWidget* aWidget, 337 CompositorVsyncScheduler* aScheduler, RefPtr<wr::WebRenderAPI>&& aApi, 338 RefPtr<AsyncImagePipelineManager>&& aImageMgr, TimeDuration aVsyncRate) 339 : mCompositorBridge(aCompositorBridge), 340 mPipelineId(aPipelineId), 341 mWidget(aWidget), 342 mApi(aApi), 343 mAsyncImageManager(aImageMgr), 344 mCompositorScheduler(aScheduler), 345 mVsyncRate(aVsyncRate), 346 mWrEpoch{0}, 347 mIdNamespace(aApi->GetNamespace()), 348 #if defined(MOZ_WIDGET_ANDROID) 349 mScreenPixelsTarget(nullptr), 350 #endif 351 mBlobTileSize(256), 352 mSkippedCompositeReasons(wr::RenderReasons::NONE), 353 mDestroyed(false), 354 mIsFirstPaint(true), 355 mPendingScrollPayloads("WebRenderBridgeParent::mPendingScrollPayloads") { 356 MOZ_ASSERT(mAsyncImageManager); 357 LOG("WebRenderBridgeParent::WebRenderBridgeParent() PipelineId %" PRIx64 358 " Id %" PRIx64 " root %d", 359 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 360 IsRootWebRenderBridgeParent()); 361 362 mAsyncImageManager->AddPipeline(mPipelineId, this); 363 if (IsRootWebRenderBridgeParent()) { 364 MOZ_ASSERT(!mCompositorScheduler); 365 mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget); 366 UpdateDebugFlags(); 367 UpdateQualitySettings(); 368 UpdateProfilerUI(); 369 UpdateParameters(); 370 // Start with the cached bool parameter bits inverted so that we update them 371 // all. 372 mBoolParameterBits = ~gfxVars::WebRenderBoolParameters(); 373 UpdateBoolParameters(); 374 } 375 mRemoteTextureTxnScheduler = 376 RemoteTextureTxnScheduler::Create(aCompositorBridge); 377 } 378 379 WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId, 380 nsCString&& aError) 381 : mCompositorBridge(nullptr), 382 mPipelineId(aPipelineId), 383 mWrEpoch{0}, 384 mIdNamespace{0}, 385 mInitError(aError), 386 mDestroyed(true), 387 mIsFirstPaint(false), 388 mPendingScrollPayloads("WebRenderBridgeParent::mPendingScrollPayloads") { 389 LOG("WebRenderBridgeParent::WebRenderBridgeParent() PipelineId %" PRIx64 "", 390 wr::AsUint64(mPipelineId)); 391 } 392 393 WebRenderBridgeParent::~WebRenderBridgeParent() { 394 LOG("WebRenderBridgeParent::WebRenderBridgeParent() PipelineId %" PRIx64 "", 395 wr::AsUint64(mPipelineId)); 396 } 397 398 /* static */ 399 WebRenderBridgeParent* WebRenderBridgeParent::CreateDestroyed( 400 const wr::PipelineId& aPipelineId, nsCString&& aError) { 401 return new WebRenderBridgeParent(aPipelineId, std::move(aError)); 402 } 403 404 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEnsureConnected( 405 TextureFactoryIdentifier* aTextureFactoryIdentifier, 406 MaybeIdNamespace* aMaybeIdNamespace, nsCString* aError) { 407 if (mDestroyed) { 408 *aTextureFactoryIdentifier = 409 TextureFactoryIdentifier(LayersBackend::LAYERS_NONE); 410 *aMaybeIdNamespace = Nothing(); 411 if (mInitError.IsEmpty()) { 412 // Got destroyed after we initialized but before the handshake finished? 413 aError->AssignLiteral("FEATURE_FAILURE_WEBRENDER_INITIALIZE_RACE"); 414 } else { 415 *aError = std::move(mInitError); 416 } 417 return IPC_OK(); 418 } 419 420 MOZ_ASSERT(mIdNamespace.mHandle != 0); 421 *aTextureFactoryIdentifier = GetTextureFactoryIdentifier(); 422 *aMaybeIdNamespace = Some(mIdNamespace); 423 424 return IPC_OK(); 425 } 426 427 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvShutdown() { 428 return HandleShutdown(); 429 } 430 431 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvShutdownSync() { 432 return HandleShutdown(); 433 } 434 435 mozilla::ipc::IPCResult WebRenderBridgeParent::HandleShutdown() { 436 Destroy(); 437 IProtocol* mgr = Manager(); 438 if (!Send__delete__(this)) { 439 return IPC_FAIL_NO_REASON(mgr); 440 } 441 return IPC_OK(); 442 } 443 444 void WebRenderBridgeParent::Destroy() { 445 if (mDestroyed) { 446 return; 447 } 448 LOG("WebRenderBridgeParent::Destroy() PipelineId %" PRIx64 " Id %" PRIx64 449 " root %d", 450 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 451 IsRootWebRenderBridgeParent()); 452 453 mDestroyed = true; 454 if (mRemoteTextureTxnScheduler) { 455 mRemoteTextureTxnScheduler = nullptr; 456 } 457 if (mWebRenderBridgeRef) { 458 // Break mutual reference 459 mWebRenderBridgeRef->Clear(); 460 mWebRenderBridgeRef = nullptr; 461 } 462 for (const auto& entry : mCompositables) { 463 entry.second->OnReleased(); 464 } 465 mCompositables.clear(); 466 ClearResources(); 467 } 468 469 struct WROTSAlloc { 470 wr::Vec<uint8_t> mVec; 471 472 void* Grow(void* aPtr, size_t aLength) { 473 if (aLength > mVec.Capacity()) { 474 mVec.Reserve(aLength - mVec.Capacity()); 475 } 476 return mVec.inner.data; 477 } 478 wr::Vec<uint8_t> ShrinkToFit(void* aPtr, size_t aLength) { 479 wr::Vec<uint8_t> result(std::move(mVec)); 480 result.inner.length = aLength; 481 return result; 482 } 483 void Free(void* aPtr) {} 484 }; 485 486 static bool ReadRawFont(const OpAddRawFont& aOp, wr::ShmSegmentsReader& aReader, 487 wr::TransactionBuilder& aUpdates) { 488 wr::Vec<uint8_t> sourceBytes; 489 Maybe<Range<uint8_t>> ptr = 490 aReader.GetReadPointerOrCopy(aOp.bytes(), sourceBytes); 491 if (ptr.isNothing()) { 492 gfxCriticalNote << "No read pointer from reader for sanitizing font " 493 << aOp.key().mHandle; 494 return false; 495 } 496 Range<uint8_t>& source = ptr.ref(); 497 // Attempt to sanitize the font before passing it along for updating. 498 // Ensure that we're not strict here about font types, since any font that 499 // failed generating a descriptor might end up here as raw font data. 500 size_t lengthHint = gfxOTSContext::GuessSanitizedFontSize( 501 source.begin().get(), source.length(), false); 502 if (!lengthHint) { 503 gfxCriticalNote << "Could not determine font type for sanitizing font " 504 << aOp.key().mHandle; 505 return false; 506 } 507 gfxOTSExpandingMemoryStream<WROTSAlloc> output(lengthHint); 508 gfxOTSContext otsContext; 509 if (!otsContext.Process(&output, source.begin().get(), source.length())) { 510 gfxCriticalNote << "Failed sanitizing font " << aOp.key().mHandle; 511 return false; 512 } 513 wr::Vec<uint8_t> bytes = output.forget(); 514 515 aUpdates.AddRawFont(aOp.key(), bytes, aOp.fontIndex()); 516 return true; 517 } 518 519 bool WebRenderBridgeParent::UpdateResources( 520 const nsTArray<OpUpdateResource>& aResourceUpdates, 521 const nsTArray<RefCountedShmem>& aSmallShmems, 522 const nsTArray<ipc::Shmem>& aLargeShmems, 523 wr::TransactionBuilder& aUpdates) { 524 wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems); 525 UniquePtr<ScheduleSharedSurfaceRelease> scheduleRelease; 526 527 while (GPUParent::MaybeFlushMemory()) { 528 // If the GPU process has memory pressure, preemptively unmap some of our 529 // shared memory images. If we are in the parent process, the expiration 530 // tracker itself will listen for the memory pressure event. 531 if (!SharedSurfacesParent::AgeAndExpireOneGeneration()) { 532 break; 533 } 534 } 535 536 bool success = true; 537 for (const auto& cmd : aResourceUpdates) { 538 switch (cmd.type()) { 539 case OpUpdateResource::TOpAddImage: { 540 const auto& op = cmd.get_OpAddImage(); 541 if (!MatchesNamespace(op.key())) { 542 MOZ_ASSERT_UNREACHABLE("Stale image key (add)!"); 543 break; 544 } 545 546 wr::Vec<uint8_t> bytes; 547 if (reader.Read(op.bytes(), bytes)) { 548 aUpdates.AddImage(op.key(), op.descriptor(), bytes); 549 } else { 550 gfxCriticalNote << "TOpAddImage failed"; 551 success = false; 552 } 553 break; 554 } 555 case OpUpdateResource::TOpUpdateImage: { 556 const auto& op = cmd.get_OpUpdateImage(); 557 if (!MatchesNamespace(op.key())) { 558 MOZ_ASSERT_UNREACHABLE("Stale image key (update)!"); 559 break; 560 } 561 562 wr::Vec<uint8_t> bytes; 563 if (reader.Read(op.bytes(), bytes)) { 564 aUpdates.UpdateImageBuffer(op.key(), op.descriptor(), bytes); 565 } else { 566 gfxCriticalNote << "TOpUpdateImage failed"; 567 success = false; 568 } 569 break; 570 } 571 case OpUpdateResource::TOpAddBlobImage: { 572 const auto& op = cmd.get_OpAddBlobImage(); 573 if (!MatchesNamespace(op.key())) { 574 MOZ_ASSERT_UNREACHABLE("Stale blob image key (add)!"); 575 break; 576 } 577 578 wr::Vec<uint8_t> bytes; 579 if (reader.Read(op.bytes(), bytes)) { 580 aUpdates.AddBlobImage(op.key(), op.descriptor(), mBlobTileSize, bytes, 581 wr::ToDeviceIntRect(op.visibleRect())); 582 } else { 583 gfxCriticalNote << "TOpAddBlobImage failed"; 584 success = false; 585 } 586 587 break; 588 } 589 case OpUpdateResource::TOpUpdateBlobImage: { 590 const auto& op = cmd.get_OpUpdateBlobImage(); 591 if (!MatchesNamespace(op.key())) { 592 MOZ_ASSERT_UNREACHABLE("Stale blob image key (update)!"); 593 break; 594 } 595 596 wr::Vec<uint8_t> bytes; 597 if (reader.Read(op.bytes(), bytes)) { 598 aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes, 599 wr::ToDeviceIntRect(op.visibleRect()), 600 wr::ToLayoutIntRect(op.dirtyRect())); 601 } else { 602 gfxCriticalNote << "TOpUpdateBlobImage failed"; 603 success = false; 604 } 605 break; 606 } 607 case OpUpdateResource::TOpSetBlobImageVisibleArea: { 608 const auto& op = cmd.get_OpSetBlobImageVisibleArea(); 609 if (!MatchesNamespace(op.key())) { 610 MOZ_ASSERT_UNREACHABLE("Stale blob image key (visible)!"); 611 break; 612 } 613 aUpdates.SetBlobImageVisibleArea(op.key(), 614 wr::ToDeviceIntRect(op.area())); 615 break; 616 } 617 case OpUpdateResource::TOpAddSnapshotImage: { 618 const auto& op = cmd.get_OpAddSnapshotImage(); 619 if (!MatchesNamespace(wr::AsImageKey(op.key()))) { 620 MOZ_ASSERT_UNREACHABLE("Stale snapshot image key (add)!"); 621 break; 622 } 623 aUpdates.AddSnapshotImage(op.key()); 624 break; 625 } 626 case OpUpdateResource::TOpDeleteSnapshotImage: { 627 const auto& op = cmd.get_OpDeleteSnapshotImage(); 628 if (NS_WARN_IF(!MatchesNamespace(wr::AsImageKey(op.key())))) { 629 // TODO(bug 1972525): Fix tab detach with an active view transition 630 // and uncomment this assertion. 631 // 632 // MOZ_ASSERT_UNREACHABLE("Stale snapshot image key (remove)!"); 633 break; 634 } 635 aUpdates.DeleteSnapshotImage(op.key()); 636 break; 637 } 638 case OpUpdateResource::TOpAddSharedExternalImage: { 639 const auto& op = cmd.get_OpAddSharedExternalImage(); 640 // gfxCriticalNote is called on error 641 if (!AddSharedExternalImage(op.externalImageId(), op.key(), aUpdates)) { 642 success = false; 643 } 644 break; 645 } 646 case OpUpdateResource::TOpPushExternalImageForTexture: { 647 const auto& op = cmd.get_OpPushExternalImageForTexture(); 648 CompositableTextureHostRef texture; 649 texture = TextureHost::AsTextureHost(op.texture().AsParent()); 650 // gfxCriticalNote is called on error 651 if (!PushExternalImageForTexture(op.externalImageId(), op.key(), 652 texture, op.isUpdate(), aUpdates)) { 653 success = false; 654 } 655 break; 656 } 657 case OpUpdateResource::TOpUpdateSharedExternalImage: { 658 const auto& op = cmd.get_OpUpdateSharedExternalImage(); 659 // gfxCriticalNote is called on error 660 if (!UpdateSharedExternalImage(op.externalImageId(), op.key(), 661 op.dirtyRect(), aUpdates, 662 scheduleRelease)) { 663 success = false; 664 } 665 break; 666 } 667 case OpUpdateResource::TOpAddRawFont: { 668 if (!ReadRawFont(cmd.get_OpAddRawFont(), reader, aUpdates)) { 669 success = false; 670 } 671 break; 672 } 673 case OpUpdateResource::TOpAddFontDescriptor: { 674 const auto& op = cmd.get_OpAddFontDescriptor(); 675 if (!MatchesNamespace(op.key())) { 676 MOZ_ASSERT_UNREACHABLE("Stale font key (add descriptor)!"); 677 break; 678 } 679 680 wr::Vec<uint8_t> bytes; 681 if (reader.Read(op.bytes(), bytes)) { 682 aUpdates.AddFontDescriptor(op.key(), bytes, op.fontIndex()); 683 } else { 684 gfxCriticalNote << "TOpAddFontDescriptor failed"; 685 success = false; 686 } 687 break; 688 } 689 case OpUpdateResource::TOpAddFontInstance: { 690 const auto& op = cmd.get_OpAddFontInstance(); 691 if (!MatchesNamespace(op.instanceKey()) || 692 !MatchesNamespace(op.fontKey())) { 693 MOZ_ASSERT_UNREACHABLE("Stale font key (add instance)!"); 694 break; 695 } 696 697 wr::Vec<uint8_t> variations; 698 if (reader.Read(op.variations(), variations)) { 699 aUpdates.AddFontInstance(op.instanceKey(), op.fontKey(), 700 op.glyphSize(), op.options().ptrOr(nullptr), 701 op.platformOptions().ptrOr(nullptr), 702 variations); 703 } else { 704 gfxCriticalNote << "TOpAddFontInstance failed"; 705 success = false; 706 } 707 break; 708 } 709 case OpUpdateResource::TOpDeleteImage: { 710 const auto& op = cmd.get_OpDeleteImage(); 711 if (!MatchesNamespace(op.key())) { 712 // TODO(aosmond): We should also assert here, but the callers are less 713 // careful about checking when cleaning up their old keys. We should 714 // perform an audit on image key usage. 715 break; 716 } 717 718 DeleteImage(op.key(), aUpdates); 719 break; 720 } 721 case OpUpdateResource::TOpDeleteBlobImage: { 722 const auto& op = cmd.get_OpDeleteBlobImage(); 723 if (!MatchesNamespace(op.key())) { 724 MOZ_ASSERT_UNREACHABLE("Stale blob image key (delete)!"); 725 break; 726 } 727 728 aUpdates.DeleteBlobImage(op.key()); 729 break; 730 } 731 case OpUpdateResource::TOpDeleteFont: { 732 const auto& op = cmd.get_OpDeleteFont(); 733 if (!MatchesNamespace(op.key())) { 734 MOZ_ASSERT_UNREACHABLE("Stale font key (delete)!"); 735 break; 736 } 737 738 aUpdates.DeleteFont(op.key()); 739 break; 740 } 741 case OpUpdateResource::TOpDeleteFontInstance: { 742 const auto& op = cmd.get_OpDeleteFontInstance(); 743 if (!MatchesNamespace(op.key())) { 744 MOZ_ASSERT_UNREACHABLE("Stale font instance key (delete)!"); 745 break; 746 } 747 748 aUpdates.DeleteFontInstance(op.key()); 749 break; 750 } 751 case OpUpdateResource::T__None: 752 break; 753 } 754 } 755 756 if (scheduleRelease) { 757 // When software WR is enabled, shared surfaces are read during rendering 758 // rather than copied to the texture cache. 759 wr::Checkpoint when = mApi->GetBackendType() == WebRenderBackend::SOFTWARE 760 ? wr::Checkpoint::FrameRendered 761 : wr::Checkpoint::FrameTexturesUpdated; 762 aUpdates.Notify(when, std::move(scheduleRelease)); 763 } 764 765 MOZ_ASSERT(success); 766 return success; 767 } 768 769 bool WebRenderBridgeParent::AddSharedExternalImage( 770 wr::ExternalImageId aExtId, wr::ImageKey aKey, 771 wr::TransactionBuilder& aResources) { 772 if (!MatchesNamespace(aKey)) { 773 MOZ_ASSERT_UNREACHABLE("Stale shared external image key (add)!"); 774 return true; 775 } 776 777 auto key = wr::AsUint64(aKey); 778 auto it = mSharedSurfaceIds.find(key); 779 if (it != mSharedSurfaceIds.end()) { 780 gfxCriticalNote << "Readding known shared surface: " << key; 781 return false; 782 } 783 784 RefPtr<DataSourceSurface> dSurf = SharedSurfacesParent::Acquire(aExtId); 785 if (!dSurf) { 786 gfxCriticalNote 787 << "DataSourceSurface of SharedSurfaces does not exist for extId:" 788 << wr::AsUint64(aExtId); 789 return false; 790 } 791 792 mSharedSurfaceIds.insert(std::make_pair(key, aExtId)); 793 794 // Prefer raw buffers, unless our backend requires native textures. 795 IntSize surfaceSize = dSurf->GetSize(); 796 TextureHost::NativeTexturePolicy policy = 797 TextureHost::BackendNativeTexturePolicy(mApi->GetBackendType(), 798 surfaceSize); 799 auto imageType = 800 policy == TextureHost::NativeTexturePolicy::REQUIRE 801 ? wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::Texture2D) 802 : wr::ExternalImageType::Buffer(); 803 wr::ImageDescriptor descriptor(surfaceSize, dSurf->Stride(), 804 dSurf->GetFormat()); 805 aResources.AddExternalImage(aKey, descriptor, aExtId, imageType, 0); 806 return true; 807 } 808 809 bool WebRenderBridgeParent::PushExternalImageForTexture( 810 wr::ExternalImageId aExtId, wr::ImageKey aKey, TextureHost* aTexture, 811 bool aIsUpdate, wr::TransactionBuilder& aResources) { 812 if (!MatchesNamespace(aKey)) { 813 MOZ_ASSERT_UNREACHABLE("Stale texture external image key!"); 814 return true; 815 } 816 817 if (!aTexture) { 818 gfxCriticalNote << "TextureHost does not exist for extId:" 819 << wr::AsUint64(aExtId); 820 return false; 821 } 822 823 auto op = aIsUpdate ? TextureHost::UPDATE_IMAGE : TextureHost::ADD_IMAGE; 824 WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost(); 825 if (wrTexture) { 826 Range<wr::ImageKey> keys(&aKey, 1); 827 wrTexture->PushResourceUpdates(aResources, op, keys, 828 wrTexture->GetExternalImageKey()); 829 auto it = mTextureHosts.find(wr::AsUint64(aKey)); 830 MOZ_ASSERT((it == mTextureHosts.end() && !aIsUpdate) || 831 (it != mTextureHosts.end() && aIsUpdate)); 832 if (it != mTextureHosts.end()) { 833 // Release Texture if it exists. 834 ReleaseTextureOfImage(aKey); 835 } 836 mTextureHosts.emplace(wr::AsUint64(aKey), 837 CompositableTextureHostRef(aTexture)); 838 return true; 839 } 840 841 RefPtr<DataSourceSurface> dSurf = aTexture->GetAsSurface(); 842 if (!dSurf) { 843 gfxCriticalNote 844 << "TextureHost does not return DataSourceSurface for extId:" 845 << wr::AsUint64(aExtId); 846 return false; 847 } 848 849 DataSourceSurface::MappedSurface map; 850 if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) { 851 gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:" 852 << wr::AsUint64(aExtId); 853 return false; 854 } 855 856 IntSize size = dSurf->GetSize(); 857 wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat()); 858 wr::Vec<uint8_t> data; 859 data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride)); 860 861 if (op == TextureHost::UPDATE_IMAGE) { 862 aResources.UpdateImageBuffer(aKey, descriptor, data); 863 } else { 864 aResources.AddImage(aKey, descriptor, data); 865 } 866 867 dSurf->Unmap(); 868 869 return true; 870 } 871 872 bool WebRenderBridgeParent::UpdateSharedExternalImage( 873 wr::ExternalImageId aExtId, wr::ImageKey aKey, 874 const ImageIntRect& aDirtyRect, wr::TransactionBuilder& aResources, 875 UniquePtr<ScheduleSharedSurfaceRelease>& aScheduleRelease) { 876 if (!MatchesNamespace(aKey)) { 877 MOZ_ASSERT_UNREACHABLE("Stale shared external image key (update)!"); 878 return true; 879 } 880 881 auto key = wr::AsUint64(aKey); 882 auto it = mSharedSurfaceIds.find(key); 883 if (it == mSharedSurfaceIds.end()) { 884 gfxCriticalNote << "Updating unknown shared surface: " << key; 885 return false; 886 } 887 888 RefPtr<DataSourceSurface> dSurf; 889 if (it->second == aExtId) { 890 dSurf = SharedSurfacesParent::Get(aExtId); 891 } else { 892 dSurf = SharedSurfacesParent::Acquire(aExtId); 893 } 894 895 if (!dSurf) { 896 gfxCriticalNote << "Shared surface does not exist for extId:" 897 << wr::AsUint64(aExtId); 898 return false; 899 } 900 901 if (!(it->second == aExtId)) { 902 // We already have a mapping for this image key, so ensure we release the 903 // previous external image ID. This can happen when an image is animated, 904 // and it is changing the external image that the animation points to. 905 if (!aScheduleRelease) { 906 aScheduleRelease = MakeUnique<ScheduleSharedSurfaceRelease>(this); 907 } 908 aScheduleRelease->Add(aKey, it->second); 909 it->second = aExtId; 910 } 911 912 // Prefer raw buffers, unless our backend requires native textures. 913 IntSize surfaceSize = dSurf->GetSize(); 914 TextureHost::NativeTexturePolicy policy = 915 TextureHost::BackendNativeTexturePolicy(mApi->GetBackendType(), 916 surfaceSize); 917 auto imageType = 918 policy == TextureHost::NativeTexturePolicy::REQUIRE 919 ? wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::Texture2D) 920 : wr::ExternalImageType::Buffer(); 921 wr::ImageDescriptor descriptor(surfaceSize, dSurf->Stride(), 922 dSurf->GetFormat()); 923 aResources.UpdateExternalImageWithDirtyRect( 924 aKey, descriptor, aExtId, imageType, wr::ToDeviceIntRect(aDirtyRect), 0, 925 /* aNormalizedUvs */ false); 926 927 return true; 928 } 929 930 void WebRenderBridgeParent::ObserveSharedSurfaceRelease( 931 const nsTArray<wr::ExternalImageKeyPair>& aPairs, 932 const bool& aFromCheckpoint) { 933 if (!mDestroyed) { 934 (void)SendWrReleasedImages(aPairs); 935 } 936 937 if (!aFromCheckpoint && mAsyncImageManager) { 938 // We failed to receive a checkpoint notification, so we are releasing these 939 // surfaces blind. Let's wait until the next epoch to complete releasing. 940 for (const auto& pair : aPairs) { 941 mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, pair.id); 942 } 943 return; 944 } 945 946 // We hit the checkpoint, so we know we can safely release the surfaces now. 947 for (const auto& pair : aPairs) { 948 SharedSurfacesParent::Release(pair.id); 949 } 950 } 951 952 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvUpdateResources( 953 const wr::IdNamespace& aIdNamespace, 954 nsTArray<OpUpdateResource>&& aResourceUpdates, 955 nsTArray<RefCountedShmem>&& aSmallShmems, 956 nsTArray<ipc::Shmem>&& aLargeShmems) { 957 const bool isValidMessage = aIdNamespace == mIdNamespace; 958 959 if (mDestroyed || !isValidMessage) { 960 wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems); 961 wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems); 962 return IPC_OK(); 963 } 964 965 LOG("WebRenderBridgeParent::RecvUpdateResources() PipelineId %" PRIx64 966 " Id %" PRIx64 " root %d", 967 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 968 IsRootWebRenderBridgeParent()); 969 970 wr::TransactionBuilder txn(mApi); 971 txn.SetLowPriority(!IsRootWebRenderBridgeParent()); 972 973 (void)GetNextWrEpoch(); 974 975 bool success = 976 UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn); 977 wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems); 978 wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems); 979 980 // Even when txn.IsResourceUpdatesEmpty() is true, there could be resource 981 // updates. It is handled by WebRenderTextureHostWrapper. In this case 982 // txn.IsRenderedFrameInvalidated() becomes true. 983 if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) { 984 // There are resource updates, then we update Epoch of transaction. 985 txn.UpdateEpoch(mPipelineId, mWrEpoch); 986 mAsyncImageManager->SetWillGenerateFrame(); 987 ScheduleGenerateFrame(wr::RenderReasons::RESOURCE_UPDATE); 988 } else { 989 // If TransactionBuilder does not have resource updates nor display list, 990 // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no 991 // need to update WrEpoch. 992 // Then we want to rollback WrEpoch. See Bug 1490117. 993 RollbackWrEpoch(); 994 } 995 996 mApi->SendTransaction(txn); 997 998 if (!success) { 999 return IPC_FAIL(this, "Invalid WebRender resource data shmem or address."); 1000 } 1001 1002 return IPC_OK(); 1003 } 1004 1005 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvDeleteCompositorAnimations( 1006 nsTArray<uint64_t>&& aIds) { 1007 if (mDestroyed) { 1008 return IPC_OK(); 1009 } 1010 1011 LOG("WebRenderBridgeParent::RecvDeleteCompositorAnimations() PipelineId " 1012 "%" PRIx64 " Id %" PRIx64 " root %d", 1013 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 1014 IsRootWebRenderBridgeParent()); 1015 1016 // Once mWrEpoch has been rendered, we can delete these compositor animations 1017 mCompositorAnimationsToDelete.push( 1018 CompositorAnimationIdsForEpoch(mWrEpoch, std::move(aIds))); 1019 return IPC_OK(); 1020 } 1021 1022 void WebRenderBridgeParent::RemoveEpochDataPriorTo( 1023 const wr::Epoch& aRenderedEpoch) { 1024 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 1025 sampler->RemoveEpochDataPriorTo(mCompositorAnimationsToDelete, 1026 mActiveAnimations, aRenderedEpoch); 1027 } 1028 } 1029 1030 bool WebRenderBridgeParent::IsRootWebRenderBridgeParent() const { 1031 return !!mWidget; 1032 } 1033 1034 void WebRenderBridgeParent::BeginRecording(const TimeStamp& aRecordingStart) { 1035 mApi->BeginRecording(aRecordingStart, mPipelineId); 1036 } 1037 1038 RefPtr<wr::WebRenderAPI::EndRecordingPromise> 1039 WebRenderBridgeParent::EndRecording() { 1040 return mApi->EndRecording(); 1041 } 1042 1043 void WebRenderBridgeParent::AddPendingScrollPayload( 1044 CompositionPayload& aPayload, const VsyncId& aCompositeStartId) { 1045 auto pendingScrollPayloads = mPendingScrollPayloads.Lock(); 1046 nsTArray<CompositionPayload>* payloads = 1047 pendingScrollPayloads->GetOrInsertNew(aCompositeStartId.mId); 1048 1049 payloads->AppendElement(aPayload); 1050 } 1051 1052 nsTArray<CompositionPayload> WebRenderBridgeParent::TakePendingScrollPayload( 1053 const VsyncId& aCompositeStartId) { 1054 auto pendingScrollPayloads = mPendingScrollPayloads.Lock(); 1055 nsTArray<CompositionPayload> payload; 1056 if (nsTArray<CompositionPayload>* storedPayload = 1057 pendingScrollPayloads->Get(aCompositeStartId.mId)) { 1058 payload.AppendElements(std::move(*storedPayload)); 1059 pendingScrollPayloads->Remove(aCompositeStartId.mId); 1060 } 1061 return payload; 1062 } 1063 1064 CompositorBridgeParent* WebRenderBridgeParent::GetRootCompositorBridgeParent() 1065 const { 1066 if (!mCompositorBridge) { 1067 return nullptr; 1068 } 1069 1070 if (IsRootWebRenderBridgeParent()) { 1071 // This WebRenderBridgeParent is attached to the root 1072 // CompositorBridgeParent. 1073 return static_cast<CompositorBridgeParent*>(mCompositorBridge); 1074 } 1075 1076 // Otherwise, this WebRenderBridgeParent is attached to a 1077 // ContentCompositorBridgeParent so we have an extra level of 1078 // indirection to unravel. 1079 CompositorBridgeParent::LayerTreeState* lts = 1080 CompositorBridgeParent::GetIndirectShadowTree(GetLayersId()); 1081 if (!lts) { 1082 return nullptr; 1083 } 1084 return lts->mParent; 1085 } 1086 1087 RefPtr<WebRenderBridgeParent> 1088 WebRenderBridgeParent::GetRootWebRenderBridgeParent() const { 1089 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 1090 if (!cbp) { 1091 return nullptr; 1092 } 1093 1094 return cbp->GetWebRenderBridgeParent(); 1095 } 1096 1097 void WebRenderBridgeParent::UpdateAPZFocusState(const FocusTarget& aFocus) { 1098 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 1099 if (!cbp) { 1100 return; 1101 } 1102 LayersId rootLayersId = cbp->RootLayerTreeId(); 1103 if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) { 1104 apz->UpdateFocusState(rootLayersId, GetLayersId(), aFocus); 1105 } 1106 } 1107 1108 void WebRenderBridgeParent::UpdateAPZScrollData(const wr::Epoch& aEpoch, 1109 WebRenderScrollData&& aData) { 1110 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 1111 if (!cbp) { 1112 return; 1113 } 1114 LayersId rootLayersId = cbp->RootLayerTreeId(); 1115 if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) { 1116 apz->UpdateScrollDataAndTreeState(rootLayersId, GetLayersId(), aEpoch, 1117 std::move(aData)); 1118 } 1119 } 1120 1121 void WebRenderBridgeParent::UpdateAPZScrollOffsets( 1122 ScrollUpdatesMap&& aUpdates, uint32_t aPaintSequenceNumber) { 1123 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 1124 if (!cbp) { 1125 return; 1126 } 1127 LayersId rootLayersId = cbp->RootLayerTreeId(); 1128 if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) { 1129 apz->UpdateScrollOffsets(rootLayersId, GetLayersId(), std::move(aUpdates), 1130 aPaintSequenceNumber); 1131 } 1132 } 1133 1134 void WebRenderBridgeParent::SetAPZSampleTime() { 1135 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 1136 if (!cbp) { 1137 return; 1138 } 1139 if (RefPtr<APZSampler> apz = cbp->GetAPZSampler()) { 1140 SampleTime animationTime; 1141 if (Maybe<TimeStamp> testTime = cbp->GetTestingTimeStamp()) { 1142 animationTime = SampleTime::FromTest(*testTime); 1143 } else { 1144 animationTime = mCompositorScheduler->GetLastComposeTime(); 1145 } 1146 TimeDuration frameInterval = cbp->GetVsyncInterval(); 1147 // As with the non-webrender codepath in AsyncCompositionManager, we want to 1148 // use the timestamp for the next vsync when advancing animations. 1149 if (frameInterval != TimeDuration::Forever()) { 1150 animationTime = animationTime + frameInterval; 1151 } 1152 apz->SetSampleTime(animationTime); 1153 } 1154 } 1155 1156 bool WebRenderBridgeParent::SetDisplayList( 1157 const LayoutDeviceRect& aRect, ipc::ByteBuf&& aDLItems, 1158 ipc::ByteBuf&& aDLCache, ipc::ByteBuf&& aSpatialTreeDL, 1159 const wr::BuiltDisplayListDescriptor& aDLDesc, 1160 const nsTArray<OpUpdateResource>& aResourceUpdates, 1161 const nsTArray<RefCountedShmem>& aSmallShmems, 1162 const nsTArray<ipc::Shmem>& aLargeShmems, const TimeStamp& aTxnStartTime, 1163 wr::TransactionBuilder& aTxn, wr::Epoch aWrEpoch, const VsyncId& aVsyncId, 1164 bool aRenderOffscreen) { 1165 bool success = 1166 UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, aTxn); 1167 1168 wr::Vec<uint8_t> dlItems(std::move(aDLItems)); 1169 wr::Vec<uint8_t> dlCache(std::move(aDLCache)); 1170 wr::Vec<uint8_t> dlSpatialTreeData(std::move(aSpatialTreeDL)); 1171 1172 if (IsRootWebRenderBridgeParent()) { 1173 LayoutDeviceIntSize widgetSize = mWidget->GetClientSize(); 1174 LayoutDeviceIntRect rect = 1175 LayoutDeviceIntRect(LayoutDeviceIntPoint(), widgetSize); 1176 aTxn.SetDocumentView(rect); 1177 } 1178 1179 wr::PipelineId pipelineId = mPipelineId; 1180 if (aRenderOffscreen) { 1181 pipelineId = gfx::GetTemporaryWebRenderPipelineId(pipelineId); 1182 } 1183 1184 aTxn.SetDisplayList(aWrEpoch, pipelineId, aDLDesc, dlItems, dlCache, 1185 dlSpatialTreeData); 1186 1187 if (aRenderOffscreen) { 1188 aTxn.RenderOffscreen(pipelineId); 1189 aTxn.RemovePipeline(pipelineId); 1190 } else { 1191 MaybeNotifyOfLayers(aTxn, true); 1192 } 1193 1194 if (!IsRootWebRenderBridgeParent() && !aRenderOffscreen) { 1195 aTxn.Notify(wr::Checkpoint::SceneBuilt, MakeUnique<SceneBuiltNotification>( 1196 this, aWrEpoch, aTxnStartTime)); 1197 } 1198 1199 NeedIncreasedMaxDirtyPageModifier(); 1200 1201 mApi->SendTransaction(aTxn); 1202 1203 // We will schedule generating a frame after the scene 1204 // build is done, so we don't need to do it here. 1205 return success; 1206 } 1207 1208 bool WebRenderBridgeParent::ProcessDisplayListData( 1209 DisplayListData& aDisplayList, wr::Epoch aWrEpoch, 1210 const TimeStamp& aTxnStartTime, bool aValidTransaction, 1211 bool aRenderOffscreen, const VsyncId& aVsyncId) { 1212 wr::TransactionBuilder txn(mApi, /* aUseSceneBuilderThread */ true, 1213 mRemoteTextureTxnScheduler, mFwdTransactionId); 1214 Maybe<wr::AutoTransactionSender> sender; 1215 1216 if (aDisplayList.mScrollData && !aDisplayList.mScrollData->Validate()) { 1217 // If the scroll data is invalid, the entire transaction needs to be dropped 1218 // because the scroll data and the display list cross-reference each other. 1219 MOZ_ASSERT( 1220 false, 1221 "Content sent malformed scroll data (or validation check has a bug)"); 1222 aValidTransaction = false; 1223 } 1224 1225 if (!aValidTransaction) { 1226 return true; 1227 } 1228 1229 MOZ_ASSERT(aDisplayList.mIdNamespace == mIdNamespace); 1230 1231 // Note that this needs to happen before the display list transaction is 1232 // sent to WebRender, so that the UpdateHitTestingTree call is guaranteed to 1233 // be in the updater queue at the time that the scene swap completes. 1234 if (aDisplayList.mScrollData) { 1235 UpdateAPZScrollData(aWrEpoch, std::move(aDisplayList.mScrollData.ref())); 1236 } 1237 1238 txn.SetLowPriority(!IsRootWebRenderBridgeParent()); 1239 sender.emplace(mApi, &txn); 1240 bool success = true; 1241 1242 success = 1243 ProcessWebRenderParentCommands(aDisplayList.mCommands, txn) && success; 1244 1245 if (aDisplayList.mDLItems && aDisplayList.mDLCache && 1246 aDisplayList.mDLSpatialTree) { 1247 success = SetDisplayList( 1248 aDisplayList.mRect, std::move(aDisplayList.mDLItems.ref()), 1249 std::move(aDisplayList.mDLCache.ref()), 1250 std::move(aDisplayList.mDLSpatialTree.ref()), 1251 aDisplayList.mDLDesc, aDisplayList.mResourceUpdates, 1252 aDisplayList.mSmallShmems, aDisplayList.mLargeShmems, 1253 aTxnStartTime, txn, aWrEpoch, aVsyncId, aRenderOffscreen) && 1254 success; 1255 } 1256 1257 return success; 1258 } 1259 1260 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList( 1261 DisplayListData&& aDisplayList, nsTArray<OpDestroy>&& aToDestroy, 1262 const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId, 1263 const bool& aContainsSVGGroup, const VsyncId& aVsyncId, 1264 const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, 1265 const TimeStamp& aTxnStartTime, const nsACString& aTxnURL, 1266 const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads, 1267 const bool& aRenderOffscreen) { 1268 if (mDestroyed) { 1269 for (const auto& op : aToDestroy) { 1270 DestroyActor(op); 1271 } 1272 wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems); 1273 wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems); 1274 return IPC_OK(); 1275 } 1276 1277 LOG("WebRenderBridgeParent::RecvSetDisplayList() PipelineId %" PRIx64 1278 " Id %" PRIx64 " root %d", 1279 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 1280 IsRootWebRenderBridgeParent()); 1281 1282 if (!IsRootWebRenderBridgeParent()) { 1283 CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL, 1284 aTxnURL); 1285 } 1286 1287 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 1288 uint64_t innerWindowId = cbp ? cbp->GetInnerWindowId() : 0; 1289 AUTO_PROFILER_MARKER_INNERWINDOWID("SetDisplayList", GRAPHICS, innerWindowId); 1290 UpdateFwdTransactionId(aFwdTransactionId); 1291 1292 // This ensures that destroy operations are always processed. It is not safe 1293 // to early-return from RecvDPEnd without doing so. 1294 AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender( 1295 this, &aToDestroy); 1296 1297 wr::Epoch wrEpoch = GetNextWrEpoch(); 1298 1299 mReceivedDisplayList = true; 1300 1301 if (aDisplayList.mScrollData && aDisplayList.mScrollData->IsFirstPaint()) { 1302 mIsFirstPaint = true; 1303 } 1304 1305 bool validTransaction = aDisplayList.mIdNamespace == mIdNamespace; 1306 bool success = 1307 ProcessDisplayListData(aDisplayList, wrEpoch, aTxnStartTime, 1308 validTransaction, aRenderOffscreen, aVsyncId); 1309 1310 if (!IsRootWebRenderBridgeParent()) { 1311 aPayloads.AppendElement( 1312 CompositionPayload{CompositionPayloadType::eContentPaint, aFwdTime}); 1313 } 1314 1315 HoldPendingTransactionId(wrEpoch, aTransactionId, aContainsSVGGroup, aVsyncId, 1316 aVsyncStartTime, aRefreshStartTime, aTxnStartTime, 1317 aTxnURL, aFwdTime, mIsFirstPaint, 1318 std::move(aPayloads)); 1319 mIsFirstPaint = false; 1320 1321 if (!validTransaction) { 1322 // Pretend we composited since someone is wating for this event, 1323 // though DisplayList was not pushed to webrender. 1324 if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) { 1325 TimeStamp now = TimeStamp::Now(); 1326 cbp->NotifyPipelineRendered(mPipelineId, wrEpoch, VsyncId(), now, now, 1327 now); 1328 } 1329 } 1330 1331 wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems); 1332 wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems); 1333 1334 if (!success) { 1335 return IPC_FAIL(this, "Failed to process DisplayListData."); 1336 } 1337 1338 return IPC_OK(); 1339 } 1340 1341 bool WebRenderBridgeParent::ProcessEmptyTransactionUpdates( 1342 TransactionData& aData, bool* aScheduleComposite) { 1343 *aScheduleComposite = false; 1344 wr::TransactionBuilder txn(mApi, /* aUseSceneBuilderThread */ true, 1345 mRemoteTextureTxnScheduler, mFwdTransactionId); 1346 txn.SetLowPriority(!IsRootWebRenderBridgeParent()); 1347 1348 if (!aData.mScrollUpdates.IsEmpty()) { 1349 UpdateAPZScrollOffsets(std::move(aData.mScrollUpdates), 1350 aData.mPaintSequenceNumber); 1351 } 1352 1353 // Update WrEpoch for UpdateResources() and ProcessWebRenderParentCommands(). 1354 // WrEpoch is used to manage ExternalImages lifetimes in 1355 // AsyncImagePipelineManager. 1356 (void)GetNextWrEpoch(); 1357 1358 const bool validTransaction = aData.mIdNamespace == mIdNamespace; 1359 bool success = true; 1360 1361 if (validTransaction) { 1362 success = UpdateResources(aData.mResourceUpdates, aData.mSmallShmems, 1363 aData.mLargeShmems, txn); 1364 if (!aData.mCommands.IsEmpty()) { 1365 success = ProcessWebRenderParentCommands(aData.mCommands, txn) && success; 1366 } 1367 } 1368 1369 MaybeNotifyOfLayers(txn, true); 1370 1371 // Even when txn.IsResourceUpdatesEmpty() is true, there could be resource 1372 // updates. It is handled by WebRenderTextureHostWrapper. In this case 1373 // txn.IsRenderedFrameInvalidated() becomes true. 1374 if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) { 1375 // There are resource updates, then we update Epoch of transaction. 1376 txn.UpdateEpoch(mPipelineId, mWrEpoch); 1377 *aScheduleComposite = true; 1378 NeedIncreasedMaxDirtyPageModifier(); 1379 } else { 1380 // If TransactionBuilder does not have resource updates nor display list, 1381 // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no 1382 // need to update WrEpoch. 1383 // Then we want to rollback WrEpoch. See Bug 1490117. 1384 RollbackWrEpoch(); 1385 } 1386 1387 if (!txn.IsEmpty()) { 1388 mApi->SendTransaction(txn); 1389 } 1390 1391 if (*aScheduleComposite) { 1392 mAsyncImageManager->SetWillGenerateFrame(); 1393 } 1394 1395 return success; 1396 } 1397 1398 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction( 1399 const FocusTarget& aFocusTarget, Maybe<TransactionData>&& aTransactionData, 1400 nsTArray<OpDestroy>&& aToDestroy, const uint64_t& aFwdTransactionId, 1401 const TransactionId& aTransactionId, const VsyncId& aVsyncId, 1402 const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, 1403 const TimeStamp& aTxnStartTime, const nsACString& aTxnURL, 1404 const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads) { 1405 if (mDestroyed) { 1406 for (const auto& op : aToDestroy) { 1407 DestroyActor(op); 1408 } 1409 if (aTransactionData) { 1410 wr::IpcResourceUpdateQueue::ReleaseShmems(this, 1411 aTransactionData->mSmallShmems); 1412 wr::IpcResourceUpdateQueue::ReleaseShmems(this, 1413 aTransactionData->mLargeShmems); 1414 } 1415 return IPC_OK(); 1416 } 1417 1418 LOG("WebRenderBridgeParent::RecvEmptyTransaction() PipelineId %" PRIx64 1419 " Id %" PRIx64 " root %d", 1420 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 1421 IsRootWebRenderBridgeParent()); 1422 1423 if (!IsRootWebRenderBridgeParent()) { 1424 CrashReporter::RecordAnnotationNSCString(CrashReporter::Annotation::URL, 1425 aTxnURL); 1426 } 1427 1428 AUTO_PROFILER_MARKER("EmptyTransaction", GRAPHICS); 1429 UpdateFwdTransactionId(aFwdTransactionId); 1430 1431 // This ensures that destroy operations are always processed. It is not safe 1432 // to early-return without doing so. 1433 AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender( 1434 this, &aToDestroy); 1435 1436 UpdateAPZFocusState(aFocusTarget); 1437 1438 bool scheduleAnyComposite = false; 1439 wr::RenderReasons renderReasons = wr::RenderReasons::NONE; 1440 1441 bool success = true; 1442 if (aTransactionData) { 1443 bool scheduleComposite = false; 1444 success = 1445 ProcessEmptyTransactionUpdates(*aTransactionData, &scheduleComposite); 1446 scheduleAnyComposite = scheduleAnyComposite || scheduleComposite; 1447 renderReasons |= wr::RenderReasons::RESOURCE_UPDATE; 1448 } 1449 1450 // If we are going to kick off a new composite as a result of this 1451 // transaction, or if there are already composite-triggering pending 1452 // transactions inflight, then set sendDidComposite to false because we will 1453 // send the DidComposite message after the composite occurs. 1454 // If there are no pending transactions and we're not going to do a 1455 // composite, then we leave sendDidComposite as true so we just send 1456 // the DidComposite notification now. 1457 bool sendDidComposite = 1458 !scheduleAnyComposite && mPendingTransactionIds.empty(); 1459 1460 // Only register a value for CONTENT_FRAME_TIME telemetry if we actually drew 1461 // something. It is for consistency with disabling WebRender. 1462 HoldPendingTransactionId(mWrEpoch, aTransactionId, false, aVsyncId, 1463 aVsyncStartTime, aRefreshStartTime, aTxnStartTime, 1464 aTxnURL, aFwdTime, 1465 /* aIsFirstPaint */ false, std::move(aPayloads), 1466 /* aUseForTelemetry */ scheduleAnyComposite); 1467 1468 if (scheduleAnyComposite) { 1469 ScheduleGenerateFrame(renderReasons); 1470 } else if (sendDidComposite) { 1471 // The only thing in the pending transaction id queue should be the entry 1472 // we just added, and now we're going to pretend we rendered it 1473 MOZ_ASSERT(mPendingTransactionIds.size() == 1); 1474 if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) { 1475 TimeStamp now = TimeStamp::Now(); 1476 cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now, 1477 now); 1478 } 1479 } 1480 1481 if (aTransactionData) { 1482 wr::IpcResourceUpdateQueue::ReleaseShmems(this, 1483 aTransactionData->mSmallShmems); 1484 wr::IpcResourceUpdateQueue::ReleaseShmems(this, 1485 aTransactionData->mLargeShmems); 1486 } 1487 1488 if (!success) { 1489 return IPC_FAIL(this, "Failed to process empty transaction update."); 1490 } 1491 1492 return IPC_OK(); 1493 } 1494 1495 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetFocusTarget( 1496 const FocusTarget& aFocusTarget) { 1497 UpdateAPZFocusState(aFocusTarget); 1498 return IPC_OK(); 1499 } 1500 1501 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvParentCommands( 1502 const wr::IdNamespace& aIdNamespace, 1503 nsTArray<WebRenderParentCommand>&& aCommands) { 1504 if (mDestroyed) { 1505 return IPC_OK(); 1506 } 1507 1508 const bool isValidMessage = aIdNamespace == mIdNamespace; 1509 if (!isValidMessage) { 1510 return IPC_OK(); 1511 } 1512 1513 LOG("WebRenderBridgeParent::RecvParentCommands() PipelineId %" PRIx64 1514 " Id %" PRIx64 " root %d", 1515 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 1516 IsRootWebRenderBridgeParent()); 1517 1518 wr::TransactionBuilder txn(mApi); 1519 txn.SetLowPriority(!IsRootWebRenderBridgeParent()); 1520 bool success = ProcessWebRenderParentCommands(aCommands, txn); 1521 NeedIncreasedMaxDirtyPageModifier(); 1522 mApi->SendTransaction(txn); 1523 1524 if (!success) { 1525 return IPC_FAIL(this, "Invalid parent command found"); 1526 } 1527 1528 return IPC_OK(); 1529 } 1530 1531 bool WebRenderBridgeParent::ProcessWebRenderParentCommands( 1532 const nsTArray<WebRenderParentCommand>& aCommands, 1533 wr::TransactionBuilder& aTxn) { 1534 // Transaction for async image pipeline that uses ImageBridge always need to 1535 // be non low priority. 1536 wr::TransactionBuilder txnForImageBridge(mApi->GetRootAPI()); 1537 wr::AutoTransactionSender sender(mApi->GetRootAPI(), &txnForImageBridge); 1538 1539 bool success = true; 1540 for (nsTArray<WebRenderParentCommand>::index_type i = 0; 1541 i < aCommands.Length(); ++i) { 1542 const WebRenderParentCommand& cmd = aCommands[i]; 1543 switch (cmd.type()) { 1544 case WebRenderParentCommand::TOpAddPipelineIdForCompositable: { 1545 const OpAddPipelineIdForCompositable& op = 1546 cmd.get_OpAddPipelineIdForCompositable(); 1547 AddPipelineIdForCompositable(op.pipelineId(), op.handle(), op.owner(), 1548 aTxn, txnForImageBridge); 1549 break; 1550 } 1551 case WebRenderParentCommand::TOpRemovePipelineIdForCompositable: { 1552 const OpRemovePipelineIdForCompositable& op = 1553 cmd.get_OpRemovePipelineIdForCompositable(); 1554 auto* pendingOps = mApi->GetPendingAsyncImagePipelineOps(aTxn); 1555 1556 RemovePipelineIdForCompositable(op.pipelineId(), pendingOps, aTxn); 1557 break; 1558 } 1559 case WebRenderParentCommand::TOpReleaseTextureOfImage: { 1560 const OpReleaseTextureOfImage& op = cmd.get_OpReleaseTextureOfImage(); 1561 ReleaseTextureOfImage(op.key()); 1562 break; 1563 } 1564 case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: { 1565 const OpUpdateAsyncImagePipeline& op = 1566 cmd.get_OpUpdateAsyncImagePipeline(); 1567 1568 auto* pendingOps = mApi->GetPendingAsyncImagePipelineOps(aTxn); 1569 auto* pendingRemotetextures = mApi->GetPendingRemoteTextureInfoList(); 1570 1571 mAsyncImageManager->UpdateAsyncImagePipeline( 1572 op.pipelineId(), op.scBounds(), op.rotation(), op.filter(), 1573 op.mixBlendMode()); 1574 MOZ_ASSERT_IF(IsRootWebRenderBridgeParent(), !pendingRemotetextures); 1575 mAsyncImageManager->ApplyAsyncImageForPipeline( 1576 op.pipelineId(), aTxn, txnForImageBridge, pendingOps, 1577 pendingRemotetextures); 1578 break; 1579 } 1580 case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: { 1581 const OpUpdatedAsyncImagePipeline& op = 1582 cmd.get_OpUpdatedAsyncImagePipeline(); 1583 aTxn.InvalidateRenderedFrame(wr::RenderReasons::ASYNC_IMAGE); 1584 1585 auto* pendingOps = mApi->GetPendingAsyncImagePipelineOps(aTxn); 1586 auto* pendingRemotetextures = mApi->GetPendingRemoteTextureInfoList(); 1587 1588 MOZ_ASSERT_IF(IsRootWebRenderBridgeParent(), !pendingRemotetextures); 1589 mAsyncImageManager->ApplyAsyncImageForPipeline( 1590 op.pipelineId(), aTxn, txnForImageBridge, pendingOps, 1591 pendingRemotetextures); 1592 break; 1593 } 1594 case WebRenderParentCommand::TCompositableOperation: { 1595 if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) { 1596 NS_ERROR("ReceiveCompositableUpdate failed"); 1597 } 1598 break; 1599 } 1600 case WebRenderParentCommand::TOpAddCompositorAnimations: { 1601 const OpAddCompositorAnimations& op = 1602 cmd.get_OpAddCompositorAnimations(); 1603 CompositorAnimations data(std::move(op.data())); 1604 // AnimationHelper::GetNextCompositorAnimationsId() encodes the child 1605 // process PID in the upper 32 bits of the id, verify that this is as 1606 // expected. 1607 if ((data.id() >> 32) != (uint64_t)OtherPid()) { 1608 gfxCriticalNote << "TOpAddCompositorAnimations bad id"; 1609 success = false; 1610 continue; 1611 } 1612 if (data.animations().Length()) { 1613 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 1614 sampler->SetAnimations(data.id(), GetLayersId(), data.animations()); 1615 const auto activeAnim = mActiveAnimations.find(data.id()); 1616 if (activeAnim == mActiveAnimations.end()) { 1617 mActiveAnimations.emplace(data.id(), mWrEpoch); 1618 } else { 1619 // Update wr::Epoch if the animation already exists. 1620 activeAnim->second = mWrEpoch; 1621 } 1622 } 1623 } 1624 break; 1625 } 1626 default: { 1627 // other commands are handle on the child 1628 break; 1629 } 1630 } 1631 } 1632 1633 MOZ_ASSERT(success); 1634 return success; 1635 } 1636 1637 void WebRenderBridgeParent::FlushSceneBuilds() { 1638 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1639 1640 // Since we are sending transactions through the scene builder thread, we need 1641 // to block until all the inflight transactions have been processed. This 1642 // flush message blocks until all previously sent scenes have been built 1643 // and received by the render backend thread. 1644 mApi->FlushSceneBuilder(); 1645 // The post-swap hook for async-scene-building calls the 1646 // ScheduleRenderOnCompositorThread function from the scene builder thread, 1647 // which then triggers a call to ScheduleGenerateFrame() on the compositor 1648 // thread. But since *this* function is running on the compositor thread, 1649 // that scheduling will not happen until this call stack unwinds (or we 1650 // could spin a nested event loop, but that's more messy). Instead, we 1651 // simulate it ourselves by calling ScheduleGenerateFrame() directly. 1652 // Note also that the post-swap hook will run and do another 1653 // ScheduleGenerateFrame() after we unwind here, so we will end up with an 1654 // extra render/composite that is probably avoidable, but in practice we 1655 // shouldn't be calling this function all that much in production so this 1656 // is probably fine. If it becomes an issue we can add more state tracking 1657 // machinery to optimize it away. 1658 ScheduleGenerateFrame(wr::RenderReasons::FLUSH); 1659 } 1660 1661 void WebRenderBridgeParent::FlushFrameGeneration(wr::RenderReasons aReasons) { 1662 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1663 MOZ_ASSERT(IsRootWebRenderBridgeParent()); // This function is only useful on 1664 // the root WRBP 1665 1666 // This forces a new GenerateFrame transaction to be sent to the render 1667 // backend thread, if one is pending. This doesn't block on any other threads. 1668 if (mCompositorScheduler->NeedsComposite()) { 1669 mCompositorScheduler->CancelCurrentCompositeTask(); 1670 // Update timestamp of scheduler for APZ and animation. 1671 mCompositorScheduler->UpdateLastComposeTime(); 1672 MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true, 1673 aReasons | wr::RenderReasons::FLUSH); 1674 } 1675 } 1676 1677 void WebRenderBridgeParent::FlushFramePresentation() { 1678 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1679 1680 // This sends a message to the render backend thread to send a message 1681 // to the renderer thread, and waits for that message to be processed. So 1682 // this effectively blocks on the render backend and renderer threads, 1683 // following the same codepath that WebRender takes to render and composite 1684 // a frame. 1685 mApi->WaitUntilPresentationFlushed(); 1686 } 1687 1688 void WebRenderBridgeParent::DisableNativeCompositor() { 1689 // Make sure that SceneBuilder thread does not have a task. 1690 mApi->FlushSceneBuilder(); 1691 // Disable WebRender's native compositor usage 1692 mApi->EnableNativeCompositor(false); 1693 // Ensure we generate and render a frame immediately. 1694 ScheduleForcedGenerateFrame(wr::RenderReasons::CONFIG_CHANGE); 1695 1696 mDisablingNativeCompositor = true; 1697 } 1698 1699 void WebRenderBridgeParent::UpdateQualitySettings() { 1700 if (!IsRootWebRenderBridgeParent()) { 1701 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1702 return; 1703 } 1704 wr::TransactionBuilder txn(mApi); 1705 txn.UpdateQualitySettings(gfxVars::ForceSubpixelAAWherePossible()); 1706 mApi->SendTransaction(txn); 1707 } 1708 1709 void WebRenderBridgeParent::UpdateDebugFlags() { 1710 if (!IsRootWebRenderBridgeParent()) { 1711 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1712 return; 1713 } 1714 1715 mApi->UpdateDebugFlags(gfxVars::WebRenderDebugFlags()); 1716 } 1717 1718 void WebRenderBridgeParent::UpdateProfilerUI() { 1719 if (!IsRootWebRenderBridgeParent()) { 1720 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1721 return; 1722 } 1723 1724 nsCString uiString = gfxVars::GetWebRenderProfilerUIOrDefault(); 1725 mApi->SetProfilerUI(uiString); 1726 } 1727 1728 void WebRenderBridgeParent::UpdateParameters() { 1729 if (!IsRootWebRenderBridgeParent()) { 1730 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1731 return; 1732 } 1733 1734 uint32_t count = gfxVars::WebRenderBatchingLookback(); 1735 mApi->SetBatchingLookback(count); 1736 mApi->SetInt(wr::IntParameter::BatchedUploadThreshold, 1737 gfxVars::WebRenderBatchedUploadThreshold()); 1738 uint32_t slow_cpu_frame = gfxVars::WebRenderSlowCpuFrameThreshold(); 1739 mApi->SetFloat(wr::FloatParameter::SlowCpuFrameThreshold, slow_cpu_frame); 1740 1741 mBlobTileSize = gfxVars::WebRenderBlobTileSize(); 1742 } 1743 1744 void WebRenderBridgeParent::UpdateBoolParameters() { 1745 if (!IsRootWebRenderBridgeParent()) { 1746 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1747 return; 1748 } 1749 1750 uint32_t bits = gfxVars::WebRenderBoolParameters(); 1751 uint32_t changedBits = mBoolParameterBits ^ bits; 1752 1753 for (auto paramName : MakeEnumeratedRange(wr::BoolParameter::Sentinel)) { 1754 uint32_t i = (uint32_t)paramName; 1755 if (changedBits & (1 << i)) { 1756 bool value = (bits & (1 << i)) != 0; 1757 mApi->SetBool(paramName, value); 1758 } 1759 } 1760 mBoolParameterBits = bits; 1761 } 1762 1763 #if defined(MOZ_WIDGET_ANDROID) 1764 void WebRenderBridgeParent::RequestScreenPixels( 1765 UiCompositorControllerParent* aController) { 1766 mScreenPixelsTarget = aController; 1767 } 1768 1769 void WebRenderBridgeParent::MaybeCaptureScreenPixels() { 1770 if (!mScreenPixelsTarget) { 1771 return; 1772 } 1773 1774 if (mDestroyed) { 1775 return; 1776 } 1777 1778 if (auto* cbp = GetRootCompositorBridgeParent()) { 1779 cbp->FlushPendingWrTransactionEventsWithWait(); 1780 } 1781 1782 // This function should only get called in the root WRBP. 1783 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 1784 # ifdef DEBUG 1785 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 1786 MOZ_ASSERT(cbp && !cbp->IsPaused()); 1787 # endif 1788 1789 SurfaceFormat format = SurfaceFormat::R8G8B8A8; // On android we use RGBA8 1790 auto client_size = mWidget->GetClientSize(); 1791 size_t buffer_size = 1792 client_size.width * client_size.height * BytesPerPixel(format); 1793 1794 ipc::Shmem mem; 1795 if (!mScreenPixelsTarget->AllocPixelBuffer(buffer_size, &mem)) { 1796 // Failed to alloc shmem, Just bail out. 1797 return; 1798 } 1799 1800 IntSize size(client_size.width, client_size.height); 1801 1802 bool needsYFlip = false; 1803 mApi->Readback(TimeStamp::Now(), size, format, 1804 Range<uint8_t>(mem.get<uint8_t>(), buffer_size), &needsYFlip); 1805 1806 (void)mScreenPixelsTarget->SendScreenPixels( 1807 std::move(mem), ScreenIntSize(client_size.width, client_size.height), 1808 needsYFlip); 1809 1810 mScreenPixelsTarget = nullptr; 1811 } 1812 #endif 1813 1814 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot( 1815 NotNull<PTextureParent*> aTexture, bool* aNeedsYFlip) { 1816 *aNeedsYFlip = false; 1817 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 1818 if (mDestroyed || !cbp || cbp->IsPaused()) { 1819 return IPC_OK(); 1820 } 1821 1822 if (auto* cbp = GetRootCompositorBridgeParent()) { 1823 cbp->FlushPendingWrTransactionEventsWithWait(); 1824 } 1825 1826 LOG("WebRenderBridgeParent::RecvGetSnapshot() PipelineId %" PRIx64 1827 " Id %" PRIx64 " root %d", 1828 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 1829 IsRootWebRenderBridgeParent()); 1830 1831 // This function should only get called in the root WRBP. If this function 1832 // gets called in a non-root WRBP, we will set mForceRendering in this WRBP 1833 // but it will have no effect because CompositeToTarget (which reads the 1834 // flag) only gets invoked in the root WRBP. So we assert that this is the 1835 // root WRBP (i.e. has a non-null mWidget) to catch violations of this rule. 1836 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 1837 1838 RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture); 1839 if (!texture) { 1840 // We kill the content process rather than have it continue with an invalid 1841 // snapshot, that may be too harsh and we could decide to return some sort 1842 // of error to the child process and let it deal with it... 1843 return IPC_FAIL_NO_REASON(this); 1844 } 1845 1846 // XXX Add other TextureHost supports. 1847 // Only BufferTextureHost is supported now. 1848 BufferTextureHost* bufferTexture = texture->AsBufferTextureHost(); 1849 if (!bufferTexture) { 1850 // We kill the content process rather than have it continue with an invalid 1851 // snapshot, that may be too harsh and we could decide to return some sort 1852 // of error to the child process and let it deal with it... 1853 return IPC_FAIL_NO_REASON(this); 1854 } 1855 1856 TimeStamp start = TimeStamp::Now(); 1857 MOZ_ASSERT(bufferTexture->GetBufferDescriptor().type() == 1858 BufferDescriptor::TRGBDescriptor); 1859 DebugOnly<uint32_t> stride = ImageDataSerializer::GetRGBStride( 1860 bufferTexture->GetBufferDescriptor().get_RGBDescriptor()); 1861 uint8_t* buffer = bufferTexture->GetBuffer(); 1862 IntSize size = bufferTexture->GetSize(); 1863 1864 MOZ_ASSERT(buffer); 1865 // For now the only formats we get here are RGBA and BGRA, and code below is 1866 // assuming a bpp of 4. If we allow other formats, the code needs adjusting 1867 // accordingly. 1868 MOZ_ASSERT(BytesPerPixel(bufferTexture->GetFormat()) == 4); 1869 uint32_t buffer_size = size.width * size.height * 4; 1870 1871 // Assert the stride of the buffer is what webrender expects 1872 MOZ_ASSERT((uint32_t)(size.width * 4) == stride); 1873 1874 FlushSceneBuilds(); 1875 FlushFrameGeneration(wr::RenderReasons::SNAPSHOT); 1876 mApi->Readback(start, size, bufferTexture->GetFormat(), 1877 Range<uint8_t>(buffer, buffer_size), aNeedsYFlip); 1878 1879 return IPC_OK(); 1880 } 1881 1882 void WebRenderBridgeParent::AddPipelineIdForCompositable( 1883 const wr::PipelineId& aPipelineId, const CompositableHandle& aHandle, 1884 const CompositableHandleOwner& aOwner, wr::TransactionBuilder& aTxn, 1885 wr::TransactionBuilder& aTxnForImageBridge) { 1886 if (mDestroyed) { 1887 return; 1888 } 1889 1890 MOZ_ASSERT(mAsyncCompositables.find(wr::AsUint64(aPipelineId)) == 1891 mAsyncCompositables.end()); 1892 1893 RefPtr<CompositableHost> host; 1894 switch (aOwner) { 1895 case CompositableHandleOwner::WebRenderBridge: 1896 host = FindCompositable(aHandle); 1897 break; 1898 case CompositableHandleOwner::ImageBridge: { 1899 RefPtr<ImageBridgeParent> imageBridge = 1900 ImageBridgeParent::GetInstance(OtherPid()); 1901 if (!imageBridge) { 1902 return; 1903 } 1904 host = imageBridge->FindCompositable(aHandle); 1905 break; 1906 } 1907 } 1908 1909 if (!host) { 1910 return; 1911 } 1912 1913 WebRenderImageHost* wrHost = host->AsWebRenderImageHost(); 1914 MOZ_ASSERT(wrHost); 1915 if (!wrHost) { 1916 gfxCriticalNote 1917 << "Incompatible CompositableHost at WebRenderBridgeParent."; 1918 } 1919 1920 if (!wrHost) { 1921 return; 1922 } 1923 1924 wrHost->SetWrBridge(aPipelineId, this); 1925 mAsyncCompositables.emplace(wr::AsUint64(aPipelineId), wrHost); 1926 mAsyncImageManager->AddAsyncImagePipeline(aPipelineId, wrHost); 1927 1928 // If this is being called from WebRenderBridgeParent::RecvSetDisplayList, 1929 // then aTxn might contain a display list that references pipelines that 1930 // we just added to the async image manager. 1931 // If we send the display list alone then WR will not yet have the content for 1932 // the pipelines and so it will emit errors; the SetEmptyDisplayList call 1933 // below ensure that we provide its content to WR as part of the same 1934 // transaction. 1935 mAsyncImageManager->SetEmptyDisplayList(aPipelineId, aTxn, 1936 aTxnForImageBridge); 1937 } 1938 1939 void WebRenderBridgeParent::RemovePipelineIdForCompositable( 1940 const wr::PipelineId& aPipelineId, AsyncImagePipelineOps* aPendingOps, 1941 wr::TransactionBuilder& aTxn) { 1942 if (mDestroyed) { 1943 return; 1944 } 1945 1946 auto it = mAsyncCompositables.find(wr::AsUint64(aPipelineId)); 1947 if (it == mAsyncCompositables.end()) { 1948 return; 1949 } 1950 RefPtr<WebRenderImageHost>& wrHost = it->second; 1951 1952 wrHost->ClearWrBridge(aPipelineId, this); 1953 mAsyncImageManager->RemoveAsyncImagePipeline(aPipelineId, aPendingOps, aTxn); 1954 aTxn.RemovePipeline(aPipelineId); 1955 mAsyncCompositables.erase(wr::AsUint64(aPipelineId)); 1956 } 1957 1958 void WebRenderBridgeParent::DeleteImage(const ImageKey& aKey, 1959 wr::TransactionBuilder& aUpdates) { 1960 if (mDestroyed) { 1961 return; 1962 } 1963 1964 auto it = mSharedSurfaceIds.find(wr::AsUint64(aKey)); 1965 if (it != mSharedSurfaceIds.end()) { 1966 mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, it->second); 1967 mSharedSurfaceIds.erase(it); 1968 } 1969 1970 aUpdates.DeleteImage(aKey); 1971 } 1972 1973 void WebRenderBridgeParent::ReleaseTextureOfImage(const wr::ImageKey& aKey) { 1974 if (mDestroyed) { 1975 return; 1976 } 1977 1978 uint64_t id = wr::AsUint64(aKey); 1979 CompositableTextureHostRef texture; 1980 WebRenderTextureHost* wrTexture = nullptr; 1981 1982 auto it = mTextureHosts.find(id); 1983 if (it != mTextureHosts.end()) { 1984 wrTexture = (*it).second->AsWebRenderTextureHost(); 1985 } 1986 if (wrTexture) { 1987 mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, wrTexture); 1988 } 1989 mTextureHosts.erase(id); 1990 } 1991 1992 void WebRenderBridgeParent::MaybeNotifyOfLayers( 1993 wr::TransactionBuilder& aBuilder, bool aWillHaveLayers) { 1994 if (mLastNotifiedHasLayers == aWillHaveLayers) { 1995 return; 1996 } 1997 1998 aBuilder.Notify(wr::Checkpoint::SceneBuilt, 1999 MakeUnique<ScheduleObserveLayersUpdate>( 2000 mCompositorBridge, GetLayersId(), aWillHaveLayers)); 2001 mLastNotifiedHasLayers = aWillHaveLayers; 2002 } 2003 2004 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvClearCachedResources() { 2005 if (mDestroyed) { 2006 return IPC_OK(); 2007 } 2008 2009 LOG("WebRenderBridgeParent::RecvClearCachedResources() PipelineId %" PRIx64 2010 " Id %" PRIx64 " root %d", 2011 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2012 IsRootWebRenderBridgeParent()); 2013 2014 if (!IsRootWebRenderBridgeParent()) { 2015 mApi->FlushPendingWrTransactionEventsWithoutWait(); 2016 } 2017 2018 // Clear resources 2019 wr::TransactionBuilder txn(mApi); 2020 txn.SetLowPriority(true); 2021 txn.ClearDisplayList(GetNextWrEpoch(), mPipelineId); 2022 MaybeNotifyOfLayers(txn, false); 2023 mApi->SendTransaction(txn); 2024 2025 // Schedule generate frame to clean up Pipeline 2026 ScheduleGenerateFrame(wr::RenderReasons::CLEAR_RESOURCES); 2027 2028 ClearAnimationResources(); 2029 2030 return IPC_OK(); 2031 } 2032 2033 wr::Epoch WebRenderBridgeParent::UpdateWebRender( 2034 CompositorVsyncScheduler* aScheduler, RefPtr<wr::WebRenderAPI>&& aApi, 2035 AsyncImagePipelineManager* aImageMgr, 2036 const TextureFactoryIdentifier& aTextureFactoryIdentifier) { 2037 MOZ_ASSERT(!IsRootWebRenderBridgeParent()); 2038 MOZ_ASSERT(aScheduler); 2039 MOZ_ASSERT(aApi); 2040 MOZ_ASSERT(aImageMgr); 2041 2042 if (mDestroyed) { 2043 return mWrEpoch; 2044 } 2045 2046 // Update id name space to identify obsoleted keys. 2047 // Since usage of invalid keys could cause crash in webrender. 2048 mIdNamespace = aApi->GetNamespace(); 2049 // XXX Remove it when webrender supports sharing/moving Keys between different 2050 // webrender instances. 2051 // XXX It requests client to update/reallocate webrender related resources, 2052 // but parent side does not wait end of the update. 2053 // The code could become simpler if we could serialise old keys deallocation 2054 // and new keys allocation. But we do not do it, it is because client side 2055 // deallocate old layers/webrender keys after new layers/webrender keys 2056 // allocation. Without client side's layout refactoring, we could not finish 2057 // all old layers/webrender keys removals before new layer/webrender keys 2058 // allocation. In future, we could address the problem. 2059 (void)SendWrUpdated(mIdNamespace, aTextureFactoryIdentifier); 2060 CompositorBridgeParentBase* cBridge = mCompositorBridge; 2061 // XXX Stop to clear resources if webreder supports resources sharing between 2062 // different webrender instances. 2063 ClearResources(); 2064 mCompositorBridge = cBridge; 2065 mCompositorScheduler = aScheduler; 2066 mApi = aApi; 2067 mAsyncImageManager = aImageMgr; 2068 2069 // Register pipeline to updated AsyncImageManager. 2070 mAsyncImageManager->AddPipeline(mPipelineId, this); 2071 2072 LOG("WebRenderBridgeParent::UpdateWebRender() PipelineId %" PRIx64 2073 " Id %" PRIx64 " root %d", 2074 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2075 IsRootWebRenderBridgeParent()); 2076 2077 return GetNextWrEpoch(); // Update webrender epoch 2078 } 2079 2080 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvInvalidateRenderedFrame() { 2081 // This function should only get called in the root WRBP 2082 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2083 LOG("WebRenderBridgeParent::RecvInvalidateRenderedFrame() PipelineId %" PRIx64 2084 " Id %" PRIx64 " root %d", 2085 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2086 IsRootWebRenderBridgeParent()); 2087 2088 InvalidateRenderedFrame(wr::RenderReasons::WIDGET); 2089 return IPC_OK(); 2090 } 2091 2092 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvScheduleComposite( 2093 const wr::RenderReasons& aReasons) { 2094 LOG("WebRenderBridgeParent::RecvScheduleComposite() PipelineId %" PRIx64 2095 " Id %" PRIx64 " root %d", 2096 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2097 IsRootWebRenderBridgeParent()); 2098 2099 // Caller of LayerManager::ScheduleComposite() expects that it trigger 2100 // composite. Then we do not want to skip generate frame. 2101 ScheduleForcedGenerateFrame(aReasons); 2102 return IPC_OK(); 2103 } 2104 2105 void WebRenderBridgeParent::InvalidateRenderedFrame( 2106 wr::RenderReasons aReasons) { 2107 if (mDestroyed) { 2108 return; 2109 } 2110 2111 wr::TransactionBuilder fastTxn(mApi, /* aUseSceneBuilderThread */ false); 2112 fastTxn.InvalidateRenderedFrame(aReasons); 2113 mApi->SendTransaction(fastTxn); 2114 } 2115 2116 void WebRenderBridgeParent::ScheduleForcedGenerateFrame( 2117 wr::RenderReasons aReasons) { 2118 if (mDestroyed) { 2119 return; 2120 } 2121 2122 InvalidateRenderedFrame(aReasons); 2123 ScheduleGenerateFrame(aReasons); 2124 } 2125 2126 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvCapture() { 2127 if (!mDestroyed) { 2128 mApi->Capture(); 2129 } 2130 return IPC_OK(); 2131 } 2132 2133 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvStartCaptureSequence( 2134 const nsACString& aPath, const uint32_t& aFlags) { 2135 if (!mDestroyed) { 2136 mApi->StartCaptureSequence(aPath, aFlags); 2137 } 2138 return IPC_OK(); 2139 } 2140 2141 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvStopCaptureSequence() { 2142 if (!mDestroyed) { 2143 mApi->StopCaptureSequence(); 2144 } 2145 return IPC_OK(); 2146 } 2147 2148 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSyncWithCompositor() { 2149 LOG("WebRenderBridgeParent::RecvSyncWithCompositor() PipelineId %" PRIx64 2150 " Id %" PRIx64 " root %d", 2151 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2152 IsRootWebRenderBridgeParent()); 2153 2154 if (mDestroyed) { 2155 return IPC_OK(); 2156 } 2157 2158 FlushSceneBuilds(); 2159 if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) { 2160 root->FlushFrameGeneration(wr::RenderReasons::CONTENT_SYNC); 2161 } 2162 FlushFramePresentation(); 2163 // Finally, we force the AsyncImagePipelineManager to handle all the 2164 // pipeline updates produced in the last step, so that it frees any 2165 // unneeded textures. Then we can return from this sync IPC call knowing 2166 // that we've done everything we can to flush stuff on the compositor. 2167 mAsyncImageManager->ProcessPipelineUpdates(); 2168 2169 return IPC_OK(); 2170 } 2171 2172 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetConfirmedTargetAPZC( 2173 const uint64_t& aBlockId, nsTArray<ScrollableLayerGuid>&& aTargets) { 2174 for (size_t i = 0; i < aTargets.Length(); i++) { 2175 // Guard against bad data from hijacked child processes 2176 if (aTargets[i].mLayersId != GetLayersId()) { 2177 NS_ERROR( 2178 "Unexpected layers id in RecvSetConfirmedTargetAPZC; dropping " 2179 "message..."); 2180 return IPC_FAIL(this, "Bad layers id"); 2181 } 2182 } 2183 2184 if (mDestroyed) { 2185 return IPC_OK(); 2186 } 2187 mCompositorBridge->SetConfirmedTargetAPZC(GetLayersId(), aBlockId, 2188 std::move(aTargets)); 2189 return IPC_OK(); 2190 } 2191 2192 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetTestSampleTime( 2193 const TimeStamp& aTime) { 2194 if (mDestroyed) { 2195 return IPC_FAIL_NO_REASON(this); 2196 } 2197 2198 if (!mCompositorBridge->SetTestSampleTime(GetLayersId(), aTime)) { 2199 return IPC_FAIL_NO_REASON(this); 2200 } 2201 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 2202 sampler->EnterTestMode(); 2203 } 2204 2205 return IPC_OK(); 2206 } 2207 2208 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvLeaveTestMode() { 2209 if (mDestroyed) { 2210 return IPC_FAIL_NO_REASON(this); 2211 } 2212 2213 mCompositorBridge->LeaveTestMode(GetLayersId()); 2214 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 2215 sampler->LeaveTestMode(); 2216 } 2217 2218 return IPC_OK(); 2219 } 2220 2221 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetAnimationValue( 2222 const uint64_t& aCompositorAnimationsId, OMTAValue* aValue) { 2223 if (mDestroyed) { 2224 return IPC_FAIL_NO_REASON(this); 2225 } 2226 2227 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 2228 Maybe<TimeStamp> testingTimeStamp; 2229 if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) { 2230 testingTimeStamp = cbp->GetTestingTimeStamp(); 2231 } 2232 2233 sampler->SampleForTesting(testingTimeStamp); 2234 *aValue = sampler->GetOMTAValue(aCompositorAnimationsId); 2235 } 2236 2237 return IPC_OK(); 2238 } 2239 2240 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncScrollOffset( 2241 const ScrollableLayerGuid::ViewID& aScrollId, const float& aX, 2242 const float& aY) { 2243 if (mDestroyed) { 2244 return IPC_OK(); 2245 } 2246 mCompositorBridge->SetTestAsyncScrollOffset(GetLayersId(), aScrollId, 2247 CSSPoint(aX, aY)); 2248 return IPC_OK(); 2249 } 2250 2251 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncZoom( 2252 const ScrollableLayerGuid::ViewID& aScrollId, const float& aZoom) { 2253 if (mDestroyed) { 2254 return IPC_OK(); 2255 } 2256 mCompositorBridge->SetTestAsyncZoom(GetLayersId(), aScrollId, 2257 LayerToParentLayerScale(aZoom)); 2258 return IPC_OK(); 2259 } 2260 2261 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvFlushApzRepaints() { 2262 if (mDestroyed) { 2263 return IPC_OK(); 2264 } 2265 mCompositorBridge->FlushApzRepaints(GetLayersId()); 2266 return IPC_OK(); 2267 } 2268 2269 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetAPZTestData( 2270 APZTestData* aOutData) { 2271 if (mDestroyed) { 2272 return IPC_FAIL_NO_REASON(this); 2273 } 2274 2275 mCompositorBridge->GetAPZTestData(GetLayersId(), aOutData); 2276 return IPC_OK(); 2277 } 2278 2279 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetFrameUniformity( 2280 FrameUniformityData* aOutData) { 2281 if (mDestroyed) { 2282 return IPC_FAIL_NO_REASON(this); 2283 } 2284 2285 mCompositorBridge->GetFrameUniformity(GetLayersId(), aOutData); 2286 return IPC_OK(); 2287 } 2288 2289 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEndWheelTransaction( 2290 EndWheelTransactionResolver&& aResolve) { 2291 if (mDestroyed) { 2292 return IPC_OK(); 2293 } 2294 mCompositorBridge->EndWheelTransaction(GetLayersId(), std::move(aResolve)); 2295 return IPC_OK(); 2296 } 2297 2298 void WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { Destroy(); } 2299 2300 void WebRenderBridgeParent::ResetPreviousSampleTime() { 2301 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 2302 sampler->ResetPreviousSampleTime(); 2303 } 2304 } 2305 2306 RefPtr<OMTASampler> WebRenderBridgeParent::GetOMTASampler() const { 2307 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 2308 if (!cbp) { 2309 return nullptr; 2310 } 2311 return cbp->GetOMTASampler(); 2312 } 2313 2314 void WebRenderBridgeParent::SetOMTASampleTime() { 2315 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2316 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 2317 sampler->SetSampleTime(mCompositorScheduler->GetLastComposeTime().Time()); 2318 } 2319 } 2320 2321 void WebRenderBridgeParent::RetrySkippedComposite() { 2322 if (!mSkippedComposite) { 2323 return; 2324 } 2325 2326 mSkippedComposite = false; 2327 if (mCompositorScheduler) { 2328 mCompositorScheduler->ScheduleComposition(mSkippedCompositeReasons | 2329 RenderReasons::SKIPPED_COMPOSITE); 2330 } 2331 mSkippedCompositeReasons = wr::RenderReasons::NONE; 2332 } 2333 2334 void WebRenderBridgeParent::CompositeToTarget(VsyncId aId, 2335 wr::RenderReasons aReasons, 2336 gfx::DrawTarget* aTarget, 2337 const gfx::IntRect* aRect) { 2338 // This function should only get called in the root WRBP 2339 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2340 2341 // The two arguments are part of the CompositorVsyncSchedulerOwner API but in 2342 // this implementation they should never be non-null. 2343 MOZ_ASSERT(aTarget == nullptr); 2344 MOZ_ASSERT(aRect == nullptr); 2345 2346 LOG("WebRenderBridgeParent::CompositeToTarget() PipelineId %" PRIx64 2347 " Id %" PRIx64 " root %d", 2348 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2349 IsRootWebRenderBridgeParent()); 2350 2351 CompositorBridgeParent* cbp = GetRootCompositorBridgeParent(); 2352 uint64_t innerWindowId = cbp ? cbp->GetInnerWindowId() : 0; 2353 AUTO_PROFILER_MARKER_INNERWINDOWID("CompositeToTarget", GRAPHICS, 2354 innerWindowId); 2355 2356 bool paused = true; 2357 if (cbp) { 2358 paused = cbp->IsPaused(); 2359 } 2360 2361 if (paused || !mReceivedDisplayList) { 2362 ResetPreviousSampleTime(); 2363 mCompositionOpportunityId = mCompositionOpportunityId.Next(); 2364 PROFILER_MARKER_TEXT("Discarded composite", GRAPHICS, 2365 MarkerInnerWindowId(innerWindowId), 2366 paused ? "Paused"_ns : "No display list"_ns); 2367 return; 2368 } 2369 2370 mSkippedComposite = 2371 wr::RenderThread::Get()->TooManyPendingFrames(mApi->GetId()); 2372 2373 if (mSkippedComposite) { 2374 // Render thread is busy, try next time. 2375 mSkippedComposite = true; 2376 mSkippedCompositeReasons = mSkippedCompositeReasons | aReasons; 2377 ResetPreviousSampleTime(); 2378 2379 // Record that we skipped presenting a frame for 2380 // all pending transactions that have finished scene building. 2381 for (auto& id : mPendingTransactionIds) { 2382 if (id.mSceneBuiltTime) { 2383 id.mSkippedComposites++; 2384 } 2385 } 2386 2387 PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS, 2388 MarkerInnerWindowId(innerWindowId), 2389 "Too many pending frames"); 2390 2391 glean::gfx::skipped_composites.Add(1); 2392 2393 return; 2394 } 2395 2396 mCompositionOpportunityId = mCompositionOpportunityId.Next(); 2397 MaybeGenerateFrame(aId, /* aForceGenerateFrame */ false, aReasons); 2398 } 2399 2400 TimeDuration WebRenderBridgeParent::GetVsyncInterval() const { 2401 // This function should only get called in the root WRBP 2402 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2403 if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) { 2404 return cbp->GetVsyncInterval(); 2405 } 2406 return TimeDuration(); 2407 } 2408 2409 void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId, 2410 bool aForceGenerateFrame, 2411 wr::RenderReasons aReasons) { 2412 // This function should only get called in the root WRBP 2413 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2414 LOG("WebRenderBridgeParent::MaybeGenerateFrame() PipelineId %" PRIx64 2415 " Id %" PRIx64 " root %d", 2416 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2417 IsRootWebRenderBridgeParent()); 2418 2419 if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) { 2420 // Skip WR render during paused state. 2421 if (cbp->IsPaused()) { 2422 TimeStamp now = TimeStamp::Now(); 2423 PROFILER_MARKER_TEXT( 2424 "SkippedComposite", GRAPHICS, 2425 MarkerOptions(MarkerInnerWindowId(cbp->GetInnerWindowId()), 2426 MarkerTiming::InstantAt(now)), 2427 "CompositorBridgeParent is paused"); 2428 cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now, 2429 now); 2430 return; 2431 } 2432 } 2433 2434 TimeStamp start = TimeStamp::Now(); 2435 2436 // Ensure GenerateFrame is handled on the render backend thread rather 2437 // than going through the scene builder thread. That way we continue 2438 // generating frames with the old scene even during slow scene builds. 2439 wr::TransactionBuilder fastTxn(mApi, false /* useSceneBuilderThread */); 2440 // Handle transaction that is related to DisplayList. 2441 wr::TransactionBuilder sceneBuilderTxn(mApi); 2442 wr::AutoTransactionSender sender(mApi, &sceneBuilderTxn); 2443 2444 mAsyncImageManager->SetCompositionInfo(start, mCompositionOpportunityId); 2445 mAsyncImageManager->ApplyAsyncImagesOfImageBridge(sceneBuilderTxn, fastTxn); 2446 mAsyncImageManager->SetCompositionInfo(TimeStamp(), 2447 CompositionOpportunityId{}); 2448 2449 if (!mAsyncImageManager->GetCompositeUntilTime().IsNull()) { 2450 // Trigger another CompositeToTarget() call because there might be another 2451 // frame that we want to generate after this one. 2452 // It will check if we actually want to generate the frame or not. 2453 mCompositorScheduler->ScheduleComposition( 2454 wr::RenderReasons::ASYNC_IMAGE_COMPOSITE_UNTIL); 2455 } 2456 2457 bool generateFrame = !fastTxn.IsEmpty() || aForceGenerateFrame; 2458 2459 if (mAsyncImageManager->GetAndResetWillGenerateFrame()) { 2460 aReasons |= wr::RenderReasons::ASYNC_IMAGE; 2461 generateFrame = true; 2462 } 2463 2464 if (!generateFrame) { 2465 // Could skip generating frame now. 2466 PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS, 2467 MarkerTiming::InstantAt(start), 2468 "No reason to generate frame"); 2469 ResetPreviousSampleTime(); 2470 return; 2471 } 2472 2473 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 2474 if (sampler->HasAnimations()) { 2475 ScheduleGenerateFrame(wr::RenderReasons::ANIMATED_PROPERTY); 2476 } 2477 } 2478 2479 SetOMTASampleTime(); 2480 SetAPZSampleTime(); 2481 2482 #if defined(ENABLE_FRAME_LATENCY_LOG) 2483 auto startTime = TimeStamp::Now(); 2484 mApi->SetFrameStartTime(startTime); 2485 #endif 2486 2487 const bool present = true; 2488 const bool tracked = true; 2489 fastTxn.GenerateFrame(aId, present, tracked, aReasons); 2490 wr::RenderThread::Get()->IncPendingFrameCount(mApi->GetId(), aId, start); 2491 2492 NeedIncreasedMaxDirtyPageModifier(); 2493 2494 mApi->SendTransaction(fastTxn); 2495 2496 #if defined(MOZ_WIDGET_ANDROID) 2497 MaybeCaptureScreenPixels(); 2498 #endif 2499 2500 mMostRecentComposite = TimeStamp::Now(); 2501 2502 // During disabling native compositor, webrender needs to render twice. 2503 // Otherwise, browser flashes black. 2504 // XXX better fix? 2505 if (mDisablingNativeCompositor) { 2506 mDisablingNativeCompositor = false; 2507 2508 // Ensure we generate and render a frame immediately. 2509 ScheduleForcedGenerateFrame(aReasons); 2510 } 2511 } 2512 2513 void WebRenderBridgeParent::HoldPendingTransactionId( 2514 const wr::Epoch& aWrEpoch, TransactionId aTransactionId, 2515 bool aContainsSVGGroup, const VsyncId& aVsyncId, 2516 const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime, 2517 const TimeStamp& aTxnStartTime, const nsACString& aTxnURL, 2518 const TimeStamp& aFwdTime, const bool aIsFirstPaint, 2519 nsTArray<CompositionPayload>&& aPayloads, const bool aUseForTelemetry) { 2520 MOZ_ASSERT(aTransactionId > LastPendingTransactionId()); 2521 mPendingTransactionIds.push_back(PendingTransactionId( 2522 aWrEpoch, aTransactionId, aContainsSVGGroup, aVsyncId, aVsyncStartTime, 2523 aRefreshStartTime, aTxnStartTime, aTxnURL, aFwdTime, aIsFirstPaint, 2524 aUseForTelemetry, std::move(aPayloads))); 2525 } 2526 2527 TransactionId WebRenderBridgeParent::LastPendingTransactionId() { 2528 TransactionId id{0}; 2529 if (!mPendingTransactionIds.empty()) { 2530 id = mPendingTransactionIds.back().mId; 2531 } 2532 return id; 2533 } 2534 2535 void WebRenderBridgeParent::NotifySceneBuiltForEpoch( 2536 const wr::Epoch& aEpoch, const TimeStamp& aEndTime) { 2537 for (auto& id : mPendingTransactionIds) { 2538 if (id.mEpoch.mHandle == aEpoch.mHandle) { 2539 id.mSceneBuiltTime = aEndTime; 2540 break; 2541 } 2542 } 2543 } 2544 2545 void WebRenderBridgeParent::ScheduleFrameAfterSceneBuild( 2546 RefPtr<const wr::WebRenderPipelineInfo> aInfo) { 2547 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2548 if (!mCompositorScheduler) { 2549 return; 2550 } 2551 2552 mAsyncImageManager->SetWillGenerateFrame(); 2553 2554 // If the scheduler has a composite more recent than our last composite (which 2555 // we missed), and we're within the threshold ms of the last vsync, then 2556 // kick of a late composite. 2557 TimeStamp lastVsync = mCompositorScheduler->GetLastVsyncTime(); 2558 VsyncId lastVsyncId = mCompositorScheduler->GetLastVsyncId(); 2559 if (lastVsyncId == VsyncId() || !mMostRecentComposite || 2560 mMostRecentComposite >= lastVsync || 2561 ((TimeStamp::Now() - lastVsync).ToMilliseconds() > 2562 StaticPrefs::gfx_webrender_late_scenebuild_threshold())) { 2563 mCompositorScheduler->ScheduleComposition(wr::RenderReasons::SCENE); 2564 return; 2565 } 2566 2567 // Look through all the pipelines contained within the built scene 2568 // and check which vsync they initiated from. 2569 const auto& info = aInfo->Raw(); 2570 for (const auto& epoch : info.epochs) { 2571 WebRenderBridgeParent* wrBridge = this; 2572 if (!(epoch.pipeline_id == PipelineId())) { 2573 wrBridge = mAsyncImageManager->GetWrBridge(epoch.pipeline_id); 2574 } 2575 2576 if (wrBridge) { 2577 VsyncId startId = wrBridge->GetVsyncIdForEpoch(epoch.epoch); 2578 // If any of the pipelines started building on the current vsync (i.e 2579 // we did all of display list building and scene building within the 2580 // threshold), then don't do an early composite. 2581 if (startId == lastVsyncId) { 2582 mCompositorScheduler->ScheduleComposition(wr::RenderReasons::SCENE); 2583 return; 2584 } 2585 } 2586 } 2587 2588 CompositeToTarget(mCompositorScheduler->GetLastVsyncId(), 2589 wr::RenderReasons::SCENE, nullptr, nullptr); 2590 } 2591 2592 static void RecordPaintPhaseTelemetry(wr::RendererStats* aStats) { 2593 if (!aStats || !aStats->full_paint) { 2594 return; 2595 } 2596 2597 const double geckoDL = aStats->gecko_display_list_time; 2598 const double wrDL = aStats->wr_display_list_time; 2599 const double sceneBuild = aStats->scene_build_time; 2600 const double frameBuild = aStats->frame_build_time; 2601 const double totalMs = geckoDL + wrDL + sceneBuild + frameBuild; 2602 2603 // If the total time was >= 16ms, then it's likely we missed a frame due to 2604 // painting. We bucket these metrics separately. 2605 const bool isLargePaint = totalMs >= 16.0; 2606 2607 // Split the results based on display list build type, partial or full. 2608 const bool isFullDisplayList = aStats->full_display_list; 2609 2610 auto AsPercentage = [&](const double aTimeMs) -> double { 2611 MOZ_ASSERT(aTimeMs <= totalMs); 2612 return (aTimeMs / totalMs) * 100.0; 2613 }; 2614 2615 auto RecordKey = [&](const nsCString& aKey, const double aTimeMs) -> void { 2616 const auto val = static_cast<uint32_t>(AsPercentage(aTimeMs)); 2617 if (isFullDisplayList) { 2618 if (isLargePaint) { 2619 glean::gfx_content::large_paint_phase_weight_full.Get(aKey) 2620 .AccumulateSingleSample(val); 2621 } else { 2622 glean::gfx_content::small_paint_phase_weight_full.Get(aKey) 2623 .AccumulateSingleSample(val); 2624 } 2625 } else { 2626 if (isLargePaint) { 2627 glean::gfx_content::large_paint_phase_weight_partial.Get(aKey) 2628 .AccumulateSingleSample(val); 2629 } else { 2630 glean::gfx_content::small_paint_phase_weight_partial.Get(aKey) 2631 .AccumulateSingleSample(val); 2632 } 2633 } 2634 }; 2635 2636 RecordKey("dl"_ns, geckoDL); 2637 RecordKey("wrdl"_ns, wrDL); 2638 RecordKey("sb"_ns, sceneBuild); 2639 RecordKey("fb"_ns, frameBuild); 2640 } 2641 2642 void WebRenderBridgeParent::FlushTransactionIdsForEpoch( 2643 const wr::Epoch& aEpoch, const VsyncId& aCompositeStartId, 2644 const TimeStamp& aCompositeStartTime, const TimeStamp& aRenderStartTime, 2645 const TimeStamp& aEndTime, UiCompositorControllerParent* aUiController, 2646 wr::RendererStats* aStats, nsTArray<FrameStats>& aOutputStats, 2647 nsTArray<TransactionId>& aOutputTransactions) { 2648 while (!mPendingTransactionIds.empty()) { 2649 const auto& transactionId = mPendingTransactionIds.front(); 2650 2651 if (aEpoch.mHandle < transactionId.mEpoch.mHandle) { 2652 break; 2653 } 2654 2655 if (!IsRootWebRenderBridgeParent() && !mVsyncRate.IsZero() && 2656 transactionId.mUseForTelemetry) { 2657 auto fullPaintTime = 2658 transactionId.mSceneBuiltTime 2659 ? transactionId.mSceneBuiltTime - transactionId.mTxnStartTime 2660 : TimeDuration::FromMilliseconds(0); 2661 2662 int32_t contentFrameTime = RecordContentFrameTime( 2663 transactionId.mVsyncId, transactionId.mVsyncStartTime, 2664 transactionId.mTxnStartTime, aCompositeStartId, aEndTime, 2665 fullPaintTime, mVsyncRate, transactionId.mContainsSVGGroup, true, 2666 aStats); 2667 2668 RecordPaintPhaseTelemetry(aStats); 2669 2670 if (StaticPrefs::gfx_logging_slow_frames_enabled_AtStartup() && 2671 contentFrameTime > 200) { 2672 aOutputStats.AppendElement(FrameStats( 2673 transactionId.mId, aCompositeStartTime, aRenderStartTime, aEndTime, 2674 contentFrameTime, 2675 aStats ? (double(aStats->resource_upload_time) / 1000000.0) : 0.0, 2676 transactionId.mTxnStartTime, transactionId.mRefreshStartTime, 2677 transactionId.mFwdTime, transactionId.mSceneBuiltTime, 2678 transactionId.mSkippedComposites, transactionId.mTxnURL)); 2679 } 2680 } 2681 2682 #if defined(ENABLE_FRAME_LATENCY_LOG) 2683 if (transactionId.mRefreshStartTime) { 2684 int32_t latencyMs = 2685 lround((aEndTime - transactionId.mRefreshStartTime).ToMilliseconds()); 2686 printf_stderr( 2687 "From transaction start to end of generate frame latencyMs %d this " 2688 "%p\n", 2689 latencyMs, this); 2690 } 2691 if (transactionId.mFwdTime) { 2692 int32_t latencyMs = 2693 lround((aEndTime - transactionId.mFwdTime).ToMilliseconds()); 2694 printf_stderr( 2695 "From forwarding transaction to end of generate frame latencyMs %d " 2696 "this %p\n", 2697 latencyMs, this); 2698 } 2699 #endif 2700 2701 if (aUiController && transactionId.mIsFirstPaint) { 2702 aUiController->NotifyFirstPaint(); 2703 } 2704 2705 RecordCompositionPayloadsPresented(aEndTime, transactionId.mPayloads); 2706 2707 aOutputTransactions.AppendElement(transactionId.mId); 2708 mPendingTransactionIds.pop_front(); 2709 } 2710 } 2711 2712 LayersId WebRenderBridgeParent::GetLayersId() const { 2713 return wr::AsLayersId(mPipelineId); 2714 } 2715 2716 void WebRenderBridgeParent::ScheduleGenerateFrame(wr::RenderReasons aReasons) { 2717 if (mCompositorScheduler) { 2718 mAsyncImageManager->SetWillGenerateFrame(); 2719 mCompositorScheduler->ScheduleComposition(aReasons); 2720 } 2721 } 2722 2723 void WebRenderBridgeParent::FlushRendering(wr::RenderReasons aReasons, 2724 bool aBlocking) { 2725 if (mDestroyed) { 2726 return; 2727 } 2728 2729 if (aBlocking) { 2730 FlushSceneBuilds(); 2731 FlushFrameGeneration(aReasons); 2732 FlushFramePresentation(); 2733 } else { 2734 ScheduleGenerateFrame(aReasons); 2735 } 2736 } 2737 2738 ipc::IPCResult WebRenderBridgeParent::RecvSetDefaultClearColor( 2739 const uint32_t& aColor) { 2740 SetClearColor(gfx::DeviceColor::FromABGR(aColor)); 2741 return IPC_OK(); 2742 } 2743 2744 void WebRenderBridgeParent::SetClearColor(const gfx::DeviceColor& aColor) { 2745 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2746 2747 if (!IsRootWebRenderBridgeParent() || mDestroyed) { 2748 return; 2749 } 2750 2751 mApi->SetClearColor(aColor); 2752 } 2753 2754 void WebRenderBridgeParent::Pause() { 2755 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2756 LOG("WebRenderBridgeParent::Pause() PipelineId %" PRIx64 " Id %" PRIx64 2757 " root %d", 2758 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2759 IsRootWebRenderBridgeParent()); 2760 2761 if (!IsRootWebRenderBridgeParent() || mDestroyed) { 2762 return; 2763 } 2764 2765 mApi->Pause(); 2766 } 2767 2768 bool WebRenderBridgeParent::Resume() { 2769 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2770 LOG("WebRenderBridgeParent::Resume() PipelineId %" PRIx64 " Id %" PRIx64 2771 " root %d", 2772 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2773 IsRootWebRenderBridgeParent()); 2774 2775 if (!IsRootWebRenderBridgeParent() || mDestroyed) { 2776 return false; 2777 } 2778 2779 if (!mApi->Resume()) { 2780 return false; 2781 } 2782 2783 // Ensure we generate and render a frame immediately. 2784 ScheduleForcedGenerateFrame(wr::RenderReasons::WIDGET); 2785 return true; 2786 } 2787 2788 void WebRenderBridgeParent::ClearResources() { 2789 if (!mApi) { 2790 return; 2791 } 2792 2793 if (!IsRootWebRenderBridgeParent()) { 2794 mApi->FlushPendingWrTransactionEventsWithoutWait(); 2795 } 2796 2797 LOG("WebRenderBridgeParent::ClearResources() PipelineId %" PRIx64 2798 " Id %" PRIx64 " root %d", 2799 wr::AsUint64(mPipelineId), wr::AsUint64(mApi->GetId()), 2800 IsRootWebRenderBridgeParent()); 2801 2802 wr::Epoch wrEpoch = GetNextWrEpoch(); 2803 mReceivedDisplayList = false; 2804 // Schedule generate frame to clean up Pipeline 2805 ScheduleGenerateFrame(wr::RenderReasons::CLEAR_RESOURCES); 2806 2807 // WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction. 2808 for (const auto& entry : mTextureHosts) { 2809 WebRenderTextureHost* wrTexture = entry.second->AsWebRenderTextureHost(); 2810 MOZ_ASSERT(wrTexture); 2811 if (wrTexture) { 2812 mAsyncImageManager->HoldExternalImage(mPipelineId, wrEpoch, wrTexture); 2813 } 2814 } 2815 mTextureHosts.clear(); 2816 2817 for (const auto& entry : mSharedSurfaceIds) { 2818 mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, entry.second); 2819 } 2820 mSharedSurfaceIds.clear(); 2821 2822 mAsyncImageManager->RemovePipeline(mPipelineId, wrEpoch); 2823 2824 wr::TransactionBuilder txn(mApi); 2825 txn.SetLowPriority(true); 2826 txn.ClearDisplayList(wrEpoch, mPipelineId); 2827 2828 for (const auto& entry : mAsyncCompositables) { 2829 wr::PipelineId pipelineId = wr::AsPipelineId(entry.first); 2830 RefPtr<WebRenderImageHost> host = entry.second; 2831 host->ClearWrBridge(pipelineId, this); 2832 mAsyncImageManager->RemoveAsyncImagePipeline( 2833 pipelineId, /* aPendingOps */ nullptr, txn); 2834 txn.RemovePipeline(pipelineId); 2835 } 2836 mAsyncCompositables.clear(); 2837 txn.RemovePipeline(mPipelineId); 2838 mApi->SendTransaction(txn); 2839 2840 ClearAnimationResources(); 2841 2842 if (IsRootWebRenderBridgeParent()) { 2843 mCompositorScheduler->Destroy(); 2844 mApi->DestroyRenderer(); 2845 } 2846 2847 mCompositorScheduler = nullptr; 2848 mAsyncImageManager = nullptr; 2849 mApi = nullptr; 2850 mCompositorBridge = nullptr; 2851 } 2852 2853 void WebRenderBridgeParent::ClearAnimationResources() { 2854 if (RefPtr<OMTASampler> sampler = GetOMTASampler()) { 2855 sampler->ClearActiveAnimations(mActiveAnimations); 2856 } 2857 mActiveAnimations.clear(); 2858 std::queue<CompositorAnimationIdsForEpoch>().swap( 2859 mCompositorAnimationsToDelete); // clear queue 2860 } 2861 2862 void WebRenderBridgeParent::SendAsyncMessage( 2863 const nsTArray<AsyncParentMessageData>& aMessage) { 2864 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 2865 } 2866 2867 void WebRenderBridgeParent::SendPendingAsyncMessages() { 2868 MOZ_ASSERT(mCompositorBridge); 2869 mCompositorBridge->SendPendingAsyncMessages(); 2870 } 2871 2872 void WebRenderBridgeParent::SetAboutToSendAsyncMessages() { 2873 MOZ_ASSERT(mCompositorBridge); 2874 mCompositorBridge->SetAboutToSendAsyncMessages(); 2875 } 2876 2877 void WebRenderBridgeParent::NotifyNotUsed(PTextureParent* aTexture, 2878 uint64_t aTransactionId) { 2879 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 2880 } 2881 2882 base::ProcessId WebRenderBridgeParent::GetChildProcessId() { 2883 return OtherPid(); 2884 } 2885 2886 dom::ContentParentId WebRenderBridgeParent::GetContentId() { 2887 MOZ_ASSERT(mCompositorBridge); 2888 return mCompositorBridge->GetContentId(); 2889 } 2890 2891 bool WebRenderBridgeParent::IsSameProcess() const { 2892 return OtherPid() == base::GetCurrentProcId(); 2893 } 2894 2895 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvNewCompositable( 2896 const CompositableHandle& aHandle, const TextureInfo& aInfo) { 2897 if (mDestroyed) { 2898 return IPC_OK(); 2899 } 2900 if (!AddCompositable(aHandle, aInfo)) { 2901 return IPC_FAIL_NO_REASON(this); 2902 } 2903 return IPC_OK(); 2904 } 2905 2906 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvReleaseCompositable( 2907 const CompositableHandle& aHandle) { 2908 if (mDestroyed) { 2909 return IPC_OK(); 2910 } 2911 ReleaseCompositable(aHandle); 2912 return IPC_OK(); 2913 } 2914 2915 TextureFactoryIdentifier WebRenderBridgeParent::GetTextureFactoryIdentifier() { 2916 MOZ_ASSERT(mApi); 2917 2918 #ifdef XP_WIN 2919 const bool supportsD3D11NV12 = gfx::DeviceManagerDx::Get()->CanUseNV12(); 2920 #else 2921 const bool supportsD3D11NV12 = false; 2922 #endif 2923 2924 TextureFactoryIdentifier ident( 2925 mApi->GetBackendType(), mApi->GetCompositorType(), XRE_GetProcessType(), 2926 mApi->GetMaxTextureSize(), mApi->GetUseANGLE(), mApi->GetUseDComp(), 2927 mApi->GetUseLayerCompositor(), mAsyncImageManager->UseCompositorWnd(), 2928 false, false, false, supportsD3D11NV12, mApi->GetSyncHandle()); 2929 return ident; 2930 } 2931 2932 wr::Epoch WebRenderBridgeParent::GetNextWrEpoch() { 2933 MOZ_RELEASE_ASSERT(mWrEpoch.mHandle != UINT32_MAX); 2934 mWrEpoch.mHandle++; 2935 return mWrEpoch; 2936 } 2937 2938 void WebRenderBridgeParent::RollbackWrEpoch() { 2939 MOZ_RELEASE_ASSERT(mWrEpoch.mHandle != 0); 2940 mWrEpoch.mHandle--; 2941 } 2942 2943 void WebRenderBridgeParent::ExtractImageCompositeNotifications( 2944 nsTArray<ImageCompositeNotificationInfo>* aNotifications) { 2945 MOZ_ASSERT(IsRootWebRenderBridgeParent()); 2946 if (mDestroyed) { 2947 return; 2948 } 2949 mAsyncImageManager->FlushImageNotifications(aNotifications); 2950 } 2951 2952 void WebRenderBridgeParent::FlushPendingWrTransactionEventsWithWait() { 2953 if (mDestroyed || IsRootWebRenderBridgeParent()) { 2954 return; 2955 } 2956 mApi->FlushPendingWrTransactionEventsWithWait(); 2957 } 2958 2959 RefPtr<WebRenderBridgeParentRef> 2960 WebRenderBridgeParent::GetWebRenderBridgeParentRef() { 2961 if (mDestroyed) { 2962 return nullptr; 2963 } 2964 2965 if (!mWebRenderBridgeRef) { 2966 mWebRenderBridgeRef = new WebRenderBridgeParentRef(this); 2967 } 2968 return mWebRenderBridgeRef; 2969 } 2970 2971 WebRenderBridgeParentRef::WebRenderBridgeParentRef( 2972 WebRenderBridgeParent* aWebRenderBridge) 2973 : mWebRenderBridge(aWebRenderBridge) { 2974 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 2975 MOZ_ASSERT(mWebRenderBridge); 2976 } 2977 2978 RefPtr<WebRenderBridgeParent> WebRenderBridgeParentRef::WrBridge() { 2979 return mWebRenderBridge; 2980 } 2981 2982 void WebRenderBridgeParentRef::Clear() { 2983 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 2984 mWebRenderBridge = nullptr; 2985 } 2986 2987 WebRenderBridgeParentRef::~WebRenderBridgeParentRef() { 2988 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 2989 MOZ_ASSERT(!mWebRenderBridge); 2990 } 2991 2992 } // namespace mozilla::layers