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/. */
6 
7 #include "base/task.h"
8 #include "GeckoProfiler.h"
9 #include "gfxPlatform.h"
10 #include "GLContext.h"
11 #include "RenderThread.h"
12 #include "nsThread.h"
13 #include "nsThreadUtils.h"
14 #include "transport/runnable_utils.h"
15 #include "mozilla/BackgroundHangMonitor.h"
16 #include "mozilla/layers/AsyncImagePipelineManager.h"
17 #include "mozilla/gfx/gfxVars.h"
18 #include "mozilla/gfx/GPUParent.h"
19 #include "mozilla/gfx/GPUProcessManager.h"
20 #include "mozilla/layers/CompositableInProcessManager.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/StaticPtr.h"
28 #include "mozilla/Telemetry.h"
29 #include "mozilla/webrender/RendererOGL.h"
30 #include "mozilla/webrender/RenderTextureHost.h"
31 #include "mozilla/widget/CompositorWidget.h"
32 #include "OGLShaderProgram.h"
33 
34 #ifdef XP_WIN
35 #  include "GLContextEGL.h"
36 #  include "GLLibraryEGL.h"
37 #  include "mozilla/widget/WinCompositorWindowThread.h"
38 #  include "mozilla/gfx/DeviceManagerDx.h"
39 #  include "mozilla/webrender/DCLayerTree.h"
40 //#  include "nsWindowsHelpers.h"
41 //#  include <d3d11.h>
42 #endif
43 
44 #ifdef MOZ_WIDGET_ANDROID
45 #  include "GLLibraryEGL.h"
46 #  include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h"
47 #endif
48 
49 #ifdef MOZ_WIDGET_GTK
50 #  include "mozilla/WidgetUtilsGtk.h"
51 #endif
52 
53 #ifdef MOZ_WAYLAND
54 #  include "GLLibraryEGL.h"
55 #endif
56 
57 using namespace mozilla;
58 
59 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError);
60 
61 MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderRendererMallocSizeOf)
62 
63 namespace mozilla::wr {
64 
65 LazyLogModule gRenderThreadLog("RenderThread");
66 // Should be called only on RenderThread, since LazyLogModule is not thread safe
67 #define LOG(...) MOZ_LOG(gRenderThreadLog, LogLevel::Debug, (__VA_ARGS__))
68 
69 static StaticRefPtr<RenderThread> sRenderThread;
70 static mozilla::BackgroundHangMonitor* sBackgroundHangMonitor;
71 
RenderThread(RefPtr<nsIThread> aThread)72 RenderThread::RenderThread(RefPtr<nsIThread> aThread)
73     : mThread(std::move(aThread)),
74       mThreadPool(false),
75       mThreadPoolLP(true),
76       mSingletonGLIsForHardwareWebRender(true),
77       mWindowInfos("RenderThread.mWindowInfos"),
78       mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
79       mHasShutdown(false),
80       mHandlingDeviceReset(false),
81       mHandlingWebRenderError(false) {}
82 
~RenderThread()83 RenderThread::~RenderThread() { MOZ_ASSERT(mRenderTexturesDeferred.empty()); }
84 
85 // static
Get()86 RenderThread* RenderThread::Get() { return sRenderThread; }
87 
88 // static
Start(uint32_t aNamespace)89 void RenderThread::Start(uint32_t aNamespace) {
90   MOZ_ASSERT(NS_IsMainThread());
91   MOZ_ASSERT(!sRenderThread);
92 
93   RefPtr<nsIThread> thread;
94   nsresult rv = NS_NewNamedThread(
95       "Renderer", getter_AddRefs(thread),
96       NS_NewRunnableFunction("Renderer::BackgroundHanSetup", []() {
97         sBackgroundHangMonitor = new mozilla::BackgroundHangMonitor(
98             "Render",
99             /* Timeout values are powers-of-two to enable us get better
100                data. 128ms is chosen for transient hangs because 8Hz should
101                be the minimally acceptable goal for Render
102                responsiveness (normal goal is 60Hz). */
103             128,
104             /* 2048ms is chosen for permanent hangs because it's longer than
105              * most Render hangs seen in the wild, but is short enough
106              * to not miss getting native hang stacks. */
107             2048);
108         nsCOMPtr<nsIThread> thread = NS_GetCurrentThread();
109         static_cast<nsThread*>(thread.get())->SetUseHangMonitor(true);
110       }));
111 
112   if (NS_FAILED(rv)) {
113     return;
114   }
115 
116   sRenderThread = new RenderThread(thread);
117 #ifdef XP_WIN
118   widget::WinCompositorWindowThread::Start();
119 #endif
120   layers::CompositableInProcessManager::Initialize(aNamespace);
121   layers::SharedSurfacesParent::Initialize();
122 
123   RefPtr<Runnable> runnable = WrapRunnable(
124       RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::InitDeviceTask);
125   sRenderThread->PostRunnable(runnable.forget());
126 }
127 
128 // static
ShutDown()129 void RenderThread::ShutDown() {
130   MOZ_ASSERT(NS_IsMainThread());
131   MOZ_ASSERT(sRenderThread);
132 
133   {
134     MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
135     sRenderThread->mHasShutdown = true;
136   }
137 
138   layers::SynchronousTask task("RenderThread");
139   RefPtr<Runnable> runnable =
140       WrapRunnable(RefPtr<RenderThread>(sRenderThread.get()),
141                    &RenderThread::ShutDownTask, &task);
142   sRenderThread->PostRunnable(runnable.forget());
143   task.Wait();
144 
145   layers::SharedSurfacesParent::Shutdown();
146   layers::CompositableInProcessManager::Shutdown();
147 
148   sRenderThread = nullptr;
149 #ifdef XP_WIN
150   if (widget::WinCompositorWindowThread::Get()) {
151     widget::WinCompositorWindowThread::ShutDown();
152   }
153 #endif
154 }
155 
156 extern void ClearAllBlobImageResources();
157 
ShutDownTask(layers::SynchronousTask * aTask)158 void RenderThread::ShutDownTask(layers::SynchronousTask* aTask) {
159   layers::AutoCompleteTask complete(aTask);
160   MOZ_ASSERT(IsInRenderThread());
161   LOG("RenderThread::ShutDownTask()");
162 
163   {
164     // Clear RenderTextureHosts
165     MutexAutoLock lock(mRenderTextureMapLock);
166     mRenderTexturesDeferred.clear();
167     mRenderTextures.clear();
168     mSyncObjectNeededRenderTextures.clear();
169     mRenderTextureOps.clear();
170   }
171 
172   // Let go of our handle to the (internally ref-counted) thread pool.
173   mThreadPool.Release();
174   mThreadPoolLP.Release();
175 
176   // Releasing on the render thread will allow us to avoid dispatching to remove
177   // remaining textures from the texture map.
178   layers::SharedSurfacesParent::ShutdownRenderThread();
179 
180 #ifdef XP_WIN
181   DCLayerTree::Shutdown();
182 #endif
183 
184   ClearAllBlobImageResources();
185   ClearSingletonGL();
186   ClearSharedSurfacePool();
187 }
188 
189 // static
IsInRenderThread()190 bool RenderThread::IsInRenderThread() {
191   return sRenderThread && sRenderThread->mThread == NS_GetCurrentThread();
192 }
193 
194 // static
GetRenderThread()195 already_AddRefed<nsIThread> RenderThread::GetRenderThread() {
196   nsCOMPtr<nsIThread> thread;
197   if (sRenderThread) {
198     thread = sRenderThread->mThread;
199   }
200   return thread.forget();
201 }
202 
DoAccumulateMemoryReport(MemoryReport aReport,const RefPtr<MemoryReportPromise::Private> & aPromise)203 void RenderThread::DoAccumulateMemoryReport(
204     MemoryReport aReport,
205     const RefPtr<MemoryReportPromise::Private>& aPromise) {
206   MOZ_ASSERT(IsInRenderThread());
207 
208   for (auto& r : mRenderers) {
209     r.second->AccumulateMemoryReport(&aReport);
210   }
211 
212   // Note memory used by the shader cache, which is shared across all WR
213   // instances.
214   MOZ_ASSERT(aReport.shader_cache == 0);
215   if (mProgramCache) {
216     aReport.shader_cache = wr_program_cache_report_memory(
217         mProgramCache->Raw(), &WebRenderRendererMallocSizeOf);
218   }
219 
220   size_t renderTextureMemory = 0;
221   {
222     MutexAutoLock lock(mRenderTextureMapLock);
223     for (const auto& entry : mRenderTextures) {
224       renderTextureMemory += entry.second->Bytes();
225     }
226   }
227   aReport.render_texture_hosts = renderTextureMemory;
228 
229   aPromise->Resolve(aReport, __func__);
230 }
231 
232 // static
AccumulateMemoryReport(MemoryReport aInitial)233 RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport(
234     MemoryReport aInitial) {
235   RefPtr<MemoryReportPromise::Private> p =
236       new MemoryReportPromise::Private(__func__);
237   MOZ_ASSERT(!IsInRenderThread());
238   if (!Get()) {
239     // This happens when the GPU process fails to start and we fall back to the
240     // basic compositor in the parent process. We could assert against this if
241     // we made the webrender detection code in gfxPlatform.cpp smarter. See bug
242     // 1494430 comment 12.
243     NS_WARNING("No render thread, returning empty memory report");
244     p->Resolve(aInitial, __func__);
245     return p;
246   }
247 
248   Get()->PostRunnable(
249       NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>(
250           "wr::RenderThread::DoAccumulateMemoryReport", Get(),
251           &RenderThread::DoAccumulateMemoryReport, aInitial, p));
252 
253   return p;
254 }
255 
AddRenderer(wr::WindowId aWindowId,UniquePtr<RendererOGL> aRenderer)256 void RenderThread::AddRenderer(wr::WindowId aWindowId,
257                                UniquePtr<RendererOGL> aRenderer) {
258   MOZ_ASSERT(IsInRenderThread());
259   LOG("RenderThread::AddRenderer() aWindowId %" PRIx64 "", AsUint64(aWindowId));
260 
261   if (mHasShutdown) {
262     return;
263   }
264 
265   mRenderers[aWindowId] = std::move(aRenderer);
266 
267   auto windows = mWindowInfos.Lock();
268   windows->emplace(AsUint64(aWindowId), new WindowInfo());
269 }
270 
RemoveRenderer(wr::WindowId aWindowId)271 void RenderThread::RemoveRenderer(wr::WindowId aWindowId) {
272   MOZ_ASSERT(IsInRenderThread());
273   LOG("RenderThread::RemoveRenderer() aWindowId %" PRIx64 "",
274       AsUint64(aWindowId));
275 
276   if (mHasShutdown) {
277     return;
278   }
279 
280   mRenderers.erase(aWindowId);
281 
282   if (mRenderers.empty()) {
283     if (mHandlingDeviceReset) {
284       ClearSingletonGL();
285     }
286     mHandlingDeviceReset = false;
287     mHandlingWebRenderError = false;
288   }
289 
290   auto windows = mWindowInfos.Lock();
291   auto it = windows->find(AsUint64(aWindowId));
292   MOZ_ASSERT(it != windows->end());
293   WindowInfo* toDelete = it->second;
294   windows->erase(it);
295   delete toDelete;
296 }
297 
GetRenderer(wr::WindowId aWindowId)298 RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) {
299   MOZ_ASSERT(IsInRenderThread());
300 
301   auto it = mRenderers.find(aWindowId);
302   MOZ_ASSERT(it != mRenderers.end());
303 
304   if (it == mRenderers.end()) {
305     return nullptr;
306   }
307 
308   return it->second.get();
309 }
310 
RendererCount()311 size_t RenderThread::RendererCount() {
312   MOZ_ASSERT(IsInRenderThread());
313   return mRenderers.size();
314 }
315 
BeginRecordingForWindow(wr::WindowId aWindowId,const TimeStamp & aRecordingStart,wr::PipelineId aRootPipelineId)316 void RenderThread::BeginRecordingForWindow(wr::WindowId aWindowId,
317                                            const TimeStamp& aRecordingStart,
318                                            wr::PipelineId aRootPipelineId) {
319   MOZ_ASSERT(IsInRenderThread());
320   RendererOGL* renderer = GetRenderer(aWindowId);
321   MOZ_ASSERT(renderer);
322 
323   renderer->BeginRecording(aRecordingStart, aRootPipelineId);
324 }
325 
WriteCollectedFramesForWindow(wr::WindowId aWindowId)326 void RenderThread::WriteCollectedFramesForWindow(wr::WindowId aWindowId) {
327   MOZ_ASSERT(IsInRenderThread());
328 
329   RendererOGL* renderer = GetRenderer(aWindowId);
330   MOZ_ASSERT(renderer);
331   renderer->WriteCollectedFrames();
332 }
333 
GetCollectedFramesForWindow(wr::WindowId aWindowId)334 Maybe<layers::CollectedFrames> RenderThread::GetCollectedFramesForWindow(
335     wr::WindowId aWindowId) {
336   MOZ_ASSERT(IsInRenderThread());
337 
338   RendererOGL* renderer = GetRenderer(aWindowId);
339   MOZ_ASSERT(renderer);
340   return renderer->GetCollectedFrames();
341 }
342 
HandleFrameOneDoc(wr::WindowId aWindowId,bool aRender)343 void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender) {
344   if (mHasShutdown) {
345     return;
346   }
347 
348   if (!IsInRenderThread()) {
349     PostRunnable(NewRunnableMethod<wr::WindowId, bool>(
350         "wr::RenderThread::HandleFrameOneDoc", this,
351         &RenderThread::HandleFrameOneDoc, aWindowId, aRender));
352     return;
353   }
354 
355   if (IsDestroyed(aWindowId)) {
356     return;
357   }
358 
359   if (mHandlingDeviceReset) {
360     return;
361   }
362 
363   bool render = false;
364   PendingFrameInfo frame;
365   {  // scope lock
366     auto windows = mWindowInfos.Lock();
367     auto it = windows->find(AsUint64(aWindowId));
368     if (it == windows->end()) {
369       MOZ_ASSERT(false);
370       return;
371     }
372 
373     WindowInfo* info = it->second;
374     PendingFrameInfo& frameInfo = info->mPendingFrames.front();
375     frameInfo.mFrameNeedsRender |= aRender;
376     render = frameInfo.mFrameNeedsRender;
377 
378     frame = frameInfo;
379   }
380 
381   // It is for ensuring that PrepareForUse() is called before
382   // RenderTextureHost::Lock().
383   HandleRenderTextureOps();
384 
385   UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, render,
386                   /* aReadbackSize */ Nothing(),
387                   /* aReadbackFormat */ Nothing(),
388                   /* aReadbackBuffer */ Nothing());
389 
390   {  // scope lock
391     auto windows = mWindowInfos.Lock();
392     auto it = windows->find(AsUint64(aWindowId));
393     if (it == windows->end()) {
394       MOZ_ASSERT(false);
395       return;
396     }
397     WindowInfo* info = it->second;
398     info->mPendingFrames.pop();
399   }
400 
401   // The start time is from WebRenderBridgeParent::CompositeToTarget. From that
402   // point until now (when the frame is finally pushed to the screen) is
403   // equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
404   mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,
405                                           frame.mStartTime);
406 }
407 
SetClearColor(wr::WindowId aWindowId,wr::ColorF aColor)408 void RenderThread::SetClearColor(wr::WindowId aWindowId, wr::ColorF aColor) {
409   if (mHasShutdown) {
410     return;
411   }
412 
413   if (!IsInRenderThread()) {
414     PostRunnable(NewRunnableMethod<wr::WindowId, wr::ColorF>(
415         "wr::RenderThread::SetClearColor", this, &RenderThread::SetClearColor,
416         aWindowId, aColor));
417     return;
418   }
419 
420   if (IsDestroyed(aWindowId)) {
421     return;
422   }
423 
424   auto it = mRenderers.find(aWindowId);
425   MOZ_ASSERT(it != mRenderers.end());
426   if (it != mRenderers.end()) {
427     wr_renderer_set_clear_color(it->second->GetRenderer(), aColor);
428   }
429 }
430 
SetProfilerUI(wr::WindowId aWindowId,const nsCString & aUI)431 void RenderThread::SetProfilerUI(wr::WindowId aWindowId, const nsCString& aUI) {
432   if (mHasShutdown) {
433     return;
434   }
435 
436   if (!IsInRenderThread()) {
437     PostRunnable(NewRunnableMethod<wr::WindowId, nsCString>(
438         "wr::RenderThread::SetProfilerUI", this, &RenderThread::SetProfilerUI,
439         aWindowId, aUI));
440     return;
441   }
442 
443   auto it = mRenderers.find(aWindowId);
444   if (it != mRenderers.end()) {
445     it->second->SetProfilerUI(aUI);
446   }
447 }
448 
RunEvent(wr::WindowId aWindowId,UniquePtr<RendererEvent> aEvent)449 void RenderThread::RunEvent(wr::WindowId aWindowId,
450                             UniquePtr<RendererEvent> aEvent) {
451   if (!IsInRenderThread()) {
452     PostRunnable(NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
453         "wr::RenderThread::RunEvent", this, &RenderThread::RunEvent, aWindowId,
454         std::move(aEvent)));
455     return;
456   }
457 
458   aEvent->Run(*this, aWindowId);
459   aEvent = nullptr;
460 }
461 
NotifyDidRender(layers::CompositorBridgeParent * aBridge,const RefPtr<const WebRenderPipelineInfo> & aInfo,VsyncId aCompositeStartId,TimeStamp aCompositeStart,TimeStamp aRenderStart,TimeStamp aEnd,bool aRender,RendererStats aStats)462 static void NotifyDidRender(layers::CompositorBridgeParent* aBridge,
463                             const RefPtr<const WebRenderPipelineInfo>& aInfo,
464                             VsyncId aCompositeStartId,
465                             TimeStamp aCompositeStart, TimeStamp aRenderStart,
466                             TimeStamp aEnd, bool aRender,
467                             RendererStats aStats) {
468   if (aRender && aBridge->GetWrBridge()) {
469     // We call this here to mimic the behavior in LayerManagerComposite, as to
470     // not change what Talos measures. That is, we do not record an empty frame
471     // as a frame.
472     aBridge->GetWrBridge()->RecordFrame();
473   }
474 
475   aBridge->NotifyDidRender(aCompositeStartId, aCompositeStart, aRenderStart,
476                            aEnd, &aStats);
477 
478   for (const auto& epoch : aInfo->Raw().epochs) {
479     aBridge->NotifyPipelineRendered(epoch.pipeline_id, epoch.epoch,
480                                     aCompositeStartId, aCompositeStart,
481                                     aRenderStart, aEnd, &aStats);
482   }
483 
484   if (aBridge->GetWrBridge()) {
485     aBridge->GetWrBridge()->CompositeIfNeeded();
486   }
487 }
488 
NotifyDidStartRender(layers::CompositorBridgeParent * aBridge)489 static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) {
490   // Starting a render will change mIsRendering, and potentially
491   // change whether we can allow the bridge to intiate another frame.
492   if (aBridge->GetWrBridge()) {
493     aBridge->GetWrBridge()->CompositeIfNeeded();
494   }
495 }
496 
UpdateAndRender(wr::WindowId aWindowId,const VsyncId & aStartId,const TimeStamp & aStartTime,bool aRender,const Maybe<gfx::IntSize> & aReadbackSize,const Maybe<wr::ImageFormat> & aReadbackFormat,const Maybe<Range<uint8_t>> & aReadbackBuffer,bool * aNeedsYFlip)497 void RenderThread::UpdateAndRender(
498     wr::WindowId aWindowId, const VsyncId& aStartId,
499     const TimeStamp& aStartTime, bool aRender,
500     const Maybe<gfx::IntSize>& aReadbackSize,
501     const Maybe<wr::ImageFormat>& aReadbackFormat,
502     const Maybe<Range<uint8_t>>& aReadbackBuffer, bool* aNeedsYFlip) {
503   std::string markerName = "Composite #" + std::to_string(AsUint64(aWindowId));
504 
505   AUTO_PROFILER_TRACING_MARKER("Paint", markerName.c_str(), GRAPHICS);
506   AUTO_PROFILER_LABEL("RenderThread::UpdateAndRender", GRAPHICS);
507   MOZ_ASSERT(IsInRenderThread());
508   MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
509 
510   auto it = mRenderers.find(aWindowId);
511   MOZ_ASSERT(it != mRenderers.end());
512   if (it == mRenderers.end()) {
513     return;
514   }
515 
516   TimeStamp start = TimeStamp::Now();
517 
518   auto& renderer = it->second;
519 
520   if (renderer->IsPaused()) {
521     aRender = false;
522   }
523   LOG("RenderThread::UpdateAndRender() aWindowId %" PRIx64 " aRender %d",
524       AsUint64(aWindowId), aRender);
525 
526   layers::CompositorThread()->Dispatch(
527       NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender,
528                           renderer->GetCompositorBridge()));
529 
530   wr::RenderedFrameId latestFrameId;
531   RendererStats stats = {0};
532   if (aRender) {
533     latestFrameId = renderer->UpdateAndRender(
534         aReadbackSize, aReadbackFormat, aReadbackBuffer, aNeedsYFlip, &stats);
535   } else {
536     renderer->Update();
537   }
538   // Check graphics reset status even when rendering is skipped.
539   renderer->CheckGraphicsResetStatus("PostUpdate", /* aForce */ false);
540 
541   TimeStamp end = TimeStamp::Now();
542   RefPtr<const WebRenderPipelineInfo> info = renderer->FlushPipelineInfo();
543 
544   layers::CompositorThread()->Dispatch(
545       NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
546                           renderer->GetCompositorBridge(), info, aStartId,
547                           aStartTime, start, end, aRender, stats));
548 
549   if (latestFrameId.IsValid()) {
550     renderer->MaybeRecordFrame(info);
551   }
552 
553   ipc::FileDescriptor fenceFd;
554 
555   if (latestFrameId.IsValid()) {
556     fenceFd = renderer->GetAndResetReleaseFence();
557 
558     // Wait for GPU after posting NotifyDidRender, since the wait is not
559     // necessary for the NotifyDidRender.
560     // The wait is necessary for Textures recycling of AsyncImagePipelineManager
561     // and for avoiding GPU queue is filled with too much tasks.
562     // WaitForGPU's implementation is different for each platform.
563     renderer->WaitForGPU();
564   } else {
565     // Update frame id for NotifyPipelinesUpdated() when rendering does not
566     // happen, either because rendering was not requested or the frame was
567     // canceled. Rendering can sometimes be canceled if UpdateAndRender is
568     // called when the window is not yet ready (not mapped or 0 size).
569     latestFrameId = renderer->UpdateFrameId();
570   }
571 
572   RenderedFrameId lastCompletedFrameId = renderer->GetLastCompletedFrameId();
573 
574   RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
575       renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
576   // pipelineMgr should always be non-null here because it is only nulled out
577   // after the WebRenderAPI instance for the CompositorBridgeParent is
578   // destroyed, and that destruction blocks until the renderer thread has
579   // removed the relevant renderer. And after that happens we should never reach
580   // this code at all; it would bail out at the mRenderers.find check above.
581   MOZ_ASSERT(pipelineMgr);
582   pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId,
583                                       std::move(fenceFd));
584 }
585 
Pause(wr::WindowId aWindowId)586 void RenderThread::Pause(wr::WindowId aWindowId) {
587   MOZ_ASSERT(IsInRenderThread());
588   LOG("RenderThread::Pause() aWindowId %" PRIx64 "", AsUint64(aWindowId));
589 
590   auto it = mRenderers.find(aWindowId);
591   MOZ_ASSERT(it != mRenderers.end());
592   if (it == mRenderers.end()) {
593     return;
594   }
595   auto& renderer = it->second;
596   renderer->Pause();
597 }
598 
Resume(wr::WindowId aWindowId)599 bool RenderThread::Resume(wr::WindowId aWindowId) {
600   MOZ_ASSERT(IsInRenderThread());
601   LOG("enderThread::Resume() aWindowId %" PRIx64 "", AsUint64(aWindowId));
602 
603   auto it = mRenderers.find(aWindowId);
604   MOZ_ASSERT(it != mRenderers.end());
605   if (it == mRenderers.end()) {
606     return false;
607   }
608   auto& renderer = it->second;
609   return renderer->Resume();
610 }
611 
TooManyPendingFrames(wr::WindowId aWindowId)612 bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) {
613   const int64_t maxFrameCount = 1;
614 
615   // Too many pending frames if pending frames exit more than maxFrameCount
616   // or if RenderBackend is still processing a frame.
617 
618   auto windows = mWindowInfos.Lock();
619   auto it = windows->find(AsUint64(aWindowId));
620   if (it == windows->end()) {
621     MOZ_ASSERT(false);
622     return true;
623   }
624   WindowInfo* info = it->second;
625 
626   if (info->PendingCount() > maxFrameCount) {
627     return true;
628   }
629   // If there is no ongoing frame build, we accept a new frame.
630   return info->mPendingFrameBuild > 0;
631 }
632 
IsDestroyed(wr::WindowId aWindowId)633 bool RenderThread::IsDestroyed(wr::WindowId aWindowId) {
634   auto windows = mWindowInfos.Lock();
635   auto it = windows->find(AsUint64(aWindowId));
636   if (it == windows->end()) {
637     return true;
638   }
639 
640   return it->second->mIsDestroyed;
641 }
642 
SetDestroyed(wr::WindowId aWindowId)643 void RenderThread::SetDestroyed(wr::WindowId aWindowId) {
644   auto windows = mWindowInfos.Lock();
645   auto it = windows->find(AsUint64(aWindowId));
646   if (it == windows->end()) {
647     MOZ_ASSERT(false);
648     return;
649   }
650   it->second->mIsDestroyed = true;
651 }
652 
IncPendingFrameCount(wr::WindowId aWindowId,const VsyncId & aStartId,const TimeStamp & aStartTime)653 void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId,
654                                         const VsyncId& aStartId,
655                                         const TimeStamp& aStartTime) {
656   auto windows = mWindowInfos.Lock();
657   auto it = windows->find(AsUint64(aWindowId));
658   if (it == windows->end()) {
659     MOZ_ASSERT(false);
660     return;
661   }
662   it->second->mPendingFrameBuild++;
663   it->second->mPendingFrames.push(
664       PendingFrameInfo{aStartTime, aStartId, false});
665 }
666 
DecPendingFrameBuildCount(wr::WindowId aWindowId)667 void RenderThread::DecPendingFrameBuildCount(wr::WindowId aWindowId) {
668   auto windows = mWindowInfos.Lock();
669   auto it = windows->find(AsUint64(aWindowId));
670   if (it == windows->end()) {
671     MOZ_ASSERT(false);
672     return;
673   }
674   WindowInfo* info = it->second;
675   MOZ_RELEASE_ASSERT(info->mPendingFrameBuild >= 1);
676   info->mPendingFrameBuild--;
677 }
678 
RegisterExternalImage(const wr::ExternalImageId & aExternalImageId,already_AddRefed<RenderTextureHost> aTexture)679 void RenderThread::RegisterExternalImage(
680     const wr::ExternalImageId& aExternalImageId,
681     already_AddRefed<RenderTextureHost> aTexture) {
682   MutexAutoLock lock(mRenderTextureMapLock);
683 
684   if (mHasShutdown) {
685     return;
686   }
687   MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
688   RefPtr<RenderTextureHost> texture = aTexture;
689   if (texture->SyncObjectNeeded()) {
690     mSyncObjectNeededRenderTextures.emplace(aExternalImageId, texture);
691   }
692   mRenderTextures.emplace(aExternalImageId, texture);
693 }
694 
UnregisterExternalImage(const wr::ExternalImageId & aExternalImageId)695 void RenderThread::UnregisterExternalImage(
696     const wr::ExternalImageId& aExternalImageId) {
697   MutexAutoLock lock(mRenderTextureMapLock);
698   if (mHasShutdown) {
699     return;
700   }
701   auto it = mRenderTextures.find(aExternalImageId);
702   if (it == mRenderTextures.end()) {
703     return;
704   }
705 
706   auto& texture = it->second;
707   if (texture->SyncObjectNeeded()) {
708     MOZ_RELEASE_ASSERT(
709         mSyncObjectNeededRenderTextures.erase(aExternalImageId) == 1);
710   }
711 
712   if (!IsInRenderThread()) {
713     // The RenderTextureHost should be released in render thread. So, post the
714     // deletion task here.
715     // The shmem and raw buffer are owned by compositor ipc channel. It's
716     // possible that RenderTextureHost is still exist after the shmem/raw buffer
717     // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
718     // for this situation. Gecko will only release the buffer if WR doesn't need
719     // it. So, no one will access the invalid buffer in RenderTextureHost.
720     RefPtr<RenderTextureHost> texture = it->second;
721     mRenderTextures.erase(it);
722     mRenderTexturesDeferred.emplace_back(std::move(texture));
723     PostRunnable(NewRunnableMethod(
724         "RenderThread::DeferredRenderTextureHostDestroy", this,
725         &RenderThread::DeferredRenderTextureHostDestroy));
726   } else {
727     mRenderTextures.erase(it);
728   }
729 }
730 
PrepareForUse(const wr::ExternalImageId & aExternalImageId)731 void RenderThread::PrepareForUse(const wr::ExternalImageId& aExternalImageId) {
732   AddRenderTextureOp(RenderTextureOp::PrepareForUse, aExternalImageId);
733 }
734 
NotifyNotUsed(const wr::ExternalImageId & aExternalImageId)735 void RenderThread::NotifyNotUsed(const wr::ExternalImageId& aExternalImageId) {
736   AddRenderTextureOp(RenderTextureOp::NotifyNotUsed, aExternalImageId);
737 }
738 
NotifyForUse(const wr::ExternalImageId & aExternalImageId)739 void RenderThread::NotifyForUse(const wr::ExternalImageId& aExternalImageId) {
740   AddRenderTextureOp(RenderTextureOp::NotifyForUse, aExternalImageId);
741 }
742 
AddRenderTextureOp(RenderTextureOp aOp,const wr::ExternalImageId & aExternalImageId)743 void RenderThread::AddRenderTextureOp(
744     RenderTextureOp aOp, const wr::ExternalImageId& aExternalImageId) {
745   MOZ_ASSERT(!IsInRenderThread());
746 
747   MutexAutoLock lock(mRenderTextureMapLock);
748 
749   auto it = mRenderTextures.find(aExternalImageId);
750   MOZ_ASSERT(it != mRenderTextures.end());
751   if (it == mRenderTextures.end()) {
752     return;
753   }
754 
755   RefPtr<RenderTextureHost> texture = it->second;
756   mRenderTextureOps.emplace_back(aOp, std::move(texture));
757 
758   if (mRenderTextureOpsRunnable) {
759     // Runnable was already triggered
760     return;
761   }
762 
763   RefPtr<nsIRunnable> runnable =
764       NewRunnableMethod("RenderThread::HandleRenderTextureOps", this,
765                         &RenderThread::HandleRenderTextureOps);
766   mRenderTextureOpsRunnable = runnable;
767   PostRunnable(runnable.forget());
768 }
769 
HandleRenderTextureOps()770 void RenderThread::HandleRenderTextureOps() {
771   MOZ_ASSERT(IsInRenderThread());
772 
773   std::list<std::pair<RenderTextureOp, RefPtr<RenderTextureHost>>>
774       renderTextureOps;
775   {
776     MutexAutoLock lock(mRenderTextureMapLock);
777     mRenderTextureOps.swap(renderTextureOps);
778     mRenderTextureOpsRunnable = nullptr;
779   }
780 
781   for (auto& it : renderTextureOps) {
782     switch (it.first) {
783       case RenderTextureOp::PrepareForUse:
784         it.second->PrepareForUse();
785         break;
786       case RenderTextureOp::NotifyForUse:
787         it.second->NotifyForUse();
788         break;
789       case RenderTextureOp::NotifyNotUsed:
790         it.second->NotifyNotUsed();
791         break;
792     }
793   }
794 }
795 
UnregisterExternalImageDuringShutdown(const wr::ExternalImageId & aExternalImageId)796 void RenderThread::UnregisterExternalImageDuringShutdown(
797     const wr::ExternalImageId& aExternalImageId) {
798   MOZ_ASSERT(IsInRenderThread());
799   MutexAutoLock lock(mRenderTextureMapLock);
800   MOZ_ASSERT(mHasShutdown);
801   MOZ_ASSERT(mRenderTextures.find(aExternalImageId) != mRenderTextures.end());
802   mRenderTextures.erase(aExternalImageId);
803 }
804 
SyncObjectNeeded()805 bool RenderThread::SyncObjectNeeded() {
806   MOZ_ASSERT(IsInRenderThread());
807   MutexAutoLock lock(mRenderTextureMapLock);
808   return !mSyncObjectNeededRenderTextures.empty();
809 }
810 
DeferredRenderTextureHostDestroy()811 void RenderThread::DeferredRenderTextureHostDestroy() {
812   MutexAutoLock lock(mRenderTextureMapLock);
813   mRenderTexturesDeferred.clear();
814 }
815 
GetRenderTexture(const wr::ExternalImageId & aExternalImageId)816 RenderTextureHost* RenderThread::GetRenderTexture(
817     const wr::ExternalImageId& aExternalImageId) {
818   MutexAutoLock lock(mRenderTextureMapLock);
819   auto it = mRenderTextures.find(aExternalImageId);
820   MOZ_ASSERT(it != mRenderTextures.end());
821   if (it == mRenderTextures.end()) {
822     return nullptr;
823   }
824   return it->second;
825 }
826 
InitDeviceTask()827 void RenderThread::InitDeviceTask() {
828   MOZ_ASSERT(IsInRenderThread());
829   MOZ_ASSERT(!mSingletonGL);
830   LOG("RenderThread::InitDeviceTask()");
831 
832   if (gfx::gfxVars::UseSoftwareWebRender()) {
833     // Ensure we don't instantiate any shared GL context when SW-WR is used.
834     return;
835   }
836 
837   nsAutoCString err;
838   CreateSingletonGL(err);
839   if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
840     mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
841   }
842   // Query the shared GL context to force the
843   // lazy initialization to happen now.
844   SingletonGL();
845 }
846 
PostRunnable(already_AddRefed<nsIRunnable> aRunnable)847 void RenderThread::PostRunnable(already_AddRefed<nsIRunnable> aRunnable) {
848   nsCOMPtr<nsIRunnable> runnable = aRunnable;
849   mThread->Dispatch(runnable.forget());
850 }
851 
852 #ifndef XP_WIN
GLenumToResetReason(GLenum aReason)853 static DeviceResetReason GLenumToResetReason(GLenum aReason) {
854   switch (aReason) {
855     case LOCAL_GL_NO_ERROR:
856       return DeviceResetReason::FORCED_RESET;
857     case LOCAL_GL_INNOCENT_CONTEXT_RESET_ARB:
858       return DeviceResetReason::DRIVER_ERROR;
859     case LOCAL_GL_PURGED_CONTEXT_RESET_NV:
860       return DeviceResetReason::NVIDIA_VIDEO;
861     case LOCAL_GL_GUILTY_CONTEXT_RESET_ARB:
862       return DeviceResetReason::RESET;
863     case LOCAL_GL_UNKNOWN_CONTEXT_RESET_ARB:
864       return DeviceResetReason::UNKNOWN;
865     case LOCAL_GL_OUT_OF_MEMORY:
866       return DeviceResetReason::OUT_OF_MEMORY;
867     default:
868       return DeviceResetReason::OTHER;
869   }
870 }
871 #endif
872 
HandleDeviceReset(const char * aWhere,GLenum aReason)873 void RenderThread::HandleDeviceReset(const char* aWhere, GLenum aReason) {
874   MOZ_ASSERT(IsInRenderThread());
875 
876   // This happens only on simulate device reset.
877   if (aReason == LOCAL_GL_NO_ERROR) {
878     MOZ_ASSERT(XRE_IsGPUProcess());
879 
880     if (!mHandlingDeviceReset) {
881       mHandlingDeviceReset = true;
882 
883       MutexAutoLock lock(mRenderTextureMapLock);
884       mRenderTexturesDeferred.clear();
885       for (const auto& entry : mRenderTextures) {
886         entry.second->ClearCachedResources();
887       }
888       // Simulate DeviceReset does not need to notify the device reset to
889       // GPUProcessManager. It is already done by
890       // GPUProcessManager::SimulateDeviceReset().
891     }
892     return;
893   }
894 
895   if (mHandlingDeviceReset) {
896     return;
897   }
898 
899   mHandlingDeviceReset = true;
900 
901 #ifndef XP_WIN
902   // On Windows, see DeviceManagerDx::MaybeResetAndReacquireDevices.
903   gfx::GPUProcessManager::RecordDeviceReset(GLenumToResetReason(aReason));
904 #endif
905 
906   {
907     MutexAutoLock lock(mRenderTextureMapLock);
908     mRenderTexturesDeferred.clear();
909     for (const auto& entry : mRenderTextures) {
910       entry.second->ClearCachedResources();
911     }
912   }
913 
914   // All RenderCompositors will be destroyed by the GPUProcessManager in
915   // either OnRemoteProcessDeviceReset via the GPUChild, or
916   // OnInProcessDeviceReset here directly.
917   // On Windows, device will be re-created before sessions re-creation.
918   gfxCriticalNote << "GFX: RenderThread detected a device reset in " << aWhere;
919   if (XRE_IsGPUProcess()) {
920     gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
921   } else {
922 #ifndef XP_WIN
923     // FIXME(aosmond): Do we need to do this on Windows? nsWindow::OnPaint
924     // seems to do its own detection for the parent process.
925     bool guilty = aReason == LOCAL_GL_GUILTY_CONTEXT_RESET_ARB;
926     NS_DispatchToMainThread(NS_NewRunnableFunction(
927         "gfx::GPUProcessManager::OnInProcessDeviceReset", [guilty]() -> void {
928           gfx::GPUProcessManager::Get()->OnInProcessDeviceReset(guilty);
929         }));
930 #endif
931   }
932 }
933 
IsHandlingDeviceReset()934 bool RenderThread::IsHandlingDeviceReset() {
935   MOZ_ASSERT(IsInRenderThread());
936   return mHandlingDeviceReset;
937 }
938 
SimulateDeviceReset()939 void RenderThread::SimulateDeviceReset() {
940   if (!IsInRenderThread()) {
941     PostRunnable(NewRunnableMethod("RenderThread::SimulateDeviceReset", this,
942                                    &RenderThread::SimulateDeviceReset));
943   } else {
944     // When this function is called GPUProcessManager::SimulateDeviceReset()
945     // already triggers destroying all CompositorSessions before re-creating
946     // them.
947     HandleDeviceReset("SimulateDeviceReset", LOCAL_GL_NO_ERROR);
948   }
949 }
950 
DoNotifyWebRenderError(WebRenderError aError)951 static void DoNotifyWebRenderError(WebRenderError aError) {
952   layers::CompositorManagerParent::NotifyWebRenderError(aError);
953 }
954 
NotifyWebRenderError(WebRenderError aError)955 void RenderThread::NotifyWebRenderError(WebRenderError aError) {
956   MOZ_ASSERT(IsInRenderThread());
957 
958   layers::CompositorThread()->Dispatch(NewRunnableFunction(
959       "DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
960 }
961 
HandleWebRenderError(WebRenderError aError)962 void RenderThread::HandleWebRenderError(WebRenderError aError) {
963   if (mHandlingWebRenderError) {
964     return;
965   }
966 
967   NotifyWebRenderError(aError);
968 
969   {
970     MutexAutoLock lock(mRenderTextureMapLock);
971     mRenderTexturesDeferred.clear();
972     for (const auto& entry : mRenderTextures) {
973       entry.second->ClearCachedResources();
974     }
975   }
976   mHandlingWebRenderError = true;
977   // WebRender is going to be disabled by
978   // GPUProcessManager::NotifyWebRenderError()
979 }
980 
IsHandlingWebRenderError()981 bool RenderThread::IsHandlingWebRenderError() {
982   MOZ_ASSERT(IsInRenderThread());
983   return mHandlingWebRenderError;
984 }
985 
SingletonGL()986 gl::GLContext* RenderThread::SingletonGL() {
987   nsAutoCString err;
988   auto* gl = SingletonGL(err);
989   if (!err.IsEmpty()) {
990     gfxCriticalNote << err.get();
991   }
992   return gl;
993 }
994 
CreateSingletonGL(nsACString & aError)995 void RenderThread::CreateSingletonGL(nsACString& aError) {
996   MOZ_ASSERT(IsInRenderThread());
997   LOG("RenderThread::CreateSingletonGL()");
998 
999   mSingletonGL = CreateGLContext(aError);
1000   mSingletonGLIsForHardwareWebRender = !gfx::gfxVars::UseSoftwareWebRender();
1001 }
1002 
SingletonGL(nsACString & aError)1003 gl::GLContext* RenderThread::SingletonGL(nsACString& aError) {
1004   MOZ_ASSERT(IsInRenderThread());
1005   if (!mSingletonGL) {
1006     CreateSingletonGL(aError);
1007     mShaders = nullptr;
1008   }
1009   if (mSingletonGL && mSingletonGLIsForHardwareWebRender && !mShaders) {
1010     mShaders = MakeUnique<WebRenderShaders>(mSingletonGL, mProgramCache.get());
1011   }
1012 
1013   return mSingletonGL.get();
1014 }
1015 
SingletonGLForCompositorOGL()1016 gl::GLContext* RenderThread::SingletonGLForCompositorOGL() {
1017   MOZ_RELEASE_ASSERT(gfx::gfxVars::UseSoftwareWebRender());
1018 
1019   if (mSingletonGLIsForHardwareWebRender) {
1020     // Clear singleton GL, since GLContext is for hardware WebRender.
1021     ClearSingletonGL();
1022   }
1023   return SingletonGL();
1024 }
1025 
ClearSingletonGL()1026 void RenderThread::ClearSingletonGL() {
1027   MOZ_ASSERT(IsInRenderThread());
1028   LOG("RenderThread::ClearSingletonGL()");
1029 
1030   if (mSurfacePool) {
1031     mSurfacePool->DestroyGLResourcesForContext(mSingletonGL);
1032   }
1033   if (mProgramsForCompositorOGL) {
1034     mProgramsForCompositorOGL->Clear();
1035     mProgramsForCompositorOGL = nullptr;
1036   }
1037   mShaders = nullptr;
1038   mSingletonGL = nullptr;
1039 }
1040 
1041 RefPtr<layers::ShaderProgramOGLsHolder>
GetProgramsForCompositorOGL()1042 RenderThread::GetProgramsForCompositorOGL() {
1043   if (!mSingletonGL) {
1044     return nullptr;
1045   }
1046 
1047   if (!mProgramsForCompositorOGL) {
1048     mProgramsForCompositorOGL =
1049         MakeAndAddRef<layers::ShaderProgramOGLsHolder>(mSingletonGL);
1050   }
1051   return mProgramsForCompositorOGL;
1052 }
1053 
SharedSurfacePool()1054 RefPtr<layers::SurfacePool> RenderThread::SharedSurfacePool() {
1055 #if defined(XP_MACOSX) || defined(MOZ_WAYLAND)
1056   if (!mSurfacePool) {
1057     size_t poolSizeLimit =
1058         StaticPrefs::gfx_webrender_compositor_surface_pool_size_AtStartup();
1059     mSurfacePool = layers::SurfacePool::Create(poolSizeLimit);
1060   }
1061 #endif
1062   return mSurfacePool;
1063 }
1064 
ClearSharedSurfacePool()1065 void RenderThread::ClearSharedSurfacePool() { mSurfacePool = nullptr; }
1066 
DebugMessageCallback(GLenum aSource,GLenum aType,GLuint aId,GLenum aSeverity,GLsizei aLength,const GLchar * aMessage,const GLvoid * aUserParam)1067 static void GLAPIENTRY DebugMessageCallback(GLenum aSource, GLenum aType,
1068                                             GLuint aId, GLenum aSeverity,
1069                                             GLsizei aLength,
1070                                             const GLchar* aMessage,
1071                                             const GLvoid* aUserParam) {
1072   constexpr const char* kContextLost = "Context has been lost.";
1073 
1074   if (StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() &&
1075       aSeverity == LOCAL_GL_DEBUG_SEVERITY_HIGH) {
1076     auto message = std::string(aMessage, aLength);
1077     // When content lost happned, error messages are flooded by its message.
1078     if (message != kContextLost) {
1079       gfxCriticalNote << message;
1080     } else {
1081       gfxCriticalNoteOnce << message;
1082     }
1083   }
1084 
1085   if (StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup()) {
1086     gl::GLContext* gl = (gl::GLContext*)aUserParam;
1087     gl->DebugCallback(aSource, aType, aId, aSeverity, aLength, aMessage);
1088   }
1089 }
1090 
1091 // static
MaybeEnableGLDebugMessage(gl::GLContext * aGLContext)1092 void RenderThread::MaybeEnableGLDebugMessage(gl::GLContext* aGLContext) {
1093   if (!aGLContext) {
1094     return;
1095   }
1096 
1097   bool enableDebugMessage =
1098       StaticPrefs::gfx_webrender_gl_debug_message_critical_note_AtStartup() ||
1099       StaticPrefs::gfx_webrender_gl_debug_message_print_AtStartup();
1100 
1101   if (enableDebugMessage &&
1102       aGLContext->IsExtensionSupported(gl::GLContext::KHR_debug)) {
1103     aGLContext->fEnable(LOCAL_GL_DEBUG_OUTPUT);
1104     aGLContext->fDisable(LOCAL_GL_DEBUG_OUTPUT_SYNCHRONOUS);
1105     aGLContext->fDebugMessageCallback(&DebugMessageCallback, (void*)aGLContext);
1106     aGLContext->fDebugMessageControl(LOCAL_GL_DONT_CARE, LOCAL_GL_DONT_CARE,
1107                                      LOCAL_GL_DONT_CARE, 0, nullptr, true);
1108   }
1109 }
1110 
WebRenderShaders(gl::GLContext * gl,WebRenderProgramCache * programCache)1111 WebRenderShaders::WebRenderShaders(gl::GLContext* gl,
1112                                    WebRenderProgramCache* programCache) {
1113   mGL = gl;
1114   mShaders =
1115       wr_shaders_new(gl, programCache ? programCache->Raw() : nullptr,
1116                      StaticPrefs::gfx_webrender_precache_shaders_AtStartup());
1117 }
1118 
~WebRenderShaders()1119 WebRenderShaders::~WebRenderShaders() {
1120   wr_shaders_delete(mShaders, mGL.get());
1121 }
1122 
WebRenderThreadPool(bool low_priority)1123 WebRenderThreadPool::WebRenderThreadPool(bool low_priority) {
1124   mThreadPool = wr_thread_pool_new(low_priority);
1125 }
1126 
~WebRenderThreadPool()1127 WebRenderThreadPool::~WebRenderThreadPool() { Release(); }
1128 
Release()1129 void WebRenderThreadPool::Release() {
1130   if (mThreadPool) {
1131     wr_thread_pool_delete(mThreadPool);
1132     mThreadPool = nullptr;
1133   }
1134 }
1135 
WebRenderProgramCache(wr::WrThreadPool * aThreadPool)1136 WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) {
1137   MOZ_ASSERT(aThreadPool);
1138 
1139   nsAutoString path;
1140   if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1141     path.Append(gfx::gfxVars::ProfDirectory());
1142   }
1143   mProgramCache = wr_program_cache_new(&path, aThreadPool);
1144   if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
1145     wr_try_load_startup_shaders_from_disk(mProgramCache);
1146   }
1147 }
1148 
~WebRenderProgramCache()1149 WebRenderProgramCache::~WebRenderProgramCache() {
1150   wr_program_cache_delete(mProgramCache);
1151 }
1152 
1153 }  // namespace mozilla::wr
1154 
1155 #ifdef XP_WIN
CreateGLContextANGLE(nsACString & aError)1156 static already_AddRefed<gl::GLContext> CreateGLContextANGLE(
1157     nsACString& aError) {
1158   const RefPtr<ID3D11Device> d3d11Device =
1159       gfx::DeviceManagerDx::Get()->GetCompositorDevice();
1160   if (!d3d11Device) {
1161     aError.Assign("RcANGLE(no compositor device for EGLDisplay)"_ns);
1162     return nullptr;
1163   }
1164 
1165   nsCString failureId;
1166   const auto lib = gl::DefaultEglLibrary(&failureId);
1167   if (!lib) {
1168     aError.Assign(
1169         nsPrintfCString("RcANGLE(load EGL lib failed: %s)", failureId.get()));
1170     return nullptr;
1171   }
1172 
1173   const auto egl = lib->CreateDisplay(d3d11Device.get());
1174   if (!egl) {
1175     aError.Assign(nsPrintfCString("RcANGLE(create EGLDisplay failed: %s)",
1176                                   failureId.get()));
1177     return nullptr;
1178   }
1179 
1180   gl::CreateContextFlags flags = gl::CreateContextFlags::PREFER_ES3;
1181 
1182   if (StaticPrefs::gfx_webrender_prefer_robustness_AtStartup()) {
1183     flags |= gl::CreateContextFlags::PREFER_ROBUSTNESS;
1184   }
1185 
1186   if (egl->IsExtensionSupported(
1187           gl::EGLExtension::MOZ_create_context_provoking_vertex_dont_care)) {
1188     flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE;
1189   }
1190 
1191   // Create GLContext with dummy EGLSurface, the EGLSurface is not used.
1192   // Instread we override it with EGLSurface of SwapChain's back buffer.
1193 
1194   const auto dummySize = mozilla::gfx::IntSize(16, 16);
1195   auto gl = gl::GLContextEGL::CreateEGLPBufferOffscreenContext(
1196       egl, {flags}, dummySize, &failureId);
1197   if (!gl || !gl->IsANGLE()) {
1198     aError.Assign(nsPrintfCString("RcANGLE(create GL context failed: %x, %s)",
1199                                   gl.get(), failureId.get()));
1200     return nullptr;
1201   }
1202 
1203   if (!gl->MakeCurrent()) {
1204     aError.Assign(
1205         nsPrintfCString("RcANGLE(make current GL context failed: %x, %x)",
1206                         gl.get(), gl->mEgl->mLib->fGetError()));
1207     return nullptr;
1208   }
1209 
1210   return gl.forget();
1211 }
1212 #endif
1213 
1214 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WAYLAND) || defined(MOZ_X11)
CreateGLContextEGL()1215 static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
1216   // Create GLContext with dummy EGLSurface.
1217   bool forHardwareWebRender = true;
1218   // SW-WR uses CompositorOGL in native compositor.
1219   if (gfx::gfxVars::UseSoftwareWebRender()) {
1220     forHardwareWebRender = false;
1221   }
1222   RefPtr<gl::GLContext> gl =
1223       gl::GLContextProviderEGL::CreateForCompositorWidget(
1224           nullptr, forHardwareWebRender, /* aForceAccelerated */ true);
1225   if (!gl || !gl->MakeCurrent()) {
1226     gfxCriticalNote << "Failed GL context creation for hardware WebRender: "
1227                     << forHardwareWebRender;
1228     return nullptr;
1229   }
1230   return gl.forget();
1231 }
1232 #endif
1233 
1234 #ifdef XP_MACOSX
CreateGLContextCGL()1235 static already_AddRefed<gl::GLContext> CreateGLContextCGL() {
1236   nsCString failureUnused;
1237   return gl::GLContextProvider::CreateHeadless(
1238       {gl::CreateContextFlags::ALLOW_OFFLINE_RENDERER |
1239        gl::CreateContextFlags::FORCE_ENABLE_HARDWARE},
1240       &failureUnused);
1241 }
1242 #endif
1243 
CreateGLContext(nsACString & aError)1244 static already_AddRefed<gl::GLContext> CreateGLContext(nsACString& aError) {
1245   RefPtr<gl::GLContext> gl;
1246 
1247 #ifdef XP_WIN
1248   if (gfx::gfxVars::UseWebRenderANGLE()) {
1249     gl = CreateGLContextANGLE(aError);
1250   }
1251 #elif defined(MOZ_WIDGET_ANDROID)
1252   gl = CreateGLContextEGL();
1253 #elif defined(MOZ_WAYLAND) || defined(MOZ_X11)
1254   if (gfx::gfxVars::UseEGL()) {
1255     gl = CreateGLContextEGL();
1256   }
1257 #elif XP_MACOSX
1258   gl = CreateGLContextCGL();
1259 #endif
1260 
1261   wr::RenderThread::MaybeEnableGLDebugMessage(gl);
1262 
1263   return gl.forget();
1264 }
1265 
1266 extern "C" {
1267 
wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId,bool aCompositeNeeded)1268 void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId,
1269                          bool aCompositeNeeded) {
1270   mozilla::wr::RenderThread::Get()->IncPendingFrameCount(aWindowId, VsyncId(),
1271                                                          TimeStamp::Now());
1272   mozilla::wr::RenderThread::Get()->DecPendingFrameBuildCount(aWindowId);
1273   mozilla::wr::RenderThread::Get()->HandleFrameOneDoc(aWindowId,
1274                                                       aCompositeNeeded);
1275 }
1276 
wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId)1277 void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId) {
1278   mozilla::wr::RenderThread::Get()->DecPendingFrameBuildCount(aWindowId);
1279   mozilla::wr::RenderThread::Get()->HandleFrameOneDoc(aWindowId,
1280                                                       /* aRender */ true);
1281 }
1282 
wr_notifier_nop_frame_done(mozilla::wr::WrWindowId aWindowId)1283 void wr_notifier_nop_frame_done(mozilla::wr::WrWindowId aWindowId) {
1284   mozilla::wr::RenderThread::Get()->DecPendingFrameBuildCount(aWindowId);
1285   mozilla::wr::RenderThread::Get()->HandleFrameOneDoc(aWindowId,
1286                                                       /* aRender */ false);
1287 }
1288 
wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,size_t aRawEvent)1289 void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
1290                                 size_t aRawEvent) {
1291   mozilla::UniquePtr<mozilla::wr::RendererEvent> evt(
1292       reinterpret_cast<mozilla::wr::RendererEvent*>(aRawEvent));
1293   mozilla::wr::RenderThread::Get()->RunEvent(mozilla::wr::WindowId(aWindowId),
1294                                              std::move(evt));
1295 }
1296 
NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,wr::RenderReasons aReasons)1297 static void NotifyScheduleRender(mozilla::wr::WrWindowId aWindowId,
1298                                  wr::RenderReasons aReasons) {
1299   RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1300       CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1301   if (cbp) {
1302     cbp->ScheduleComposition(aReasons);
1303   }
1304 }
1305 
wr_schedule_render(mozilla::wr::WrWindowId aWindowId,wr::RenderReasons aReasons)1306 void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
1307                         wr::RenderReasons aReasons) {
1308   layers::CompositorThread()->Dispatch(NewRunnableFunction(
1309       "NotifyScheduleRender", &NotifyScheduleRender, aWindowId, aReasons));
1310 }
1311 
NotifyDidSceneBuild(mozilla::wr::WrWindowId aWindowId,const RefPtr<const wr::WebRenderPipelineInfo> & aInfo)1312 static void NotifyDidSceneBuild(
1313     mozilla::wr::WrWindowId aWindowId,
1314     const RefPtr<const wr::WebRenderPipelineInfo>& aInfo) {
1315   RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
1316       CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
1317   if (cbp) {
1318     cbp->NotifyDidSceneBuild(aInfo);
1319   }
1320 }
1321 
wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,mozilla::wr::WrPipelineInfo * aPipelineInfo)1322 void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,
1323                              mozilla::wr::WrPipelineInfo* aPipelineInfo) {
1324   RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo();
1325   info->Raw() = std::move(*aPipelineInfo);
1326   layers::CompositorThread()->Dispatch(NewRunnableFunction(
1327       "NotifyDidSceneBuild", &NotifyDidSceneBuild, aWindowId, info));
1328 }
1329 
1330 }  // extern C
1331