Bug 1874684 - Part 28: Return DateDuration from DifferenceISODateTime. r=mgaudet
[gecko.git] / gfx / webrender_bindings / RenderThread.cpp
blobe1a41ee225c443a2d292dba5c32f2867d5265464
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
73 size_t RenderThread::sRendererCount = 0;
74 size_t RenderThread::sActiveRendererCount = 0;
76 RenderThread::RenderThread(RefPtr<nsIThread> aThread)
77 : mThread(std::move(aThread)),
78 mThreadPool(false),
79 mThreadPoolLP(true),
80 mSingletonGLIsForHardwareWebRender(true),
81 mBatteryInfo("RenderThread.mBatteryInfo"),
82 mWindowInfos("RenderThread.mWindowInfos"),
83 mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
84 mHasShutdown(false),
85 mHandlingDeviceReset(false),
86 mHandlingWebRenderError(false) {}
88 RenderThread::~RenderThread() { MOZ_ASSERT(mRenderTexturesDeferred.empty()); }
90 // static
91 RenderThread* RenderThread::Get() { return sRenderThread; }
93 // static
94 void RenderThread::Start(uint32_t aNamespace) {
95 MOZ_ASSERT(NS_IsMainThread());
96 MOZ_ASSERT(!sRenderThread);
98 #ifdef DEBUG
99 // Check to ensure nobody will try to ever start us more than once during
100 // the process' lifetime (in particular after ShutDown).
101 MOZ_ASSERT(!sRenderThreadEverStarted);
102 sRenderThreadEverStarted = true;
103 #endif
105 // When the CanvasRenderer thread is disabled, WebGL may be handled on this
106 // thread, requiring a bigger stack size. See: CanvasManagerParent::Init
108 // This is 4M, which is higher than the default 256K.
109 // Increased with bug 1753349 to accommodate the `chromium/5359` branch of
110 // ANGLE, which has large peak stack usage for some pathological shader
111 // compilations.
113 // Previously increased to 512K to accommodate Mesa in bug 1753340.
115 // Previously increased to 320K to avoid a stack overflow in the
116 // Intel Vulkan driver initialization in bug 1716120.
118 // Note: we only override it if it's limited already.
119 uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE;
120 if (stackSize && !gfx::gfxVars::SupportsThreadsafeGL()) {
121 stackSize = std::max(stackSize, 4096U << 10);
124 RefPtr<nsIThread> thread;
125 nsresult rv = NS_NewNamedThread(
126 "Renderer", getter_AddRefs(thread),
127 NS_NewRunnableFunction(
128 "Renderer::BackgroundHanSetup",
129 []() {
130 sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor(
131 "Render",
132 /* Timeout values are powers-of-two to enable us get better
133 data. 128ms is chosen for transient hangs because 8Hz should
134 be the minimally acceptable goal for Render
135 responsiveness (normal goal is 60Hz). */
136 128,
137 /* 2048ms is chosen for permanent hangs because it's longer than
138 * most Render hangs seen in the wild, but is short enough
139 * to not miss getting native hang stacks. */
140 2048);
141 nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
142 nsThread* nsthread = static_cast<nsThread*>(thread.get());
143 nsthread->SetUseHangMonitor(true);
144 nsthread->SetPriority(nsISupportsPriority::PRIORITY_HIGH);
146 {.stackSize = stackSize});
148 if (NS_FAILED(rv)) {
149 gfxCriticalNote << "Failed to create Renderer thread: "
150 << gfx::hexa((uint32_t)rv);
151 return;
154 sRenderThread = new RenderThread(thread);
155 CrashReporter::RegisterAnnotationUSize(
156 CrashReporter::Annotation::GraphicsNumRenderers, &sRendererCount);
157 CrashReporter::RegisterAnnotationUSize(
158 CrashReporter::Annotation::GraphicsNumActiveRenderers,
159 &sActiveRendererCount);
160 #ifdef XP_WIN
161 widget::WinCompositorWindowThread::Start();
162 #endif
163 layers::SharedSurfacesParent::Initialize();
165 RefPtr<Runnable> runnable = WrapRunnable(
166 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::InitDeviceTask);
167 sRenderThread->PostRunnable(runnable.forget());
170 // static
171 void RenderThread::ShutDown() {
172 MOZ_ASSERT(NS_IsMainThread());
173 MOZ_ASSERT(sRenderThread);
176 MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
177 sRenderThread->mHasShutdown = true;
180 RefPtr<Runnable> runnable = WrapRunnable(
181 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::ShutDownTask);
182 sRenderThread->PostRunnable(runnable.forget());
184 // This will empty the thread queue and thus run the above runnable while
185 // spinning the MT event loop.
186 nsCOMPtr<nsIThread> oldThread = sRenderThread->GetRenderThread();
187 oldThread->Shutdown();
189 layers::SharedSurfacesParent::Shutdown();
191 #ifdef XP_WIN
192 if (widget::WinCompositorWindowThread::Get()) {
193 widget::WinCompositorWindowThread::ShutDown();
195 #endif
197 // We null this out only after we finished shutdown to give everbody the
198 // chance to check for sRenderThread->mHasShutdown. Hopefully everybody
199 // checks this before using us!
200 sRenderThread = nullptr;
203 extern void ClearAllBlobImageResources();
205 void RenderThread::ShutDownTask() {
206 MOZ_ASSERT(IsInRenderThread());
207 LOG("RenderThread::ShutDownTask()");
210 // Clear RenderTextureHosts
211 MutexAutoLock lock(mRenderTextureMapLock);
212 mRenderTexturesDeferred.clear();
213 mRenderTextures.clear();
214 mSyncObjectNeededRenderTextures.clear();
215 mRenderTextureOps.clear();
218 // Let go of our handle to the (internally ref-counted) thread pool.
219 mThreadPool.Release();
220 mThreadPoolLP.Release();
222 // Releasing on the render thread will allow us to avoid dispatching to remove
223 // remaining textures from the texture map.
224 layers::SharedSurfacesParent::ShutdownRenderThread();
226 #ifdef XP_WIN
227 DCLayerTree::Shutdown();
228 #endif
230 ClearAllBlobImageResources();
231 ClearSingletonGL();
232 ClearSharedSurfacePool();
235 // static
236 bool RenderThread::IsInRenderThread() {
237 return sRenderThread && sRenderThread->mThread == NS_GetCurrentThread();
240 // static
241 already_AddRefed<nsIThread> RenderThread::GetRenderThread() {
242 nsCOMPtr<nsIThread> thread;
243 if (sRenderThread) {
244 thread = sRenderThread->mThread;
246 return thread.forget();
249 void RenderThread::DoAccumulateMemoryReport(
250 MemoryReport aReport,
251 const RefPtr<MemoryReportPromise::Private>& aPromise) {
252 MOZ_ASSERT(IsInRenderThread());
254 for (auto& r : mRenderers) {
255 r.second->AccumulateMemoryReport(&aReport);
258 // Note memory used by the shader cache, which is shared across all WR
259 // instances.
260 MOZ_ASSERT(aReport.shader_cache == 0);
261 if (mProgramCache) {
262 aReport.shader_cache = wr_program_cache_report_memory(
263 mProgramCache->Raw(), &WebRenderRendererMallocSizeOf);
266 size_t renderTextureMemory = 0;
268 MutexAutoLock lock(mRenderTextureMapLock);
269 for (const auto& entry : mRenderTextures) {
270 renderTextureMemory += entry.second->Bytes();
273 aReport.render_texture_hosts = renderTextureMemory;
275 aPromise->Resolve(aReport, __func__);
278 // static
279 RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport(
280 MemoryReport aInitial) {
281 RefPtr<MemoryReportPromise::Private> p =
282 new MemoryReportPromise::Private(__func__);
283 MOZ_ASSERT(!IsInRenderThread());
284 if (!Get()) {
285 // This happens when the GPU process fails to start and we fall back to the
286 // basic compositor in the parent process. We could assert against this if
287 // we made the webrender detection code in gfxPlatform.cpp smarter. See bug
288 // 1494430 comment 12.
289 NS_WARNING("No render thread, returning empty memory report");
290 p->Resolve(aInitial, __func__);
291 return p;
294 Get()->PostRunnable(
295 NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>(
296 "wr::RenderThread::DoAccumulateMemoryReport", Get(),
297 &RenderThread::DoAccumulateMemoryReport, aInitial, p));
299 return p;
302 void RenderThread::SetBatteryInfo(const hal::BatteryInformation& aBatteryInfo) {
303 MOZ_ASSERT(XRE_IsGPUProcess());
305 auto batteryInfo = mBatteryInfo.Lock();
306 batteryInfo.ref() = Some(aBatteryInfo);
309 bool RenderThread::GetPowerIsCharging() {
310 MOZ_ASSERT(XRE_IsGPUProcess());
312 auto batteryInfo = mBatteryInfo.Lock();
313 if (batteryInfo.ref().isSome()) {
314 return batteryInfo.ref().ref().charging();
317 gfxCriticalNoteOnce << "BatteryInfo is not set";
318 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
319 return false;
322 void RenderThread::AddRenderer(wr::WindowId aWindowId,
323 UniquePtr<RendererOGL> aRenderer) {
324 MOZ_ASSERT(IsInRenderThread());
325 LOG("RenderThread::AddRenderer() aWindowId %" PRIx64 "", AsUint64(aWindowId));
327 if (mHasShutdown) {
328 return;
331 mRenderers[aWindowId] = std::move(aRenderer);
332 sRendererCount = mRenderers.size();
334 auto windows = mWindowInfos.Lock();
335 windows->emplace(AsUint64(aWindowId), new WindowInfo());
336 mWrNotifierEventsQueues.emplace(AsUint64(aWindowId),
337 new std::queue<WrNotifierEvent>);
340 void RenderThread::RemoveRenderer(wr::WindowId aWindowId) {
341 MOZ_ASSERT(IsInRenderThread());
342 LOG("RenderThread::RemoveRenderer() aWindowId %" PRIx64 "",
343 AsUint64(aWindowId));
345 if (mHasShutdown) {
346 return;
349 mRenderers.erase(aWindowId);
350 sRendererCount = mRenderers.size();
352 if (mRenderers.empty()) {
353 if (mHandlingDeviceReset) {
354 ClearSingletonGL();
356 mHandlingDeviceReset = false;
357 mHandlingWebRenderError = false;
360 auto windows = mWindowInfos.Lock();
361 auto it = windows->find(AsUint64(aWindowId));
362 MOZ_ASSERT(it != windows->end());
363 windows->erase(it);
365 // Defer std::deque<WrNotifierEvent> remove, RemoveRenderer() is called in
366 // HandleWrNotifierEvents().
367 RefPtr<Runnable> runnable =
368 NS_NewRunnableFunction("RenderThread::RemoveRenderer", [aWindowId]() {
369 auto* self = RenderThread::Get();
370 auto it = self->mWrNotifierEventsQueues.find(AsUint64(aWindowId));
371 if (it == self->mWrNotifierEventsQueues.end()) {
372 return;
374 self->mWrNotifierEventsQueues.erase(it);
376 RenderThread::Get()->PostRunnable(runnable.forget());
379 RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) {
380 MOZ_ASSERT(IsInRenderThread());
382 auto it = mRenderers.find(aWindowId);
383 MOZ_ASSERT(it != mRenderers.end());
385 if (it == mRenderers.end()) {
386 return nullptr;
389 return it->second.get();
392 size_t RenderThread::RendererCount() const {
393 MOZ_ASSERT(IsInRenderThread());
394 return mRenderers.size();
397 void RenderThread::UpdateActiveRendererCount() {
398 MOZ_ASSERT(IsInRenderThread());
399 size_t num_active = 0;
400 for (const auto& it : mRenderers) {
401 if (!it.second->IsPaused()) {
402 num_active++;
405 sActiveRendererCount = num_active;
408 void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId,
409 bool aCompositeNeeded) {
410 auto windows = mWindowInfos.Lock();
411 auto it = windows->find(AsUint64(aWindowId));
412 if (it == windows->end()) {
413 MOZ_ASSERT(false);
414 return;
417 WindowInfo* info = it->second.get();
419 info->mPendingWrNotifierEvents.emplace(
420 WrNotifierEvent::WakeUp(aCompositeNeeded));
421 PostWrNotifierEvents(aWindowId, info);
424 void RenderThread::WrNotifierEvent_NewFrameReady(WrWindowId aWindowId,
425 bool aCompositeNeeded,
426 FramePublishId aPublishId) {
427 auto windows = mWindowInfos.Lock();
428 auto it = windows->find(AsUint64(aWindowId));
429 if (it == windows->end()) {
430 MOZ_ASSERT(false);
431 return;
433 WindowInfo* info = it->second.get();
435 info->mPendingWrNotifierEvents.emplace(
436 WrNotifierEvent::NewFrameReady(aCompositeNeeded, aPublishId));
437 PostWrNotifierEvents(aWindowId, info);
440 void RenderThread::WrNotifierEvent_ExternalEvent(WrWindowId aWindowId,
441 size_t aRawEvent) {
442 UniquePtr<RendererEvent> evt(reinterpret_cast<RendererEvent*>(aRawEvent));
444 auto windows = mWindowInfos.Lock();
445 auto it = windows->find(AsUint64(aWindowId));
446 if (it == windows->end()) {
447 MOZ_ASSERT(false);
448 return;
450 WindowInfo* info = it->second.get();
452 info->mPendingWrNotifierEvents.emplace(
453 WrNotifierEvent::ExternalEvent(std::move(evt)));
454 PostWrNotifierEvents(aWindowId, info);
458 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId) {
460 auto windows = mWindowInfos.Lock();
461 auto it = windows->find(AsUint64(aWindowId));
462 if (it == windows->end()) {
463 MOZ_ASSERT(false);
464 return;
466 WindowInfo* info = it->second.get();
467 PostWrNotifierEvents(aWindowId, info);
471 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId,
472 WindowInfo* aInfo) {
473 // Runnable has already been triggered.
474 if (aInfo->mWrNotifierEventsRunnable) {
475 return;
478 // Runnable has not been triggered yet.
479 RefPtr<nsIRunnable> runnable = NewRunnableMethod<WrWindowId>(
480 "RenderThread::HandleWrNotifierEvents", this,
481 &RenderThread::HandleWrNotifierEvents, aWindowId);
482 aInfo->mWrNotifierEventsRunnable = runnable;
483 PostRunnable(runnable.forget());
486 void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId) {
487 MOZ_ASSERT(IsInRenderThread());
489 auto eventsIt = mWrNotifierEventsQueues.find(AsUint64(aWindowId));
490 if (eventsIt == mWrNotifierEventsQueues.end()) {
491 return;
493 auto* events = eventsIt->second.get();
496 auto windows = mWindowInfos.Lock();
497 auto infoIt = windows->find(AsUint64(aWindowId));
498 if (infoIt == windows->end()) {
499 MOZ_ASSERT(false);
500 return;
502 WindowInfo* info = infoIt->second.get();
503 info->mWrNotifierEventsRunnable = nullptr;
505 if (events->empty() && !info->mPendingWrNotifierEvents.empty()) {
506 events->swap(info->mPendingWrNotifierEvents);
510 bool handleNext = true;
512 while (!events->empty() && handleNext) {
513 auto& front = events->front();
514 switch (front.mTag) {
515 case WrNotifierEvent::Tag::WakeUp:
516 WrNotifierEvent_HandleWakeUp(aWindowId, front.CompositeNeeded());
517 handleNext = false;
518 break;
519 case WrNotifierEvent::Tag::NewFrameReady:
520 WrNotifierEvent_HandleNewFrameReady(aWindowId, front.CompositeNeeded(),
521 front.PublishId());
522 handleNext = false;
523 break;
524 case WrNotifierEvent::Tag::ExternalEvent:
525 WrNotifierEvent_HandleExternalEvent(aWindowId, front.ExternalEvent());
526 break;
528 events->pop();
532 auto windows = mWindowInfos.Lock();
533 auto it = windows->find(AsUint64(aWindowId));
534 if (it == windows->end()) {
535 return;
537 WindowInfo* info = it->second.get();
539 if (!events->empty() || !info->mPendingWrNotifierEvents.empty()) {
540 PostWrNotifierEvents(aWindowId, info);
545 void RenderThread::WrNotifierEvent_HandleWakeUp(wr::WindowId aWindowId,
546 bool aCompositeNeeded) {
547 MOZ_ASSERT(IsInRenderThread());
549 bool isTrackedFrame = false;
550 HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame, Nothing());
553 void RenderThread::WrNotifierEvent_HandleNewFrameReady(
554 wr::WindowId aWindowId, bool aCompositeNeeded, FramePublishId aPublishId) {
555 MOZ_ASSERT(IsInRenderThread());
557 bool isTrackedFrame = true;
558 HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame,
559 Some(aPublishId));
562 void RenderThread::WrNotifierEvent_HandleExternalEvent(
563 wr::WindowId aWindowId, UniquePtr<RendererEvent> aRendererEvent) {
564 MOZ_ASSERT(IsInRenderThread());
566 RunEvent(aWindowId, std::move(aRendererEvent));
569 void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId,
570 const TimeStamp& aRecordingStart,
571 wr::PipelineId aRootPipelineId) {
572 MOZ_ASSERT(IsInRenderThread());
573 RendererOGL* renderer = GetRenderer(aWindowId);
574 MOZ_ASSERT(renderer);
576 renderer->BeginRecording(aRecordingStart, aRootPipelineId);
579 Maybe<layers::FrameRecording> RenderThread::EndRecordingForWindow(
580 wr::WindowId aWindowId) {
581 MOZ_ASSERT(IsInRenderThread());
583 RendererOGL* renderer = GetRenderer(aWindowId);
584 MOZ_ASSERT(renderer);
585 return renderer->EndRecording();
588 void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender,
589 bool aTrackedFrame,
590 Maybe<FramePublishId> aPublishId) {
591 MOZ_ASSERT(IsInRenderThread());
593 if (mHasShutdown) {
594 return;
597 HandleFrameOneDocInner(aWindowId, aRender, aTrackedFrame, aPublishId);
599 if (aTrackedFrame) {
600 DecPendingFrameCount(aWindowId);
604 void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId, bool aRender,
605 bool aTrackedFrame,
606 Maybe<FramePublishId> aPublishId) {
607 if (IsDestroyed(aWindowId)) {
608 return;
611 if (mHandlingDeviceReset) {
612 return;
615 bool render = aRender;
616 PendingFrameInfo frame;
617 if (aTrackedFrame) {
618 // scope lock
619 auto windows = mWindowInfos.Lock();
620 auto it = windows->find(AsUint64(aWindowId));
621 if (it == windows->end()) {
622 MOZ_ASSERT(false);
623 return;
626 WindowInfo* info = it->second.get();
627 PendingFrameInfo& frameInfo = info->mPendingFrames.front();
629 frame = frameInfo;
630 } else {
631 // Just give the frame info default values.
632 frame = {TimeStamp::Now(), VsyncId()};
635 // Sadly this doesn't include the lock, since we don't have the frame there
636 // yet.
637 glean::wr::time_to_render_start.AccumulateRawDuration(TimeStamp::Now() -
638 frame.mStartTime);
640 // It is for ensuring that PrepareForUse() is called before
641 // RenderTextureHost::Lock().
642 HandleRenderTextureOps();
644 if (aPublishId.isSome()) {
645 SetFramePublishId(aWindowId, aPublishId.ref());
648 UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, render,
649 /* aReadbackSize */ Nothing(),
650 /* aReadbackFormat */ Nothing(),
651 /* aReadbackBuffer */ Nothing());
653 // The start time is from WebRenderBridgeParent::CompositeToTarget. From that
654 // point until now (when the frame is finally pushed to the screen) is
655 // equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
656 TimeDuration compositeDuration = TimeStamp::Now() - frame.mStartTime;
657 mozilla::glean::gfx::composite_time.AccumulateRawDuration(compositeDuration);
658 PerfStats::RecordMeasurement(PerfStats::Metric::Compositing,
659 compositeDuration);
662 void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) {
663 if (mHasShutdown) {
664 return;
667 if (!IsInRenderThread()) {
668 PostRunnable(NewRunnableMethod<wr::WindowId, wr::ColorF>(
669 "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor,
670 aWindowId, aColor));
671 return;
674 if (IsDestroyed(aWindowId)) {
675 return;
678 auto it = mRenderers.find(aWindowId);
679 MOZ_ASSERT(it != mRenderers.end());
680 if (it != mRenderers.end()) {
681 wr_renderer_set_clear_color(it->second->GetRenderer(), aColor);
685 void RenderThread::SetProfilerUI(wr::WindowId aWindowId,
686 const nsACString& aUI) {
687 if (mHasShutdown) {
688 return;
691 if (!IsInRenderThread()) {
692 PostRunnable(NewRunnableMethod<wr::WindowId, nsCString>(
693 "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI,
694 aWindowId, nsCString(aUI)));
695 return;
698 auto it = mRenderers.find(aWindowId);
699 if (it != mRenderers.end()) {
700 it->second->SetProfilerUI(aUI);
704 void RenderThread::PostEvent(wr::WindowId aWindowId,
705 UniquePtr<RendererEvent> aEvent) {
706 PostRunnable(NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
707 "wr::RenderThread::PostEvent", this, &RenderThread::RunEvent, aWindowId,
708 std::move(aEvent)));
711 void RenderThread::RunEvent(wr::WindowId aWindowId,
712 UniquePtr<RendererEvent> aEvent) {
713 MOZ_ASSERT(IsInRenderThread());
715 aEvent->Run(*this, aWindowId);
716 aEvent = nullptr;
719 static void NotifyDidRender(layers::CompositorBridgeParent* aBridge,
720 const RefPtr<const WebRenderPipelineInfo>& aInfo,
721 VsyncId aCompositeStartId,
722 TimeStamp aCompositeStart, TimeStamp aRenderStart,
723 TimeStamp aEnd, bool aRender,
724 RendererStats aStats) {
725 if (aRender && aBridge->GetWrBridge()) {
726 // We call this here to mimic the behavior in LayerManagerComposite, as to
727 // not change what Talos measures. That is, we do not record an empty frame
728 // as a frame.
729 aBridge->GetWrBridge()->RecordFrame();
732 aBridge->NotifyDidRender(aCompositeStartId, aCompositeStart, aRenderStart,
733 aEnd, &aStats);
735 for (const auto& epoch : aInfo->Raw().epochs) {
736 aBridge->NotifyPipelineRendered(epoch.pipeline_id, epoch.epoch,
737 aCompositeStartId, aCompositeStart,
738 aRenderStart, aEnd, &aStats);
741 if (aBridge->GetWrBridge()) {
742 aBridge->GetWrBridge()->RetrySkippedComposite();
746 static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) {
747 if (aBridge->GetWrBridge()) {
748 aBridge->GetWrBridge()->RetrySkippedComposite();
752 void RenderThread::SetFramePublishId(wr::WindowId aWindowId,
753 FramePublishId aPublishId) {
754 MOZ_ASSERT(IsInRenderThread());
756 auto it = mRenderers.find(aWindowId);
757 MOZ_ASSERT(it != mRenderers.end());
758 if (it == mRenderers.end()) {
759 return;
761 auto& renderer = it->second;
763 renderer->SetFramePublishId(aPublishId);
766 void RenderThread::UpdateAndRender(
767 wr::WindowId aWindowId, const VsyncId& aStartId,
768 const TimeStamp& aStartTime, bool aRender,
769 const Maybe<gfx::IntSize>& aReadbackSize,
770 const Maybe<wr::ImageFormat>& aReadbackFormat,
771 const Maybe<Range<uint8_t>>& aReadbackBuffer, bool* aNeedsYFlip) {
772 AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS);
773 MOZ_ASSERT(IsInRenderThread());
774 MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
776 auto it = mRenderers.find(aWindowId);
777 MOZ_ASSERT(it != mRenderers.end());
778 if (it == mRenderers.end()) {
779 return;
782 TimeStamp start = TimeStamp::Now();
784 auto& renderer = it->second;
786 std::string markerName = "Composite #" + std::to_string(AsUint64(aWindowId));
787 AutoProfilerTracing tracingCompositeMarker(
788 "Paint", markerName.c_str(), geckoprofiler::category::GRAPHICS,
789 Some(renderer->GetCompositorBridge()->GetInnerWindowId()));
791 if (renderer->IsPaused()) {
792 aRender = false;
794 LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64 " aRender %d",
795 AsUint64(aWindowId), aRender);
797 layers::CompositorThread()->Dispatch(
798 NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender,
799 renderer->GetCompositorBridge()));
801 wr::RenderedFrameId latestFrameId;
802 RendererStats stats = {0};
803 if (aRender) {
804 latestFrameId = renderer->UpdateAndRender(
805 aReadbackSize, aReadbackFormat, aReadbackBuffer, aNeedsYFlip, &stats);
806 } else {
807 renderer->Update();
809 // Check graphics reset status even when rendering is skipped.
810 renderer->CheckGraphicsResetStatus("PostUpdate", /* aForce */ false);
812 TimeStamp end = TimeStamp::Now();
813 RefPtr<const WebRenderPipelineInfo> info = renderer->GetLastPipelineInfo();
815 layers::CompositorThread()->Dispatch(
816 NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
817 renderer->GetCompositorBridge(), info, aStartId,
818 aStartTime, start, end, aRender, stats));
820 ipc::FileDescriptor fenceFd;
822 if (latestFrameId.IsValid()) {
823 fenceFd = renderer->GetAndResetReleaseFence();
825 // Wait for GPU after posting NotifyDidRender, since the wait is not
826 // necessary for the NotifyDidRender.
827 // The wait is necessary for Textures recycling of AsyncImagePipelineManager
828 // and for avoiding GPU queue is filled with too much tasks.
829 // WaitForGPU's implementation is different for each platform.
830 auto timerId = glean::wr::gpu_wait_time.Start();
831 renderer->WaitForGPU();
832 glean::wr::gpu_wait_time.StopAndAccumulate(std::move(timerId));
833 } else {
834 // Update frame id for NotifyPipelinesUpdated() when rendering does not
835 // happen, either because rendering was not requested or the frame was
836 // canceled. Rendering can sometimes be canceled if UpdateAndRender is
837 // called when the window is not yet ready (not mapped or 0 size).
838 latestFrameId = renderer->UpdateFrameId();
841 RenderedFrameId lastCompletedFrameId = renderer->GetLastCompletedFrameId();
843 RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
844 renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
845 // pipelineMgr should always be non-null here because it is only nulled out
846 // after the WebRenderAPI instance for the CompositorBridgeParent is
847 // destroyed, and that destruction blocks until the renderer thread has
848 // removed the relevant renderer. And after that happens we should never reach
849 // this code at all; it would bail out at the mRenderers.find check above.
850 MOZ_ASSERT(pipelineMgr);
851 pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId,
852 std::move(fenceFd));
855 void RenderThread::Pause(wr::WindowId aWindowId) {
856 MOZ_ASSERT(IsInRenderThread());
857 LOG("RenderThread::Pause() aWindowId %" PRIx64 "", AsUint64(aWindowId));
859 auto it = mRenderers.find(aWindowId);
860 MOZ_ASSERT(it != mRenderers.end());
861 if (it == mRenderers.end()) {
862 gfxCriticalNote << "RenderThread cannot find renderer for window "
863 << gfx::hexa(aWindowId) << " to pause.";
864 return;
866 auto& renderer = it->second;
867 renderer->Pause();
869 UpdateActiveRendererCount();
872 bool RenderThread::Resume(wr::WindowId aWindowId) {
873 MOZ_ASSERT(IsInRenderThread());
874 LOG("enderThread::Resume() aWindowId %" PRIx64 "", AsUint64(aWindowId));
876 auto it = mRenderers.find(aWindowId);
877 MOZ_ASSERT(it != mRenderers.end());
878 if (it == mRenderers.end()) {
879 gfxCriticalNote << "RenderThread cannot find renderer for window "
880 << gfx::hexa(aWindowId) << " to resume.";
881 return false;
883 auto& renderer = it->second;
884 bool resumed = renderer->Resume();
886 UpdateActiveRendererCount();
888 return resumed;
891 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) {
892 const int64_t maxFrameCount = 1;
894 // Too many pending frames if pending frames exit more than maxFrameCount
895 // or if RenderBackend is still processing a frame.
897 auto windows = mWindowInfos.Lock();
898 auto it = windows->find(AsUint64(aWindowId));
899 if (it == windows->end()) {
900 MOZ_ASSERT(false);
901 return true;
903 WindowInfo* info = it->second.get();
905 if (info->PendingCount() > maxFrameCount) {
906 return true;
908 // If there is no ongoing frame build, we accept a new frame.
909 return info->mPendingFrameBuild > 0;
912 bool RenderThread::IsDestroyed(wr::WindowId aWindowId) {
913 auto windows = mWindowInfos.Lock();
914 auto it = windows->find(AsUint64(aWindowId));
915 if (it == windows->end()) {
916 return true;
919 return it->second->mIsDestroyed;
922 void RenderThread::SetDestroyed(wr::WindowId aWindowId) {
923 auto windows = mWindowInfos.Lock();
924 auto it = windows->find(AsUint64(aWindowId));
925 if (it == windows->end()) {
926 MOZ_ASSERT(false);
927 return;
929 it->second->mIsDestroyed = true;
932 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId,
933 const VsyncId& aStartId,
934 const TimeStamp& aStartTime) {
935 auto windows = mWindowInfos.Lock();
936 auto it = windows->find(AsUint64(aWindowId));
937 if (it == windows->end()) {
938 MOZ_ASSERT(false);
939 return;
941 it->second->mPendingFrameBuild++;
942 it->second->mPendingFrames.push(PendingFrameInfo{aStartTime, aStartId});
945 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId) {
946 auto windows = mWindowInfos.Lock();
947 auto it = windows->find(AsUint64(aWindowId));
948 if (it == windows->end()) {
949 MOZ_ASSERT(false);
950 return;
952 WindowInfo* info = it->second.get();
953 MOZ_RELEASE_ASSERT(info->mPendingFrameBuild >= 1);
954 info->mPendingFrameBuild--;
957 void RenderThread::DecPendingFrameCount(wr::WindowId aWindowId) {
958 auto windows = mWindowInfos.Lock();
959 auto it = windows->find(AsUint64(aWindowId));
960 if (it == windows->end()) {
961 MOZ_ASSERT(false);
962 return;
964 WindowInfo* info = it->second.get();
965 info->mPendingFrames.pop();
968 void RenderThread::RegisterExternalImage(
969 const wr::ExternalImageId& aExternalImageId,
970 already_AddRefed<RenderTextureHost> aTexture) {
971 MutexAutoLock lock(mRenderTextureMapLock);
973 if (mHasShutdown) {
974 return;
976 MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
977 RefPtr<RenderTextureHost> texture = aTexture;
978 if (texture->SyncObjectNeeded()) {
979 mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture);
981 mRenderTextures.emplace(aExternalImageId, texture);
984 void RenderThread::UnregisterExternalImage(
985 const wr::ExternalImageId& aExternalImageId) {
986 MutexAutoLock lock(mRenderTextureMapLock);
987 if (mHasShutdown) {
988 return;
990 auto it = mRenderTextures.find(aExternalImageId);
991 if (it == mRenderTextures.end()) {
992 return;
995 auto& texture = it->second;
996 if (texture->SyncObjectNeeded()) {
997 MOZ_RELEASE_ASSERT(
998 mSyncObjectNeededRenderTextures.erase(aExternalImageId) == 1);
1001 if (!IsInRenderThread()) {
1002 // The RenderTextureHost should be released in render thread. So, post the
1003 // deletion task here.
1004 // The shmem and raw buffer are owned by compositor ipc channel. It's
1005 // possible that RenderTextureHost is still exist after the shmem/raw buffer
1006 // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
1007 // for this situation. Gecko will only release the buffer if WR doesn't need
1008 // it. So, no one will access the invalid buffer in RenderTextureHost.
1009 RefPtr<RenderTextureHost> texture = it->second;
1010 mRenderTextures.erase(it);
1011 mRenderTexturesDeferred.emplace_back(std::move(texture));
1012 PostRunnable(NewRunnableMethod(
1013 "RenderThread::DeferredRenderTextureHostDestroy", this,
1014 &RenderThread::DeferredRenderTextureHostDestroy));
1015 } else {
1016 mRenderTextures.erase(it);
1020 void RenderThread::DestroyExternalImagesSyncWait(
1021 const std::vector<wr::ExternalImageId>&& aIds) {
1022 if (!IsInRenderThread()) {
1023 layers::SynchronousTask task("Destroy external images");
1025 RefPtr<Runnable> runnable = NS_NewRunnableFunction(
1026 "RenderThread::DestroyExternalImagesSyncWait::Runnable",
1027 [&task, ids = std::move(aIds)]() {
1028 layers::AutoCompleteTask complete(&task);
1029 RenderThread::Get()->DestroyExternalImages(std::move(ids));
1032 PostRunnable(runnable.forget());
1033 task.Wait();
1034 return;
1036 DestroyExternalImages(std::move(aIds));
1039 void RenderThread::DestroyExternalImages(
1040 const std::vector<wr::ExternalImageId>&& aIds) {
1041 MOZ_ASSERT(IsInRenderThread());
1043 std::vector<RefPtr<RenderTextureHost>> hosts;
1045 MutexAutoLock lock(mRenderTextureMapLock);
1046 if (mHasShutdown) {
1047 return;
1050 for (auto& id : aIds) {
1051 auto it = mRenderTextures.find(id);
1052 if (it == mRenderTextures.end()) {
1053 continue;
1055 hosts.emplace_back(it->second);
1059 for (auto& host : hosts) {
1060 host->Destroy();
1064 void RenderThread::PrepareForUse(const wr::ExternalImageId& aExternalImageId) {
1065 AddRenderTextureOp(RenderTextureOp::PrepareForUse, aExternalImageId);
1068 void RenderThread::NotifyNotUsed(const wr::ExternalImageId& aExternalImageId) {
1069 AddRenderTextureOp(RenderTextureOp::NotifyNotUsed, aExternalImageId);
1072 void RenderThread::NotifyForUse(const wr::ExternalImageId& aExternalImageId) {
1073 AddRenderTextureOp(RenderTextureOp::NotifyForUse, aExternalImageId);
1076 void RenderThread::AddRenderTextureOp(
1077 RenderTextureOp aOp, const wr::ExternalImageId& aExternalImageId) {
1078 MOZ_ASSERT(!IsInRenderThread());
1080 MutexAutoLock lock(mRenderTextureMapLock);
1082 auto it = mRenderTextures.find(aExternalImageId);
1083 MOZ_ASSERT(it != mRenderTextures.end());
1084 if (it == mRenderTextures.end()) {
1085 return;
1088 RefPtr<RenderTextureHost> texture = it->second;
1089 mRenderTextureOps.emplace_back(aOp, std::move(texture));
1091 if (mRenderTextureOpsRunnable) {
1092 // Runnable was already triggered
1093 return;
1096 RefPtr<nsIRunnable> runnable =
1097 NewRunnableMethod("RenderThread::HandleRenderTextureOps", this,
1098 &RenderThread::HandleRenderTextureOps);
1099 mRenderTextureOpsRunnable = runnable;
1100 PostRunnable(runnable.forget());
1103 void RenderThread::HandleRenderTextureOps() {
1104 MOZ_ASSERT(IsInRenderThread());
1106 std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>>
1107 renderTextureOps;
1109 MutexAutoLock lock(mRenderTextureMapLock);
1110 mRenderTextureOps.swap(renderTextureOps);
1111 mRenderTextureOpsRunnable = nullptr;
1114 for (auto& it : renderTextureOps) {
1115 switch (it.first) {
1116 case RenderTextureOp::PrepareForUse:
1117 it.second->PrepareForUse();
1118 break;
1119 case RenderTextureOp::NotifyForUse:
1120 it.second->NotifyForUse();
1121 break;
1122 case RenderTextureOp::NotifyNotUsed:
1123 it.second->NotifyNotUsed();
1124 break;
1129 void RenderThread::UnregisterExternalImageDuringShutdown(
1130 const wr::ExternalImageId& aExternalImageId) {
1131 MOZ_ASSERT(IsInRenderThread());
1132 MutexAutoLock lock(mRenderTextureMapLock);
1133 MOZ_ASSERT(mHasShutdown);
1134 mRenderTextures.erase(aExternalImageId);
1137 bool RenderThread::SyncObjectNeeded() {
1138 MOZ_ASSERT(IsInRenderThread());
1139 MutexAutoLock lock(mRenderTextureMapLock);
1140 return !mSyncObjectNeededRenderTextures.empty();
1143 void RenderThread::DeferredRenderTextureHostDestroy() {
1144 MutexAutoLock lock(mRenderTextureMapLock);
1145 mRenderTexturesDeferred.clear();
1148 RenderTextureHost* RenderThread::GetRenderTexture(
1149 const wr::ExternalImageId& aExternalImageId) {
1150 MutexAutoLock lock(mRenderTextureMapLock);
1151 auto it = mRenderTextures.find(aExternalImageId);
1152 MOZ_ASSERT(it != mRenderTextures.end());
1153 if (it == mRenderTextures.end()) {
1154 return nullptr;
1156 return it->second;
1159 void RenderThread::InitDeviceTask() {
1160 MOZ_ASSERT(IsInRenderThread());
1161 MOZ_ASSERT(!mSingletonGL);
1162 LOG("RenderThread::InitDeviceTask()");
1164 if (gfx::gfxVars::UseSoftwareWebRender()) {
1165 // Ensure we don't instantiate any shared GL context when SW-WR is used.
1166 return;
1169 nsAutoCString err;
1170 CreateSingletonGL(err);
1171 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1172 mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
1174 // Query the shared GL context to force the
1175 // lazy initialization to happen now.
1176 SingletonGL();
1179 void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
1180 nsCOMPtr<nsIRunnable> runnable = aRunnable;
1181 mThread->Dispatch(runnable.forget());
1184 #ifndef XP_WIN
1185 static DeviceResetReason GLenumToResetReason(GLenum aReason) {
1186 switch (aReason) {
1187 case LOCAL_GL_NO_ERROR:
1188 return DeviceResetReason::FORCED_RESET;
1189 case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
1190 return DeviceResetReason::DRIVER_ERROR;
1191 case LOCAL_GL_PURGED_CONTEXT_RESET_NV:
1192 return DeviceResetReason::NVIDIA_VIDEO;
1193 case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
1194 return DeviceResetReason::RESET;
1195 case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
1196 return DeviceResetReason::UNKNOWN;
1197 case LOCAL_GL_OUT_OF_MEMORY:
1198 return DeviceResetReason::OUT_OF_MEMORY;
1199 default:
1200 return DeviceResetReason::OTHER;
1203 #endif
1205 void RenderThread::HandleDeviceReset(const char* aWhere, GLenum aReason) {
1206 MOZ_ASSERT(IsInRenderThread());
1208 // This happens only on simulate device reset.
1209 if (aReason == LOCAL_GL_NO_ERROR) {
1210 if (!mHandlingDeviceReset) {
1211 mHandlingDeviceReset = true;
1213 MutexAutoLock lock(mRenderTextureMapLock);
1214 mRenderTexturesDeferred.clear();
1215 for (const auto& entry : mRenderTextures) {
1216 entry.second->ClearCachedResources();
1219 // All RenderCompositors will be destroyed by the GPUProcessManager in
1220 // either OnRemoteProcessDeviceReset via the GPUChild, or
1221 // OnInProcessDeviceReset here directly.
1222 if (XRE_IsGPUProcess()) {
1223 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1224 } else {
1225 NS_DispatchToMainThread(NS_NewRunnableFunction(
1226 "gfx::GPUProcessManager::OnInProcessDeviceReset", []() -> void {
1227 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(
1228 /* aTrackThreshold */ false);
1229 }));
1232 return;
1235 if (mHandlingDeviceReset) {
1236 return;
1239 mHandlingDeviceReset = true;
1241 #ifndef XP_WIN
1242 // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices.
1243 gfx::GPUProcessManager::RecordDeviceReset(GLenumToResetReason(aReason));
1244 #endif
1247 MutexAutoLock lock(mRenderTextureMapLock);
1248 mRenderTexturesDeferred.clear();
1249 for (const auto& entry : mRenderTextures) {
1250 entry.second->ClearCachedResources();
1254 // All RenderCompositors will be destroyed by the GPUProcessManager in
1255 // either OnRemoteProcessDeviceReset via the GPUChild, or
1256 // OnInProcessDeviceReset here directly.
1257 // On Windows, device will be re-created before sessions re-creation.
1258 gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
1259 if (XRE_IsGPUProcess()) {
1260 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1261 } else {
1262 #ifndef XP_WIN
1263 // FIXME(aosmond): Do we need to do this on Windows? nsWindow::OnPaint
1264 // seems to do its own detection for the parent process.
1265 bool guilty = aReason == LOCAL_GL_GUILTY_CONTEXT_RESET_ARB;
1266 NS_DispatchToMainThread(NS_NewRunnableFunction(
1267 "gfx::GPUProcessManager::OnInProcessDeviceReset", [guilty]() -> void {
1268 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(guilty);
1269 }));
1270 #endif
1274 bool RenderThread::IsHandlingDeviceReset() {
1275 MOZ_ASSERT(IsInRenderThread());
1276 return mHandlingDeviceReset;
1279 void RenderThread::SimulateDeviceReset() {
1280 if (!IsInRenderThread()) {
1281 PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this,
1282 &RenderThread::SimulateDeviceReset));
1283 } else {
1284 // When this function is called GPUProcessManager::SimulateDeviceReset()
1285 // already triggers destroying all CompositorSessions before re-creating
1286 // them.
1287 HandleDeviceReset("SimulateDeviceReset", LOCAL_GL_NO_ERROR);
1291 static void DoNotifyWebRenderError(WebRenderError aError) {
1292 layers::CompositorManagerParent::NotifyWebRenderError(aError);
1295 void RenderThread::NotifyWebRenderError(WebRenderError aError) {
1296 MOZ_ASSERT(IsInRenderThread());
1298 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1299 "DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
1302 void RenderThread::HandleWebRenderError(WebRenderError aError) {
1303 MOZ_ASSERT(IsInRenderThread());
1304 if (mHandlingWebRenderError) {
1305 return;
1308 NotifyWebRenderError(aError);
1311 MutexAutoLock lock(mRenderTextureMapLock);
1312 mRenderTexturesDeferred.clear();
1313 for (const auto& entry : mRenderTextures) {
1314 entry.second->ClearCachedResources();
1317 mHandlingWebRenderError = true;
1318 // WebRender is going to be disabled by
1319 // GPUProcessManager::NotifyWebRenderError()
1322 bool RenderThread::IsHandlingWebRenderError() {
1323 MOZ_ASSERT(IsInRenderThread());
1324 return mHandlingWebRenderError;
1327 gl::GLContext* RenderThread::SingletonGL() {
1328 nsAutoCString err;
1329 auto* gl = SingletonGL(err);
1330 if (!err.IsEmpty()) {
1331 gfxCriticalNote << err.get();
1333 return gl;
1336 void RenderThread::CreateSingletonGL(nsACString& aError) {
1337 MOZ_ASSERT(IsInRenderThread());
1338 LOG("RenderThread::CreateSingletonGL()");
1340 mSingletonGL = CreateGLContext(aError);
1341 mSingletonGLIsForHardwareWebRender = !gfx::gfxVars::UseSoftwareWebRender();
1344 gl::GLContext* RenderThread::SingletonGL(nsACString& aError) {
1345 MOZ_ASSERT(IsInRenderThread());
1346 if (!mSingletonGL) {
1347 CreateSingletonGL(aError);
1348 mShaders = nullptr;
1350 if (mSingletonGL && mSingletonGLIsForHardwareWebRender && !mShaders) {
1351 mShaders = MakeUnique<WebRenderShaders>(mSingletonGL, mProgramCache.get());
1354 return mSingletonGL.get();
1357 gl::GLContext* RenderThread::SingletonGLForCompositorOGL() {
1358 MOZ_RELEASE_ASSERT(gfx::gfxVars::UseSoftwareWebRender());
1360 if (mSingletonGLIsForHardwareWebRender) {
1361 // Clear singleton GL, since GLContext is for hardware WebRender.
1362 ClearSingletonGL();
1364 return SingletonGL();
1367 void RenderThread::ClearSingletonGL() {
1368 MOZ_ASSERT(IsInRenderThread());
1369 LOG("RenderThread::ClearSingletonGL()");
1371 if (mSurfacePool) {
1372 mSurfacePool->DestroyGLResourcesForContext(mSingletonGL);
1374 if (mProgramsForCompositorOGL) {
1375 mProgramsForCompositorOGL->Clear();
1376 mProgramsForCompositorOGL = nullptr;
1378 if (mShaders) {
1379 if (mSingletonGL) {
1380 mSingletonGL->MakeCurrent();
1382 mShaders = nullptr;
1384 mSingletonGL = nullptr;
1387 RefPtr<layers::ShaderProgramOGLsHolder>
1388 RenderThread::GetProgramsForCompositorOGL() {
1389 if (!mSingletonGL) {
1390 return nullptr;
1393 if (!mProgramsForCompositorOGL) {
1394 mProgramsForCompositorOGL =
1395 MakeAndAddRef<layers::ShaderProgramOGLsHolder>(mSingletonGL);
1397 return mProgramsForCompositorOGL;
1400 RefPtr<layers::SurfacePool> RenderThread::SharedSurfacePool() {
1401 #if defined(XP_DARWIN) || defined(MOZ_WAYLAND)
1402 if (!mSurfacePool) {
1403 size_t poolSizeLimit =
1404 StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup();
1405 mSurfacePool = layers::SurfacePool::Create(poolSizeLimit);
1407 #endif
1408 return mSurfacePool;
1411 void RenderThread::ClearSharedSurfacePool() { mSurfacePool = nullptr; }
1413 static void GLAPIENTRY DebugMessageCallback(GLenum aSource, GLenum aType,
1414 GLuint aId, GLenum aSeverity,
1415 GLsizei aLength,
1416 const GLchar* aMessage,
1417 const GLvoid* aUserParam) {
1418 constexpr const char* kContextLost = "Context has been lost.";
1420 if (StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() &&
1421 aSeverity == LOCAL_GL_DEBUG_SEVERITY_HIGH) {
1422 auto message = std::string(aMessage, aLength);
1423 // When content lost happned, error messages are flooded by its message.
1424 if (message != kContextLost) {
1425 gfxCriticalNote << message;
1426 } else {
1427 gfxCriticalNoteOnce << message;
1431 if (StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup()) {
1432 gl::GLContext* gl = (gl::GLContext*)aUserParam;
1433 gl->DebugCallback(aSource, aType, aId, aSeverity, aLength, aMessage);
1437 // static
1438 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext* aGLContext) {
1439 if (!aGLContext) {
1440 return;
1443 bool enableDebugMessage =
1444 StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() ||
1445 StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup();
1447 if (enableDebugMessage &&
1448 aGLContext->IsExtensionSupported(gl::GLContext::KHR_debug)) {
1449 aGLContext->fEnable(LOCAL_GL_DEBUG_OUTPUT);
1450 aGLContext->fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
1451 aGLContext->fDebugMessageCallback(&DebugMessageCallback, (void*)aGLContext);
1452 aGLContext->fDebugMessageControl(LOCAL_GL_DONT_CARE, LOCAL_GL_DONT_CARE,
1453 LOCAL_GL_DONT_CARE, 0, nullptr, true);
1457 WebRenderShaders::WebRenderShaders(gl::GLContext* gl,
1458 WebRenderProgramCache* programCache) {
1459 mGL = gl;
1460 mShaders =
1461 wr_shaders_new(gl, programCache ? programCache->Raw() : nullptr,
1462 StaticPrefs::gfx_webrender_precache_shaders_AtStartup());
1465 WebRenderShaders::~WebRenderShaders() {
1466 wr_shaders_delete(mShaders, mGL.get());
1469 WebRenderThreadPool::WebRenderThreadPool(bool low_priority) {
1470 mThreadPool = wr_thread_pool_new(low_priority);
1473 WebRenderThreadPool::~WebRenderThreadPool() { Release(); }
1475 void WebRenderThreadPool::Release() {
1476 if (mThreadPool) {
1477 wr_thread_pool_delete(mThreadPool);
1478 mThreadPool = nullptr;
1482 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) {
1483 MOZ_ASSERT(aThreadPool);
1485 nsAutoString path;
1486 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1487 path.Append(gfx::gfxVars::ProfDirectory());
1489 mProgramCache = wr_program_cache_new(&path, aThreadPool);
1490 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1491 wr_try_load_startup_shaders_from_disk(mProgramCache);
1495 WebRenderProgramCache::~WebRenderProgramCache() {
1496 wr_program_cache_delete(mProgramCache);
1499 } // namespace mozilla::wr
1501 #ifdef XP_WIN
1502 static already_AddRefed<gl::GLContext> CreateGLContextANGLE(
1503 nsACString& aError) {
1504 const RefPtr<ID3D11Device> d3d11Device =
1505 gfx::DeviceManagerDx::Get()->GetCompositorDevice();
1506 if (!d3d11Device) {
1507 aError.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns);
1508 return nullptr;
1511 nsCString failureId;
1512 const auto lib = gl::GLLibraryEGL::Get(&failureId);
1513 if (!lib) {
1514 aError.Assign(
1515 nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get()));
1516 return nullptr;
1519 const auto egl = lib->CreateDisplay(d3d11Device.get());
1520 if (!egl) {
1521 aError.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
1522 failureId.get()));
1523 return nullptr;
1526 gl::CreateContextFlags flags = gl::CreateContextFlags::PREFER_ES3;
1528 if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
1529 flags |= gl::CreateContextFlags::PREFER_ROBUSTNESS;
1532 if (egl->IsExtensionSupported(
1533 gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
1534 flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE;
1537 // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
1538 // Instread we override it with EGLSurface of SwapChain's back buffer.
1540 auto gl = gl::GLContextEGL::CreateWithoutSurface(egl, {flags}, &failureId);
1541 if (!gl || !gl->IsANGLE()) {
1542 aError.Assign(nsPrintfCString("RcANGLE(create GL context failed: %p, %s)",
1543 gl.get(), failureId.get()));
1544 return nullptr;
1547 if (!gl->MakeCurrent()) {
1548 aError.Assign(
1549 nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)",
1550 gl.get(), gl->mEgl->mLib->fGetError()));
1551 return nullptr;
1554 return gl.forget();
1556 #endif
1558 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
1559 static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
1560 // Create GLContext with dummy EGLSurface.
1561 bool forHardwareWebRender = true;
1562 // SW-WR uses CompositorOGL in native compositor.
1563 if (gfx::gfxVars::UseSoftwareWebRender()) {
1564 forHardwareWebRender = false;
1566 RefPtr<gl::GLContext> gl =
1567 gl::GLContextProviderEGL::CreateForCompositorWidget(
1568 nullptr, forHardwareWebRender, /* aForceAccelerated */ true);
1569 if (!gl || !gl->MakeCurrent()) {
1570 gfxCriticalNote << "Failed GL context creation for hardware WebRender: "
1571 << forHardwareWebRender;
1572 return nullptr;
1574 return gl.forget();
1576 #endif
1578 #ifdef XP_DARWIN
1579 static already_AddRefed<gl::GLContext> CreateGLContextCGL() {
1580 nsCString failureUnused;
1581 return gl::GLContextProvider::CreateHeadless(
1582 {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
1583 gl::CreateContextFlags::FORBID_SOFTWARE},
1584 &failureUnused);
1586 #endif
1588 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) {
1589 RefPtr<gl::GLContext> gl;
1591 #ifdef XP_WIN
1592 if (gfx::gfxVars::UseWebRenderANGLE()) {
1593 gl = CreateGLContextANGLE(aError);
1595 #elif defined(MOZ_WIDGET_ANDROID)
1596 gl = CreateGLContextEGL();
1597 #elif defined(MOZ_WIDGET_GTK)
1598 if (gfx::gfxVars::UseEGL()) {
1599 gl = CreateGLContextEGL();
1601 #elif XP_DARWIN
1602 gl = CreateGLContextCGL();
1603 #endif
1605 wr::RenderThread::MaybeEnableGLDebugMessage(gl);
1607 return gl.forget();
1610 extern "C" {
1612 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId,
1613 bool aCompositeNeeded) {
1614 // wake_up is used for things like propagating debug options or memory
1615 // pressure events, so we are not tracking pending frame counts.
1616 mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId,
1617 aCompositeNeeded);
1620 void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId,
1621 bool aCompositeNeeded,
1622 mozilla::wr::FramePublishId aPublishId) {
1623 auto* renderThread = mozilla::wr::RenderThread::Get();
1624 renderThread->DecPendingFrameBuildCount(aWindowId);
1626 renderThread->WrNotifierEvent_NewFrameReady(aWindowId, aCompositeNeeded,
1627 aPublishId);
1630 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
1631 size_t aRawEvent) {
1632 mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent(
1633 mozilla::wr::WindowId(aWindowId), aRawEvent);
1636 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,
1637 wr::RenderReasons aReasons) {
1638 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1639 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1640 if (cbp) {
1641 cbp->ScheduleComposition(aReasons);
1645 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
1646 wr::RenderReasons aReasons) {
1647 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1648 "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons));
1651 static void NotifyDidSceneBuild(
1652 mozilla::wr::WrWindowId aWindowId,
1653 const RefPtr<const wr::WebRenderPipelineInfo>& aInfo) {
1654 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1655 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1656 if (cbp) {
1657 cbp->NotifyDidSceneBuild(aInfo);
1661 void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,
1662 mozilla::wr::WrPipelineInfo* aPipelineInfo) {
1663 RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo();
1664 info->Raw() = std::move(*aPipelineInfo);
1665 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1666 "NotifyDidSceneBuild", &NotifyDidSceneBuild, aWindowId, info));
1669 } // extern C