Bug 1833753 [wpt PR 40065] - Allow newly-added test to also pass when mutation events...
[gecko.git] / gfx / webrender_bindings / RenderThread.cpp
blobdc5914da12177dca331c7eaafab88a9703ece7e6
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/. */
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/GleanMetrics.h"
21 #include "mozilla/layers/CompositorThread.h"
22 #include "mozilla/layers/CompositorBridgeParent.h"
23 #include "mozilla/layers/CompositorManagerParent.h"
24 #include "mozilla/layers/WebRenderBridgeParent.h"
25 #include "mozilla/layers/SharedSurfacesParent.h"
26 #include "mozilla/layers/SurfacePool.h"
27 #include "mozilla/layers/SynchronousTask.h"
28 #include "mozilla/PerfStats.h"
29 #include "mozilla/StaticPtr.h"
30 #include "mozilla/Telemetry.h"
31 #include "mozilla/webrender/RendererOGL.h"
32 #include "mozilla/webrender/RenderTextureHost.h"
33 #include "mozilla/widget/CompositorWidget.h"
34 #include "OGLShaderProgram.h"
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
46 #ifdef MOZ_WIDGET_ANDROID
47 # include "GLLibraryEGL.h"
48 # include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h"
49 #endif
51 #ifdef MOZ_WIDGET_GTK
52 # include "mozilla/WidgetUtilsGtk.h"
53 #endif
55 #ifdef MOZ_WAYLAND
56 # include "GLLibraryEGL.h"
57 #endif
59 using namespace mozilla;
61 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError);
63 MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderRendererMallocSizeOf)
65 namespace mozilla::wr {
67 LazyLogModule gRenderThreadLog("RenderThread");
68 // Should be called only on RenderThread, since LazyLogModule is not thread safe
69 #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
71 static StaticRefPtr<RenderThread> sRenderThread;
72 static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor;
73 #ifdef DEBUG
74 static bool sRenderThreadEverStarted = false;
75 #endif
77 RenderThread::RenderThread(RefPtr<nsIThread> aThread)
78 : mThread(std::move(aThread)),
79 mThreadPool(false),
80 mThreadPoolLP(true),
81 mSingletonGLIsForHardwareWebRender(true),
82 mWindowInfos("RenderThread.mWindowInfos"),
83 mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
84 mHasShutdown(false),
85 mHandlingDeviceReset(false),
86 mHandlingWebRenderError(false) {}
88 RenderThread::~RenderThread() { MOZ_ASSERT(mRenderTexturesDeferred.empty()); }
90 // static
91 RenderThread* RenderThread::Get() { return sRenderThread; }
93 // static
94 void RenderThread::Start(uint32_t aNamespace) {
95 MOZ_ASSERT(NS_IsMainThread());
96 MOZ_ASSERT(!sRenderThread);
98 #ifdef DEBUG
99 // Check to ensure nobody will try to ever start us more than once during
100 // the process' lifetime (in particular after ShutDown).
101 MOZ_ASSERT(!sRenderThreadEverStarted);
102 sRenderThreadEverStarted = true;
103 #endif
105 // When the CanvasRenderer thread is disabled, WebGL may be handled on this
106 // thread, requiring a bigger stack size. See: CanvasManagerParent::Init
108 // This is 4M, which is higher than the default 256K.
109 // Increased with bug 1753349 to accommodate the `chromium/5359` branch of
110 // ANGLE, which has large peak stack usage for some pathological shader
111 // compilations.
113 // Previously increased to 512K to accommodate Mesa in bug 1753340.
115 // Previously increased to 320K to avoid a stack overflow in the
116 // Intel Vulkan driver initialization in bug 1716120.
118 // Note: we only override it if it's limited already.
119 uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE;
120 if (stackSize && !gfx::gfxVars::SupportsThreadsafeGL()) {
121 stackSize = std::max(stackSize, 4096U << 10);
124 RefPtr<nsIThread> thread;
125 nsresult rv = NS_NewNamedThread(
126 "Renderer", getter_AddRefs(thread),
127 NS_NewRunnableFunction(
128 "Renderer::BackgroundHanSetup",
129 []() {
130 sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor(
131 "Render",
132 /* Timeout values are powers-of-two to enable us get better
133 data. 128ms is chosen for transient hangs because 8Hz should
134 be the minimally acceptable goal for Render
135 responsiveness (normal goal is 60Hz). */
136 128,
137 /* 2048ms is chosen for permanent hangs because it's longer than
138 * most Render hangs seen in the wild, but is short enough
139 * to not miss getting native hang stacks. */
140 2048);
141 nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
142 nsThread* nsthread = static_cast<nsThread*>(thread.get());
143 nsthread->SetUseHangMonitor(true);
144 nsthread->SetPriority(nsISupportsPriority::PRIORITY_HIGH);
146 {.stackSize = stackSize});
148 if (NS_FAILED(rv)) {
149 gfxCriticalNote << "Failed to create Renderer thread: "
150 << gfx::hexa((uint32_t)rv);
151 return;
154 sRenderThread = new RenderThread(thread);
155 #ifdef XP_WIN
156 widget::WinCompositorWindowThread::Start();
157 #endif
158 layers::SharedSurfacesParent::Initialize();
160 RefPtr<Runnable> runnable = WrapRunnable(
161 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::InitDeviceTask);
162 sRenderThread->PostRunnable(runnable.forget());
165 // static
166 void RenderThread::ShutDown() {
167 MOZ_ASSERT(NS_IsMainThread());
168 MOZ_ASSERT(sRenderThread);
171 MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
172 sRenderThread->mHasShutdown = true;
175 RefPtr<Runnable> runnable = WrapRunnable(
176 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::ShutDownTask);
177 sRenderThread->PostRunnable(runnable.forget());
179 // This will empty the thread queue and thus run the above runnable while
180 // spinning the MT event loop.
181 nsCOMPtr<nsIThread> oldThread = sRenderThread->GetRenderThread();
182 oldThread->Shutdown();
184 layers::SharedSurfacesParent::Shutdown();
186 #ifdef XP_WIN
187 if (widget::WinCompositorWindowThread::Get()) {
188 widget::WinCompositorWindowThread::ShutDown();
190 #endif
192 // We null this out only after we finished shutdown to give everbody the
193 // chance to check for sRenderThread->mHasShutdown. Hopefully everybody
194 // checks this before using us!
195 sRenderThread = nullptr;
198 extern void ClearAllBlobImageResources();
200 void RenderThread::ShutDownTask() {
201 MOZ_ASSERT(IsInRenderThread());
202 LOG("RenderThread::ShutDownTask()");
205 // Clear RenderTextureHosts
206 MutexAutoLock lock(mRenderTextureMapLock);
207 mRenderTexturesDeferred.clear();
208 mRenderTextures.clear();
209 mSyncObjectNeededRenderTextures.clear();
210 mRenderTextureOps.clear();
213 // Let go of our handle to the (internally ref-counted) thread pool.
214 mThreadPool.Release();
215 mThreadPoolLP.Release();
217 // Releasing on the render thread will allow us to avoid dispatching to remove
218 // remaining textures from the texture map.
219 layers::SharedSurfacesParent::ShutdownRenderThread();
221 #ifdef XP_WIN
222 DCLayerTree::Shutdown();
223 #endif
225 ClearAllBlobImageResources();
226 ClearSingletonGL();
227 ClearSharedSurfacePool();
230 // static
231 bool RenderThread::IsInRenderThread() {
232 return sRenderThread && sRenderThread->mThread == NS_GetCurrentThread();
235 // static
236 already_AddRefed<nsIThread> RenderThread::GetRenderThread() {
237 nsCOMPtr<nsIThread> thread;
238 if (sRenderThread) {
239 thread = sRenderThread->mThread;
241 return thread.forget();
244 void RenderThread::DoAccumulateMemoryReport(
245 MemoryReport aReport,
246 const RefPtr<MemoryReportPromise::Private>& aPromise) {
247 MOZ_ASSERT(IsInRenderThread());
249 for (auto& r : mRenderers) {
250 r.second->AccumulateMemoryReport(&aReport);
253 // Note memory used by the shader cache, which is shared across all WR
254 // instances.
255 MOZ_ASSERT(aReport.shader_cache == 0);
256 if (mProgramCache) {
257 aReport.shader_cache = wr_program_cache_report_memory(
258 mProgramCache->Raw(), &WebRenderRendererMallocSizeOf);
261 size_t renderTextureMemory = 0;
263 MutexAutoLock lock(mRenderTextureMapLock);
264 for (const auto& entry : mRenderTextures) {
265 renderTextureMemory += entry.second->Bytes();
268 aReport.render_texture_hosts = renderTextureMemory;
270 aPromise->Resolve(aReport, __func__);
273 // static
274 RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport(
275 MemoryReport aInitial) {
276 RefPtr<MemoryReportPromise::Private> p =
277 new MemoryReportPromise::Private(__func__);
278 MOZ_ASSERT(!IsInRenderThread());
279 if (!Get()) {
280 // This happens when the GPU process fails to start and we fall back to the
281 // basic compositor in the parent process. We could assert against this if
282 // we made the webrender detection code in gfxPlatform.cpp smarter. See bug
283 // 1494430 comment 12.
284 NS_WARNING("No render thread, returning empty memory report");
285 p->Resolve(aInitial, __func__);
286 return p;
289 Get()->PostRunnable(
290 NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>(
291 "wr::RenderThread::DoAccumulateMemoryReport", Get(),
292 &RenderThread::DoAccumulateMemoryReport, aInitial, p));
294 return p;
297 void RenderThread::AddRenderer(wr::WindowId aWindowId,
298 UniquePtr<RendererOGL> aRenderer) {
299 MOZ_ASSERT(IsInRenderThread());
300 LOG("RenderThread::AddRenderer() aWindowId %" PRIx64 "", AsUint64(aWindowId));
302 if (mHasShutdown) {
303 return;
306 mRenderers[aWindowId] = std::move(aRenderer);
307 CrashReporter::AnnotateCrashReport(
308 CrashReporter::Annotation::GraphicsNumRenderers,
309 (unsigned int)mRenderers.size());
311 auto windows = mWindowInfos.Lock();
312 windows->emplace(AsUint64(aWindowId), new WindowInfo());
313 mWrNotifierEventsQueues.emplace(AsUint64(aWindowId),
314 new std::queue<WrNotifierEvent>);
317 void RenderThread::RemoveRenderer(wr::WindowId aWindowId) {
318 MOZ_ASSERT(IsInRenderThread());
319 LOG("RenderThread::RemoveRenderer() aWindowId %" PRIx64 "",
320 AsUint64(aWindowId));
322 if (mHasShutdown) {
323 return;
326 mRenderers.erase(aWindowId);
327 CrashReporter::AnnotateCrashReport(
328 CrashReporter::Annotation::GraphicsNumRenderers,
329 (unsigned int)mRenderers.size());
331 if (mRenderers.empty()) {
332 if (mHandlingDeviceReset) {
333 ClearSingletonGL();
335 mHandlingDeviceReset = false;
336 mHandlingWebRenderError = false;
339 auto windows = mWindowInfos.Lock();
340 auto it = windows->find(AsUint64(aWindowId));
341 MOZ_ASSERT(it != windows->end());
342 windows->erase(it);
344 // Defer std::deque<WrNotifierEvent> remove, RemoveRenderer() is called in
345 // HandleWrNotifierEvents().
346 RefPtr<Runnable> runnable =
347 NS_NewRunnableFunction("RenderThread::RemoveRenderer", [aWindowId]() {
348 auto* self = RenderThread::Get();
349 auto it = self->mWrNotifierEventsQueues.find(AsUint64(aWindowId));
350 if (it == self->mWrNotifierEventsQueues.end()) {
351 return;
353 self->mWrNotifierEventsQueues.erase(it);
355 RenderThread::Get()->PostRunnable(runnable.forget());
358 RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) {
359 MOZ_ASSERT(IsInRenderThread());
361 auto it = mRenderers.find(aWindowId);
362 MOZ_ASSERT(it != mRenderers.end());
364 if (it == mRenderers.end()) {
365 return nullptr;
368 return it->second.get();
371 size_t RenderThread::RendererCount() const {
372 MOZ_ASSERT(IsInRenderThread());
373 return mRenderers.size();
376 size_t RenderThread::ActiveRendererCount() const {
377 MOZ_ASSERT(IsInRenderThread());
378 size_t num_active = 0;
379 for (const auto& it : mRenderers) {
380 if (!it.second->IsPaused()) {
381 num_active++;
384 return num_active;
387 void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId,
388 bool aCompositeNeeded) {
389 auto windows = mWindowInfos.Lock();
390 auto it = windows->find(AsUint64(aWindowId));
391 if (it == windows->end()) {
392 MOZ_ASSERT(false);
393 return;
396 WindowInfo* info = it->second.get();
398 info->mPendingWrNotifierEvents.emplace(
399 WrNotifierEvent::WakeUp(aCompositeNeeded));
400 PostWrNotifierEvents(aWindowId, info);
403 void RenderThread::WrNotifierEvent_NewFrameReady(WrWindowId aWindowId,
404 bool aCompositeNeeded,
405 FramePublishId aPublishId) {
406 auto windows = mWindowInfos.Lock();
407 auto it = windows->find(AsUint64(aWindowId));
408 if (it == windows->end()) {
409 MOZ_ASSERT(false);
410 return;
412 WindowInfo* info = it->second.get();
414 info->mPendingWrNotifierEvents.emplace(
415 WrNotifierEvent::NewFrameReady(aCompositeNeeded, aPublishId));
416 PostWrNotifierEvents(aWindowId, info);
419 void RenderThread::WrNotifierEvent_ExternalEvent(WrWindowId aWindowId,
420 size_t aRawEvent) {
421 UniquePtr<RendererEvent> evt(reinterpret_cast<RendererEvent*>(aRawEvent));
423 auto windows = mWindowInfos.Lock();
424 auto it = windows->find(AsUint64(aWindowId));
425 if (it == windows->end()) {
426 MOZ_ASSERT(false);
427 return;
429 WindowInfo* info = it->second.get();
431 info->mPendingWrNotifierEvents.emplace(
432 WrNotifierEvent::ExternalEvent(std::move(evt)));
433 PostWrNotifierEvents(aWindowId, info);
437 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId) {
439 auto windows = mWindowInfos.Lock();
440 auto it = windows->find(AsUint64(aWindowId));
441 if (it == windows->end()) {
442 MOZ_ASSERT(false);
443 return;
445 WindowInfo* info = it->second.get();
446 PostWrNotifierEvents(aWindowId, info);
450 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId,
451 WindowInfo* aInfo) {
452 // Runnable has already been triggered.
453 if (aInfo->mWrNotifierEventsRunnable) {
454 return;
457 // Runnable has not been triggered yet.
458 RefPtr<nsIRunnable> runnable = NewRunnableMethod<WrWindowId>(
459 "RenderThread::HandleWrNotifierEvents", this,
460 &RenderThread::HandleWrNotifierEvents, aWindowId);
461 aInfo->mWrNotifierEventsRunnable = runnable;
462 PostRunnable(runnable.forget());
465 void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId) {
466 MOZ_ASSERT(IsInRenderThread());
468 auto eventsIt = mWrNotifierEventsQueues.find(AsUint64(aWindowId));
469 if (eventsIt == mWrNotifierEventsQueues.end()) {
470 return;
472 auto* events = eventsIt->second.get();
475 auto windows = mWindowInfos.Lock();
476 auto infoIt = windows->find(AsUint64(aWindowId));
477 if (infoIt == windows->end()) {
478 MOZ_ASSERT(false);
479 return;
481 WindowInfo* info = infoIt->second.get();
482 info->mWrNotifierEventsRunnable = nullptr;
484 if (events->empty() && !info->mPendingWrNotifierEvents.empty()) {
485 events->swap(info->mPendingWrNotifierEvents);
489 bool handleNext = true;
491 while (!events->empty() && handleNext) {
492 auto& front = events->front();
493 switch (front.mTag) {
494 case WrNotifierEvent::Tag::WakeUp:
495 WrNotifierEvent_HandleWakeUp(aWindowId, front.CompositeNeeded());
496 handleNext = false;
497 break;
498 case WrNotifierEvent::Tag::NewFrameReady:
499 WrNotifierEvent_HandleNewFrameReady(aWindowId, front.CompositeNeeded(),
500 front.PublishId());
501 handleNext = false;
502 break;
503 case WrNotifierEvent::Tag::ExternalEvent:
504 WrNotifierEvent_HandleExternalEvent(aWindowId, front.ExternalEvent());
505 break;
507 events->pop();
511 auto windows = mWindowInfos.Lock();
512 auto it = windows->find(AsUint64(aWindowId));
513 if (it == windows->end()) {
514 return;
516 WindowInfo* info = it->second.get();
518 if (!events->empty() || !info->mPendingWrNotifierEvents.empty()) {
519 PostWrNotifierEvents(aWindowId, info);
524 void RenderThread::WrNotifierEvent_HandleWakeUp(wr::WindowId aWindowId,
525 bool aCompositeNeeded) {
526 MOZ_ASSERT(IsInRenderThread());
528 bool isTrackedFrame = false;
529 HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame, Nothing());
532 void RenderThread::WrNotifierEvent_HandleNewFrameReady(
533 wr::WindowId aWindowId, bool aCompositeNeeded, FramePublishId aPublishId) {
534 MOZ_ASSERT(IsInRenderThread());
536 bool isTrackedFrame = true;
537 HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame,
538 Some(aPublishId));
541 void RenderThread::WrNotifierEvent_HandleExternalEvent(
542 wr::WindowId aWindowId, UniquePtr<RendererEvent> aRendererEvent) {
543 MOZ_ASSERT(IsInRenderThread());
545 RunEvent(aWindowId, std::move(aRendererEvent));
548 void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId,
549 const TimeStamp& aRecordingStart,
550 wr::PipelineId aRootPipelineId) {
551 MOZ_ASSERT(IsInRenderThread());
552 RendererOGL* renderer = GetRenderer(aWindowId);
553 MOZ_ASSERT(renderer);
555 renderer->BeginRecording(aRecordingStart, aRootPipelineId);
558 Maybe<layers::FrameRecording> RenderThread::EndRecordingForWindow(
559 wr::WindowId aWindowId) {
560 MOZ_ASSERT(IsInRenderThread());
562 RendererOGL* renderer = GetRenderer(aWindowId);
563 MOZ_ASSERT(renderer);
564 return renderer->EndRecording();
567 void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender,
568 bool aTrackedFrame,
569 Maybe<FramePublishId> aPublishId) {
570 MOZ_ASSERT(IsInRenderThread());
572 if (mHasShutdown) {
573 return;
576 HandleFrameOneDocInner(aWindowId, aRender, aTrackedFrame, aPublishId);
578 if (aTrackedFrame) {
579 DecPendingFrameCount(aWindowId);
583 void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId, bool aRender,
584 bool aTrackedFrame,
585 Maybe<FramePublishId> aPublishId) {
586 if (IsDestroyed(aWindowId)) {
587 return;
590 if (mHandlingDeviceReset) {
591 return;
594 bool render = aRender;
595 PendingFrameInfo frame;
596 if (aTrackedFrame) {
597 // scope lock
598 auto windows = mWindowInfos.Lock();
599 auto it = windows->find(AsUint64(aWindowId));
600 if (it == windows->end()) {
601 MOZ_ASSERT(false);
602 return;
605 WindowInfo* info = it->second.get();
606 PendingFrameInfo& frameInfo = info->mPendingFrames.front();
607 frameInfo.mFrameNeedsRender |= aRender;
608 render = frameInfo.mFrameNeedsRender;
610 frame = frameInfo;
611 } else {
612 // Just give the frame info default values.
613 frame = {TimeStamp::Now(), VsyncId(), aRender};
616 // Sadly this doesn't include the lock, since we don't have the frame there
617 // yet.
618 glean::wr::time_to_render_start.AccumulateRawDuration(TimeStamp::Now() -
619 frame.mStartTime);
621 // It is for ensuring that PrepareForUse() is called before
622 // RenderTextureHost::Lock().
623 HandleRenderTextureOps();
625 if (aPublishId.isSome()) {
626 SetFramePublishId(aWindowId, aPublishId.ref());
629 UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, render,
630 /* aReadbackSize */ Nothing(),
631 /* aReadbackFormat */ Nothing(),
632 /* aReadbackBuffer */ Nothing());
634 // The start time is from WebRenderBridgeParent::CompositeToTarget. From that
635 // point until now (when the frame is finally pushed to the screen) is
636 // equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
637 TimeDuration compositeDuration = TimeStamp::Now() - frame.mStartTime;
638 mozilla::Telemetry::Accumulate(mozilla::Telemetry::COMPOSITE_TIME,
639 uint32_t(compositeDuration.ToMilliseconds()));
640 PerfStats::RecordMeasurement(PerfStats::Metric::Compositing,
641 compositeDuration);
644 void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) {
645 if (mHasShutdown) {
646 return;
649 if (!IsInRenderThread()) {
650 PostRunnable(NewRunnableMethod<wr::WindowId, wr::ColorF>(
651 "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor,
652 aWindowId, aColor));
653 return;
656 if (IsDestroyed(aWindowId)) {
657 return;
660 auto it = mRenderers.find(aWindowId);
661 MOZ_ASSERT(it != mRenderers.end());
662 if (it != mRenderers.end()) {
663 wr_renderer_set_clear_color(it->second->GetRenderer(), aColor);
667 void RenderThread::SetProfilerUI(wr::WindowId aWindowId,
668 const nsACString& aUI) {
669 if (mHasShutdown) {
670 return;
673 if (!IsInRenderThread()) {
674 PostRunnable(NewRunnableMethod<wr::WindowId, nsCString>(
675 "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI,
676 aWindowId, nsCString(aUI)));
677 return;
680 auto it = mRenderers.find(aWindowId);
681 if (it != mRenderers.end()) {
682 it->second->SetProfilerUI(aUI);
686 void RenderThread::PostEvent(wr::WindowId aWindowId,
687 UniquePtr<RendererEvent> aEvent) {
688 PostRunnable(NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
689 "wr::RenderThread::PostEvent", this, &RenderThread::RunEvent, aWindowId,
690 std::move(aEvent)));
693 void RenderThread::RunEvent(wr::WindowId aWindowId,
694 UniquePtr<RendererEvent> aEvent) {
695 MOZ_ASSERT(IsInRenderThread());
697 aEvent->Run(*this, aWindowId);
698 aEvent = nullptr;
701 static void NotifyDidRender(layers::CompositorBridgeParent* aBridge,
702 const RefPtr<const WebRenderPipelineInfo>& aInfo,
703 VsyncId aCompositeStartId,
704 TimeStamp aCompositeStart, TimeStamp aRenderStart,
705 TimeStamp aEnd, bool aRender,
706 RendererStats aStats) {
707 if (aRender && aBridge->GetWrBridge()) {
708 // We call this here to mimic the behavior in LayerManagerComposite, as to
709 // not change what Talos measures. That is, we do not record an empty frame
710 // as a frame.
711 aBridge->GetWrBridge()->RecordFrame();
714 aBridge->NotifyDidRender(aCompositeStartId, aCompositeStart, aRenderStart,
715 aEnd, &aStats);
717 for (const auto& epoch : aInfo->Raw().epochs) {
718 aBridge->NotifyPipelineRendered(epoch.pipeline_id, epoch.epoch,
719 aCompositeStartId, aCompositeStart,
720 aRenderStart, aEnd, &aStats);
723 if (aBridge->GetWrBridge()) {
724 aBridge->GetWrBridge()->RetrySkippedComposite();
728 static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) {
729 if (aBridge->GetWrBridge()) {
730 aBridge->GetWrBridge()->RetrySkippedComposite();
734 void RenderThread::SetFramePublishId(wr::WindowId aWindowId,
735 FramePublishId aPublishId) {
736 MOZ_ASSERT(IsInRenderThread());
738 auto it = mRenderers.find(aWindowId);
739 MOZ_ASSERT(it != mRenderers.end());
740 if (it == mRenderers.end()) {
741 return;
743 auto& renderer = it->second;
745 renderer->SetFramePublishId(aPublishId);
748 void RenderThread::UpdateAndRender(
749 wr::WindowId aWindowId, const VsyncId& aStartId,
750 const TimeStamp& aStartTime, bool aRender,
751 const Maybe<gfx::IntSize>& aReadbackSize,
752 const Maybe<wr::ImageFormat>& aReadbackFormat,
753 const Maybe<Range<uint8_t>>& aReadbackBuffer, bool* aNeedsYFlip) {
754 AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS);
755 MOZ_ASSERT(IsInRenderThread());
756 MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
758 auto it = mRenderers.find(aWindowId);
759 MOZ_ASSERT(it != mRenderers.end());
760 if (it == mRenderers.end()) {
761 return;
764 TimeStamp start = TimeStamp::Now();
766 auto& renderer = it->second;
768 std::string markerName = "Composite #" + std::to_string(AsUint64(aWindowId));
769 AutoProfilerTracing tracingCompositeMarker(
770 "Paint", markerName.c_str(), geckoprofiler::category::GRAPHICS,
771 Some(renderer->GetCompositorBridge()->GetInnerWindowId()));
773 if (renderer->IsPaused()) {
774 aRender = false;
776 LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64 " aRender %d",
777 AsUint64(aWindowId), aRender);
779 layers::CompositorThread()->Dispatch(
780 NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender,
781 renderer->GetCompositorBridge()));
783 wr::RenderedFrameId latestFrameId;
784 RendererStats stats = {0};
785 if (aRender) {
786 latestFrameId = renderer->UpdateAndRender(
787 aReadbackSize, aReadbackFormat, aReadbackBuffer, aNeedsYFlip, &stats);
788 } else {
789 renderer->Update();
791 // Check graphics reset status even when rendering is skipped.
792 renderer->CheckGraphicsResetStatus("PostUpdate", /* aForce */ false);
794 TimeStamp end = TimeStamp::Now();
795 RefPtr<const WebRenderPipelineInfo> info = renderer->GetLastPipelineInfo();
797 layers::CompositorThread()->Dispatch(
798 NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
799 renderer->GetCompositorBridge(), info, aStartId,
800 aStartTime, start, end, aRender, stats));
802 ipc::FileDescriptor fenceFd;
804 if (latestFrameId.IsValid()) {
805 fenceFd = renderer->GetAndResetReleaseFence();
807 // Wait for GPU after posting NotifyDidRender, since the wait is not
808 // necessary for the NotifyDidRender.
809 // The wait is necessary for Textures recycling of AsyncImagePipelineManager
810 // and for avoiding GPU queue is filled with too much tasks.
811 // WaitForGPU's implementation is different for each platform.
812 auto timerId = glean::wr::gpu_wait_time.Start();
813 renderer->WaitForGPU();
814 glean::wr::gpu_wait_time.StopAndAccumulate(std::move(timerId));
815 } else {
816 // Update frame id for NotifyPipelinesUpdated() when rendering does not
817 // happen, either because rendering was not requested or the frame was
818 // canceled. Rendering can sometimes be canceled if UpdateAndRender is
819 // called when the window is not yet ready (not mapped or 0 size).
820 latestFrameId = renderer->UpdateFrameId();
823 RenderedFrameId lastCompletedFrameId = renderer->GetLastCompletedFrameId();
825 RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
826 renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
827 // pipelineMgr should always be non-null here because it is only nulled out
828 // after the WebRenderAPI instance for the CompositorBridgeParent is
829 // destroyed, and that destruction blocks until the renderer thread has
830 // removed the relevant renderer. And after that happens we should never reach
831 // this code at all; it would bail out at the mRenderers.find check above.
832 MOZ_ASSERT(pipelineMgr);
833 pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId,
834 std::move(fenceFd));
837 void RenderThread::Pause(wr::WindowId aWindowId) {
838 MOZ_ASSERT(IsInRenderThread());
839 LOG("RenderThread::Pause() aWindowId %" PRIx64 "", AsUint64(aWindowId));
841 auto it = mRenderers.find(aWindowId);
842 MOZ_ASSERT(it != mRenderers.end());
843 if (it == mRenderers.end()) {
844 gfxCriticalNote << "RenderThread cannot find renderer for window "
845 << gfx::hexa(aWindowId) << " to pause.";
846 return;
848 auto& renderer = it->second;
849 renderer->Pause();
851 CrashReporter::AnnotateCrashReport(
852 CrashReporter::Annotation::GraphicsNumActiveRenderers,
853 (unsigned int)ActiveRendererCount());
856 bool RenderThread::Resume(wr::WindowId aWindowId) {
857 MOZ_ASSERT(IsInRenderThread());
858 LOG("enderThread::Resume() aWindowId %" PRIx64 "", AsUint64(aWindowId));
860 auto it = mRenderers.find(aWindowId);
861 MOZ_ASSERT(it != mRenderers.end());
862 if (it == mRenderers.end()) {
863 gfxCriticalNote << "RenderThread cannot find renderer for window "
864 << gfx::hexa(aWindowId) << " to resume.";
865 return false;
867 auto& renderer = it->second;
868 bool resumed = renderer->Resume();
870 CrashReporter::AnnotateCrashReport(
871 CrashReporter::Annotation::GraphicsNumActiveRenderers,
872 (unsigned int)ActiveRendererCount());
874 return resumed;
877 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) {
878 const int64_t maxFrameCount = 1;
880 // Too many pending frames if pending frames exit more than maxFrameCount
881 // or if RenderBackend is still processing a frame.
883 auto windows = mWindowInfos.Lock();
884 auto it = windows->find(AsUint64(aWindowId));
885 if (it == windows->end()) {
886 MOZ_ASSERT(false);
887 return true;
889 WindowInfo* info = it->second.get();
891 if (info->PendingCount() > maxFrameCount) {
892 return true;
894 // If there is no ongoing frame build, we accept a new frame.
895 return info->mPendingFrameBuild > 0;
898 bool RenderThread::IsDestroyed(wr::WindowId aWindowId) {
899 auto windows = mWindowInfos.Lock();
900 auto it = windows->find(AsUint64(aWindowId));
901 if (it == windows->end()) {
902 return true;
905 return it->second->mIsDestroyed;
908 void RenderThread::SetDestroyed(wr::WindowId aWindowId) {
909 auto windows = mWindowInfos.Lock();
910 auto it = windows->find(AsUint64(aWindowId));
911 if (it == windows->end()) {
912 MOZ_ASSERT(false);
913 return;
915 it->second->mIsDestroyed = true;
918 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId,
919 const VsyncId& aStartId,
920 const TimeStamp& aStartTime) {
921 auto windows = mWindowInfos.Lock();
922 auto it = windows->find(AsUint64(aWindowId));
923 if (it == windows->end()) {
924 MOZ_ASSERT(false);
925 return;
927 it->second->mPendingFrameBuild++;
928 it->second->mPendingFrames.push(
929 PendingFrameInfo{aStartTime, aStartId, false});
932 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId) {
933 auto windows = mWindowInfos.Lock();
934 auto it = windows->find(AsUint64(aWindowId));
935 if (it == windows->end()) {
936 MOZ_ASSERT(false);
937 return;
939 WindowInfo* info = it->second.get();
940 MOZ_RELEASE_ASSERT(info->mPendingFrameBuild >= 1);
941 info->mPendingFrameBuild--;
944 void RenderThread::DecPendingFrameCount(wr::WindowId aWindowId) {
945 auto windows = mWindowInfos.Lock();
946 auto it = windows->find(AsUint64(aWindowId));
947 if (it == windows->end()) {
948 MOZ_ASSERT(false);
949 return;
951 WindowInfo* info = it->second.get();
952 info->mPendingFrames.pop();
955 void RenderThread::RegisterExternalImage(
956 const wr::ExternalImageId& aExternalImageId,
957 already_AddRefed<RenderTextureHost> aTexture) {
958 MutexAutoLock lock(mRenderTextureMapLock);
960 if (mHasShutdown) {
961 return;
963 MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
964 RefPtr<RenderTextureHost> texture = aTexture;
965 if (texture->SyncObjectNeeded()) {
966 mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture);
968 mRenderTextures.emplace(aExternalImageId, texture);
971 void RenderThread::UnregisterExternalImage(
972 const wr::ExternalImageId& aExternalImageId) {
973 MutexAutoLock lock(mRenderTextureMapLock);
974 if (mHasShutdown) {
975 return;
977 auto it = mRenderTextures.find(aExternalImageId);
978 if (it == mRenderTextures.end()) {
979 return;
982 auto& texture = it->second;
983 if (texture->SyncObjectNeeded()) {
984 MOZ_RELEASE_ASSERT(
985 mSyncObjectNeededRenderTextures.erase(aExternalImageId) == 1);
988 if (!IsInRenderThread()) {
989 // The RenderTextureHost should be released in render thread. So, post the
990 // deletion task here.
991 // The shmem and raw buffer are owned by compositor ipc channel. It's
992 // possible that RenderTextureHost is still exist after the shmem/raw buffer
993 // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
994 // for this situation. Gecko will only release the buffer if WR doesn't need
995 // it. So, no one will access the invalid buffer in RenderTextureHost.
996 RefPtr<RenderTextureHost> texture = it->second;
997 mRenderTextures.erase(it);
998 mRenderTexturesDeferred.emplace_back(std::move(texture));
999 PostRunnable(NewRunnableMethod(
1000 "RenderThread::DeferredRenderTextureHostDestroy", this,
1001 &RenderThread::DeferredRenderTextureHostDestroy));
1002 } else {
1003 mRenderTextures.erase(it);
1007 void RenderThread::DestroyExternalImagesSyncWait(
1008 const std::vector<wr::ExternalImageId>&& aIds) {
1009 if (!IsInRenderThread()) {
1010 layers::SynchronousTask task("Destroy external images");
1012 RefPtr<Runnable> runnable = NS_NewRunnableFunction(
1013 "RenderThread::DestroyExternalImagesSyncWait::Runnable",
1014 [&task, ids = std::move(aIds)]() {
1015 layers::AutoCompleteTask complete(&task);
1016 RenderThread::Get()->DestroyExternalImages(std::move(ids));
1019 PostRunnable(runnable.forget());
1020 task.Wait();
1021 return;
1023 DestroyExternalImages(std::move(aIds));
1026 void RenderThread::DestroyExternalImages(
1027 const std::vector<wr::ExternalImageId>&& aIds) {
1028 MOZ_ASSERT(IsInRenderThread());
1030 std::vector<RefPtr<RenderTextureHost>> hosts;
1032 MutexAutoLock lock(mRenderTextureMapLock);
1033 if (mHasShutdown) {
1034 return;
1037 for (auto& id : aIds) {
1038 auto it = mRenderTextures.find(id);
1039 if (it == mRenderTextures.end()) {
1040 continue;
1042 hosts.emplace_back(it->second);
1046 for (auto& host : hosts) {
1047 host->Destroy();
1051 void RenderThread::PrepareForUse(const wr::ExternalImageId& aExternalImageId) {
1052 AddRenderTextureOp(RenderTextureOp::PrepareForUse, aExternalImageId);
1055 void RenderThread::NotifyNotUsed(const wr::ExternalImageId& aExternalImageId) {
1056 AddRenderTextureOp(RenderTextureOp::NotifyNotUsed, aExternalImageId);
1059 void RenderThread::NotifyForUse(const wr::ExternalImageId& aExternalImageId) {
1060 AddRenderTextureOp(RenderTextureOp::NotifyForUse, aExternalImageId);
1063 void RenderThread::AddRenderTextureOp(
1064 RenderTextureOp aOp, const wr::ExternalImageId& aExternalImageId) {
1065 MOZ_ASSERT(!IsInRenderThread());
1067 MutexAutoLock lock(mRenderTextureMapLock);
1069 auto it = mRenderTextures.find(aExternalImageId);
1070 MOZ_ASSERT(it != mRenderTextures.end());
1071 if (it == mRenderTextures.end()) {
1072 return;
1075 RefPtr<RenderTextureHost> texture = it->second;
1076 mRenderTextureOps.emplace_back(aOp, std::move(texture));
1078 if (mRenderTextureOpsRunnable) {
1079 // Runnable was already triggered
1080 return;
1083 RefPtr<nsIRunnable> runnable =
1084 NewRunnableMethod("RenderThread::HandleRenderTextureOps", this,
1085 &RenderThread::HandleRenderTextureOps);
1086 mRenderTextureOpsRunnable = runnable;
1087 PostRunnable(runnable.forget());
1090 void RenderThread::HandleRenderTextureOps() {
1091 MOZ_ASSERT(IsInRenderThread());
1093 std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>>
1094 renderTextureOps;
1096 MutexAutoLock lock(mRenderTextureMapLock);
1097 mRenderTextureOps.swap(renderTextureOps);
1098 mRenderTextureOpsRunnable = nullptr;
1101 for (auto& it : renderTextureOps) {
1102 switch (it.first) {
1103 case RenderTextureOp::PrepareForUse:
1104 it.second->PrepareForUse();
1105 break;
1106 case RenderTextureOp::NotifyForUse:
1107 it.second->NotifyForUse();
1108 break;
1109 case RenderTextureOp::NotifyNotUsed:
1110 it.second->NotifyNotUsed();
1111 break;
1116 void RenderThread::UnregisterExternalImageDuringShutdown(
1117 const wr::ExternalImageId& aExternalImageId) {
1118 MOZ_ASSERT(IsInRenderThread());
1119 MutexAutoLock lock(mRenderTextureMapLock);
1120 MOZ_ASSERT(mHasShutdown);
1121 MOZ_ASSERT(mRenderTextures.find(aExternalImageId) != mRenderTextures.end());
1122 mRenderTextures.erase(aExternalImageId);
1125 bool RenderThread::SyncObjectNeeded() {
1126 MOZ_ASSERT(IsInRenderThread());
1127 MutexAutoLock lock(mRenderTextureMapLock);
1128 return !mSyncObjectNeededRenderTextures.empty();
1131 void RenderThread::DeferredRenderTextureHostDestroy() {
1132 MutexAutoLock lock(mRenderTextureMapLock);
1133 mRenderTexturesDeferred.clear();
1136 RenderTextureHost* RenderThread::GetRenderTexture(
1137 const wr::ExternalImageId& aExternalImageId) {
1138 MutexAutoLock lock(mRenderTextureMapLock);
1139 auto it = mRenderTextures.find(aExternalImageId);
1140 MOZ_ASSERT(it != mRenderTextures.end());
1141 if (it == mRenderTextures.end()) {
1142 return nullptr;
1144 return it->second;
1147 void RenderThread::InitDeviceTask() {
1148 MOZ_ASSERT(IsInRenderThread());
1149 MOZ_ASSERT(!mSingletonGL);
1150 LOG("RenderThread::InitDeviceTask()");
1152 if (gfx::gfxVars::UseSoftwareWebRender()) {
1153 // Ensure we don't instantiate any shared GL context when SW-WR is used.
1154 return;
1157 nsAutoCString err;
1158 CreateSingletonGL(err);
1159 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1160 mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
1162 // Query the shared GL context to force the
1163 // lazy initialization to happen now.
1164 SingletonGL();
1167 void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
1168 nsCOMPtr<nsIRunnable> runnable = aRunnable;
1169 mThread->Dispatch(runnable.forget());
1172 #ifndef XP_WIN
1173 static DeviceResetReason GLenumToResetReason(GLenum aReason) {
1174 switch (aReason) {
1175 case LOCAL_GL_NO_ERROR:
1176 return DeviceResetReason::FORCED_RESET;
1177 case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
1178 return DeviceResetReason::DRIVER_ERROR;
1179 case LOCAL_GL_PURGED_CONTEXT_RESET_NV:
1180 return DeviceResetReason::NVIDIA_VIDEO;
1181 case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
1182 return DeviceResetReason::RESET;
1183 case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
1184 return DeviceResetReason::UNKNOWN;
1185 case LOCAL_GL_OUT_OF_MEMORY:
1186 return DeviceResetReason::OUT_OF_MEMORY;
1187 default:
1188 return DeviceResetReason::OTHER;
1191 #endif
1193 void RenderThread::HandleDeviceReset(const char* aWhere, GLenum aReason) {
1194 MOZ_ASSERT(IsInRenderThread());
1196 // This happens only on simulate device reset.
1197 if (aReason == LOCAL_GL_NO_ERROR) {
1198 if (!mHandlingDeviceReset) {
1199 mHandlingDeviceReset = true;
1201 MutexAutoLock lock(mRenderTextureMapLock);
1202 mRenderTexturesDeferred.clear();
1203 for (const auto& entry : mRenderTextures) {
1204 entry.second->ClearCachedResources();
1207 // All RenderCompositors will be destroyed by the GPUProcessManager in
1208 // either OnRemoteProcessDeviceReset via the GPUChild, or
1209 // OnInProcessDeviceReset here directly.
1210 if (XRE_IsGPUProcess()) {
1211 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1212 } else {
1213 NS_DispatchToMainThread(NS_NewRunnableFunction(
1214 "gfx::GPUProcessManager::OnInProcessDeviceReset", []() -> void {
1215 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(
1216 /* aTrackThreshold */ false);
1217 }));
1220 return;
1223 if (mHandlingDeviceReset) {
1224 return;
1227 mHandlingDeviceReset = true;
1229 #ifndef XP_WIN
1230 // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices.
1231 gfx::GPUProcessManager::RecordDeviceReset(GLenumToResetReason(aReason));
1232 #endif
1235 MutexAutoLock lock(mRenderTextureMapLock);
1236 mRenderTexturesDeferred.clear();
1237 for (const auto& entry : mRenderTextures) {
1238 entry.second->ClearCachedResources();
1242 // All RenderCompositors will be destroyed by the GPUProcessManager in
1243 // either OnRemoteProcessDeviceReset via the GPUChild, or
1244 // OnInProcessDeviceReset here directly.
1245 // On Windows, device will be re-created before sessions re-creation.
1246 gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
1247 if (XRE_IsGPUProcess()) {
1248 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1249 } else {
1250 #ifndef XP_WIN
1251 // FIXME(aosmond): Do we need to do this on Windows? nsWindow::OnPaint
1252 // seems to do its own detection for the parent process.
1253 bool guilty = aReason == LOCAL_GL_GUILTY_CONTEXT_RESET_ARB;
1254 NS_DispatchToMainThread(NS_NewRunnableFunction(
1255 "gfx::GPUProcessManager::OnInProcessDeviceReset", [guilty]() -> void {
1256 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(guilty);
1257 }));
1258 #endif
1262 bool RenderThread::IsHandlingDeviceReset() {
1263 MOZ_ASSERT(IsInRenderThread());
1264 return mHandlingDeviceReset;
1267 void RenderThread::SimulateDeviceReset() {
1268 if (!IsInRenderThread()) {
1269 PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this,
1270 &RenderThread::SimulateDeviceReset));
1271 } else {
1272 // When this function is called GPUProcessManager::SimulateDeviceReset()
1273 // already triggers destroying all CompositorSessions before re-creating
1274 // them.
1275 HandleDeviceReset("SimulateDeviceReset", LOCAL_GL_NO_ERROR);
1279 static void DoNotifyWebRenderError(WebRenderError aError) {
1280 layers::CompositorManagerParent::NotifyWebRenderError(aError);
1283 void RenderThread::NotifyWebRenderError(WebRenderError aError) {
1284 MOZ_ASSERT(IsInRenderThread());
1286 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1287 "DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
1290 void RenderThread::HandleWebRenderError(WebRenderError aError) {
1291 if (mHandlingWebRenderError) {
1292 return;
1295 NotifyWebRenderError(aError);
1298 MutexAutoLock lock(mRenderTextureMapLock);
1299 mRenderTexturesDeferred.clear();
1300 for (const auto& entry : mRenderTextures) {
1301 entry.second->ClearCachedResources();
1304 mHandlingWebRenderError = true;
1305 // WebRender is going to be disabled by
1306 // GPUProcessManager::NotifyWebRenderError()
1309 bool RenderThread::IsHandlingWebRenderError() {
1310 MOZ_ASSERT(IsInRenderThread());
1311 return mHandlingWebRenderError;
1314 gl::GLContext* RenderThread::SingletonGL() {
1315 nsAutoCString err;
1316 auto* gl = SingletonGL(err);
1317 if (!err.IsEmpty()) {
1318 gfxCriticalNote << err.get();
1320 return gl;
1323 void RenderThread::CreateSingletonGL(nsACString& aError) {
1324 MOZ_ASSERT(IsInRenderThread());
1325 LOG("RenderThread::CreateSingletonGL()");
1327 mSingletonGL = CreateGLContext(aError);
1328 mSingletonGLIsForHardwareWebRender = !gfx::gfxVars::UseSoftwareWebRender();
1331 gl::GLContext* RenderThread::SingletonGL(nsACString& aError) {
1332 MOZ_ASSERT(IsInRenderThread());
1333 if (!mSingletonGL) {
1334 CreateSingletonGL(aError);
1335 mShaders = nullptr;
1337 if (mSingletonGL && mSingletonGLIsForHardwareWebRender && !mShaders) {
1338 mShaders = MakeUnique<WebRenderShaders>(mSingletonGL, mProgramCache.get());
1341 return mSingletonGL.get();
1344 gl::GLContext* RenderThread::SingletonGLForCompositorOGL() {
1345 MOZ_RELEASE_ASSERT(gfx::gfxVars::UseSoftwareWebRender());
1347 if (mSingletonGLIsForHardwareWebRender) {
1348 // Clear singleton GL, since GLContext is for hardware WebRender.
1349 ClearSingletonGL();
1351 return SingletonGL();
1354 void RenderThread::ClearSingletonGL() {
1355 MOZ_ASSERT(IsInRenderThread());
1356 LOG("RenderThread::ClearSingletonGL()");
1358 if (mSurfacePool) {
1359 mSurfacePool->DestroyGLResourcesForContext(mSingletonGL);
1361 if (mProgramsForCompositorOGL) {
1362 mProgramsForCompositorOGL->Clear();
1363 mProgramsForCompositorOGL = nullptr;
1365 mShaders = nullptr;
1366 mSingletonGL = nullptr;
1369 RefPtr<layers::ShaderProgramOGLsHolder>
1370 RenderThread::GetProgramsForCompositorOGL() {
1371 if (!mSingletonGL) {
1372 return nullptr;
1375 if (!mProgramsForCompositorOGL) {
1376 mProgramsForCompositorOGL =
1377 MakeAndAddRef<layers::ShaderProgramOGLsHolder>(mSingletonGL);
1379 return mProgramsForCompositorOGL;
1382 RefPtr<layers::SurfacePool> RenderThread::SharedSurfacePool() {
1383 #if defined(XP_MACOSX) || defined(MOZ_WAYLAND)
1384 if (!mSurfacePool) {
1385 size_t poolSizeLimit =
1386 StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup();
1387 mSurfacePool = layers::SurfacePool::Create(poolSizeLimit);
1389 #endif
1390 return mSurfacePool;
1393 void RenderThread::ClearSharedSurfacePool() { mSurfacePool = nullptr; }
1395 static void GLAPIENTRY DebugMessageCallback(GLenum aSource, GLenum aType,
1396 GLuint aId, GLenum aSeverity,
1397 GLsizei aLength,
1398 const GLchar* aMessage,
1399 const GLvoid* aUserParam) {
1400 constexpr const char* kContextLost = "Context has been lost.";
1402 if (StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() &&
1403 aSeverity == LOCAL_GL_DEBUG_SEVERITY_HIGH) {
1404 auto message = std::string(aMessage, aLength);
1405 // When content lost happned, error messages are flooded by its message.
1406 if (message != kContextLost) {
1407 gfxCriticalNote << message;
1408 } else {
1409 gfxCriticalNoteOnce << message;
1413 if (StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup()) {
1414 gl::GLContext* gl = (gl::GLContext*)aUserParam;
1415 gl->DebugCallback(aSource, aType, aId, aSeverity, aLength, aMessage);
1419 // static
1420 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext* aGLContext) {
1421 if (!aGLContext) {
1422 return;
1425 bool enableDebugMessage =
1426 StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() ||
1427 StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup();
1429 if (enableDebugMessage &&
1430 aGLContext->IsExtensionSupported(gl::GLContext::KHR_debug)) {
1431 aGLContext->fEnable(LOCAL_GL_DEBUG_OUTPUT);
1432 aGLContext->fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
1433 aGLContext->fDebugMessageCallback(&DebugMessageCallback, (void*)aGLContext);
1434 aGLContext->fDebugMessageControl(LOCAL_GL_DONT_CARE, LOCAL_GL_DONT_CARE,
1435 LOCAL_GL_DONT_CARE, 0, nullptr, true);
1439 WebRenderShaders::WebRenderShaders(gl::GLContext* gl,
1440 WebRenderProgramCache* programCache) {
1441 mGL = gl;
1442 mShaders =
1443 wr_shaders_new(gl, programCache ? programCache->Raw() : nullptr,
1444 StaticPrefs::gfx_webrender_precache_shaders_AtStartup());
1447 WebRenderShaders::~WebRenderShaders() {
1448 wr_shaders_delete(mShaders, mGL.get());
1451 WebRenderThreadPool::WebRenderThreadPool(bool low_priority) {
1452 mThreadPool = wr_thread_pool_new(low_priority);
1455 WebRenderThreadPool::~WebRenderThreadPool() { Release(); }
1457 void WebRenderThreadPool::Release() {
1458 if (mThreadPool) {
1459 wr_thread_pool_delete(mThreadPool);
1460 mThreadPool = nullptr;
1464 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) {
1465 MOZ_ASSERT(aThreadPool);
1467 nsAutoString path;
1468 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1469 path.Append(gfx::gfxVars::ProfDirectory());
1471 mProgramCache = wr_program_cache_new(&path, aThreadPool);
1472 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1473 wr_try_load_startup_shaders_from_disk(mProgramCache);
1477 WebRenderProgramCache::~WebRenderProgramCache() {
1478 wr_program_cache_delete(mProgramCache);
1481 } // namespace mozilla::wr
1483 #ifdef XP_WIN
1484 static already_AddRefed<gl::GLContext> CreateGLContextANGLE(
1485 nsACString& aError) {
1486 const RefPtr<ID3D11Device> d3d11Device =
1487 gfx::DeviceManagerDx::Get()->GetCompositorDevice();
1488 if (!d3d11Device) {
1489 aError.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns);
1490 return nullptr;
1493 nsCString failureId;
1494 const auto lib = gl::GLLibraryEGL::Get(&failureId);
1495 if (!lib) {
1496 aError.Assign(
1497 nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get()));
1498 return nullptr;
1501 const auto egl = lib->CreateDisplay(d3d11Device.get());
1502 if (!egl) {
1503 aError.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
1504 failureId.get()));
1505 return nullptr;
1508 gl::CreateContextFlags flags = gl::CreateContextFlags::PREFER_ES3;
1510 if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
1511 flags |= gl::CreateContextFlags::PREFER_ROBUSTNESS;
1514 if (egl->IsExtensionSupported(
1515 gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
1516 flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE;
1519 // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
1520 // Instread we override it with EGLSurface of SwapChain's back buffer.
1522 auto gl = gl::GLContextEGL::CreateWithoutSurface(egl, {flags}, &failureId);
1523 if (!gl || !gl->IsANGLE()) {
1524 aError.Assign(nsPrintfCString("RcANGLE(create GL context failed: %p, %s)",
1525 gl.get(), failureId.get()));
1526 return nullptr;
1529 if (!gl->MakeCurrent()) {
1530 aError.Assign(
1531 nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)",
1532 gl.get(), gl->mEgl->mLib->fGetError()));
1533 return nullptr;
1536 return gl.forget();
1538 #endif
1540 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WAYLAND) || defined(MOZ_X11)
1541 static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
1542 // Create GLContext with dummy EGLSurface.
1543 bool forHardwareWebRender = true;
1544 // SW-WR uses CompositorOGL in native compositor.
1545 if (gfx::gfxVars::UseSoftwareWebRender()) {
1546 forHardwareWebRender = false;
1548 RefPtr<gl::GLContext> gl =
1549 gl::GLContextProviderEGL::CreateForCompositorWidget(
1550 nullptr, forHardwareWebRender, /* aForceAccelerated */ true);
1551 if (!gl || !gl->MakeCurrent()) {
1552 gfxCriticalNote << "Failed GL context creation for hardware WebRender: "
1553 << forHardwareWebRender;
1554 return nullptr;
1556 return gl.forget();
1558 #endif
1560 #ifdef XP_MACOSX
1561 static already_AddRefed<gl::GLContext> CreateGLContextCGL() {
1562 nsCString failureUnused;
1563 return gl::GLContextProvider::CreateHeadless(
1564 {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
1565 gl::CreateContextFlags::FORBID_SOFTWARE},
1566 &failureUnused);
1568 #endif
1570 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) {
1571 RefPtr<gl::GLContext> gl;
1573 #ifdef XP_WIN
1574 if (gfx::gfxVars::UseWebRenderANGLE()) {
1575 gl = CreateGLContextANGLE(aError);
1577 #elif defined(MOZ_WIDGET_ANDROID)
1578 gl = CreateGLContextEGL();
1579 #elif defined(MOZ_WAYLAND) || defined(MOZ_X11)
1580 if (gfx::gfxVars::UseEGL()) {
1581 gl = CreateGLContextEGL();
1583 #elif XP_MACOSX
1584 gl = CreateGLContextCGL();
1585 #endif
1587 wr::RenderThread::MaybeEnableGLDebugMessage(gl);
1589 return gl.forget();
1592 extern "C" {
1594 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId,
1595 bool aCompositeNeeded) {
1596 // wake_up is used for things like propagating debug options or memory
1597 // pressure events, so we are not tracking pending frame counts.
1598 mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId,
1599 aCompositeNeeded);
1602 void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId,
1603 bool aCompositeNeeded,
1604 mozilla::wr::FramePublishId aPublishId) {
1605 auto* renderThread = mozilla::wr::RenderThread::Get();
1606 renderThread->DecPendingFrameBuildCount(aWindowId);
1608 renderThread->WrNotifierEvent_NewFrameReady(aWindowId, aCompositeNeeded,
1609 aPublishId);
1612 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
1613 size_t aRawEvent) {
1614 mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent(
1615 mozilla::wr::WindowId(aWindowId), aRawEvent);
1618 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,
1619 wr::RenderReasons aReasons) {
1620 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1621 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1622 if (cbp) {
1623 cbp->ScheduleComposition(aReasons);
1627 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
1628 wr::RenderReasons aReasons) {
1629 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1630 "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons));
1633 static void NotifyDidSceneBuild(
1634 mozilla::wr::WrWindowId aWindowId,
1635 const RefPtr<const wr::WebRenderPipelineInfo>& aInfo) {
1636 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1637 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1638 if (cbp) {
1639 cbp->NotifyDidSceneBuild(aInfo);
1643 void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,
1644 mozilla::wr::WrPipelineInfo* aPipelineInfo) {
1645 RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo();
1646 info->Raw() = std::move(*aPipelineInfo);
1647 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1648 "NotifyDidSceneBuild", &NotifyDidSceneBuild, aWindowId, info));
1651 } // extern C