Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/wr/WebRenderBridgeParent.cpp
Line
Count
Source (jump to first uncovered line)
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 "gfxPrefs.h"
12
#include "gfxEnv.h"
13
#include "GeckoProfiler.h"
14
#include "GLContext.h"
15
#include "GLContextProvider.h"
16
#include "mozilla/Range.h"
17
#include "mozilla/layers/AnimationHelper.h"
18
#include "mozilla/layers/APZSampler.h"
19
#include "mozilla/layers/APZUpdater.h"
20
#include "mozilla/layers/Compositor.h"
21
#include "mozilla/layers/CompositorBridgeParent.h"
22
#include "mozilla/layers/CompositorThread.h"
23
#include "mozilla/layers/CompositorVsyncScheduler.h"
24
#include "mozilla/layers/ImageBridgeParent.h"
25
#include "mozilla/layers/ImageDataSerializer.h"
26
#include "mozilla/layers/IpcResourceUpdateQueue.h"
27
#include "mozilla/layers/SharedSurfacesParent.h"
28
#include "mozilla/layers/TextureHost.h"
29
#include "mozilla/layers/AsyncImagePipelineManager.h"
30
#include "mozilla/layers/WebRenderImageHost.h"
31
#include "mozilla/layers/WebRenderTextureHost.h"
32
#include "mozilla/Telemetry.h"
33
#include "mozilla/TimeStamp.h"
34
#include "mozilla/Unused.h"
35
#include "mozilla/webrender/RenderThread.h"
36
#include "mozilla/widget/CompositorWidget.h"
37
38
bool is_in_main_thread()
39
0
{
40
0
  return NS_IsMainThread();
41
0
}
42
43
bool is_in_compositor_thread()
44
0
{
45
0
  return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
46
0
}
47
48
bool is_in_render_thread()
49
0
{
50
0
  return mozilla::wr::RenderThread::IsInRenderThread();
51
0
}
52
53
bool is_glcontext_egl(void* glcontext_ptr)
54
0
{
55
0
  MOZ_ASSERT(glcontext_ptr);
56
0
57
0
  mozilla::gl::GLContext* glcontext = reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
58
0
  if (!glcontext) {
59
0
    return false;
60
0
  }
61
0
  return glcontext->GetContextType() == mozilla::gl::GLContextType::EGL;
62
0
}
63
64
bool is_glcontext_angle(void* glcontext_ptr)
65
0
{
66
0
  MOZ_ASSERT(glcontext_ptr);
67
0
68
0
  mozilla::gl::GLContext* glcontext = reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
69
0
  if (!glcontext) {
70
0
    return false;
71
0
  }
72
0
  return glcontext->IsANGLE();
73
0
}
74
75
bool gfx_use_wrench()
76
0
{
77
0
  return gfxEnv::EnableWebRenderRecording();
78
0
}
79
80
const char* gfx_wr_resource_path_override()
81
0
{
82
0
  const char* resourcePath = PR_GetEnv("WR_RESOURCE_PATH");
83
0
  if (!resourcePath || resourcePath[0] == '\0') {
84
0
    return nullptr;
85
0
  }
86
0
  return resourcePath;
87
0
}
88
89
void gfx_critical_note(const char* msg)
90
0
{
91
0
  gfxCriticalNote << msg;
92
0
}
93
94
void gfx_critical_error(const char* msg)
95
0
{
96
0
  gfxCriticalError() << msg;
97
0
}
98
99
void gecko_printf_stderr_output(const char* msg)
100
0
{
101
0
  printf_stderr("%s\n", msg);
102
0
}
103
104
void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname)
105
0
{
106
0
  MOZ_ASSERT(glcontext_ptr);
107
0
108
0
  mozilla::gl::GLContext* glcontext = reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
109
0
  if (!glcontext) {
110
0
    return nullptr;
111
0
  }
112
0
  PRFuncPtr p = glcontext->LookupSymbol(procname);
113
0
  return reinterpret_cast<void*>(p);
114
0
}
115
116
void
117
gecko_profiler_register_thread(const char* name)
118
0
{
119
0
  PROFILER_REGISTER_THREAD(name);
120
0
}
121
122
void
123
gecko_profiler_unregister_thread()
124
0
{
125
0
  PROFILER_UNREGISTER_THREAD();
126
0
}
127
128
void
129
record_telemetry_time(mozilla::wr::TelemetryProbe aProbe, uint64_t aTimeNs)
130
0
{
131
0
  uint32_t time_ms = (uint32_t)(aTimeNs / 1000000);
132
0
  switch (aProbe) {
133
0
    case mozilla::wr::TelemetryProbe::SceneBuildTime:
134
0
      mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_SCENEBUILD_TIME, time_ms);
135
0
      break;
136
0
    case mozilla::wr::TelemetryProbe::SceneSwapTime:
137
0
      mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_SCENESWAP_TIME, time_ms);
138
0
      break;
139
0
    case mozilla::wr::TelemetryProbe::RenderTime:
140
0
      mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_RENDER_TIME, time_ms);
141
0
      break;
142
0
    default:
143
0
      MOZ_ASSERT(false);
144
0
      break;
145
0
  }
