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