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"
56 # include "GLLibraryEGL.h"
59 using namespace mozilla
;
61 static already_AddRefed
<gl::GLContext
> CreateGLContext(nsACString
& aError
);
63 MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderRendererMallocSizeOf
)
65 namespace mozilla::wr
{
67 LazyLogModule
gRenderThreadLog("RenderThread");
68 // Should be called only on RenderThread, since LazyLogModule is not thread safe
69 #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
71 static StaticRefPtr
<RenderThread
> sRenderThread
;
72 static mozilla::BackgroundHangMonitor
* sBackgroundHangMonitor
;
74 static bool sRenderThreadEverStarted
= false;
77 RenderThread::RenderThread(RefPtr
<nsIThread
> aThread
)
78 : mThread(std::move(aThread
)),
81 mSingletonGLIsForHardwareWebRender(true),
82 mWindowInfos("RenderThread.mWindowInfos"),
83 mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
85 mHandlingDeviceReset(false),
86 mHandlingWebRenderError(false) {}
88 RenderThread::~RenderThread() { MOZ_ASSERT(mRenderTexturesDeferred
.empty()); }
91 RenderThread
* RenderThread::Get() { return sRenderThread
; }
94 void RenderThread::Start(uint32_t aNamespace
) {
95 MOZ_ASSERT(NS_IsMainThread());
96 MOZ_ASSERT(!sRenderThread
);
99 // Check to ensure nobody will try to ever start us more than once during
100 // the process' lifetime (in particular after ShutDown).
101 MOZ_ASSERT(!sRenderThreadEverStarted
);
102 sRenderThreadEverStarted
= true;
105 // When the CanvasRenderer thread is disabled, WebGL may be handled on this
106 // thread, requiring a bigger stack size. See: CanvasManagerParent::Init
108 // This is 4M, which is higher than the default 256K.
109 // Increased with bug 1753349 to accommodate the `chromium/5359` branch of
110 // ANGLE, which has large peak stack usage for some pathological shader
113 // Previously increased to 512K to accommodate Mesa in bug 1753340.
115 // Previously increased to 320K to avoid a stack overflow in the
116 // Intel Vulkan driver initialization in bug 1716120.
118 // Note: we only override it if it's limited already.
119 uint32_t stackSize
= nsIThreadManager::DEFAULT_STACK_SIZE
;
120 if (stackSize
&& !gfx::gfxVars::SupportsThreadsafeGL()) {
121 stackSize
= std::max(stackSize
, 4096U << 10);
124 RefPtr
<nsIThread
> thread
;
125 nsresult rv
= NS_NewNamedThread(
126 "Renderer", getter_AddRefs(thread
),
127 NS_NewRunnableFunction(
128 "Renderer::BackgroundHanSetup",
130 sBackgroundHangMonitor
= new mozilla::BackgroundHangMonitor(
132 /* Timeout values are powers-of-two to enable us get better
133 data. 128ms is chosen for transient hangs because 8Hz should
134 be the minimally acceptable goal for Render
135 responsiveness (normal goal is 60Hz). */
137 /* 2048ms is chosen for permanent hangs because it's longer than
138 * most Render hangs seen in the wild, but is short enough
139 * to not miss getting native hang stacks. */
141 nsCOMPtr
<nsIThread
> thread
= NS_GetCurrentThread();
142 nsThread
* nsthread
= static_cast<nsThread
*>(thread
.get());
143 nsthread
->SetUseHangMonitor(true);
144 nsthread
->SetPriority(nsISupportsPriority::PRIORITY_HIGH
);
146 {.stackSize
= stackSize
});
149 gfxCriticalNote
<< "Failed to create Renderer thread: "
150 << gfx::hexa((uint32_t)rv
);
154 sRenderThread
= new RenderThread(thread
);
156 widget::WinCompositorWindowThread::Start();
158 layers::SharedSurfacesParent::Initialize();
160 RefPtr
<Runnable
> runnable
= WrapRunnable(
161 RefPtr
<RenderThread
>(sRenderThread
.get()), &RenderThread::InitDeviceTask
);
162 sRenderThread
->PostRunnable(runnable
.forget());
166 void RenderThread::ShutDown() {
167 MOZ_ASSERT(NS_IsMainThread());
168 MOZ_ASSERT(sRenderThread
);
171 MutexAutoLock
lock(sRenderThread
->mRenderTextureMapLock
);
172 sRenderThread
->mHasShutdown
= true;
175 RefPtr
<Runnable
> runnable
= WrapRunnable(
176 RefPtr
<RenderThread
>(sRenderThread
.get()), &RenderThread::ShutDownTask
);
177 sRenderThread
->PostRunnable(runnable
.forget());
179 // This will empty the thread queue and thus run the above runnable while
180 // spinning the MT event loop.
181 nsCOMPtr
<nsIThread
> oldThread
= sRenderThread
->GetRenderThread();
182 oldThread
->Shutdown();
184 layers::SharedSurfacesParent::Shutdown();
187 if (widget::WinCompositorWindowThread::Get()) {
188 widget::WinCompositorWindowThread::ShutDown();
192 // We null this out only after we finished shutdown to give everbody the
193 // chance to check for sRenderThread->mHasShutdown. Hopefully everybody
194 // checks this before using us!
195 sRenderThread
= nullptr;
198 extern void ClearAllBlobImageResources();
200 void RenderThread::ShutDownTask() {
201 MOZ_ASSERT(IsInRenderThread());
202 LOG("RenderThread::ShutDownTask()");
205 // Clear RenderTextureHosts
206 MutexAutoLock
lock(mRenderTextureMapLock
);
207 mRenderTexturesDeferred
.clear();
208 mRenderTextures
.clear();
209 mSyncObjectNeededRenderTextures
.clear();
210 mRenderTextureOps
.clear();
213 // Let go of our handle to the (internally ref-counted) thread pool.
214 mThreadPool
.Release();
215 mThreadPoolLP
.Release();
217 // Releasing on the render thread will allow us to avoid dispatching to remove
218 // remaining textures from the texture map.
219 layers::SharedSurfacesParent::ShutdownRenderThread();
222 DCLayerTree::Shutdown();
225 ClearAllBlobImageResources();
227 ClearSharedSurfacePool();
231 bool RenderThread::IsInRenderThread() {
232 return sRenderThread
&& sRenderThread
->mThread
== NS_GetCurrentThread();
236 already_AddRefed
<nsIThread
> RenderThread::GetRenderThread() {
237 nsCOMPtr
<nsIThread
> thread
;
239 thread
= sRenderThread
->mThread
;
241 return thread
.forget();
244 void RenderThread::DoAccumulateMemoryReport(
245 MemoryReport aReport
,
246 const RefPtr
<MemoryReportPromise::Private
>& aPromise
) {
247 MOZ_ASSERT(IsInRenderThread());
249 for (auto& r
: mRenderers
) {
250 r
.second
->AccumulateMemoryReport(&aReport
);
253 // Note memory used by the shader cache, which is shared across all WR
255 MOZ_ASSERT(aReport
.shader_cache
== 0);
257 aReport
.shader_cache
= wr_program_cache_report_memory(
258 mProgramCache
->Raw(), &WebRenderRendererMallocSizeOf
);
261 size_t renderTextureMemory
= 0;
263 MutexAutoLock
lock(mRenderTextureMapLock
);
264 for (const auto& entry
: mRenderTextures
) {
265 renderTextureMemory
+= entry
.second
->Bytes();
268 aReport
.render_texture_hosts
= renderTextureMemory
;
270 aPromise
->Resolve(aReport
, __func__
);
274 RefPtr
<MemoryReportPromise
> RenderThread::AccumulateMemoryReport(
275 MemoryReport aInitial
) {
276 RefPtr
<MemoryReportPromise::Private
> p
=
277 new MemoryReportPromise::Private(__func__
);
278 MOZ_ASSERT(!IsInRenderThread());
280 // This happens when the GPU process fails to start and we fall back to the
281 // basic compositor in the parent process. We could assert against this if
282 // we made the webrender detection code in gfxPlatform.cpp smarter. See bug
283 // 1494430 comment 12.
284 NS_WARNING("No render thread, returning empty memory report");
285 p
->Resolve(aInitial
, __func__
);
290 NewRunnableMethod
<MemoryReport
, RefPtr
<MemoryReportPromise::Private
>>(
291 "wr::RenderThread::DoAccumulateMemoryReport", Get(),
292 &RenderThread::DoAccumulateMemoryReport
, aInitial
, p
));
297 void RenderThread::AddRenderer(wr::WindowId aWindowId
,
298 UniquePtr
<RendererOGL
> aRenderer
) {
299 MOZ_ASSERT(IsInRenderThread());
300 LOG("RenderThread::AddRenderer() aWindowId %" PRIx64
"", AsUint64(aWindowId
));
306 mRenderers
[aWindowId
] = std::move(aRenderer
);
307 CrashReporter::AnnotateCrashReport(
308 CrashReporter::Annotation::GraphicsNumRenderers
,
309 (unsigned int)mRenderers
.size());
311 auto windows
= mWindowInfos
.Lock();
312 windows
->emplace(AsUint64(aWindowId
), new WindowInfo());
313 mWrNotifierEventsQueues
.emplace(AsUint64(aWindowId
),
314 new std::queue
<WrNotifierEvent
>);
317 void RenderThread::RemoveRenderer(wr::WindowId aWindowId
) {
318 MOZ_ASSERT(IsInRenderThread());
319 LOG("RenderThread::RemoveRenderer() aWindowId %" PRIx64
"",
320 AsUint64(aWindowId
));
326 mRenderers
.erase(aWindowId
);
327 CrashReporter::AnnotateCrashReport(
328 CrashReporter::Annotation::GraphicsNumRenderers
,
329 (unsigned int)mRenderers
.size());
331 if (mRenderers
.empty()) {
332 if (mHandlingDeviceReset
) {
335 mHandlingDeviceReset
= false;
336 mHandlingWebRenderError
= false;
339 auto windows
= mWindowInfos
.Lock();
340 auto it
= windows
->find(AsUint64(aWindowId
));
341 MOZ_ASSERT(it
!= windows
->end());
344 // Defer std::deque<WrNotifierEvent> remove, RemoveRenderer() is called in
345 // HandleWrNotifierEvents().
346 RefPtr
<Runnable
> runnable
=
347 NS_NewRunnableFunction("RenderThread::RemoveRenderer", [aWindowId
]() {
348 auto* self
= RenderThread::Get();
349 auto it
= self
->mWrNotifierEventsQueues
.find(AsUint64(aWindowId
));
350 if (it
== self
->mWrNotifierEventsQueues
.end()) {
353 self
->mWrNotifierEventsQueues
.erase(it
);
355 RenderThread::Get()->PostRunnable(runnable
.forget());
358 RendererOGL
* RenderThread::GetRenderer(wr::WindowId aWindowId
) {
359 MOZ_ASSERT(IsInRenderThread());
361 auto it
= mRenderers
.find(aWindowId
);
362 MOZ_ASSERT(it
!= mRenderers
.end());
364 if (it
== mRenderers
.end()) {
368 return it
->second
.get();
371 size_t RenderThread::RendererCount() const {
372 MOZ_ASSERT(IsInRenderThread());
373 return mRenderers
.size();
376 size_t RenderThread::ActiveRendererCount() const {
377 MOZ_ASSERT(IsInRenderThread());
378 size_t num_active
= 0;
379 for (const auto& it
: mRenderers
) {
380 if (!it
.second
->IsPaused()) {
387 void RenderThread::WrNotifierEvent_WakeUp(WrWindowId aWindowId
,
388 bool aCompositeNeeded
) {
389 auto windows
= mWindowInfos
.Lock();
390 auto it
= windows
->find(AsUint64(aWindowId
));
391 if (it
== windows
->end()) {
396 WindowInfo
* info
= it
->second
.get();
398 info
->mPendingWrNotifierEvents
.emplace(
399 WrNotifierEvent::WakeUp(aCompositeNeeded
));
400 PostWrNotifierEvents(aWindowId
, info
);
403 void RenderThread::WrNotifierEvent_NewFrameReady(WrWindowId aWindowId
,
404 bool aCompositeNeeded
,
405 FramePublishId aPublishId
) {
406 auto windows
= mWindowInfos
.Lock();
407 auto it
= windows
->find(AsUint64(aWindowId
));
408 if (it
== windows
->end()) {
412 WindowInfo
* info
= it
->second
.get();
414 info
->mPendingWrNotifierEvents
.emplace(
415 WrNotifierEvent::NewFrameReady(aCompositeNeeded
, aPublishId
));
416 PostWrNotifierEvents(aWindowId
, info
);
419 void RenderThread::WrNotifierEvent_ExternalEvent(WrWindowId aWindowId
,
421 UniquePtr
<RendererEvent
> evt(reinterpret_cast<RendererEvent
*>(aRawEvent
));
423 auto windows
= mWindowInfos
.Lock();
424 auto it
= windows
->find(AsUint64(aWindowId
));
425 if (it
== windows
->end()) {
429 WindowInfo
* info
= it
->second
.get();
431 info
->mPendingWrNotifierEvents
.emplace(
432 WrNotifierEvent::ExternalEvent(std::move(evt
)));
433 PostWrNotifierEvents(aWindowId
, info
);
437 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId
) {
439 auto windows
= mWindowInfos
.Lock();
440 auto it
= windows
->find(AsUint64(aWindowId
));
441 if (it
== windows
->end()) {
445 WindowInfo
* info
= it
->second
.get();
446 PostWrNotifierEvents(aWindowId
, info
);
450 void RenderThread::PostWrNotifierEvents(WrWindowId aWindowId
,
452 // Runnable has already been triggered.
453 if (aInfo
->mWrNotifierEventsRunnable
) {
457 // Runnable has not been triggered yet.
458 RefPtr
<nsIRunnable
> runnable
= NewRunnableMethod
<WrWindowId
>(
459 "RenderThread::HandleWrNotifierEvents", this,
460 &RenderThread::HandleWrNotifierEvents
, aWindowId
);
461 aInfo
->mWrNotifierEventsRunnable
= runnable
;
462 PostRunnable(runnable
.forget());
465 void RenderThread::HandleWrNotifierEvents(WrWindowId aWindowId
) {
466 MOZ_ASSERT(IsInRenderThread());
468 auto eventsIt
= mWrNotifierEventsQueues
.find(AsUint64(aWindowId
));
469 if (eventsIt
== mWrNotifierEventsQueues
.end()) {
472 auto* events
= eventsIt
->second
.get();
475 auto windows
= mWindowInfos
.Lock();
476 auto infoIt
= windows
->find(AsUint64(aWindowId
));
477 if (infoIt
== windows
->end()) {
481 WindowInfo
* info
= infoIt
->second
.get();
482 info
->mWrNotifierEventsRunnable
= nullptr;
484 if (events
->empty() && !info
->mPendingWrNotifierEvents
.empty()) {
485 events
->swap(info
->mPendingWrNotifierEvents
);
489 bool handleNext
= true;
491 while (!events
->empty() && handleNext
) {
492 auto& front
= events
->front();
493 switch (front
.mTag
) {
494 case WrNotifierEvent::Tag::WakeUp
:
495 WrNotifierEvent_HandleWakeUp(aWindowId
, front
.CompositeNeeded());
498 case WrNotifierEvent::Tag::NewFrameReady
:
499 WrNotifierEvent_HandleNewFrameReady(aWindowId
, front
.CompositeNeeded(),
503 case WrNotifierEvent::Tag::ExternalEvent
:
504 WrNotifierEvent_HandleExternalEvent(aWindowId
, front
.ExternalEvent());
511 auto windows
= mWindowInfos
.Lock();
512 auto it
= windows
->find(AsUint64(aWindowId
));
513 if (it
== windows
->end()) {
516 WindowInfo
* info
= it
->second
.get();
518 if (!events
->empty() || !info
->mPendingWrNotifierEvents
.empty()) {
519 PostWrNotifierEvents(aWindowId
, info
);
524 void RenderThread::WrNotifierEvent_HandleWakeUp(wr::WindowId aWindowId
,
525 bool aCompositeNeeded
) {
526 MOZ_ASSERT(IsInRenderThread());
528 bool isTrackedFrame
= false;
529 HandleFrameOneDoc(aWindowId
, aCompositeNeeded
, isTrackedFrame
, Nothing());
532 void RenderThread::WrNotifierEvent_HandleNewFrameReady(
533 wr::WindowId aWindowId
, bool aCompositeNeeded
, FramePublishId aPublishId
) {
534 MOZ_ASSERT(IsInRenderThread());
536 bool isTrackedFrame
= true;
537 HandleFrameOneDoc(aWindowId
, aCompositeNeeded
, isTrackedFrame
,
541 void RenderThread::WrNotifierEvent_HandleExternalEvent(
542 wr::WindowId aWindowId
, UniquePtr
<RendererEvent
> aRendererEvent
) {
543 MOZ_ASSERT(IsInRenderThread());
545 RunEvent(aWindowId
, std::move(aRendererEvent
));
548 void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId
,
549 const TimeStamp
& aRecordingStart
,
550 wr::PipelineId aRootPipelineId
) {
551 MOZ_ASSERT(IsInRenderThread());
552 RendererOGL
* renderer
= GetRenderer(aWindowId
);
553 MOZ_ASSERT(renderer
);
555 renderer
->BeginRecording(aRecordingStart
, aRootPipelineId
);
558 Maybe
<layers::FrameRecording
> RenderThread::EndRecordingForWindow(
559 wr::WindowId aWindowId
) {
560 MOZ_ASSERT(IsInRenderThread());
562 RendererOGL
* renderer
= GetRenderer(aWindowId
);
563 MOZ_ASSERT(renderer
);
564 return renderer
->EndRecording();
567 void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId
, bool aRender
,
569 Maybe
<FramePublishId
> aPublishId
) {
570 MOZ_ASSERT(IsInRenderThread());
576 HandleFrameOneDocInner(aWindowId
, aRender
, aTrackedFrame
, aPublishId
);
579 DecPendingFrameCount(aWindowId
);
583 void RenderThread::HandleFrameOneDocInner(wr::WindowId aWindowId
, bool aRender
,
585 Maybe
<FramePublishId
> aPublishId
) {
586 if (IsDestroyed(aWindowId
)) {
590 if (mHandlingDeviceReset
) {
594 bool render
= aRender
;
595 PendingFrameInfo frame
;
598 auto windows
= mWindowInfos
.Lock();
599 auto it
= windows
->find(AsUint64(aWindowId
));
600 if (it
== windows
->end()) {
605 WindowInfo
* info
= it
->second
.get();
606 PendingFrameInfo
& frameInfo
= info
->mPendingFrames
.front();
607 frameInfo
.mFrameNeedsRender
|= aRender
;
608 render
= frameInfo
.mFrameNeedsRender
;
612 // Just give the frame info default values.
613 frame
= {TimeStamp::Now(), VsyncId(), aRender
};
616 // Sadly this doesn't include the lock, since we don't have the frame there
618 glean::wr::time_to_render_start
.AccumulateRawDuration(TimeStamp::Now() -
621 // It is for ensuring that PrepareForUse() is called before
622 // RenderTextureHost::Lock().
623 HandleRenderTextureOps();
625 if (aPublishId
.isSome()) {
626 SetFramePublishId(aWindowId
, aPublishId
.ref());
629 UpdateAndRender(aWindowId
, frame
.mStartId
, frame
.mStartTime
, render
,
630 /* aReadbackSize */ Nothing(),
631 /* aReadbackFormat */ Nothing(),
632 /* aReadbackBuffer */ Nothing());
634 // The start time is from WebRenderBridgeParent::CompositeToTarget. From that
635 // point until now (when the frame is finally pushed to the screen) is
636 // equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
637 TimeDuration compositeDuration
= TimeStamp::Now() - frame
.mStartTime
;
638 mozilla::Telemetry::Accumulate(mozilla::Telemetry::COMPOSITE_TIME
,
639 uint32_t(compositeDuration
.ToMilliseconds()));
640 PerfStats::RecordMeasurement(PerfStats::Metric::Compositing
,
644 void RenderThread::SetClearColor(wr::WindowId aWindowId
, wr::ColorF aColor
) {
649 if (!IsInRenderThread()) {
650 PostRunnable(NewRunnableMethod
<wr::WindowId
, wr::ColorF
>(
651 "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor
,
656 if (IsDestroyed(aWindowId
)) {
660 auto it
= mRenderers
.find(aWindowId
);
661 MOZ_ASSERT(it
!= mRenderers
.end());
662 if (it
!= mRenderers
.end()) {
663 wr_renderer_set_clear_color(it
->second
->GetRenderer(), aColor
);
667 void RenderThread::SetProfilerUI(wr::WindowId aWindowId
,
668 const nsACString
& aUI
) {
673 if (!IsInRenderThread()) {
674 PostRunnable(NewRunnableMethod
<wr::WindowId
, nsCString
>(
675 "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI
,
676 aWindowId
, nsCString(aUI
)));
680 auto it
= mRenderers
.find(aWindowId
);
681 if (it
!= mRenderers
.end()) {
682 it
->second
->SetProfilerUI(aUI
);
686 void RenderThread::PostEvent(wr::WindowId aWindowId
,
687 UniquePtr
<RendererEvent
> aEvent
) {
688 PostRunnable(NewRunnableMethod
<wr::WindowId
, UniquePtr
<RendererEvent
>&&>(
689 "wr::RenderThread::PostEvent", this, &RenderThread::RunEvent
, aWindowId
,
693 void RenderThread::RunEvent(wr::WindowId aWindowId
,
694 UniquePtr
<RendererEvent
> aEvent
) {
695 MOZ_ASSERT(IsInRenderThread());
697 aEvent
->Run(*this, aWindowId
);
701 static void NotifyDidRender(layers::CompositorBridgeParent
* aBridge
,
702 const RefPtr
<const WebRenderPipelineInfo
>& aInfo
,
703 VsyncId aCompositeStartId
,
704 TimeStamp aCompositeStart
, TimeStamp aRenderStart
,
705 TimeStamp aEnd
, bool aRender
,
706 RendererStats aStats
) {
707 if (aRender
&& aBridge
->GetWrBridge()) {
708 // We call this here to mimic the behavior in LayerManagerComposite, as to
709 // not change what Talos measures. That is, we do not record an empty frame
711 aBridge
->GetWrBridge()->RecordFrame();
714 aBridge
->NotifyDidRender(aCompositeStartId
, aCompositeStart
, aRenderStart
,
717 for (const auto& epoch
: aInfo
->Raw().epochs
) {
718 aBridge
->NotifyPipelineRendered(epoch
.pipeline_id
, epoch
.epoch
,
719 aCompositeStartId
, aCompositeStart
,
720 aRenderStart
, aEnd
, &aStats
);
723 if (aBridge
->GetWrBridge()) {
724 aBridge
->GetWrBridge()->RetrySkippedComposite();
728 static void NotifyDidStartRender(layers::CompositorBridgeParent
* aBridge
) {
729 if (aBridge
->GetWrBridge()) {
730 aBridge
->GetWrBridge()->RetrySkippedComposite();
734 void RenderThread::SetFramePublishId(wr::WindowId aWindowId
,
735 FramePublishId aPublishId
) {
736 MOZ_ASSERT(IsInRenderThread());
738 auto it
= mRenderers
.find(aWindowId
);
739 MOZ_ASSERT(it
!= mRenderers
.end());
740 if (it
== mRenderers
.end()) {
743 auto& renderer
= it
->second
;
745 renderer
->SetFramePublishId(aPublishId
);
748 void RenderThread::UpdateAndRender(
749 wr::WindowId aWindowId
, const VsyncId
& aStartId
,
750 const TimeStamp
& aStartTime
, bool aRender
,
751 const Maybe
<gfx::IntSize
>& aReadbackSize
,
752 const Maybe
<wr::ImageFormat
>& aReadbackFormat
,
753 const Maybe
<Range
<uint8_t>>& aReadbackBuffer
, bool* aNeedsYFlip
) {
754 AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS
);
755 MOZ_ASSERT(IsInRenderThread());
756 MOZ_ASSERT(aRender
|| aReadbackBuffer
.isNothing());
758 auto it
= mRenderers
.find(aWindowId
);
759 MOZ_ASSERT(it
!= mRenderers
.end());
760 if (it
== mRenderers
.end()) {
764 TimeStamp start
= TimeStamp::Now();
766 auto& renderer
= it
->second
;
768 std::string markerName
= "Composite #" + std::to_string(AsUint64(aWindowId
));
769 AutoProfilerTracing
tracingCompositeMarker(
770 "Paint", markerName
.c_str(), geckoprofiler::category::GRAPHICS
,
771 Some(renderer
->GetCompositorBridge()->GetInnerWindowId()));
773 if (renderer
->IsPaused()) {
776 LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64
" aRender %d",
777 AsUint64(aWindowId
), aRender
);
779 layers::CompositorThread()->Dispatch(
780 NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender
,
781 renderer
->GetCompositorBridge()));
783 wr::RenderedFrameId latestFrameId
;
784 RendererStats stats
= {0};
786 latestFrameId
= renderer
->UpdateAndRender(
787 aReadbackSize
, aReadbackFormat
, aReadbackBuffer
, aNeedsYFlip
, &stats
);
791 // Check graphics reset status even when rendering is skipped.
792 renderer
->CheckGraphicsResetStatus("PostUpdate", /* aForce */ false);
794 TimeStamp end
= TimeStamp::Now();
795 RefPtr
<const WebRenderPipelineInfo
> info
= renderer
->GetLastPipelineInfo();
797 layers::CompositorThread()->Dispatch(
798 NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender
,
799 renderer
->GetCompositorBridge(), info
, aStartId
,
800 aStartTime
, start
, end
, aRender
, stats
));
802 ipc::FileDescriptor fenceFd
;
804 if (latestFrameId
.IsValid()) {
805 fenceFd
= renderer
->GetAndResetReleaseFence();
807 // Wait for GPU after posting NotifyDidRender, since the wait is not
808 // necessary for the NotifyDidRender.
809 // The wait is necessary for Textures recycling of AsyncImagePipelineManager
810 // and for avoiding GPU queue is filled with too much tasks.
811 // WaitForGPU's implementation is different for each platform.
812 auto timerId
= glean::wr::gpu_wait_time
.Start();
813 renderer
->WaitForGPU();
814 glean::wr::gpu_wait_time
.StopAndAccumulate(std::move(timerId
));
816 // Update frame id for NotifyPipelinesUpdated() when rendering does not
817 // happen, either because rendering was not requested or the frame was
818 // canceled. Rendering can sometimes be canceled if UpdateAndRender is
819 // called when the window is not yet ready (not mapped or 0 size).
820 latestFrameId
= renderer
->UpdateFrameId();
823 RenderedFrameId lastCompletedFrameId
= renderer
->GetLastCompletedFrameId();
825 RefPtr
<layers::AsyncImagePipelineManager
> pipelineMgr
=
826 renderer
->GetCompositorBridge()->GetAsyncImagePipelineManager();
827 // pipelineMgr should always be non-null here because it is only nulled out
828 // after the WebRenderAPI instance for the CompositorBridgeParent is
829 // destroyed, and that destruction blocks until the renderer thread has
830 // removed the relevant renderer. And after that happens we should never reach
831 // this code at all; it would bail out at the mRenderers.find check above.
832 MOZ_ASSERT(pipelineMgr
);
833 pipelineMgr
->NotifyPipelinesUpdated(info
, latestFrameId
, lastCompletedFrameId
,
837 void RenderThread::Pause(wr::WindowId aWindowId
) {
838 MOZ_ASSERT(IsInRenderThread());
839 LOG("RenderThread::Pause() aWindowId %" PRIx64
"", AsUint64(aWindowId
));
841 auto it
= mRenderers
.find(aWindowId
);
842 MOZ_ASSERT(it
!= mRenderers
.end());
843 if (it
== mRenderers
.end()) {
844 gfxCriticalNote
<< "RenderThread cannot find renderer for window "
845 << gfx::hexa(aWindowId
) << " to pause.";
848 auto& renderer
= it
->second
;
851 CrashReporter::AnnotateCrashReport(
852 CrashReporter::Annotation::GraphicsNumActiveRenderers
,
853 (unsigned int)ActiveRendererCount());
856 bool RenderThread::Resume(wr::WindowId aWindowId
) {
857 MOZ_ASSERT(IsInRenderThread());
858 LOG("enderThread::Resume() aWindowId %" PRIx64
"", AsUint64(aWindowId
));
860 auto it
= mRenderers
.find(aWindowId
);
861 MOZ_ASSERT(it
!= mRenderers
.end());
862 if (it
== mRenderers
.end()) {
863 gfxCriticalNote
<< "RenderThread cannot find renderer for window "
864 << gfx::hexa(aWindowId
) << " to resume.";
867 auto& renderer
= it
->second
;
868 bool resumed
= renderer
->Resume();
870 CrashReporter::AnnotateCrashReport(
871 CrashReporter::Annotation::GraphicsNumActiveRenderers
,
872 (unsigned int)ActiveRendererCount());
877 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId
) {
878 const int64_t maxFrameCount
= 1;
880 // Too many pending frames if pending frames exit more than maxFrameCount
881 // or if RenderBackend is still processing a frame.
883 auto windows
= mWindowInfos
.Lock();
884 auto it
= windows
->find(AsUint64(aWindowId
));
885 if (it
== windows
->end()) {
889 WindowInfo
* info
= it
->second
.get();
891 if (info
->PendingCount() > maxFrameCount
) {
894 // If there is no ongoing frame build, we accept a new frame.
895 return info
->mPendingFrameBuild
> 0;
898 bool RenderThread::IsDestroyed(wr::WindowId aWindowId
) {
899 auto windows
= mWindowInfos
.Lock();
900 auto it
= windows
->find(AsUint64(aWindowId
));
901 if (it
== windows
->end()) {
905 return it
->second
->mIsDestroyed
;
908 void RenderThread::SetDestroyed(wr::WindowId aWindowId
) {
909 auto windows
= mWindowInfos
.Lock();
910 auto it
= windows
->find(AsUint64(aWindowId
));
911 if (it
== windows
->end()) {
915 it
->second
->mIsDestroyed
= true;
918 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId
,
919 const VsyncId
& aStartId
,
920 const TimeStamp
& aStartTime
) {
921 auto windows
= mWindowInfos
.Lock();
922 auto it
= windows
->find(AsUint64(aWindowId
));
923 if (it
== windows
->end()) {
927 it
->second
->mPendingFrameBuild
++;
928 it
->second
->mPendingFrames
.push(
929 PendingFrameInfo
{aStartTime
, aStartId
, false});
932 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId
) {
933 auto windows
= mWindowInfos
.Lock();
934 auto it
= windows
->find(AsUint64(aWindowId
));
935 if (it
== windows
->end()) {
939 WindowInfo
* info
= it
->second
.get();
940 MOZ_RELEASE_ASSERT(info
->mPendingFrameBuild
>= 1);
941 info
->mPendingFrameBuild
--;
944 void RenderThread::DecPendingFrameCount(wr::WindowId aWindowId
) {
945 auto windows
= mWindowInfos
.Lock();
946 auto it
= windows
->find(AsUint64(aWindowId
));
947 if (it
== windows
->end()) {
951 WindowInfo
* info
= it
->second
.get();
952 info
->mPendingFrames
.pop();
955 void RenderThread::RegisterExternalImage(
956 const wr::ExternalImageId
& aExternalImageId
,
957 already_AddRefed
<RenderTextureHost
> aTexture
) {
958 MutexAutoLock
lock(mRenderTextureMapLock
);
963 MOZ_ASSERT(mRenderTextures
.find(aExternalImageId
) == mRenderTextures
.end());
964 RefPtr
<RenderTextureHost
> texture
= aTexture
;
965 if (texture
->SyncObjectNeeded()) {
966 mSyncObjectNeededRenderTextures
.emplace(aExternalImageId
, texture
);
968 mRenderTextures
.emplace(aExternalImageId
, texture
);
971 void RenderThread::UnregisterExternalImage(
972 const wr::ExternalImageId
& aExternalImageId
) {
973 MutexAutoLock
lock(mRenderTextureMapLock
);
977 auto it
= mRenderTextures
.find(aExternalImageId
);
978 if (it
== mRenderTextures
.end()) {
982 auto& texture
= it
->second
;
983 if (texture
->SyncObjectNeeded()) {
985 mSyncObjectNeededRenderTextures
.erase(aExternalImageId
) == 1);
988 if (!IsInRenderThread()) {
989 // The RenderTextureHost should be released in render thread. So, post the
990 // deletion task here.
991 // The shmem and raw buffer are owned by compositor ipc channel. It's
992 // possible that RenderTextureHost is still exist after the shmem/raw buffer
993 // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
994 // for this situation. Gecko will only release the buffer if WR doesn't need
995 // it. So, no one will access the invalid buffer in RenderTextureHost.
996 RefPtr
<RenderTextureHost
> texture
= it
->second
;
997 mRenderTextures
.erase(it
);
998 mRenderTexturesDeferred
.emplace_back(std::move(texture
));
999 PostRunnable(NewRunnableMethod(
1000 "RenderThread::DeferredRenderTextureHostDestroy", this,
1001 &RenderThread::DeferredRenderTextureHostDestroy
));
1003 mRenderTextures
.erase(it
);
1007 void RenderThread::DestroyExternalImagesSyncWait(
1008 const std::vector
<wr::ExternalImageId
>&& aIds
) {
1009 if (!IsInRenderThread()) {
1010 layers::SynchronousTask
task("Destroy external images");
1012 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
1013 "RenderThread::DestroyExternalImagesSyncWait::Runnable",
1014 [&task
, ids
= std::move(aIds
)]() {
1015 layers::AutoCompleteTask
complete(&task
);
1016 RenderThread::Get()->DestroyExternalImages(std::move(ids
));
1019 PostRunnable(runnable
.forget());
1023 DestroyExternalImages(std::move(aIds
));
1026 void RenderThread::DestroyExternalImages(
1027 const std::vector
<wr::ExternalImageId
>&& aIds
) {
1028 MOZ_ASSERT(IsInRenderThread());
1030 std::vector
<RefPtr
<RenderTextureHost
>> hosts
;
1032 MutexAutoLock
lock(mRenderTextureMapLock
);
1037 for (auto& id
: aIds
) {
1038 auto it
= mRenderTextures
.find(id
);
1039 if (it
== mRenderTextures
.end()) {
1042 hosts
.emplace_back(it
->second
);
1046 for (auto& host
: hosts
) {
1051 void RenderThread::PrepareForUse(const wr::ExternalImageId
& aExternalImageId
) {
1052 AddRenderTextureOp(RenderTextureOp::PrepareForUse
, aExternalImageId
);
1055 void RenderThread::NotifyNotUsed(const wr::ExternalImageId
& aExternalImageId
) {
1056 AddRenderTextureOp(RenderTextureOp::NotifyNotUsed
, aExternalImageId
);
1059 void RenderThread::NotifyForUse(const wr::ExternalImageId
& aExternalImageId
) {
1060 AddRenderTextureOp(RenderTextureOp::NotifyForUse
, aExternalImageId
);
1063 void RenderThread::AddRenderTextureOp(
1064 RenderTextureOp aOp
, const wr::ExternalImageId
& aExternalImageId
) {
1065 MOZ_ASSERT(!IsInRenderThread());
1067 MutexAutoLock
lock(mRenderTextureMapLock
);
1069 auto it
= mRenderTextures
.find(aExternalImageId
);
1070 MOZ_ASSERT(it
!= mRenderTextures
.end());
1071 if (it
== mRenderTextures
.end()) {
1075 RefPtr
<RenderTextureHost
> texture
= it
->second
;
1076 mRenderTextureOps
.emplace_back(aOp
, std::move(texture
));
1078 if (mRenderTextureOpsRunnable
) {
1079 // Runnable was already triggered
1083 RefPtr
<nsIRunnable
> runnable
=
1084 NewRunnableMethod("RenderThread::HandleRenderTextureOps", this,
1085 &RenderThread::HandleRenderTextureOps
);
1086 mRenderTextureOpsRunnable
= runnable
;
1087 PostRunnable(runnable
.forget());
1090 void RenderThread::HandleRenderTextureOps() {
1091 MOZ_ASSERT(IsInRenderThread());
1093 std::list
<std::pair
<RenderTextureOp
, RefPtr
<RenderTextureHost
>>>
1096 MutexAutoLock
lock(mRenderTextureMapLock
);
1097 mRenderTextureOps
.swap(renderTextureOps
);
1098 mRenderTextureOpsRunnable
= nullptr;
1101 for (auto& it
: renderTextureOps
) {
1103 case RenderTextureOp::PrepareForUse
:
1104 it
.second
->PrepareForUse();
1106 case RenderTextureOp::NotifyForUse
:
1107 it
.second
->NotifyForUse();
1109 case RenderTextureOp::NotifyNotUsed
:
1110 it
.second
->NotifyNotUsed();
1116 void RenderThread::UnregisterExternalImageDuringShutdown(
1117 const wr::ExternalImageId
& aExternalImageId
) {
1118 MOZ_ASSERT(IsInRenderThread());
1119 MutexAutoLock
lock(mRenderTextureMapLock
);
1120 MOZ_ASSERT(mHasShutdown
);
1121 MOZ_ASSERT(mRenderTextures
.find(aExternalImageId
) != mRenderTextures
.end());
1122 mRenderTextures
.erase(aExternalImageId
);
1125 bool RenderThread::SyncObjectNeeded() {
1126 MOZ_ASSERT(IsInRenderThread());
1127 MutexAutoLock
lock(mRenderTextureMapLock
);
1128 return !mSyncObjectNeededRenderTextures
.empty();
1131 void RenderThread::DeferredRenderTextureHostDestroy() {
1132 MutexAutoLock
lock(mRenderTextureMapLock
);
1133 mRenderTexturesDeferred
.clear();
1136 RenderTextureHost
* RenderThread::GetRenderTexture(
1137 const wr::ExternalImageId
& aExternalImageId
) {
1138 MutexAutoLock
lock(mRenderTextureMapLock
);
1139 auto it
= mRenderTextures
.find(aExternalImageId
);
1140 MOZ_ASSERT(it
!= mRenderTextures
.end());
1141 if (it
== mRenderTextures
.end()) {
1147 void RenderThread::InitDeviceTask() {
1148 MOZ_ASSERT(IsInRenderThread());
1149 MOZ_ASSERT(!mSingletonGL
);
1150 LOG("RenderThread::InitDeviceTask()");
1152 if (gfx::gfxVars::UseSoftwareWebRender()) {
1153 // Ensure we don't instantiate any shared GL context when SW-WR is used.
1158 CreateSingletonGL(err
);
1159 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1160 mProgramCache
= MakeUnique
<WebRenderProgramCache
>(ThreadPool().Raw());
1162 // Query the shared GL context to force the
1163 // lazy initialization to happen now.
1167 void RenderThread::PostRunnable(already_AddRefed
<nsIRunnable
> aRunnable
) {
1168 nsCOMPtr
<nsIRunnable
> runnable
= aRunnable
;
1169 mThread
->Dispatch(runnable
.forget());
1173 static DeviceResetReason
GLenumToResetReason(GLenum aReason
) {
1175 case LOCAL_GL_NO_ERROR
:
1176 return DeviceResetReason::FORCED_RESET
;
1177 case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB
:
1178 return DeviceResetReason::DRIVER_ERROR
;
1179 case LOCAL_GL_PURGED_CONTEXT_RESET_NV
:
1180 return DeviceResetReason::NVIDIA_VIDEO
;
1181 case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB
:
1182 return DeviceResetReason::RESET
;
1183 case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB
:
1184 return DeviceResetReason::UNKNOWN
;
1185 case LOCAL_GL_OUT_OF_MEMORY
:
1186 return DeviceResetReason::OUT_OF_MEMORY
;
1188 return DeviceResetReason::OTHER
;
1193 void RenderThread::HandleDeviceReset(const char* aWhere
, GLenum aReason
) {
1194 MOZ_ASSERT(IsInRenderThread());
1196 // This happens only on simulate device reset.
1197 if (aReason
== LOCAL_GL_NO_ERROR
) {
1198 if (!mHandlingDeviceReset
) {
1199 mHandlingDeviceReset
= true;
1201 MutexAutoLock
lock(mRenderTextureMapLock
);
1202 mRenderTexturesDeferred
.clear();
1203 for (const auto& entry
: mRenderTextures
) {
1204 entry
.second
->ClearCachedResources();
1207 // All RenderCompositors will be destroyed by the GPUProcessManager in
1208 // either OnRemoteProcessDeviceReset via the GPUChild, or
1209 // OnInProcessDeviceReset here directly.
1210 if (XRE_IsGPUProcess()) {
1211 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1213 NS_DispatchToMainThread(NS_NewRunnableFunction(
1214 "gfx::GPUProcessManager::OnInProcessDeviceReset", []() -> void {
1215 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(
1216 /* aTrackThreshold */ false);
1223 if (mHandlingDeviceReset
) {
1227 mHandlingDeviceReset
= true;
1230 // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices.
1231 gfx::GPUProcessManager::RecordDeviceReset(GLenumToResetReason(aReason
));
1235 MutexAutoLock
lock(mRenderTextureMapLock
);
1236 mRenderTexturesDeferred
.clear();
1237 for (const auto& entry
: mRenderTextures
) {
1238 entry
.second
->ClearCachedResources();
1242 // All RenderCompositors will be destroyed by the GPUProcessManager in
1243 // either OnRemoteProcessDeviceReset via the GPUChild, or
1244 // OnInProcessDeviceReset here directly.
1245 // On Windows, device will be re-created before sessions re-creation.
1246 gfxCriticalNote
<< "GFX: RenderThread detected a device reset in " << aWhere
;
1247 if (XRE_IsGPUProcess()) {
1248 gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
1251 // FIXME(aosmond): Do we need to do this on Windows? nsWindow::OnPaint
1252 // seems to do its own detection for the parent process.
1253 bool guilty
= aReason
== LOCAL_GL_GUILTY_CONTEXT_RESET_ARB
;
1254 NS_DispatchToMainThread(NS_NewRunnableFunction(
1255 "gfx::GPUProcessManager::OnInProcessDeviceReset", [guilty
]() -> void {
1256 gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(guilty
);
1262 bool RenderThread::IsHandlingDeviceReset() {
1263 MOZ_ASSERT(IsInRenderThread());
1264 return mHandlingDeviceReset
;
1267 void RenderThread::SimulateDeviceReset() {
1268 if (!IsInRenderThread()) {
1269 PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this,
1270 &RenderThread::SimulateDeviceReset
));
1272 // When this function is called GPUProcessManager::SimulateDeviceReset()
1273 // already triggers destroying all CompositorSessions before re-creating
1275 HandleDeviceReset("SimulateDeviceReset", LOCAL_GL_NO_ERROR
);
1279 static void DoNotifyWebRenderError(WebRenderError aError
) {
1280 layers::CompositorManagerParent::NotifyWebRenderError(aError
);
1283 void RenderThread::NotifyWebRenderError(WebRenderError aError
) {
1284 MOZ_ASSERT(IsInRenderThread());
1286 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1287 "DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError
, aError
));
1290 void RenderThread::HandleWebRenderError(WebRenderError aError
) {
1291 if (mHandlingWebRenderError
) {
1295 NotifyWebRenderError(aError
);
1298 MutexAutoLock
lock(mRenderTextureMapLock
);
1299 mRenderTexturesDeferred
.clear();
1300 for (const auto& entry
: mRenderTextures
) {
1301 entry
.second
->ClearCachedResources();
1304 mHandlingWebRenderError
= true;
1305 // WebRender is going to be disabled by
1306 // GPUProcessManager::NotifyWebRenderError()
1309 bool RenderThread::IsHandlingWebRenderError() {
1310 MOZ_ASSERT(IsInRenderThread());
1311 return mHandlingWebRenderError
;
1314 gl::GLContext
* RenderThread::SingletonGL() {
1316 auto* gl
= SingletonGL(err
);
1317 if (!err
.IsEmpty()) {
1318 gfxCriticalNote
<< err
.get();
1323 void RenderThread::CreateSingletonGL(nsACString
& aError
) {
1324 MOZ_ASSERT(IsInRenderThread());
1325 LOG("RenderThread::CreateSingletonGL()");
1327 mSingletonGL
= CreateGLContext(aError
);
1328 mSingletonGLIsForHardwareWebRender
= !gfx::gfxVars::UseSoftwareWebRender();
1331 gl::GLContext
* RenderThread::SingletonGL(nsACString
& aError
) {
1332 MOZ_ASSERT(IsInRenderThread());
1333 if (!mSingletonGL
) {
1334 CreateSingletonGL(aError
);
1337 if (mSingletonGL
&& mSingletonGLIsForHardwareWebRender
&& !mShaders
) {
1338 mShaders
= MakeUnique
<WebRenderShaders
>(mSingletonGL
, mProgramCache
.get());
1341 return mSingletonGL
.get();
1344 gl::GLContext
* RenderThread::SingletonGLForCompositorOGL() {
1345 MOZ_RELEASE_ASSERT(gfx::gfxVars::UseSoftwareWebRender());
1347 if (mSingletonGLIsForHardwareWebRender
) {
1348 // Clear singleton GL, since GLContext is for hardware WebRender.
1351 return SingletonGL();
1354 void RenderThread::ClearSingletonGL() {
1355 MOZ_ASSERT(IsInRenderThread());
1356 LOG("RenderThread::ClearSingletonGL()");
1359 mSurfacePool
->DestroyGLResourcesForContext(mSingletonGL
);
1361 if (mProgramsForCompositorOGL
) {
1362 mProgramsForCompositorOGL
->Clear();
1363 mProgramsForCompositorOGL
= nullptr;
1366 mSingletonGL
= nullptr;
1369 RefPtr
<layers::ShaderProgramOGLsHolder
>
1370 RenderThread::GetProgramsForCompositorOGL() {
1371 if (!mSingletonGL
) {
1375 if (!mProgramsForCompositorOGL
) {
1376 mProgramsForCompositorOGL
=
1377 MakeAndAddRef
<layers::ShaderProgramOGLsHolder
>(mSingletonGL
);
1379 return mProgramsForCompositorOGL
;
1382 RefPtr
<layers::SurfacePool
> RenderThread::SharedSurfacePool() {
1383 #if defined(XP_MACOSX) || defined(MOZ_WAYLAND)
1384 if (!mSurfacePool
) {
1385 size_t poolSizeLimit
=
1386 StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup();
1387 mSurfacePool
= layers::SurfacePool::Create(poolSizeLimit
);
1390 return mSurfacePool
;
1393 void RenderThread::ClearSharedSurfacePool() { mSurfacePool
= nullptr; }
1395 static void GLAPIENTRY
DebugMessageCallback(GLenum aSource
, GLenum aType
,
1396 GLuint aId
, GLenum aSeverity
,
1398 const GLchar
* aMessage
,
1399 const GLvoid
* aUserParam
) {
1400 constexpr const char* kContextLost
= "Context has been lost.";
1402 if (StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() &&
1403 aSeverity
== LOCAL_GL_DEBUG_SEVERITY_HIGH
) {
1404 auto message
= std::string(aMessage
, aLength
);
1405 // When content lost happned, error messages are flooded by its message.
1406 if (message
!= kContextLost
) {
1407 gfxCriticalNote
<< message
;
1409 gfxCriticalNoteOnce
<< message
;
1413 if (StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup()) {
1414 gl::GLContext
* gl
= (gl::GLContext
*)aUserParam
;
1415 gl
->DebugCallback(aSource
, aType
, aId
, aSeverity
, aLength
, aMessage
);
1420 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext
* aGLContext
) {
1425 bool enableDebugMessage
=
1426 StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() ||
1427 StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup();
1429 if (enableDebugMessage
&&
1430 aGLContext
->IsExtensionSupported(gl::GLContext::KHR_debug
)) {
1431 aGLContext
->fEnable(LOCAL_GL_DEBUG_OUTPUT
);
1432 aGLContext
->fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS
);
1433 aGLContext
->fDebugMessageCallback(&DebugMessageCallback
, (void*)aGLContext
);
1434 aGLContext
->fDebugMessageControl(LOCAL_GL_DONT_CARE
, LOCAL_GL_DONT_CARE
,
1435 LOCAL_GL_DONT_CARE
, 0, nullptr, true);
1439 WebRenderShaders::WebRenderShaders(gl::GLContext
* gl
,
1440 WebRenderProgramCache
* programCache
) {
1443 wr_shaders_new(gl
, programCache
? programCache
->Raw() : nullptr,
1444 StaticPrefs::gfx_webrender_precache_shaders_AtStartup());
1447 WebRenderShaders::~WebRenderShaders() {
1448 wr_shaders_delete(mShaders
, mGL
.get());
1451 WebRenderThreadPool::WebRenderThreadPool(bool low_priority
) {
1452 mThreadPool
= wr_thread_pool_new(low_priority
);
1455 WebRenderThreadPool::~WebRenderThreadPool() { Release(); }
1457 void WebRenderThreadPool::Release() {
1459 wr_thread_pool_delete(mThreadPool
);
1460 mThreadPool
= nullptr;
1464 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool
* aThreadPool
) {
1465 MOZ_ASSERT(aThreadPool
);
1468 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1469 path
.Append(gfx::gfxVars::ProfDirectory());
1471 mProgramCache
= wr_program_cache_new(&path
, aThreadPool
);
1472 if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1473 wr_try_load_startup_shaders_from_disk(mProgramCache
);
1477 WebRenderProgramCache::~WebRenderProgramCache() {
1478 wr_program_cache_delete(mProgramCache
);
1481 } // namespace mozilla::wr
1484 static already_AddRefed
<gl::GLContext
> CreateGLContextANGLE(
1485 nsACString
& aError
) {
1486 const RefPtr
<ID3D11Device
> d3d11Device
=
1487 gfx::DeviceManagerDx::Get()->GetCompositorDevice();
1489 aError
.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns
);
1493 nsCString failureId
;
1494 const auto lib
= gl::GLLibraryEGL::Get(&failureId
);
1497 nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId
.get()));
1501 const auto egl
= lib
->CreateDisplay(d3d11Device
.get());
1503 aError
.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
1508 gl::CreateContextFlags flags
= gl::CreateContextFlags::PREFER_ES3
;
1510 if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
1511 flags
|= gl::CreateContextFlags::PREFER_ROBUSTNESS
;
1514 if (egl
->IsExtensionSupported(
1515 gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care
)) {
1516 flags
|= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE
;
1519 // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
1520 // Instread we override it with EGLSurface of SwapChain's back buffer.
1522 auto gl
= gl::GLContextEGL::CreateWithoutSurface(egl
, {flags
}, &failureId
);
1523 if (!gl
|| !gl
->IsANGLE()) {
1524 aError
.Assign(nsPrintfCString("RcANGLE(create GL context failed: %p, %s)",
1525 gl
.get(), failureId
.get()));
1529 if (!gl
->MakeCurrent()) {
1531 nsPrintfCString("RcANGLE(make current GL context failed: %p, %x)",
1532 gl
.get(), gl
->mEgl
->mLib
->fGetError()));
1540 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WAYLAND) || defined(MOZ_X11)
1541 static already_AddRefed
<gl::GLContext
> CreateGLContextEGL() {
1542 // Create GLContext with dummy EGLSurface.
1543 bool forHardwareWebRender
= true;
1544 // SW-WR uses CompositorOGL in native compositor.
1545 if (gfx::gfxVars::UseSoftwareWebRender()) {
1546 forHardwareWebRender
= false;
1548 RefPtr
<gl::GLContext
> gl
=
1549 gl::GLContextProviderEGL::CreateForCompositorWidget(
1550 nullptr, forHardwareWebRender
, /* aForceAccelerated */ true);
1551 if (!gl
|| !gl
->MakeCurrent()) {
1552 gfxCriticalNote
<< "Failed GL context creation for hardware WebRender: "
1553 << forHardwareWebRender
;
1561 static already_AddRefed
<gl::GLContext
> CreateGLContextCGL() {
1562 nsCString failureUnused
;
1563 return gl::GLContextProvider::CreateHeadless(
1564 {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER
|
1565 gl::CreateContextFlags::FORBID_SOFTWARE
},
1570 static already_AddRefed
<gl::GLContext
> CreateGLContext(nsACString
& aError
) {
1571 RefPtr
<gl::GLContext
> gl
;
1574 if (gfx::gfxVars::UseWebRenderANGLE()) {
1575 gl
= CreateGLContextANGLE(aError
);
1577 #elif defined(MOZ_WIDGET_ANDROID)
1578 gl
= CreateGLContextEGL();
1579 #elif defined(MOZ_WAYLAND) || defined(MOZ_X11)
1580 if (gfx::gfxVars::UseEGL()) {
1581 gl
= CreateGLContextEGL();
1584 gl
= CreateGLContextCGL();
1587 wr::RenderThread::MaybeEnableGLDebugMessage(gl
);
1594 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId
,
1595 bool aCompositeNeeded
) {
1596 // wake_up is used for things like propagating debug options or memory
1597 // pressure events, so we are not tracking pending frame counts.
1598 mozilla::wr::RenderThread::Get()->WrNotifierEvent_WakeUp(aWindowId
,
1602 void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId
,
1603 bool aCompositeNeeded
,
1604 mozilla::wr::FramePublishId aPublishId
) {
1605 auto* renderThread
= mozilla::wr::RenderThread::Get();
1606 renderThread
->DecPendingFrameBuildCount(aWindowId
);
1608 renderThread
->WrNotifierEvent_NewFrameReady(aWindowId
, aCompositeNeeded
,
1612 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId
,
1614 mozilla::wr::RenderThread::Get()->WrNotifierEvent_ExternalEvent(
1615 mozilla::wr::WindowId(aWindowId
), aRawEvent
);
1618 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId
,
1619 wr::RenderReasons aReasons
) {
1620 RefPtr
<mozilla::layers::CompositorBridgeParent
> cbp
= mozilla::layers::
1621 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId
);
1623 cbp
->ScheduleComposition(aReasons
);
1627 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId
,
1628 wr::RenderReasons aReasons
) {
1629 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1630 "NotifyScheduleRender", &NotifyScheduleRender
, aWindowId
, aReasons
));
1633 static void NotifyDidSceneBuild(
1634 mozilla::wr::WrWindowId aWindowId
,
1635 const RefPtr
<const wr::WebRenderPipelineInfo
>& aInfo
) {
1636 RefPtr
<mozilla::layers::CompositorBridgeParent
> cbp
= mozilla::layers::
1637 CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId
);
1639 cbp
->NotifyDidSceneBuild(aInfo
);
1643 void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId
,
1644 mozilla::wr::WrPipelineInfo
* aPipelineInfo
) {
1645 RefPtr
<wr::WebRenderPipelineInfo
> info
= new wr::WebRenderPipelineInfo();
1646 info
->Raw() = std::move(*aPipelineInfo
);
1647 layers::CompositorThread()->Dispatch(NewRunnableFunction(
1648 "NotifyDidSceneBuild", &NotifyDidSceneBuild
, aWindowId
, info
));