146
0
}
147
148
namespace mozilla {
149
150
namespace layers {
151
152
using namespace mozilla::gfx;
153
154
class ScheduleObserveLayersUpdate: public wr::NotificationHandler {
155
public:
156
  ScheduleObserveLayersUpdate(RefPtr<CompositorBridgeParentBase> aBridge,
157
                              LayersId aLayersId,
158
                              LayersObserverEpoch aEpoch,
159
                              bool aIsActive)
160
  : mBridge(aBridge)
161
  , mLayersId(aLayersId)
162
  , mObserverEpoch(aEpoch)
163
  , mIsActive(aIsActive)
164
0
  {}
165
166
0
  virtual void Notify(wr::Checkpoint) override {
167
0
    CompositorThreadHolder::Loop()->PostTask(
168
0
      NewRunnableMethod<LayersId, LayersObserverEpoch, int>(
169
0
        "ObserveLayersUpdate",
170
0
        mBridge, &CompositorBridgeParentBase::ObserveLayersUpdate,
171
0
        mLayersId, mObserverEpoch, mIsActive
172
0
      )
173
0
    );
174
0
  }
175
protected:
176
  RefPtr<CompositorBridgeParentBase> mBridge;
177
  LayersId mLayersId;
178
  LayersObserverEpoch mObserverEpoch;
179
  bool mIsActive;
180
};
181
182
class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender
183
{
184
public:
185
  explicit AutoWebRenderBridgeParentAsyncMessageSender(WebRenderBridgeParent* aWebRenderBridgeParent,
186
                                                       InfallibleTArray<OpDestroy>* aDestroyActors = nullptr)
187
    : mWebRenderBridgeParent(aWebRenderBridgeParent)
188
    , mActorsToDestroy(aDestroyActors)
189
0
  {
190
0
    mWebRenderBridgeParent->SetAboutToSendAsyncMessages();
191
0
  }
192
193
  ~AutoWebRenderBridgeParentAsyncMessageSender()
194
0
  {
195
0
    mWebRenderBridgeParent->SendPendingAsyncMessages();
196
0
    if (mActorsToDestroy) {
197
0
      // Destroy the actors after sending the async messages because the latter may contain
198
0
      // references to some actors.
199
0
      for (const auto& op : *mActorsToDestroy) {
200
0
        mWebRenderBridgeParent->DestroyActor(op);
201
0
      }
202
0
    }
203
0
  }
204
private:
205
  WebRenderBridgeParent* mWebRenderBridgeParent;
206
  InfallibleTArray<OpDestroy>* mActorsToDestroy;
207
};
208
209
WebRenderBridgeParent::WebRenderBridgeParent(CompositorBridgeParentBase* aCompositorBridge,
210
                                             const wr::PipelineId& aPipelineId,
211
                                             widget::CompositorWidget* aWidget,
212
                                             CompositorVsyncScheduler* aScheduler,
213
                                             RefPtr<wr::WebRenderAPI>&& aApi,
214
                                             RefPtr<AsyncImagePipelineManager>&& aImageMgr,
215
                                             RefPtr<CompositorAnimationStorage>&& aAnimStorage,
216
                                             TimeDuration aVsyncRate)
217
  : mCompositorBridge(aCompositorBridge)
218
  , mPipelineId(aPipelineId)
219
  , mWidget(aWidget)
220
  , mApi(aApi)
221
  , mAsyncImageManager(aImageMgr)
222
  , mCompositorScheduler(aScheduler)
223
  , mAnimStorage(aAnimStorage)
224
  , mVsyncRate(aVsyncRate)
225
  , mChildLayersObserverEpoch{0}
226
  , mParentLayersObserverEpoch{0}
227
  , mWrEpoch{0}
228
  , mIdNamespace(aApi->GetNamespace())
229
  , mPaused(false)
230
  , mDestroyed(false)
231
  , mReceivedDisplayList(false)
232
0
{
233
0
  MOZ_ASSERT(mAsyncImageManager);
234
0
  MOZ_ASSERT(mAnimStorage);
235
0
  mAsyncImageManager->AddPipeline(mPipelineId);
236
0
  if (IsRootWebRenderBridgeParent()) {
237
0
    MOZ_ASSERT(!mCompositorScheduler);
238
0
    mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
239
0
  }
240
0
}
241
242
WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId)
243
  : mCompositorBridge(nullptr)
244
  , mPipelineId(aPipelineId)
245
  , mChildLayersObserverEpoch{0}
246
  , mParentLayersObserverEpoch{0}
247
  , mWrEpoch{0}
248
  , mIdNamespace{0}
249
  , mPaused(false)
250
  , mDestroyed(true)
251
  , mReceivedDisplayList(false)
252
0
{
253
0
}
254
255
/* static */ WebRenderBridgeParent*
256
WebRenderBridgeParent::CreateDestroyed(const wr::PipelineId& aPipelineId)
257
0
{
258
0
  return new WebRenderBridgeParent(aPipelineId);
259
0
}
260
261
WebRenderBridgeParent::~WebRenderBridgeParent()
262
0
{
263
0
}
264
265
mozilla::ipc::IPCResult
266
WebRenderBridgeParent::RecvCreate(const gfx::IntSize& aSize)
267
0
{
268
0
  if (mDestroyed) {
269
0
    return IPC_OK();
270
0
  }
271
0
272
0
  MOZ_ASSERT(mApi);
273
0
274
#ifdef MOZ_WIDGET_ANDROID
275
  // XXX temporary hack.
276
  // XXX Remove it when APZ is supported.
277
  // XXX Broken by Dynamic Toolbar v3. See: Bug 1335895
278
//  RefPtr<UiCompositorControllerParent> uiController = UiCompositorControllerParent::GetFromRootLayerTreeId(/* Root Layer Tree ID */);
279
//  if (uiController) {
280
//    uiController->ToolbarAnimatorMessageFromCompositor(/*FIRST_PAINT*/ 5);
281
//  }
282
#endif
283
284
0
  return IPC_OK();
285
0
}
286
287
mozilla::ipc::IPCResult
288
WebRenderBridgeParent::RecvShutdown()
289
0
{
290
0
  return HandleShutdown();
291
0
}
292
293
mozilla::ipc::IPCResult
294
WebRenderBridgeParent::RecvShutdownSync()
295
0
{
296
0
  return HandleShutdown();
297
0
}
298
299
mozilla::ipc::IPCResult
300
WebRenderBridgeParent::HandleShutdown()
301
0
{
302
0
  Destroy();
303
0
  IProtocol* mgr = Manager();
304
0
  if (!Send__delete__(this)) {
305
0
    return IPC_FAIL_NO_REASON(mgr);
306
0
  }
307
0
  return IPC_OK();
308
0
}
309
310
void
311
WebRenderBridgeParent::Destroy()
312
0
{
313
0
  if (mDestroyed) {
314
0
    return;
315
0
  }
316
0
  mDestroyed = true;
317
0
  ClearResources();
318
0
}
319
320
bool
321
WebRenderBridgeParent::UpdateResources(const nsTArray<OpUpdateResource>& aResourceUpdates,
322
                                       const nsTArray<RefCountedShmem>& aSmallShmems,
323
                                       const nsTArray<ipc::Shmem>& aLargeShmems,
324
                                       wr::TransactionBuilder& aUpdates)
325
0
{
326
0
  wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems);
327
0
328
0
  for (const auto& cmd : aResourceUpdates) {
329
0
    switch (cmd.type()) {
330
0
      case OpUpdateResource::TOpAddImage: {
331
0
        const auto& op = cmd.get_OpAddImage();
332
0
        wr::Vec<uint8_t> bytes;
333
0
        if (!reader.Read(op.bytes(), bytes)) {
334
0
          return false;
335
0
        }
336
0
        aUpdates.AddImage(op.key(), op.descriptor(), bytes);
337
0
        break;
338
0
      }
339
0
      case OpUpdateResource::TOpUpdateImage: {
340
0
        const auto& op = cmd.get_OpUpdateImage();
341
0
        wr::Vec<uint8_t> bytes;
342
0
        if (!reader.Read(op.bytes(), bytes)) {
343
0
          return false;
344
0
        }
345
0
        aUpdates.UpdateImageBuffer(op.key(), op.descriptor(), bytes);
346
0
        break;
347
0
      }
348
0
      case OpUpdateResource::TOpAddBlobImage: {
349
0
        const auto& op = cmd.get_OpAddBlobImage();
350
0
        wr::Vec<uint8_t> bytes;
351
0
        if (!reader.Read(op.bytes(), bytes)) {
352
0
          return false;
353
0
        }
354
0
        aUpdates.AddBlobImage(op.key(), op.descriptor(), bytes);
355
0
        break;
356
0
      }
357
0
      case OpUpdateResource::TOpUpdateBlobImage: {
358
0
        const auto& op = cmd.get_OpUpdateBlobImage();
359
0
        wr::Vec<uint8_t> bytes;
360
0
        if (!reader.Read(op.bytes(), bytes)) {
361
0
          return false;
362
0
        }
363
0
        aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes, wr::ToDeviceUintRect(op.dirtyRect()));
364
0
        break;
365
0
      }
366
0
      case OpUpdateResource::TOpSetImageVisibleArea: {
367
0
        const auto& op = cmd.get_OpSetImageVisibleArea();
368
0
        wr::NormalizedRect area;
369
0
        area.origin.x = op.area().x;
370
0
        area.origin.y = op.area().y;
371
0
        area.size.width = op.area().width;
372
0
        area.size.height = op.area().height;
373
0
        aUpdates.SetImageVisibleArea(op.key(), area);
374
0
        break;
375
0
      }
376
0
      case OpUpdateResource::TOpAddExternalImage: {
377
0
        const auto& op = cmd.get_OpAddExternalImage();
378
0
        if (!AddExternalImage(op.externalImageId(), op.key(), aUpdates)) {
379
0
          return false;
380
0
        }
381
0
        break;
382
0
      }
383
0
      case OpUpdateResource::TOpPushExternalImageForTexture: {
384
0
        const auto& op = cmd.get_OpPushExternalImageForTexture();
385
0
        CompositableTextureHostRef texture;
386
0
        texture = TextureHost::AsTextureHost(op.textureParent());
387
0
        if (!PushExternalImageForTexture(op.externalImageId(), op.key(), texture, op.isUpdate(), aUpdates)) {
388
0
          return false;
389
0
        }
390
0
        break;
391
0
      }
392
0
      case OpUpdateResource::TOpUpdateExternalImage: {
393
0
        const auto& op = cmd.get_OpUpdateExternalImage();
394
0
        if (!UpdateExternalImage(op.externalImageId(), op.key(), op.dirtyRect(), aUpdates)) {
395
0
          return false;
396
0
        }
397
0
        break;
398
0
      }
399
0
      case OpUpdateResource::TOpAddRawFont: {
400
0
        const auto& op = cmd.get_OpAddRawFont();
401
0
        wr::Vec<uint8_t> bytes;
402
0
        if (!reader.Read(op.bytes(), bytes)) {
403
0
          return false;
404
0
        }
405
0
        aUpdates.AddRawFont(op.key(), bytes, op.fontIndex());
406
0
        break;
407
0
      }
408
0
      case OpUpdateResource::TOpAddFontDescriptor: {
409
0
        const auto& op = cmd.get_OpAddFontDescriptor();
410
0
        wr::Vec<uint8_t> bytes;
411
0
        if (!reader.Read(op.bytes(), bytes)) {
412
0
          return false;
413
0
        }
414
0
        aUpdates.AddFontDescriptor(op.key(), bytes, op.fontIndex());
415
0
        break;
416
0
      }
417
0
      case OpUpdateResource::TOpAddFontInstance: {
418
0
        const auto& op = cmd.get_OpAddFontInstance();
419
0
        wr::Vec<uint8_t> variations;
420
0
        if (!reader.Read(op.variations(), variations)) {
421
0
            return false;
422
0
        }
423
0
        aUpdates.AddFontInstance(op.instanceKey(), op.fontKey(),
424
0
                                 op.glyphSize(),
425
0
                                 op.options().ptrOr(nullptr),
426
0
                                 op.platformOptions().ptrOr(nullptr),
427
0
                                 variations);
428
0
        break;
429
0
      }
430
0
      case OpUpdateResource::TOpDeleteImage: {
431
0
        const auto& op = cmd.get_OpDeleteImage();
432
0
        aUpdates.DeleteImage(op.key());
433
0
        break;
434
0
      }
435
0
      case OpUpdateResource::TOpDeleteFont: {
436
0
        const auto& op = cmd.get_OpDeleteFont();
437
0
        aUpdates.DeleteFont(op.key());
438
0
        break;
439
0
      }
440
0
      case OpUpdateResource::TOpDeleteFontInstance: {
441
0
        const auto& op = cmd.get_OpDeleteFontInstance();
442
0
        aUpdates.DeleteFontInstance(op.key());
443
0
        break;
444
0
      }
445
0
      case OpUpdateResource::T__None: break;
446
0
    }
447
0
  }
448
0
449
0
  return true;
450
0
}
451
452
bool
453
WebRenderBridgeParent::AddExternalImage(wr::ExternalImageId aExtId, wr::ImageKey aKey,
454
                                        wr::TransactionBuilder& aResources)
455
0
{
456
0
  Range<wr::ImageKey> keys(&aKey, 1);
457
0
  // Check if key is obsoleted.
458
0
  if (keys[0].mNamespace != mIdNamespace) {
459
0
    return true;
460
0
  }
461
0
462
0
  RefPtr<DataSourceSurface> dSurf = SharedSurfacesParent::Acquire(aExtId);
463
0
  if (dSurf) {
464
0
    auto it = mSharedSurfaceIds.emplace(wr::AsUint64(aExtId));
465
0
    if (!it.second) {
466
0
      // We already have a mapping for this image, so decrement the ownership
467
0
      // counter just increased unnecessarily. This can happen when an image is
468
0
      // slow to decode and we need to invalidate it by updating its image key.
469
0
      SharedSurfacesParent::Release(aExtId);
470
0
    }
471
0
472
0
    if (!gfxEnv::EnableWebRenderRecording()) {
473
0
      wr::ImageDescriptor descriptor(dSurf->GetSize(), dSurf->Stride(),
474
0
                                     dSurf->GetFormat());
475
0
      aResources.AddExternalImage(aKey, descriptor, aExtId,
476
0
                                  wr::WrExternalImageBufferType::ExternalBuffer,
477
0
                                  0);
478
0
      return true;
479
0
    }
480
0
  } else {
481
0
    gfxCriticalNote << "DataSourceSurface of SharedSurfaces does not exist for extId:" << wr::AsUint64(aExtId);
482
0
    return false;
483
0
  }
484
0
485
0
  DataSourceSurface::MappedSurface map;
486
0
  if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
487
0
    gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:" << wr::AsUint64(aExtId);
488
0
    return false;
489
0
  }
490
0
491
0
  IntSize size = dSurf->GetSize();
492
0
  wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
493
0
  wr::Vec<uint8_t> data;
494
0
  data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
495
0
  aResources.AddImage(keys[0], descriptor, data);
496
0
  dSurf->Unmap();
497
0
498
0
  return true;
499
0
}
500
501
bool
502
WebRenderBridgeParent::PushExternalImageForTexture(wr::ExternalImageId aExtId,
503
                                                   wr::ImageKey aKey,
504
                                                   TextureHost* aTexture,
505
                                                   bool aIsUpdate,
506
                                                   wr::TransactionBuilder& aResources)
507
0
{
508
0
  auto op = aIsUpdate ? TextureHost::UPDATE_IMAGE : TextureHost::ADD_IMAGE;
509
0
  Range<wr::ImageKey> keys(&aKey, 1);
510
0
  // Check if key is obsoleted.
511
0
  if (keys[0].mNamespace != mIdNamespace) {
512
0
    return true;
513
0
  }
514
0
515
0
  if(!aTexture) {
516
0
    gfxCriticalNote << "TextureHost does not exist for extId:" << wr::AsUint64(aExtId);
517
0
    return false;
518
0
  }
519
0
520
0
  if (!gfxEnv::EnableWebRenderRecording()) {
521
0
    WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
522
0
    if (wrTexture) {
523
0
      wrTexture->PushResourceUpdates(aResources, op, keys,
524
0
                                     wrTexture->GetExternalImageKey());
525
0
      auto it = mTextureHosts.find(wr::AsUint64(aKey));
526
0
      MOZ_ASSERT((it == mTextureHosts.end() && !aIsUpdate) ||
527
0
                 (it != mTextureHosts.end() && aIsUpdate));
528
0
      if (it != mTextureHosts.end()) {
529
0
        // Release Texture if it exists.
530
0
        ReleaseTextureOfImage(aKey);
531
0
      }
532
0
      mTextureHosts.emplace(wr::AsUint64(aKey), CompositableTextureHostRef(aTexture));
533
0
      return true;
534
0
    }
535
0
  }
536
0
  RefPtr<DataSourceSurface> dSurf = aTexture->GetAsSurface();
537
0
  if (!dSurf) {
538
0
    gfxCriticalNote << "TextureHost does not return DataSourceSurface for extId:" << wr::AsUint64(aExtId);
539
0
    return false;
540
0
  }
541
0
542
0
  DataSourceSurface::MappedSurface map;
543
0
  if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
544
0
    gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:" << wr::AsUint64(aExtId);
545
0
    return false;
546
0
  }
