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