RenderThread.cpp (56033B)
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 "base/task.h" 8 #include "GeckoProfiler.h" 9 #include "gfxPlatform.h" 10 #include "GLContext.h" 11 #include "RenderThread.h" 12 #include "nsThread.h" 13 #include "nsThreadUtils.h" 14 #include "transport/runnable_utils.h" 15 #include "mozilla/BackgroundHangMonitor.h" 16 #include "mozilla/layers/AsyncImagePipelineManager.h" 17 #include "mozilla/gfx/gfxVars.h" 18 #include "mozilla/gfx/GPUParent.h" 19 #include "mozilla/gfx/GPUProcessManager.h" 20 #include "mozilla/glean/GfxMetrics.h" 21 #include "mozilla/layers/CompositorThread.h" 22 #include "mozilla/layers/CompositorBridgeParent.h" 23 #include "mozilla/layers/CompositorManagerParent.h" 24 #include "mozilla/layers/Fence.h" 25 #include "mozilla/layers/WebRenderBridgeParent.h" 26 #include "mozilla/layers/SharedSurfacesParent.h" 27 #include "mozilla/layers/SurfacePool.h" 28 #include "mozilla/layers/SynchronousTask.h" 29 #include "mozilla/PerfStats.h" 30 #include "mozilla/StaticPtr.h" 31 #include "mozilla/webrender/RendererOGL.h" 32 #include "mozilla/webrender/RenderTextureHost.h" 33 #include "mozilla/widget/CompositorWidget.h" 34 #include "OGLShaderProgram.h" 35 36 #ifdef XP_WIN 37 # include "GLContextEGL.h" 38 # include "GLLibraryEGL.h" 39 # include "mozilla/widget/WinCompositorWindowThread.h" 40 # include "mozilla/gfx/DeviceManagerDx.h" 41 # include "mozilla/webrender/DCLayerTree.h" 42 // # include "nsWindowsHelpers.h" 43 // # include <d3d11.h> 44 #endif 45 46 #ifdef MOZ_WIDGET_ANDROID 47 # include "GLLibraryEGL.h" 48 # include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h" 49 #endif 50 51 #ifdef MOZ_WIDGET_GTK 52 # include "mozilla/WidgetUtilsGtk.h" 53 # include "GLLibraryEGL.h" 54 #endif 55 56 using namespace mozilla; 57 58 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError); 59 60 MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderRendererMallocSizeOf) 61 62 namespace mozilla::wr { 63 64 LazyLogModule gRenderThreadLog("RenderThread"); 65 // Should be called only on RenderThread, since LazyLogModule is not thread safe 66 #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__)) 67 68 static StaticRefPtr<RenderThread> sRenderThread; 69 static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor; 70 #ifdef DEBUG 71 static bool sRenderThreadEverStarted = false; 72 #endif 73 size_t RenderThread::sRendererCount = 0; 74 size_t RenderThread::sActiveRendererCount = 0; 75 76 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK) 77 static bool USE_DEDICATED_GLYPH_RASTER_THREAD = true; 78 #else 79 static bool USE_DEDICATED_GLYPH_RASTER_THREAD = false; 80 #endif 81 82 RenderThread::RenderThread(RefPtr<nsIThread> aThread) 83 : mThread(std::move(aThread)), 84 mThreadPool(false), 85 mThreadPoolLP(true), 86 mChunkPool(wr_chunk_pool_new()), 87 mGlyphRasterThread(USE_DEDICATED_GLYPH_RASTER_THREAD), 88 mSingletonGLIsForHardwareWebRender(true), 89 mBatteryInfo("RenderThread.mBatteryInfo"), 90 mWindowInfos("RenderThread.mWindowInfos"), 91 mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"), 92 mHasShutdown(false), 93 mHandlingDeviceReset(false), 94 mHandlingWebRenderError(false) {} 95 96 RenderThread::~RenderThread() { 97 MOZ_ASSERT(mRenderTexturesDeferred.empty()); 98 wr_chunk_pool_delete(mChunkPool); 99 } 100 101 // static 102 RenderThread* RenderThread::Get() { return sRenderThread; } 103 104 // static 105 void RenderThread::Start(uint32_t aNamespace) { 106 MOZ_ASSERT(NS_IsMainThread()); 107 MOZ_ASSERT(!sRenderThread); 108 109 #ifdef DEBUG 110 // Check to ensure nobody will try to ever start us more than once during 111 // the process' lifetime (in particular after ShutDown). 112 MOZ_ASSERT(!sRenderThreadEverStarted); 113 sRenderThreadEverStarted = true; 114 #endif 115 116 // When the CanvasRenderer thread is disabled, WebGL may be handled on this 117 // thread, requiring a bigger stack size. See: CanvasManagerParent::Init 118 // 119 // This is 4M, which is higher than the default 256K. 120 // Increased with bug 1753349 to accommodate the `chromium/5359` branch of 121 // ANGLE, which has large peak stack usage for some pathological shader 122 // compilations. 123 // 124 // Previously increased to 512K to accommodate Mesa in bug 1753340. 125 // 126 // Previously increased to 320K to avoid a stack overflow in the 127 // Intel Vulkan driver initialization in bug 1716120. 128 // 129 // Note: we only override it if it's limited already. 130 uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE; 131 if (stackSize && !gfx::gfxVars::SupportsThreadsafeGL()) { 132 stackSize = std::max(stackSize, 4096U << 10); 133 } 134 #if !defined(__OPTIMIZE__) 135 // swgl's draw_quad_spans will allocate ~1.5MB in no-opt builds 136 // and the default thread stack size on macOS is 512KB 137 stackSize = std::max(stackSize, 4 * 1024 * 1024U); 138 #endif 139 140 RefPtr<nsIThread> thread; 141 nsresult rv = NS_NewNamedThread( 142 "Renderer", getter_AddRefs(thread), 143 NS_NewRunnableFunction( 144 "Renderer::BackgroundHanSetup", 145 []() { 146 sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor( 147 "Render", 148 /* Timeout values are powers-of-two to enable us get better 149 data. 128ms is chosen for transient hangs because 8Hz should 150 be the minimally acceptable goal for Render 151 responsiveness (normal goal is 60Hz). */ 152 128, 153 /* 2048ms is chosen for permanent hangs because it's longer than 154 * most Render hangs seen in the wild, but is short enough 155 * to not miss getting native hang stacks. */ 156 2048); 157 nsCOMPtr<nsIThread> thread = NS_GetCurrentThread(); 158 nsThread* nsthread = static_cast<nsThread*>(thread.get()); 159 nsthread->SetUseHangMonitor(true); 160 nsthread->SetPriority(nsISupportsPriority::PRIORITY_HIGH); 161 }), 162 {.stackSize = stackSize}); 163 164 if (NS_FAILED(rv)) { 165 gfxCriticalNote << "Failed to create Renderer thread: " 166 << gfx::hexa((uint32_t)rv); 167 return; 168 } 169 170 sRenderThread = new RenderThread(thread); 171 CrashReporter::RegisterAnnotationUSize( 172 CrashReporter::Annotation::GraphicsNumRenderers, &sRendererCount); 173 CrashReporter::RegisterAnnotationUSize( 174 CrashReporter::Annotation::GraphicsNumActiveRenderers, 175 &sActiveRendererCount); 176 #ifdef XP_WIN 177 widget::WinCompositorWindowThread::Start(); 178 #endif 179 layers::SharedSurfacesParent::Initialize(); 180 181 RefPtr<Runnable> runnable = WrapRunnable( 182 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::InitDeviceTask); 183 sRenderThread->PostRunnable(runnable.forget()); 184 } 185 186 // static 187 void RenderThread::ShutDown() { 188 MOZ_ASSERT(NS_IsMainThread()); 189 MOZ_ASSERT(sRenderThread); 190 191 { 192 MutexAutoLock lock(sRenderThread->mRenderTextureMapLock); 193 sRenderThread->mHasShutdown = true; 194 } 195 196 RefPtr<Runnable> runnable = WrapRunnable( 197 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::ShutDownTask); 198 sRenderThread->PostRunnable(runnable.forget()); 199 200 // This will empty the thread queue and thus run the above runnable while 201 // spinning the MT event loop. 202 nsCOMPtr<nsIThread> oldThread = sRenderThread->GetRenderThread(); 203 oldThread->Shutdown(); 204 205 layers::SharedSurfacesParent::Shutdown(); 206 207 #ifdef XP_WIN 208 if (widget::WinCompositorWindowThread::Get()) { 209 widget::WinCompositorWindowThread::ShutDown(); 210 } 211 #endif 212 213 // We null this out only after we finished shutdown to give everbody the 214 // chance to check for sRenderThread->mHasShutdown. Hopefully everybody 215 // checks this before using us! 216 sRenderThread = nullptr; 217 } 218 219 extern void ClearAllBlobImageResources(); 220 221 void RenderThread::ShutDownTask() { 222 MOZ_ASSERT(IsInRenderThread()); 223 LOG("RenderThread::ShutDownTask()"); 224 225 { 226 // Clear RenderTextureHosts 227 MutexAutoLock lock(mRenderTextureMapLock); 228 mRenderTexturesDeferred.clear(); 229 mRenderTextures.clear(); 230 mSyncObjectNeededRenderTextures.clear(); 231 mRenderTextureOps.clear(); 232 } 233 234 // Let go of our handle to the (internally ref-counted) thread pool. 235 mThreadPool.Release(); 236 mThreadPoolLP.Release(); 237 238 // Releasing on the render thread will allow us to avoid dispatching to remove 239 // remaining textures from the texture map. 240 layers::SharedSurfacesParent::ShutdownRenderThread(); 241 242 #ifdef XP_WIN 243 DCLayerTree::Shutdown(); 244 #endif 245 246 ClearAllBlobImageResources(); 247 ClearSingletonGL(); 248 ClearSharedSurfacePool(); 249 } 250 251 // static 252 bool RenderThread::IsInRenderThread() { 253 return sRenderThread && sRenderThread->mThread == NS_GetCurrentThread(); 254 } 255 256 // static 257 already_AddRefed<nsIThread> RenderThread::GetRenderThread() { 258 nsCOMPtr<nsIThread> thread; 259 if (sRenderThread) { 260 thread = sRenderThread->mThread; 261 } 262 return thread.forget(); 263 } 264 265 void RenderThread::DoAccumulateMemoryReport( 266 MemoryReport aReport, 267 const RefPtr<MemoryReportPromise::Private>& aPromise) { 268 MOZ_ASSERT(IsInRenderThread()); 269 270 for (auto& r : mRenderers) { 271 r.second->AccumulateMemoryReport(&aReport); 272 } 273 274 // Note memory used by the shader cache, which is shared across all WR 275 // instances. 276 MOZ_ASSERT(aReport.shader_cache == 0); 277 if (mProgramCache) { 278 aReport.shader_cache = wr_program_cache_report_memory( 279 mProgramCache->Raw(), &WebRenderRendererMallocSizeOf); 280 } 281 282 size_t renderTextureMemory = 0; 283 { 284 MutexAutoLock lock(mRenderTextureMapLock); 285 for (const auto& entry : mRenderTextures) { 286 renderTextureMemory += entry.second->Bytes(); 287 } 288 } 289 aReport.render_texture_hosts = renderTextureMemory; 290 291 aPromise->Resolve(aReport, __func__); 292 } 293 294 // static 295 RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport( 296 MemoryReport aInitial) { 297 RefPtr<MemoryReportPromise::Private> p = 298 new MemoryReportPromise::Private(__func__); 299 MOZ_ASSERT(!IsInRenderThread()); 300 if (!Get()) { 301 // This happens when the GPU process fails to start and we fall back to the 302 // basic compositor in the parent process. We could assert against this if 303 // we made the webrender detection code in gfxPlatform.cpp smarter. See bug 304 // 1494430 comment 12. 305 NS_WARNING("No render thread, returning empty memory report"); 306 p->Resolve(aInitial, __func__); 307 return p; 308 } 309 310 Get()->PostRunnable( 311 NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>( 312 "wr::RenderThread::DoAccumulateMemoryReport", Get(), 313 &RenderThread::DoAccumulateMemoryReport, aInitial, p)); 314 315 return p; 316 } 317 318 void RenderThread::SetBatteryInfo(const hal::BatteryInformation& aBatteryInfo) { 319 MOZ_ASSERT(XRE_IsGPUProcess()); 320 321 auto batteryInfo = mBatteryInfo.Lock(); 322 batteryInfo.ref() = Some(aBatteryInfo); 323 } 324 325 bool RenderThread::GetPowerIsCharging() { 326 MOZ_ASSERT(XRE_IsGPUProcess()); 327 328 auto batteryInfo = mBatteryInfo.Lock(); 329 if (batteryInfo.ref().isSome()) { 330 return batteryInfo.ref().ref().charging(); 331 } 332 333 gfxCriticalNoteOnce << "BatteryInfo is not set"; 334 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 335 return false; 336 } 337 338 void RenderThread::AddRenderer(wr::WindowId aWindowId, 339 UniquePtr<RendererOGL> aRenderer) { 340 MOZ_ASSERT(IsInRenderThread()); 341 LOG("RenderThread::AddRenderer() aWindowId %" PRIx64 "", AsUint64(aWindowId)); 342 343 if (mHasShutdown) { 344 return; 345 } 346 347 mRenderers[aWindowId] = std::move(aRenderer); 348 sRendererCount = mRenderers.size(); 349 350 auto windows = mWindowInfos.Lock(); 351 windows->emplace(AsUint64(aWindowId), new WindowInfo()); 352 mWrNotifierEventsQueues.emplace(AsUint64(aWindowId), 353 new std::queue<WrNotifierEvent>); 354 } 355 356 void RenderThread::RemoveRenderer(wr::WindowId aWindowId) { 357 MOZ_ASSERT(IsInRenderThread()); 358 LOG("RenderThread::RemoveRenderer() aWindowId %" PRIx64 "", 359 AsUint64(aWindowId)); 360 361 if (mHasShutdown) { 362 return; 363 } 364 365 mRenderers.erase(aWindowId); 366 sRendererCount = mRenderers.size(); 367 368 if (mRenderers.empty()) { 369 if (mHandlingDeviceReset) { 370 ClearSingletonGL(); 371 } 372 mHandlingDeviceReset = false; 373 mHandlingWebRenderError = false; 374 } 375 376 auto windows = mWindowInfos.Lock(); 377 auto it = windows->find(AsUint64(aWindowId)); 378 MOZ_ASSERT(it != windows->end()); 379 windows->erase(it); 380 381 // Defer std::deque<WrNotifierEvent> remove, RemoveRenderer() is called in 382 // HandleWrNotifierEvents(). 383 RefPtr<Runnable> runnable = 384 NS_NewRunnableFunction("RenderThread::RemoveRenderer", [aWindowId]() { 385 auto* self = RenderThread::Get(); 386 auto it = self->mWrNotifierEventsQueues.find(AsUint64(aWindowId)); 387 if (it == self->mWrNotifierEventsQueues.end()) { 388 return; 389 } 390 self->mWrNotifierEventsQueues.erase(it); 391 }); 392 RenderThread::Get()->PostRunnable(runnable.forget()); 393 } 394 395 RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) { 396 MOZ_ASSERT(IsInRenderThread()); 397 398 auto it = mRenderers.find(aWindowId); 399 MOZ_ASSERT(it != mRenderers.end()); 400 401 if (it == mRenderers.end()) { 402 return nullptr; 403 } 404 405 return it->second.get(); 406 } 407 408 size_t RenderThread::RendererCount() const { 409 MOZ_ASSERT(IsInRenderThread()); 410 return mRenderers.size(); 411 } 412 413 void RenderThread::UpdateActiveRendererCount() { 414 MOZ_ASSERT(IsInRenderThread()); 415 size_t num_active = 0; 416 for (const auto& it : mRenderers) { 417 if (!it.second->IsPaused()) { 418 num_active++; 419 } 420 } 421 sActiveRendererCount = num_active; 422 } 423 424 void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId, 425 bool aCompositeNeeded) { 426 auto windows = mWindowInfos.Lock(); 427 auto it = windows->find(AsUint64(aWindowId)); 428 if (it == windows->end()) { 429 MOZ_ASSERT(false); 430 return; 431 } 432 433 WindowInfo* info = it->second.get(); 434 435 info->mPendingWrNotifierEvents.emplace( 436 WrNotifierEvent::WakeUp(aCompositeNeeded)); 437 PostWrNotifierEvents(aWindowId, info); 438 } 439 440 void RenderThread::WrNotifierEvent_NewFrameReady( 441 WrWindowId aWindowId, wr::FramePublishId aPublishId, 442 const wr::FrameReadyParams* aParams) { 443 auto windows = mWindowInfos.Lock(); 444 auto it = windows->find(AsUint64(aWindowId)); 445 if (it == windows->end()) { 446 MOZ_ASSERT(false); 447 return; 448 } 449 WindowInfo* info = it->second.get(); 450 451 info->mPendingWrNotifierEvents.emplace( 452 WrNotifierEvent::NewFrameReady(aPublishId, aParams)); 453 PostWrNotifierEvents(aWindowId, info); 454 } 455 456 void RenderThread::WrNotifierEvent_ExternalEvent(WrWindowId aWindowId, 457 size_t aRawEvent) { 458 UniquePtr<RendererEvent> evt(reinterpret_cast<RendererEvent*>(aRawEvent)); 459 { 460 auto windows = mWindowInfos.Lock(); 461 auto it = windows->find(AsUint64(aWindowId)); 462 if (it == windows->end()) { 463 MOZ_ASSERT(false); 464 return; 465 } 466 WindowInfo* info = it->second.get(); 467 468 info->mPendingWrNotifierEvents.emplace( 469 WrNotifierEvent::ExternalEvent(std::move(evt))); 470 PostWrNotifierEvents(aWindowId, info); 471 } 472 } 473 474 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId) { 475 { 476 auto windows = mWindowInfos.Lock(); 477 auto it = windows->find(AsUint64(aWindowId)); 478 if (it == windows->end()) { 479 MOZ_ASSERT(false); 480 return; 481 } 482 WindowInfo* info = it->second.get(); 483 PostWrNotifierEvents(aWindowId, info); 484 } 485 } 486 487 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId, 488 WindowInfo* aInfo) { 489 // Runnable has already been triggered. 490 if (aInfo->mWrNotifierEventsRunnable) { 491 return; 492 } 493 494 // Runnable has not been triggered yet. 495 RefPtr<nsIRunnable> runnable = NewRunnableMethod<WrWindowId>( 496 "RenderThread::HandleWrNotifierEvents", this, 497 &RenderThread::HandleWrNotifierEvents, aWindowId); 498 aInfo->mWrNotifierEventsRunnable = runnable; 499 PostRunnable(runnable.forget()); 500 } 501 502 void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId) { 503 MOZ_ASSERT(IsInRenderThread()); 504 505 auto eventsIt = mWrNotifierEventsQueues.find(AsUint64(aWindowId)); 506 if (eventsIt == mWrNotifierEventsQueues.end()) { 507 return; 508 } 509 auto* events = eventsIt->second.get(); 510 511 { 512 auto windows = mWindowInfos.Lock(); 513 auto infoIt = windows->find(AsUint64(aWindowId)); 514 if (infoIt == windows->end()) { 515 MOZ_ASSERT(false); 516 return; 517 } 518 WindowInfo* info = infoIt->second.get(); 519 info->mWrNotifierEventsRunnable = nullptr; 520 521 if (events->empty() && !info->mPendingWrNotifierEvents.empty()) { 522 events->swap(info->mPendingWrNotifierEvents); 523 } 524 } 525 526 bool handleNext = true; 527 528 while (!events->empty() && handleNext) { 529 auto& front = events->front(); 530 switch (front.mTag) { 531 case WrNotifierEvent::Tag::WakeUp: 532 WrNotifierEvent_HandleWakeUp(aWindowId, front.FrameReadyParams()); 533 handleNext = false; 534 break; 535 case WrNotifierEvent::Tag::NewFrameReady: 536 WrNotifierEvent_HandleNewFrameReady(aWindowId, front.PublishId(), 537 front.FrameReadyParams()); 538 handleNext = false; 539 break; 540 case WrNotifierEvent::Tag::ExternalEvent: 541 WrNotifierEvent_HandleExternalEvent(aWindowId, front.ExternalEvent()); 542 break; 543 } 544 events->pop(); 545 } 546 547 { 548 auto windows = mWindowInfos.Lock(); 549 auto it = windows->find(AsUint64(aWindowId)); 550 if (it == windows->end()) { 551 return; 552 } 553 WindowInfo* info = it->second.get(); 554 555 if (!events->empty() || !info->mPendingWrNotifierEvents.empty()) { 556 PostWrNotifierEvents(aWindowId, info); 557 } 558 } 559 } 560 561 void RenderThread::WrNotifierEvent_HandleWakeUp( 562 wr::WindowId aWindowId, const wr::FrameReadyParams& aParams) { 563 MOZ_ASSERT(IsInRenderThread()); 564 MOZ_ASSERT(!aParams.tracked); 565 HandleFrameOneDoc(aWindowId, aParams, Nothing()); 566 } 567 568 void RenderThread::WrNotifierEvent_HandleNewFrameReady( 569 wr::WindowId aWindowId, wr::FramePublishId aPublishId, 570 const wr::FrameReadyParams& aParams) { 571 MOZ_ASSERT(IsInRenderThread()); 572 573 HandleFrameOneDoc(aWindowId, aParams, Some(aPublishId)); 574 } 575 576 void RenderThread::WrNotifierEvent_HandleExternalEvent( 577 wr::WindowId aWindowId, UniquePtr<RendererEvent> aRendererEvent) { 578 MOZ_ASSERT(IsInRenderThread()); 579 580 RunEvent(aWindowId, std::move(aRendererEvent), /* aViaWebRender */ true); 581 } 582 583 void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId, 584 const TimeStamp& aRecordingStart, 585 wr::PipelineId aRootPipelineId) { 586 MOZ_ASSERT(IsInRenderThread()); 587 RendererOGL* renderer = GetRenderer(aWindowId); 588 MOZ_ASSERT(renderer); 589 590 renderer->BeginRecording(aRecordingStart, aRootPipelineId); 591 } 592 593 Maybe<layers::FrameRecording> RenderThread::EndRecordingForWindow( 594 wr::WindowId aWindowId) { 595 MOZ_ASSERT(IsInRenderThread()); 596 597 RendererOGL* renderer = GetRenderer(aWindowId); 598 MOZ_ASSERT(renderer); 599 return renderer->EndRecording(); 600 } 601 602 void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, 603 const wr::FrameReadyParams& aParams, 604 Maybe<FramePublishId> aPublishId) { 605 MOZ_ASSERT(IsInRenderThread()); 606 607 if (mHasShutdown) { 608 return; 609 } 610 611 HandleFrameOneDocInner(aWindowId, aParams, aPublishId); 612 613 if (aParams.tracked) { 614 DecPendingFrameCount(aWindowId); 615 } 616 } 617 618 void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId, 619 const wr::FrameReadyParams& aParams, 620 Maybe<FramePublishId> aPublishId) { 621 if (IsDestroyed(aWindowId)) { 622 return; 623 } 624 625 if (mHandlingDeviceReset) { 626 return; 627 } 628 629 PendingFrameInfo frame; 630 if (aParams.tracked) { 631 // scope lock 632 auto windows = mWindowInfos.Lock(); 633 auto it = windows->find(AsUint64(aWindowId)); 634 if (it == windows->end()) { 635 MOZ_ASSERT(false); 636 return; 637 } 638 639 WindowInfo* info = it->second.get(); 640 PendingFrameInfo& frameInfo = info->mPendingFrames.front(); 641 642 frame = frameInfo; 643 } else { 644 // Just give the frame info default values. 645 frame = {TimeStamp::Now(), VsyncId()}; 646 } 647 648 // Sadly this doesn't include the lock, since we don't have the frame there 649 // yet. 650 glean::wr::time_to_render_start.AccumulateRawDuration(TimeStamp::Now() - 651 frame.mStartTime); 652 653 // It is for ensuring that PrepareForUse() is called before 654 // RenderTextureHost::Lock(). 655 HandleRenderTextureOps(); 656 657 if (aPublishId.isSome()) { 658 SetFramePublishId(aWindowId, aPublishId.ref()); 659 } 660 661 RendererStats stats = {0}; 662 663 UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, aParams, 664 /* aReadbackSize */ Nothing(), 665 /* aReadbackFormat */ Nothing(), 666 /* aReadbackBuffer */ Nothing(), &stats); 667 668 // The start time is from WebRenderBridgeParent::CompositeToTarget. From that 669 // point until now (when the frame is finally pushed to the screen) is 670 // equivalent to the COMPOSITE_TIME metric in the non-WR codepath. 671 TimeDuration compositeDuration = TimeStamp::Now() - frame.mStartTime; 672 mozilla::glean::gfx::composite_time.AccumulateRawDuration(compositeDuration); 673 PerfStats::RecordMeasurement(PerfStats::Metric::Compositing, 674 compositeDuration); 675 if (stats.frame_build_time > 0.0) { 676 TimeDuration fbTime = 677 TimeDuration::FromMilliseconds(stats.frame_build_time); 678 mozilla::glean::wr::framebuild_time.AccumulateRawDuration(fbTime); 679 PerfStats::RecordMeasurement(PerfStats::Metric::FrameBuilding, fbTime); 680 } 681 } 682 683 void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) { 684 if (mHasShutdown) { 685 return; 686 } 687 688 if (!IsInRenderThread()) { 689 PostRunnable(NewRunnableMethod<wr::WindowId, wr::ColorF>( 690 "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor, 691 aWindowId, aColor)); 692 return; 693 } 694 695 if (IsDestroyed(aWindowId)) { 696 return; 697 } 698 699 auto it = mRenderers.find(aWindowId); 700 MOZ_ASSERT(it != mRenderers.end()); 701 if (it != mRenderers.end()) { 702 wr_renderer_set_clear_color(it->second->GetRenderer(), aColor); 703 } 704 } 705 706 void RenderThread::SetProfilerUI(wr::WindowId aWindowId, 707 const nsACString& aUI) { 708 if (mHasShutdown) { 709 return; 710 } 711 712 if (!IsInRenderThread()) { 713 PostRunnable(NewRunnableMethod<wr::WindowId, nsCString>( 714 "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI, 715 aWindowId, nsCString(aUI))); 716 return; 717 } 718 719 auto it = mRenderers.find(aWindowId); 720 if (it != mRenderers.end()) { 721 it->second->SetProfilerUI(aUI); 722 } 723 } 724 725 void RenderThread::PostEvent(wr::WindowId aWindowId, 726 UniquePtr<RendererEvent> aEvent) { 727 PostRunnable( 728 NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&, bool>( 729 "wr::RenderThread::PostEvent", this, &RenderThread::RunEvent, 730 aWindowId, std::move(aEvent), /* aViaWebRender */ false)); 731 } 732 733 void RenderThread::RunEvent(wr::WindowId aWindowId, 734 UniquePtr<RendererEvent> aEvent, 735 bool aViaWebRender) { 736 MOZ_ASSERT(IsInRenderThread()); 737 738 #ifndef DEBUG 739 const auto maxDurationMs = 2 * 1000; 740 const auto start = TimeStamp::Now(); 741 const auto delayMs = static_cast<uint32_t>( 742 (start - aEvent->mCreationTimeStamp).ToMilliseconds()); 743 // Check for the delay only if RendererEvent is delivered without using 744 // WebRender. Its delivery via WebRender can be very slow. 745 if (aViaWebRender && (delayMs > maxDurationMs)) { 746 gfxCriticalNote << "Calling " << aEvent->Name() 747 << "::Run: is delayed: " << delayMs; 748 } 749 #endif 750 751 aEvent->Run(*this, aWindowId); 752 aEvent = nullptr; 753 754 #ifndef DEBUG 755 const auto end = TimeStamp::Now(); 756 const auto durationMs = static_cast<uint32_t>((end - start).ToMilliseconds()); 757 if (durationMs > maxDurationMs) { 758 gfxCriticalNote << "NewRenderer::Run is slow: " << durationMs; 759 } 760 #endif 761 } 762 763 static void NotifyDidRender(layers::CompositorBridgeParent* aBridge, 764 const RefPtr<const WebRenderPipelineInfo>& aInfo, 765 VsyncId aCompositeStartId, 766 TimeStamp aCompositeStart, TimeStamp aRenderStart, 767 TimeStamp aEnd, bool aRender, 768 RendererStats aStats) { 769 if (aRender && aBridge->GetWrBridge()) { 770 // We call this here to mimic the behavior in LayerManagerComposite, as to 771 // not change what Talos measures. That is, we do not record an empty frame 772 // as a frame. 773 aBridge->GetWrBridge()->RecordFrame(); 774 } 775 776 aBridge->NotifyDidRender(aCompositeStartId, aCompositeStart, aRenderStart, 777 aEnd, &aStats); 778 779 for (const auto& epoch : aInfo->Raw().epochs) { 780 aBridge->NotifyPipelineRendered(epoch.pipeline_id, epoch.epoch, 781 aCompositeStartId, aCompositeStart, 782 aRenderStart, aEnd, &aStats); 783 } 784 785 if (aBridge->GetWrBridge()) { 786 aBridge->GetWrBridge()->RetrySkippedComposite(); 787 } 788 } 789 790 static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) { 791 if (aBridge->GetWrBridge()) { 792 aBridge->GetWrBridge()->RetrySkippedComposite(); 793 } 794 } 795 796 void RenderThread::SetFramePublishId(wr::WindowId aWindowId, 797 FramePublishId aPublishId) { 798 MOZ_ASSERT(IsInRenderThread()); 799 800 auto it = mRenderers.find(aWindowId); 801 MOZ_ASSERT(it != mRenderers.end()); 802 if (it == mRenderers.end()) { 803 return; 804 } 805 auto& renderer = it->second; 806 807 renderer->SetFramePublishId(aPublishId); 808 } 809 810 void RenderThread::UpdateAndRender( 811 wr::WindowId aWindowId, const VsyncId& aStartId, 812 const TimeStamp& aStartTime, const wr::FrameReadyParams& aParams, 813 const Maybe<gfx::IntSize>& aReadbackSize, 814 const Maybe<wr::ImageFormat>& aReadbackFormat, 815 const Maybe<Range<uint8_t>>& aReadbackBuffer, RendererStats* aStats, 816 bool* aNeedsYFlip) { 817 AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS); 818 MOZ_ASSERT(IsInRenderThread()); 819 MOZ_ASSERT(aParams.render || aReadbackBuffer.isNothing()); 820 821 auto it = mRenderers.find(aWindowId); 822 MOZ_ASSERT(it != mRenderers.end()); 823 if (it == mRenderers.end()) { 824 return; 825 } 826 827 TimeStamp start = TimeStamp::Now(); 828 829 auto& renderer = it->second; 830 831 std::string markerName = "Composite #" + std::to_string(AsUint64(aWindowId)); 832 AutoProfilerTracing tracingCompositeMarker( 833 markerName.c_str(), geckoprofiler::category::GRAPHICS, 834 Some(renderer->GetCompositorBridge()->GetInnerWindowId())); 835 836 bool render = aParams.render; 837 if (renderer->IsPaused()) { 838 render = false; 839 } 840 LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64 " aRender %d", 841 AsUint64(aWindowId), render); 842 843 layers::CompositorThread()->Dispatch( 844 NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender, 845 renderer->GetCompositorBridge())); 846 847 wr::RenderedFrameId latestFrameId; 848 if (render) { 849 latestFrameId = renderer->UpdateAndRender(aReadbackSize, aReadbackFormat, 850 aReadbackBuffer, aNeedsYFlip, 851 aParams, aStats); 852 } else { 853 renderer->Update(); 854 } 855 // Check graphics reset status even when rendering is skipped. 856 renderer->CheckGraphicsResetStatus( 857 gfx::DeviceResetDetectPlace::WR_POST_UPDATE, 858 /* aForce */ false); 859 860 TimeStamp end = TimeStamp::Now(); 861 RefPtr<const WebRenderPipelineInfo> info = renderer->GetLastPipelineInfo(); 862 863 layers::CompositorThread()->Dispatch( 864 NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender, 865 renderer->GetCompositorBridge(), info, aStartId, 866 aStartTime, start, end, render, *aStats)); 867 868 RefPtr<layers::Fence> fence; 869 870 if (latestFrameId.IsValid()) { 871 fence = renderer->GetAndResetReleaseFence(); 872 873 // Wait for GPU after posting NotifyDidRender, since the wait is not 874 // necessary for the NotifyDidRender. 875 // The wait is necessary for Textures recycling of AsyncImagePipelineManager 876 // and for avoiding GPU queue is filled with too much tasks. 877 // WaitForGPU's implementation is different for each platform. 878 auto timerId = glean::wr::gpu_wait_time.Start(); 879 renderer->WaitForGPU(); 880 glean::wr::gpu_wait_time.StopAndAccumulate(std::move(timerId)); 881 } else { 882 // Update frame id for NotifyPipelinesUpdated() when rendering does not 883 // happen, either because rendering was not requested or the frame was 884 // canceled. Rendering can sometimes be canceled if UpdateAndRender is 885 // called when the window is not yet ready (not mapped or 0 size). 886 latestFrameId = renderer->UpdateFrameId(); 887 } 888 889 RenderedFrameId lastCompletedFrameId = renderer->GetLastCompletedFrameId(); 890 891 RefPtr<layers::AsyncImagePipelineManager> pipelineMgr = 892 renderer->GetCompositorBridge()->GetAsyncImagePipelineManager(); 893 // pipelineMgr should always be non-null here because it is only nulled out 894 // after the WebRenderAPI instance for the CompositorBridgeParent is 895 // destroyed, and that destruction blocks until the renderer thread has 896 // removed the relevant renderer. And after that happens we should never reach 897 // this code at all; it would bail out at the mRenderers.find check above. 898 MOZ_ASSERT(pipelineMgr); 899 pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId, 900 std::move(fence)); 901 } 902 903 void RenderThread::Pause(wr::WindowId aWindowId) { 904 MOZ_ASSERT(IsInRenderThread()); 905 LOG("RenderThread::Pause() aWindowId %" PRIx64 "", AsUint64(aWindowId)); 906 907 auto it = mRenderers.find(aWindowId); 908 MOZ_ASSERT(it != mRenderers.end()); 909 if (it == mRenderers.end()) { 910 gfxCriticalNote << "RenderThread cannot find renderer for window " 911 << gfx::hexa(aWindowId) << " to pause."; 912 return; 913 } 914 auto& renderer = it->second; 915 renderer->Pause(); 916 917 UpdateActiveRendererCount(); 918 } 919 920 bool RenderThread::Resume(wr::WindowId aWindowId) { 921 MOZ_ASSERT(IsInRenderThread()); 922 LOG("enderThread::Resume() aWindowId %" PRIx64 "", AsUint64(aWindowId)); 923 924 auto it = mRenderers.find(aWindowId); 925 MOZ_ASSERT(it != mRenderers.end()); 926 if (it == mRenderers.end()) { 927 gfxCriticalNote << "RenderThread cannot find renderer for window " 928 << gfx::hexa(aWindowId) << " to resume."; 929 return false; 930 } 931 auto& renderer = it->second; 932 bool resumed = renderer->Resume(); 933 934 UpdateActiveRendererCount(); 935 936 return resumed; 937 } 938 939 void RenderThread::NotifyIdle() { 940 if (!IsInRenderThread()) { 941 PostRunnable(NewRunnableMethod("RenderThread::NotifyIdle", this, 942 &RenderThread::NotifyIdle)); 943 944 return; 945 } 946 947 wr_chunk_pool_purge(mChunkPool); 948 } 949 950 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) { 951 const int64_t maxFrameCount = 1; 952 953 // Too many pending frames if pending frames exit more than maxFrameCount 954 // or if RenderBackend is still processing a frame. 955 956 auto windows = mWindowInfos.Lock(); 957 auto it = windows->find(AsUint64(aWindowId)); 958 if (it == windows->end()) { 959 MOZ_ASSERT(false); 960 return true; 961 } 962 WindowInfo* info = it->second.get(); 963 964 if (info->PendingCount() > maxFrameCount) { 965 return true; 966 } 967 // If there is no ongoing frame build, we accept a new frame. 968 return info->mPendingFrameBuild > 0; 969 } 970 971 bool RenderThread::IsDestroyed(wr::WindowId aWindowId) { 972 auto windows = mWindowInfos.Lock(); 973 auto it = windows->find(AsUint64(aWindowId)); 974 if (it == windows->end()) { 975 return true; 976 } 977 978 return it->second->mIsDestroyed; 979 } 980 981 void RenderThread::SetDestroyed(wr::WindowId aWindowId) { 982 auto windows = mWindowInfos.Lock(); 983 auto it = windows->find(AsUint64(aWindowId)); 984 if (it == windows->end()) { 985 MOZ_ASSERT(false); 986 return; 987 } 988 it->second->mIsDestroyed = true; 989 } 990 991 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId, 992 const VsyncId& aStartId, 993 const TimeStamp& aStartTime) { 994 auto windows = mWindowInfos.Lock(); 995 auto it = windows->find(AsUint64(aWindowId)); 996 if (it == windows->end()) { 997 MOZ_ASSERT(false); 998 return; 999 } 1000 it->second->mPendingFrameBuild++; 1001 it->second->mPendingFrames.push(PendingFrameInfo{aStartTime, aStartId}); 1002 } 1003 1004 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId) { 1005 auto windows = mWindowInfos.Lock(); 1006 auto it = windows->find(AsUint64(aWindowId)); 1007 if (it == windows->end()) { 1008 MOZ_ASSERT(false); 1009 return; 1010 } 1011 WindowInfo* info = it->second.get(); 1012 MOZ_RELEASE_ASSERT(info->mPendingFrameBuild >= 1); 1013 info->mPendingFrameBuild--; 1014 } 1015 1016 void RenderThread::DecPendingFrameCount(wr::WindowId aWindowId) { 1017 auto windows = mWindowInfos.Lock(); 1018 auto it = windows->find(AsUint64(aWindowId)); 1019 if (it == windows->end()) { 1020 MOZ_ASSERT(false); 1021 return; 1022 } 1023 WindowInfo* info = it->second.get(); 1024 info->mPendingFrames.pop(); 1025 } 1026 1027 void RenderThread::RegisterExternalImage( 1028 const wr::ExternalImageId& aExternalImageId, 1029 already_AddRefed<RenderTextureHost> aTexture) { 1030 MutexAutoLock lock(mRenderTextureMapLock); 1031 1032 if (mHasShutdown) { 1033 return; 1034 } 1035 MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end()); 1036 RefPtr<RenderTextureHost> texture = aTexture; 1037 if (texture->SyncObjectNeeded()) { 1038 mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture); 1039 } 1040 mRenderTextures.emplace(aExternalImageId, texture); 1041 1042 #ifdef DEBUG 1043 int32_t maxAllowedIncrease = 1044 StaticPrefs::gfx_testing_assert_render_textures_increase(); 1045 1046 if (maxAllowedIncrease <= 0) { 1047 mRenderTexturesLastTime = -1; 1048 } else { 1049 if (mRenderTexturesLastTime < 0) { 1050 mRenderTexturesLastTime = static_cast<int32_t>(mRenderTextures.size()); 1051 } 1052 MOZ_ASSERT((static_cast<int32_t>(mRenderTextures.size()) - 1053 mRenderTexturesLastTime) < maxAllowedIncrease); 1054 } 1055 #endif 1056 } 1057 1058 void RenderThread::UnregisterExternalImage( 1059 const wr::ExternalImageId& aExternalImageId) { 1060 MutexAutoLock lock(mRenderTextureMapLock); 1061 if (mHasShutdown) { 1062 return; 1063 } 1064 auto it = mRenderTextures.find(aExternalImageId); 1065 if (it == mRenderTextures.end()) { 1066 return; 1067 } 1068 1069 auto& texture = it->second; 1070 if (texture->SyncObjectNeeded()) { 1071 MOZ_RELEASE_ASSERT( 1072 mSyncObjectNeededRenderTextures.erase(aExternalImageId) == 1); 1073 } 1074 1075 if (!IsInRenderThread()) { 1076 // The RenderTextureHost should be released in render thread. So, post the 1077 // deletion task here. 1078 // The shmem and raw buffer are owned by compositor ipc channel. It's 1079 // possible that RenderTextureHost is still exist after the shmem/raw buffer 1080 // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine 1081 // for this situation. Gecko will only release the buffer if WR doesn't need 1082 // it. So, no one will access the invalid buffer in RenderTextureHost. 1083 RefPtr<RenderTextureHost> texture = it->second; 1084 mRenderTextures.erase(it); 1085 mRenderTexturesDeferred.emplace_back(std::move(texture)); 1086 PostRunnable(NewRunnableMethod( 1087 "RenderThread::DeferredRenderTextureHostDestroy", this, 1088 &RenderThread::DeferredRenderTextureHostDestroy)); 1089 } else { 1090 mRenderTextures.erase(it); 1091 } 1092 } 1093 1094 void RenderThread::DestroyExternalImagesSyncWait( 1095 const std::vector<wr::ExternalImageId>&& aIds) { 1096 if (!IsInRenderThread()) { 1097 layers::SynchronousTask task("Destroy external images"); 1098 1099 RefPtr<Runnable> runnable = NS_NewRunnableFunction( 1100 "RenderThread::DestroyExternalImagesSyncWait::Runnable", 1101 [&task, ids = std::move(aIds)]() { 1102 layers::AutoCompleteTask complete(&task); 1103 RenderThread::Get()->DestroyExternalImages(std::move(ids)); 1104 }); 1105 1106 PostRunnable(runnable.forget()); 1107 task.Wait(); 1108 return; 1109 } 1110 DestroyExternalImages(std::move(aIds)); 1111 } 1112 1113 void RenderThread::DestroyExternalImages( 1114 const std::vector<wr::ExternalImageId>&& aIds) { 1115 MOZ_ASSERT(IsInRenderThread()); 1116 1117 std::vector<RefPtr<RenderTextureHost>> hosts; 1118 { 1119 MutexAutoLock lock(mRenderTextureMapLock); 1120 if (mHasShutdown) { 1121 return; 1122 } 1123 1124 for (auto& id : aIds) { 1125 auto it = mRenderTextures.find(id); 1126 if (it == mRenderTextures.end()) { 1127 continue; 1128 } 1129 hosts.emplace_back(it->second); 1130 } 1131 } 1132 1133 for (auto& host : hosts) { 1134 host->Destroy(); 1135 } 1136 } 1137 1138 void RenderThread::PrepareForUse(const wr::ExternalImageId& aExternalImageId) { 1139 AddRenderTextureOp(RenderTextureOp::PrepareForUse, aExternalImageId); 1140 } 1141 1142 void RenderThread::NotifyNotUsed(const wr::ExternalImageId& aExternalImageId) { 1143 AddRenderTextureOp(RenderTextureOp::NotifyNotUsed, aExternalImageId); 1144 } 1145 1146 void RenderThread::NotifyForUse(const wr::ExternalImageId& aExternalImageId) { 1147 AddRenderTextureOp(RenderTextureOp::NotifyForUse, aExternalImageId); 1148 } 1149 1150 void RenderThread::AddRenderTextureOp( 1151 RenderTextureOp aOp, const wr::ExternalImageId& aExternalImageId) { 1152 MOZ_ASSERT(!IsInRenderThread()); 1153 1154 MutexAutoLock lock(mRenderTextureMapLock); 1155 1156 auto it = mRenderTextures.find(aExternalImageId); 1157 MOZ_ASSERT(it != mRenderTextures.end()); 1158 if (it == mRenderTextures.end()) { 1159 return; 1160 } 1161 1162 RefPtr<RenderTextureHost> texture = it->second; 1163 mRenderTextureOps.emplace_back(aOp, std::move(texture)); 1164 1165 if (mRenderTextureOpsRunnable) { 1166 // Runnable was already triggered 1167 return; 1168 } 1169 1170 RefPtr<nsIRunnable> runnable = 1171 NewRunnableMethod("RenderThread::HandleRenderTextureOps", this, 1172 &RenderThread::HandleRenderTextureOps); 1173 mRenderTextureOpsRunnable = runnable; 1174 PostRunnable(runnable.forget()); 1175 } 1176 1177 void RenderThread::HandleRenderTextureOps() { 1178 MOZ_ASSERT(IsInRenderThread()); 1179 1180 std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>> 1181 renderTextureOps; 1182 { 1183 MutexAutoLock lock(mRenderTextureMapLock); 1184 mRenderTextureOps.swap(renderTextureOps); 1185 mRenderTextureOpsRunnable = nullptr; 1186 } 1187 1188 for (auto& it : renderTextureOps) { 1189 switch (it.first) { 1190 case RenderTextureOp::PrepareForUse: 1191 it.second->PrepareForUse(); 1192 break; 1193 case RenderTextureOp::NotifyForUse: 1194 it.second->NotifyForUse(); 1195 break; 1196 case RenderTextureOp::NotifyNotUsed: 1197 it.second->NotifyNotUsed(); 1198 break; 1199 } 1200 } 1201 } 1202 1203 RefPtr<RenderTextureHostUsageInfo> RenderThread::GetOrMergeUsageInfo( 1204 const wr::ExternalImageId& aExternalImageId, 1205 RefPtr<RenderTextureHostUsageInfo> aUsageInfo) { 1206 MutexAutoLock lock(mRenderTextureMapLock); 1207 if (mHasShutdown) { 1208 return nullptr; 1209 } 1210 auto it = mRenderTextures.find(aExternalImageId); 1211 if (it == mRenderTextures.end()) { 1212 return nullptr; 1213 } 1214 1215 auto& texture = it->second; 1216 return texture->GetOrMergeUsageInfo(lock, aUsageInfo); 1217 } 1218 1219 void RenderThread::UnregisterExternalImageDuringShutdown( 1220 const wr::ExternalImageId& aExternalImageId) { 1221 MOZ_ASSERT(IsInRenderThread()); 1222 MutexAutoLock lock(mRenderTextureMapLock); 1223 MOZ_ASSERT(mHasShutdown); 1224 mRenderTextures.erase(aExternalImageId); 1225 } 1226 1227 bool RenderThread::SyncObjectNeeded() { 1228 MOZ_ASSERT(IsInRenderThread()); 1229 MutexAutoLock lock(mRenderTextureMapLock); 1230 return !mSyncObjectNeededRenderTextures.empty(); 1231 } 1232 1233 void RenderThread::DeferredRenderTextureHostDestroy() { 1234 MutexAutoLock lock(mRenderTextureMapLock); 1235 mRenderTexturesDeferred.clear(); 1236 } 1237 1238 RenderTextureHost* RenderThread::GetRenderTexture( 1239 const wr::ExternalImageId& aExternalImageId) { 1240 MutexAutoLock lock(mRenderTextureMapLock); 1241 auto it = mRenderTextures.find(aExternalImageId); 1242 MOZ_ASSERT(it != mRenderTextures.end()); 1243 if (it == mRenderTextures.end()) { 1244 return nullptr; 1245 } 1246 return it->second; 1247 } 1248 1249 std::tuple<RenderTextureHost*, RefPtr<RenderTextureHostUsageInfo>> 1250 RenderThread::GetRenderTextureAndUsageInfo( 1251 const wr::ExternalImageId& aExternalImageId) { 1252 MutexAutoLock lock(mRenderTextureMapLock); 1253 auto it = mRenderTextures.find(aExternalImageId); 1254 MOZ_ASSERT(it != mRenderTextures.end()); 1255 if (it == mRenderTextures.end()) { 1256 return {}; 1257 } 1258 return {it->second, it->second->GetTextureHostUsageInfo(lock)}; 1259 } 1260 1261 void RenderThread::InitDeviceTask() { 1262 MOZ_ASSERT(IsInRenderThread()); 1263 MOZ_ASSERT(!mSingletonGL); 1264 LOG("RenderThread::InitDeviceTask()"); 1265 1266 const auto start = TimeStamp::Now(); 1267 1268 if (gfx::gfxVars::UseSoftwareWebRender()) { 1269 // Ensure we don't instantiate any shared GL context when SW-WR is used. 1270 return; 1271 } 1272 1273 nsAutoCString err; 1274 CreateSingletonGL(err); 1275 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) { 1276 mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw()); 1277 } 1278 // Query the shared GL context to force the 1279 // lazy initialization to happen now. 1280 SingletonGL(); 1281 1282 const auto maxDurationMs = 3 * 1000; 1283 const auto end = TimeStamp::Now(); 1284 const auto durationMs = static_cast<uint32_t>((end - start).ToMilliseconds()); 1285 if (durationMs > maxDurationMs) { 1286 gfxCriticalNoteOnce << "RenderThread::InitDeviceTask is slow: " 1287 << durationMs; 1288 } 1289 } 1290 1291 void RenderThread::BeginShaderWarmupIfNeeded() { 1292 if (mShaders && gfx::gfxVars::ShouldWarmUpWebRenderProgramBinaries()) { 1293 PostResumeShaderWarmupRunnable(); 1294 } 1295 } 1296 1297 void RenderThread::PostResumeShaderWarmupRunnable() { 1298 RefPtr<Runnable> runnable = 1299 NewRunnableMethod("RenderThread::ResumeShaderWarmup", this, 1300 &RenderThread::ResumeShaderWarmup); 1301 PostRunnable(runnable.forget()); 1302 } 1303 1304 void RenderThread::ResumeShaderWarmup() { 1305 if (mShaders) { 1306 bool needAnotherWarmupStep = mShaders->ResumeWarmup(); 1307 if (needAnotherWarmupStep) { 1308 PostResumeShaderWarmupRunnable(); 1309 } 1310 } 1311 } 1312 1313 void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) { 1314 nsCOMPtr<nsIRunnable> runnable = aRunnable; 1315 mThread->Dispatch(runnable.forget()); 1316 } 1317 1318 /* static */ void RenderThread::PostHandleDeviceReset( 1319 gfx::DeviceResetDetectPlace aPlace, gfx::DeviceResetReason aReason) { 1320 MOZ_ASSERT(!IsInRenderThread()); 1321 auto* renderThread = Get(); 1322 if (!renderThread) { 1323 gfx::GPUProcessManager::NotifyDeviceReset(aReason, aPlace); 1324 return; 1325 } 1326 1327 renderThread->PostRunnable( 1328 NewRunnableMethod<gfx::DeviceResetDetectPlace, gfx::DeviceResetReason>( 1329 "wr::RenderThread::HandleDeviceReset", renderThread, 1330 &RenderThread::HandleDeviceReset, aPlace, aReason)); 1331 } 1332 1333 void RenderThread::HandleDeviceReset(gfx::DeviceResetDetectPlace aPlace, 1334 gfx::DeviceResetReason aReason) { 1335 MOZ_ASSERT(IsInRenderThread()); 1336 1337 if (mHandlingDeviceReset) { 1338 return; 1339 } 1340 1341 mHandlingDeviceReset = true; 1342 1343 { 1344 MutexAutoLock lock(mRenderTextureMapLock); 1345 mRenderTexturesDeferred.clear(); 1346 for (const auto& entry : mRenderTextures) { 1347 entry.second->ClearCachedResources(); 1348 } 1349 } 1350 1351 gfx::GPUProcessManager::NotifyDeviceReset(aReason, aPlace); 1352 } 1353 1354 bool RenderThread::IsHandlingDeviceReset() { 1355 MOZ_ASSERT(IsInRenderThread()); 1356 return mHandlingDeviceReset; 1357 } 1358 1359 void RenderThread::SimulateDeviceReset() { 1360 if (!IsInRenderThread()) { 1361 PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this, 1362 &RenderThread::SimulateDeviceReset)); 1363 } else { 1364 // When this function is called GPUProcessManager::SimulateDeviceReset() 1365 // already triggers destroying all CompositorSessions before re-creating 1366 // them. 1367 HandleDeviceReset(gfx::DeviceResetDetectPlace::WR_SIMULATE, 1368 gfx::DeviceResetReason::FORCED_RESET); 1369 } 1370 } 1371 1372 static void DoNotifyWebRenderError(WebRenderError aError) { 1373 layers::CompositorManagerParent::NotifyWebRenderError(aError); 1374 } 1375 1376 void RenderThread::NotifyWebRenderError(WebRenderError aError) { 1377 MOZ_ASSERT(IsInRenderThread()); 1378 1379 layers::CompositorThread()->Dispatch(NewRunnableFunction( 1380 "DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError)); 1381 } 1382 1383 void RenderThread::HandleWebRenderError(WebRenderError aError) { 1384 MOZ_ASSERT(IsInRenderThread()); 1385 if (mHandlingWebRenderError) { 1386 return; 1387 } 1388 1389 NotifyWebRenderError(aError); 1390 1391 { 1392 MutexAutoLock lock(mRenderTextureMapLock); 1393 mRenderTexturesDeferred.clear(); 1394 for (const auto& entry : mRenderTextures) { 1395 entry.second->ClearCachedResources(); 1396 } 1397 } 1398 mHandlingWebRenderError = true; 1399 // WebRender is going to be disabled by 1400 // GPUProcessManager::NotifyWebRenderError() 1401 } 1402 1403 bool RenderThread::IsHandlingWebRenderError() { 1404 MOZ_ASSERT(IsInRenderThread()); 1405 return mHandlingWebRenderError; 1406 } 1407 1408 gl::GLContext* RenderThread::SingletonGL() { 1409 nsAutoCString err; 1410 auto* gl = SingletonGL(err); 1411 if (!err.IsEmpty()) { 1412 gfxCriticalNote << err.get(); 1413 } 1414 return gl; 1415 } 1416 1417 void RenderThread::CreateSingletonGL(nsACString& aError) { 1418 MOZ_ASSERT(IsInRenderThread()); 1419 LOG("RenderThread::CreateSingletonGL()"); 1420 1421 mSingletonGL = CreateGLContext(aError); 1422 mSingletonGLIsForHardwareWebRender = !gfx::gfxVars::UseSoftwareWebRender(); 1423 } 1424 1425 gl::GLContext* RenderThread::SingletonGL(nsACString& aError) { 1426 MOZ_ASSERT(IsInRenderThread()); 1427 if (!mSingletonGL) { 1428 CreateSingletonGL(aError); 1429 mShaders = nullptr; 1430 } 1431 if (mSingletonGL && mSingletonGLIsForHardwareWebRender && !mShaders) { 1432 mShaders = MakeUnique<WebRenderShaders>(mSingletonGL, mProgramCache.get()); 1433 } 1434 1435 return mSingletonGL.get(); 1436 } 1437 1438 gl::GLContext* RenderThread::SingletonGLForCompositorOGL() { 1439 MOZ_RELEASE_ASSERT(gfx::gfxVars::UseSoftwareWebRender()); 1440 1441 if (mSingletonGLIsForHardwareWebRender) { 1442 // Clear singleton GL, since GLContext is for hardware WebRender. 1443 ClearSingletonGL(); 1444 } 1445 return SingletonGL(); 1446 } 1447 1448 void RenderThread::ClearSingletonGL() { 1449 MOZ_ASSERT(IsInRenderThread()); 1450 LOG("RenderThread::ClearSingletonGL()"); 1451 1452 if (mSurfacePool) { 1453 mSurfacePool->DestroyGLResourcesForContext(mSingletonGL); 1454 } 1455 if (mProgramsForCompositorOGL) { 1456 mProgramsForCompositorOGL->Clear(); 1457 mProgramsForCompositorOGL = nullptr; 1458 } 1459 mShaders = nullptr; 1460 mSingletonGL = nullptr; 1461 } 1462 1463 RefPtr<layers::ShaderProgramOGLsHolder> 1464 RenderThread::GetProgramsForCompositorOGL() { 1465 if (!mSingletonGL) { 1466 return nullptr; 1467 } 1468 1469 if (!mProgramsForCompositorOGL) { 1470 mProgramsForCompositorOGL = 1471 MakeAndAddRef<layers::ShaderProgramOGLsHolder>(mSingletonGL); 1472 } 1473 return mProgramsForCompositorOGL; 1474 } 1475 1476 RefPtr<layers::SurfacePool> RenderThread::SharedSurfacePool() { 1477 #if defined(XP_DARWIN) || defined(MOZ_WAYLAND) 1478 if (!mSurfacePool) { 1479 size_t poolSizeLimit = 1480 StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup(); 1481 mSurfacePool = layers::SurfacePool::Create(poolSizeLimit); 1482 } 1483 #endif 1484 return mSurfacePool; 1485 } 1486 1487 void RenderThread::ClearSharedSurfacePool() { mSurfacePool = nullptr; } 1488 1489 static void GLAPIENTRY DebugMessageCallback(GLenum aSource, GLenum aType, 1490 GLuint aId, GLenum aSeverity, 1491 GLsizei aLength, 1492 const GLchar* aMessage, 1493 const GLvoid* aUserParam) { 1494 constexpr const char* kContextLost = "Context has been lost."; 1495 1496 if (StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() && 1497 aSeverity == LOCAL_GL_DEBUG_SEVERITY_HIGH) { 1498 auto message = std::string(aMessage, aLength); 1499 // When content lost happned, error messages are flooded by its message. 1500 if (message != kContextLost) { 1501 gfxCriticalNote << message; 1502 } else { 1503 gfxCriticalNoteOnce << message; 1504 } 1505 } 1506 1507 if (StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup()) { 1508 gl::GLContext* gl = (gl::GLContext*)aUserParam; 1509 gl->DebugCallback(aSource, aType, aId, aSeverity, aLength, aMessage); 1510 } 1511 } 1512 1513 // static 1514 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext* aGLContext) { 1515 if (!aGLContext) { 1516 return; 1517 } 1518 1519 bool enableDebugMessage = 1520 StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() || 1521 StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup(); 1522 1523 if (enableDebugMessage && 1524 aGLContext->IsExtensionSupported(gl::GLContext::KHR_debug)) { 1525 aGLContext->fEnable(LOCAL_GL_DEBUG_OUTPUT); 1526 aGLContext->fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS); 1527 aGLContext->fDebugMessageCallback(&DebugMessageCallback, (void*)aGLContext); 1528 aGLContext->fDebugMessageControl(LOCAL_GL_DONT_CARE, LOCAL_GL_DONT_CARE, 1529 LOCAL_GL_DONT_CARE, 0, nullptr, true); 1530 } 1531 } 1532 1533 WebRenderShaders::WebRenderShaders(gl::GLContext* gl, 1534 WebRenderProgramCache* programCache) { 1535 mGL = gl; 1536 mShaders = 1537 wr_shaders_new(gl, programCache ? programCache->Raw() : nullptr, 1538 StaticPrefs::gfx_webrender_precache_shaders_AtStartup()); 1539 } 1540 1541 WebRenderShaders::~WebRenderShaders() { 1542 mGL->MakeCurrent(); 1543 wr_shaders_delete(mShaders); 1544 } 1545 1546 bool WebRenderShaders::ResumeWarmup() { 1547 mGL->MakeCurrent(); 1548 return wr_shaders_resume_warmup(mShaders); 1549 } 1550 1551 WebRenderThreadPool::WebRenderThreadPool(bool low_priority) { 1552 mThreadPool = wr_thread_pool_new(low_priority); 1553 } 1554 1555 WebRenderThreadPool::~WebRenderThreadPool() { Release(); } 1556 1557 void WebRenderThreadPool::Release() { 1558 if (mThreadPool) { 1559 wr_thread_pool_delete(mThreadPool); 1560 mThreadPool = nullptr; 1561 } 1562 } 1563 1564 MaybeWebRenderGlyphRasterThread::MaybeWebRenderGlyphRasterThread(bool aEnable) { 1565 if (aEnable) { 1566 mThread = wr_glyph_raster_thread_new(); 1567 } else { 1568 mThread = nullptr; 1569 } 1570 } 1571 1572 MaybeWebRenderGlyphRasterThread::~MaybeWebRenderGlyphRasterThread() { 1573 if (mThread) { 1574 wr_glyph_raster_thread_delete(mThread); 1575 } 1576 } 1577 1578 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) { 1579 MOZ_ASSERT(aThreadPool); 1580 1581 nsAutoString path; 1582 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) { 1583 path.Append(gfx::gfxVars::ProfDirectory()); 1584 } 1585 mProgramCache = wr_program_cache_new(&path, aThreadPool); 1586 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) { 1587 wr_try_load_startup_shaders_from_disk(mProgramCache); 1588 } 1589 } 1590 1591 WebRenderProgramCache::~WebRenderProgramCache() { 1592 wr_program_cache_delete(mProgramCache); 1593 } 1594 1595 } // namespace mozilla::wr 1596 1597 #ifdef XP_WIN 1598 static already_AddRefed<gl::GLContext> CreateGLContextANGLE( 1599 nsACString& aError) { 1600 const RefPtr<ID3D11Device> d3d11Device = 1601 gfx::DeviceManagerDx::Get()->GetCompositorDevice(); 1602 if (!d3d11Device) { 1603 aError.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns); 1604 return nullptr; 1605 } 1606 1607 nsCString failureId; 1608 const auto lib = gl::GLLibraryEGL::Get(&failureId); 1609 if (!lib) { 1610 aError.Assign( 1611 nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get())); 1612 return nullptr; 1613 } 1614 1615 const auto egl = lib->CreateDisplay(d3d11Device.get()); 1616 if (!egl) { 1617 aError.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)", 1618 failureId.get())); 1619 return nullptr; 1620 } 1621 1622 gl::CreateContextFlags flags = gl::CreateContextFlags::PREFER_ES3; 1623 1624 if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) { 1625 flags |= gl::CreateContextFlags::PREFER_ROBUSTNESS; 1626 } 1627 1628 if (egl->IsExtensionSupported( 1629 gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) { 1630 flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE; 1631 } 1632 1633 // Create GLContext with dummy EGLSurface, the EGLSurface is not used. 1634 // Instread we override it with EGLSurface of SwapChain's back buffer. 1635 1636 auto gl = gl::GLContextEGL::CreateWithoutSurface(egl, {flags}, &failureId); 1637 if (!gl || !gl->IsANGLE()) { 1638 aError.Assign(nsPrintfCString("RcANGLE(create GL context failed: %p, %s)", 1639 gl.get(), failureId.get())); 1640 return nullptr; 1641 } 1642 1643 if (!gl->MakeCurrent()) { 1644 aError.Assign( 1645 nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)", 1646 gl.get(), gl->mEgl->mLib->fGetError())); 1647 return nullptr; 1648 } 1649 1650 return gl.forget(); 1651 } 1652 #endif 1653 1654 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK) 1655 static already_AddRefed<gl::GLContext> CreateGLContextEGL() { 1656 // Create GLContext with dummy EGLSurface. 1657 bool forHardwareWebRender = true; 1658 // SW-WR uses CompositorOGL in native compositor. 1659 if (gfx::gfxVars::UseSoftwareWebRender()) { 1660 forHardwareWebRender = false; 1661 } 1662 RefPtr<gl::GLContext> gl = 1663 gl::GLContextProviderEGL::CreateForCompositorWidget( 1664 nullptr, forHardwareWebRender, /* aForceAccelerated */ true); 1665 if (!gl || !gl->MakeCurrent()) { 1666 gfxCriticalNote << "Failed GL context creation for hardware WebRender: " 1667 << forHardwareWebRender; 1668 return nullptr; 1669 } 1670 return gl.forget(); 1671 } 1672 #endif 1673 1674 #ifdef XP_DARWIN 1675 static already_AddRefed<gl::GLContext> CreateGLContextCGL() { 1676 nsCString failureUnused; 1677 return gl::GLContextProvider::CreateHeadless( 1678 {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER | 1679 gl::CreateContextFlags::FORBID_SOFTWARE}, 1680 &failureUnused); 1681 } 1682 #endif 1683 1684 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) { 1685 RefPtr<gl::GLContext> gl; 1686 1687 #ifdef XP_WIN 1688 if (gfx::gfxVars::UseWebRenderANGLE()) { 1689 gl = CreateGLContextANGLE(aError); 1690 } 1691 #elif defined(MOZ_WIDGET_ANDROID) 1692 gl = CreateGLContextEGL(); 1693 #elif defined(MOZ_WIDGET_GTK) 1694 if (gfx::gfxVars::UseEGL()) { 1695 gl = CreateGLContextEGL(); 1696 } 1697 #elif XP_DARWIN 1698 gl = CreateGLContextCGL(); 1699 #endif 1700 1701 wr::RenderThread::MaybeEnableGLDebugMessage(gl); 1702 1703 return gl.forget(); 1704 } 1705 1706 extern "C" { 1707 1708 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId, 1709 bool aCompositeNeeded) { 1710 // wake_up is used for things like propagating debug options or memory 1711 // pressure events, so we are not tracking pending frame counts. 1712 mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId, 1713 aCompositeNeeded); 1714 } 1715 1716 void wr_notifier_new_frame_ready(wr::WrWindowId aWindowId, 1717 wr::FramePublishId aPublishId, 1718 const wr::FrameReadyParams* aParams) { 1719 auto* renderThread = mozilla::wr::RenderThread::Get(); 1720 if (aParams->tracked) { 1721 renderThread->DecPendingFrameBuildCount(aWindowId); 1722 } 1723 1724 renderThread->WrNotifierEvent_NewFrameReady(aWindowId, aPublishId, aParams); 1725 } 1726 1727 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId, 1728 size_t aRawEvent) { 1729 mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent( 1730 mozilla::wr::WindowId(aWindowId), aRawEvent); 1731 } 1732 1733 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId, 1734 wr::RenderReasons aReasons) { 1735 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers:: 1736 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId); 1737 if (cbp) { 1738 cbp->ScheduleComposition(aReasons); 1739 } 1740 } 1741 1742 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId, 1743 wr::RenderReasons aReasons) { 1744 layers::CompositorThread()->Dispatch(NewRunnableFunction( 1745 "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons)); 1746 } 1747 1748 static void ScheduleFrameAfterSceneBuild( 1749 mozilla::wr::WrWindowId aWindowId, 1750 const RefPtr<const wr::WebRenderPipelineInfo>& aInfo) { 1751 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers:: 1752 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId); 1753 if (cbp) { 1754 cbp->ScheduleFrameAfterSceneBuild(aInfo); 1755 } 1756 } 1757 1758 void wr_schedule_frame_after_scene_build( 1759 mozilla::wr::WrWindowId aWindowId, 1760 mozilla::wr::WrPipelineInfo* aPipelineInfo) { 1761 RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo(); 1762 info->Raw() = std::move(*aPipelineInfo); 1763 layers::CompositorThread()->Dispatch( 1764 NewRunnableFunction("ScheduleFrameAfterSceneBuild", 1765 &ScheduleFrameAfterSceneBuild, aWindowId, info)); 1766 } 1767 1768 } // extern C