547
0
548
0
  IntSize size = dSurf->GetSize();
549
0
  wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
550
0
  wr::Vec<uint8_t> data;
551
0
  data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
552
0
553
0
  if (op == TextureHost::UPDATE_IMAGE) {
554
0
    aResources.UpdateImageBuffer(keys[0], descriptor, data);
555
0
  } else {
556
0
    aResources.AddImage(keys[0], descriptor, data);
557
0
  }
558
0
559
0
  dSurf->Unmap();
560
0
561
0
  return true;
562
0
}
563
564
bool
565
WebRenderBridgeParent::UpdateExternalImage(wr::ExternalImageId aExtId,
566
                                           wr::ImageKey aKey,
567
                                           const ImageIntRect& aDirtyRect,
568
                                           wr::TransactionBuilder& aResources)
569
0
{
570
0
  Range<wr::ImageKey> keys(&aKey, 1);
571
0
  // Check if key is obsoleted.
572
0
  if (keys[0].mNamespace != mIdNamespace) {
573
0
    return true;
574
0
  }
575
0
576
0
  uint64_t imageId = wr::AsUint64(aExtId);
577
0
  if (mSharedSurfaceIds.find(imageId) == mSharedSurfaceIds.end()) {
578
0
    gfxCriticalNote << "Updating unknown shared surface: " << wr::AsUint64(aExtId);
579
0
    return false;
580
0
  }
581
0
582
0
  RefPtr<DataSourceSurface> dSurf = SharedSurfacesParent::Get(aExtId);
583
0
  if (!dSurf) {
584
0
    gfxCriticalNote << "Shared surface does not exist for extId:" << wr::AsUint64(aExtId);
585
0
    return false;
586
0
  }
587
0
588
0
  if (!gfxEnv::EnableWebRenderRecording()) {
589
0
    wr::ImageDescriptor descriptor(dSurf->GetSize(), dSurf->Stride(),
590
0
                                   dSurf->GetFormat());
591
0
    aResources.UpdateExternalImageWithDirtyRect(aKey, descriptor, aExtId,
592
0
                                                wr::WrExternalImageBufferType::ExternalBuffer,
593
0
                                                wr::ToDeviceUintRect(aDirtyRect),
594
0
                                                0);
595
0
    return true;
596
0
  }
597
0
598
0
  DataSourceSurface::ScopedMap map(dSurf, DataSourceSurface::READ);
599
0
  if (!map.IsMapped()) {
600
0
    gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:" << wr::AsUint64(aExtId);
601
0
    return false;
602
0
  }
603
0
604
0
  IntSize size = dSurf->GetSize();
605
0
  wr::ImageDescriptor descriptor(size, map.GetStride(), dSurf->GetFormat());
606
0
  wr::Vec<uint8_t> data;
607
0
  data.PushBytes(Range<uint8_t>(map.GetData(), size.height * map.GetStride()));
608
0
  aResources.UpdateImageBuffer(keys[0], descriptor, data);
609
0
  return true;
610
0
}
611
612
mozilla::ipc::IPCResult
613
WebRenderBridgeParent::RecvUpdateResources(nsTArray<OpUpdateResource>&& aResourceUpdates,
614
                                           nsTArray<RefCountedShmem>&& aSmallShmems,
615
                                           nsTArray<ipc::Shmem>&& aLargeShmems)
616
0
{
617
0
  if (mDestroyed) {
618
0
    return IPC_OK();
619
0
  }
620
0
621
0
  wr::TransactionBuilder txn;
622
0
  txn.SetLowPriority(!IsRootWebRenderBridgeParent());
623
0
624
0
  if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn)) {
625
0
    wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
626
0
    wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
627
0
    IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
628
0
  }
629
0
630
0
  mApi->SendTransaction(txn);
631
0
632
0
  wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
633
0
  wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
634
0
  return IPC_OK();
635
0
}
636
637
mozilla::ipc::IPCResult
638
WebRenderBridgeParent::RecvDeleteCompositorAnimations(InfallibleTArray<uint64_t>&& aIds)
639
0
{
640
0
  if (mDestroyed) {
641
0
    return IPC_OK();
642
0
  }
643
0
644
0
  // Once mWrEpoch has been rendered, we can delete these compositor animations
645
0
  mCompositorAnimationsToDelete.push(CompositorAnimationIdsForEpoch(mWrEpoch, std::move(aIds)));
646
0
  return IPC_OK();
647
0
}
648
649
void
650
WebRenderBridgeParent::RemoveEpochDataPriorTo(const wr::Epoch& aRenderedEpoch)
651
0
{
652
0
  while (!mCompositorAnimationsToDelete.empty()) {
653
0
    if (mCompositorAnimationsToDelete.front().mEpoch.mHandle > aRenderedEpoch.mHandle) {
654
0
      break;
655
0
    }
656
0
    for (uint64_t id : mCompositorAnimationsToDelete.front().mIds) {
657
0
      if (mActiveAnimations.erase(id) > 0) {
658
0
        mAnimStorage->ClearById(id);
659
0
      } else {
660
0
        NS_ERROR("Tried to delete invalid animation");
661
0
      }
662
0
    }
663
0
    mCompositorAnimationsToDelete.pop();
664
0
  }
665
0
}
666
667
bool
668
WebRenderBridgeParent::IsRootWebRenderBridgeParent() const
669
0
{
670
0
  return !!mWidget;
671
0
}
672
673
CompositorBridgeParent*
674
WebRenderBridgeParent::GetRootCompositorBridgeParent() const
675
0
{
676
0
  if (!mCompositorBridge) {
677
0
    return nullptr;
678
0
  }
679
0
680
0
  if (IsRootWebRenderBridgeParent()) {
681
0
    // This WebRenderBridgeParent is attached to the root
682
0
    // CompositorBridgeParent.
683
0
    return static_cast<CompositorBridgeParent*>(mCompositorBridge);
684
0
  }
685
0
686
0
  // Otherwise, this WebRenderBridgeParent is attached to a
687
0
  // CrossProcessCompositorBridgeParent so we have an extra level of
688
0
  // indirection to unravel.
689
0
  CompositorBridgeParent::LayerTreeState* lts =
690
0
      CompositorBridgeParent::GetIndirectShadowTree(GetLayersId());
691
0
  if (!lts) {
692
0
    return nullptr;
693
0
  }
694
0
  return lts->mParent;
695
0
}
696
697
RefPtr<WebRenderBridgeParent>
698
WebRenderBridgeParent::GetRootWebRenderBridgeParent() const
699
0
{
700
0
  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
701
0
  if (!cbp) {
702
0
    return nullptr;
703
0
  }
704
0
705
0
  return cbp->GetWebRenderBridgeParent();
706
0
}
707
708
void
709
WebRenderBridgeParent::UpdateAPZFocusState(const FocusTarget& aFocus)
710
0
{
711
0
  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
712
0
  if (!cbp) {
713
0
    return;
714
0
  }
715
0
  LayersId rootLayersId = cbp->RootLayerTreeId();
716
0
  if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
717
0
    apz->UpdateFocusState(rootLayersId, GetLayersId(), aFocus);
718
0
  }
719
0
}
720
721
void
722
WebRenderBridgeParent::UpdateAPZScrollData(const wr::Epoch& aEpoch,
723
                                           WebRenderScrollData&& aData)
724
0
{
725
0
  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
726
0
  if (!cbp) {
727
0
    return;
728
0
  }
729
0
  LayersId rootLayersId = cbp->RootLayerTreeId();
730
0
  if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
731
0
    apz->UpdateScrollDataAndTreeState(rootLayersId, GetLayersId(), aEpoch, std::move(aData));
732
0
  }
733
0
}
734
735
void
736
WebRenderBridgeParent::UpdateAPZScrollOffsets(ScrollUpdatesMap&& aUpdates,
737
                                              uint32_t aPaintSequenceNumber)
738
0
{
739
0
  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
740
0
  if (!cbp) {
741
0
    return;
742
0
  }
743
0
  LayersId rootLayersId = cbp->RootLayerTreeId();
744
0
  if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
745
0
    apz->UpdateScrollOffsets(rootLayersId, GetLayersId(), std::move(aUpdates), aPaintSequenceNumber);
746
0
  }
747
0
}
748
749
void
750
WebRenderBridgeParent::SetAPZSampleTime()
751
0
{
752
0
  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
753
0
  if (!cbp) {
754
0
    return;
755
0
  }
756
0
  if (RefPtr<APZSampler> apz = cbp->GetAPZSampler()) {
757
0
    TimeStamp animationTime = cbp->GetTestingTimeStamp().valueOr(
758
0
        mCompositorScheduler->GetLastComposeTime());
759
0
    TimeDuration frameInterval = cbp->GetVsyncInterval();
760
0
    // As with the non-webrender codepath in AsyncCompositionManager, we want to
761
0
    // use the timestamp for the next vsync when advancing animations.
762
0
    if (frameInterval != TimeDuration::Forever()) {
763
0
      animationTime += frameInterval;
764
0
    }
765
0
    apz->SetSampleTime(animationTime);
766
0
  }
767
0
}
768
769
mozilla::ipc::IPCResult
770
WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
771
                                          InfallibleTArray<WebRenderParentCommand>&& aCommands,
772
                                          InfallibleTArray<OpDestroy>&& aToDestroy,
773
                                          const uint64_t& aFwdTransactionId,
774
                                          const TransactionId& aTransactionId,
775
                                          const wr::LayoutSize& aContentSize,
776
                                          ipc::ByteBuf&& dl,
777
                                          const wr::BuiltDisplayListDescriptor& dlDesc,
778
                                          const WebRenderScrollData& aScrollData,
779
                                          nsTArray<OpUpdateResource>&& aResourceUpdates,
780
                                          nsTArray<RefCountedShmem>&& aSmallShmems,
781
                                          nsTArray<ipc::Shmem>&& aLargeShmems,
782
                                          const wr::IdNamespace& aIdNamespace,
783
                                          const bool& aContainsSVGGroup,
784
                                          const TimeStamp& aRefreshStartTime,
