Bug 1842773 - Part 11: Make DataView byteOffset and byteLength accessors aware of...
[gecko.git] / gfx / webrender_bindings / RenderThread.cpp
blobfc3a137f30bb6c6f6a06897004dd4ba2a9adf675
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::Telemetry::Accumulate(mozilla::Telemetry::COMPOSITE_TIME,
634 uint32_t(compositeDuration.ToMilliseconds()));
635 PerfStats::RecordMeasurement(PerfStats::Metric::Compositing,
636 compositeDuration);
639 void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) {
640 if (mHasShutdown) {
641 return;
644 if (!IsInRenderThread()) {
645 PostRunnable(NewRunnableMethod<wr::WindowId, wr::ColorF>(
646 "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor,
647 aWindowId, aColor));
648 return;
651 if (IsDestroyed(aWindowId)) {
652 return;
655 auto it = mRenderers.find(aWindowId);
656 MOZ_ASSERT(it != mRenderers.end());
657 if (it != mRenderers.end()) {
658 wr_renderer_set_clear_color(it->second->GetRenderer(), aColor);
662 void RenderThread::SetProfilerUI(wr::WindowId aWindowId,
663 const nsACString& aUI) {
664 if (mHasShutdown) {
665 return;
668 if (!IsInRenderThread()) {
669 PostRunnable(NewRunnableMethod<wr::WindowId, nsCString>(
670 "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI,
671 aWindowId, nsCString(aUI)));
672 return;
675 auto it = mRenderers.find(aWindowId);
676 if (it != mRenderers.end()) {
677 it->second->SetProfilerUI(aUI);
681 void RenderThread::PostEvent(wr::WindowId aWindowId,
682 UniquePtr<RendererEvent> aEvent) {
683 PostRunnable(NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
684 "wr::RenderThread::PostEvent", this, &RenderThread::RunEvent, aWindowId,
685 std::move(aEvent)));
688 void RenderThread::RunEvent(wr::WindowId aWindowId,
689 UniquePtr<RendererEvent> aEvent) {
690 MOZ_ASSERT(IsInRenderThread());
692 aEvent->Run(*this, aWindowId);
693 aEvent = nullptr;
696 static void NotifyDidRender(layers::CompositorBridgeParent* aBridge,
697 const RefPtr<const WebRenderPipelineInfo>& aInfo,
698 VsyncId aCompositeStartId,
699 TimeStamp aCompositeStart, TimeStamp aRenderStart,
700 TimeStamp aEnd, bool aRender,
701 RendererStats aStats) {
702 if (aRender && aBridge->GetWrBridge()) {
703 // We call this here to mimic the behavior in LayerManagerComposite, as to
704 // not change what Talos measures. That is, we do not record an empty frame
705 // as a frame.
706 aBridge->GetWrBridge()->RecordFrame();
709 aBridge->NotifyDidRender(aCompositeStartId, aCompositeStart, aRenderStart,
710 aEnd, &aStats);
712 for (const auto& epoch : aInfo->Raw().epochs) {
713 aBridge->NotifyPipelineRendered(epoch.pipeline_id, epoch.epoch,
714 aCompositeStartId, aCompositeStart,
715 aRenderStart, aEnd, &aStats);
718 if (aBridge->GetWrBridge()) {
719 aBridge->GetWrBridge()->RetrySkippedComposite();
723 static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) {
724 if (aBridge->GetWrBridge()) {
725 aBridge->GetWrBridge()->RetrySkippedComposite();
729 void RenderThread::SetFramePublishId(wr::WindowId aWindowId,
730 FramePublishId aPublishId) {
731 MOZ_ASSERT(IsInRenderThread());
733 auto it = mRenderers.find(aWindowId);
734 MOZ_ASSERT(it != mRenderers.end());
735 if (it == mRenderers.end()) {
736 return;
738 auto& renderer = it->second;
740 renderer->SetFramePublishId(aPublishId);
743 void RenderThread::UpdateAndRender(
744 wr::WindowId aWindowId, const VsyncId& aStartId,
745 const TimeStamp& aStartTime, bool aRender,
746 const Maybe<gfx::IntSize>& aReadbackSize,
747 const Maybe<wr::ImageFormat>& aReadbackFormat,
748 const Maybe<Range<uint8_t>>& aReadbackBuffer, bool* aNeedsYFlip) {
749 AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS);
750 MOZ_ASSERT(IsInRenderThread());
751 MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
753 auto it = mRenderers.find(aWindowId);
754 MOZ_ASSERT(it != mRenderers.end());
755 if (it == mRenderers.end()) {
756 return;
759 TimeStamp start = TimeStamp::Now();
761 auto& renderer = it->second;
763 std::string markerName = "Composite #" + std::to_string(AsUint64(aWindowId));
764 AutoProfilerTracing tracingCompositeMarker(
765 "Paint", markerName.c_str(), geckoprofiler::category::GRAPHICS,
766 Some(renderer->GetCompositorBridge()->GetInnerWindowId()));
768 if (renderer->IsPaused()) {
769 aRender = false;
771 LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64 " aRender %d",
772 AsUint64(aWindowId), aRender);
774 layers::CompositorThread()->Dispatch(
775 NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender,
776 renderer->GetCompositorBridge()));
778 wr::RenderedFrameId latestFrameId;
779 RendererStats stats = {0};
780 if (aRender) {
781 latestFrameId = renderer->UpdateAndRender(
782 aReadbackSize, aReadbackFormat, aReadbackBuffer, aNeedsYFlip, &stats);
783 } else {
784 renderer->Update();
786 // Check graphics reset status even when rendering is skipped.
787 renderer->CheckGraphicsResetStatus("PostUpdate", /* aForce */ false);
789 TimeStamp end = TimeStamp::Now();
790 RefPtr<const WebRenderPipelineInfo> info = renderer->GetLastPipelineInfo();
792 layers::CompositorThread()->Dispatch(
793 NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
794 renderer->GetCompositorBridge(), info, aStartId,
795 aStartTime, start, end, aRender, stats));
797 ipc::FileDescriptor fenceFd;
799 if (latestFrameId.IsValid()) {
800 fenceFd = renderer->GetAndResetReleaseFence();
802 // Wait for GPU after posting NotifyDidRender, since the wait is not
803 // necessary for the NotifyDidRender.
804 // The wait is necessary for Textures recycling of AsyncImagePipelineManager
805 // and for avoiding GPU queue is filled with too much tasks.
806 // WaitForGPU's implementation is different for each platform.
807 auto timerId = glean::wr::gpu_wait_time.Start();
808 renderer->WaitForGPU();
809 glean::wr::gpu_wait_time.StopAndAccumulate(std::move(timerId));
810 } else {
811 // Update frame id for NotifyPipelinesUpdated() when rendering does not
812 // happen, either because rendering was not requested or the frame was
813 // canceled. Rendering can sometimes be canceled if UpdateAndRender is
814 // called when the window is not yet ready (not mapped or 0 size).
815 latestFrameId = renderer->UpdateFrameId();
818 RenderedFrameId lastCompletedFrameId = renderer->GetLastCompletedFrameId();
820 RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
821 renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
822 // pipelineMgr should always be non-null here because it is only nulled out
823 // after the WebRenderAPI instance for the CompositorBridgeParent is
824 // destroyed, and that destruction blocks until the renderer thread has
825 // removed the relevant renderer. And after that happens we should never reach
826 // this code at all; it would bail out at the mRenderers.find check above.
827 MOZ_ASSERT(pipelineMgr);
828 pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId,
829 std::move(fenceFd));
832 void RenderThread::Pause(wr::WindowId aWindowId) {
833 MOZ_ASSERT(IsInRenderThread());
834 LOG("RenderThread::Pause() aWindowId %" PRIx64 "", AsUint64(aWindowId));
836 auto it = mRenderers.find(aWindowId);
837 MOZ_ASSERT(it != mRenderers.end());
838 if (it == mRenderers.end()) {
839 gfxCriticalNote << "RenderThread cannot find renderer for window "
840 << gfx::hexa(aWindowId) << " to pause.";
841 return;
843 auto& renderer = it->second;
844 renderer->Pause();
846 CrashReporter::AnnotateCrashReport(
847 CrashReporter::Annotation::GraphicsNumActiveRenderers,
848 (unsigned int)ActiveRendererCount());
851 bool RenderThread::Resume(wr::WindowId aWindowId) {
852 MOZ_ASSERT(IsInRenderThread());
853 LOG("enderThread::Resume() aWindowId %" PRIx64 "", AsUint64(aWindowId));
855 auto it = mRenderers.find(aWindowId);
856 MOZ_ASSERT(it != mRenderers.end());
857 if (it == mRenderers.end()) {
858 gfxCriticalNote << "RenderThread cannot find renderer for window "
859 << gfx::hexa(aWindowId) << " to resume.";
860 return false;
862 auto& renderer = it->second;
863 bool resumed = renderer->Resume();
865 CrashReporter::AnnotateCrashReport(
866 CrashReporter::Annotation::GraphicsNumActiveRenderers,
867 (unsigned int)ActiveRendererCount());
869 return resumed;
872 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) {
873 const int64_t maxFrameCount = 1;
875 // Too many pending frames if pending frames exit more than maxFrameCount
876 // or if RenderBackend is still processing a frame.
878 auto windows = mWindowInfos.Lock();
879 auto it = windows->find(AsUint64(aWindowId));
880 if (it == windows->end()) {
881 MOZ_ASSERT(false);
882 return true;
884 WindowInfo* info = it->second.get();
886 if (info->PendingCount() > maxFrameCount) {
887 return true;
889 // If there is no ongoing frame build, we accept a new frame.
890 return info->mPendingFrameBuild > 0;
893 bool RenderThread::IsDestroyed(wr::WindowId aWindowId) {
894 auto windows = mWindowInfos.Lock();
895 auto it = windows->find(AsUint64(aWindowId));
896 if (it == windows->end()) {
897 return true;
900 return it->second->mIsDestroyed;
903 void RenderThread::SetDestroyed(wr::WindowId aWindowId) {
904 auto windows = mWindowInfos.Lock();
905 auto it = windows->find(AsUint64(aWindowId));
906 if (it == windows->end()) {
907 MOZ_ASSERT(false);
908 return;
910 it->second->mIsDestroyed = true;
913 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId,
914 const VsyncId& aStartId,
915 const TimeStamp& aStartTime) {
916 auto windows = mWindowInfos.Lock();
917 auto it = windows->find(AsUint64(aWindowId));
918 if (it == windows->end()) {
919 MOZ_ASSERT(false);
920 return;
922 it->second->mPendingFrameBuild++;
923 it->second->mPendingFrames.push(PendingFrameInfo{aStartTime, aStartId});
926 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId) {
927 auto windows = mWindowInfos.Lock();
928 auto it = windows->find(AsUint64(aWindowId));
929 if (it == windows->end()) {
930 MOZ_ASSERT(false);
931 return;
933 WindowInfo* info = it->second.get();
934 MOZ_RELEASE_ASSERT(info->mPendingFrameBuild >= 1);
935 info->mPendingFrameBuild--;
938 void RenderThread::DecPendingFrameCount(wr::WindowId aWindowId) {
939 auto windows = mWindowInfos.Lock();
940 auto it = windows->find(AsUint64(aWindowId));
941 if (it == windows->end()) {
942 MOZ_ASSERT(false);
943 return;
945 WindowInfo* info = it->second.get();
946 info->mPendingFrames.pop();
949 void RenderThread::RegisterExternalImage(
950 const wr::ExternalImageId& aExternalImageId,
951 already_AddRefed<RenderTextureHost> aTexture) {
952 MutexAutoLock lock(mRenderTextureMapLock);
954 if (mHasShutdown) {
955 return;
957 MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
958 RefPtr<RenderTextureHost> texture = aTexture;
959 if (texture->SyncObjectNeeded()) {
960 mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture);
962 mRenderTextures.emplace(aExternalImageId, texture);
965 void RenderThread::UnregisterExternalImage(
966 const wr::ExternalImageId& aExternalImageId) {
967 MutexAutoLock lock(mRenderTextureMapLock);
968 if (mHasShutdown) {
969 return;
971 auto it = mRenderTextures.find(aExternalImageId);
972 if (it == mRenderTextures.end()) {
973 return;
976 auto& texture = it->second;
977 if (texture->SyncObjectNeeded()) {
978 MOZ_RELEASE_ASSERT(
979 mSyncObjectNeededRenderTextures.erase(aExternalImageId) == 1);
982 if (!IsInRenderThread()) {
983 // The RenderTextureHost should be released in render thread. So, post the
984 // deletion task here.
985 // The shmem and raw buffer are owned by compositor ipc channel. It's
986 // possible that RenderTextureHost is still exist after the shmem/raw buffer
987 // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
988 // for this situation. Gecko will only release the buffer if WR doesn't need
989 // it. So, no one will access the invalid buffer in RenderTextureHost.
990 RefPtr<RenderTextureHost> texture = it->second;
991 mRenderTextures.erase(it);
992 mRenderTexturesDeferred.emplace_back(std::move(texture));
993 PostRunnable(NewRunnableMethod(
994 "RenderThread::DeferredRenderTextureHostDestroy", this,
995 &RenderThread::DeferredRenderTextureHostDestroy));
996 } else {
997 mRenderTextures.erase(it);
1001 void RenderThread::DestroyExternalImagesSyncWait(
1002 const std::vector<wr::ExternalImageId>&& aIds) {
1003 if (!IsInRenderThread()) {
1004 layers::SynchronousTask task("Destroy external images");
1006 RefPtr<Runnable> runnable = NS_NewRunnableFunction(
1007 "RenderThread::DestroyExternalImagesSyncWait::Runnable",
1008 [&task, ids = std::move(aIds)]() {
1009 layers::AutoCompleteTask complete(&task);
1010 RenderThread::Get()->DestroyExternalImages(std::move(ids));
1013 PostRunnable(runnable.forget());
1014 task.Wait();
1015 return;
1017 DestroyExternalImages(std::move(aIds));
1020 void RenderThread::DestroyExternalImages(
1021 const std::vector<wr::ExternalImageId>&& aIds) {
1022 MOZ_ASSERT(IsInRenderThread());
1024 std::vector<RefPtr<RenderTextureHost>> hosts;
1026 MutexAutoLock lock(mRenderTextureMapLock);
1027 if (mHasShutdown) {
1028 return;
1031 for (auto& id : aIds) {
1032 auto it = mRenderTextures.find(id);
1033 if (it == mRenderTextures.end()) {
1034 continue;
1036 hosts.emplace_back(it->second);
1040 for (auto& host : hosts) {
1041 host->Destroy();
1045 void RenderThread::PrepareForUse(const wr::ExternalImageId& aExternalImageId) {
1046 AddRenderTextureOp(RenderTextureOp::PrepareForUse, aExternalImageId);
1049 void RenderThread::NotifyNotUsed(const wr::ExternalImageId& aExternalImageId) {
1050 AddRenderTextureOp(RenderTextureOp::NotifyNotUsed, aExternalImageId);
1053 void RenderThread::NotifyForUse(const wr::ExternalImageId& aExternalImageId) {
1054 AddRenderTextureOp(RenderTextureOp::NotifyForUse, aExternalImageId);
1057 void RenderThread::AddRenderTextureOp(
1058 RenderTextureOp aOp, const wr::ExternalImageId& aExternalImageId) {
1059 MOZ_ASSERT(!IsInRenderThread());
1061 MutexAutoLock lock(mRenderTextureMapLock);
1063 auto it = mRenderTextures.find(aExternalImageId);
1064 MOZ_ASSERT(it != mRenderTextures.end());
1065 if (it == mRenderTextures.end()) {
1066 return;
1069 RefPtr<RenderTextureHost> texture = it->second;
1070 mRenderTextureOps.emplace_back(aOp, std::move(texture));
1072 if (mRenderTextureOpsRunnable) {
1073 // Runnable was already triggered
1074 return;
1077 RefPtr<nsIRunnable> runnable =
1078 NewRunnableMethod("RenderThread::HandleRenderTextureOps", this,
1079 &RenderThread::HandleRenderTextureOps);
1080 mRenderTextureOpsRunnable = runnable;
1081 PostRunnable(runnable.forget());
1084 void RenderThread::HandleRenderTextureOps() {
1085 MOZ_ASSERT(IsInRenderThread());
1087 std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>>
1088 renderTextureOps;
1090 MutexAutoLock lock(mRenderTextureMapLock);
1091 mRenderTextureOps.swap(renderTextureOps);
1092 mRenderTextureOpsRunnable = nullptr;
1095 for (auto& it : renderTextureOps) {
1096 switch (it.first) {
1097 case RenderTextureOp::PrepareForUse:
1098 it.second->PrepareForUse();
1099 break;
1100 case RenderTextureOp::NotifyForUse:
1101 it.second->NotifyForUse();
1102 break;
1103 case RenderTextureOp::NotifyNotUsed:
1104 it.second->NotifyNotUsed();
1105 break;
1110 void RenderThread::UnregisterExternalImageDuringShutdown(
1111 const wr::ExternalImageId& aExternalImageId) {
1112 MOZ_ASSERT(IsInRenderThread());
1113 MutexAutoLock lock(mRenderTextureMapLock);
1114 MOZ_ASSERT(mHasShutdown);
1115 mRenderTextures.erase(aExternalImageId);
1118 bool RenderThread::SyncObjectNeeded() {
1119 MOZ_ASSERT(IsInRenderThread());
1120 MutexAutoLock lock(mRenderTextureMapLock);
1121 return !mSyncObjectNeededRenderTextures.empty();
1124 void RenderThread::DeferredRenderTextureHostDestroy() {
1125 MutexAutoLock lock(mRenderTextureMapLock);
1126 mRenderTexturesDeferred.clear();
1129 RenderTextureHost* RenderThread::GetRenderTexture(
1130 const wr::ExternalImageId& aExternalImageId) {
1131 MutexAutoLock lock(mRenderTextureMapLock);
1132 auto it = mRenderTextures.find(aExternalImageId);
1133 MOZ_ASSERT(it != mRenderTextures.end());
1134 if (it == mRenderTextures.end()) {
1135 return nullptr;
1137 return it->second;
1140 void RenderThread::InitDeviceTask() {
1141 MOZ_ASSERT(IsInRenderThread());
1142 MOZ_ASSERT(!mSingletonGL);
1143 LOG("RenderThread::InitDeviceTask()");
1145 if (gfx::gfxVars::UseSoftwareWebRender()) {
1146 // Ensure we don't instantiate any shared GL context when SW-WR is used.
1147 return;
1150 nsAutoCString err;
1151 CreateSingletonGL(err);
1152 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1153 mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
1155 // Query the shared GL context to force the
1156 // lazy initialization to happen now.
1157 SingletonGL();
1160 void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
1161 nsCOMPtr<nsIRunnable> runnable = aRunnable;
1162 mThread->Dispatch(runnable.forget());
1165 #ifndef XP_WIN
1166 static DeviceResetReason GLenumToResetReason(GLenum aReason) {
1167 switch (aReason) {
1168 case LOCAL_GL_NO_ERROR:
1169 return DeviceResetReason::FORCED_RESET;
1170 case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
1171 return DeviceResetReason::DRIVER_ERROR;
1172 case LOCAL_GL_PURGED_CONTEXT_RESET_NV:
1173 return DeviceResetReason::NVIDIA_VIDEO;
1174 case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
1175 return DeviceResetReason::RESET;
1176 case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
1177 return DeviceResetReason::UNKNOWN;
1178 case LOCAL_GL_OUT_OF_MEMORY:
1179 return DeviceResetReason::OUT_OF_MEMORY;
1180 default:
1181 return DeviceResetReason::OTHER;
1184 #endif
1186 void RenderThread::HandleDeviceReset(const char* aWhere, GLenum aReason) {
1187 MOZ_ASSERT(IsInRenderThread());
1189 // This happens only on simulate device reset.
1190 if (aReason == LOCAL_GL_NO_ERROR) {
1191 if (!mHandlingDeviceReset) {
1192 mHandlingDeviceReset = true;
1194 MutexAutoLock lock(mRenderTextureMapLock);
1195 mRenderTexturesDeferred.clear();
1196 for (const auto& entry : mRenderTextures) {
1197 entry.second->ClearCachedResources();
1200 // All RenderCompositors will be destroyed by the GPUProcessManager in
1201 // either OnRemoteProcessDeviceReset via the GPUChild, or
1202 // OnInProcessDeviceReset here directly.
1203 if (XRE_IsGPUProcess()) {
1204 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1205 } else {
1206 NS_DispatchToMainThread(NS_NewRunnableFunction(
1207 "gfx::GPUProcessManager::OnInProcessDeviceReset", []() -> void {
1208 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(
1209 /* aTrackThreshold */ false);
1210 }));
1213 return;
1216 if (mHandlingDeviceReset) {
1217 return;
1220 mHandlingDeviceReset = true;
1222 #ifndef XP_WIN
1223 // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices.
1224 gfx::GPUProcessManager::RecordDeviceReset(GLenumToResetReason(aReason));
1225 #endif
1228 MutexAutoLock lock(mRenderTextureMapLock);
1229 mRenderTexturesDeferred.clear();
1230 for (const auto& entry : mRenderTextures) {
1231 entry.second->ClearCachedResources();
1235 // All RenderCompositors will be destroyed by the GPUProcessManager in
1236 // either OnRemoteProcessDeviceReset via the GPUChild, or
1237 // OnInProcessDeviceReset here directly.
1238 // On Windows, device will be re-created before sessions re-creation.
1239 gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
1240 if (XRE_IsGPUProcess()) {
1241 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1242 } else {
1243 #ifndef XP_WIN
1244 // FIXME(aosmond): Do we need to do this on Windows? nsWindow::OnPaint
1245 // seems to do its own detection for the parent process.
1246 bool guilty = aReason == LOCAL_GL_GUILTY_CONTEXT_RESET_ARB;
1247 NS_DispatchToMainThread(NS_NewRunnableFunction(
1248 "gfx::GPUProcessManager::OnInProcessDeviceReset", [guilty]() -> void {
1249 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(guilty);
1250 }));
1251 #endif
1255 bool RenderThread::IsHandlingDeviceReset() {
1256 MOZ_ASSERT(IsInRenderThread());
1257 return mHandlingDeviceReset;
1260 void RenderThread::SimulateDeviceReset() {
1261 if (!IsInRenderThread()) {
1262 PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this,
1263 &RenderThread::SimulateDeviceReset));
1264 } else {
1265 // When this function is called GPUProcessManager::SimulateDeviceReset()
1266 // already triggers destroying all CompositorSessions before re-creating
1267 // them.
1268 HandleDeviceReset("SimulateDeviceReset", LOCAL_GL_NO_ERROR);
1272 static void DoNotifyWebRenderError(WebRenderError aError) {
1273 layers::CompositorManagerParent::NotifyWebRenderError(aError);
1276 void RenderThread::NotifyWebRenderError(WebRenderError aError) {
1277 MOZ_ASSERT(IsInRenderThread());
1279 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1280 "DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
1283 void RenderThread::HandleWebRenderError(WebRenderError aError) {
1284 MOZ_ASSERT(IsInRenderThread());
1285 if (mHandlingWebRenderError) {
1286 return;
1289 NotifyWebRenderError(aError);
1292 MutexAutoLock lock(mRenderTextureMapLock);
1293 mRenderTexturesDeferred.clear();
1294 for (const auto& entry : mRenderTextures) {
1295 entry.second->ClearCachedResources();
1298 mHandlingWebRenderError = true;
1299 // WebRender is going to be disabled by
1300 // GPUProcessManager::NotifyWebRenderError()
1303 bool RenderThread::IsHandlingWebRenderError() {
1304 MOZ_ASSERT(IsInRenderThread());
1305 return mHandlingWebRenderError;
1308 gl::GLContext* RenderThread::SingletonGL() {
1309 nsAutoCString err;
1310 auto* gl = SingletonGL(err);
1311 if (!err.IsEmpty()) {
1312 gfxCriticalNote << err.get();
1314 return gl;
1317 void RenderThread::CreateSingletonGL(nsACString& aError) {
1318 MOZ_ASSERT(IsInRenderThread());
1319 LOG("RenderThread::CreateSingletonGL()");
1321 mSingletonGL = CreateGLContext(aError);
1322 mSingletonGLIsForHardwareWebRender = !gfx::gfxVars::UseSoftwareWebRender();
1325 gl::GLContext* RenderThread::SingletonGL(nsACString& aError) {
1326 MOZ_ASSERT(IsInRenderThread());
1327 if (!mSingletonGL) {
1328 CreateSingletonGL(aError);
1329 mShaders = nullptr;
1331 if (mSingletonGL && mSingletonGLIsForHardwareWebRender && !mShaders) {
1332 mShaders = MakeUnique<WebRenderShaders>(mSingletonGL, mProgramCache.get());
1335 return mSingletonGL.get();
1338 gl::GLContext* RenderThread::SingletonGLForCompositorOGL() {
1339 MOZ_RELEASE_ASSERT(gfx::gfxVars::UseSoftwareWebRender());
1341 if (mSingletonGLIsForHardwareWebRender) {
1342 // Clear singleton GL, since GLContext is for hardware WebRender.
1343 ClearSingletonGL();
1345 return SingletonGL();
1348 void RenderThread::ClearSingletonGL() {
1349 MOZ_ASSERT(IsInRenderThread());
1350 LOG("RenderThread::ClearSingletonGL()");
1352 if (mSurfacePool) {
1353 mSurfacePool->DestroyGLResourcesForContext(mSingletonGL);
1355 if (mProgramsForCompositorOGL) {
1356 mProgramsForCompositorOGL->Clear();
1357 mProgramsForCompositorOGL = nullptr;
1359 if (mShaders) {
1360 if (mSingletonGL) {
1361 mSingletonGL->MakeCurrent();
1363 mShaders = nullptr;
1365 mSingletonGL = nullptr;
1368 RefPtr<layers::ShaderProgramOGLsHolder>
1369 RenderThread::GetProgramsForCompositorOGL() {
1370 if (!mSingletonGL) {
1371 return nullptr;
1374 if (!mProgramsForCompositorOGL) {
1375 mProgramsForCompositorOGL =
1376 MakeAndAddRef<layers::ShaderProgramOGLsHolder>(mSingletonGL);
1378 return mProgramsForCompositorOGL;
1381 RefPtr<layers::SurfacePool> RenderThread::SharedSurfacePool() {
1382 #if defined(XP_MACOSX) || defined(MOZ_WAYLAND)
1383 if (!mSurfacePool) {
1384 size_t poolSizeLimit =
1385 StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup();
1386 mSurfacePool = layers::SurfacePool::Create(poolSizeLimit);
1388 #endif
1389 return mSurfacePool;
1392 void RenderThread::ClearSharedSurfacePool() { mSurfacePool = nullptr; }
1394 static void GLAPIENTRY DebugMessageCallback(GLenum aSource, GLenum aType,
1395 GLuint aId, GLenum aSeverity,
1396 GLsizei aLength,
1397 const GLchar* aMessage,
1398 const GLvoid* aUserParam) {
1399 constexpr const char* kContextLost = "Context has been lost.";
1401 if (StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() &&
1402 aSeverity == LOCAL_GL_DEBUG_SEVERITY_HIGH) {
1403 auto message = std::string(aMessage, aLength);
1404 // When content lost happned, error messages are flooded by its message.
1405 if (message != kContextLost) {
1406 gfxCriticalNote << message;
1407 } else {
1408 gfxCriticalNoteOnce << message;
1412 if (StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup()) {
1413 gl::GLContext* gl = (gl::GLContext*)aUserParam;
1414 gl->DebugCallback(aSource, aType, aId, aSeverity, aLength, aMessage);
1418 // static
1419 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext* aGLContext) {
1420 if (!aGLContext) {
1421 return;
1424 bool enableDebugMessage =
1425 StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() ||
1426 StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup();
1428 if (enableDebugMessage &&
1429 aGLContext->IsExtensionSupported(gl::GLContext::KHR_debug)) {
1430 aGLContext->fEnable(LOCAL_GL_DEBUG_OUTPUT);
1431 aGLContext->fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
1432 aGLContext->fDebugMessageCallback(&DebugMessageCallback, (void*)aGLContext);
1433 aGLContext->fDebugMessageControl(LOCAL_GL_DONT_CARE, LOCAL_GL_DONT_CARE,
1434 LOCAL_GL_DONT_CARE, 0, nullptr, true);
1438 WebRenderShaders::WebRenderShaders(gl::GLContext* gl,
1439 WebRenderProgramCache* programCache) {
1440 mGL = gl;
1441 mShaders =
1442 wr_shaders_new(gl, programCache ? programCache->Raw() : nullptr,
1443 StaticPrefs::gfx_webrender_precache_shaders_AtStartup());
1446 WebRenderShaders::~WebRenderShaders() {
1447 wr_shaders_delete(mShaders, mGL.get());
1450 WebRenderThreadPool::WebRenderThreadPool(bool low_priority) {
1451 mThreadPool = wr_thread_pool_new(low_priority);
1454 WebRenderThreadPool::~WebRenderThreadPool() { Release(); }
1456 void WebRenderThreadPool::Release() {
1457 if (mThreadPool) {
1458 wr_thread_pool_delete(mThreadPool);
1459 mThreadPool = nullptr;
1463 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) {
1464 MOZ_ASSERT(aThreadPool);
1466 nsAutoString path;
1467 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1468 path.Append(gfx::gfxVars::ProfDirectory());
1470 mProgramCache = wr_program_cache_new(&path, aThreadPool);
1471 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1472 wr_try_load_startup_shaders_from_disk(mProgramCache);
1476 WebRenderProgramCache::~WebRenderProgramCache() {
1477 wr_program_cache_delete(mProgramCache);
1480 } // namespace mozilla::wr
1482 #ifdef XP_WIN
1483 static already_AddRefed<gl::GLContext> CreateGLContextANGLE(
1484 nsACString& aError) {
1485 const RefPtr<ID3D11Device> d3d11Device =
1486 gfx::DeviceManagerDx::Get()->GetCompositorDevice();
1487 if (!d3d11Device) {
1488 aError.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns);
1489 return nullptr;
1492 nsCString failureId;
1493 const auto lib = gl::GLLibraryEGL::Get(&failureId);
1494 if (!lib) {
1495 aError.Assign(
1496 nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get()));
1497 return nullptr;
1500 const auto egl = lib->CreateDisplay(d3d11Device.get());
1501 if (!egl) {
1502 aError.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
1503 failureId.get()));
1504 return nullptr;
1507 gl::CreateContextFlags flags = gl::CreateContextFlags::PREFER_ES3;
1509 if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
1510 flags |= gl::CreateContextFlags::PREFER_ROBUSTNESS;
1513 if (egl->IsExtensionSupported(
1514 gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
1515 flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE;
1518 // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
1519 // Instread we override it with EGLSurface of SwapChain's back buffer.
1521 auto gl = gl::GLContextEGL::CreateWithoutSurface(egl, {flags}, &failureId);
1522 if (!gl || !gl->IsANGLE()) {
1523 aError.Assign(nsPrintfCString("RcANGLE(create GL context failed: %p, %s)",
1524 gl.get(), failureId.get()));
1525 return nullptr;
1528 if (!gl->MakeCurrent()) {
1529 aError.Assign(
1530 nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)",
1531 gl.get(), gl->mEgl->mLib->fGetError()));
1532 return nullptr;
1535 return gl.forget();
1537 #endif
1539 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
1540 static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
1541 // Create GLContext with dummy EGLSurface.
1542 bool forHardwareWebRender = true;
1543 // SW-WR uses CompositorOGL in native compositor.
1544 if (gfx::gfxVars::UseSoftwareWebRender()) {
1545 forHardwareWebRender = false;
1547 RefPtr<gl::GLContext> gl =
1548 gl::GLContextProviderEGL::CreateForCompositorWidget(
1549 nullptr, forHardwareWebRender, /* aForceAccelerated */ true);
1550 if (!gl || !gl->MakeCurrent()) {
1551 gfxCriticalNote << "Failed GL context creation for hardware WebRender: "
1552 << forHardwareWebRender;
1553 return nullptr;
1555 return gl.forget();
1557 #endif
1559 #ifdef XP_MACOSX
1560 static already_AddRefed<gl::GLContext> CreateGLContextCGL() {
1561 nsCString failureUnused;
1562 return gl::GLContextProvider::CreateHeadless(
1563 {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
1564 gl::CreateContextFlags::FORBID_SOFTWARE},
1565 &failureUnused);
1567 #endif
1569 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) {
1570 RefPtr<gl::GLContext> gl;
1572 #ifdef XP_WIN
1573 if (gfx::gfxVars::UseWebRenderANGLE()) {
1574 gl = CreateGLContextANGLE(aError);
1576 #elif defined(MOZ_WIDGET_ANDROID)
1577 gl = CreateGLContextEGL();
1578 #elif defined(MOZ_WIDGET_GTK)
1579 if (gfx::gfxVars::UseEGL()) {
1580 gl = CreateGLContextEGL();
1582 #elif XP_MACOSX
1583 gl = CreateGLContextCGL();
1584 #endif
1586 wr::RenderThread::MaybeEnableGLDebugMessage(gl);
1588 return gl.forget();
1591 extern "C" {
1593 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId,
1594 bool aCompositeNeeded) {
1595 // wake_up is used for things like propagating debug options or memory
1596 // pressure events, so we are not tracking pending frame counts.
1597 mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId,
1598 aCompositeNeeded);
1601 void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId,
1602 bool aCompositeNeeded,
1603 mozilla::wr::FramePublishId aPublishId) {
1604 auto* renderThread = mozilla::wr::RenderThread::Get();
1605 renderThread->DecPendingFrameBuildCount(aWindowId);
1607 renderThread->WrNotifierEvent_NewFrameReady(aWindowId, aCompositeNeeded,
1608 aPublishId);
1611 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
1612 size_t aRawEvent) {
1613 mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent(
1614 mozilla::wr::WindowId(aWindowId), aRawEvent);
1617 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,
1618 wr::RenderReasons aReasons) {
1619 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1620 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1621 if (cbp) {
1622 cbp->ScheduleComposition(aReasons);
1626 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
1627 wr::RenderReasons aReasons) {
1628 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1629 "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons));
1632 static void NotifyDidSceneBuild(
1633 mozilla::wr::WrWindowId aWindowId,
1634 const RefPtr<const wr::WebRenderPipelineInfo>& aInfo) {
1635 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1636 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1637 if (cbp) {
1638 cbp->NotifyDidSceneBuild(aInfo);
1642 void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,
1643 mozilla::wr::WrPipelineInfo* aPipelineInfo) {
1644 RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo();
1645 info->Raw() = std::move(*aPipelineInfo);
1646 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1647 "NotifyDidSceneBuild", &NotifyDidSceneBuild, aWindowId, info));
1650 } // extern C