no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / gfx / webrender_bindings / RenderThread.cpp
blob89fc339c032c12259b16ba29ac47e48927d8e52e
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 # include "GLLibraryEGL.h"
54 #endif
56 using namespace mozilla;
58 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError);
60 MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderRendererMallocSizeOf)
62 namespace mozilla::wr {
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__))
68 static StaticRefPtr<RenderThread> sRenderThread;
69 static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor;
70 #ifdef DEBUG
71 static bool sRenderThreadEverStarted = false;
72 #endif
74 RenderThread::RenderThread(RefPtr<nsIThread> aThread)
75 : mThread(std::move(aThread)),
76 mThreadPool(false),
77 mThreadPoolLP(true),
78 mSingletonGLIsForHardwareWebRender(true),
79 mWindowInfos("RenderThread.mWindowInfos"),
80 mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
81 mHasShutdown(false),
82 mHandlingDeviceReset(false),
83 mHandlingWebRenderError(false) {}
85 RenderThread::~RenderThread() { MOZ_ASSERT(mRenderTexturesDeferred.empty()); }
87 // static
88 RenderThread* RenderThread::Get() { return sRenderThread; }
90 // static
91 void RenderThread::Start(uint32_t aNamespace) {
92 MOZ_ASSERT(NS_IsMainThread());
93 MOZ_ASSERT(!sRenderThread);
95 #ifdef DEBUG
96 // Check to ensure nobody will try to ever start us more than once during
97 // the process' lifetime (in particular after ShutDown).
98 MOZ_ASSERT(!sRenderThreadEverStarted);
99 sRenderThreadEverStarted = true;
100 #endif
102 // When the CanvasRenderer thread is disabled, WebGL may be handled on this
103 // thread, requiring a bigger stack size. See: CanvasManagerParent::Init
105 // This is 4M, which is higher than the default 256K.
106 // Increased with bug 1753349 to accommodate the `chromium/5359` branch of
107 // ANGLE, which has large peak stack usage for some pathological shader
108 // compilations.
110 // Previously increased to 512K to accommodate Mesa in bug 1753340.
112 // Previously increased to 320K to avoid a stack overflow in the
113 // Intel Vulkan driver initialization in bug 1716120.
115 // Note: we only override it if it's limited already.
116 uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE;
117 if (stackSize && !gfx::gfxVars::SupportsThreadsafeGL()) {
118 stackSize = std::max(stackSize, 4096U << 10);
121 RefPtr<nsIThread> thread;
122 nsresult rv = NS_NewNamedThread(
123 "Renderer", getter_AddRefs(thread),
124 NS_NewRunnableFunction(
125 "Renderer::BackgroundHanSetup",
126 []() {
127 sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor(
128 "Render",
129 /* Timeout values are powers-of-two to enable us get better
130 data. 128ms is chosen for transient hangs because 8Hz should
131 be the minimally acceptable goal for Render
132 responsiveness (normal goal is 60Hz). */
133 128,
134 /* 2048ms is chosen for permanent hangs because it's longer than
135 * most Render hangs seen in the wild, but is short enough
136 * to not miss getting native hang stacks. */
137 2048);
138 nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
139 nsThread* nsthread = static_cast<nsThread*>(thread.get());
140 nsthread->SetUseHangMonitor(true);
141 nsthread->SetPriority(nsISupportsPriority::PRIORITY_HIGH);
143 {.stackSize = stackSize});
145 if (NS_FAILED(rv)) {
146 gfxCriticalNote << "Failed to create Renderer thread: "
147 << gfx::hexa((uint32_t)rv);
148 return;
151 sRenderThread = new RenderThread(thread);
152 #ifdef XP_WIN
153 widget::WinCompositorWindowThread::Start();
154 #endif
155 layers::SharedSurfacesParent::Initialize();
157 RefPtr<Runnable> runnable = WrapRunnable(
158 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::InitDeviceTask);
159 sRenderThread->PostRunnable(runnable.forget());
162 // static
163 void RenderThread::ShutDown() {
164 MOZ_ASSERT(NS_IsMainThread());
165 MOZ_ASSERT(sRenderThread);
168 MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
169 sRenderThread->mHasShutdown = true;
172 RefPtr<Runnable> runnable = WrapRunnable(
173 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::ShutDownTask);
174 sRenderThread->PostRunnable(runnable.forget());
176 // This will empty the thread queue and thus run the above runnable while
177 // spinning the MT event loop.
178 nsCOMPtr<nsIThread> oldThread = sRenderThread->GetRenderThread();
179 oldThread->Shutdown();
181 layers::SharedSurfacesParent::Shutdown();
183 #ifdef XP_WIN
184 if (widget::WinCompositorWindowThread::Get()) {
185 widget::WinCompositorWindowThread::ShutDown();
187 #endif
189 // We null this out only after we finished shutdown to give everbody the
190 // chance to check for sRenderThread->mHasShutdown. Hopefully everybody
191 // checks this before using us!
192 sRenderThread = nullptr;
195 extern void ClearAllBlobImageResources();
197 void RenderThread::ShutDownTask() {
198 MOZ_ASSERT(IsInRenderThread());
199 LOG("RenderThread::ShutDownTask()");
202 // Clear RenderTextureHosts
203 MutexAutoLock lock(mRenderTextureMapLock);
204 mRenderTexturesDeferred.clear();
205 mRenderTextures.clear();
206 mSyncObjectNeededRenderTextures.clear();
207 mRenderTextureOps.clear();
210 // Let go of our handle to the (internally ref-counted) thread pool.
211 mThreadPool.Release();
212 mThreadPoolLP.Release();
214 // Releasing on the render thread will allow us to avoid dispatching to remove
215 // remaining textures from the texture map.
216 layers::SharedSurfacesParent::ShutdownRenderThread();
218 #ifdef XP_WIN
219 DCLayerTree::Shutdown();
220 #endif
222 ClearAllBlobImageResources();
223 ClearSingletonGL();
224 ClearSharedSurfacePool();
227 // static
228 bool RenderThread::IsInRenderThread() {
229 return sRenderThread && sRenderThread->mThread == NS_GetCurrentThread();
232 // static
233 already_AddRefed<nsIThread> RenderThread::GetRenderThread() {
234 nsCOMPtr<nsIThread> thread;
235 if (sRenderThread) {
236 thread = sRenderThread->mThread;
238 return thread.forget();
241 void RenderThread::DoAccumulateMemoryReport(
242 MemoryReport aReport,
243 const RefPtr<MemoryReportPromise::Private>& aPromise) {
244 MOZ_ASSERT(IsInRenderThread());
246 for (auto& r : mRenderers) {
247 r.second->AccumulateMemoryReport(&aReport);
250 // Note memory used by the shader cache, which is shared across all WR
251 // instances.
252 MOZ_ASSERT(aReport.shader_cache == 0);
253 if (mProgramCache) {
254 aReport.shader_cache = wr_program_cache_report_memory(
255 mProgramCache->Raw(), &WebRenderRendererMallocSizeOf);
258 size_t renderTextureMemory = 0;
260 MutexAutoLock lock(mRenderTextureMapLock);
261 for (const auto& entry : mRenderTextures) {
262 renderTextureMemory += entry.second->Bytes();
265 aReport.render_texture_hosts = renderTextureMemory;
267 aPromise->Resolve(aReport, __func__);
270 // static
271 RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport(
272 MemoryReport aInitial) {
273 RefPtr<MemoryReportPromise::Private> p =
274 new MemoryReportPromise::Private(__func__);
275 MOZ_ASSERT(!IsInRenderThread());
276 if (!Get()) {
277 // This happens when the GPU process fails to start and we fall back to the
278 // basic compositor in the parent process. We could assert against this if
279 // we made the webrender detection code in gfxPlatform.cpp smarter. See bug
280 // 1494430 comment 12.
281 NS_WARNING("No render thread, returning empty memory report");
282 p->Resolve(aInitial, __func__);
283 return p;
286 Get()->PostRunnable(
287 NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>(
288 "wr::RenderThread::DoAccumulateMemoryReport", Get(),
289 &RenderThread::DoAccumulateMemoryReport, aInitial, p));
291 return p;
294 void RenderThread::AddRenderer(wr::WindowId aWindowId,
295 UniquePtr<RendererOGL> aRenderer) {
296 MOZ_ASSERT(IsInRenderThread());
297 LOG("RenderThread::AddRenderer() aWindowId %" PRIx64 "", AsUint64(aWindowId));
299 if (mHasShutdown) {
300 return;
303 mRenderers[aWindowId] = std::move(aRenderer);
304 CrashReporter::AnnotateCrashReport(
305 CrashReporter::Annotation::GraphicsNumRenderers,
306 (unsigned int)mRenderers.size());
308 auto windows = mWindowInfos.Lock();
309 windows->emplace(AsUint64(aWindowId), new WindowInfo());
310 mWrNotifierEventsQueues.emplace(AsUint64(aWindowId),
311 new std::queue<WrNotifierEvent>);
314 void RenderThread::RemoveRenderer(wr::WindowId aWindowId) {
315 MOZ_ASSERT(IsInRenderThread());
316 LOG("RenderThread::RemoveRenderer() aWindowId %" PRIx64 "",
317 AsUint64(aWindowId));
319 if (mHasShutdown) {
320 return;
323 mRenderers.erase(aWindowId);
324 CrashReporter::AnnotateCrashReport(
325 CrashReporter::Annotation::GraphicsNumRenderers,
326 (unsigned int)mRenderers.size());
328 if (mRenderers.empty()) {
329 if (mHandlingDeviceReset) {
330 ClearSingletonGL();
332 mHandlingDeviceReset = false;
333 mHandlingWebRenderError = false;
336 auto windows = mWindowInfos.Lock();
337 auto it = windows->find(AsUint64(aWindowId));
338 MOZ_ASSERT(it != windows->end());
339 windows->erase(it);
341 // Defer std::deque<WrNotifierEvent> remove, RemoveRenderer() is called in
342 // HandleWrNotifierEvents().
343 RefPtr<Runnable> runnable =
344 NS_NewRunnableFunction("RenderThread::RemoveRenderer", [aWindowId]() {
345 auto* self = RenderThread::Get();
346 auto it = self->mWrNotifierEventsQueues.find(AsUint64(aWindowId));
347 if (it == self->mWrNotifierEventsQueues.end()) {
348 return;
350 self->mWrNotifierEventsQueues.erase(it);
352 RenderThread::Get()->PostRunnable(runnable.forget());
355 RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) {
356 MOZ_ASSERT(IsInRenderThread());
358 auto it = mRenderers.find(aWindowId);
359 MOZ_ASSERT(it != mRenderers.end());
361 if (it == mRenderers.end()) {
362 return nullptr;
365 return it->second.get();
368 size_t RenderThread::RendererCount() const {
369 MOZ_ASSERT(IsInRenderThread());
370 return mRenderers.size();
373 size_t RenderThread::ActiveRendererCount() const {
374 MOZ_ASSERT(IsInRenderThread());
375 size_t num_active = 0;
376 for (const auto& it : mRenderers) {
377 if (!it.second->IsPaused()) {
378 num_active++;
381 return num_active;
384 void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId,
385 bool aCompositeNeeded) {
386 auto windows = mWindowInfos.Lock();
387 auto it = windows->find(AsUint64(aWindowId));
388 if (it == windows->end()) {
389 MOZ_ASSERT(false);
390 return;
393 WindowInfo* info = it->second.get();
395 info->mPendingWrNotifierEvents.emplace(
396 WrNotifierEvent::WakeUp(aCompositeNeeded));
397 PostWrNotifierEvents(aWindowId, info);
400 void RenderThread::WrNotifierEvent_NewFrameReady(WrWindowId aWindowId,
401 bool aCompositeNeeded,
402 FramePublishId aPublishId) {
403 auto windows = mWindowInfos.Lock();
404 auto it = windows->find(AsUint64(aWindowId));
405 if (it == windows->end()) {
406 MOZ_ASSERT(false);
407 return;
409 WindowInfo* info = it->second.get();
411 info->mPendingWrNotifierEvents.emplace(
412 WrNotifierEvent::NewFrameReady(aCompositeNeeded, aPublishId));
413 PostWrNotifierEvents(aWindowId, info);
416 void RenderThread::WrNotifierEvent_ExternalEvent(WrWindowId aWindowId,
417 size_t aRawEvent) {
418 UniquePtr<RendererEvent> evt(reinterpret_cast<RendererEvent*>(aRawEvent));
420 auto windows = mWindowInfos.Lock();
421 auto it = windows->find(AsUint64(aWindowId));
422 if (it == windows->end()) {
423 MOZ_ASSERT(false);
424 return;
426 WindowInfo* info = it->second.get();
428 info->mPendingWrNotifierEvents.emplace(
429 WrNotifierEvent::ExternalEvent(std::move(evt)));
430 PostWrNotifierEvents(aWindowId, info);
434 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId) {
436 auto windows = mWindowInfos.Lock();
437 auto it = windows->find(AsUint64(aWindowId));
438 if (it == windows->end()) {
439 MOZ_ASSERT(false);
440 return;
442 WindowInfo* info = it->second.get();
443 PostWrNotifierEvents(aWindowId, info);
447 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId,
448 WindowInfo* aInfo) {
449 // Runnable has already been triggered.
450 if (aInfo->mWrNotifierEventsRunnable) {
451 return;
454 // Runnable has not been triggered yet.
455 RefPtr<nsIRunnable> runnable = NewRunnableMethod<WrWindowId>(
456 "RenderThread::HandleWrNotifierEvents", this,
457 &RenderThread::HandleWrNotifierEvents, aWindowId);
458 aInfo->mWrNotifierEventsRunnable = runnable;
459 PostRunnable(runnable.forget());
462 void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId) {
463 MOZ_ASSERT(IsInRenderThread());
465 auto eventsIt = mWrNotifierEventsQueues.find(AsUint64(aWindowId));
466 if (eventsIt == mWrNotifierEventsQueues.end()) {
467 return;
469 auto* events = eventsIt->second.get();
472 auto windows = mWindowInfos.Lock();
473 auto infoIt = windows->find(AsUint64(aWindowId));
474 if (infoIt == windows->end()) {
475 MOZ_ASSERT(false);
476 return;
478 WindowInfo* info = infoIt->second.get();
479 info->mWrNotifierEventsRunnable = nullptr;
481 if (events->empty() && !info->mPendingWrNotifierEvents.empty()) {
482 events->swap(info->mPendingWrNotifierEvents);
486 bool handleNext = true;
488 while (!events->empty() && handleNext) {
489 auto& front = events->front();
490 switch (front.mTag) {
491 case WrNotifierEvent::Tag::WakeUp:
492 WrNotifierEvent_HandleWakeUp(aWindowId, front.CompositeNeeded());
493 handleNext = false;
494 break;
495 case WrNotifierEvent::Tag::NewFrameReady:
496 WrNotifierEvent_HandleNewFrameReady(aWindowId, front.CompositeNeeded(),
497 front.PublishId());
498 handleNext = false;
499 break;
500 case WrNotifierEvent::Tag::ExternalEvent:
501 WrNotifierEvent_HandleExternalEvent(aWindowId, front.ExternalEvent());
502 break;
504 events->pop();
508 auto windows = mWindowInfos.Lock();
509 auto it = windows->find(AsUint64(aWindowId));
510 if (it == windows->end()) {
511 return;
513 WindowInfo* info = it->second.get();
515 if (!events->empty() || !info->mPendingWrNotifierEvents.empty()) {
516 PostWrNotifierEvents(aWindowId, info);
521 void RenderThread::WrNotifierEvent_HandleWakeUp(wr::WindowId aWindowId,
522 bool aCompositeNeeded) {
523 MOZ_ASSERT(IsInRenderThread());
525 bool isTrackedFrame = false;
526 HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame, Nothing());
529 void RenderThread::WrNotifierEvent_HandleNewFrameReady(
530 wr::WindowId aWindowId, bool aCompositeNeeded, FramePublishId aPublishId) {
531 MOZ_ASSERT(IsInRenderThread());
533 bool isTrackedFrame = true;
534 HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame,
535 Some(aPublishId));
538 void RenderThread::WrNotifierEvent_HandleExternalEvent(
539 wr::WindowId aWindowId, UniquePtr<RendererEvent> aRendererEvent) {
540 MOZ_ASSERT(IsInRenderThread());
542 RunEvent(aWindowId, std::move(aRendererEvent));
545 void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId,
546 const TimeStamp& aRecordingStart,
547 wr::PipelineId aRootPipelineId) {
548 MOZ_ASSERT(IsInRenderThread());
549 RendererOGL* renderer = GetRenderer(aWindowId);
550 MOZ_ASSERT(renderer);
552 renderer->BeginRecording(aRecordingStart, aRootPipelineId);
555 Maybe<layers::FrameRecording> RenderThread::EndRecordingForWindow(
556 wr::WindowId aWindowId) {
557 MOZ_ASSERT(IsInRenderThread());
559 RendererOGL* renderer = GetRenderer(aWindowId);
560 MOZ_ASSERT(renderer);
561 return renderer->EndRecording();
564 void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender,
565 bool aTrackedFrame,
566 Maybe<FramePublishId> aPublishId) {
567 MOZ_ASSERT(IsInRenderThread());
569 if (mHasShutdown) {
570 return;
573 HandleFrameOneDocInner(aWindowId, aRender, aTrackedFrame, aPublishId);
575 if (aTrackedFrame) {
576 DecPendingFrameCount(aWindowId);
580 void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId, bool aRender,
581 bool aTrackedFrame,
582 Maybe<FramePublishId> aPublishId) {
583 if (IsDestroyed(aWindowId)) {
584 return;
587 if (mHandlingDeviceReset) {
588 return;
591 bool render = aRender;
592 PendingFrameInfo frame;
593 if (aTrackedFrame) {
594 // scope lock
595 auto windows = mWindowInfos.Lock();
596 auto it = windows->find(AsUint64(aWindowId));
597 if (it == windows->end()) {
598 MOZ_ASSERT(false);
599 return;
602 WindowInfo* info = it->second.get();
603 PendingFrameInfo& frameInfo = info->mPendingFrames.front();
605 frame = frameInfo;
606 } else {
607 // Just give the frame info default values.
608 frame = {TimeStamp::Now(), VsyncId()};
611 // Sadly this doesn't include the lock, since we don't have the frame there
612 // yet.
613 glean::wr::time_to_render_start.AccumulateRawDuration(TimeStamp::Now() -
614 frame.mStartTime);
616 // It is for ensuring that PrepareForUse() is called before
617 // RenderTextureHost::Lock().
618 HandleRenderTextureOps();
620 if (aPublishId.isSome()) {
621 SetFramePublishId(aWindowId, aPublishId.ref());
624 UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, render,
625 /* aReadbackSize */ Nothing(),
626 /* aReadbackFormat */ Nothing(),
627 /* aReadbackBuffer */ Nothing());
629 // The start time is from WebRenderBridgeParent::CompositeToTarget. From that
630 // point until now (when the frame is finally pushed to the screen) is
631 // equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
632 TimeDuration compositeDuration = TimeStamp::Now() - frame.mStartTime;
633 mozilla::glean::gfx::composite_time.AccumulateRawDuration(compositeDuration);
634 PerfStats::RecordMeasurement(PerfStats::Metric::Compositing,
635 compositeDuration);
638 void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) {
639 if (mHasShutdown) {
640 return;
643 if (!IsInRenderThread()) {
644 PostRunnable(NewRunnableMethod<wr::WindowId, wr::ColorF>(
645 "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor,
646 aWindowId, aColor));
647 return;
650 if (IsDestroyed(aWindowId)) {
651 return;
654 auto it = mRenderers.find(aWindowId);
655 MOZ_ASSERT(it != mRenderers.end());
656 if (it != mRenderers.end()) {
657 wr_renderer_set_clear_color(it->second->GetRenderer(), aColor);
661 void RenderThread::SetProfilerUI(wr::WindowId aWindowId,
662 const nsACString& aUI) {
663 if (mHasShutdown) {
664 return;
667 if (!IsInRenderThread()) {
668 PostRunnable(NewRunnableMethod<wr::WindowId, nsCString>(
669 "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI,
670 aWindowId, nsCString(aUI)));
671 return;
674 auto it = mRenderers.find(aWindowId);
675 if (it != mRenderers.end()) {
676 it->second->SetProfilerUI(aUI);
680 void RenderThread::PostEvent(wr::WindowId aWindowId,
681 UniquePtr<RendererEvent> aEvent) {
682 PostRunnable(NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
683 "wr::RenderThread::PostEvent", this, &RenderThread::RunEvent, aWindowId,
684 std::move(aEvent)));
687 void RenderThread::RunEvent(wr::WindowId aWindowId,
688 UniquePtr<RendererEvent> aEvent) {
689 MOZ_ASSERT(IsInRenderThread());
691 aEvent->Run(*this, aWindowId);
692 aEvent = nullptr;
695 static void NotifyDidRender(layers::CompositorBridgeParent* aBridge,
696 const RefPtr<const WebRenderPipelineInfo>& aInfo,
697 VsyncId aCompositeStartId,
698 TimeStamp aCompositeStart, TimeStamp aRenderStart,
699 TimeStamp aEnd, bool aRender,
700 RendererStats aStats) {
701 if (aRender && aBridge->GetWrBridge()) {
702 // We call this here to mimic the behavior in LayerManagerComposite, as to
703 // not change what Talos measures. That is, we do not record an empty frame
704 // as a frame.
705 aBridge->GetWrBridge()->RecordFrame();
708 aBridge->NotifyDidRender(aCompositeStartId, aCompositeStart, aRenderStart,
709 aEnd, &aStats);
711 for (const auto& epoch : aInfo->Raw().epochs) {
712 aBridge->NotifyPipelineRendered(epoch.pipeline_id, epoch.epoch,
713 aCompositeStartId, aCompositeStart,
714 aRenderStart, aEnd, &aStats);
717 if (aBridge->GetWrBridge()) {
718 aBridge->GetWrBridge()->RetrySkippedComposite();
722 static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) {
723 if (aBridge->GetWrBridge()) {
724 aBridge->GetWrBridge()->RetrySkippedComposite();
728 void RenderThread::SetFramePublishId(wr::WindowId aWindowId,
729 FramePublishId aPublishId) {
730 MOZ_ASSERT(IsInRenderThread());
732 auto it = mRenderers.find(aWindowId);
733 MOZ_ASSERT(it != mRenderers.end());
734 if (it == mRenderers.end()) {
735 return;
737 auto& renderer = it->second;
739 renderer->SetFramePublishId(aPublishId);
742 void RenderThread::UpdateAndRender(
743 wr::WindowId aWindowId, const VsyncId& aStartId,
744 const TimeStamp& aStartTime, bool aRender,
745 const Maybe<gfx::IntSize>& aReadbackSize,
746 const Maybe<wr::ImageFormat>& aReadbackFormat,
747 const Maybe<Range<uint8_t>>& aReadbackBuffer, bool* aNeedsYFlip) {
748 AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS);
749 MOZ_ASSERT(IsInRenderThread());
750 MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
752 auto it = mRenderers.find(aWindowId);
753 MOZ_ASSERT(it != mRenderers.end());
754 if (it == mRenderers.end()) {
755 return;
758 TimeStamp start = TimeStamp::Now();
760 auto& renderer = it->second;
762 std::string markerName = "Composite #" + std::to_string(AsUint64(aWindowId));
763 AutoProfilerTracing tracingCompositeMarker(
764 "Paint", markerName.c_str(), geckoprofiler::category::GRAPHICS,
765 Some(renderer->GetCompositorBridge()->GetInnerWindowId()));
767 if (renderer->IsPaused()) {
768 aRender = false;
770 LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64 " aRender %d",
771 AsUint64(aWindowId), aRender);
773 layers::CompositorThread()->Dispatch(
774 NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender,
775 renderer->GetCompositorBridge()));
777 wr::RenderedFrameId latestFrameId;
778 RendererStats stats = {0};
779 if (aRender) {
780 latestFrameId = renderer->UpdateAndRender(
781 aReadbackSize, aReadbackFormat, aReadbackBuffer, aNeedsYFlip, &stats);
782 } else {
783 renderer->Update();
785 // Check graphics reset status even when rendering is skipped.
786 renderer->CheckGraphicsResetStatus("PostUpdate", /* aForce */ false);
788 TimeStamp end = TimeStamp::Now();
789 RefPtr<const WebRenderPipelineInfo> info = renderer->GetLastPipelineInfo();
791 layers::CompositorThread()->Dispatch(
792 NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
793 renderer->GetCompositorBridge(), info, aStartId,
794 aStartTime, start, end, aRender, stats));
796 ipc::FileDescriptor fenceFd;
798 if (latestFrameId.IsValid()) {
799 fenceFd = renderer->GetAndResetReleaseFence();
801 // Wait for GPU after posting NotifyDidRender, since the wait is not
802 // necessary for the NotifyDidRender.
803 // The wait is necessary for Textures recycling of AsyncImagePipelineManager
804 // and for avoiding GPU queue is filled with too much tasks.
805 // WaitForGPU's implementation is different for each platform.
806 auto timerId = glean::wr::gpu_wait_time.Start();
807 renderer->WaitForGPU();
808 glean::wr::gpu_wait_time.StopAndAccumulate(std::move(timerId));
809 } else {
810 // Update frame id for NotifyPipelinesUpdated() when rendering does not
811 // happen, either because rendering was not requested or the frame was
812 // canceled. Rendering can sometimes be canceled if UpdateAndRender is
813 // called when the window is not yet ready (not mapped or 0 size).
814 latestFrameId = renderer->UpdateFrameId();
817 RenderedFrameId lastCompletedFrameId = renderer->GetLastCompletedFrameId();
819 RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
820 renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
821 // pipelineMgr should always be non-null here because it is only nulled out
822 // after the WebRenderAPI instance for the CompositorBridgeParent is
823 // destroyed, and that destruction blocks until the renderer thread has
824 // removed the relevant renderer. And after that happens we should never reach
825 // this code at all; it would bail out at the mRenderers.find check above.
826 MOZ_ASSERT(pipelineMgr);
827 pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId,
828 std::move(fenceFd));
831 void RenderThread::Pause(wr::WindowId aWindowId) {
832 MOZ_ASSERT(IsInRenderThread());
833 LOG("RenderThread::Pause() aWindowId %" PRIx64 "", AsUint64(aWindowId));
835 auto it = mRenderers.find(aWindowId);
836 MOZ_ASSERT(it != mRenderers.end());
837 if (it == mRenderers.end()) {
838 gfxCriticalNote << "RenderThread cannot find renderer for window "
839 << gfx::hexa(aWindowId) << " to pause.";
840 return;
842 auto& renderer = it->second;
843 renderer->Pause();
845 CrashReporter::AnnotateCrashReport(
846 CrashReporter::Annotation::GraphicsNumActiveRenderers,
847 (unsigned int)ActiveRendererCount());
850 bool RenderThread::Resume(wr::WindowId aWindowId) {
851 MOZ_ASSERT(IsInRenderThread());
852 LOG("enderThread::Resume() aWindowId %" PRIx64 "", AsUint64(aWindowId));
854 auto it = mRenderers.find(aWindowId);
855 MOZ_ASSERT(it != mRenderers.end());
856 if (it == mRenderers.end()) {
857 gfxCriticalNote << "RenderThread cannot find renderer for window "
858 << gfx::hexa(aWindowId) << " to resume.";
859 return false;
861 auto& renderer = it->second;
862 bool resumed = renderer->Resume();
864 CrashReporter::AnnotateCrashReport(
865 CrashReporter::Annotation::GraphicsNumActiveRenderers,
866 (unsigned int)ActiveRendererCount());
868 return resumed;
871 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) {
872 const int64_t maxFrameCount = 1;
874 // Too many pending frames if pending frames exit more than maxFrameCount
875 // or if RenderBackend is still processing a frame.
877 auto windows = mWindowInfos.Lock();
878 auto it = windows->find(AsUint64(aWindowId));
879 if (it == windows->end()) {
880 MOZ_ASSERT(false);
881 return true;
883 WindowInfo* info = it->second.get();
885 if (info->PendingCount() > maxFrameCount) {
886 return true;
888 // If there is no ongoing frame build, we accept a new frame.
889 return info->mPendingFrameBuild > 0;
892 bool RenderThread::IsDestroyed(wr::WindowId aWindowId) {
893 auto windows = mWindowInfos.Lock();
894 auto it = windows->find(AsUint64(aWindowId));
895 if (it == windows->end()) {
896 return true;
899 return it->second->mIsDestroyed;
902 void RenderThread::SetDestroyed(wr::WindowId aWindowId) {
903 auto windows = mWindowInfos.Lock();
904 auto it = windows->find(AsUint64(aWindowId));
905 if (it == windows->end()) {
906 MOZ_ASSERT(false);
907 return;
909 it->second->mIsDestroyed = true;
912 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId,
913 const VsyncId& aStartId,
914 const TimeStamp& aStartTime) {
915 auto windows = mWindowInfos.Lock();
916 auto it = windows->find(AsUint64(aWindowId));
917 if (it == windows->end()) {
918 MOZ_ASSERT(false);
919 return;
921 it->second->mPendingFrameBuild++;
922 it->second->mPendingFrames.push(PendingFrameInfo{aStartTime, aStartId});
925 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId) {
926 auto windows = mWindowInfos.Lock();
927 auto it = windows->find(AsUint64(aWindowId));
928 if (it == windows->end()) {
929 MOZ_ASSERT(false);
930 return;
932 WindowInfo* info = it->second.get();
933 MOZ_RELEASE_ASSERT(info->mPendingFrameBuild >= 1);
934 info->mPendingFrameBuild--;
937 void RenderThread::DecPendingFrameCount(wr::WindowId aWindowId) {
938 auto windows = mWindowInfos.Lock();
939 auto it = windows->find(AsUint64(aWindowId));
940 if (it == windows->end()) {
941 MOZ_ASSERT(false);
942 return;
944 WindowInfo* info = it->second.get();
945 info->mPendingFrames.pop();
948 void RenderThread::RegisterExternalImage(
949 const wr::ExternalImageId& aExternalImageId,
950 already_AddRefed<RenderTextureHost> aTexture) {
951 MutexAutoLock lock(mRenderTextureMapLock);
953 if (mHasShutdown) {
954 return;
956 MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
957 RefPtr<RenderTextureHost> texture = aTexture;
958 if (texture->SyncObjectNeeded()) {
959 mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture);
961 mRenderTextures.emplace(aExternalImageId, texture);
964 void RenderThread::UnregisterExternalImage(
965 const wr::ExternalImageId& aExternalImageId) {
966 MutexAutoLock lock(mRenderTextureMapLock);
967 if (mHasShutdown) {
968 return;
970 auto it = mRenderTextures.find(aExternalImageId);
971 if (it == mRenderTextures.end()) {
972 return;
975 auto& texture = it->second;
976 if (texture->SyncObjectNeeded()) {
977 MOZ_RELEASE_ASSERT(
978 mSyncObjectNeededRenderTextures.erase(aExternalImageId) == 1);
981 if (!IsInRenderThread()) {
982 // The RenderTextureHost should be released in render thread. So, post the
983 // deletion task here.
984 // The shmem and raw buffer are owned by compositor ipc channel. It's
985 // possible that RenderTextureHost is still exist after the shmem/raw buffer
986 // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
987 // for this situation. Gecko will only release the buffer if WR doesn't need
988 // it. So, no one will access the invalid buffer in RenderTextureHost.
989 RefPtr<RenderTextureHost> texture = it->second;
990 mRenderTextures.erase(it);
991 mRenderTexturesDeferred.emplace_back(std::move(texture));
992 PostRunnable(NewRunnableMethod(
993 "RenderThread::DeferredRenderTextureHostDestroy", this,
994 &RenderThread::DeferredRenderTextureHostDestroy));
995 } else {
996 mRenderTextures.erase(it);
1000 void RenderThread::DestroyExternalImagesSyncWait(
1001 const std::vector<wr::ExternalImageId>&& aIds) {
1002 if (!IsInRenderThread()) {
1003 layers::SynchronousTask task("Destroy external images");
1005 RefPtr<Runnable> runnable = NS_NewRunnableFunction(
1006 "RenderThread::DestroyExternalImagesSyncWait::Runnable",
1007 [&task, ids = std::move(aIds)]() {
1008 layers::AutoCompleteTask complete(&task);
1009 RenderThread::Get()->DestroyExternalImages(std::move(ids));
1012 PostRunnable(runnable.forget());
1013 task.Wait();
1014 return;
1016 DestroyExternalImages(std::move(aIds));
1019 void RenderThread::DestroyExternalImages(
1020 const std::vector<wr::ExternalImageId>&& aIds) {
1021 MOZ_ASSERT(IsInRenderThread());
1023 std::vector<RefPtr<RenderTextureHost>> hosts;
1025 MutexAutoLock lock(mRenderTextureMapLock);
1026 if (mHasShutdown) {
1027 return;
1030 for (auto& id : aIds) {
1031 auto it = mRenderTextures.find(id);
1032 if (it == mRenderTextures.end()) {
1033 continue;
1035 hosts.emplace_back(it->second);
1039 for (auto& host : hosts) {
1040 host->Destroy();
1044 void RenderThread::PrepareForUse(const wr::ExternalImageId& aExternalImageId) {
1045 AddRenderTextureOp(RenderTextureOp::PrepareForUse, aExternalImageId);
1048 void RenderThread::NotifyNotUsed(const wr::ExternalImageId& aExternalImageId) {
1049 AddRenderTextureOp(RenderTextureOp::NotifyNotUsed, aExternalImageId);
1052 void RenderThread::NotifyForUse(const wr::ExternalImageId& aExternalImageId) {
1053 AddRenderTextureOp(RenderTextureOp::NotifyForUse, aExternalImageId);
1056 void RenderThread::AddRenderTextureOp(
1057 RenderTextureOp aOp, const wr::ExternalImageId& aExternalImageId) {
1058 MOZ_ASSERT(!IsInRenderThread());
1060 MutexAutoLock lock(mRenderTextureMapLock);
1062 auto it = mRenderTextures.find(aExternalImageId);
1063 MOZ_ASSERT(it != mRenderTextures.end());
1064 if (it == mRenderTextures.end()) {
1065 return;
1068 RefPtr<RenderTextureHost> texture = it->second;
1069 mRenderTextureOps.emplace_back(aOp, std::move(texture));
1071 if (mRenderTextureOpsRunnable) {
1072 // Runnable was already triggered
1073 return;
1076 RefPtr<nsIRunnable> runnable =
1077 NewRunnableMethod("RenderThread::HandleRenderTextureOps", this,
1078 &RenderThread::HandleRenderTextureOps);
1079 mRenderTextureOpsRunnable = runnable;
1080 PostRunnable(runnable.forget());
1083 void RenderThread::HandleRenderTextureOps() {
1084 MOZ_ASSERT(IsInRenderThread());
1086 std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>>
1087 renderTextureOps;
1089 MutexAutoLock lock(mRenderTextureMapLock);
1090 mRenderTextureOps.swap(renderTextureOps);
1091 mRenderTextureOpsRunnable = nullptr;
1094 for (auto& it : renderTextureOps) {
1095 switch (it.first) {
1096 case RenderTextureOp::PrepareForUse:
1097 it.second->PrepareForUse();
1098 break;
1099 case RenderTextureOp::NotifyForUse:
1100 it.second->NotifyForUse();
1101 break;
1102 case RenderTextureOp::NotifyNotUsed:
1103 it.second->NotifyNotUsed();
1104 break;
1109 void RenderThread::UnregisterExternalImageDuringShutdown(
1110 const wr::ExternalImageId& aExternalImageId) {
1111 MOZ_ASSERT(IsInRenderThread());
1112 MutexAutoLock lock(mRenderTextureMapLock);
1113 MOZ_ASSERT(mHasShutdown);
1114 mRenderTextures.erase(aExternalImageId);
1117 bool RenderThread::SyncObjectNeeded() {
1118 MOZ_ASSERT(IsInRenderThread());
1119 MutexAutoLock lock(mRenderTextureMapLock);
1120 return !mSyncObjectNeededRenderTextures.empty();
1123 void RenderThread::DeferredRenderTextureHostDestroy() {
1124 MutexAutoLock lock(mRenderTextureMapLock);
1125 mRenderTexturesDeferred.clear();
1128 RenderTextureHost* RenderThread::GetRenderTexture(
1129 const wr::ExternalImageId& aExternalImageId) {
1130 MutexAutoLock lock(mRenderTextureMapLock);
1131 auto it = mRenderTextures.find(aExternalImageId);
1132 MOZ_ASSERT(it != mRenderTextures.end());
1133 if (it == mRenderTextures.end()) {
1134 return nullptr;
1136 return it->second;
1139 void RenderThread::InitDeviceTask() {
1140 MOZ_ASSERT(IsInRenderThread());
1141 MOZ_ASSERT(!mSingletonGL);
1142 LOG("RenderThread::InitDeviceTask()");
1144 if (gfx::gfxVars::UseSoftwareWebRender()) {
1145 // Ensure we don't instantiate any shared GL context when SW-WR is used.
1146 return;
1149 nsAutoCString err;
1150 CreateSingletonGL(err);
1151 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1152 mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
1154 // Query the shared GL context to force the
1155 // lazy initialization to happen now.
1156 SingletonGL();
1159 void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
1160 nsCOMPtr<nsIRunnable> runnable = aRunnable;
1161 mThread->Dispatch(runnable.forget());
1164 #ifndef XP_WIN
1165 static DeviceResetReason GLenumToResetReason(GLenum aReason) {
1166 switch (aReason) {
1167 case LOCAL_GL_NO_ERROR:
1168 return DeviceResetReason::FORCED_RESET;
1169 case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
1170 return DeviceResetReason::DRIVER_ERROR;
1171 case LOCAL_GL_PURGED_CONTEXT_RESET_NV:
1172 return DeviceResetReason::NVIDIA_VIDEO;
1173 case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
1174 return DeviceResetReason::RESET;
1175 case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
1176 return DeviceResetReason::UNKNOWN;
1177 case LOCAL_GL_OUT_OF_MEMORY:
1178 return DeviceResetReason::OUT_OF_MEMORY;
1179 default:
1180 return DeviceResetReason::OTHER;
1183 #endif
1185 void RenderThread::HandleDeviceReset(const char* aWhere, GLenum aReason) {
1186 MOZ_ASSERT(IsInRenderThread());
1188 // This happens only on simulate device reset.
1189 if (aReason == LOCAL_GL_NO_ERROR) {
1190 if (!mHandlingDeviceReset) {
1191 mHandlingDeviceReset = true;
1193 MutexAutoLock lock(mRenderTextureMapLock);
1194 mRenderTexturesDeferred.clear();
1195 for (const auto& entry : mRenderTextures) {
1196 entry.second->ClearCachedResources();
1199 // All RenderCompositors will be destroyed by the GPUProcessManager in
1200 // either OnRemoteProcessDeviceReset via the GPUChild, or
1201 // OnInProcessDeviceReset here directly.
1202 if (XRE_IsGPUProcess()) {
1203 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1204 } else {
1205 NS_DispatchToMainThread(NS_NewRunnableFunction(
1206 "gfx::GPUProcessManager::OnInProcessDeviceReset", []() -> void {
1207 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(
1208 /* aTrackThreshold */ false);
1209 }));
1212 return;
1215 if (mHandlingDeviceReset) {
1216 return;
1219 mHandlingDeviceReset = true;
1221 #ifndef XP_WIN
1222 // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices.
1223 gfx::GPUProcessManager::RecordDeviceReset(GLenumToResetReason(aReason));
1224 #endif
1227 MutexAutoLock lock(mRenderTextureMapLock);
1228 mRenderTexturesDeferred.clear();
1229 for (const auto& entry : mRenderTextures) {
1230 entry.second->ClearCachedResources();
1234 // All RenderCompositors will be destroyed by the GPUProcessManager in
1235 // either OnRemoteProcessDeviceReset via the GPUChild, or
1236 // OnInProcessDeviceReset here directly.
1237 // On Windows, device will be re-created before sessions re-creation.
1238 gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
1239 if (XRE_IsGPUProcess()) {
1240 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1241 } else {
1242 #ifndef XP_WIN
1243 // FIXME(aosmond): Do we need to do this on Windows? nsWindow::OnPaint
1244 // seems to do its own detection for the parent process.
1245 bool guilty = aReason == LOCAL_GL_GUILTY_CONTEXT_RESET_ARB;
1246 NS_DispatchToMainThread(NS_NewRunnableFunction(
1247 "gfx::GPUProcessManager::OnInProcessDeviceReset", [guilty]() -> void {
1248 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(guilty);
1249 }));
1250 #endif
1254 bool RenderThread::IsHandlingDeviceReset() {
1255 MOZ_ASSERT(IsInRenderThread());
1256 return mHandlingDeviceReset;
1259 void RenderThread::SimulateDeviceReset() {
1260 if (!IsInRenderThread()) {
1261 PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this,
1262 &RenderThread::SimulateDeviceReset));
1263 } else {
1264 // When this function is called GPUProcessManager::SimulateDeviceReset()
1265 // already triggers destroying all CompositorSessions before re-creating
1266 // them.
1267 HandleDeviceReset("SimulateDeviceReset", LOCAL_GL_NO_ERROR);
1271 static void DoNotifyWebRenderError(WebRenderError aError) {
1272 layers::CompositorManagerParent::NotifyWebRenderError(aError);
1275 void RenderThread::NotifyWebRenderError(WebRenderError aError) {
1276 MOZ_ASSERT(IsInRenderThread());
1278 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1279 "DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
1282 void RenderThread::HandleWebRenderError(WebRenderError aError) {
1283 MOZ_ASSERT(IsInRenderThread());
1284 if (mHandlingWebRenderError) {
1285 return;
1288 NotifyWebRenderError(aError);
1291 MutexAutoLock lock(mRenderTextureMapLock);
1292 mRenderTexturesDeferred.clear();
1293 for (const auto& entry : mRenderTextures) {
1294 entry.second->ClearCachedResources();
1297 mHandlingWebRenderError = true;
1298 // WebRender is going to be disabled by
1299 // GPUProcessManager::NotifyWebRenderError()
1302 bool RenderThread::IsHandlingWebRenderError() {
1303 MOZ_ASSERT(IsInRenderThread());
1304 return mHandlingWebRenderError;
1307 gl::GLContext* RenderThread::SingletonGL() {
1308 nsAutoCString err;
1309 auto* gl = SingletonGL(err);
1310 if (!err.IsEmpty()) {
1311 gfxCriticalNote << err.get();
1313 return gl;
1316 void RenderThread::CreateSingletonGL(nsACString& aError) {
1317 MOZ_ASSERT(IsInRenderThread());
1318 LOG("RenderThread::CreateSingletonGL()");
1320 mSingletonGL = CreateGLContext(aError);
1321 mSingletonGLIsForHardwareWebRender = !gfx::gfxVars::UseSoftwareWebRender();
1324 gl::GLContext* RenderThread::SingletonGL(nsACString& aError) {
1325 MOZ_ASSERT(IsInRenderThread());
1326 if (!mSingletonGL) {
1327 CreateSingletonGL(aError);
1328 mShaders = nullptr;
1330 if (mSingletonGL && mSingletonGLIsForHardwareWebRender && !mShaders) {
1331 mShaders = MakeUnique<WebRenderShaders>(mSingletonGL, mProgramCache.get());
1334 return mSingletonGL.get();
1337 gl::GLContext* RenderThread::SingletonGLForCompositorOGL() {
1338 MOZ_RELEASE_ASSERT(gfx::gfxVars::UseSoftwareWebRender());
1340 if (mSingletonGLIsForHardwareWebRender) {
1341 // Clear singleton GL, since GLContext is for hardware WebRender.
1342 ClearSingletonGL();
1344 return SingletonGL();
1347 void RenderThread::ClearSingletonGL() {
1348 MOZ_ASSERT(IsInRenderThread());
1349 LOG("RenderThread::ClearSingletonGL()");
1351 if (mSurfacePool) {
1352 mSurfacePool->DestroyGLResourcesForContext(mSingletonGL);
1354 if (mProgramsForCompositorOGL) {
1355 mProgramsForCompositorOGL->Clear();
1356 mProgramsForCompositorOGL = nullptr;
1358 if (mShaders) {
1359 if (mSingletonGL) {
1360 mSingletonGL->MakeCurrent();
1362 mShaders = nullptr;
1364 mSingletonGL = nullptr;
1367 RefPtr<layers::ShaderProgramOGLsHolder>
1368 RenderThread::GetProgramsForCompositorOGL() {
1369 if (!mSingletonGL) {
1370 return nullptr;
1373 if (!mProgramsForCompositorOGL) {
1374 mProgramsForCompositorOGL =
1375 MakeAndAddRef<layers::ShaderProgramOGLsHolder>(mSingletonGL);
1377 return mProgramsForCompositorOGL;
1380 RefPtr<layers::SurfacePool> RenderThread::SharedSurfacePool() {
1381 #if defined(XP_MACOSX) || defined(MOZ_WAYLAND)
1382 if (!mSurfacePool) {
1383 size_t poolSizeLimit =
1384 StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup();
1385 mSurfacePool = layers::SurfacePool::Create(poolSizeLimit);
1387 #endif
1388 return mSurfacePool;
1391 void RenderThread::ClearSharedSurfacePool() { mSurfacePool = nullptr; }
1393 static void GLAPIENTRY DebugMessageCallback(GLenum aSource, GLenum aType,
1394 GLuint aId, GLenum aSeverity,
1395 GLsizei aLength,
1396 const GLchar* aMessage,
1397 const GLvoid* aUserParam) {
1398 constexpr const char* kContextLost = "Context has been lost.";
1400 if (StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() &&
1401 aSeverity == LOCAL_GL_DEBUG_SEVERITY_HIGH) {
1402 auto message = std::string(aMessage, aLength);
1403 // When content lost happned, error messages are flooded by its message.
1404 if (message != kContextLost) {
1405 gfxCriticalNote << message;
1406 } else {
1407 gfxCriticalNoteOnce << message;
1411 if (StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup()) {
1412 gl::GLContext* gl = (gl::GLContext*)aUserParam;
1413 gl->DebugCallback(aSource, aType, aId, aSeverity, aLength, aMessage);
1417 // static
1418 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext* aGLContext) {
1419 if (!aGLContext) {
1420 return;
1423 bool enableDebugMessage =
1424 StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() ||
1425 StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup();
1427 if (enableDebugMessage &&
1428 aGLContext->IsExtensionSupported(gl::GLContext::KHR_debug)) {
1429 aGLContext->fEnable(LOCAL_GL_DEBUG_OUTPUT);
1430 aGLContext->fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
1431 aGLContext->fDebugMessageCallback(&DebugMessageCallback, (void*)aGLContext);
1432 aGLContext->fDebugMessageControl(LOCAL_GL_DONT_CARE, LOCAL_GL_DONT_CARE,
1433 LOCAL_GL_DONT_CARE, 0, nullptr, true);
1437 WebRenderShaders::WebRenderShaders(gl::GLContext* gl,
1438 WebRenderProgramCache* programCache) {
1439 mGL = gl;
1440 mShaders =
1441 wr_shaders_new(gl, programCache ? programCache->Raw() : nullptr,
1442 StaticPrefs::gfx_webrender_precache_shaders_AtStartup());
1445 WebRenderShaders::~WebRenderShaders() {
1446 wr_shaders_delete(mShaders, mGL.get());
1449 WebRenderThreadPool::WebRenderThreadPool(bool low_priority) {
1450 mThreadPool = wr_thread_pool_new(low_priority);
1453 WebRenderThreadPool::~WebRenderThreadPool() { Release(); }
1455 void WebRenderThreadPool::Release() {
1456 if (mThreadPool) {
1457 wr_thread_pool_delete(mThreadPool);
1458 mThreadPool = nullptr;
1462 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) {
1463 MOZ_ASSERT(aThreadPool);
1465 nsAutoString path;
1466 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1467 path.Append(gfx::gfxVars::ProfDirectory());
1469 mProgramCache = wr_program_cache_new(&path, aThreadPool);
1470 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1471 wr_try_load_startup_shaders_from_disk(mProgramCache);
1475 WebRenderProgramCache::~WebRenderProgramCache() {
1476 wr_program_cache_delete(mProgramCache);
1479 } // namespace mozilla::wr
1481 #ifdef XP_WIN
1482 static already_AddRefed<gl::GLContext> CreateGLContextANGLE(
1483 nsACString& aError) {
1484 const RefPtr<ID3D11Device> d3d11Device =
1485 gfx::DeviceManagerDx::Get()->GetCompositorDevice();
1486 if (!d3d11Device) {
1487 aError.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns);
1488 return nullptr;
1491 nsCString failureId;
1492 const auto lib = gl::GLLibraryEGL::Get(&failureId);
1493 if (!lib) {
1494 aError.Assign(
1495 nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get()));
1496 return nullptr;
1499 const auto egl = lib->CreateDisplay(d3d11Device.get());
1500 if (!egl) {
1501 aError.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
1502 failureId.get()));
1503 return nullptr;
1506 gl::CreateContextFlags flags = gl::CreateContextFlags::PREFER_ES3;
1508 if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
1509 flags |= gl::CreateContextFlags::PREFER_ROBUSTNESS;
1512 if (egl->IsExtensionSupported(
1513 gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
1514 flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE;
1517 // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
1518 // Instread we override it with EGLSurface of SwapChain's back buffer.
1520 auto gl = gl::GLContextEGL::CreateWithoutSurface(egl, {flags}, &failureId);
1521 if (!gl || !gl->IsANGLE()) {
1522 aError.Assign(nsPrintfCString("RcANGLE(create GL context failed: %p, %s)",
1523 gl.get(), failureId.get()));
1524 return nullptr;
1527 if (!gl->MakeCurrent()) {
1528 aError.Assign(
1529 nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)",
1530 gl.get(), gl->mEgl->mLib->fGetError()));
1531 return nullptr;
1534 return gl.forget();
1536 #endif
1538 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
1539 static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
1540 // Create GLContext with dummy EGLSurface.
1541 bool forHardwareWebRender = true;
1542 // SW-WR uses CompositorOGL in native compositor.
1543 if (gfx::gfxVars::UseSoftwareWebRender()) {
1544 forHardwareWebRender = false;
1546 RefPtr<gl::GLContext> gl =
1547 gl::GLContextProviderEGL::CreateForCompositorWidget(
1548 nullptr, forHardwareWebRender, /* aForceAccelerated */ true);
1549 if (!gl || !gl->MakeCurrent()) {
1550 gfxCriticalNote << "Failed GL context creation for hardware WebRender: "
1551 << forHardwareWebRender;
1552 return nullptr;
1554 return gl.forget();
1556 #endif
1558 #ifdef XP_MACOSX
1559 static already_AddRefed<gl::GLContext> CreateGLContextCGL() {
1560 nsCString failureUnused;
1561 return gl::GLContextProvider::CreateHeadless(
1562 {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
1563 gl::CreateContextFlags::FORBID_SOFTWARE},
1564 &failureUnused);
1566 #endif
1568 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) {
1569 RefPtr<gl::GLContext> gl;
1571 #ifdef XP_WIN
1572 if (gfx::gfxVars::UseWebRenderANGLE()) {
1573 gl = CreateGLContextANGLE(aError);
1575 #elif defined(MOZ_WIDGET_ANDROID)
1576 gl = CreateGLContextEGL();
1577 #elif defined(MOZ_WIDGET_GTK)
1578 if (gfx::gfxVars::UseEGL()) {
1579 gl = CreateGLContextEGL();
1581 #elif XP_MACOSX
1582 gl = CreateGLContextCGL();
1583 #endif
1585 wr::RenderThread::MaybeEnableGLDebugMessage(gl);
1587 return gl.forget();
1590 extern "C" {
1592 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId,
1593 bool aCompositeNeeded) {
1594 // wake_up is used for things like propagating debug options or memory
1595 // pressure events, so we are not tracking pending frame counts.
1596 mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId,
1597 aCompositeNeeded);
1600 void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId,
1601 bool aCompositeNeeded,
1602 mozilla::wr::FramePublishId aPublishId) {
1603 auto* renderThread = mozilla::wr::RenderThread::Get();
1604 renderThread->DecPendingFrameBuildCount(aWindowId);
1606 renderThread->WrNotifierEvent_NewFrameReady(aWindowId, aCompositeNeeded,
1607 aPublishId);
1610 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
1611 size_t aRawEvent) {
1612 mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent(
1613 mozilla::wr::WindowId(aWindowId), aRawEvent);
1616 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,
1617 wr::RenderReasons aReasons) {
1618 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1619 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1620 if (cbp) {
1621 cbp->ScheduleComposition(aReasons);
1625 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
1626 wr::RenderReasons aReasons) {
1627 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1628 "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons));
1631 static void NotifyDidSceneBuild(
1632 mozilla::wr::WrWindowId aWindowId,
1633 const RefPtr<const wr::WebRenderPipelineInfo>& aInfo) {
1634 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1635 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1636 if (cbp) {
1637 cbp->NotifyDidSceneBuild(aInfo);
1641 void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,
1642 mozilla::wr::WrPipelineInfo* aPipelineInfo) {
1643 RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo();
1644 info->Raw() = std::move(*aPipelineInfo);
1645 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1646 "NotifyDidSceneBuild", &NotifyDidSceneBuild, aWindowId, info));
1649 } // extern C