785
                                          const TimeStamp& aTxnStartTime,
786
                                          const TimeStamp& aFwdTime)
787
0
{
788
0
  if (mDestroyed) {
789
0
    for (const auto& op : aToDestroy) {
790
0
      DestroyActor(op);
791
0
    }
792
0
    return IPC_OK();
793
0
  }
794
0
795
0
  AUTO_PROFILER_TRACING("Paint", "SetDisplayList");
796
0
  UpdateFwdTransactionId(aFwdTransactionId);
797
0
798
0
  // This ensures that destroy operations are always processed. It is not safe
799
0
  // to early-return from RecvDPEnd without doing so.
800
0
  AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
801
0
802
0
  wr::Epoch wrEpoch = GetNextWrEpoch();
803
0
804
0
  mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
805
0
806
0
  // If id namespaces do not match, it means the command is obsolete, probably
807
0
  // because the tab just moved to a new window.
808
0
  // In that case do not send the commands to webrender.
809
0
  bool validTransaction = aIdNamespace == mIdNamespace;
810
0
  wr::TransactionBuilder txn;
811
0
  txn.SetLowPriority(!IsRootWebRenderBridgeParent());
812
0
  Maybe<wr::AutoTransactionSender> sender;
813
0
  if (validTransaction) {
814
0
    sender.emplace(mApi, &txn);
815
0
  }
816
0
817
0
  if (!ProcessWebRenderParentCommands(aCommands, txn)) {
818
0
    return IPC_FAIL(this, "Invalid parent command found");
819
0
  }
820
0
821
0
  if (!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn)) {
822
0
    return IPC_FAIL(this, "Failed to deserialize resource updates");
823
0
  }
824
0
825
0
  mReceivedDisplayList = true;
826
0
827
0
  // aScrollData is moved into this function but that is not reflected by the
828
0
  // function signature due to the way the IPDL generator works. We remove the
829
0
  // const so that we can move this structure all the way to the desired
830
0
  // destination.
831
0
  // Also note that this needs to happen before the display list transaction is
832
0
  // sent to WebRender, so that the UpdateHitTestingTree call is guaranteed to
833
0
  // be in the updater queue at the time that the scene swap completes.
834
0
  UpdateAPZScrollData(wrEpoch, std::move(const_cast<WebRenderScrollData&>(aScrollData)));
835
0
836
0
  wr::Vec<uint8_t> dlData(std::move(dl));
837
0
838
0
  bool observeLayersUpdate = ShouldParentObserveEpoch();
839
0
840
0
  if (validTransaction) {
841
0
    if (IsRootWebRenderBridgeParent()) {
842
0
      LayoutDeviceIntSize widgetSize = mWidget->GetClientSize();
843
0
      LayoutDeviceIntRect docRect(LayoutDeviceIntPoint(), widgetSize);
844
0
      txn.SetWindowParameters(widgetSize, docRect);
845
0
    }
846
0
    gfx::Color clearColor(0.f, 0.f, 0.f, 0.f);
847
0
    txn.SetDisplayList(clearColor, wrEpoch, LayerSize(aSize.width, aSize.height),
848
0
                       mPipelineId, aContentSize,
849
0
                       dlDesc, dlData);
850
0
851
0
    if (observeLayersUpdate) {
852
0
      txn.Notify(
853
0
        wr::Checkpoint::SceneBuilt,
854
0
        MakeUnique<ScheduleObserveLayersUpdate>(
855
0
          mCompositorBridge,
856
0
          GetLayersId(),
857
0
          mChildLayersObserverEpoch,
858
0
          true
859
0
        )
860
0
      );
861
0
    }
862
0
863
0
    mApi->SendTransaction(txn);
864
0
865
0
    // We will schedule generating a frame after the scene
866
0
    // build is done, so we don't need to do it here.
867
0
  } else if (observeLayersUpdate) {
868
0
    mCompositorBridge->ObserveLayersUpdate(GetLayersId(), mChildLayersObserverEpoch, true);
869
0
  }
870
0
871
0
  HoldPendingTransactionId(wrEpoch, aTransactionId, aContainsSVGGroup,
872
0
                           aRefreshStartTime, aTxnStartTime, aFwdTime);
873
0
874
0
  if (!validTransaction) {
875
0
    // Pretend we composited since someone is wating for this event,
876
0
    // though DisplayList was not pushed to webrender.
877
0
    if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
878
0
      TimeStamp now = TimeStamp::Now();
879
0
      cbp->NotifyPipelineRendered(mPipelineId, wrEpoch, now, now);
880
0
    }
881
0
  }
882
0
883
0
  wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
884
0
  wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
885
0
  return IPC_OK();
886
0
}
887
888
mozilla::ipc::IPCResult
889
WebRenderBridgeParent::RecvEmptyTransaction(const FocusTarget& aFocusTarget,
890
                                            const ScrollUpdatesMap& aUpdates,
891
                                            const uint32_t& aPaintSequenceNumber,
892
                                            InfallibleTArray<WebRenderParentCommand>&& aCommands,
893
                                            InfallibleTArray<OpDestroy>&& aToDestroy,
894
                                            const uint64_t& aFwdTransactionId,
895
                                            const TransactionId& aTransactionId,
896
                                            const wr::IdNamespace& aIdNamespace,
897
                                            const TimeStamp& aRefreshStartTime,
898
                                            const TimeStamp& aTxnStartTime,
899
                                            const TimeStamp& aFwdTime)
900
0
{
901
0
  if (mDestroyed) {
902
0
    for (const auto& op : aToDestroy) {
903
0
      DestroyActor(op);
904
0
    }
905
0
    return IPC_OK();
906
0
  }
907
0
908
0
  AUTO_PROFILER_TRACING("Paint", "EmptyTransaction");
909
0
  UpdateFwdTransactionId(aFwdTransactionId);
910
0
911
0
  // This ensures that destroy operations are always processed. It is not safe
912
0
  // to early-return without doing so.
913
0
  AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
914
0
915
0
  bool scheduleComposite = false;
916
0
917
0
  UpdateAPZFocusState(aFocusTarget);
918
0
  if (!aUpdates.empty()) {
919
0
    // aUpdates is moved into this function but that is not reflected by the
920
0
    // function signature due to the way the IPDL generator works. We remove the
921
0
    // const so that we can move this structure all the way to the desired
922
0
    // destination.
923
0
    UpdateAPZScrollOffsets(std::move(const_cast<ScrollUpdatesMap&>(aUpdates)), aPaintSequenceNumber);
924
0
    scheduleComposite = true;
925
0
  }
926
0
927
0
  if (!aCommands.IsEmpty()) {
928
0
    mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
929
0
    wr::TransactionBuilder txn;
930
0
    txn.SetLowPriority(!IsRootWebRenderBridgeParent());
931
0
    wr::Epoch wrEpoch = GetNextWrEpoch();
932
0
    txn.UpdateEpoch(mPipelineId, wrEpoch);
933
0
    if (!ProcessWebRenderParentCommands(aCommands, txn)) {
934
0
      return IPC_FAIL(this, "Invalid parent command found");
935
0
    }
936
0
    if (ShouldParentObserveEpoch()) {
937
0
      txn.Notify(
938
0
        wr::Checkpoint::SceneBuilt,
939
0
        MakeUnique<ScheduleObserveLayersUpdate>(
940
0
          mCompositorBridge,
941
0
          GetLayersId(),
942
0
          mChildLayersObserverEpoch,
943
0
          true
944
0
        )
945
0
      );
946
0
    }
947
0
948
0
    mApi->SendTransaction(txn);
949
0
    scheduleComposite = true;
950
0
  }
951
0
952
0
  bool sendDidComposite = true;
953
0
  if (scheduleComposite || !mPendingTransactionIds.empty()) {
954
0
    // If we are going to kick off a new composite as a result of this
955
0
    // transaction, or if there are already composite-triggering pending
956
0
    // transactions inflight, then set sendDidComposite to false because we will
957
0
    // send the DidComposite message after the composite occurs.
958
0
    // If there are no pending transactions and we're not going to do a
959
0
    // composite, then we leave sendDidComposite as true so we just send
960
0
    // the DidComposite notification now.
961
0
    sendDidComposite = false;
962
0
  }
963
0
964
0
  // Only register a value for CONTENT_FRAME_TIME telemetry if we actually drew
965
0
  // something. It is for consistency with disabling WebRender.
966
0
  HoldPendingTransactionId(mWrEpoch,
967
0
                           aTransactionId,
968
0
                           false,
969
0
                           aRefreshStartTime,
970
0
                           aTxnStartTime,
971
0
                           aFwdTime,
972
0
                           /* aUseForTelemetry */scheduleComposite);
973
0
974
0
  if (scheduleComposite) {
975
0
    ScheduleGenerateFrame();
976
0
  } else if (sendDidComposite) {
977
0
    // The only thing in the pending transaction id queue should be the entry
978
0
    // we just added, and now we're going to pretend we rendered it
979
0
    MOZ_ASSERT(mPendingTransactionIds.size() == 1);
980
0
    if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
981
0
      TimeStamp now = TimeStamp::Now();
982
0
      cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, now, now);
983
0
    }
984
0
  }
985
0
986
0
  return IPC_OK();
987
0
}
988
989
mozilla::ipc::IPCResult
990
WebRenderBridgeParent::RecvSetFocusTarget(const FocusTarget& aFocusTarget)
991
0
{
992
0
  UpdateAPZFocusState(aFocusTarget);
993
0
  return IPC_OK();
994
0
}
995
996
mozilla::ipc::IPCResult
997
WebRenderBridgeParent::RecvParentCommands(nsTArray<WebRenderParentCommand>&& aCommands)
998
0
{
999
0
  if (mDestroyed) {
1000
0
    return IPC_OK();
1001
0
  }
1002
0
  wr::TransactionBuilder txn;
1003
0
  txn.SetLowPriority(!IsRootWebRenderBridgeParent());
1004
0
  if (!ProcessWebRenderParentCommands(aCommands, txn)) {
1005
0
    return IPC_FAIL(this, "Invalid parent command found");
1006
0
  }
1007
0
  mApi->SendTransaction(txn);
1008
0
  return IPC_OK();
1009
0
}
1010
1011
bool
1012
WebRenderBridgeParent::ProcessWebRenderParentCommands(const InfallibleTArray<WebRenderParentCommand>& aCommands,
1013
                                                      wr::TransactionBuilder& aTxn)
