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 "mozilla/layers/WebRenderBridgeParent.h"
8 
9 #include "CompositableHost.h"
10 #include "gfxEnv.h"
11 #include "gfxPlatform.h"
12 #include "gfxOTSUtils.h"
13 #include "GeckoProfiler.h"
14 #include "GLContext.h"
15 #include "GLContextProvider.h"
16 #include "GLLibraryLoader.h"
17 #include "Layers.h"
18 #include "nsExceptionHandler.h"
19 #include "mozilla/Range.h"
20 #include "mozilla/StaticPrefs_gfx.h"
21 #include "mozilla/UniquePtr.h"
22 #include "mozilla/gfx/gfxVars.h"
23 #include "mozilla/gfx/GPUParent.h"
24 #include "mozilla/layers/AnimationHelper.h"
25 #include "mozilla/layers/APZSampler.h"
26 #include "mozilla/layers/APZUpdater.h"
27 #include "mozilla/layers/Compositor.h"
28 #include "mozilla/layers/CompositorBridgeParent.h"
29 #include "mozilla/layers/CompositorAnimationStorage.h"
30 #include "mozilla/layers/CompositorThread.h"
31 #include "mozilla/layers/CompositorVsyncScheduler.h"
32 #include "mozilla/layers/ImageBridgeParent.h"
33 #include "mozilla/layers/ImageDataSerializer.h"
34 #include "mozilla/layers/IpcResourceUpdateQueue.h"
35 #include "mozilla/layers/OMTASampler.h"
36 #include "mozilla/layers/SharedSurfacesParent.h"
37 #include "mozilla/layers/TextureHost.h"
38 #include "mozilla/layers/AsyncImagePipelineManager.h"
39 #include "mozilla/layers/UiCompositorControllerParent.h"
40 #include "mozilla/layers/WebRenderImageHost.h"
41 #include "mozilla/layers/WebRenderTextureHost.h"
42 #include "mozilla/ProfilerMarkerTypes.h"
43 #include "mozilla/Telemetry.h"
44 #include "mozilla/TimeStamp.h"
45 #include "mozilla/Unused.h"
46 #include "mozilla/webrender/RenderTextureHostSWGL.h"
47 #include "mozilla/webrender/RenderThread.h"
48 #include "mozilla/widget/CompositorWidget.h"
49 
50 #ifdef XP_WIN
51 #  include "mozilla/widget/WinCompositorWidget.h"
52 #endif
53 
is_in_main_thread()54 bool is_in_main_thread() { return NS_IsMainThread(); }
55 
is_in_compositor_thread()56 bool is_in_compositor_thread() {
57   return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
58 }
59 
is_in_render_thread()60 bool is_in_render_thread() {
61   return mozilla::wr::RenderThread::IsInRenderThread();
62 }
63 
gecko_profiler_start_marker(const char * name)64 void gecko_profiler_start_marker(const char* name) {
65   PROFILER_MARKER(mozilla::ProfilerString8View::WrapNullTerminatedString(name),
66                   GRAPHICS, mozilla::MarkerTiming::IntervalStart(), Tracing,
67                   "WebRender");
68 }
69 
gecko_profiler_end_marker(const char * name)70 void gecko_profiler_end_marker(const char* name) {
71   PROFILER_MARKER(mozilla::ProfilerString8View::WrapNullTerminatedString(name),
72                   GRAPHICS, mozilla::MarkerTiming::IntervalEnd(), Tracing,
73                   "WebRender");
74 }
75 
gecko_profiler_event_marker(const char * name)76 void gecko_profiler_event_marker(const char* name) {
77   PROFILER_MARKER(mozilla::ProfilerString8View::WrapNullTerminatedString(name),
78                   GRAPHICS, {}, Tracing, "WebRender");
79 }
80 
gecko_profiler_add_text_marker(const char * name,const char * text_bytes,size_t text_len,uint64_t microseconds)81 void gecko_profiler_add_text_marker(const char* name, const char* text_bytes,
82                                     size_t text_len, uint64_t microseconds) {
83   if (profiler_thread_is_being_profiled()) {
84     auto now = mozilla::TimeStamp::NowUnfuzzed();
85     [[maybe_unused]] auto start =
86         now - mozilla::TimeDuration::FromMicroseconds(microseconds);
87     PROFILER_MARKER_TEXT(
88         mozilla::ProfilerString8View::WrapNullTerminatedString(name), GRAPHICS,
89         mozilla::MarkerTiming::Interval(start, now),
90         mozilla::ProfilerString8View(text_bytes, text_len));
91   }
92 }
93 
gecko_profiler_thread_is_being_profiled()94 bool gecko_profiler_thread_is_being_profiled() {
95   return profiler_thread_is_being_profiled();
96 }
97 
is_glcontext_gles(void * const glcontext_ptr)98 bool is_glcontext_gles(void* const glcontext_ptr) {
99   MOZ_RELEASE_ASSERT(glcontext_ptr);
100   return reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr)->IsGLES();
101 }
102 
is_glcontext_angle(void * glcontext_ptr)103 bool is_glcontext_angle(void* glcontext_ptr) {
104   MOZ_ASSERT(glcontext_ptr);
105 
106   mozilla::gl::GLContext* glcontext =
107       reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
108   if (!glcontext) {
109     return false;
110   }
111   return glcontext->IsANGLE();
112 }
113 
gfx_wr_resource_path_override()114 const char* gfx_wr_resource_path_override() {
115   return gfxPlatform::WebRenderResourcePathOverride();
116 }
117 
gfx_wr_use_optimized_shaders()118 bool gfx_wr_use_optimized_shaders() {
119   return mozilla::gfx::gfxVars::UseWebRenderOptimizedShaders();
120 }
121 
gfx_critical_note(const char * msg)122 void gfx_critical_note(const char* msg) { gfxCriticalNote << msg; }
123 
gfx_critical_error(const char * msg)124 void gfx_critical_error(const char* msg) { gfxCriticalError() << msg; }
125 
gecko_printf_stderr_output(const char * msg)126 void gecko_printf_stderr_output(const char* msg) { printf_stderr("%s\n", msg); }
127 
get_proc_address_from_glcontext(void * glcontext_ptr,const char * procname)128 void* get_proc_address_from_glcontext(void* glcontext_ptr,
129                                       const char* procname) {
130   mozilla::gl::GLContext* glcontext =
131       reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
132   MOZ_ASSERT(glcontext);
133   if (!glcontext) {
134     return nullptr;
135   }
136   const auto& loader = glcontext->GetSymbolLoader();
137   MOZ_ASSERT(loader);
138 
139   const auto ret = loader->GetProcAddress(procname);
140   return reinterpret_cast<void*>(ret);
141 }
142 
record_telemetry_time(mozilla::wr::TelemetryProbe aProbe,uint64_t aTimeNs)143 void record_telemetry_time(mozilla::wr::TelemetryProbe aProbe,
144                            uint64_t aTimeNs) {
145   uint32_t time_ms = (uint32_t)(aTimeNs / 1000000);
146   switch (aProbe) {
147     case mozilla::wr::TelemetryProbe::SceneBuildTime:
148       mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_SCENEBUILD_TIME,
149                                      time_ms);
150       break;
151     case mozilla::wr::TelemetryProbe::SceneSwapTime:
152       mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_SCENESWAP_TIME,
153                                      time_ms);
154       break;
155     case mozilla::wr::TelemetryProbe::FrameBuildTime:
156       mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_FRAMEBUILD_TIME,
157                                      time_ms);
158       break;
159     default:
160       MOZ_ASSERT(false);
161       break;
162   }
163 }
164 
FromWrCrashAnnotation(mozilla::wr::CrashAnnotation aAnnotation)165 static CrashReporter::Annotation FromWrCrashAnnotation(
166     mozilla::wr::CrashAnnotation aAnnotation) {
167   switch (aAnnotation) {
168     case mozilla::wr::CrashAnnotation::CompileShader:
169       return CrashReporter::Annotation::GraphicsCompileShader;
170     case mozilla::wr::CrashAnnotation::DrawShader:
171       return CrashReporter::Annotation::GraphicsDrawShader;
172     default:
173       MOZ_ASSERT_UNREACHABLE("Unhandled annotation!");
174       return CrashReporter::Annotation::Count;
175   }
176 }
177 
178 extern "C" {
179 
gfx_wr_set_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation,const char * aValue)180 void gfx_wr_set_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation,
181                                  const char* aValue) {
182   MOZ_ASSERT(aValue);
183 
184   auto annotation = FromWrCrashAnnotation(aAnnotation);
185   if (annotation == CrashReporter::Annotation::Count) {
186     return;
187   }
188 
189   CrashReporter::AnnotateCrashReport(annotation, nsDependentCString(aValue));
190 }
191 
gfx_wr_clear_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation)192 void gfx_wr_clear_crash_annotation(mozilla::wr::CrashAnnotation aAnnotation) {
193   auto annotation = FromWrCrashAnnotation(aAnnotation);
194   if (annotation == CrashReporter::Annotation::Count) {
195     return;
196   }
197 
198   CrashReporter::RemoveCrashReportAnnotation(annotation);
199 }
200 }
201 
202 namespace mozilla {
203 
204 namespace layers {
205 
206 using namespace mozilla::gfx;
207 
208 class ScheduleObserveLayersUpdate : public wr::NotificationHandler {
209  public:
ScheduleObserveLayersUpdate(RefPtr<CompositorBridgeParentBase> aBridge,LayersId aLayersId,LayersObserverEpoch aEpoch,bool aIsActive)210   ScheduleObserveLayersUpdate(RefPtr<CompositorBridgeParentBase> aBridge,
211                               LayersId aLayersId, LayersObserverEpoch aEpoch,
212                               bool aIsActive)
213       : mBridge(aBridge),
214         mLayersId(aLayersId),
215         mObserverEpoch(aEpoch),
216         mIsActive(aIsActive) {}
217 
Notify(wr::Checkpoint)218   void Notify(wr::Checkpoint) override {
219     CompositorThread()->Dispatch(
220         NewRunnableMethod<LayersId, LayersObserverEpoch, int>(
221             "ObserveLayersUpdate", mBridge,
222             &CompositorBridgeParentBase::ObserveLayersUpdate, mLayersId,
223             mObserverEpoch, mIsActive));
224   }
225 
226  protected:
227   RefPtr<CompositorBridgeParentBase> mBridge;
228   LayersId mLayersId;
229   LayersObserverEpoch mObserverEpoch;
230   bool mIsActive;
231 };
232 
233 class SceneBuiltNotification : public wr::NotificationHandler {
234  public:
SceneBuiltNotification(WebRenderBridgeParent * aParent,wr::Epoch aEpoch,TimeStamp aTxnStartTime)235   SceneBuiltNotification(WebRenderBridgeParent* aParent, wr::Epoch aEpoch,
236                          TimeStamp aTxnStartTime)
237       : mParent(aParent), mEpoch(aEpoch), mTxnStartTime(aTxnStartTime) {}
238 
Notify(wr::Checkpoint)239   void Notify(wr::Checkpoint) override {
240     auto startTime = this->mTxnStartTime;
241     RefPtr<WebRenderBridgeParent> parent = mParent;
242     wr::Epoch epoch = mEpoch;
243     CompositorThread()->Dispatch(NS_NewRunnableFunction(
244         "SceneBuiltNotificationRunnable", [parent, epoch, startTime]() {
245           auto endTime = TimeStamp::Now();
246           if (profiler_can_accept_markers()) {
247             PROFILER_MARKER("CONTENT_FULL_PAINT_TIME", GRAPHICS,
248                             MarkerTiming::Interval(startTime, endTime),
249                             ContentBuildMarker);
250           }
251           Telemetry::Accumulate(
252               Telemetry::CONTENT_FULL_PAINT_TIME,
253               static_cast<uint32_t>((endTime - startTime).ToMilliseconds()));
254           parent->NotifySceneBuiltForEpoch(epoch, endTime);
255         }));
256   }
257 
258  protected:
259   RefPtr<WebRenderBridgeParent> mParent;
260   wr::Epoch mEpoch;
261   TimeStamp mTxnStartTime;
262 };
263 
264 class WebRenderBridgeParent::ScheduleSharedSurfaceRelease final
265     : public wr::NotificationHandler {
266  public:
ScheduleSharedSurfaceRelease(WebRenderBridgeParent * aWrBridge)267   explicit ScheduleSharedSurfaceRelease(WebRenderBridgeParent* aWrBridge)
268       : mWrBridge(aWrBridge), mSurfaces(20) {}
269 
Add(const wr::ImageKey & aKey,const wr::ExternalImageId & aId)270   void Add(const wr::ImageKey& aKey, const wr::ExternalImageId& aId) {
271     mSurfaces.AppendElement(wr::ExternalImageKeyPair{aKey, aId});
272   }
273 
Notify(wr::Checkpoint)274   void Notify(wr::Checkpoint) override {
275     CompositorThread()->Dispatch(
276         NewRunnableMethod<nsTArray<wr::ExternalImageKeyPair>>(
277             "ObserveSharedSurfaceRelease", mWrBridge,
278             &WebRenderBridgeParent::ObserveSharedSurfaceRelease,
279             std::move(mSurfaces)));
280   }
281 
282  private:
283   RefPtr<WebRenderBridgeParent> mWrBridge;
284   nsTArray<wr::ExternalImageKeyPair> mSurfaces;
285 };
286 
287 class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender final {
288  public:
AutoWebRenderBridgeParentAsyncMessageSender(WebRenderBridgeParent * aWebRenderBridgeParent,nsTArray<OpDestroy> * aDestroyActors=nullptr)289   explicit AutoWebRenderBridgeParentAsyncMessageSender(
290       WebRenderBridgeParent* aWebRenderBridgeParent,
291       nsTArray<OpDestroy>* aDestroyActors = nullptr)
292       : mWebRenderBridgeParent(aWebRenderBridgeParent),
293         mActorsToDestroy(aDestroyActors) {
294     mWebRenderBridgeParent->SetAboutToSendAsyncMessages();
295   }
296 
~AutoWebRenderBridgeParentAsyncMessageSender()297   ~AutoWebRenderBridgeParentAsyncMessageSender() {
298     mWebRenderBridgeParent->SendPendingAsyncMessages();
299     if (mActorsToDestroy) {
300       // Destroy the actors after sending the async messages because the latter
301       // may contain references to some actors.
302       for (const auto& op : *mActorsToDestroy) {
303         mWebRenderBridgeParent->DestroyActor(op);
304       }
305     }
306   }
307 
308  private:
309   WebRenderBridgeParent* mWebRenderBridgeParent;
310   nsTArray<OpDestroy>* mActorsToDestroy;
311 };
312 
WebRenderBridgeParent(CompositorBridgeParentBase * aCompositorBridge,const wr::PipelineId & aPipelineId,widget::CompositorWidget * aWidget,CompositorVsyncScheduler * aScheduler,RefPtr<wr::WebRenderAPI> && aApi,RefPtr<AsyncImagePipelineManager> && aImageMgr,TimeDuration aVsyncRate)313 WebRenderBridgeParent::WebRenderBridgeParent(
314     CompositorBridgeParentBase* aCompositorBridge,
315     const wr::PipelineId& aPipelineId, widget::CompositorWidget* aWidget,
316     CompositorVsyncScheduler* aScheduler, RefPtr<wr::WebRenderAPI>&& aApi,
317     RefPtr<AsyncImagePipelineManager>&& aImageMgr, TimeDuration aVsyncRate)
318     : mCompositorBridge(aCompositorBridge),
319       mPipelineId(aPipelineId),
320       mWidget(aWidget),
321       mApi(aApi),
322       mAsyncImageManager(aImageMgr),
323       mCompositorScheduler(aScheduler),
324       mVsyncRate(aVsyncRate),
325       mChildLayersObserverEpoch{0},
326       mParentLayersObserverEpoch{0},
327       mWrEpoch{0},
328       mIdNamespace(aApi->GetNamespace()),
329 #if defined(MOZ_WIDGET_ANDROID)
330       mScreenPixelsTarget(nullptr),
331 #endif
332       mDestroyed(false),
333       mReceivedDisplayList(false),
334       mIsFirstPaint(true),
335       mSkippedComposite(false),
336       mDisablingNativeCompositor(false),
337       mPendingScrollPayloads("WebRenderBridgeParent::mPendingScrollPayloads") {
338   MOZ_ASSERT(mAsyncImageManager);
339   mAsyncImageManager->AddPipeline(mPipelineId, this);
340   if (IsRootWebRenderBridgeParent()) {
341     MOZ_ASSERT(!mCompositorScheduler);
342     mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
343   }
344   UpdateDebugFlags();
345   UpdateQualitySettings();
346   UpdateProfilerUI();
347 }
348 
WebRenderBridgeParent(const wr::PipelineId & aPipelineId,nsCString && aError)349 WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId,
350                                              nsCString&& aError)
351     : mCompositorBridge(nullptr),
352       mPipelineId(aPipelineId),
353       mChildLayersObserverEpoch{0},
354       mParentLayersObserverEpoch{0},
355       mWrEpoch{0},
356       mIdNamespace{0},
357       mInitError(aError),
358       mDestroyed(true),
359       mReceivedDisplayList(false),
360       mIsFirstPaint(false),
361       mSkippedComposite(false),
362       mDisablingNativeCompositor(false),
363       mPendingScrollPayloads("WebRenderBridgeParent::mPendingScrollPayloads") {}
364 
~WebRenderBridgeParent()365 WebRenderBridgeParent::~WebRenderBridgeParent() {}
366 
367 /* static */
CreateDestroyed(const wr::PipelineId & aPipelineId,nsCString && aError)368 WebRenderBridgeParent* WebRenderBridgeParent::CreateDestroyed(
369     const wr::PipelineId& aPipelineId, nsCString&& aError) {
370   return new WebRenderBridgeParent(aPipelineId, std::move(aError));
371 }
372 
RecvEnsureConnected(TextureFactoryIdentifier * aTextureFactoryIdentifier,MaybeIdNamespace * aMaybeIdNamespace,nsCString * aError)373 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEnsureConnected(
374     TextureFactoryIdentifier* aTextureFactoryIdentifier,
375     MaybeIdNamespace* aMaybeIdNamespace, nsCString* aError) {
376   if (mDestroyed) {
377     *aTextureFactoryIdentifier =
378         TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
379     *aMaybeIdNamespace = Nothing();
380     if (mInitError.IsEmpty()) {
381       // Got destroyed after we initialized but before the handshake finished?
382       aError->AssignLiteral("FEATURE_FAILURE_WEBRENDER_INITIALIZE_RACE");
383     } else {
384       *aError = std::move(mInitError);
385     }
386     return IPC_OK();
387   }
388 
389   MOZ_ASSERT(mIdNamespace.mHandle != 0);
390   *aTextureFactoryIdentifier = GetTextureFactoryIdentifier();
391   *aMaybeIdNamespace = Some(mIdNamespace);
392 
393   return IPC_OK();
394 }
395 
RecvShutdown()396 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvShutdown() {
397   return HandleShutdown();
398 }
399 
RecvShutdownSync()400 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvShutdownSync() {
401   return HandleShutdown();
402 }
403 
HandleShutdown()404 mozilla::ipc::IPCResult WebRenderBridgeParent::HandleShutdown() {
405   Destroy();
406   IProtocol* mgr = Manager();
407   if (!Send__delete__(this)) {
408     return IPC_FAIL_NO_REASON(mgr);
409   }
410   return IPC_OK();
411 }
412 
Destroy()413 void WebRenderBridgeParent::Destroy() {
414   if (mDestroyed) {
415     return;
416   }
417   mDestroyed = true;
418   if (mWebRenderBridgeRef) {
419     // Break mutual reference
420     mWebRenderBridgeRef->Clear();
421     mWebRenderBridgeRef = nullptr;
422   }
423   mCompositables.clear();
424   ClearResources();
425 }
426 
427 struct WROTSAlloc {
428   wr::Vec<uint8_t> mVec;
429 
Growmozilla::layers::WROTSAlloc430   void* Grow(void* aPtr, size_t aLength) {
431     if (aLength > mVec.Capacity()) {
432       mVec.Reserve(aLength - mVec.Capacity());
433     }
434     return mVec.inner.data;
435   }
ShrinkToFitmozilla::layers::WROTSAlloc436   wr::Vec<uint8_t> ShrinkToFit(void* aPtr, size_t aLength) {
437     wr::Vec<uint8_t> result(std::move(mVec));
438     result.inner.length = aLength;
439     return result;
440   }
Freemozilla::layers::WROTSAlloc441   void Free(void* aPtr) {}
442 };
443 
ReadRawFont(const OpAddRawFont & aOp,wr::ShmSegmentsReader & aReader,wr::TransactionBuilder & aUpdates)444 static bool ReadRawFont(const OpAddRawFont& aOp, wr::ShmSegmentsReader& aReader,
445                         wr::TransactionBuilder& aUpdates) {
446   wr::Vec<uint8_t> sourceBytes;
447   Maybe<Range<uint8_t>> ptr =
448       aReader.GetReadPointerOrCopy(aOp.bytes(), sourceBytes);
449   if (ptr.isNothing()) {
450     return false;
451   }
452   Range<uint8_t>& source = ptr.ref();
453   // Attempt to sanitize the font before passing it along for updating.
454   // Ensure that we're not strict here about font types, since any font that
455   // failed generating a descriptor might end up here as raw font data.
456   size_t lengthHint = gfxOTSContext::GuessSanitizedFontSize(
457       source.begin().get(), source.length(), false);
458   if (!lengthHint) {
459     gfxCriticalNote << "Could not determine font type for sanitizing font "
460                     << aOp.key().mHandle;
461     return false;
462   }
463   gfxOTSExpandingMemoryStream<WROTSAlloc> output(lengthHint);
464   gfxOTSContext otsContext;
465   if (!otsContext.Process(&output, source.begin().get(), source.length())) {
466     gfxCriticalNote << "Failed sanitizing font " << aOp.key().mHandle;
467     return false;
468   }
469   wr::Vec<uint8_t> bytes = output.forget();
470 
471   aUpdates.AddRawFont(aOp.key(), bytes, aOp.fontIndex());
472   return true;
473 }
474 
UpdateResources(const nsTArray<OpUpdateResource> & aResourceUpdates,const nsTArray<RefCountedShmem> & aSmallShmems,const nsTArray<ipc::Shmem> & aLargeShmems,wr::TransactionBuilder & aUpdates)475 bool WebRenderBridgeParent::UpdateResources(
476     const nsTArray<OpUpdateResource>& aResourceUpdates,
477     const nsTArray<RefCountedShmem>& aSmallShmems,
478     const nsTArray<ipc::Shmem>& aLargeShmems,
479     wr::TransactionBuilder& aUpdates) {
480   wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems);
481   UniquePtr<ScheduleSharedSurfaceRelease> scheduleRelease;
482 
483   while (GPUParent::MaybeFlushMemory()) {
484     // If the GPU process has memory pressure, preemptively unmap some of our
485     // shared memory images. If we are in the parent process, the expiration
486     // tracker itself will listen for the memory pressure event.
487     if (!SharedSurfacesParent::AgeAndExpireOneGeneration()) {
488       break;
489     }
490   }
491 
492   for (const auto& cmd : aResourceUpdates) {
493     switch (cmd.type()) {
494       case OpUpdateResource::TOpAddImage: {
495         const auto& op = cmd.get_OpAddImage();
496         if (!MatchesNamespace(op.key())) {
497           MOZ_ASSERT_UNREACHABLE("Stale image key (add)!");
498           break;
499         }
500 
501         wr::Vec<uint8_t> bytes;
502         if (!reader.Read(op.bytes(), bytes)) {
503           gfxCriticalNote << "TOpAddImage failed";
504           return false;
505         }
506         aUpdates.AddImage(op.key(), op.descriptor(), bytes);
507         break;
508       }
509       case OpUpdateResource::TOpUpdateImage: {
510         const auto& op = cmd.get_OpUpdateImage();
511         if (!MatchesNamespace(op.key())) {
512           MOZ_ASSERT_UNREACHABLE("Stale image key (update)!");
513           break;
514         }
515 
516         wr::Vec<uint8_t> bytes;
517         if (!reader.Read(op.bytes(), bytes)) {
518           gfxCriticalNote << "TOpUpdateImage failed";
519           return false;
520         }
521         aUpdates.UpdateImageBuffer(op.key(), op.descriptor(), bytes);
522         break;
523       }
524       case OpUpdateResource::TOpAddBlobImage: {
525         const auto& op = cmd.get_OpAddBlobImage();
526         if (!MatchesNamespace(op.key())) {
527           MOZ_ASSERT_UNREACHABLE("Stale blob image key (add)!");
528           break;
529         }
530 
531         wr::Vec<uint8_t> bytes;
532         if (!reader.Read(op.bytes(), bytes)) {
533           gfxCriticalNote << "TOpAddBlobImage failed";
534           return false;
535         }
536         aUpdates.AddBlobImage(op.key(), op.descriptor(), bytes,
537                               wr::ToDeviceIntRect(op.visibleRect()));
538         break;
539       }
540       case OpUpdateResource::TOpUpdateBlobImage: {
541         const auto& op = cmd.get_OpUpdateBlobImage();
542         if (!MatchesNamespace(op.key())) {
543           MOZ_ASSERT_UNREACHABLE("Stale blob image key (update)!");
544           break;
545         }
546 
547         wr::Vec<uint8_t> bytes;
548         if (!reader.Read(op.bytes(), bytes)) {
549           gfxCriticalNote << "TOpUpdateBlobImage failed";
550           return false;
551         }
552         aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes,
553                                  wr::ToDeviceIntRect(op.visibleRect()),
554                                  wr::ToLayoutIntRect(op.dirtyRect()));
555         break;
556       }
557       case OpUpdateResource::TOpSetBlobImageVisibleArea: {
558         const auto& op = cmd.get_OpSetBlobImageVisibleArea();
559         if (!MatchesNamespace(op.key())) {
560           MOZ_ASSERT_UNREACHABLE("Stale blob image key (visible)!");
561           break;
562         }
563         aUpdates.SetBlobImageVisibleArea(op.key(),
564                                          wr::ToDeviceIntRect(op.area()));
565         break;
566       }
567       case OpUpdateResource::TOpAddPrivateExternalImage: {
568         const auto& op = cmd.get_OpAddPrivateExternalImage();
569         AddPrivateExternalImage(op.externalImageId(), op.key(), op.descriptor(),
570                                 aUpdates);
571         break;
572       }
573       case OpUpdateResource::TOpAddSharedExternalImage: {
574         const auto& op = cmd.get_OpAddSharedExternalImage();
575         // gfxCriticalNote is called on error
576         if (!AddSharedExternalImage(op.externalImageId(), op.key(), aUpdates)) {
577           return false;
578         }
579         break;
580       }
581       case OpUpdateResource::TOpPushExternalImageForTexture: {
582         const auto& op = cmd.get_OpPushExternalImageForTexture();
583         CompositableTextureHostRef texture;
584         texture = TextureHost::AsTextureHost(op.textureParent());
585         // gfxCriticalNote is called on error
586         if (!PushExternalImageForTexture(op.externalImageId(), op.key(),
587                                          texture, op.isUpdate(), aUpdates)) {
588           return false;
589         }
590         break;
591       }
592       case OpUpdateResource::TOpUpdatePrivateExternalImage: {
593         const auto& op = cmd.get_OpUpdatePrivateExternalImage();
594         UpdatePrivateExternalImage(op.externalImageId(), op.key(),
595                                    op.descriptor(), op.dirtyRect(), aUpdates);
596         break;
597       }
598       case OpUpdateResource::TOpUpdateSharedExternalImage: {
599         const auto& op = cmd.get_OpUpdateSharedExternalImage();
600         // gfxCriticalNote is called on error
601         if (!UpdateSharedExternalImage(op.externalImageId(), op.key(),
602                                        op.dirtyRect(), aUpdates,
603                                        scheduleRelease)) {
604           return false;
605         }
606         break;
607       }
608       case OpUpdateResource::TOpAddRawFont: {
609         if (!ReadRawFont(cmd.get_OpAddRawFont(), reader, aUpdates)) {
610           gfxCriticalNote << "TOpAddRawFont failed";
611           return false;
612         }
613         break;
614       }
615       case OpUpdateResource::TOpAddFontDescriptor: {
616         const auto& op = cmd.get_OpAddFontDescriptor();
617         if (!MatchesNamespace(op.key())) {
618           MOZ_ASSERT_UNREACHABLE("Stale font key (add descriptor)!");
619           break;
620         }
621 
622         wr::Vec<uint8_t> bytes;
623         if (!reader.Read(op.bytes(), bytes)) {
624           gfxCriticalNote << "TOpAddFontDescriptor failed";
625           return false;
626         }
627         aUpdates.AddFontDescriptor(op.key(), bytes, op.fontIndex());
628         break;
629       }
630       case OpUpdateResource::TOpAddFontInstance: {
631         const auto& op = cmd.get_OpAddFontInstance();
632         if (!MatchesNamespace(op.instanceKey()) ||
633             !MatchesNamespace(op.fontKey())) {
634           MOZ_ASSERT_UNREACHABLE("Stale font key (add instance)!");
635           break;
636         }
637 
638         wr::Vec<uint8_t> variations;
639         if (!reader.Read(op.variations(), variations)) {
640           gfxCriticalNote << "TOpAddFontInstance failed";
641           return false;
642         }
643         aUpdates.AddFontInstance(op.instanceKey(), op.fontKey(), op.glyphSize(),
644                                  op.options().ptrOr(nullptr),
645                                  op.platformOptions().ptrOr(nullptr),
646                                  variations);
647         break;
648       }
649       case OpUpdateResource::TOpDeleteImage: {
650         const auto& op = cmd.get_OpDeleteImage();
651         if (!MatchesNamespace(op.key())) {
652           // TODO(aosmond): We should also assert here, but the callers are less
653           // careful about checking when cleaning up their old keys. We should
654           // perform an audit on image key usage.
655           break;
656         }
657 
658         DeleteImage(op.key(), aUpdates);
659         break;
660       }
661       case OpUpdateResource::TOpDeleteBlobImage: {
662         const auto& op = cmd.get_OpDeleteBlobImage();
663         if (!MatchesNamespace(op.key())) {
664           MOZ_ASSERT_UNREACHABLE("Stale blob image key (delete)!");
665           break;
666         }
667 
668         aUpdates.DeleteBlobImage(op.key());
669         break;
670       }
671       case OpUpdateResource::TOpDeleteFont: {
672         const auto& op = cmd.get_OpDeleteFont();
673         if (!MatchesNamespace(op.key())) {
674           MOZ_ASSERT_UNREACHABLE("Stale font key (delete)!");
675           break;
676         }
677 
678         aUpdates.DeleteFont(op.key());
679         break;
680       }
681       case OpUpdateResource::TOpDeleteFontInstance: {
682         const auto& op = cmd.get_OpDeleteFontInstance();
683         if (!MatchesNamespace(op.key())) {
684           MOZ_ASSERT_UNREACHABLE("Stale font instance key (delete)!");
685           break;
686         }
687 
688         aUpdates.DeleteFontInstance(op.key());
689         break;
690       }
691       case OpUpdateResource::T__None:
692         break;
693     }
694   }
695 
696   if (scheduleRelease) {
697     // When software WR is enabled, shared surfaces are read during rendering
698     // rather than copied to the texture cache.
699     wr::Checkpoint when = mApi->GetBackendType() == WebRenderBackend::SOFTWARE
700                               ? wr::Checkpoint::FrameRendered
701                               : wr::Checkpoint::FrameTexturesUpdated;
702     aUpdates.Notify(when, std::move(scheduleRelease));
703   }
704   return true;
705 }
706 
AddPrivateExternalImage(wr::ExternalImageId aExtId,wr::ImageKey aKey,wr::ImageDescriptor aDesc,wr::TransactionBuilder & aResources)707 void WebRenderBridgeParent::AddPrivateExternalImage(
708     wr::ExternalImageId aExtId, wr::ImageKey aKey, wr::ImageDescriptor aDesc,
709     wr::TransactionBuilder& aResources) {
710   if (!MatchesNamespace(aKey)) {
711     MOZ_ASSERT_UNREACHABLE("Stale private external image key (add)!");
712     return;
713   }
714 
715   aResources.AddExternalImage(aKey, aDesc, aExtId,
716                               wr::ExternalImageType::Buffer(), 0);
717 }
718 
UpdatePrivateExternalImage(wr::ExternalImageId aExtId,wr::ImageKey aKey,const wr::ImageDescriptor & aDesc,const ImageIntRect & aDirtyRect,wr::TransactionBuilder & aResources)719 void WebRenderBridgeParent::UpdatePrivateExternalImage(
720     wr::ExternalImageId aExtId, wr::ImageKey aKey,
721     const wr::ImageDescriptor& aDesc, const ImageIntRect& aDirtyRect,
722     wr::TransactionBuilder& aResources) {
723   if (!MatchesNamespace(aKey)) {
724     MOZ_ASSERT_UNREACHABLE("Stale private external image key (update)!");
725     return;
726   }
727 
728   aResources.UpdateExternalImageWithDirtyRect(
729       aKey, aDesc, aExtId, wr::ExternalImageType::Buffer(),
730       wr::ToDeviceIntRect(aDirtyRect), 0);
731 }
732 
AddSharedExternalImage(wr::ExternalImageId aExtId,wr::ImageKey aKey,wr::TransactionBuilder & aResources)733 bool WebRenderBridgeParent::AddSharedExternalImage(
734     wr::ExternalImageId aExtId, wr::ImageKey aKey,
735     wr::TransactionBuilder& aResources) {
736   if (!MatchesNamespace(aKey)) {
737     MOZ_ASSERT_UNREACHABLE("Stale shared external image key (add)!");
738     return true;
739   }
740 
741   auto key = wr::AsUint64(aKey);
742   auto it = mSharedSurfaceIds.find(key);
743   if (it != mSharedSurfaceIds.end()) {
744     gfxCriticalNote << "Readding known shared surface: " << key;
745     return false;
746   }
747 
748   RefPtr<DataSourceSurface> dSurf = SharedSurfacesParent::Acquire(aExtId);
749   if (!dSurf) {
750     gfxCriticalNote
751         << "DataSourceSurface of SharedSurfaces does not exist for extId:"
752         << wr::AsUint64(aExtId);
753     return false;
754   }
755 
756   mSharedSurfaceIds.insert(std::make_pair(key, aExtId));
757 
758   // Prefer raw buffers, unless our backend requires native textures.
759   IntSize surfaceSize = dSurf->GetSize();
760   TextureHost::NativeTexturePolicy policy =
761       TextureHost::BackendNativeTexturePolicy(mApi->GetBackendType(),
762                                               surfaceSize);
763   auto imageType =
764       policy == TextureHost::NativeTexturePolicy::REQUIRE
765           ? wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::Texture2D)
766           : wr::ExternalImageType::Buffer();
767   wr::ImageDescriptor descriptor(surfaceSize, dSurf->Stride(),
768                                  dSurf->GetFormat());
769   aResources.AddExternalImage(aKey, descriptor, aExtId, imageType, 0);
770   return true;
771 }
772 
PushExternalImageForTexture(wr::ExternalImageId aExtId,wr::ImageKey aKey,TextureHost * aTexture,bool aIsUpdate,wr::TransactionBuilder & aResources)773 bool WebRenderBridgeParent::PushExternalImageForTexture(
774     wr::ExternalImageId aExtId, wr::ImageKey aKey, TextureHost* aTexture,
775     bool aIsUpdate, wr::TransactionBuilder& aResources) {
776   if (!MatchesNamespace(aKey)) {
777     MOZ_ASSERT_UNREACHABLE("Stale texture external image key!");
778     return true;
779   }
780 
781   if (!aTexture) {
782     gfxCriticalNote << "TextureHost does not exist for extId:"
783                     << wr::AsUint64(aExtId);
784     return false;
785   }
786 
787   auto op = aIsUpdate ? TextureHost::UPDATE_IMAGE : TextureHost::ADD_IMAGE;
788   WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
789   if (wrTexture) {
790     Range<wr::ImageKey> keys(&aKey, 1);
791     wrTexture->PushResourceUpdates(aResources, op, keys,
792                                    wrTexture->GetExternalImageKey());
793     auto it = mTextureHosts.find(wr::AsUint64(aKey));
794     MOZ_ASSERT((it == mTextureHosts.end() && !aIsUpdate) ||
795                (it != mTextureHosts.end() && aIsUpdate));
796     if (it != mTextureHosts.end()) {
797       // Release Texture if it exists.
798       ReleaseTextureOfImage(aKey);
799     }
800     mTextureHosts.emplace(wr::AsUint64(aKey),
801                           CompositableTextureHostRef(aTexture));
802     return true;
803   }
804 
805   RefPtr<DataSourceSurface> dSurf = aTexture->GetAsSurface();
806   if (!dSurf) {
807     gfxCriticalNote
808         << "TextureHost does not return DataSourceSurface for extId:"
809         << wr::AsUint64(aExtId);
810     return false;
811   }
812 
813   DataSourceSurface::MappedSurface map;
814   if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
815     gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:"
816                     << wr::AsUint64(aExtId);
817     return false;
818   }
819 
820   IntSize size = dSurf->GetSize();
821   wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
822   wr::Vec<uint8_t> data;
823   data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
824 
825   if (op == TextureHost::UPDATE_IMAGE) {
826     aResources.UpdateImageBuffer(aKey, descriptor, data);
827   } else {
828     aResources.AddImage(aKey, descriptor, data);
829   }
830 
831   dSurf->Unmap();
832 
833   return true;
834 }
835 
UpdateSharedExternalImage(wr::ExternalImageId aExtId,wr::ImageKey aKey,const ImageIntRect & aDirtyRect,wr::TransactionBuilder & aResources,UniquePtr<ScheduleSharedSurfaceRelease> & aScheduleRelease)836 bool WebRenderBridgeParent::UpdateSharedExternalImage(
837     wr::ExternalImageId aExtId, wr::ImageKey aKey,
838     const ImageIntRect& aDirtyRect, wr::TransactionBuilder& aResources,
839     UniquePtr<ScheduleSharedSurfaceRelease>& aScheduleRelease) {
840   if (!MatchesNamespace(aKey)) {
841     MOZ_ASSERT_UNREACHABLE("Stale shared external image key (update)!");
842     return true;
843   }
844 
845   auto key = wr::AsUint64(aKey);
846   auto it = mSharedSurfaceIds.find(key);
847   if (it == mSharedSurfaceIds.end()) {
848     gfxCriticalNote << "Updating unknown shared surface: " << key;
849     return false;
850   }
851 
852   RefPtr<DataSourceSurface> dSurf;
853   if (it->second == aExtId) {
854     dSurf = SharedSurfacesParent::Get(aExtId);
855   } else {
856     dSurf = SharedSurfacesParent::Acquire(aExtId);
857   }
858 
859   if (!dSurf) {
860     gfxCriticalNote << "Shared surface does not exist for extId:"
861                     << wr::AsUint64(aExtId);
862     return false;
863   }
864 
865   if (!(it->second == aExtId)) {
866     // We already have a mapping for this image key, so ensure we release the
867     // previous external image ID. This can happen when an image is animated,
868     // and it is changing the external image that the animation points to.
869     if (!aScheduleRelease) {
870       aScheduleRelease = MakeUnique<ScheduleSharedSurfaceRelease>(this);
871     }
872     aScheduleRelease->Add(aKey, it->second);
873     it->second = aExtId;
874   }
875 
876   // Prefer raw buffers, unless our backend requires native textures.
877   IntSize surfaceSize = dSurf->GetSize();
878   TextureHost::NativeTexturePolicy policy =
879       TextureHost::BackendNativeTexturePolicy(mApi->GetBackendType(),
880                                               surfaceSize);
881   auto imageType =
882       policy == TextureHost::NativeTexturePolicy::REQUIRE
883           ? wr::ExternalImageType::TextureHandle(wr::ImageBufferKind::Texture2D)
884           : wr::ExternalImageType::Buffer();
885   wr::ImageDescriptor descriptor(surfaceSize, dSurf->Stride(),
886                                  dSurf->GetFormat());
887   aResources.UpdateExternalImageWithDirtyRect(
888       aKey, descriptor, aExtId, imageType, wr::ToDeviceIntRect(aDirtyRect), 0);
889 
890   return true;
891 }
892 
ObserveSharedSurfaceRelease(const nsTArray<wr::ExternalImageKeyPair> & aPairs)893 void WebRenderBridgeParent::ObserveSharedSurfaceRelease(
894     const nsTArray<wr::ExternalImageKeyPair>& aPairs) {
895   if (!mDestroyed) {
896     Unused << SendWrReleasedImages(aPairs);
897   }
898   for (const auto& pair : aPairs) {
899     SharedSurfacesParent::Release(pair.id);
900   }
901 }
902 
RecvUpdateResources(const wr::IdNamespace & aIdNamespace,nsTArray<OpUpdateResource> && aResourceUpdates,nsTArray<RefCountedShmem> && aSmallShmems,nsTArray<ipc::Shmem> && aLargeShmems)903 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvUpdateResources(
904     const wr::IdNamespace& aIdNamespace,
905     nsTArray<OpUpdateResource>&& aResourceUpdates,
906     nsTArray<RefCountedShmem>&& aSmallShmems,
907     nsTArray<ipc::Shmem>&& aLargeShmems) {
908   if (mDestroyed || aIdNamespace != mIdNamespace) {
909     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
910     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
911     return IPC_OK();
912   }
913 
914   wr::TransactionBuilder txn(mApi);
915   txn.SetLowPriority(!IsRootWebRenderBridgeParent());
916 
917   Unused << GetNextWrEpoch();
918 
919   bool success =
920       UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn);
921   wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
922   wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
923 
924   // Even when txn.IsResourceUpdatesEmpty() is true, there could be resource
925   // updates. It is handled by WebRenderTextureHostWrapper. In this case
926   // txn.IsRenderedFrameInvalidated() becomes true.
927   if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) {
928     // There are resource updates, then we update Epoch of transaction.
929     txn.UpdateEpoch(mPipelineId, mWrEpoch);
930     mAsyncImageManager->SetWillGenerateFrame();
931     ScheduleGenerateFrame();
932   } else {
933     // If TransactionBuilder does not have resource updates nor display list,
934     // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no
935     // need to update WrEpoch.
936     // Then we want to rollback WrEpoch. See Bug 1490117.
937     RollbackWrEpoch();
938   }
939 
940   if (!success) {
941     return IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
942   }
943 
944   mApi->SendTransaction(txn);
945 
946   return IPC_OK();
947 }
948 
RecvDeleteCompositorAnimations(nsTArray<uint64_t> && aIds)949 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvDeleteCompositorAnimations(
950     nsTArray<uint64_t>&& aIds) {
951   if (mDestroyed) {
952     return IPC_OK();
953   }
954 
955   // Once mWrEpoch has been rendered, we can delete these compositor animations
956   mCompositorAnimationsToDelete.push(
957       CompositorAnimationIdsForEpoch(mWrEpoch, std::move(aIds)));
958   return IPC_OK();
959 }
960 
RemoveEpochDataPriorTo(const wr::Epoch & aRenderedEpoch)961 void WebRenderBridgeParent::RemoveEpochDataPriorTo(
962     const wr::Epoch& aRenderedEpoch) {
963   if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
964     sampler->RemoveEpochDataPriorTo(mCompositorAnimationsToDelete,
965                                     mActiveAnimations, aRenderedEpoch);
966   }
967 }
968 
IsRootWebRenderBridgeParent() const969 bool WebRenderBridgeParent::IsRootWebRenderBridgeParent() const {
970   return !!mWidget;
971 }
972 
BeginRecording(const TimeStamp & aRecordingStart)973 void WebRenderBridgeParent::BeginRecording(const TimeStamp& aRecordingStart) {
974   mApi->BeginRecording(aRecordingStart, mPipelineId);
975 }
976 
977 RefPtr<wr::WebRenderAPI::WriteCollectedFramesPromise>
WriteCollectedFrames()978 WebRenderBridgeParent::WriteCollectedFrames() {
979   return mApi->WriteCollectedFrames();
980 }
981 
982 RefPtr<wr::WebRenderAPI::GetCollectedFramesPromise>
GetCollectedFrames()983 WebRenderBridgeParent::GetCollectedFrames() {
984   return mApi->GetCollectedFrames();
985 }
986 
AddPendingScrollPayload(CompositionPayload & aPayload,const VsyncId & aCompositeStartId)987 void WebRenderBridgeParent::AddPendingScrollPayload(
988     CompositionPayload& aPayload, const VsyncId& aCompositeStartId) {
989   auto pendingScrollPayloads = mPendingScrollPayloads.Lock();
990   nsTArray<CompositionPayload>* payloads =
991       pendingScrollPayloads->GetOrInsertNew(aCompositeStartId.mId);
992 
993   payloads->AppendElement(aPayload);
994 }
995 
TakePendingScrollPayload(const VsyncId & aCompositeStartId)996 nsTArray<CompositionPayload> WebRenderBridgeParent::TakePendingScrollPayload(
997     const VsyncId& aCompositeStartId) {
998   auto pendingScrollPayloads = mPendingScrollPayloads.Lock();
999   nsTArray<CompositionPayload> payload;
1000   if (nsTArray<CompositionPayload>* storedPayload =
1001           pendingScrollPayloads->Get(aCompositeStartId.mId)) {
1002     payload.AppendElements(std::move(*storedPayload));
1003     pendingScrollPayloads->Remove(aCompositeStartId.mId);
1004   }
1005   return payload;
1006 }
1007 
GetRootCompositorBridgeParent() const1008 CompositorBridgeParent* WebRenderBridgeParent::GetRootCompositorBridgeParent()
1009     const {
1010   if (!mCompositorBridge) {
1011     return nullptr;
1012   }
1013 
1014   if (IsRootWebRenderBridgeParent()) {
1015     // This WebRenderBridgeParent is attached to the root
1016     // CompositorBridgeParent.
1017     return static_cast<CompositorBridgeParent*>(mCompositorBridge);
1018   }
1019 
1020   // Otherwise, this WebRenderBridgeParent is attached to a
1021   // ContentCompositorBridgeParent so we have an extra level of
1022   // indirection to unravel.
1023   CompositorBridgeParent::LayerTreeState* lts =
1024       CompositorBridgeParent::GetIndirectShadowTree(GetLayersId());
1025   if (!lts) {
1026     return nullptr;
1027   }
1028   return lts->mParent;
1029 }
1030 
1031 RefPtr<WebRenderBridgeParent>
GetRootWebRenderBridgeParent() const1032 WebRenderBridgeParent::GetRootWebRenderBridgeParent() const {
1033   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1034   if (!cbp) {
1035     return nullptr;
1036   }
1037 
1038   return cbp->GetWebRenderBridgeParent();
1039 }
1040 
UpdateAPZFocusState(const FocusTarget & aFocus)1041 void WebRenderBridgeParent::UpdateAPZFocusState(const FocusTarget& aFocus) {
1042   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1043   if (!cbp) {
1044     return;
1045   }
1046   LayersId rootLayersId = cbp->RootLayerTreeId();
1047   if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
1048     apz->UpdateFocusState(rootLayersId, GetLayersId(), aFocus);
1049   }
1050 }
1051 
UpdateAPZScrollData(const wr::Epoch & aEpoch,WebRenderScrollData && aData)1052 void WebRenderBridgeParent::UpdateAPZScrollData(const wr::Epoch& aEpoch,
1053                                                 WebRenderScrollData&& aData) {
1054   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1055   if (!cbp) {
1056     return;
1057   }
1058   LayersId rootLayersId = cbp->RootLayerTreeId();
1059   if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
1060     apz->UpdateScrollDataAndTreeState(rootLayersId, GetLayersId(), aEpoch,
1061                                       std::move(aData));
1062   }
1063 }
1064 
UpdateAPZScrollOffsets(ScrollUpdatesMap && aUpdates,uint32_t aPaintSequenceNumber)1065 void WebRenderBridgeParent::UpdateAPZScrollOffsets(
1066     ScrollUpdatesMap&& aUpdates, uint32_t aPaintSequenceNumber) {
1067   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1068   if (!cbp) {
1069     return;
1070   }
1071   LayersId rootLayersId = cbp->RootLayerTreeId();
1072   if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
1073     apz->UpdateScrollOffsets(rootLayersId, GetLayersId(), std::move(aUpdates),
1074                              aPaintSequenceNumber);
1075   }
1076 }
1077 
SetAPZSampleTime()1078 void WebRenderBridgeParent::SetAPZSampleTime() {
1079   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1080   if (!cbp) {
1081     return;
1082   }
1083   if (RefPtr<APZSampler> apz = cbp->GetAPZSampler()) {
1084     SampleTime animationTime;
1085     if (Maybe<TimeStamp> testTime = cbp->GetTestingTimeStamp()) {
1086       animationTime = SampleTime::FromTest(*testTime);
1087     } else {
1088       animationTime = mCompositorScheduler->GetLastComposeTime();
1089     }
1090     TimeDuration frameInterval = cbp->GetVsyncInterval();
1091     // As with the non-webrender codepath in AsyncCompositionManager, we want to
1092     // use the timestamp for the next vsync when advancing animations.
1093     if (frameInterval != TimeDuration::Forever()) {
1094       animationTime = animationTime + frameInterval;
1095     }
1096     apz->SetSampleTime(animationTime);
1097   }
1098 }
1099 
SetDisplayList(const LayoutDeviceRect & aRect,ipc::ByteBuf && aDL,const wr::BuiltDisplayListDescriptor & aDLDesc,const nsTArray<OpUpdateResource> & aResourceUpdates,const nsTArray<RefCountedShmem> & aSmallShmems,const nsTArray<ipc::Shmem> & aLargeShmems,const TimeStamp & aTxnStartTime,wr::TransactionBuilder & aTxn,wr::Epoch aWrEpoch,bool aObserveLayersUpdate)1100 bool WebRenderBridgeParent::SetDisplayList(
1101     const LayoutDeviceRect& aRect, ipc::ByteBuf&& aDL,
1102     const wr::BuiltDisplayListDescriptor& aDLDesc,
1103     const nsTArray<OpUpdateResource>& aResourceUpdates,
1104     const nsTArray<RefCountedShmem>& aSmallShmems,
1105     const nsTArray<ipc::Shmem>& aLargeShmems, const TimeStamp& aTxnStartTime,
1106     wr::TransactionBuilder& aTxn, wr::Epoch aWrEpoch,
1107     bool aObserveLayersUpdate) {
1108   if (NS_WARN_IF(!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems,
1109                                   aTxn))) {
1110     return false;
1111   }
1112 
1113   wr::Vec<uint8_t> dlData(std::move(aDL));
1114 
1115   if (IsRootWebRenderBridgeParent()) {
1116     LayoutDeviceIntSize widgetSize = mWidget->GetClientSize();
1117     LayoutDeviceIntRect rect =
1118         LayoutDeviceIntRect(LayoutDeviceIntPoint(), widgetSize);
1119     aTxn.SetDocumentView(rect);
1120   }
1121   gfx::DeviceColor clearColor(0.f, 0.f, 0.f, 0.f);
1122   aTxn.SetDisplayList(clearColor, aWrEpoch,
1123                       wr::ToLayoutSize(RoundedToInt(aRect).Size()), mPipelineId,
1124                       aDLDesc, dlData);
1125 
1126   if (aObserveLayersUpdate) {
1127     aTxn.Notify(
1128         wr::Checkpoint::SceneBuilt,
1129         MakeUnique<ScheduleObserveLayersUpdate>(
1130             mCompositorBridge, GetLayersId(), mChildLayersObserverEpoch, true));
1131   }
1132 
1133   if (!IsRootWebRenderBridgeParent()) {
1134     aTxn.Notify(wr::Checkpoint::SceneBuilt, MakeUnique<SceneBuiltNotification>(
1135                                                 this, aWrEpoch, aTxnStartTime));
1136   }
1137 
1138   mApi->SendTransaction(aTxn);
1139 
1140   // We will schedule generating a frame after the scene
1141   // build is done, so we don't need to do it here.
1142   return true;
1143 }
1144 
ProcessDisplayListData(DisplayListData & aDisplayList,wr::Epoch aWrEpoch,const TimeStamp & aTxnStartTime,bool aValidTransaction,bool aObserveLayersUpdate)1145 bool WebRenderBridgeParent::ProcessDisplayListData(
1146     DisplayListData& aDisplayList, wr::Epoch aWrEpoch,
1147     const TimeStamp& aTxnStartTime, bool aValidTransaction,
1148     bool aObserveLayersUpdate) {
1149   wr::TransactionBuilder txn(mApi);
1150   Maybe<wr::AutoTransactionSender> sender;
1151 
1152   // Note that this needs to happen before the display list transaction is
1153   // sent to WebRender, so that the UpdateHitTestingTree call is guaranteed to
1154   // be in the updater queue at the time that the scene swap completes.
1155   if (aDisplayList.mScrollData) {
1156     UpdateAPZScrollData(aWrEpoch, std::move(aDisplayList.mScrollData.ref()));
1157   }
1158 
1159   txn.SetLowPriority(!IsRootWebRenderBridgeParent());
1160   if (aValidTransaction) {
1161     MOZ_ASSERT(aDisplayList.mIdNamespace == mIdNamespace);
1162     sender.emplace(mApi, &txn);
1163   }
1164 
1165   if (NS_WARN_IF(
1166           !ProcessWebRenderParentCommands(aDisplayList.mCommands, txn))) {
1167     return false;
1168   }
1169 
1170   if (aDisplayList.mDL && aValidTransaction &&
1171       !SetDisplayList(aDisplayList.mRect, std::move(aDisplayList.mDL.ref()),
1172                       aDisplayList.mDLDesc, aDisplayList.mResourceUpdates,
1173                       aDisplayList.mSmallShmems, aDisplayList.mLargeShmems,
1174                       aTxnStartTime, txn, aWrEpoch, aObserveLayersUpdate)) {
1175     return false;
1176   }
1177   return true;
1178 }
1179 
RecvSetDisplayList(DisplayListData && aDisplayList,nsTArray<OpDestroy> && aToDestroy,const uint64_t & aFwdTransactionId,const TransactionId & aTransactionId,const bool & aContainsSVGGroup,const VsyncId & aVsyncId,const TimeStamp & aVsyncStartTime,const TimeStamp & aRefreshStartTime,const TimeStamp & aTxnStartTime,const nsCString & aTxnURL,const TimeStamp & aFwdTime,nsTArray<CompositionPayload> && aPayloads)1180 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList(
1181     DisplayListData&& aDisplayList, nsTArray<OpDestroy>&& aToDestroy,
1182     const uint64_t& aFwdTransactionId, const TransactionId& aTransactionId,
1183     const bool& aContainsSVGGroup, const VsyncId& aVsyncId,
1184     const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
1185     const TimeStamp& aTxnStartTime, const nsCString& aTxnURL,
1186     const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads) {
1187   if (mDestroyed) {
1188     for (const auto& op : aToDestroy) {
1189       DestroyActor(op);
1190     }
1191     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems);
1192     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems);
1193     return IPC_OK();
1194   }
1195 
1196   if (!IsRootWebRenderBridgeParent()) {
1197     CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aTxnURL);
1198   }
1199 
1200   AUTO_PROFILER_TRACING_MARKER("Paint", "SetDisplayList", GRAPHICS);
1201   UpdateFwdTransactionId(aFwdTransactionId);
1202 
1203   // This ensures that destroy operations are always processed. It is not safe
1204   // to early-return from RecvDPEnd without doing so.
1205   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(
1206       this, &aToDestroy);
1207 
1208   wr::Epoch wrEpoch = GetNextWrEpoch();
1209 
1210   mReceivedDisplayList = true;
1211 
1212   if (aDisplayList.mScrollData && aDisplayList.mScrollData->IsFirstPaint()) {
1213     mIsFirstPaint = true;
1214   }
1215 
1216   bool validTransaction = aDisplayList.mIdNamespace == mIdNamespace;
1217   bool observeLayersUpdate = ShouldParentObserveEpoch();
1218 
1219   if (!ProcessDisplayListData(aDisplayList, wrEpoch, aTxnStartTime,
1220                               validTransaction, observeLayersUpdate)) {
1221     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems);
1222     wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems);
1223     return IPC_FAIL(this, "Failed to process DisplayListData.");
1224   }
1225 
1226   if (!validTransaction && observeLayersUpdate) {
1227     mCompositorBridge->ObserveLayersUpdate(GetLayersId(),
1228                                            mChildLayersObserverEpoch, true);
1229   }
1230 
1231   if (!IsRootWebRenderBridgeParent()) {
1232     aPayloads.AppendElement(
1233         CompositionPayload{CompositionPayloadType::eContentPaint, aFwdTime});
1234   }
1235 
1236   HoldPendingTransactionId(wrEpoch, aTransactionId, aContainsSVGGroup, aVsyncId,
1237                            aVsyncStartTime, aRefreshStartTime, aTxnStartTime,
1238                            aTxnURL, aFwdTime, mIsFirstPaint,
1239                            std::move(aPayloads));
1240   mIsFirstPaint = false;
1241 
1242   if (!validTransaction) {
1243     // Pretend we composited since someone is wating for this event,
1244     // though DisplayList was not pushed to webrender.
1245     if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
1246       TimeStamp now = TimeStamp::Now();
1247       cbp->NotifyPipelineRendered(mPipelineId, wrEpoch, VsyncId(), now, now,
1248                                   now);
1249     }
1250   }
1251 
1252   wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mSmallShmems);
1253   wr::IpcResourceUpdateQueue::ReleaseShmems(this, aDisplayList.mLargeShmems);
1254 
1255   return IPC_OK();
1256 }
1257 
ProcessEmptyTransactionUpdates(TransactionData & aData,bool * aScheduleComposite)1258 bool WebRenderBridgeParent::ProcessEmptyTransactionUpdates(
1259     TransactionData& aData, bool* aScheduleComposite) {
1260   *aScheduleComposite = false;
1261   wr::TransactionBuilder txn(mApi);
1262   txn.SetLowPriority(!IsRootWebRenderBridgeParent());
1263 
1264   if (!aData.mScrollUpdates.IsEmpty()) {
1265     UpdateAPZScrollOffsets(std::move(aData.mScrollUpdates),
1266                            aData.mPaintSequenceNumber);
1267   }
1268 
1269   // Update WrEpoch for UpdateResources() and ProcessWebRenderParentCommands().
1270   // WrEpoch is used to manage ExternalImages lifetimes in
1271   // AsyncImagePipelineManager.
1272   Unused << GetNextWrEpoch();
1273 
1274   if (aData.mIdNamespace == mIdNamespace &&
1275       !UpdateResources(aData.mResourceUpdates, aData.mSmallShmems,
1276                        aData.mLargeShmems, txn)) {
1277     return false;
1278   }
1279 
1280   if (!aData.mCommands.IsEmpty()) {
1281     if (!ProcessWebRenderParentCommands(aData.mCommands, txn)) {
1282       return false;
1283     }
1284   }
1285 
1286   if (ShouldParentObserveEpoch()) {
1287     txn.Notify(
1288         wr::Checkpoint::SceneBuilt,
1289         MakeUnique<ScheduleObserveLayersUpdate>(
1290             mCompositorBridge, GetLayersId(), mChildLayersObserverEpoch, true));
1291   }
1292 
1293   // Even when txn.IsResourceUpdatesEmpty() is true, there could be resource
1294   // updates. It is handled by WebRenderTextureHostWrapper. In this case
1295   // txn.IsRenderedFrameInvalidated() becomes true.
1296   if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) {
1297     // There are resource updates, then we update Epoch of transaction.
1298     txn.UpdateEpoch(mPipelineId, mWrEpoch);
1299     *aScheduleComposite = true;
1300   } else {
1301     // If TransactionBuilder does not have resource updates nor display list,
1302     // ScheduleGenerateFrame is not triggered via SceneBuilder and there is no
1303     // need to update WrEpoch.
1304     // Then we want to rollback WrEpoch. See Bug 1490117.
1305     RollbackWrEpoch();
1306   }
1307 
1308   if (!txn.IsEmpty()) {
1309     mApi->SendTransaction(txn);
1310   }
1311 
1312   if (*aScheduleComposite) {
1313     mAsyncImageManager->SetWillGenerateFrame();
1314   }
1315 
1316   return true;
1317 }
1318 
RecvEmptyTransaction(const FocusTarget & aFocusTarget,Maybe<TransactionData> && aTransactionData,nsTArray<OpDestroy> && aToDestroy,const uint64_t & aFwdTransactionId,const TransactionId & aTransactionId,const VsyncId & aVsyncId,const TimeStamp & aVsyncStartTime,const TimeStamp & aRefreshStartTime,const TimeStamp & aTxnStartTime,const nsCString & aTxnURL,const TimeStamp & aFwdTime,nsTArray<CompositionPayload> && aPayloads)1319 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction(
1320     const FocusTarget& aFocusTarget, Maybe<TransactionData>&& aTransactionData,
1321     nsTArray<OpDestroy>&& aToDestroy, const uint64_t& aFwdTransactionId,
1322     const TransactionId& aTransactionId, const VsyncId& aVsyncId,
1323     const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
1324     const TimeStamp& aTxnStartTime, const nsCString& aTxnURL,
1325     const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads) {
1326   if (mDestroyed) {
1327     for (const auto& op : aToDestroy) {
1328       DestroyActor(op);
1329     }
1330     if (aTransactionData) {
1331       wr::IpcResourceUpdateQueue::ReleaseShmems(this,
1332                                                 aTransactionData->mSmallShmems);
1333       wr::IpcResourceUpdateQueue::ReleaseShmems(this,
1334                                                 aTransactionData->mLargeShmems);
1335     }
1336     return IPC_OK();
1337   }
1338 
1339   if (!IsRootWebRenderBridgeParent()) {
1340     CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aTxnURL);
1341   }
1342 
1343   AUTO_PROFILER_TRACING_MARKER("Paint", "EmptyTransaction", GRAPHICS);
1344   UpdateFwdTransactionId(aFwdTransactionId);
1345 
1346   // This ensures that destroy operations are always processed. It is not safe
1347   // to early-return without doing so.
1348   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(
1349       this, &aToDestroy);
1350 
1351   UpdateAPZFocusState(aFocusTarget);
1352 
1353   bool scheduleAnyComposite = false;
1354 
1355   if (aTransactionData) {
1356     bool scheduleComposite = false;
1357     if (!ProcessEmptyTransactionUpdates(*aTransactionData,
1358                                         &scheduleComposite)) {
1359       wr::IpcResourceUpdateQueue::ReleaseShmems(this,
1360                                                 aTransactionData->mSmallShmems);
1361       wr::IpcResourceUpdateQueue::ReleaseShmems(this,
1362                                                 aTransactionData->mLargeShmems);
1363       return IPC_FAIL(this, "Failed to process empty transaction update.");
1364     }
1365     scheduleAnyComposite = scheduleAnyComposite || scheduleComposite;
1366   }
1367 
1368   // If we are going to kick off a new composite as a result of this
1369   // transaction, or if there are already composite-triggering pending
1370   // transactions inflight, then set sendDidComposite to false because we will
1371   // send the DidComposite message after the composite occurs.
1372   // If there are no pending transactions and we're not going to do a
1373   // composite, then we leave sendDidComposite as true so we just send
1374   // the DidComposite notification now.
1375   bool sendDidComposite =
1376       !scheduleAnyComposite && mPendingTransactionIds.empty();
1377 
1378   // Only register a value for CONTENT_FRAME_TIME telemetry if we actually drew
1379   // something. It is for consistency with disabling WebRender.
1380   HoldPendingTransactionId(mWrEpoch, aTransactionId, false, aVsyncId,
1381                            aVsyncStartTime, aRefreshStartTime, aTxnStartTime,
1382                            aTxnURL, aFwdTime,
1383                            /* aIsFirstPaint */ false, std::move(aPayloads),
1384                            /* aUseForTelemetry */ scheduleAnyComposite);
1385 
1386   if (scheduleAnyComposite) {
1387     ScheduleGenerateFrame();
1388   } else if (sendDidComposite) {
1389     // The only thing in the pending transaction id queue should be the entry
1390     // we just added, and now we're going to pretend we rendered it
1391     MOZ_ASSERT(mPendingTransactionIds.size() == 1);
1392     if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
1393       TimeStamp now = TimeStamp::Now();
1394       cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now,
1395                                   now);
1396     }
1397   }
1398 
1399   if (aTransactionData) {
1400     wr::IpcResourceUpdateQueue::ReleaseShmems(this,
1401                                               aTransactionData->mSmallShmems);
1402     wr::IpcResourceUpdateQueue::ReleaseShmems(this,
1403                                               aTransactionData->mLargeShmems);
1404   }
1405   return IPC_OK();
1406 }
1407 
RecvSetFocusTarget(const FocusTarget & aFocusTarget)1408 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetFocusTarget(
1409     const FocusTarget& aFocusTarget) {
1410   UpdateAPZFocusState(aFocusTarget);
1411   return IPC_OK();
1412 }
1413 
RecvParentCommands(nsTArray<WebRenderParentCommand> && aCommands)1414 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvParentCommands(
1415     nsTArray<WebRenderParentCommand>&& aCommands) {
1416   if (mDestroyed) {
1417     return IPC_OK();
1418   }
1419 
1420   wr::TransactionBuilder txn(mApi);
1421   txn.SetLowPriority(!IsRootWebRenderBridgeParent());
1422   if (!ProcessWebRenderParentCommands(aCommands, txn)) {
1423     return IPC_FAIL(this, "Invalid parent command found");
1424   }
1425 
1426   mApi->SendTransaction(txn);
1427   return IPC_OK();
1428 }
1429 
ProcessWebRenderParentCommands(const nsTArray<WebRenderParentCommand> & aCommands,wr::TransactionBuilder & aTxn)1430 bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
1431     const nsTArray<WebRenderParentCommand>& aCommands,
1432     wr::TransactionBuilder& aTxn) {
1433   // Transaction for async image pipeline that uses ImageBridge always need to
1434   // be non low priority.
1435   wr::TransactionBuilder txnForImageBridge(mApi);
1436   wr::AutoTransactionSender sender(mApi, &txnForImageBridge);
1437 
1438   for (nsTArray<WebRenderParentCommand>::index_type i = 0;
1439        i < aCommands.Length(); ++i) {
1440     const WebRenderParentCommand& cmd = aCommands[i];
1441     switch (cmd.type()) {
1442       case WebRenderParentCommand::TOpAddPipelineIdForCompositable: {
1443         const OpAddPipelineIdForCompositable& op =
1444             cmd.get_OpAddPipelineIdForCompositable();
1445         AddPipelineIdForCompositable(op.pipelineId(), op.handle(), op.isAsync(),
1446                                      aTxn, txnForImageBridge);
1447         break;
1448       }
1449       case WebRenderParentCommand::TOpRemovePipelineIdForCompositable: {
1450         const OpRemovePipelineIdForCompositable& op =
1451             cmd.get_OpRemovePipelineIdForCompositable();
1452         RemovePipelineIdForCompositable(op.pipelineId(), aTxn);
1453         break;
1454       }
1455       case WebRenderParentCommand::TOpReleaseTextureOfImage: {
1456         const OpReleaseTextureOfImage& op = cmd.get_OpReleaseTextureOfImage();
1457         ReleaseTextureOfImage(op.key());
1458         break;
1459       }
1460       case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
1461         const OpUpdateAsyncImagePipeline& op =
1462             cmd.get_OpUpdateAsyncImagePipeline();
1463         mAsyncImageManager->UpdateAsyncImagePipeline(
1464             op.pipelineId(), op.scBounds(), op.rotation(), op.filter(),
1465             op.mixBlendMode());
1466         mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn,
1467                                                        txnForImageBridge);
1468         break;
1469       }
1470       case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: {
1471         const OpUpdatedAsyncImagePipeline& op =
1472             cmd.get_OpUpdatedAsyncImagePipeline();
1473         aTxn.InvalidateRenderedFrame();
1474         mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn,
1475                                                        txnForImageBridge);
1476         break;
1477       }
1478       case WebRenderParentCommand::TCompositableOperation: {
1479         if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) {
1480           NS_ERROR("ReceiveCompositableUpdate failed");
1481         }
1482         break;
1483       }
1484       case WebRenderParentCommand::TOpAddCompositorAnimations: {
1485         const OpAddCompositorAnimations& op =
1486             cmd.get_OpAddCompositorAnimations();
1487         CompositorAnimations data(std::move(op.data()));
1488         // AnimationHelper::GetNextCompositorAnimationsId() encodes the child
1489         // process PID in the upper 32 bits of the id, verify that this is as
1490         // expected.
1491         if ((data.id() >> 32) != (uint64_t)OtherPid()) {
1492           return false;
1493         }
1494         if (data.animations().Length()) {
1495           if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
1496             sampler->SetAnimations(data.id(), GetLayersId(), data.animations());
1497             const auto activeAnim = mActiveAnimations.find(data.id());
1498             if (activeAnim == mActiveAnimations.end()) {
1499               mActiveAnimations.emplace(data.id(), mWrEpoch);
1500             } else {
1501               // Update wr::Epoch if the animation already exists.
1502               activeAnim->second = mWrEpoch;
1503             }
1504           }
1505         }
1506         break;
1507       }
1508       default: {
1509         // other commands are handle on the child
1510         break;
1511       }
1512     }
1513   }
1514   return true;
1515 }
1516 
FlushSceneBuilds()1517 void WebRenderBridgeParent::FlushSceneBuilds() {
1518   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1519 
1520   // Since we are sending transactions through the scene builder thread, we need
1521   // to block until all the inflight transactions have been processed. This
1522   // flush message blocks until all previously sent scenes have been built
1523   // and received by the render backend thread.
1524   mApi->FlushSceneBuilder();
1525   // The post-swap hook for async-scene-building calls the
1526   // ScheduleRenderOnCompositorThread function from the scene builder thread,
1527   // which then triggers a call to ScheduleGenerateFrame() on the compositor
1528   // thread. But since *this* function is running on the compositor thread,
1529   // that scheduling will not happen until this call stack unwinds (or we
1530   // could spin a nested event loop, but that's more messy). Instead, we
1531   // simulate it ourselves by calling ScheduleGenerateFrame() directly.
1532   // Note also that the post-swap hook will run and do another
1533   // ScheduleGenerateFrame() after we unwind here, so we will end up with an
1534   // extra render/composite that is probably avoidable, but in practice we
1535   // shouldn't be calling this function all that much in production so this
1536   // is probably fine. If it becomes an issue we can add more state tracking
1537   // machinery to optimize it away.
1538   ScheduleGenerateFrame();
1539 }
1540 
FlushFrameGeneration()1541 void WebRenderBridgeParent::FlushFrameGeneration() {
1542   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1543   MOZ_ASSERT(IsRootWebRenderBridgeParent());  // This function is only useful on
1544                                               // the root WRBP
1545 
1546   // This forces a new GenerateFrame transaction to be sent to the render
1547   // backend thread, if one is pending. This doesn't block on any other threads.
1548   if (mCompositorScheduler->NeedsComposite()) {
1549     mCompositorScheduler->CancelCurrentCompositeTask();
1550     // Update timestamp of scheduler for APZ and animation.
1551     mCompositorScheduler->UpdateLastComposeTime();
1552     MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true);
1553   }
1554 }
1555 
FlushFramePresentation()1556 void WebRenderBridgeParent::FlushFramePresentation() {
1557   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1558 
1559   // This sends a message to the render backend thread to send a message
1560   // to the renderer thread, and waits for that message to be processed. So
1561   // this effectively blocks on the render backend and renderer threads,
1562   // following the same codepath that WebRender takes to render and composite
1563   // a frame.
1564   mApi->WaitFlushed();
1565 }
1566 
DisableNativeCompositor()1567 void WebRenderBridgeParent::DisableNativeCompositor() {
1568   // Make sure that SceneBuilder thread does not have a task.
1569   mApi->FlushSceneBuilder();
1570   // Disable WebRender's native compositor usage
1571   mApi->EnableNativeCompositor(false);
1572   // Ensure we generate and render a frame immediately.
1573   ScheduleForcedGenerateFrame();
1574 
1575   mDisablingNativeCompositor = true;
1576 }
1577 
UpdateQualitySettings()1578 void WebRenderBridgeParent::UpdateQualitySettings() {
1579   wr::TransactionBuilder txn(mApi);
1580   txn.UpdateQualitySettings(gfxVars::ForceSubpixelAAWherePossible());
1581   mApi->SendTransaction(txn);
1582 }
1583 
UpdateDebugFlags()1584 void WebRenderBridgeParent::UpdateDebugFlags() {
1585   mApi->UpdateDebugFlags(gfxVars::WebRenderDebugFlags());
1586 }
1587 
UpdateProfilerUI()1588 void WebRenderBridgeParent::UpdateProfilerUI() {
1589   nsCString uiString = gfxVars::GetWebRenderProfilerUIOrDefault();
1590   mApi->SetProfilerUI(uiString);
1591 }
1592 
UpdateMultithreading()1593 void WebRenderBridgeParent::UpdateMultithreading() {
1594   mApi->EnableMultithreading(gfxVars::UseWebRenderMultithreading());
1595 }
1596 
UpdateBatchingParameters()1597 void WebRenderBridgeParent::UpdateBatchingParameters() {
1598   uint32_t count = gfxVars::WebRenderBatchingLookback();
1599   mApi->SetBatchingLookback(count);
1600 }
1601 
1602 #if defined(MOZ_WIDGET_ANDROID)
RequestScreenPixels(UiCompositorControllerParent * aController)1603 void WebRenderBridgeParent::RequestScreenPixels(
1604     UiCompositorControllerParent* aController) {
1605   mScreenPixelsTarget = aController;
1606 }
1607 
MaybeCaptureScreenPixels()1608 void WebRenderBridgeParent::MaybeCaptureScreenPixels() {
1609   if (!mScreenPixelsTarget) {
1610     return;
1611   }
1612 
1613   if (mDestroyed) {
1614     return;
1615   }
1616 
1617   // This function should only get called in the root WRBP.
1618   MOZ_ASSERT(IsRootWebRenderBridgeParent());
1619 #  ifdef DEBUG
1620   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1621   MOZ_ASSERT(cbp && !cbp->IsPaused());
1622 #  endif
1623 
1624   SurfaceFormat format = SurfaceFormat::R8G8B8A8;  // On android we use RGBA8
1625   auto client_size = mWidget->GetClientSize();
1626   size_t buffer_size =
1627       client_size.width * client_size.height * BytesPerPixel(format);
1628 
1629   ipc::Shmem mem;
1630   if (!mScreenPixelsTarget->AllocPixelBuffer(buffer_size, &mem)) {
1631     // Failed to alloc shmem, Just bail out.
1632     return;
1633   }
1634 
1635   IntSize size(client_size.width, client_size.height);
1636 
1637   bool needsYFlip = false;
1638   mApi->Readback(TimeStamp::Now(), size, format,
1639                  Range<uint8_t>(mem.get<uint8_t>(), buffer_size), &needsYFlip);
1640 
1641   Unused << mScreenPixelsTarget->SendScreenPixels(
1642       std::move(mem), ScreenIntSize(client_size.width, client_size.height),
1643       needsYFlip);
1644 
1645   mScreenPixelsTarget = nullptr;
1646 }
1647 #endif
1648 
RecvGetSnapshot(PTextureParent * aTexture,bool * aNeedsYFlip)1649 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
1650     PTextureParent* aTexture, bool* aNeedsYFlip) {
1651   *aNeedsYFlip = false;
1652   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1653   if (mDestroyed || !cbp || cbp->IsPaused()) {
1654     return IPC_OK();
1655   }
1656 
1657   // This function should only get called in the root WRBP. If this function
1658   // gets called in a non-root WRBP, we will set mForceRendering in this WRBP
1659   // but it will have no effect because CompositeToTarget (which reads the
1660   // flag) only gets invoked in the root WRBP. So we assert that this is the
1661   // root WRBP (i.e. has a non-null mWidget) to catch violations of this rule.
1662   MOZ_ASSERT(IsRootWebRenderBridgeParent());
1663 
1664   RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
1665   if (!texture) {
1666     // We kill the content process rather than have it continue with an invalid
1667     // snapshot, that may be too harsh and we could decide to return some sort
1668     // of error to the child process and let it deal with it...
1669     return IPC_FAIL_NO_REASON(this);
1670   }
1671 
1672   // XXX Add other TextureHost supports.
1673   // Only BufferTextureHost is supported now.
1674   BufferTextureHost* bufferTexture = texture->AsBufferTextureHost();
1675   if (!bufferTexture) {
1676     // We kill the content process rather than have it continue with an invalid
1677     // snapshot, that may be too harsh and we could decide to return some sort
1678     // of error to the child process and let it deal with it...
1679     return IPC_FAIL_NO_REASON(this);
1680   }
1681 
1682   TimeStamp start = TimeStamp::Now();
1683   MOZ_ASSERT(bufferTexture->GetBufferDescriptor().type() ==
1684              BufferDescriptor::TRGBDescriptor);
1685   DebugOnly<uint32_t> stride = ImageDataSerializer::GetRGBStride(
1686       bufferTexture->GetBufferDescriptor().get_RGBDescriptor());
1687   uint8_t* buffer = bufferTexture->GetBuffer();
1688   IntSize size = bufferTexture->GetSize();
1689 
1690   MOZ_ASSERT(buffer);
1691   // For now the only formats we get here are RGBA and BGRA, and code below is
1692   // assuming a bpp of 4. If we allow other formats, the code needs adjusting
1693   // accordingly.
1694   MOZ_ASSERT(BytesPerPixel(bufferTexture->GetFormat()) == 4);
1695   uint32_t buffer_size = size.width * size.height * 4;
1696 
1697   // Assert the stride of the buffer is what webrender expects
1698   MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
1699 
1700   FlushSceneBuilds();
1701   FlushFrameGeneration();
1702   mApi->Readback(start, size, bufferTexture->GetFormat(),
1703                  Range<uint8_t>(buffer, buffer_size), aNeedsYFlip);
1704 
1705   return IPC_OK();
1706 }
1707 
AddPipelineIdForCompositable(const wr::PipelineId & aPipelineId,const CompositableHandle & aHandle,const bool & aAsync,wr::TransactionBuilder & aTxn,wr::TransactionBuilder & aTxnForImageBridge)1708 void WebRenderBridgeParent::AddPipelineIdForCompositable(
1709     const wr::PipelineId& aPipelineId, const CompositableHandle& aHandle,
1710     const bool& aAsync, wr::TransactionBuilder& aTxn,
1711     wr::TransactionBuilder& aTxnForImageBridge) {
1712   if (mDestroyed) {
1713     return;
1714   }
1715 
1716   MOZ_ASSERT(mAsyncCompositables.find(wr::AsUint64(aPipelineId)) ==
1717              mAsyncCompositables.end());
1718 
1719   RefPtr<CompositableHost> host;
1720   if (aAsync) {
1721     RefPtr<ImageBridgeParent> imageBridge =
1722         ImageBridgeParent::GetInstance(OtherPid());
1723     if (!imageBridge) {
1724       return;
1725     }
1726     host = imageBridge->FindCompositable(aHandle);
1727   } else {
1728     host = FindCompositable(aHandle);
1729   }
1730   if (!host) {
1731     return;
1732   }
1733 
1734   WebRenderImageHost* wrHost = host->AsWebRenderImageHost();
1735   MOZ_ASSERT(wrHost);
1736   if (!wrHost) {
1737     gfxCriticalNote
1738         << "Incompatible CompositableHost at WebRenderBridgeParent.";
1739   }
1740 
1741   if (!wrHost) {
1742     return;
1743   }
1744 
1745   wrHost->SetWrBridge(aPipelineId, this);
1746   mAsyncCompositables.emplace(wr::AsUint64(aPipelineId), wrHost);
1747   mAsyncImageManager->AddAsyncImagePipeline(aPipelineId, wrHost);
1748 
1749   // If this is being called from WebRenderBridgeParent::RecvSetDisplayList,
1750   // then aTxn might contain a display list that references pipelines that
1751   // we just added to the async image manager.
1752   // If we send the display list alone then WR will not yet have the content for
1753   // the pipelines and so it will emit errors; the SetEmptyDisplayList call
1754   // below ensure that we provide its content to WR as part of the same
1755   // transaction.
1756   mAsyncImageManager->SetEmptyDisplayList(aPipelineId, aTxn,
1757                                           aTxnForImageBridge);
1758 }
1759 
RemovePipelineIdForCompositable(const wr::PipelineId & aPipelineId,wr::TransactionBuilder & aTxn)1760 void WebRenderBridgeParent::RemovePipelineIdForCompositable(
1761     const wr::PipelineId& aPipelineId, wr::TransactionBuilder& aTxn) {
1762   if (mDestroyed) {
1763     return;
1764   }
1765 
1766   auto it = mAsyncCompositables.find(wr::AsUint64(aPipelineId));
1767   if (it == mAsyncCompositables.end()) {
1768     return;
1769   }
1770   RefPtr<WebRenderImageHost>& wrHost = it->second;
1771 
1772   wrHost->ClearWrBridge(aPipelineId, this);
1773   mAsyncImageManager->RemoveAsyncImagePipeline(aPipelineId, aTxn);
1774   aTxn.RemovePipeline(aPipelineId);
1775   mAsyncCompositables.erase(wr::AsUint64(aPipelineId));
1776 }
1777 
DeleteImage(const ImageKey & aKey,wr::TransactionBuilder & aUpdates)1778 void WebRenderBridgeParent::DeleteImage(const ImageKey& aKey,
1779                                         wr::TransactionBuilder& aUpdates) {
1780   if (mDestroyed) {
1781     return;
1782   }
1783 
1784   auto it = mSharedSurfaceIds.find(wr::AsUint64(aKey));
1785   if (it != mSharedSurfaceIds.end()) {
1786     mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, it->second);
1787     mSharedSurfaceIds.erase(it);
1788   }
1789 
1790   aUpdates.DeleteImage(aKey);
1791 }
1792 
ReleaseTextureOfImage(const wr::ImageKey & aKey)1793 void WebRenderBridgeParent::ReleaseTextureOfImage(const wr::ImageKey& aKey) {
1794   if (mDestroyed) {
1795     return;
1796   }
1797 
1798   uint64_t id = wr::AsUint64(aKey);
1799   CompositableTextureHostRef texture;
1800   WebRenderTextureHost* wrTexture = nullptr;
1801 
1802   auto it = mTextureHosts.find(id);
1803   if (it != mTextureHosts.end()) {
1804     wrTexture = (*it).second->AsWebRenderTextureHost();
1805   }
1806   if (wrTexture) {
1807     mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, wrTexture);
1808   }
1809   mTextureHosts.erase(id);
1810 }
1811 
RecvSetLayersObserverEpoch(const LayersObserverEpoch & aChildEpoch)1812 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetLayersObserverEpoch(
1813     const LayersObserverEpoch& aChildEpoch) {
1814   if (mDestroyed) {
1815     return IPC_OK();
1816   }
1817   mChildLayersObserverEpoch = aChildEpoch;
1818   return IPC_OK();
1819 }
1820 
RecvClearCachedResources()1821 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvClearCachedResources() {
1822   if (mDestroyed) {
1823     return IPC_OK();
1824   }
1825 
1826   // Clear resources
1827   wr::TransactionBuilder txn(mApi);
1828   txn.SetLowPriority(true);
1829   txn.ClearDisplayList(GetNextWrEpoch(), mPipelineId);
1830   txn.Notify(
1831       wr::Checkpoint::SceneBuilt,
1832       MakeUnique<ScheduleObserveLayersUpdate>(
1833           mCompositorBridge, GetLayersId(), mChildLayersObserverEpoch, false));
1834   mApi->SendTransaction(txn);
1835 
1836   // Schedule generate frame to clean up Pipeline
1837   ScheduleGenerateFrame();
1838 
1839   ClearAnimationResources();
1840 
1841   return IPC_OK();
1842 }
1843 
UpdateWebRender(CompositorVsyncScheduler * aScheduler,RefPtr<wr::WebRenderAPI> && aApi,AsyncImagePipelineManager * aImageMgr,const TextureFactoryIdentifier & aTextureFactoryIdentifier)1844 wr::Epoch WebRenderBridgeParent::UpdateWebRender(
1845     CompositorVsyncScheduler* aScheduler, RefPtr<wr::WebRenderAPI>&& aApi,
1846     AsyncImagePipelineManager* aImageMgr,
1847     const TextureFactoryIdentifier& aTextureFactoryIdentifier) {
1848   MOZ_ASSERT(!IsRootWebRenderBridgeParent());
1849   MOZ_ASSERT(aScheduler);
1850   MOZ_ASSERT(aApi);
1851   MOZ_ASSERT(aImageMgr);
1852 
1853   if (mDestroyed) {
1854     return mWrEpoch;
1855   }
1856 
1857   // Update id name space to identify obsoleted keys.
1858   // Since usage of invalid keys could cause crash in webrender.
1859   mIdNamespace = aApi->GetNamespace();
1860   // XXX Remove it when webrender supports sharing/moving Keys between different
1861   // webrender instances.
1862   // XXX It requests client to update/reallocate webrender related resources,
1863   // but parent side does not wait end of the update.
1864   // The code could become simpler if we could serialise old keys deallocation
1865   // and new keys allocation. But we do not do it, it is because client side
1866   // deallocate old layers/webrender keys after new layers/webrender keys
1867   // allocation. Without client side's layout refactoring, we could not finish
1868   // all old layers/webrender keys removals before new layer/webrender keys
1869   // allocation. In future, we could address the problem.
1870   Unused << SendWrUpdated(mIdNamespace, aTextureFactoryIdentifier);
1871   CompositorBridgeParentBase* cBridge = mCompositorBridge;
1872   // XXX Stop to clear resources if webreder supports resources sharing between
1873   // different webrender instances.
1874   ClearResources();
1875   mCompositorBridge = cBridge;
1876   mCompositorScheduler = aScheduler;
1877   mApi = aApi;
1878   mAsyncImageManager = aImageMgr;
1879 
1880   // Register pipeline to updated AsyncImageManager.
1881   mAsyncImageManager->AddPipeline(mPipelineId, this);
1882 
1883   return GetNextWrEpoch();  // Update webrender epoch
1884 }
1885 
RecvInvalidateRenderedFrame()1886 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvInvalidateRenderedFrame() {
1887   // This function should only get called in the root WRBP
1888   MOZ_ASSERT(IsRootWebRenderBridgeParent());
1889 
1890   InvalidateRenderedFrame();
1891   return IPC_OK();
1892 }
1893 
RecvScheduleComposite()1894 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvScheduleComposite() {
1895   // Caller of LayerManager::ScheduleComposite() expects that it trigger
1896   // composite. Then we do not want to skip generate frame.
1897   ScheduleForcedGenerateFrame();
1898   return IPC_OK();
1899 }
1900 
InvalidateRenderedFrame()1901 void WebRenderBridgeParent::InvalidateRenderedFrame() {
1902   if (mDestroyed) {
1903     return;
1904   }
1905 
1906   wr::TransactionBuilder fastTxn(mApi, /* aUseSceneBuilderThread */ false);
1907   fastTxn.InvalidateRenderedFrame();
1908   mApi->SendTransaction(fastTxn);
1909 }
1910 
ScheduleForcedGenerateFrame()1911 void WebRenderBridgeParent::ScheduleForcedGenerateFrame() {
1912   if (mDestroyed) {
1913     return;
1914   }
1915 
1916   InvalidateRenderedFrame();
1917   ScheduleGenerateFrame();
1918 }
1919 
RecvCapture()1920 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvCapture() {
1921   if (!mDestroyed) {
1922     mApi->Capture();
1923   }
1924   return IPC_OK();
1925 }
1926 
RecvStartCaptureSequence(const nsCString & aPath,const uint32_t & aFlags)1927 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvStartCaptureSequence(
1928     const nsCString& aPath, const uint32_t& aFlags) {
1929   if (!mDestroyed) {
1930     mApi->StartCaptureSequence(aPath, aFlags);
1931   }
1932   return IPC_OK();
1933 }
1934 
RecvStopCaptureSequence()1935 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvStopCaptureSequence() {
1936   if (!mDestroyed) {
1937     mApi->StopCaptureSequence();
1938   }
1939   return IPC_OK();
1940 }
1941 
RecvSyncWithCompositor()1942 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSyncWithCompositor() {
1943   FlushSceneBuilds();
1944   if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
1945     root->FlushFrameGeneration();
1946   }
1947   FlushFramePresentation();
1948   // Finally, we force the AsyncImagePipelineManager to handle all the
1949   // pipeline updates produced in the last step, so that it frees any
1950   // unneeded textures. Then we can return from this sync IPC call knowing
1951   // that we've done everything we can to flush stuff on the compositor.
1952   mAsyncImageManager->ProcessPipelineUpdates();
1953 
1954   return IPC_OK();
1955 }
1956 
RecvSetConfirmedTargetAPZC(const uint64_t & aBlockId,nsTArray<ScrollableLayerGuid> && aTargets)1957 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetConfirmedTargetAPZC(
1958     const uint64_t& aBlockId, nsTArray<ScrollableLayerGuid>&& aTargets) {
1959   for (size_t i = 0; i < aTargets.Length(); i++) {
1960     // Guard against bad data from hijacked child processes
1961     if (aTargets[i].mLayersId != GetLayersId()) {
1962       NS_ERROR(
1963           "Unexpected layers id in RecvSetConfirmedTargetAPZC; dropping "
1964           "message...");
1965       return IPC_FAIL(this, "Bad layers id");
1966     }
1967   }
1968 
1969   if (mDestroyed) {
1970     return IPC_OK();
1971   }
1972   mCompositorBridge->SetConfirmedTargetAPZC(GetLayersId(), aBlockId,
1973                                             std::move(aTargets));
1974   return IPC_OK();
1975 }
1976 
RecvSetTestSampleTime(const TimeStamp & aTime)1977 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetTestSampleTime(
1978     const TimeStamp& aTime) {
1979   if (!mCompositorBridge->SetTestSampleTime(GetLayersId(), aTime)) {
1980     return IPC_FAIL_NO_REASON(this);
1981   }
1982   if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
1983     sampler->EnterTestMode();
1984   }
1985 
1986   return IPC_OK();
1987 }
1988 
RecvLeaveTestMode()1989 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvLeaveTestMode() {
1990   if (mDestroyed) {
1991     return IPC_FAIL_NO_REASON(this);
1992   }
1993 
1994   mCompositorBridge->LeaveTestMode(GetLayersId());
1995   if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
1996     sampler->LeaveTestMode();
1997   }
1998 
1999   return IPC_OK();
2000 }
2001 
RecvGetAnimationValue(const uint64_t & aCompositorAnimationsId,OMTAValue * aValue)2002 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetAnimationValue(
2003     const uint64_t& aCompositorAnimationsId, OMTAValue* aValue) {
2004   if (mDestroyed) {
2005     return IPC_FAIL_NO_REASON(this);
2006   }
2007 
2008   if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
2009     Maybe<TimeStamp> testingTimeStamp;
2010     if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
2011       testingTimeStamp = cbp->GetTestingTimeStamp();
2012     }
2013 
2014     sampler->SampleForTesting(testingTimeStamp);
2015     *aValue = sampler->GetOMTAValue(aCompositorAnimationsId);
2016   }
2017 
2018   return IPC_OK();
2019 }
2020 
RecvSetAsyncScrollOffset(const ScrollableLayerGuid::ViewID & aScrollId,const float & aX,const float & aY)2021 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncScrollOffset(
2022     const ScrollableLayerGuid::ViewID& aScrollId, const float& aX,
2023     const float& aY) {
2024   if (mDestroyed) {
2025     return IPC_OK();
2026   }
2027   mCompositorBridge->SetTestAsyncScrollOffset(GetLayersId(), aScrollId,
2028                                               CSSPoint(aX, aY));
2029   return IPC_OK();
2030 }
2031 
RecvSetAsyncZoom(const ScrollableLayerGuid::ViewID & aScrollId,const float & aZoom)2032 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetAsyncZoom(
2033     const ScrollableLayerGuid::ViewID& aScrollId, const float& aZoom) {
2034   if (mDestroyed) {
2035     return IPC_OK();
2036   }
2037   mCompositorBridge->SetTestAsyncZoom(GetLayersId(), aScrollId,
2038                                       LayerToParentLayerScale(aZoom));
2039   return IPC_OK();
2040 }
2041 
RecvFlushApzRepaints()2042 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvFlushApzRepaints() {
2043   if (mDestroyed) {
2044     return IPC_OK();
2045   }
2046   mCompositorBridge->FlushApzRepaints(GetLayersId());
2047   return IPC_OK();
2048 }
2049 
RecvGetAPZTestData(APZTestData * aOutData)2050 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetAPZTestData(
2051     APZTestData* aOutData) {
2052   mCompositorBridge->GetAPZTestData(GetLayersId(), aOutData);
2053   return IPC_OK();
2054 }
2055 
RecvGetFrameUniformity(FrameUniformityData * aOutData)2056 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetFrameUniformity(
2057     FrameUniformityData* aOutData) {
2058   mCompositorBridge->GetFrameUniformity(GetLayersId(), aOutData);
2059   return IPC_OK();
2060 }
2061 
ActorDestroy(ActorDestroyReason aWhy)2062 void WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { Destroy(); }
2063 
ResetPreviousSampleTime()2064 void WebRenderBridgeParent::ResetPreviousSampleTime() {
2065   if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
2066     sampler->ResetPreviousSampleTime();
2067   }
2068 }
2069 
GetOMTASampler() const2070 RefPtr<OMTASampler> WebRenderBridgeParent::GetOMTASampler() const {
2071   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
2072   if (!cbp) {
2073     return nullptr;
2074   }
2075   return cbp->GetOMTASampler();
2076 }
2077 
SetOMTASampleTime()2078 void WebRenderBridgeParent::SetOMTASampleTime() {
2079   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2080   if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
2081     sampler->SetSampleTime(mCompositorScheduler->GetLastComposeTime().Time());
2082   }
2083 }
2084 
CompositeIfNeeded()2085 void WebRenderBridgeParent::CompositeIfNeeded() {
2086   if (mSkippedComposite) {
2087     mSkippedComposite = false;
2088     if (mCompositorScheduler) {
2089       mCompositorScheduler->ScheduleComposition();
2090     }
2091   }
2092 }
2093 
CompositeToTarget(VsyncId aId,gfx::DrawTarget * aTarget,const gfx::IntRect * aRect)2094 void WebRenderBridgeParent::CompositeToTarget(VsyncId aId,
2095                                               gfx::DrawTarget* aTarget,
2096                                               const gfx::IntRect* aRect) {
2097   // This function should only get called in the root WRBP
2098   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2099 
2100   // The two arguments are part of the CompositorVsyncSchedulerOwner API but in
2101   // this implementation they should never be non-null.
2102   MOZ_ASSERT(aTarget == nullptr);
2103   MOZ_ASSERT(aRect == nullptr);
2104 
2105   AUTO_PROFILER_TRACING_MARKER("Paint", "CompositeToTarget", GRAPHICS);
2106 
2107   bool paused = true;
2108   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
2109   if (cbp) {
2110     paused = cbp->IsPaused();
2111   }
2112 
2113   if (paused || !mReceivedDisplayList) {
2114     ResetPreviousSampleTime();
2115     mCompositionOpportunityId = mCompositionOpportunityId.Next();
2116     PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS, {},
2117                          paused ? "Paused"_ns : "No display list"_ns);
2118     return;
2119   }
2120 
2121   if (mSkippedComposite ||
2122       wr::RenderThread::Get()->TooManyPendingFrames(mApi->GetId())) {
2123     // Render thread is busy, try next time.
2124     mSkippedComposite = true;
2125     ResetPreviousSampleTime();
2126 
2127     // Record that we skipped presenting a frame for
2128     // all pending transactions that have finished scene building.
2129     for (auto& id : mPendingTransactionIds) {
2130       if (id.mSceneBuiltTime) {
2131         id.mSkippedComposites++;
2132       }
2133     }
2134 
2135     PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS, {},
2136                          "Too many pending frames");
2137     return;
2138   }
2139 
2140   mCompositionOpportunityId = mCompositionOpportunityId.Next();
2141   MaybeGenerateFrame(aId, /* aForceGenerateFrame */ false);
2142 }
2143 
GetVsyncInterval() const2144 TimeDuration WebRenderBridgeParent::GetVsyncInterval() const {
2145   // This function should only get called in the root WRBP
2146   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2147   if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
2148     return cbp->GetVsyncInterval();
2149   }
2150   return TimeDuration();
2151 }
2152 
MaybeGenerateFrame(VsyncId aId,bool aForceGenerateFrame)2153 void WebRenderBridgeParent::MaybeGenerateFrame(VsyncId aId,
2154                                                bool aForceGenerateFrame) {
2155   // This function should only get called in the root WRBP
2156   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2157 
2158   if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
2159     // Skip WR render during paused state.
2160     if (cbp->IsPaused()) {
2161       TimeStamp now = TimeStamp::NowUnfuzzed();
2162       PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS,
2163                            MarkerTiming::InstantAt(now),
2164                            "CompositorBridgeParent is paused");
2165       cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now,
2166                                   now);
2167       return;
2168     }
2169   }
2170 
2171   TimeStamp start = TimeStamp::Now();
2172 
2173   // Ensure GenerateFrame is handled on the render backend thread rather
2174   // than going through the scene builder thread. That way we continue
2175   // generating frames with the old scene even during slow scene builds.
2176   wr::TransactionBuilder fastTxn(mApi, false /* useSceneBuilderThread */);
2177   // Handle transaction that is related to DisplayList.
2178   wr::TransactionBuilder sceneBuilderTxn(mApi);
2179   wr::AutoTransactionSender sender(mApi, &sceneBuilderTxn);
2180 
2181   mAsyncImageManager->SetCompositionInfo(start, mCompositionOpportunityId);
2182   mAsyncImageManager->ApplyAsyncImagesOfImageBridge(sceneBuilderTxn, fastTxn);
2183   mAsyncImageManager->SetCompositionInfo(TimeStamp(),
2184                                          CompositionOpportunityId{});
2185 
2186   if (!mAsyncImageManager->GetCompositeUntilTime().IsNull()) {
2187     // Trigger another CompositeToTarget() call because there might be another
2188     // frame that we want to generate after this one.
2189     // It will check if we actually want to generate the frame or not.
2190     mCompositorScheduler->ScheduleComposition();
2191   }
2192 
2193   bool generateFrame = mAsyncImageManager->GetAndResetWillGenerateFrame() ||
2194                        !fastTxn.IsEmpty() || aForceGenerateFrame;
2195 
2196   if (!generateFrame) {
2197     // Could skip generating frame now.
2198     PROFILER_MARKER_TEXT("SkippedComposite", GRAPHICS,
2199                          MarkerTiming::InstantAt(start),
2200                          "No reason to generate frame");
2201     ResetPreviousSampleTime();
2202     return;
2203   }
2204 
2205   if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
2206     if (sampler->HasAnimations()) {
2207       ScheduleGenerateFrame();
2208     }
2209   }
2210 
2211   SetOMTASampleTime();
2212   SetAPZSampleTime();
2213 
2214   wr::RenderThread::Get()->IncPendingFrameCount(mApi->GetId(), aId, start);
2215 
2216 #if defined(ENABLE_FRAME_LATENCY_LOG)
2217   auto startTime = TimeStamp::Now();
2218   mApi->SetFrameStartTime(startTime);
2219 #endif
2220 
2221   MOZ_ASSERT(generateFrame);
2222   fastTxn.GenerateFrame(aId);
2223   mApi->SendTransaction(fastTxn);
2224 
2225 #if defined(MOZ_WIDGET_ANDROID)
2226   MaybeCaptureScreenPixels();
2227 #endif
2228 
2229   mMostRecentComposite = TimeStamp::Now();
2230 
2231   // During disabling native compositor, webrender needs to render twice.
2232   // Otherwise, browser flashes black.
2233   // XXX better fix?
2234   if (mDisablingNativeCompositor) {
2235     mDisablingNativeCompositor = false;
2236 
2237     // Ensure we generate and render a frame immediately.
2238     ScheduleForcedGenerateFrame();
2239   }
2240 }
2241 
HoldPendingTransactionId(const wr::Epoch & aWrEpoch,TransactionId aTransactionId,bool aContainsSVGGroup,const VsyncId & aVsyncId,const TimeStamp & aVsyncStartTime,const TimeStamp & aRefreshStartTime,const TimeStamp & aTxnStartTime,const nsCString & aTxnURL,const TimeStamp & aFwdTime,const bool aIsFirstPaint,nsTArray<CompositionPayload> && aPayloads,const bool aUseForTelemetry)2242 void WebRenderBridgeParent::HoldPendingTransactionId(
2243     const wr::Epoch& aWrEpoch, TransactionId aTransactionId,
2244     bool aContainsSVGGroup, const VsyncId& aVsyncId,
2245     const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
2246     const TimeStamp& aTxnStartTime, const nsCString& aTxnURL,
2247     const TimeStamp& aFwdTime, const bool aIsFirstPaint,
2248     nsTArray<CompositionPayload>&& aPayloads, const bool aUseForTelemetry) {
2249   MOZ_ASSERT(aTransactionId > LastPendingTransactionId());
2250   mPendingTransactionIds.push_back(PendingTransactionId(
2251       aWrEpoch, aTransactionId, aContainsSVGGroup, aVsyncId, aVsyncStartTime,
2252       aRefreshStartTime, aTxnStartTime, aTxnURL, aFwdTime, aIsFirstPaint,
2253       aUseForTelemetry, std::move(aPayloads)));
2254 }
2255 
LastPendingTransactionId()2256 TransactionId WebRenderBridgeParent::LastPendingTransactionId() {
2257   TransactionId id{0};
2258   if (!mPendingTransactionIds.empty()) {
2259     id = mPendingTransactionIds.back().mId;
2260   }
2261   return id;
2262 }
2263 
NotifySceneBuiltForEpoch(const wr::Epoch & aEpoch,const TimeStamp & aEndTime)2264 void WebRenderBridgeParent::NotifySceneBuiltForEpoch(
2265     const wr::Epoch& aEpoch, const TimeStamp& aEndTime) {
2266   for (auto& id : mPendingTransactionIds) {
2267     if (id.mEpoch.mHandle == aEpoch.mHandle) {
2268       id.mSceneBuiltTime = aEndTime;
2269       break;
2270     }
2271   }
2272 }
2273 
NotifyDidSceneBuild(RefPtr<const wr::WebRenderPipelineInfo> aInfo)2274 void WebRenderBridgeParent::NotifyDidSceneBuild(
2275     RefPtr<const wr::WebRenderPipelineInfo> aInfo) {
2276   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2277   if (!mCompositorScheduler) {
2278     return;
2279   }
2280 
2281   mAsyncImageManager->SetWillGenerateFrame();
2282 
2283   // If the scheduler has a composite more recent than our last composite (which
2284   // we missed), and we're within the threshold ms of the last vsync, then
2285   // kick of a late composite.
2286   TimeStamp lastVsync = mCompositorScheduler->GetLastVsyncTime();
2287   VsyncId lastVsyncId = mCompositorScheduler->GetLastVsyncId();
2288   if (lastVsyncId == VsyncId() || !mMostRecentComposite ||
2289       mMostRecentComposite >= lastVsync ||
2290       ((TimeStamp::Now() - lastVsync).ToMilliseconds() >
2291        StaticPrefs::gfx_webrender_late_scenebuild_threshold())) {
2292     mCompositorScheduler->ScheduleComposition();
2293     return;
2294   }
2295 
2296   // Look through all the pipelines contained within the built scene
2297   // and check which vsync they initiated from.
2298   const auto& info = aInfo->Raw();
2299   for (const auto& epoch : info.epochs) {
2300     WebRenderBridgeParent* wrBridge = this;
2301     if (!(epoch.pipeline_id == PipelineId())) {
2302       wrBridge = mAsyncImageManager->GetWrBridge(epoch.pipeline_id);
2303     }
2304 
2305     if (wrBridge) {
2306       VsyncId startId = wrBridge->GetVsyncIdForEpoch(epoch.epoch);
2307       // If any of the pipelines started building on the current vsync (i.e
2308       // we did all of display list building and scene building within the
2309       // threshold), then don't do an early composite.
2310       if (startId == lastVsyncId) {
2311         mCompositorScheduler->ScheduleComposition();
2312         return;
2313       }
2314     }
2315   }
2316 
2317   CompositeToTarget(mCompositorScheduler->GetLastVsyncId(), nullptr, nullptr);
2318 }
2319 
GetHistogramId(const bool aIsLargePaint,const bool aIsFullDisplayList)2320 static Telemetry::HistogramID GetHistogramId(const bool aIsLargePaint,
2321                                              const bool aIsFullDisplayList) {
2322   const Telemetry::HistogramID histogramIds[] = {
2323       Telemetry::CONTENT_SMALL_PAINT_PHASE_WEIGHT_PARTIAL,
2324       Telemetry::CONTENT_LARGE_PAINT_PHASE_WEIGHT_PARTIAL,
2325       Telemetry::CONTENT_SMALL_PAINT_PHASE_WEIGHT_FULL,
2326       Telemetry::CONTENT_LARGE_PAINT_PHASE_WEIGHT_FULL,
2327   };
2328 
2329   return histogramIds[(aIsFullDisplayList * 2) + aIsLargePaint];
2330 }
2331 
RecordPaintPhaseTelemetry(wr::RendererStats * aStats)2332 static void RecordPaintPhaseTelemetry(wr::RendererStats* aStats) {
2333   if (!aStats || !aStats->full_paint) {
2334     return;
2335   }
2336 
2337   const double geckoDL = aStats->gecko_display_list_time;
2338   const double wrDL = aStats->wr_display_list_time;
2339   const double sceneBuild = aStats->scene_build_time;
2340   const double frameBuild = aStats->frame_build_time;
2341   const double totalMs = geckoDL + wrDL + sceneBuild + frameBuild;
2342 
2343   // If the total time was >= 16ms, then it's likely we missed a frame due to
2344   // painting. We bucket these metrics separately.
2345   const bool isLargePaint = totalMs >= 16.0;
2346 
2347   // Split the results based on display list build type, partial or full.
2348   const bool isFullDisplayList = aStats->full_display_list;
2349 
2350   auto AsPercentage = [&](const double aTimeMs) -> double {
2351     MOZ_ASSERT(aTimeMs <= totalMs);
2352     return (aTimeMs / totalMs) * 100.0;
2353   };
2354 
2355   auto RecordKey = [&](const nsCString& aKey, const double aTimeMs) -> void {
2356     const auto val = static_cast<uint32_t>(AsPercentage(aTimeMs));
2357     const auto histogramId = GetHistogramId(isLargePaint, isFullDisplayList);
2358     Telemetry::Accumulate(histogramId, aKey, val);
2359   };
2360 
2361   RecordKey("dl"_ns, geckoDL);
2362   RecordKey("wrdl"_ns, wrDL);
2363   RecordKey("sb"_ns, sceneBuild);
2364   RecordKey("fb"_ns, frameBuild);
2365 }
2366 
FlushTransactionIdsForEpoch(const wr::Epoch & aEpoch,const VsyncId & aCompositeStartId,const TimeStamp & aCompositeStartTime,const TimeStamp & aRenderStartTime,const TimeStamp & aEndTime,UiCompositorControllerParent * aUiController,wr::RendererStats * aStats,nsTArray<FrameStats> & aOutputStats,nsTArray<TransactionId> & aOutputTransactions)2367 void WebRenderBridgeParent::FlushTransactionIdsForEpoch(
2368     const wr::Epoch& aEpoch, const VsyncId& aCompositeStartId,
2369     const TimeStamp& aCompositeStartTime, const TimeStamp& aRenderStartTime,
2370     const TimeStamp& aEndTime, UiCompositorControllerParent* aUiController,
2371     wr::RendererStats* aStats, nsTArray<FrameStats>& aOutputStats,
2372     nsTArray<TransactionId>& aOutputTransactions) {
2373   while (!mPendingTransactionIds.empty()) {
2374     const auto& transactionId = mPendingTransactionIds.front();
2375 
2376     if (aEpoch.mHandle < transactionId.mEpoch.mHandle) {
2377       break;
2378     }
2379 
2380     if (!IsRootWebRenderBridgeParent() && !mVsyncRate.IsZero() &&
2381         transactionId.mUseForTelemetry) {
2382       auto fullPaintTime =
2383           transactionId.mSceneBuiltTime
2384               ? transactionId.mSceneBuiltTime - transactionId.mTxnStartTime
2385               : TimeDuration::FromMilliseconds(0);
2386 
2387       int32_t contentFrameTime = RecordContentFrameTime(
2388           transactionId.mVsyncId, transactionId.mVsyncStartTime,
2389           transactionId.mTxnStartTime, aCompositeStartId, aEndTime,
2390           fullPaintTime, mVsyncRate, transactionId.mContainsSVGGroup, true,
2391           aStats);
2392 
2393       RecordPaintPhaseTelemetry(aStats);
2394 
2395       if (contentFrameTime > 200) {
2396         aOutputStats.AppendElement(FrameStats(
2397             transactionId.mId, aCompositeStartTime, aRenderStartTime, aEndTime,
2398             contentFrameTime,
2399             aStats ? (double(aStats->resource_upload_time) / 1000000.0) : 0.0,
2400             aStats ? (double(aStats->gpu_cache_upload_time) / 1000000.0) : 0.0,
2401             transactionId.mTxnStartTime, transactionId.mRefreshStartTime,
2402             transactionId.mFwdTime, transactionId.mSceneBuiltTime,
2403             transactionId.mSkippedComposites, transactionId.mTxnURL));
2404       }
2405     }
2406 
2407 #if defined(ENABLE_FRAME_LATENCY_LOG)
2408     if (transactionId.mRefreshStartTime) {
2409       int32_t latencyMs =
2410           lround((aEndTime - transactionId.mRefreshStartTime).ToMilliseconds());
2411       printf_stderr(
2412           "From transaction start to end of generate frame latencyMs %d this "
2413           "%p\n",
2414           latencyMs, this);
2415     }
2416     if (transactionId.mFwdTime) {
2417       int32_t latencyMs =
2418           lround((aEndTime - transactionId.mFwdTime).ToMilliseconds());
2419       printf_stderr(
2420           "From forwarding transaction to end of generate frame latencyMs %d "
2421           "this %p\n",
2422           latencyMs, this);
2423     }
2424 #endif
2425 
2426     if (aUiController && transactionId.mIsFirstPaint) {
2427       aUiController->NotifyFirstPaint();
2428     }
2429 
2430     RecordCompositionPayloadsPresented(aEndTime, transactionId.mPayloads);
2431 
2432     aOutputTransactions.AppendElement(transactionId.mId);
2433     mPendingTransactionIds.pop_front();
2434   }
2435 }
2436 
GetLayersId() const2437 LayersId WebRenderBridgeParent::GetLayersId() const {
2438   return wr::AsLayersId(mPipelineId);
2439 }
2440 
ScheduleGenerateFrame()2441 void WebRenderBridgeParent::ScheduleGenerateFrame() {
2442   if (mCompositorScheduler) {
2443     mAsyncImageManager->SetWillGenerateFrame();
2444     mCompositorScheduler->ScheduleComposition();
2445   }
2446 }
2447 
FlushRendering(bool aWaitForPresent)2448 void WebRenderBridgeParent::FlushRendering(bool aWaitForPresent) {
2449   if (mDestroyed) {
2450     return;
2451   }
2452 
2453   // This gets called during e.g. window resizes, so we need to flush the
2454   // scene (which has the display list at the new window size).
2455   FlushSceneBuilds();
2456   FlushFrameGeneration();
2457   if (aWaitForPresent) {
2458     FlushFramePresentation();
2459   }
2460 }
2461 
SetClearColor(const gfx::DeviceColor & aColor)2462 void WebRenderBridgeParent::SetClearColor(const gfx::DeviceColor& aColor) {
2463   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2464 
2465   if (!IsRootWebRenderBridgeParent() || mDestroyed) {
2466     return;
2467   }
2468 
2469   mApi->SetClearColor(aColor);
2470 }
2471 
Pause()2472 void WebRenderBridgeParent::Pause() {
2473   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2474 
2475   if (!IsRootWebRenderBridgeParent() || mDestroyed) {
2476     return;
2477   }
2478 
2479   mApi->Pause();
2480 }
2481 
Resume()2482 bool WebRenderBridgeParent::Resume() {
2483   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2484 
2485   if (!IsRootWebRenderBridgeParent() || mDestroyed) {
2486     return false;
2487   }
2488 
2489   if (!mApi->Resume()) {
2490     return false;
2491   }
2492 
2493   // Ensure we generate and render a frame immediately.
2494   ScheduleForcedGenerateFrame();
2495   return true;
2496 }
2497 
ClearResources()2498 void WebRenderBridgeParent::ClearResources() {
2499   if (!mApi) {
2500     return;
2501   }
2502 
2503   wr::Epoch wrEpoch = GetNextWrEpoch();
2504   mReceivedDisplayList = false;
2505   // Schedule generate frame to clean up Pipeline
2506   ScheduleGenerateFrame();
2507 
2508   // WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction.
2509   for (const auto& entry : mTextureHosts) {
2510     WebRenderTextureHost* wrTexture = entry.second->AsWebRenderTextureHost();
2511     MOZ_ASSERT(wrTexture);
2512     if (wrTexture) {
2513       mAsyncImageManager->HoldExternalImage(mPipelineId, wrEpoch, wrTexture);
2514     }
2515   }
2516   mTextureHosts.clear();
2517 
2518   for (const auto& entry : mSharedSurfaceIds) {
2519     mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, entry.second);
2520   }
2521   mSharedSurfaceIds.clear();
2522 
2523   mAsyncImageManager->RemovePipeline(mPipelineId, wrEpoch);
2524 
2525   wr::TransactionBuilder txn(mApi);
2526   txn.SetLowPriority(true);
2527   txn.ClearDisplayList(wrEpoch, mPipelineId);
2528 
2529   for (const auto& entry : mAsyncCompositables) {
2530     wr::PipelineId pipelineId = wr::AsPipelineId(entry.first);
2531     RefPtr<WebRenderImageHost> host = entry.second;
2532     host->ClearWrBridge(pipelineId, this);
2533     mAsyncImageManager->RemoveAsyncImagePipeline(pipelineId, txn);
2534     txn.RemovePipeline(pipelineId);
2535   }
2536   mAsyncCompositables.clear();
2537   txn.RemovePipeline(mPipelineId);
2538   mApi->SendTransaction(txn);
2539 
2540   ClearAnimationResources();
2541 
2542   if (IsRootWebRenderBridgeParent()) {
2543     mCompositorScheduler->Destroy();
2544     mApi->DestroyRenderer();
2545   }
2546 
2547   mCompositorScheduler = nullptr;
2548   mAsyncImageManager = nullptr;
2549   mApi = nullptr;
2550   mCompositorBridge = nullptr;
2551 }
2552 
ClearAnimationResources()2553 void WebRenderBridgeParent::ClearAnimationResources() {
2554   if (RefPtr<OMTASampler> sampler = GetOMTASampler()) {
2555     sampler->ClearActiveAnimations(mActiveAnimations);
2556   }
2557   mActiveAnimations.clear();
2558   std::queue<CompositorAnimationIdsForEpoch>().swap(
2559       mCompositorAnimationsToDelete);  // clear queue
2560 }
2561 
ShouldParentObserveEpoch()2562 bool WebRenderBridgeParent::ShouldParentObserveEpoch() {
2563   if (mParentLayersObserverEpoch == mChildLayersObserverEpoch) {
2564     return false;
2565   }
2566 
2567   mParentLayersObserverEpoch = mChildLayersObserverEpoch;
2568   return true;
2569 }
2570 
SendAsyncMessage(const nsTArray<AsyncParentMessageData> & aMessage)2571 void WebRenderBridgeParent::SendAsyncMessage(
2572     const nsTArray<AsyncParentMessageData>& aMessage) {
2573   MOZ_ASSERT_UNREACHABLE("unexpected to be called");
2574 }
2575 
SendPendingAsyncMessages()2576 void WebRenderBridgeParent::SendPendingAsyncMessages() {
2577   MOZ_ASSERT(mCompositorBridge);
2578   mCompositorBridge->SendPendingAsyncMessages();
2579 }
2580 
SetAboutToSendAsyncMessages()2581 void WebRenderBridgeParent::SetAboutToSendAsyncMessages() {
2582   MOZ_ASSERT(mCompositorBridge);
2583   mCompositorBridge->SetAboutToSendAsyncMessages();
2584 }
2585 
NotifyNotUsed(PTextureParent * aTexture,uint64_t aTransactionId)2586 void WebRenderBridgeParent::NotifyNotUsed(PTextureParent* aTexture,
2587                                           uint64_t aTransactionId) {
2588   MOZ_ASSERT_UNREACHABLE("unexpected to be called");
2589 }
2590 
GetChildProcessId()2591 base::ProcessId WebRenderBridgeParent::GetChildProcessId() {
2592   return OtherPid();
2593 }
2594 
IsSameProcess() const2595 bool WebRenderBridgeParent::IsSameProcess() const {
2596   return OtherPid() == base::GetCurrentProcId();
2597 }
2598 
RecvNewCompositable(const CompositableHandle & aHandle,const TextureInfo & aInfo)2599 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvNewCompositable(
2600     const CompositableHandle& aHandle, const TextureInfo& aInfo) {
2601   if (mDestroyed) {
2602     return IPC_OK();
2603   }
2604   if (!AddCompositable(aHandle, aInfo, /* aUseWebRender */ true)) {
2605     return IPC_FAIL_NO_REASON(this);
2606   }
2607   return IPC_OK();
2608 }
2609 
RecvReleaseCompositable(const CompositableHandle & aHandle)2610 mozilla::ipc::IPCResult WebRenderBridgeParent::RecvReleaseCompositable(
2611     const CompositableHandle& aHandle) {
2612   if (mDestroyed) {
2613     return IPC_OK();
2614   }
2615   ReleaseCompositable(aHandle);
2616   return IPC_OK();
2617 }
2618 
GetTextureFactoryIdentifier()2619 TextureFactoryIdentifier WebRenderBridgeParent::GetTextureFactoryIdentifier() {
2620   MOZ_ASSERT(mApi);
2621 
2622   TextureFactoryIdentifier ident(
2623       mApi->GetBackendType(), mApi->GetCompositorType(), XRE_GetProcessType(),
2624       mApi->GetMaxTextureSize(), false, mApi->GetUseANGLE(),
2625       mApi->GetUseDComp(), mAsyncImageManager->UseCompositorWnd(), false, false,
2626       false, mApi->GetSyncHandle());
2627   return ident;
2628 }
2629 
GetNextWrEpoch()2630 wr::Epoch WebRenderBridgeParent::GetNextWrEpoch() {
2631   MOZ_RELEASE_ASSERT(mWrEpoch.mHandle != UINT32_MAX);
2632   mWrEpoch.mHandle++;
2633   return mWrEpoch;
2634 }
2635 
RollbackWrEpoch()2636 void WebRenderBridgeParent::RollbackWrEpoch() {
2637   MOZ_RELEASE_ASSERT(mWrEpoch.mHandle != 0);
2638   mWrEpoch.mHandle--;
2639 }
2640 
ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo> * aNotifications)2641 void WebRenderBridgeParent::ExtractImageCompositeNotifications(
2642     nsTArray<ImageCompositeNotificationInfo>* aNotifications) {
2643   MOZ_ASSERT(IsRootWebRenderBridgeParent());
2644   if (mDestroyed) {
2645     return;
2646   }
2647   mAsyncImageManager->FlushImageNotifications(aNotifications);
2648 }
2649 
2650 RefPtr<WebRenderBridgeParentRef>
GetWebRenderBridgeParentRef()2651 WebRenderBridgeParent::GetWebRenderBridgeParentRef() {
2652   if (mDestroyed) {
2653     return nullptr;
2654   }
2655 
2656   if (!mWebRenderBridgeRef) {
2657     mWebRenderBridgeRef = new WebRenderBridgeParentRef(this);
2658   }
2659   return mWebRenderBridgeRef;
2660 }
2661 
WebRenderBridgeParentRef(WebRenderBridgeParent * aWebRenderBridge)2662 WebRenderBridgeParentRef::WebRenderBridgeParentRef(
2663     WebRenderBridgeParent* aWebRenderBridge)
2664     : mWebRenderBridge(aWebRenderBridge) {
2665   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2666   MOZ_ASSERT(mWebRenderBridge);
2667 }
2668 
WrBridge()2669 RefPtr<WebRenderBridgeParent> WebRenderBridgeParentRef::WrBridge() {
2670   return mWebRenderBridge;
2671 }
2672 
Clear()2673 void WebRenderBridgeParentRef::Clear() {
2674   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2675   mWebRenderBridge = nullptr;
2676 }
2677 
~WebRenderBridgeParentRef()2678 WebRenderBridgeParentRef::~WebRenderBridgeParentRef() {
2679   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
2680   MOZ_ASSERT(!mWebRenderBridge);
2681 }
2682 
2683 }  // namespace layers
2684 }  // namespace mozilla
2685