Bug 1905865 - [devtools] Update webidl-pure-allowlist.js. r=devtools-reviewers,ochameau.
[gecko.git] / gfx / webrender_bindings / RenderThread.cpp
blobbd52e4e6e7fa45d98a78c189f07233f80c75d5a6
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 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
77 static bool USE_DEDICATED_GLYPH_RASTER_THREAD = true;
78 #else
79 static bool USE_DEDICATED_GLYPH_RASTER_THREAD = false;
80 #endif
82 RenderThread::RenderThread(RefPtr<nsIThread> aThread)
83 : mThread(std::move(aThread)),
84 mThreadPool(false),
85 mThreadPoolLP(true),
86 mGlyphRasterThread(USE_DEDICATED_GLYPH_RASTER_THREAD),
87 mSingletonGLIsForHardwareWebRender(true),
88 mBatteryInfo("RenderThread.mBatteryInfo"),
89 mWindowInfos("RenderThread.mWindowInfos"),
90 mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
91 mHasShutdown(false),
92 mHandlingDeviceReset(false),
93 mHandlingWebRenderError(false) {}
95 RenderThread::~RenderThread() { MOZ_ASSERT(mRenderTexturesDeferred.empty()); }
97 // static
98 RenderThread* RenderThread::Get() { return sRenderThread; }
100 // static
101 void RenderThread::Start(uint32_t aNamespace) {
102 MOZ_ASSERT(NS_IsMainThread());
103 MOZ_ASSERT(!sRenderThread);
105 #ifdef DEBUG
106 // Check to ensure nobody will try to ever start us more than once during
107 // the process' lifetime (in particular after ShutDown).
108 MOZ_ASSERT(!sRenderThreadEverStarted);
109 sRenderThreadEverStarted = true;
110 #endif
112 // When the CanvasRenderer thread is disabled, WebGL may be handled on this
113 // thread, requiring a bigger stack size. See: CanvasManagerParent::Init
115 // This is 4M, which is higher than the default 256K.
116 // Increased with bug 1753349 to accommodate the `chromium/5359` branch of
117 // ANGLE, which has large peak stack usage for some pathological shader
118 // compilations.
120 // Previously increased to 512K to accommodate Mesa in bug 1753340.
122 // Previously increased to 320K to avoid a stack overflow in the
123 // Intel Vulkan driver initialization in bug 1716120.
125 // Note: we only override it if it's limited already.
126 uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE;
127 if (stackSize && !gfx::gfxVars::SupportsThreadsafeGL()) {
128 stackSize = std::max(stackSize, 4096U << 10);
130 #if !defined(__OPTIMIZE__)
131 // swgl's draw_quad_spans will allocate ~1.5MB in no-opt builds
132 // and the default thread stack size on macOS is 512KB
133 stackSize = std::max(stackSize, 4 * 1024 * 1024U);
134 #endif
136 RefPtr<nsIThread> thread;
137 nsresult rv = NS_NewNamedThread(
138 "Renderer", getter_AddRefs(thread),
139 NS_NewRunnableFunction(
140 "Renderer::BackgroundHanSetup",
141 []() {
142 sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor(
143 "Render",
144 /* Timeout values are powers-of-two to enable us get better
145 data. 128ms is chosen for transient hangs because 8Hz should
146 be the minimally acceptable goal for Render
147 responsiveness (normal goal is 60Hz). */
148 128,
149 /* 2048ms is chosen for permanent hangs because it's longer than
150 * most Render hangs seen in the wild, but is short enough
151 * to not miss getting native hang stacks. */
152 2048);
153 nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
154 nsThread* nsthread = static_cast<nsThread*>(thread.get());
155 nsthread->SetUseHangMonitor(true);
156 nsthread->SetPriority(nsISupportsPriority::PRIORITY_HIGH);
158 {.stackSize = stackSize});
160 if (NS_FAILED(rv)) {
161 gfxCriticalNote << "Failed to create Renderer thread: "
162 << gfx::hexa((uint32_t)rv);
163 return;
166 sRenderThread = new RenderThread(thread);
167 CrashReporter::RegisterAnnotationUSize(
168 CrashReporter::Annotation::GraphicsNumRenderers, &sRendererCount);
169 CrashReporter::RegisterAnnotationUSize(
170 CrashReporter::Annotation::GraphicsNumActiveRenderers,
171 &sActiveRendererCount);
172 #ifdef XP_WIN
173 widget::WinCompositorWindowThread::Start();
174 #endif
175 layers::SharedSurfacesParent::Initialize();
177 RefPtr<Runnable> runnable = WrapRunnable(
178 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::InitDeviceTask);
179 sRenderThread->PostRunnable(runnable.forget());
182 // static
183 void RenderThread::ShutDown() {
184 MOZ_ASSERT(NS_IsMainThread());
185 MOZ_ASSERT(sRenderThread);
188 MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
189 sRenderThread->mHasShutdown = true;
192 RefPtr<Runnable> runnable = WrapRunnable(
193 RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::ShutDownTask);
194 sRenderThread->PostRunnable(runnable.forget());
196 // This will empty the thread queue and thus run the above runnable while
197 // spinning the MT event loop.
198 nsCOMPtr<nsIThread> oldThread = sRenderThread->GetRenderThread();
199 oldThread->Shutdown();
201 layers::SharedSurfacesParent::Shutdown();
203 #ifdef XP_WIN
204 if (widget::WinCompositorWindowThread::Get()) {
205 widget::WinCompositorWindowThread::ShutDown();
207 #endif
209 // We null this out only after we finished shutdown to give everbody the
210 // chance to check for sRenderThread->mHasShutdown. Hopefully everybody
211 // checks this before using us!
212 sRenderThread = nullptr;
215 extern void ClearAllBlobImageResources();
217 void RenderThread::ShutDownTask() {
218 MOZ_ASSERT(IsInRenderThread());
219 LOG("RenderThread::ShutDownTask()");
222 // Clear RenderTextureHosts
223 MutexAutoLock lock(mRenderTextureMapLock);
224 mRenderTexturesDeferred.clear();
225 mRenderTextures.clear();
226 mSyncObjectNeededRenderTextures.clear();
227 mRenderTextureOps.clear();
230 // Let go of our handle to the (internally ref-counted) thread pool.
231 mThreadPool.Release();
232 mThreadPoolLP.Release();
234 // Releasing on the render thread will allow us to avoid dispatching to remove
235 // remaining textures from the texture map.
236 layers::SharedSurfacesParent::ShutdownRenderThread();
238 #ifdef XP_WIN
239 DCLayerTree::Shutdown();
240 #endif
242 ClearAllBlobImageResources();
243 ClearSingletonGL();
244 ClearSharedSurfacePool();
247 // static
248 bool RenderThread::IsInRenderThread() {
249 return sRenderThread && sRenderThread->mThread == NS_GetCurrentThread();
252 // static
253 already_AddRefed<nsIThread> RenderThread::GetRenderThread() {
254 nsCOMPtr<nsIThread> thread;
255 if (sRenderThread) {
256 thread = sRenderThread->mThread;
258 return thread.forget();
261 void RenderThread::DoAccumulateMemoryReport(
262 MemoryReport aReport,
263 const RefPtr<MemoryReportPromise::Private>& aPromise) {
264 MOZ_ASSERT(IsInRenderThread());
266 for (auto& r : mRenderers) {
267 r.second->AccumulateMemoryReport(&aReport);
270 // Note memory used by the shader cache, which is shared across all WR
271 // instances.
272 MOZ_ASSERT(aReport.shader_cache == 0);
273 if (mProgramCache) {
274 aReport.shader_cache = wr_program_cache_report_memory(
275 mProgramCache->Raw(), &WebRenderRendererMallocSizeOf);
278 size_t renderTextureMemory = 0;
280 MutexAutoLock lock(mRenderTextureMapLock);
281 for (const auto& entry : mRenderTextures) {
282 renderTextureMemory += entry.second->Bytes();
285 aReport.render_texture_hosts = renderTextureMemory;
287 aPromise->Resolve(aReport, __func__);
290 // static
291 RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport(
292 MemoryReport aInitial) {
293 RefPtr<MemoryReportPromise::Private> p =
294 new MemoryReportPromise::Private(__func__);
295 MOZ_ASSERT(!IsInRenderThread());
296 if (!Get()) {
297 // This happens when the GPU process fails to start and we fall back to the
298 // basic compositor in the parent process. We could assert against this if
299 // we made the webrender detection code in gfxPlatform.cpp smarter. See bug
300 // 1494430 comment 12.
301 NS_WARNING("No render thread, returning empty memory report");
302 p->Resolve(aInitial, __func__);
303 return p;
306 Get()->PostRunnable(
307 NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>(
308 "wr::RenderThread::DoAccumulateMemoryReport", Get(),
309 &RenderThread::DoAccumulateMemoryReport, aInitial, p));
311 return p;
314 void RenderThread::SetBatteryInfo(const hal::BatteryInformation& aBatteryInfo) {
315 MOZ_ASSERT(XRE_IsGPUProcess());
317 auto batteryInfo = mBatteryInfo.Lock();
318 batteryInfo.ref() = Some(aBatteryInfo);
321 bool RenderThread::GetPowerIsCharging() {
322 MOZ_ASSERT(XRE_IsGPUProcess());
324 auto batteryInfo = mBatteryInfo.Lock();
325 if (batteryInfo.ref().isSome()) {
326 return batteryInfo.ref().ref().charging();
329 gfxCriticalNoteOnce << "BatteryInfo is not set";
330 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
331 return false;
334 void RenderThread::AddRenderer(wr::WindowId aWindowId,
335 UniquePtr<RendererOGL> aRenderer) {
336 MOZ_ASSERT(IsInRenderThread());
337 LOG("RenderThread::AddRenderer() aWindowId %" PRIx64 "", AsUint64(aWindowId));
339 if (mHasShutdown) {
340 return;
343 mRenderers[aWindowId] = std::move(aRenderer);
344 sRendererCount = mRenderers.size();
346 auto windows = mWindowInfos.Lock();
347 windows->emplace(AsUint64(aWindowId), new WindowInfo());
348 mWrNotifierEventsQueues.emplace(AsUint64(aWindowId),
349 new std::queue<WrNotifierEvent>);
352 void RenderThread::RemoveRenderer(wr::WindowId aWindowId) {
353 MOZ_ASSERT(IsInRenderThread());
354 LOG("RenderThread::RemoveRenderer() aWindowId %" PRIx64 "",
355 AsUint64(aWindowId));
357 if (mHasShutdown) {
358 return;
361 mRenderers.erase(aWindowId);
362 sRendererCount = mRenderers.size();
364 if (mRenderers.empty()) {
365 if (mHandlingDeviceReset) {
366 ClearSingletonGL();
368 mHandlingDeviceReset = false;
369 mHandlingWebRenderError = false;
372 auto windows = mWindowInfos.Lock();
373 auto it = windows->find(AsUint64(aWindowId));
374 MOZ_ASSERT(it != windows->end());
375 windows->erase(it);
377 // Defer std::deque<WrNotifierEvent> remove, RemoveRenderer() is called in
378 // HandleWrNotifierEvents().
379 RefPtr<Runnable> runnable =
380 NS_NewRunnableFunction("RenderThread::RemoveRenderer", [aWindowId]() {
381 auto* self = RenderThread::Get();
382 auto it = self->mWrNotifierEventsQueues.find(AsUint64(aWindowId));
383 if (it == self->mWrNotifierEventsQueues.end()) {
384 return;
386 self->mWrNotifierEventsQueues.erase(it);
388 RenderThread::Get()->PostRunnable(runnable.forget());
391 RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) {
392 MOZ_ASSERT(IsInRenderThread());
394 auto it = mRenderers.find(aWindowId);
395 MOZ_ASSERT(it != mRenderers.end());
397 if (it == mRenderers.end()) {
398 return nullptr;
401 return it->second.get();
404 size_t RenderThread::RendererCount() const {
405 MOZ_ASSERT(IsInRenderThread());
406 return mRenderers.size();
409 void RenderThread::UpdateActiveRendererCount() {
410 MOZ_ASSERT(IsInRenderThread());
411 size_t num_active = 0;
412 for (const auto& it : mRenderers) {
413 if (!it.second->IsPaused()) {
414 num_active++;
417 sActiveRendererCount = num_active;
420 void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId,
421 bool aCompositeNeeded) {
422 auto windows = mWindowInfos.Lock();
423 auto it = windows->find(AsUint64(aWindowId));
424 if (it == windows->end()) {
425 MOZ_ASSERT(false);
426 return;
429 WindowInfo* info = it->second.get();
431 info->mPendingWrNotifierEvents.emplace(
432 WrNotifierEvent::WakeUp(aCompositeNeeded));
433 PostWrNotifierEvents(aWindowId, info);
436 void RenderThread::WrNotifierEvent_NewFrameReady(WrWindowId aWindowId,
437 bool aCompositeNeeded,
438 FramePublishId aPublishId) {
439 auto windows = mWindowInfos.Lock();
440 auto it = windows->find(AsUint64(aWindowId));
441 if (it == windows->end()) {
442 MOZ_ASSERT(false);
443 return;
445 WindowInfo* info = it->second.get();
447 info->mPendingWrNotifierEvents.emplace(
448 WrNotifierEvent::NewFrameReady(aCompositeNeeded, aPublishId));
449 PostWrNotifierEvents(aWindowId, info);
452 void RenderThread::WrNotifierEvent_ExternalEvent(WrWindowId aWindowId,
453 size_t aRawEvent) {
454 UniquePtr<RendererEvent> evt(reinterpret_cast<RendererEvent*>(aRawEvent));
456 auto windows = mWindowInfos.Lock();
457 auto it = windows->find(AsUint64(aWindowId));
458 if (it == windows->end()) {
459 MOZ_ASSERT(false);
460 return;
462 WindowInfo* info = it->second.get();
464 info->mPendingWrNotifierEvents.emplace(
465 WrNotifierEvent::ExternalEvent(std::move(evt)));
466 PostWrNotifierEvents(aWindowId, info);
470 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId) {
472 auto windows = mWindowInfos.Lock();
473 auto it = windows->find(AsUint64(aWindowId));
474 if (it == windows->end()) {
475 MOZ_ASSERT(false);
476 return;
478 WindowInfo* info = it->second.get();
479 PostWrNotifierEvents(aWindowId, info);
483 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId,
484 WindowInfo* aInfo) {
485 // Runnable has already been triggered.
486 if (aInfo->mWrNotifierEventsRunnable) {
487 return;
490 // Runnable has not been triggered yet.
491 RefPtr<nsIRunnable> runnable = NewRunnableMethod<WrWindowId>(
492 "RenderThread::HandleWrNotifierEvents", this,
493 &RenderThread::HandleWrNotifierEvents, aWindowId);
494 aInfo->mWrNotifierEventsRunnable = runnable;
495 PostRunnable(runnable.forget());
498 void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId) {
499 MOZ_ASSERT(IsInRenderThread());
501 auto eventsIt = mWrNotifierEventsQueues.find(AsUint64(aWindowId));
502 if (eventsIt == mWrNotifierEventsQueues.end()) {
503 return;
505 auto* events = eventsIt->second.get();
508 auto windows = mWindowInfos.Lock();
509 auto infoIt = windows->find(AsUint64(aWindowId));
510 if (infoIt == windows->end()) {
511 MOZ_ASSERT(false);
512 return;
514 WindowInfo* info = infoIt->second.get();
515 info->mWrNotifierEventsRunnable = nullptr;
517 if (events->empty() && !info->mPendingWrNotifierEvents.empty()) {
518 events->swap(info->mPendingWrNotifierEvents);
522 bool handleNext = true;
524 while (!events->empty() && handleNext) {
525 auto& front = events->front();
526 switch (front.mTag) {
527 case WrNotifierEvent::Tag::WakeUp:
528 WrNotifierEvent_HandleWakeUp(aWindowId, front.CompositeNeeded());
529 handleNext = false;
530 break;
531 case WrNotifierEvent::Tag::NewFrameReady:
532 WrNotifierEvent_HandleNewFrameReady(aWindowId, front.CompositeNeeded(),
533 front.PublishId());
534 handleNext = false;
535 break;
536 case WrNotifierEvent::Tag::ExternalEvent:
537 WrNotifierEvent_HandleExternalEvent(aWindowId, front.ExternalEvent());
538 break;
540 events->pop();
544 auto windows = mWindowInfos.Lock();
545 auto it = windows->find(AsUint64(aWindowId));
546 if (it == windows->end()) {
547 return;
549 WindowInfo* info = it->second.get();
551 if (!events->empty() || !info->mPendingWrNotifierEvents.empty()) {
552 PostWrNotifierEvents(aWindowId, info);
557 void RenderThread::WrNotifierEvent_HandleWakeUp(wr::WindowId aWindowId,
558 bool aCompositeNeeded) {
559 MOZ_ASSERT(IsInRenderThread());
561 bool isTrackedFrame = false;
562 HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame, Nothing());
565 void RenderThread::WrNotifierEvent_HandleNewFrameReady(
566 wr::WindowId aWindowId, bool aCompositeNeeded, FramePublishId aPublishId) {
567 MOZ_ASSERT(IsInRenderThread());
569 bool isTrackedFrame = true;
570 HandleFrameOneDoc(aWindowId, aCompositeNeeded, isTrackedFrame,
571 Some(aPublishId));
574 void RenderThread::WrNotifierEvent_HandleExternalEvent(
575 wr::WindowId aWindowId, UniquePtr<RendererEvent> aRendererEvent) {
576 MOZ_ASSERT(IsInRenderThread());
578 RunEvent(aWindowId, std::move(aRendererEvent));
581 void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId,
582 const TimeStamp& aRecordingStart,
583 wr::PipelineId aRootPipelineId) {
584 MOZ_ASSERT(IsInRenderThread());
585 RendererOGL* renderer = GetRenderer(aWindowId);
586 MOZ_ASSERT(renderer);
588 renderer->BeginRecording(aRecordingStart, aRootPipelineId);
591 Maybe<layers::FrameRecording> RenderThread::EndRecordingForWindow(
592 wr::WindowId aWindowId) {
593 MOZ_ASSERT(IsInRenderThread());
595 RendererOGL* renderer = GetRenderer(aWindowId);
596 MOZ_ASSERT(renderer);
597 return renderer->EndRecording();
600 void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender,
601 bool aTrackedFrame,
602 Maybe<FramePublishId> aPublishId) {
603 MOZ_ASSERT(IsInRenderThread());
605 if (mHasShutdown) {
606 return;
609 HandleFrameOneDocInner(aWindowId, aRender, aTrackedFrame, aPublishId);
611 if (aTrackedFrame) {
612 DecPendingFrameCount(aWindowId);
616 void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId, bool aRender,
617 bool aTrackedFrame,
618 Maybe<FramePublishId> aPublishId) {
619 if (IsDestroyed(aWindowId)) {
620 return;
623 if (mHandlingDeviceReset) {
624 return;
627 bool render = aRender;
628 PendingFrameInfo frame;
629 if (aTrackedFrame) {
630 // scope lock
631 auto windows = mWindowInfos.Lock();
632 auto it = windows->find(AsUint64(aWindowId));
633 if (it == windows->end()) {
634 MOZ_ASSERT(false);
635 return;
638 WindowInfo* info = it->second.get();
639 PendingFrameInfo& frameInfo = info->mPendingFrames.front();
641 frame = frameInfo;
642 } else {
643 // Just give the frame info default values.
644 frame = {TimeStamp::Now(), VsyncId()};
647 // Sadly this doesn't include the lock, since we don't have the frame there
648 // yet.
649 glean::wr::time_to_render_start.AccumulateRawDuration(TimeStamp::Now() -
650 frame.mStartTime);
652 // It is for ensuring that PrepareForUse() is called before
653 // RenderTextureHost::Lock().
654 HandleRenderTextureOps();
656 if (aPublishId.isSome()) {
657 SetFramePublishId(aWindowId, aPublishId.ref());
660 UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, render,
661 /* aReadbackSize */ Nothing(),
662 /* aReadbackFormat */ Nothing(),
663 /* aReadbackBuffer */ Nothing());
665 // The start time is from WebRenderBridgeParent::CompositeToTarget. From that
666 // point until now (when the frame is finally pushed to the screen) is
667 // equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
668 TimeDuration compositeDuration = TimeStamp::Now() - frame.mStartTime;
669 mozilla::glean::gfx::composite_time.AccumulateRawDuration(compositeDuration);
670 PerfStats::RecordMeasurement(PerfStats::Metric::Compositing,
671 compositeDuration);
674 void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) {
675 if (mHasShutdown) {
676 return;
679 if (!IsInRenderThread()) {
680 PostRunnable(NewRunnableMethod<wr::WindowId, wr::ColorF>(
681 "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor,
682 aWindowId, aColor));
683 return;
686 if (IsDestroyed(aWindowId)) {
687 return;
690 auto it = mRenderers.find(aWindowId);
691 MOZ_ASSERT(it != mRenderers.end());
692 if (it != mRenderers.end()) {
693 wr_renderer_set_clear_color(it->second->GetRenderer(), aColor);
697 void RenderThread::SetProfilerUI(wr::WindowId aWindowId,
698 const nsACString& aUI) {
699 if (mHasShutdown) {
700 return;
703 if (!IsInRenderThread()) {
704 PostRunnable(NewRunnableMethod<wr::WindowId, nsCString>(
705 "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI,
706 aWindowId, nsCString(aUI)));
707 return;
710 auto it = mRenderers.find(aWindowId);
711 if (it != mRenderers.end()) {
712 it->second->SetProfilerUI(aUI);
716 void RenderThread::PostEvent(wr::WindowId aWindowId,
717 UniquePtr<RendererEvent> aEvent) {
718 PostRunnable(NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
719 "wr::RenderThread::PostEvent", this, &RenderThread::RunEvent, aWindowId,
720 std::move(aEvent)));
723 void RenderThread::RunEvent(wr::WindowId aWindowId,
724 UniquePtr<RendererEvent> aEvent) {
725 MOZ_ASSERT(IsInRenderThread());
727 aEvent->Run(*this, aWindowId);
728 aEvent = nullptr;
731 static void NotifyDidRender(layers::CompositorBridgeParent* aBridge,
732 const RefPtr<const WebRenderPipelineInfo>& aInfo,
733 VsyncId aCompositeStartId,
734 TimeStamp aCompositeStart, TimeStamp aRenderStart,
735 TimeStamp aEnd, bool aRender,
736 RendererStats aStats) {
737 if (aRender && aBridge->GetWrBridge()) {
738 // We call this here to mimic the behavior in LayerManagerComposite, as to
739 // not change what Talos measures. That is, we do not record an empty frame
740 // as a frame.
741 aBridge->GetWrBridge()->RecordFrame();
744 aBridge->NotifyDidRender(aCompositeStartId, aCompositeStart, aRenderStart,
745 aEnd, &aStats);
747 for (const auto& epoch : aInfo->Raw().epochs) {
748 aBridge->NotifyPipelineRendered(epoch.pipeline_id, epoch.epoch,
749 aCompositeStartId, aCompositeStart,
750 aRenderStart, aEnd, &aStats);
753 if (aBridge->GetWrBridge()) {
754 aBridge->GetWrBridge()->RetrySkippedComposite();
758 static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) {
759 if (aBridge->GetWrBridge()) {
760 aBridge->GetWrBridge()->RetrySkippedComposite();
764 void RenderThread::SetFramePublishId(wr::WindowId aWindowId,
765 FramePublishId aPublishId) {
766 MOZ_ASSERT(IsInRenderThread());
768 auto it = mRenderers.find(aWindowId);
769 MOZ_ASSERT(it != mRenderers.end());
770 if (it == mRenderers.end()) {
771 return;
773 auto& renderer = it->second;
775 renderer->SetFramePublishId(aPublishId);
778 void RenderThread::UpdateAndRender(
779 wr::WindowId aWindowId, const VsyncId& aStartId,
780 const TimeStamp& aStartTime, bool aRender,
781 const Maybe<gfx::IntSize>& aReadbackSize,
782 const Maybe<wr::ImageFormat>& aReadbackFormat,
783 const Maybe<Range<uint8_t>>& aReadbackBuffer, bool* aNeedsYFlip) {
784 AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS);
785 MOZ_ASSERT(IsInRenderThread());
786 MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
788 auto it = mRenderers.find(aWindowId);
789 MOZ_ASSERT(it != mRenderers.end());
790 if (it == mRenderers.end()) {
791 return;
794 TimeStamp start = TimeStamp::Now();
796 auto& renderer = it->second;
798 std::string markerName = "Composite #" + std::to_string(AsUint64(aWindowId));
799 AutoProfilerTracing tracingCompositeMarker(
800 "Paint", markerName.c_str(), geckoprofiler::category::GRAPHICS,
801 Some(renderer->GetCompositorBridge()->GetInnerWindowId()));
803 if (renderer->IsPaused()) {
804 aRender = false;
806 LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64 " aRender %d",
807 AsUint64(aWindowId), aRender);
809 layers::CompositorThread()->Dispatch(
810 NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender,
811 renderer->GetCompositorBridge()));
813 wr::RenderedFrameId latestFrameId;
814 RendererStats stats = {0};
815 if (aRender) {
816 latestFrameId = renderer->UpdateAndRender(
817 aReadbackSize, aReadbackFormat, aReadbackBuffer, aNeedsYFlip, &stats);
818 } else {
819 renderer->Update();
821 // Check graphics reset status even when rendering is skipped.
822 renderer->CheckGraphicsResetStatus(
823 gfx::DeviceResetDetectPlace::WR_POST_UPDATE,
824 /* aForce */ false);
826 TimeStamp end = TimeStamp::Now();
827 RefPtr<const WebRenderPipelineInfo> info = renderer->GetLastPipelineInfo();
829 layers::CompositorThread()->Dispatch(
830 NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
831 renderer->GetCompositorBridge(), info, aStartId,
832 aStartTime, start, end, aRender, stats));
834 ipc::FileDescriptor fenceFd;
836 if (latestFrameId.IsValid()) {
837 fenceFd = renderer->GetAndResetReleaseFence();
839 // Wait for GPU after posting NotifyDidRender, since the wait is not
840 // necessary for the NotifyDidRender.
841 // The wait is necessary for Textures recycling of AsyncImagePipelineManager
842 // and for avoiding GPU queue is filled with too much tasks.
843 // WaitForGPU's implementation is different for each platform.
844 auto timerId = glean::wr::gpu_wait_time.Start();
845 renderer->WaitForGPU();
846 glean::wr::gpu_wait_time.StopAndAccumulate(std::move(timerId));
847 } else {
848 // Update frame id for NotifyPipelinesUpdated() when rendering does not
849 // happen, either because rendering was not requested or the frame was
850 // canceled. Rendering can sometimes be canceled if UpdateAndRender is
851 // called when the window is not yet ready (not mapped or 0 size).
852 latestFrameId = renderer->UpdateFrameId();
855 RenderedFrameId lastCompletedFrameId = renderer->GetLastCompletedFrameId();
857 RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
858 renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
859 // pipelineMgr should always be non-null here because it is only nulled out
860 // after the WebRenderAPI instance for the CompositorBridgeParent is
861 // destroyed, and that destruction blocks until the renderer thread has
862 // removed the relevant renderer. And after that happens we should never reach
863 // this code at all; it would bail out at the mRenderers.find check above.
864 MOZ_ASSERT(pipelineMgr);
865 pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId,
866 std::move(fenceFd));
869 void RenderThread::Pause(wr::WindowId aWindowId) {
870 MOZ_ASSERT(IsInRenderThread());
871 LOG("RenderThread::Pause() aWindowId %" PRIx64 "", AsUint64(aWindowId));
873 auto it = mRenderers.find(aWindowId);
874 MOZ_ASSERT(it != mRenderers.end());
875 if (it == mRenderers.end()) {
876 gfxCriticalNote << "RenderThread cannot find renderer for window "
877 << gfx::hexa(aWindowId) << " to pause.";
878 return;
880 auto& renderer = it->second;
881 renderer->Pause();
883 UpdateActiveRendererCount();
886 bool RenderThread::Resume(wr::WindowId aWindowId) {
887 MOZ_ASSERT(IsInRenderThread());
888 LOG("enderThread::Resume() aWindowId %" PRIx64 "", AsUint64(aWindowId));
890 auto it = mRenderers.find(aWindowId);
891 MOZ_ASSERT(it != mRenderers.end());
892 if (it == mRenderers.end()) {
893 gfxCriticalNote << "RenderThread cannot find renderer for window "
894 << gfx::hexa(aWindowId) << " to resume.";
895 return false;
897 auto& renderer = it->second;
898 bool resumed = renderer->Resume();
900 UpdateActiveRendererCount();
902 return resumed;
905 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) {
906 const int64_t maxFrameCount = 1;
908 // Too many pending frames if pending frames exit more than maxFrameCount
909 // or if RenderBackend is still processing a frame.
911 auto windows = mWindowInfos.Lock();
912 auto it = windows->find(AsUint64(aWindowId));
913 if (it == windows->end()) {
914 MOZ_ASSERT(false);
915 return true;
917 WindowInfo* info = it->second.get();
919 if (info->PendingCount() > maxFrameCount) {
920 return true;
922 // If there is no ongoing frame build, we accept a new frame.
923 return info->mPendingFrameBuild > 0;
926 bool RenderThread::IsDestroyed(wr::WindowId aWindowId) {
927 auto windows = mWindowInfos.Lock();
928 auto it = windows->find(AsUint64(aWindowId));
929 if (it == windows->end()) {
930 return true;
933 return it->second->mIsDestroyed;
936 void RenderThread::SetDestroyed(wr::WindowId aWindowId) {
937 auto windows = mWindowInfos.Lock();
938 auto it = windows->find(AsUint64(aWindowId));
939 if (it == windows->end()) {
940 MOZ_ASSERT(false);
941 return;
943 it->second->mIsDestroyed = true;
946 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId,
947 const VsyncId& aStartId,
948 const TimeStamp& aStartTime) {
949 auto windows = mWindowInfos.Lock();
950 auto it = windows->find(AsUint64(aWindowId));
951 if (it == windows->end()) {
952 MOZ_ASSERT(false);
953 return;
955 it->second->mPendingFrameBuild++;
956 it->second->mPendingFrames.push(PendingFrameInfo{aStartTime, aStartId});
959 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId) {
960 auto windows = mWindowInfos.Lock();
961 auto it = windows->find(AsUint64(aWindowId));
962 if (it == windows->end()) {
963 MOZ_ASSERT(false);
964 return;
966 WindowInfo* info = it->second.get();
967 MOZ_RELEASE_ASSERT(info->mPendingFrameBuild >= 1);
968 info->mPendingFrameBuild--;
971 void RenderThread::DecPendingFrameCount(wr::WindowId aWindowId) {
972 auto windows = mWindowInfos.Lock();
973 auto it = windows->find(AsUint64(aWindowId));
974 if (it == windows->end()) {
975 MOZ_ASSERT(false);
976 return;
978 WindowInfo* info = it->second.get();
979 info->mPendingFrames.pop();
982 void RenderThread::RegisterExternalImage(
983 const wr::ExternalImageId& aExternalImageId,
984 already_AddRefed<RenderTextureHost> aTexture) {
985 MutexAutoLock lock(mRenderTextureMapLock);
987 if (mHasShutdown) {
988 return;
990 MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
991 RefPtr<RenderTextureHost> texture = aTexture;
992 if (texture->SyncObjectNeeded()) {
993 mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture);
995 mRenderTextures.emplace(aExternalImageId, texture);
997 #ifdef DEBUG
998 int32_t maxAllowedIncrease =
999 StaticPrefs::gfx_testing_assert_render_textures_increase();
1001 if (maxAllowedIncrease <= 0) {
1002 mRenderTexturesLastTime = -1;
1003 } else {
1004 if (mRenderTexturesLastTime < 0) {
1005 mRenderTexturesLastTime = static_cast<int32_t>(mRenderTextures.size());
1007 MOZ_ASSERT((static_cast<int32_t>(mRenderTextures.size()) -
1008 mRenderTexturesLastTime) < maxAllowedIncrease);
1010 #endif
1013 void RenderThread::UnregisterExternalImage(
1014 const wr::ExternalImageId& aExternalImageId) {
1015 MutexAutoLock lock(mRenderTextureMapLock);
1016 if (mHasShutdown) {
1017 return;
1019 auto it = mRenderTextures.find(aExternalImageId);
1020 if (it == mRenderTextures.end()) {
1021 return;
1024 auto& texture = it->second;
1025 if (texture->SyncObjectNeeded()) {
1026 MOZ_RELEASE_ASSERT(
1027 mSyncObjectNeededRenderTextures.erase(aExternalImageId) == 1);
1030 if (!IsInRenderThread()) {
1031 // The RenderTextureHost should be released in render thread. So, post the
1032 // deletion task here.
1033 // The shmem and raw buffer are owned by compositor ipc channel. It's
1034 // possible that RenderTextureHost is still exist after the shmem/raw buffer
1035 // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
1036 // for this situation. Gecko will only release the buffer if WR doesn't need
1037 // it. So, no one will access the invalid buffer in RenderTextureHost.
1038 RefPtr<RenderTextureHost> texture = it->second;
1039 mRenderTextures.erase(it);
1040 mRenderTexturesDeferred.emplace_back(std::move(texture));
1041 PostRunnable(NewRunnableMethod(
1042 "RenderThread::DeferredRenderTextureHostDestroy", this,
1043 &RenderThread::DeferredRenderTextureHostDestroy));
1044 } else {
1045 mRenderTextures.erase(it);
1049 void RenderThread::DestroyExternalImagesSyncWait(
1050 const std::vector<wr::ExternalImageId>&& aIds) {
1051 if (!IsInRenderThread()) {
1052 layers::SynchronousTask task("Destroy external images");
1054 RefPtr<Runnable> runnable = NS_NewRunnableFunction(
1055 "RenderThread::DestroyExternalImagesSyncWait::Runnable",
1056 [&task, ids = std::move(aIds)]() {
1057 layers::AutoCompleteTask complete(&task);
1058 RenderThread::Get()->DestroyExternalImages(std::move(ids));
1061 PostRunnable(runnable.forget());
1062 task.Wait();
1063 return;
1065 DestroyExternalImages(std::move(aIds));
1068 void RenderThread::DestroyExternalImages(
1069 const std::vector<wr::ExternalImageId>&& aIds) {
1070 MOZ_ASSERT(IsInRenderThread());
1072 std::vector<RefPtr<RenderTextureHost>> hosts;
1074 MutexAutoLock lock(mRenderTextureMapLock);
1075 if (mHasShutdown) {
1076 return;
1079 for (auto& id : aIds) {
1080 auto it = mRenderTextures.find(id);
1081 if (it == mRenderTextures.end()) {
1082 continue;
1084 hosts.emplace_back(it->second);
1088 for (auto& host : hosts) {
1089 host->Destroy();
1093 void RenderThread::PrepareForUse(const wr::ExternalImageId& aExternalImageId) {
1094 AddRenderTextureOp(RenderTextureOp::PrepareForUse, aExternalImageId);
1097 void RenderThread::NotifyNotUsed(const wr::ExternalImageId& aExternalImageId) {
1098 AddRenderTextureOp(RenderTextureOp::NotifyNotUsed, aExternalImageId);
1101 void RenderThread::NotifyForUse(const wr::ExternalImageId& aExternalImageId) {
1102 AddRenderTextureOp(RenderTextureOp::NotifyForUse, aExternalImageId);
1105 void RenderThread::AddRenderTextureOp(
1106 RenderTextureOp aOp, const wr::ExternalImageId& aExternalImageId) {
1107 MOZ_ASSERT(!IsInRenderThread());
1109 MutexAutoLock lock(mRenderTextureMapLock);
1111 auto it = mRenderTextures.find(aExternalImageId);
1112 MOZ_ASSERT(it != mRenderTextures.end());
1113 if (it == mRenderTextures.end()) {
1114 return;
1117 RefPtr<RenderTextureHost> texture = it->second;
1118 mRenderTextureOps.emplace_back(aOp, std::move(texture));
1120 if (mRenderTextureOpsRunnable) {
1121 // Runnable was already triggered
1122 return;
1125 RefPtr<nsIRunnable> runnable =
1126 NewRunnableMethod("RenderThread::HandleRenderTextureOps", this,
1127 &RenderThread::HandleRenderTextureOps);
1128 mRenderTextureOpsRunnable = runnable;
1129 PostRunnable(runnable.forget());
1132 void RenderThread::HandleRenderTextureOps() {
1133 MOZ_ASSERT(IsInRenderThread());
1135 std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>>
1136 renderTextureOps;
1138 MutexAutoLock lock(mRenderTextureMapLock);
1139 mRenderTextureOps.swap(renderTextureOps);
1140 mRenderTextureOpsRunnable = nullptr;
1143 for (auto& it : renderTextureOps) {
1144 switch (it.first) {
1145 case RenderTextureOp::PrepareForUse:
1146 it.second->PrepareForUse();
1147 break;
1148 case RenderTextureOp::NotifyForUse:
1149 it.second->NotifyForUse();
1150 break;
1151 case RenderTextureOp::NotifyNotUsed:
1152 it.second->NotifyNotUsed();
1153 break;
1158 void RenderThread::UnregisterExternalImageDuringShutdown(
1159 const wr::ExternalImageId& aExternalImageId) {
1160 MOZ_ASSERT(IsInRenderThread());
1161 MutexAutoLock lock(mRenderTextureMapLock);
1162 MOZ_ASSERT(mHasShutdown);
1163 mRenderTextures.erase(aExternalImageId);
1166 bool RenderThread::SyncObjectNeeded() {
1167 MOZ_ASSERT(IsInRenderThread());
1168 MutexAutoLock lock(mRenderTextureMapLock);
1169 return !mSyncObjectNeededRenderTextures.empty();
1172 void RenderThread::DeferredRenderTextureHostDestroy() {
1173 MutexAutoLock lock(mRenderTextureMapLock);
1174 mRenderTexturesDeferred.clear();
1177 RenderTextureHost* RenderThread::GetRenderTexture(
1178 const wr::ExternalImageId& aExternalImageId) {
1179 MutexAutoLock lock(mRenderTextureMapLock);
1180 auto it = mRenderTextures.find(aExternalImageId);
1181 MOZ_ASSERT(it != mRenderTextures.end());
1182 if (it == mRenderTextures.end()) {
1183 return nullptr;
1185 return it->second;
1188 void RenderThread::InitDeviceTask() {
1189 MOZ_ASSERT(IsInRenderThread());
1190 MOZ_ASSERT(!mSingletonGL);
1191 LOG("RenderThread::InitDeviceTask()");
1193 if (gfx::gfxVars::UseSoftwareWebRender()) {
1194 // Ensure we don't instantiate any shared GL context when SW-WR is used.
1195 return;
1198 nsAutoCString err;
1199 CreateSingletonGL(err);
1200 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1201 mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
1203 // Query the shared GL context to force the
1204 // lazy initialization to happen now.
1205 SingletonGL();
1208 void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
1209 nsCOMPtr<nsIRunnable> runnable = aRunnable;
1210 mThread->Dispatch(runnable.forget());
1213 void RenderThread::HandleDeviceReset(gfx::DeviceResetDetectPlace aPlace,
1214 gfx::DeviceResetReason aReason) {
1215 MOZ_ASSERT(IsInRenderThread());
1217 // This happens only on simulate device reset.
1218 if (aReason == gfx::DeviceResetReason::FORCED_RESET) {
1219 if (!mHandlingDeviceReset) {
1220 mHandlingDeviceReset = true;
1222 MutexAutoLock lock(mRenderTextureMapLock);
1223 mRenderTexturesDeferred.clear();
1224 for (const auto& entry : mRenderTextures) {
1225 entry.second->ClearCachedResources();
1228 // All RenderCompositors will be destroyed by the GPUProcessManager in
1229 // either OnRemoteProcessDeviceReset via the GPUChild, or
1230 // OnInProcessDeviceReset here directly.
1231 gfx::GPUProcessManager::GPUProcessManager::NotifyDeviceReset(
1232 gfx::DeviceResetReason::FORCED_RESET, aPlace);
1234 return;
1237 if (mHandlingDeviceReset) {
1238 return;
1241 mHandlingDeviceReset = true;
1243 #ifndef XP_WIN
1244 // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices.
1245 gfx::GPUProcessManager::RecordDeviceReset(aReason);
1246 #endif
1249 MutexAutoLock lock(mRenderTextureMapLock);
1250 mRenderTexturesDeferred.clear();
1251 for (const auto& entry : mRenderTextures) {
1252 entry.second->ClearCachedResources();
1256 // All RenderCompositors will be destroyed by the GPUProcessManager in
1257 // either OnRemoteProcessDeviceReset via the GPUChild, or
1258 // OnInProcessDeviceReset here directly.
1259 // On Windows, device will be re-created before sessions re-creation.
1260 if (XRE_IsGPUProcess()) {
1261 gfx::GPUProcessManager::GPUProcessManager::NotifyDeviceReset(aReason,
1262 aPlace);
1263 } else {
1264 #ifndef XP_WIN
1265 // FIXME(aosmond): Do we need to do this on Windows? nsWindow::OnPaint
1266 // seems to do its own detection for the parent process.
1267 gfx::GPUProcessManager::GPUProcessManager::NotifyDeviceReset(aReason,
1268 aPlace);
1269 #endif
1273 bool RenderThread::IsHandlingDeviceReset() {
1274 MOZ_ASSERT(IsInRenderThread());
1275 return mHandlingDeviceReset;
1278 void RenderThread::SimulateDeviceReset() {
1279 if (!IsInRenderThread()) {
1280 PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this,
1281 &RenderThread::SimulateDeviceReset));
1282 } else {
1283 // When this function is called GPUProcessManager::SimulateDeviceReset()
1284 // already triggers destroying all CompositorSessions before re-creating
1285 // them.
1286 HandleDeviceReset(gfx::DeviceResetDetectPlace::WR_SIMULATE,
1287 gfx::DeviceResetReason::FORCED_RESET);
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 MaybeWebRenderGlyphRasterThread::MaybeWebRenderGlyphRasterThread(bool aEnable) {
1483 if (aEnable) {
1484 mThread = wr_glyph_raster_thread_new();
1485 } else {
1486 mThread = nullptr;
1490 MaybeWebRenderGlyphRasterThread::~MaybeWebRenderGlyphRasterThread() {
1491 if (mThread) {
1492 wr_glyph_raster_thread_delete(mThread);
1496 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) {
1497 MOZ_ASSERT(aThreadPool);
1499 nsAutoString path;
1500 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1501 path.Append(gfx::gfxVars::ProfDirectory());
1503 mProgramCache = wr_program_cache_new(&path, aThreadPool);
1504 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1505 wr_try_load_startup_shaders_from_disk(mProgramCache);
1509 WebRenderProgramCache::~WebRenderProgramCache() {
1510 wr_program_cache_delete(mProgramCache);
1513 } // namespace mozilla::wr
1515 #ifdef XP_WIN
1516 static already_AddRefed<gl::GLContext> CreateGLContextANGLE(
1517 nsACString& aError) {
1518 const RefPtr<ID3D11Device> d3d11Device =
1519 gfx::DeviceManagerDx::Get()->GetCompositorDevice();
1520 if (!d3d11Device) {
1521 aError.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns);
1522 return nullptr;
1525 nsCString failureId;
1526 const auto lib = gl::GLLibraryEGL::Get(&failureId);
1527 if (!lib) {
1528 aError.Assign(
1529 nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get()));
1530 return nullptr;
1533 const auto egl = lib->CreateDisplay(d3d11Device.get());
1534 if (!egl) {
1535 aError.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
1536 failureId.get()));
1537 return nullptr;
1540 gl::CreateContextFlags flags = gl::CreateContextFlags::PREFER_ES3;
1542 if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
1543 flags |= gl::CreateContextFlags::PREFER_ROBUSTNESS;
1546 if (egl->IsExtensionSupported(
1547 gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
1548 flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE;
1551 // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
1552 // Instread we override it with EGLSurface of SwapChain's back buffer.
1554 auto gl = gl::GLContextEGL::CreateWithoutSurface(egl, {flags}, &failureId);
1555 if (!gl || !gl->IsANGLE()) {
1556 aError.Assign(nsPrintfCString("RcANGLE(create GL context failed: %p, %s)",
1557 gl.get(), failureId.get()));
1558 return nullptr;
1561 if (!gl->MakeCurrent()) {
1562 aError.Assign(
1563 nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)",
1564 gl.get(), gl->mEgl->mLib->fGetError()));
1565 return nullptr;
1568 return gl.forget();
1570 #endif
1572 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GTK)
1573 static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
1574 // Create GLContext with dummy EGLSurface.
1575 bool forHardwareWebRender = true;
1576 // SW-WR uses CompositorOGL in native compositor.
1577 if (gfx::gfxVars::UseSoftwareWebRender()) {
1578 forHardwareWebRender = false;
1580 RefPtr<gl::GLContext> gl =
1581 gl::GLContextProviderEGL::CreateForCompositorWidget(
1582 nullptr, forHardwareWebRender, /* aForceAccelerated */ true);
1583 if (!gl || !gl->MakeCurrent()) {
1584 gfxCriticalNote << "Failed GL context creation for hardware WebRender: "
1585 << forHardwareWebRender;
1586 return nullptr;
1588 return gl.forget();
1590 #endif
1592 #ifdef XP_DARWIN
1593 static already_AddRefed<gl::GLContext> CreateGLContextCGL() {
1594 nsCString failureUnused;
1595 return gl::GLContextProvider::CreateHeadless(
1596 {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
1597 gl::CreateContextFlags::FORBID_SOFTWARE},
1598 &failureUnused);
1600 #endif
1602 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) {
1603 RefPtr<gl::GLContext> gl;
1605 #ifdef XP_WIN
1606 if (gfx::gfxVars::UseWebRenderANGLE()) {
1607 gl = CreateGLContextANGLE(aError);
1609 #elif defined(MOZ_WIDGET_ANDROID)
1610 gl = CreateGLContextEGL();
1611 #elif defined(MOZ_WIDGET_GTK)
1612 if (gfx::gfxVars::UseEGL()) {
1613 gl = CreateGLContextEGL();
1615 #elif XP_DARWIN
1616 gl = CreateGLContextCGL();
1617 #endif
1619 wr::RenderThread::MaybeEnableGLDebugMessage(gl);
1621 return gl.forget();
1624 extern "C" {
1626 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId,
1627 bool aCompositeNeeded) {
1628 // wake_up is used for things like propagating debug options or memory
1629 // pressure events, so we are not tracking pending frame counts.
1630 mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId,
1631 aCompositeNeeded);
1634 void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId,
1635 bool aCompositeNeeded,
1636 mozilla::wr::FramePublishId aPublishId) {
1637 auto* renderThread = mozilla::wr::RenderThread::Get();
1638 renderThread->DecPendingFrameBuildCount(aWindowId);
1640 renderThread->WrNotifierEvent_NewFrameReady(aWindowId, aCompositeNeeded,
1641 aPublishId);
1644 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
1645 size_t aRawEvent) {
1646 mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent(
1647 mozilla::wr::WindowId(aWindowId), aRawEvent);
1650 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,
1651 wr::RenderReasons aReasons) {
1652 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1653 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1654 if (cbp) {
1655 cbp->ScheduleComposition(aReasons);
1659 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
1660 wr::RenderReasons aReasons) {
1661 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1662 "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons));
1665 static void NotifyDidSceneBuild(
1666 mozilla::wr::WrWindowId aWindowId,
1667 const RefPtr<const wr::WebRenderPipelineInfo>& aInfo) {
1668 RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1669 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1670 if (cbp) {
1671 cbp->NotifyDidSceneBuild(aInfo);
1675 void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,
1676 mozilla::wr::WrPipelineInfo* aPipelineInfo) {
1677 RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo();
1678 info->Raw() = std::move(*aPipelineInfo);
1679 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1680 "NotifyDidSceneBuild", &NotifyDidSceneBuild, aWindowId, info));
1683 } // extern C