1014
0
{
1015
0
  for (InfallibleTArray<WebRenderParentCommand>::index_type i = 0; i < aCommands.Length(); ++i) {
1016
0
    const WebRenderParentCommand& cmd = aCommands[i];
1017
0
    switch (cmd.type()) {
1018
0
      case WebRenderParentCommand::TOpAddPipelineIdForCompositable: {
1019
0
        const OpAddPipelineIdForCompositable& op = cmd.get_OpAddPipelineIdForCompositable();
1020
0
        AddPipelineIdForCompositable(op.pipelineId(),
1021
0
                                     op.handle(),
1022
0
                                     op.isAsync(),
1023
0
                                     aTxn);
1024
0
        break;
1025
0
      }
1026
0
      case WebRenderParentCommand::TOpRemovePipelineIdForCompositable: {
1027
0
        const OpRemovePipelineIdForCompositable& op = cmd.get_OpRemovePipelineIdForCompositable();
1028
0
        RemovePipelineIdForCompositable(op.pipelineId(), aTxn);
1029
0
        break;
1030
0
      }
1031
0
      case WebRenderParentCommand::TOpRemoveExternalImageId: {
1032
0
        const OpRemoveExternalImageId& op = cmd.get_OpRemoveExternalImageId();
1033
0
        RemoveExternalImageId(op.externalImageId());
1034
0
        break;
1035
0
      }
1036
0
      case WebRenderParentCommand::TOpReleaseTextureOfImage: {
1037
0
        const OpReleaseTextureOfImage& op = cmd.get_OpReleaseTextureOfImage();
1038
0
        ReleaseTextureOfImage(op.key());
1039
0
        break;
1040
0
      }
1041
0
      case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
1042
0
        const OpUpdateAsyncImagePipeline& op = cmd.get_OpUpdateAsyncImagePipeline();
1043
0
        mAsyncImageManager->UpdateAsyncImagePipeline(op.pipelineId(),
1044
0
                                                     op.scBounds(),
1045
0
                                                     op.scTransform(),
1046
0
                                                     op.scaleToSize(),
1047
0
                                                     op.filter(),
1048
0
                                                     op.mixBlendMode());
1049
0
        mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn);
1050
0
        break;
1051
0
      }
1052
0
      case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: {
1053
0
        const OpUpdatedAsyncImagePipeline& op = cmd.get_OpUpdatedAsyncImagePipeline();
1054
0
        mAsyncImageManager->ApplyAsyncImageForPipeline(op.pipelineId(), aTxn);
1055
0
        break;
1056
0
      }
1057
0
      case WebRenderParentCommand::TCompositableOperation: {
1058
0
        if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) {
1059
0
          NS_ERROR("ReceiveCompositableUpdate failed");
1060
0
        }
1061
0
        break;
1062
0
      }
1063
0
      case WebRenderParentCommand::TOpAddCompositorAnimations: {
1064
0
        const OpAddCompositorAnimations& op = cmd.get_OpAddCompositorAnimations();
1065
0
        CompositorAnimations data(std::move(op.data()));
1066
0
        // AnimationHelper::GetNextCompositorAnimationsId() encodes the child process PID
1067
0
        // in the upper 32 bits of the id, verify that this is as expected.
1068
0
        if ((data.id() >> 32) != (uint64_t)OtherPid()) {
1069
0
          return false;
1070
0
        }
1071
0
        if (data.animations().Length()) {
1072
0
          mAnimStorage->SetAnimations(data.id(), data.animations());
1073
0
          mActiveAnimations.insert(data.id());
1074
0
        }
1075
0
        break;
1076
0
      }
1077
0
      default: {
1078
0
        // other commands are handle on the child
1079
0
        break;
1080
0
      }
1081
0
    }
1082
0
  }
1083
0
  return true;
1084
0
}
1085
1086
void
1087
WebRenderBridgeParent::FlushSceneBuilds()
1088
0
{
1089
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1090
0
1091
0
  // Since we are sending transactions through the scene builder thread, we need
1092
0
  // to block until all the inflight transactions have been processed. This
1093
0
  // flush message blocks until all previously sent scenes have been built
1094
0
  // and received by the render backend thread.
1095
0
  mApi->FlushSceneBuilder();
1096
0
  // The post-swap hook for async-scene-building calls the
1097
0
  // ScheduleRenderOnCompositorThread function from the scene builder thread,
1098
0
  // which then triggers a call to ScheduleGenerateFrame() on the compositor
1099
0
  // thread. But since *this* function is running on the compositor thread,
1100
0
  // that scheduling will not happen until this call stack unwinds (or we
1101
0
  // could spin a nested event loop, but that's more messy). Instead, we
1102
0
  // simulate it ourselves by calling ScheduleGenerateFrame() directly.
1103
0
  // Note also that the post-swap hook will run and do another
1104
0
  // ScheduleGenerateFrame() after we unwind here, so we will end up with an
1105
0
  // extra render/composite that is probably avoidable, but in practice we
1106
0
  // shouldn't be calling this function all that much in production so this
1107
0
  // is probably fine. If it becomes an issue we can add more state tracking
1108
0
  // machinery to optimize it away.
1109
0
  ScheduleGenerateFrame();
1110
0
}
1111
1112
void
1113
WebRenderBridgeParent::FlushFrameGeneration()
1114
0
{
1115
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1116
0
  MOZ_ASSERT(IsRootWebRenderBridgeParent()); // This function is only useful on the root WRBP
1117
0
1118
0
  // This forces a new GenerateFrame transaction to be sent to the render
1119
0
  // backend thread, if one is pending. This doesn't block on any other threads.
1120
0
  if (mCompositorScheduler->NeedsComposite()) {
1121
0
    mCompositorScheduler->CancelCurrentCompositeTask();
1122
0
    // Update timestamp of scheduler for APZ and animation.
1123
0
    mCompositorScheduler->UpdateLastComposeTime();
1124
0
    MaybeGenerateFrame(/* aForceGenerateFrame */ true);
1125
0
  }
1126
0
}
1127
1128
void
1129
WebRenderBridgeParent::FlushFramePresentation()
1130
0
{
1131
0
  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1132
0
1133
0
  // This sends a message to the render backend thread to send a message
1134
0
  // to the renderer thread, and waits for that message to be processed. So
1135
0
  // this effectively blocks on the render backend and renderer threads,
1136
0
  // following the same codepath that WebRender takes to render and composite
1137
0
  // a frame.
1138
0
  mApi->WaitFlushed();
1139
0
}
1140
1141
mozilla::ipc::IPCResult
1142
WebRenderBridgeParent::RecvGetSnapshot(PTextureParent* aTexture)
1143
0
{
1144
0
  if (mDestroyed) {
1145
0
    return IPC_OK();
1146
0
  }
1147
0
  MOZ_ASSERT(!mPaused);
1148
0
1149
0
  // This function should only get called in the root WRBP. If this function
1150
0
  // gets called in a non-root WRBP, we will set mForceRendering in this WRBP
1151
0
  // but it will have no effect because CompositeToTarget (which reads the
1152
0
  // flag) only gets invoked in the root WRBP. So we assert that this is the
1153
0
  // root WRBP (i.e. has a non-null mWidget) to catch violations of this rule.
1154
0
  MOZ_ASSERT(IsRootWebRenderBridgeParent());
1155
0
1156
0
  RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
1157
0
  if (!texture) {
1158
0
    // We kill the content process rather than have it continue with an invalid
1159
0
    // snapshot, that may be too harsh and we could decide to return some sort
1160
0
    // of error to the child process and let it deal with it...
1161
0
    return IPC_FAIL_NO_REASON(this);
1162
0
  }
1163
0
1164
0
  // XXX Add other TextureHost supports.
1165
0
  // Only BufferTextureHost is supported now.
1166
0
  BufferTextureHost* bufferTexture = texture->AsBufferTextureHost();
1167
0
  if (!bufferTexture) {
1168
0
    // We kill the content process rather than have it continue with an invalid
1169
0
    // snapshot, that may be too harsh and we could decide to return some sort
1170
0
    // of error to the child process and let it deal with it...
1171
0
    return IPC_FAIL_NO_REASON(this);
1172
0
  }
1173
0
1174
0
  TimeStamp start = TimeStamp::Now();
1175
0
  MOZ_ASSERT(bufferTexture->GetBufferDescriptor().type() == BufferDescriptor::TRGBDescriptor);
1176
0
  DebugOnly<uint32_t> stride = ImageDataSerializer::GetRGBStride(bufferTexture->GetBufferDescriptor().get_RGBDescriptor());
1177
0
  uint8_t* buffer = bufferTexture->GetBuffer();
1178
0
  IntSize size = bufferTexture->GetSize();
1179
0
1180
0
  // We only support B8G8R8A8 for now.
1181
0
  MOZ_ASSERT(buffer);
1182
0
  MOZ_ASSERT(bufferTexture->GetFormat() == SurfaceFormat::B8G8R8A8);
1183
0
  uint32_t buffer_size = size.width * size.height * 4;
1184
0
1185
0
  // Assert the stride of the buffer is what webrender expects
1186
0
  MOZ_ASSERT((uint32_t)(size.width * 4) == stride);
1187
0
1188
0
  FlushSceneBuilds();
1189
0
  FlushFrameGeneration();
1190
0
  mApi->Readback(start, size, buffer, buffer_size);
1191
0
1192
0
  return IPC_OK();
1193
0
}
1194
1195
void
1196
WebRenderBridgeParent::AddPipelineIdForCompositable(const wr::PipelineId& aPipelineId,
1197
                                                    const CompositableHandle& aHandle,
1198
                                                    const bool& aAsync,
1199
                                                    wr::TransactionBuilder& aTxn)
1200
0
{
1201
0
  if (mDestroyed) {
1202
0
    return;
1203
0
  }
1204
0
1205
0
  MOZ_ASSERT(mAsyncCompositables.find(wr::AsUint64(aPipelineId)) == mAsyncCompositables.end());
1206
0
1207
0
  RefPtr<CompositableHost> host;
1208
0
  if (aAsync) {
1209
0
    RefPtr<ImageBridgeParent> imageBridge = ImageBridgeParent::GetInstance(OtherPid());
1210
0
    if (!imageBridge) {
1211
0
       return;
1212
0
    }
1213
0
    host = imageBridge->FindCompositable(aHandle);
1214
0
  } else {
1215
0
    host = FindCompositable(aHandle);
1216
0
  }
1217
0
  if (!host) {
1218
0
    return;
1219
0
  }
1220
0
1221
0
  WebRenderImageHost* wrHost = host->AsWebRenderImageHost();
1222
0
  MOZ_ASSERT(wrHost);
1223
0
  if (!wrHost) {
1224
0
    gfxCriticalNote << "Incompatible CompositableHost at WebRenderBridgeParent.";
1225
0
  }
1226
0
1227
0
  if (!wrHost) {
1228
0
    return;
1229
0
  }
1230
0
1231
0
  wrHost->SetWrBridge(this);
1232
0
  wrHost->EnableUseAsyncImagePipeline();
1233
0
  mAsyncCompositables.emplace(wr::AsUint64(aPipelineId), wrHost);
1234
0
  mAsyncImageManager->AddAsyncImagePipeline(aPipelineId, wrHost);
1235
0
1236
0
  // If this is being called from WebRenderBridgeParent::RecvSetDisplayList,
1237
0
  // then aTxn might contain a display list that references pipelines that
1238
0
  // we just added to the async image manager.
1239
0
  // If we send the display list alone then WR will not yet have the content for
1240
0
  // the pipelines and so it will emit errors; the SetEmptyDisplayList call
1241
0
  // below ensure that we provide its content to WR as part of the same transaction.
1242
0
  mAsyncImageManager->SetEmptyDisplayList(aPipelineId, aTxn);
1243
0
  return;
1244
0
}
1245
1246
void
1247
WebRenderBridgeParent::RemovePipelineIdForCompositable(const wr::PipelineId& aPipelineId,
1248
                                                       wr::TransactionBuilder& aTxn)
