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/. */
8 #include "GeckoProfiler.h"
9 #include "gfxPlatform.h"
10 #include "GLContext.h"
11 #include "RenderThread.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"
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>
46 #ifdef MOZ_WIDGET_ANDROID
47 # include "GLLibraryEGL.h"
48 # include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h"
52 # include "mozilla/WidgetUtilsGtk.h"
53 # include "GLLibraryEGL.h"
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
;
71 static bool sRenderThreadEverStarted
= false;
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;
79 static bool USE_DEDICATED_GLYPH_RASTER_THREAD
= false;
82 RenderThread::RenderThread(RefPtr
<nsIThread
> aThread
)
83 : mThread(std::move(aThread
)),
86 mGlyphRasterThread(USE_DEDICATED_GLYPH_RASTER_THREAD
),
87 mSingletonGLIsForHardwareWebRender(true),
88 mBatteryInfo("RenderThread.mBatteryInfo"),
89 mWindowInfos("RenderThread.mWindowInfos"),
90 mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
92 mHandlingDeviceReset(false),
93 mHandlingWebRenderError(false) {}
95 RenderThread::~RenderThread() { MOZ_ASSERT(mRenderTexturesDeferred
.empty()); }
98 RenderThread
* RenderThread::Get() { return sRenderThread
; }
101 void RenderThread::Start(uint32_t aNamespace
) {
102 MOZ_ASSERT(NS_IsMainThread());
103 MOZ_ASSERT(!sRenderThread
);
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;
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
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);
136 RefPtr
<nsIThread
> thread
;
137 nsresult rv
= NS_NewNamedThread(
138 "Renderer", getter_AddRefs(thread
),
139 NS_NewRunnableFunction(
140 "Renderer::BackgroundHanSetup",
142 sBackgroundHangMonitor
= new mozilla::BackgroundHangMonitor(
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). */
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. */
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
});
161 gfxCriticalNote
<< "Failed to create Renderer thread: "
162 << gfx::hexa((uint32_t)rv
);
166 sRenderThread
= new RenderThread(thread
);
167 CrashReporter::RegisterAnnotationUSize(
168 CrashReporter::Annotation::GraphicsNumRenderers
, &sRendererCount
);
169 CrashReporter::RegisterAnnotationUSize(
170 CrashReporter::Annotation::GraphicsNumActiveRenderers
,
171 &sActiveRendererCount
);
173 widget::WinCompositorWindowThread::Start();
175 layers::SharedSurfacesParent::Initialize();
177 RefPtr
<Runnable
> runnable
= WrapRunnable(
178 RefPtr
<RenderThread
>(sRenderThread
.get()), &RenderThread::InitDeviceTask
);
179 sRenderThread
->PostRunnable(runnable
.forget());
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();
204 if (widget::WinCompositorWindowThread::Get()) {
205 widget::WinCompositorWindowThread::ShutDown();
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();
239 DCLayerTree::Shutdown();
242 ClearAllBlobImageResources();
244 ClearSharedSurfacePool();
248 bool RenderThread::IsInRenderThread() {
249 return sRenderThread
&& sRenderThread
->mThread
== NS_GetCurrentThread();
253 already_AddRefed
<nsIThread
> RenderThread::GetRenderThread() {
254 nsCOMPtr
<nsIThread
> thread
;
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
272 MOZ_ASSERT(aReport
.shader_cache
== 0);
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__
);
291 RefPtr
<MemoryReportPromise
> RenderThread::AccumulateMemoryReport(
292 MemoryReport aInitial
) {
293 RefPtr
<MemoryReportPromise::Private
> p
=
294 new MemoryReportPromise::Private(__func__
);
295 MOZ_ASSERT(!IsInRenderThread());
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__
);
307 NewRunnableMethod
<MemoryReport
, RefPtr
<MemoryReportPromise::Private
>>(
308 "wr::RenderThread::DoAccumulateMemoryReport", Get(),
309 &RenderThread::DoAccumulateMemoryReport
, aInitial
, 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");
334 void RenderThread::AddRenderer(wr::WindowId aWindowId
,
335 UniquePtr
<RendererOGL
> aRenderer
) {
336 MOZ_ASSERT(IsInRenderThread());
337 LOG("RenderThread::AddRenderer() aWindowId %" PRIx64
"", AsUint64(aWindowId
));
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
));
361 mRenderers
.erase(aWindowId
);
362 sRendererCount
= mRenderers
.size();
364 if (mRenderers
.empty()) {
365 if (mHandlingDeviceReset
) {
368 mHandlingDeviceReset
= false;
369 mHandlingWebRenderError
= false;
372 auto windows
= mWindowInfos
.Lock();
373 auto it
= windows
->find(AsUint64(aWindowId
));
374 MOZ_ASSERT(it
!= windows
->end());
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()) {
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()) {
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()) {
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()) {
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()) {
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
,
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()) {
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()) {
478 WindowInfo
* info
= it
->second
.get();
479 PostWrNotifierEvents(aWindowId
, info
);
483 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId
,
485 // Runnable has already been triggered.
486 if (aInfo
->mWrNotifierEventsRunnable
) {
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()) {
505 auto* events
= eventsIt
->second
.get();
508 auto windows
= mWindowInfos
.Lock();
509 auto infoIt
= windows
->find(AsUint64(aWindowId
));
510 if (infoIt
== windows
->end()) {
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());
531 case WrNotifierEvent::Tag::NewFrameReady
:
532 WrNotifierEvent_HandleNewFrameReady(aWindowId
, front
.CompositeNeeded(),
536 case WrNotifierEvent::Tag::ExternalEvent
:
537 WrNotifierEvent_HandleExternalEvent(aWindowId
, front
.ExternalEvent());
544 auto windows
= mWindowInfos
.Lock();
545 auto it
= windows
->find(AsUint64(aWindowId
));
546 if (it
== windows
->end()) {
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
,
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
,
602 Maybe
<FramePublishId
> aPublishId
) {
603 MOZ_ASSERT(IsInRenderThread());
609 HandleFrameOneDocInner(aWindowId
, aRender
, aTrackedFrame
, aPublishId
);
612 DecPendingFrameCount(aWindowId
);
616 void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId
, bool aRender
,
618 Maybe
<FramePublishId
> aPublishId
) {
619 if (IsDestroyed(aWindowId
)) {
623 if (mHandlingDeviceReset
) {
627 bool render
= aRender
;
628 PendingFrameInfo frame
;
631 auto windows
= mWindowInfos
.Lock();
632 auto it
= windows
->find(AsUint64(aWindowId
));
633 if (it
== windows
->end()) {
638 WindowInfo
* info
= it
->second
.get();
639 PendingFrameInfo
& frameInfo
= info
->mPendingFrames
.front();
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
649 glean::wr::time_to_render_start
.AccumulateRawDuration(TimeStamp::Now() -
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
,
674 void RenderThread::SetClearColor(wr::WindowId aWindowId
, wr::ColorF aColor
) {
679 if (!IsInRenderThread()) {
680 PostRunnable(NewRunnableMethod
<wr::WindowId
, wr::ColorF
>(
681 "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor
,
686 if (IsDestroyed(aWindowId
)) {
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
) {
703 if (!IsInRenderThread()) {
704 PostRunnable(NewRunnableMethod
<wr::WindowId
, nsCString
>(
705 "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI
,
706 aWindowId
, nsCString(aUI
)));
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
,
723 void RenderThread::RunEvent(wr::WindowId aWindowId
,
724 UniquePtr
<RendererEvent
> aEvent
) {
725 MOZ_ASSERT(IsInRenderThread());
727 aEvent
->Run(*this, aWindowId
);
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
741 aBridge
->GetWrBridge()->RecordFrame();
744 aBridge
->NotifyDidRender(aCompositeStartId
, aCompositeStart
, aRenderStart
,
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()) {
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()) {
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()) {
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};
816 latestFrameId
= renderer
->UpdateAndRender(
817 aReadbackSize
, aReadbackFormat
, aReadbackBuffer
, aNeedsYFlip
, &stats
);
821 // Check graphics reset status even when rendering is skipped.
822 renderer
->CheckGraphicsResetStatus(
823 gfx::DeviceResetDetectPlace::WR_POST_UPDATE
,
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
));
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
,
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.";
880 auto& renderer
= it
->second
;
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.";
897 auto& renderer
= it
->second
;
898 bool resumed
= renderer
->Resume();
900 UpdateActiveRendererCount();
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()) {
917 WindowInfo
* info
= it
->second
.get();
919 if (info
->PendingCount() > maxFrameCount
) {
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()) {
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()) {
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()) {
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()) {
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()) {
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
);
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
);
998 int32_t maxAllowedIncrease
=
999 StaticPrefs::gfx_testing_assert_render_textures_increase();
1001 if (maxAllowedIncrease
<= 0) {
1002 mRenderTexturesLastTime
= -1;
1004 if (mRenderTexturesLastTime
< 0) {
1005 mRenderTexturesLastTime
= static_cast<int32_t>(mRenderTextures
.size());
1007 MOZ_ASSERT((static_cast<int32_t>(mRenderTextures
.size()) -
1008 mRenderTexturesLastTime
) < maxAllowedIncrease
);
1013 void RenderThread::UnregisterExternalImage(
1014 const wr::ExternalImageId
& aExternalImageId
) {
1015 MutexAutoLock
lock(mRenderTextureMapLock
);
1019 auto it
= mRenderTextures
.find(aExternalImageId
);
1020 if (it
== mRenderTextures
.end()) {
1024 auto& texture
= it
->second
;
1025 if (texture
->SyncObjectNeeded()) {
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
));
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());
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
);
1079 for (auto& id
: aIds
) {
1080 auto it
= mRenderTextures
.find(id
);
1081 if (it
== mRenderTextures
.end()) {
1084 hosts
.emplace_back(it
->second
);
1088 for (auto& host
: hosts
) {
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()) {
1117 RefPtr
<RenderTextureHost
> texture
= it
->second
;
1118 mRenderTextureOps
.emplace_back(aOp
, std::move(texture
));
1120 if (mRenderTextureOpsRunnable
) {
1121 // Runnable was already triggered
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
>>>
1138 MutexAutoLock
lock(mRenderTextureMapLock
);
1139 mRenderTextureOps
.swap(renderTextureOps
);
1140 mRenderTextureOpsRunnable
= nullptr;
1143 for (auto& it
: renderTextureOps
) {
1145 case RenderTextureOp::PrepareForUse
:
1146 it
.second
->PrepareForUse();
1148 case RenderTextureOp::NotifyForUse
:
1149 it
.second
->NotifyForUse();
1151 case RenderTextureOp::NotifyNotUsed
:
1152 it
.second
->NotifyNotUsed();
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()) {
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.
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.
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
);
1237 if (mHandlingDeviceReset
) {
1241 mHandlingDeviceReset
= true;
1244 // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices.
1245 gfx::GPUProcessManager::RecordDeviceReset(aReason
);
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
,
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
,
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
));
1283 // When this function is called GPUProcessManager::SimulateDeviceReset()
1284 // already triggers destroying all CompositorSessions before re-creating
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
) {
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() {
1329 auto* gl
= SingletonGL(err
);
1330 if (!err
.IsEmpty()) {
1331 gfxCriticalNote
<< err
.get();
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
);
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.
1364 return SingletonGL();
1367 void RenderThread::ClearSingletonGL() {
1368 MOZ_ASSERT(IsInRenderThread());
1369 LOG("RenderThread::ClearSingletonGL()");
1372 mSurfacePool
->DestroyGLResourcesForContext(mSingletonGL
);
1374 if (mProgramsForCompositorOGL
) {
1375 mProgramsForCompositorOGL
->Clear();
1376 mProgramsForCompositorOGL
= nullptr;
1380 mSingletonGL
->MakeCurrent();
1384 mSingletonGL
= nullptr;
1387 RefPtr
<layers::ShaderProgramOGLsHolder
>
1388 RenderThread::GetProgramsForCompositorOGL() {
1389 if (!mSingletonGL
) {
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
);
1408 return mSurfacePool
;
1411 void RenderThread::ClearSharedSurfacePool() { mSurfacePool
= nullptr; }
1413 static void GLAPIENTRY
DebugMessageCallback(GLenum aSource
, GLenum aType
,
1414 GLuint aId
, GLenum aSeverity
,
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
;
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
);
1438 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext
* aGLContext
) {
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
) {
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() {
1477 wr_thread_pool_delete(mThreadPool
);
1478 mThreadPool
= nullptr;
1482 MaybeWebRenderGlyphRasterThread::MaybeWebRenderGlyphRasterThread(bool aEnable
) {
1484 mThread
= wr_glyph_raster_thread_new();
1490 MaybeWebRenderGlyphRasterThread::~MaybeWebRenderGlyphRasterThread() {
1492 wr_glyph_raster_thread_delete(mThread
);
1496 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool
* aThreadPool
) {
1497 MOZ_ASSERT(aThreadPool
);
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
1516 static already_AddRefed
<gl::GLContext
> CreateGLContextANGLE(
1517 nsACString
& aError
) {
1518 const RefPtr
<ID3D11Device
> d3d11Device
=
1519 gfx::DeviceManagerDx::Get()->GetCompositorDevice();
1521 aError
.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns
);
1525 nsCString failureId
;
1526 const auto lib
= gl::GLLibraryEGL::Get(&failureId
);
1529 nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId
.get()));
1533 const auto egl
= lib
->CreateDisplay(d3d11Device
.get());
1535 aError
.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
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()));
1561 if (!gl
->MakeCurrent()) {
1563 nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)",
1564 gl
.get(), gl
->mEgl
->mLib
->fGetError()));
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
;
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
},
1602 static already_AddRefed
<gl::GLContext
> CreateGLContext(nsACString
& aError
) {
1603 RefPtr
<gl::GLContext
> gl
;
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();
1616 gl
= CreateGLContextCGL();
1619 wr::RenderThread::MaybeEnableGLDebugMessage(gl
);
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
,
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
,
1644 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId
,
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
);
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
);
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
));