1249
0
{
1250
0
  if (mDestroyed) {
1251
0
    return;
1252
0
  }
1253
0
1254
0
  auto it = mAsyncCompositables.find(wr::AsUint64(aPipelineId));
1255
0
  if (it == mAsyncCompositables.end()) {
1256
0
    return;
1257
0
  }
1258
0
  RefPtr<WebRenderImageHost>& wrHost = it->second;
1259
0
1260
0
  wrHost->ClearWrBridge();
1261
0
  mAsyncImageManager->RemoveAsyncImagePipeline(aPipelineId, aTxn);
1262
0
  aTxn.RemovePipeline(aPipelineId);
1263
0
  mAsyncCompositables.erase(wr::AsUint64(aPipelineId));
1264
0
  return;
1265
0
}
1266
1267
void
1268
WebRenderBridgeParent::RemoveExternalImageId(const ExternalImageId& aImageId)
1269
0
{
1270
0
  if (mDestroyed) {
1271
0
    return;
1272
0
  }
1273
0
1274
0
  uint64_t imageId = wr::AsUint64(aImageId);
1275
0
  if (mSharedSurfaceIds.find(imageId) != mSharedSurfaceIds.end()) {
1276
0
    mSharedSurfaceIds.erase(imageId);
1277
0
    mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, aImageId);
1278
0
  }
1279
0
}
1280
1281
void
1282
WebRenderBridgeParent::ReleaseTextureOfImage(const wr::ImageKey& aKey)
1283
0
{
1284
0
  if (mDestroyed) {
1285
0
    return;
1286
0
  }
1287
0
1288
0
  uint64_t id = wr::AsUint64(aKey);
1289
0
  CompositableTextureHostRef texture;
1290
0
  WebRenderTextureHost* wrTexture = nullptr;
1291
0
1292
0
  auto it = mTextureHosts.find(id);
1293
0
  if (it != mTextureHosts.end()) {
1294
0
    wrTexture = (*it).second->AsWebRenderTextureHost();
1295
0
  }
1296
0
  if (wrTexture) {
1297
0
    mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, wrTexture);
1298
0
  }
1299
0
  mTextureHosts.erase(id);
1300
0
}
1301
1302
mozilla::ipc::IPCResult
1303
WebRenderBridgeParent::RecvSetLayersObserverEpoch(const LayersObserverEpoch& aChildEpoch)
1304
0
{
1305
0
  if (mDestroyed) {
1306
0
    return IPC_OK();
1307
0
  }
1308
0
  mChildLayersObserverEpoch = aChildEpoch;
1309
0
  return IPC_OK();
1310
0
}
1311
1312
mozilla::ipc::IPCResult
1313
WebRenderBridgeParent::RecvClearCachedResources()
1314
0
{
1315
0
  if (mDestroyed) {
1316
0
    return IPC_OK();
1317
0
  }
1318
0
1319
0
  // Clear resources
1320
0
  wr::TransactionBuilder txn;
1321
0
  txn.SetLowPriority(true);
1322
0
  txn.ClearDisplayList(GetNextWrEpoch(), mPipelineId);
1323
0
  txn.Notify(
1324
0
    wr::Checkpoint::SceneBuilt,
1325
0
    MakeUnique<ScheduleObserveLayersUpdate>(
1326
0
      mCompositorBridge,
1327
0
      GetLayersId(),
1328
0
      mChildLayersObserverEpoch,
1329
0
      false
1330
0
    )
1331
0
  );
1332
0
1333
0
  mApi->SendTransaction(txn);
1334
0
  // Schedule generate frame to clean up Pipeline
1335
0
  ScheduleGenerateFrame();
1336
0
  // Remove animations.
1337
0
  for (const auto& id : mActiveAnimations) {
1338
0
    mAnimStorage->ClearById(id);
1339
0
  }
1340
0
  mActiveAnimations.clear();
1341
0
  std::queue<CompositorAnimationIdsForEpoch>().swap(mCompositorAnimationsToDelete); // clear queue
1342
0
  return IPC_OK();
1343
0
}
1344
1345
wr::Epoch
1346
WebRenderBridgeParent::UpdateWebRender(CompositorVsyncScheduler* aScheduler,
1347
                                       wr::WebRenderAPI* aApi,
1348
                                       AsyncImagePipelineManager* aImageMgr,
1349
                                       CompositorAnimationStorage* aAnimStorage,
1350
                                       const TextureFactoryIdentifier& aTextureFactoryIdentifier)
1351
0
{
1352
0
  MOZ_ASSERT(!IsRootWebRenderBridgeParent());
1353
0
  MOZ_ASSERT(aScheduler);
1354
0
  MOZ_ASSERT(aApi);
1355
0
  MOZ_ASSERT(aImageMgr);
1356
0
  MOZ_ASSERT(aAnimStorage);
1357
0
1358
0
  if (mDestroyed) {
1359
0
    return mWrEpoch;
1360
0
  }
1361
0
1362
0
  // Update id name space to identify obsoleted keys.
1363
0
  // Since usage of invalid keys could cause crash in webrender.
1364
0
  mIdNamespace = aApi->GetNamespace();
1365
0
  // XXX Remove it when webrender supports sharing/moving Keys between different webrender instances.
1366
0
  // XXX It requests client to update/reallocate webrender related resources,
1367
0
  // but parent side does not wait end of the update.
1368
0
  // The code could become simpler if we could serialise old keys deallocation and new keys allocation.
1369
0
  // But we do not do it, it is because client side deallocate old layers/webrender keys
1370
0
  // after new layers/webrender keys allocation.
1371
0
  // Without client side's layout refactoring, we could not finish all old layers/webrender keys removals
1372
0
  // before new layer/webrender keys allocation. In future, we could address the problem.
1373
0
  Unused << SendWrUpdated(mIdNamespace, aTextureFactoryIdentifier);
1374
0
  CompositorBridgeParentBase* cBridge = mCompositorBridge;
1375
0
  // XXX Stop to clear resources if webreder supports resources sharing between different webrender instances.
1376
0
  ClearResources();
1377
0
  mCompositorBridge = cBridge;
1378
0
  mCompositorScheduler = aScheduler;
1379
0
  mApi = aApi;
1380
0
  mAsyncImageManager = aImageMgr;
1381
0
  mAnimStorage = aAnimStorage;
1382
0
1383
0
  // Register pipeline to updated AsyncImageManager.
1384
0
  mAsyncImageManager->AddPipeline(mPipelineId);
1385
0
1386
0
  return GetNextWrEpoch(); // Update webrender epoch
1387
0
}
1388
1389
mozilla::ipc::IPCResult
1390
WebRenderBridgeParent::RecvScheduleComposite()
1391
0
{
1392
0
  if (mDestroyed) {
1393
0
    return IPC_OK();
1394
0
  }
1395
0
  ScheduleGenerateFrame();
1396
0
  return IPC_OK();
1397
0
}
1398
1399
mozilla::ipc::IPCResult
1400
WebRenderBridgeParent::RecvCapture()
1401
0
{
1402
0
  if (!mDestroyed) {
1403
0
    mApi->Capture();
1404
0
  }
1405
0
  return IPC_OK();
1406
0
}
1407
1408
mozilla::ipc::IPCResult
1409
WebRenderBridgeParent::RecvSyncWithCompositor()
1410
0
{
1411
0
  FlushSceneBuilds();
1412
0
  if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
1413
0
    root->FlushFrameGeneration();
1414
0
  }
1415
0
  FlushFramePresentation();
1416
0
  // Finally, we force the AsyncImagePipelineManager to handle all the
1417
0
  // pipeline updates produced in the last step, so that it frees any
1418
0
  // unneeded textures. Then we can return from this sync IPC call knowing
1419
0
  // that we've done everything we can to flush stuff on the compositor.
1420
0
  mAsyncImageManager->ProcessPipelineUpdates();
1421
0
1422
0
  return IPC_OK();
1423
0
}
1424
1425
mozilla::ipc::IPCResult
1426
WebRenderBridgeParent::RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
1427
                                                  nsTArray<ScrollableLayerGuid>&& aTargets)
1428
0
{
1429
0
  if (mDestroyed) {
1430
0
    return IPC_OK();
1431
0
  }
1432
0
  mCompositorBridge->SetConfirmedTargetAPZC(GetLayersId(), aBlockId, aTargets);
1433
0
  return IPC_OK();
1434
0
}
1435
1436
mozilla::ipc::IPCResult
1437
WebRenderBridgeParent::RecvSetTestSampleTime(const TimeStamp& aTime)
1438
0
{
1439
0
  if (!mCompositorBridge->SetTestSampleTime(GetLayersId(), aTime)) {
1440
0
    return IPC_FAIL_NO_REASON(this);
1441
0
  }
1442
0
  return IPC_OK();
1443
0
}
1444
1445
mozilla::ipc::IPCResult
1446
WebRenderBridgeParent::RecvLeaveTestMode()
1447
0
{
1448
0
  mCompositorBridge->LeaveTestMode(GetLayersId());
1449
0
  return IPC_OK();
1450
0
}
1451
1452
mozilla::ipc::IPCResult
1453
WebRenderBridgeParent::RecvGetAnimationValue(const uint64_t& aCompositorAnimationsId,
1454
                                             OMTAValue* aValue)
1455
0
{
1456
0
  if (mDestroyed) {
1457
0
    return IPC_FAIL_NO_REASON(this);
1458
0
  }
1459
0
1460
0
  MOZ_ASSERT(mAnimStorage);
1461
0
  if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
1462
0
    root->AdvanceAnimations();
1463
0
  } else {
1464
0
    AdvanceAnimations();
1465
0
  }
1466
0
1467
0
  *aValue = mAnimStorage->GetOMTAValue(aCompositorAnimationsId);
1468
0
  return IPC_OK();
1469
0
}
1470
1471
mozilla::ipc::IPCResult
1472
WebRenderBridgeParent::RecvSetAsyncScrollOffset(const FrameMetrics::ViewID& aScrollId,
1473
                                                const float& aX,
1474
                                                const float& aY)
1475
0
{
1476
0
  if (mDestroyed) {
1477
0
    return IPC_OK();
1478
0
  }
1479
0
  mCompositorBridge->SetTestAsyncScrollOffset(GetLayersId(), aScrollId, CSSPoint(aX, aY));
1480
0
  return IPC_OK();
1481
0
}
1482
1483
mozilla::ipc::IPCResult
1484
WebRenderBridgeParent::RecvSetAsyncZoom(const FrameMetrics::ViewID& aScrollId,
1485
                                        const float& aZoom)
1486
0
{
1487
0
  if (mDestroyed) {
1488
0
    return IPC_OK();
1489
0
  }
1490
0
  mCompositorBridge->SetTestAsyncZoom(GetLayersId(), aScrollId, LayerToParentLayerScale(aZoom));
1491
0
  return IPC_OK();
1492
0
}
1493
1494
mozilla::ipc::IPCResult
1495
WebRenderBridgeParent::RecvFlushApzRepaints()
1496
0
{
1497
0
  if (mDestroyed) {
1498
0
    return IPC_OK();
1499
0
  }
1500
0
  mCompositorBridge->FlushApzRepaints(GetLayersId());
1501
0
  return IPC_OK();
1502
0
}
1503
1504
mozilla::ipc::IPCResult
1505
WebRenderBridgeParent::RecvGetAPZTestData(APZTestData* aOutData)
1506
0
{
1507
0
  mCompositorBridge->GetAPZTestData(GetLayersId(), aOutData);
1508
0
  return IPC_OK();
1509
0
}
1510
1511
void
1512
WebRenderBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
1513
0
{
1514
0
  Destroy();
1515
0
}
1516
1517
bool
1518
WebRenderBridgeParent::AdvanceAnimations()
1519
0
{
1520
0
  if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
1521
0
    Maybe<TimeStamp> testingTimeStamp = cbp->GetTestingTimeStamp();
1522
0
    if (testingTimeStamp) {
1523
0
      // If we are on testing refresh mode, use the testing time stamp.  And
1524
0
      // also we don't update mPreviousFrameTimeStamp since unlike normal
1525
0
      // refresh mode, on the testing mode animations on the compositor are
1526
0
      // synchronously composed, so we don't need to worry about the time gap
1527
0
      // between the main thread and compositor thread.
1528
0
      return AnimationHelper::SampleAnimations(mAnimStorage,
1529
0
                                               *testingTimeStamp,
1530
0
                                               *testingTimeStamp);
1531
0
    }
1532
0
  }
1533
0
1534
0
  TimeStamp lastComposeTime = mCompositorScheduler->GetLastComposeTime();
1535
0
  const bool isAnimating =
1536
0
    AnimationHelper::SampleAnimations(mAnimStorage,
1537
0
                                      mPreviousFrameTimeStamp,
1538
0
                                      lastComposeTime);
1539
0
1540
0
  // Reset the previous time stamp if we don't already have any running
1541
0
  // animations to avoid using the time which is far behind for newly
1542
0
  // started animations.
1543
0
  mPreviousFrameTimeStamp = isAnimating ? lastComposeTime : TimeStamp();
1544
0
1545
0
  return isAnimating;
1546
0
}
1547
1548
bool
1549
WebRenderBridgeParent::SampleAnimations(nsTArray<wr::WrOpacityProperty>& aOpacityArray,
1550
                                        nsTArray<wr::WrTransformProperty>& aTransformArray)
1551
0
{
1552
0
  const bool isAnimating = AdvanceAnimations();
1553
0
1554
0
  // return the animated data if has
1555
0
  if (mAnimStorage->AnimatedValueCount()) {
1556
0
    for(auto iter = mAnimStorage->ConstAnimatedValueTableIter();
1557
0
        !iter.Done(); iter.Next()) {
1558
0
      AnimatedValue * value = iter.UserData();
1559
0
      if (value->mType == AnimatedValue::TRANSFORM) {
1560
0
        aTransformArray.AppendElement(
1561
0
          wr::ToWrTransformProperty(iter.Key(), value->mTransform.mTransformInDevSpace));
1562
0
      } else if (value->mType == AnimatedValue::OPACITY) {
1563
0
        aOpacityArray.AppendElement(
1564
0
          wr::ToWrOpacityProperty(iter.Key(), value->mOpacity));
1565
0
      }
1566
0
    }
1567
0
  }
1568
0
1569
0
  return isAnimating;
1570
0
}
1571
1572
void
1573
WebRenderBridgeParent::CompositeToTarget(gfx::DrawTarget* aTarget, const gfx::IntRect* aRect)
1574
0
{
1575
0
  // This function should only get called in the root WRBP
1576
0
  MOZ_ASSERT(IsRootWebRenderBridgeParent());
1577
0
1578
0
  // The two arguments are part of the CompositorVsyncSchedulerOwner API but in
1579
0
  // this implementation they should never be non-null.
1580
0
  MOZ_ASSERT(aTarget == nullptr);
1581
0
  MOZ_ASSERT(aRect == nullptr);
1582
0
1583
0
  AUTO_PROFILER_TRACING("Paint", "CompositeToTraget");
1584
0
  if (mPaused || !mReceivedDisplayList) {
1585
0
    mPreviousFrameTimeStamp = TimeStamp();
1586
0
    return;
1587
0
  }
1588
0
1589
0
  if (wr::RenderThread::Get()->TooManyPendingFrames(mApi->GetId())) {
1590
0
    // Render thread is busy, try next time.
1591
0
    mCompositorScheduler->ScheduleComposition();
1592
0
    mPreviousFrameTimeStamp = TimeStamp();
1593
0
    return;
1594
0
  }
1595
0
  MaybeGenerateFrame(/* aForceGenerateFrame */ false);
1596
0
}
1597
1598
void
1599
WebRenderBridgeParent::MaybeGenerateFrame(bool aForceGenerateFrame)
1600
0
{
1601
0
  // This function should only get called in the root WRBP
1602
0
  MOZ_ASSERT(IsRootWebRenderBridgeParent());
1603
0
1604
0
  TimeStamp start = TimeStamp::Now();
1605
0
  mAsyncImageManager->SetCompositionTime(start);
1606
0
1607
0
  // Ensure GenerateFrame is handled on the render backend thread rather
1608
0
  // than going through the scene builder thread. That way we continue generating
1609
0
  // frames with the old scene even during slow scene builds.
1610
0
  bool useSceneBuilderThread = false;
1611
0
  wr::TransactionBuilder fastTxn(useSceneBuilderThread);
1612
0
1613
0
  // Handle transaction that is related to DisplayList.
1614
0
  wr::TransactionBuilder sceneBuilderTxn;
1615
0
  wr::AutoTransactionSender sender(mApi, &sceneBuilderTxn);
1616
0
1617
0
  // Adding and updating wr::ImageKeys of ImageHosts that uses ImageBridge are
1618
0
  // done without using transaction of scene builder thread. With it, updating of
1619
0
  // video frame becomes faster.
1620
0
  mAsyncImageManager->ApplyAsyncImagesOfImageBridge(sceneBuilderTxn, fastTxn);
1621
0
1622
0
  if (!mAsyncImageManager->GetCompositeUntilTime().IsNull()) {
1623
0
    // Trigger another CompositeToTarget() call because there might be another
1624
0
    // frame that we want to generate after this one.
1625
0
    // It will check if we actually want to generate the frame or not.
1626
0
    mCompositorScheduler->ScheduleComposition();
1627
0
  }
1628
0
1629
0
  if (!mAsyncImageManager->GetAndResetWillGenerateFrame() &&
1630
0
      fastTxn.IsEmpty() &&
1631
0
      !aForceGenerateFrame) {
1632
0
    // Could skip generating frame now.
1633
0
    mPreviousFrameTimeStamp = TimeStamp();
1634
0
    return;
1635
0
  }
1636
0
1637
0
  nsTArray<wr::WrOpacityProperty> opacityArray;
1638
0
  nsTArray<wr::WrTransformProperty> transformArray;
1639
0
1640
0
  if (SampleAnimations(opacityArray, transformArray)) {
1641
0
    ScheduleGenerateFrame();
1642
0
  }
1643
0
  // We do this even if the arrays are empty, because it will clear out any
1644
0
  // previous properties store on the WR side, which is desirable.
1645
0
  fastTxn.UpdateDynamicProperties(opacityArray, transformArray);
1646
0
1647
0
  SetAPZSampleTime();
1648
0
1649
0
  wr::RenderThread::Get()->IncPendingFrameCount(mApi->GetId(), start);
1650
0
1651
#if defined(ENABLE_FRAME_LATENCY_LOG)
1652
  auto startTime = TimeStamp::Now();
1653
  mApi->SetFrameStartTime(startTime);
1654
#endif
1655
1656
0
  fastTxn.GenerateFrame();
1657
0
1658
0
  mApi->SendTransaction(fastTxn);
1659
0
}
1660
1661
void
1662
WebRenderBridgeParent::HoldPendingTransactionId(const wr::Epoch& aWrEpoch,
1663
                                                TransactionId aTransactionId,
1664
                                                bool aContainsSVGGroup,
1665
                                                const TimeStamp& aRefreshStartTime,
1666
                                                const TimeStamp& aTxnStartTime,
1667
                                                const TimeStamp& aFwdTime,
1668
                                                const bool aUseForTelemetry)
1669
0
{
1670
0
  MOZ_ASSERT(aTransactionId > LastPendingTransactionId());
1671
0
  mPendingTransactionIds.push(PendingTransactionId(aWrEpoch,
1672
0
                                                   aTransactionId,
1673
0
                                                   aContainsSVGGroup,
1674
0
                                                   aRefreshStartTime,
1675
0
                                                   aTxnStartTime,
1676
0
                                                   aFwdTime,
1677
0
                                                   aUseForTelemetry));
1678
0
}
1679
1680
TransactionId
1681
WebRenderBridgeParent::LastPendingTransactionId()
1682
0
{
1683
0
  TransactionId id{0};
1684
0
  if (!mPendingTransactionIds.empty()) {
1685
0
    id = mPendingTransactionIds.back().mId;
1686
0
  }
1687
0
  return id;
1688
0
}
1689
1690
TransactionId
1691
WebRenderBridgeParent::FlushTransactionIdsForEpoch(const wr::Epoch& aEpoch, const TimeStamp& aEndTime)
1692
0
{
1693
0
  TransactionId id{0};
1694
0
  while (!mPendingTransactionIds.empty()) {
1695
0
    const auto& transactionId = mPendingTransactionIds.front();
1696
0
1697
0
    if (aEpoch.mHandle < transactionId.mEpoch.mHandle) {
1698
0
      break;
1699
0
    }
1700
0
1701
0
    if (!IsRootWebRenderBridgeParent() && !mVsyncRate.IsZero() && transactionId.mUseForTelemetry) {
1702
0
      double latencyMs = (aEndTime - transactionId.mTxnStartTime).ToMilliseconds();
1703
0
      double latencyNorm = latencyMs / mVsyncRate.ToMilliseconds();
1704
0
      int32_t fracLatencyNorm = lround(latencyNorm * 100.0);
1705
0
      Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME, fracLatencyNorm);
1706
0
      if (transactionId.mContainsSVGGroup) {
1707
0
        Telemetry::Accumulate(Telemetry::CONTENT_FRAME_TIME_WITH_SVG, fracLatencyNorm);
1708
0
      }
1709
0
    }
1710
0
1711
#if defined(ENABLE_FRAME_LATENCY_LOG)
1712
    if (transactionId.mRefreshStartTime) {
1713
      int32_t latencyMs = lround((aEndTime - transactionId.mRefreshStartTime).ToMilliseconds());
1714
      printf_stderr("From transaction start to end of generate frame latencyMs %d this %p\n", latencyMs, this);
1715
    }
1716
    if (transactionId.mFwdTime) {
1717
      int32_t latencyMs = lround((aEndTime - transactionId.mFwdTime).ToMilliseconds());
1718
      printf_stderr("From forwarding transaction to end of generate frame latencyMs %d this %p\n", latencyMs, this);
1719
    }
1720
#endif
1721
    id = transactionId.mId;
1722
0
    mPendingTransactionIds.pop();
1723
0
  }
1724
0
  return id;
1725
0
}
1726
1727
LayersId
1728
WebRenderBridgeParent::GetLayersId() const
1729
0
{
1730
0
  return wr::AsLayersId(mPipelineId);
1731
0
}
1732
1733
void
1734
WebRenderBridgeParent::ScheduleGenerateFrame()
1735
0
{
1736
0
  if (mCompositorScheduler) {
1737
0
    mAsyncImageManager->SetWillGenerateFrame();
1738
0
    mCompositorScheduler->ScheduleComposition();
1739
0
  }
1740
0
}
1741
1742
void
1743
WebRenderBridgeParent::FlushRendering(bool aWaitForPresent)
1744
0
{
1745
0
  if (mDestroyed) {
1746
0
    return;
1747
0
  }
1748
0
1749
0
  // This gets called during e.g. window resizes, so we need to flush the
1750
0
  // scene (which has the display list at the new window size).
1751
0
  FlushSceneBuilds();
1752
0
  FlushFrameGeneration();
1753
0
  if (aWaitForPresent) {
1754
0
    FlushFramePresentation();
1755
0
  }
1756
0
}
1757
1758
void
1759
WebRenderBridgeParent::Pause()
1760
0
{
1761
0
  MOZ_ASSERT(IsRootWebRenderBridgeParent());
1762
#ifdef MOZ_WIDGET_ANDROID
1763
  if (!IsRootWebRenderBridgeParent() || mDestroyed) {
1764
    return;
1765
  }
1766
  mApi->Pause();
1767
#endif
1768
  mPaused = true;
1769
0
}
1770
1771
bool
1772
WebRenderBridgeParent::Resume()
1773
0
{
1774
0
  MOZ_ASSERT(IsRootWebRenderBridgeParent());
1775
#ifdef MOZ_WIDGET_ANDROID
1776
  if (!IsRootWebRenderBridgeParent() || mDestroyed) {
1777
    return false;
1778
  }
1779
1780
  if (!mApi->Resume()) {
1781
    return false;
1782
  }
1783
#endif
1784
  mPaused = false;
1785
0
  return true;
1786
0
}
1787
1788
void
1789
WebRenderBridgeParent::ClearResources()
1790
0
{
1791
0
  if (!mApi) {
1792
0
    return;
1793
0
  }
1794
0
1795
0
  wr::Epoch wrEpoch = GetNextWrEpoch();
1796
0
1797
0
  wr::TransactionBuilder txn;
1798
0
  txn.SetLowPriority(true);
1799
0
  txn.ClearDisplayList(wrEpoch, mPipelineId);
1800
0
  mReceivedDisplayList = false;
1801
0
1802
0
  // Schedule generate frame to clean up Pipeline
1803
0
  ScheduleGenerateFrame();
1804
0
  // WrFontKeys and WrImageKeys are deleted during WebRenderAPI destruction.
1805
0
  for (const auto& entry : mTextureHosts) {
1806
0
    WebRenderTextureHost* wrTexture = entry.second->AsWebRenderTextureHost();
1807
0
    MOZ_ASSERT(wrTexture);
1808
0
    if (wrTexture) {
1809
0
      mAsyncImageManager->HoldExternalImage(mPipelineId, wrEpoch, wrTexture);
1810
0
    }
1811
0
  }
1812
0
  mTextureHosts.clear();
1813
0
  for (const auto& entry : mAsyncCompositables) {
1814
0
    wr::PipelineId pipelineId = wr::AsPipelineId(entry.first);
1815
0
    RefPtr<WebRenderImageHost> host = entry.second;
1816
0
    host->ClearWrBridge();
1817
0
    mAsyncImageManager->RemoveAsyncImagePipeline(pipelineId, txn);
1818
0
    txn.RemovePipeline(pipelineId);
1819
0
  }
1820
0
  mAsyncCompositables.clear();
1821
0
  for (const auto& entry : mSharedSurfaceIds) {
1822
0
    wr::ExternalImageId id = wr::ToExternalImageId(entry);
1823
0
    mAsyncImageManager->HoldExternalImage(mPipelineId, mWrEpoch, id);
1824
0
  }
1825
0
  mSharedSurfaceIds.clear();
1826
0
1827
0
  mAsyncImageManager->RemovePipeline(mPipelineId, wrEpoch);
1828
0
  txn.RemovePipeline(mPipelineId);
1829
0
1830
0
  mApi->SendTransaction(txn);
1831
0
1832
0
  for (const auto& id : mActiveAnimations) {
1833
0
    mAnimStorage->ClearById(id);
1834
0
  }
1835
0
  mActiveAnimations.clear();
1836
0
  std::queue<CompositorAnimationIdsForEpoch>().swap(mCompositorAnimationsToDelete); // clear queue
1837
0
1838
0
  if (IsRootWebRenderBridgeParent()) {
1839
0
    mCompositorScheduler->Destroy();
1840
0
  }
1841
0
1842
0
  // Before tearing down mApi we should make sure the above transaction has been
1843
0
  // flushed back to the render backend thread. Otherwise the cleanup messages
1844
0
  // that the WebRenderAPI destructor triggers can race ahead of the transaction
1845
0
  // (because it goes directly to the RB thread, bypassing the scene builder
1846
0
  // thread) and clear caches etc. that are still in use.
1847
0
  FlushSceneBuilds();
1848
0
1849
0
  mAnimStorage = nullptr;
1850
0
  mCompositorScheduler = nullptr;
1851
0
  mAsyncImageManager = nullptr;
1852
0
  mApi = nullptr;
1853
0
  mCompositorBridge = nullptr;
1854
0
}
1855
1856
bool
1857
WebRenderBridgeParent::ShouldParentObserveEpoch()
1858
0
{
1859
0
  if (mParentLayersObserverEpoch == mChildLayersObserverEpoch) {
1860
0
    return false;
1861
0
  }
1862
0
1863
0
  mParentLayersObserverEpoch = mChildLayersObserverEpoch;
1864
0
  return true;
1865
0
}
1866
1867
void
1868
WebRenderBridgeParent::SendAsyncMessage(const InfallibleTArray<AsyncParentMessageData>& aMessage)
1869
0
{
1870
0
  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1871
0
}
1872
1873
void
1874
WebRenderBridgeParent::SendPendingAsyncMessages()
1875
0
{
1876
0
  MOZ_ASSERT(mCompositorBridge);
1877
0
  mCompositorBridge->SendPendingAsyncMessages();
1878
0
}
1879
1880
void
1881
WebRenderBridgeParent::SetAboutToSendAsyncMessages()
1882
0
{
1883
0
  MOZ_ASSERT(mCompositorBridge);
1884
0
  mCompositorBridge->SetAboutToSendAsyncMessages();
1885
0
}
1886
1887
void
1888
WebRenderBridgeParent::NotifyNotUsed(PTextureParent* aTexture, uint64_t aTransactionId)
1889
0
{
1890
0
  MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1891
0
}
1892
1893
base::ProcessId
1894
WebRenderBridgeParent::GetChildProcessId()
1895
0
{
1896
0
  return OtherPid();
1897
0
}
1898
1899
bool
1900
WebRenderBridgeParent::IsSameProcess() const
1901
0
{
1902
0
  return OtherPid() == base::GetCurrentProcId();
1903
0
}
1904
1905
mozilla::ipc::IPCResult
1906
WebRenderBridgeParent::RecvNewCompositable(const CompositableHandle& aHandle,
1907
                                           const TextureInfo& aInfo)
1908
0
{
1909
0
  if (mDestroyed) {
1910
0
    return IPC_OK();
1911
0
  }
1912
0
  if (!AddCompositable(aHandle, aInfo, /* aUseWebRender */ true)) {
1913
0
    return IPC_FAIL_NO_REASON(this);
1914
0
  }
1915
0
  return IPC_OK();
1916
0
}
1917
1918
mozilla::ipc::IPCResult
1919
WebRenderBridgeParent::RecvReleaseCompositable(const CompositableHandle& aHandle)
1920
0
{
1921
0
  if (mDestroyed) {
1922
0
    return IPC_OK();
1923
0
  }
1924
0
  ReleaseCompositable(aHandle);
1925
0
  return IPC_OK();
1926
0
}
1927
1928
TextureFactoryIdentifier
1929
WebRenderBridgeParent::GetTextureFactoryIdentifier()
1930
0
{
1931
0
  MOZ_ASSERT(mApi);
1932
0
1933
0
  return TextureFactoryIdentifier(LayersBackend::LAYERS_WR,
1934
0
                                  XRE_GetProcessType(),
1935
0
                                  mApi->GetMaxTextureSize(),
1936
0
                                  false,
1937
0
                                  mApi->GetUseANGLE(),
1938
0
                                  mApi->GetUseDComp(),
1939
0
                                  false,
1940
0
                                  false,
1941
0
                                  false,
1942
0
                                  mApi->GetSyncHandle());
1943
0
}
1944
1945
wr::Epoch
1946
WebRenderBridgeParent::GetNextWrEpoch()
1947
0
{
1948
0
  MOZ_RELEASE_ASSERT(mWrEpoch.mHandle != UINT32_MAX);
1949
0
  mWrEpoch.mHandle++;
1950
0
  return mWrEpoch;
1951
0
}
1952
1953
void
1954
WebRenderBridgeParent::ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications)
1955
0
{
1956
0
  MOZ_ASSERT(IsRootWebRenderBridgeParent());
1957
0
  if (mDestroyed) {
1958
0
    return;
1959
0
  }
1960
0
  mAsyncImageManager->FlushImageNotifications(aNotifications);
1961
0
}
1962
1963
} // namespace layers
1964
} // namespace mozilla