Source code

Revision control

Other Tools

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 "gfxEnv.h"
12
#include "GeckoProfiler.h"
13
#include "GLContext.h"
14
#include "GLContextProvider.h"
15
#include "nsExceptionHandler.h"
16
#include "mozilla/Range.h"
17
#include "mozilla/StaticPrefs_gfx.h"
18
#include "mozilla/UniquePtr.h"
19
#include "mozilla/layers/AnimationHelper.h"
20
#include "mozilla/layers/APZSampler.h"
21
#include "mozilla/layers/APZUpdater.h"
22
#include "mozilla/layers/Compositor.h"
23
#include "mozilla/layers/CompositorBridgeParent.h"
24
#include "mozilla/layers/CompositorThread.h"
25
#include "mozilla/layers/CompositorVsyncScheduler.h"
26
#include "mozilla/layers/ImageBridgeParent.h"
27
#include "mozilla/layers/ImageDataSerializer.h"
28
#include "mozilla/layers/IpcResourceUpdateQueue.h"
29
#include "mozilla/layers/SharedSurfacesParent.h"
30
#include "mozilla/layers/TextureHost.h"
31
#include "mozilla/layers/AsyncImagePipelineManager.h"
32
#include "mozilla/layers/WebRenderImageHost.h"
33
#include "mozilla/layers/WebRenderTextureHost.h"
34
#include "mozilla/Telemetry.h"
35
#include "mozilla/TimeStamp.h"
36
#include "mozilla/Unused.h"
37
#include "mozilla/webrender/RenderThread.h"
38
#include "mozilla/widget/CompositorWidget.h"
39
40
#ifdef MOZ_GECKO_PROFILER
41
# include "ProfilerMarkerPayload.h"
42
#endif
43
44
bool is_in_main_thread() { return NS_IsMainThread(); }
45
46
bool is_in_compositor_thread() {
47
return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
48
}
49
50
bool is_in_render_thread() {
51
return mozilla::wr::RenderThread::IsInRenderThread();
52
}
53
54
void gecko_profiler_start_marker(const char* name) {
55
#ifdef MOZ_GECKO_PROFILER
56
profiler_tracing("WebRender", name, JS::ProfilingCategoryPair::GRAPHICS,
57
TRACING_INTERVAL_START);
58
#endif
59
}
60
61
void gecko_profiler_end_marker(const char* name) {
62
#ifdef MOZ_GECKO_PROFILER
63
profiler_tracing("WebRender", name, JS::ProfilingCategoryPair::GRAPHICS,
64
TRACING_INTERVAL_END);
65
#endif
66
}
67
68
void gecko_profiler_add_text_marker(const char* name, const char* text_bytes,
69
size_t text_len, uint64_t microseconds) {
70
#ifdef MOZ_GECKO_PROFILER
71
if (profiler_thread_is_being_profiled()) {
72
auto now = mozilla::TimeStamp::NowUnfuzzed();
73
auto start = now - mozilla::TimeDuration::FromMicroseconds(microseconds);
74
profiler_add_text_marker(name, nsDependentCSubstring(text_bytes, text_len),
75
JS::ProfilingCategoryPair::GRAPHICS, start, now);
76
}
77
#endif
78
}
79
80
bool gecko_profiler_thread_is_being_profiled() {
81
#ifdef MOZ_GECKO_PROFILER
82
return profiler_thread_is_being_profiled();
83
#else
84
return false;
85
#endif
86
}
87
88
bool is_glcontext_gles(void* const glcontext_ptr) {
89
MOZ_RELEASE_ASSERT(glcontext_ptr);
90
return reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr)->IsGLES();
91
}
92
93
bool is_glcontext_angle(void* glcontext_ptr) {
94
MOZ_ASSERT(glcontext_ptr);
95
96
mozilla::gl::GLContext* glcontext =
97
reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
98
if (!glcontext) {
99
return false;
100
}
101
return glcontext->IsANGLE();
102
}
103
104
bool gfx_use_wrench() { return gfxEnv::EnableWebRenderRecording(); }
105
106
const char* gfx_wr_resource_path_override() {
107
const char* resourcePath = PR_GetEnv("WR_RESOURCE_PATH");
108
if (!resourcePath || resourcePath[0] == '\0') {
109
return nullptr;
110
}
111
return resourcePath;
112
}
113
114
void gfx_critical_note(const char* msg) { gfxCriticalNote << msg; }
115
116
void gfx_critical_error(const char* msg) { gfxCriticalError() << msg; }
117
118
void gecko_printf_stderr_output(const char* msg) { printf_stderr("%s\n", msg); }
119
120
void* get_proc_address_from_glcontext(void* glcontext_ptr,
121
const char* procname) {
122
mozilla::gl::GLContext* glcontext =
123
reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
124
MOZ_ASSERT(glcontext);
125
if (!glcontext) {
126
return nullptr;
127
}
128
const auto& loader = glcontext->GetSymbolLoader();
129
MOZ_ASSERT(loader);
130
131
const auto ret = loader->GetProcAddress(procname);
132
return reinterpret_cast<void*>(ret);
133
}
134
135
void gecko_profiler_register_thread(const char* name) {
136
PROFILER_REGISTER_THREAD(name);
137
}
138
139
void gecko_profiler_unregister_thread() { PROFILER_UNREGISTER_THREAD(); }
140
141
void record_telemetry_time(mozilla::wr::TelemetryProbe aProbe,
142
uint64_t aTimeNs) {
143
uint32_t time_ms = (uint32_t)(aTimeNs / 1000000);
144
switch (aProbe) {
145
case mozilla::wr::TelemetryProbe::SceneBuildTime:
146
mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_SCENEBUILD_TIME,
147
time_ms);
148
break;
149
case mozilla::wr::TelemetryProbe::SceneSwapTime:
150
mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_SCENESWAP_TIME,
151
time_ms);
152
break;
153
case mozilla::wr::TelemetryProbe::RenderTime:
154
mozilla::Telemetry::Accumulate(mozilla::Telemetry::WR_RENDER_TIME,
155
time_ms);
156
break;
157
default:
158
MOZ_ASSERT(false);
159
break;
160
}
161
}
162
163
namespace mozilla {
164
165
namespace layers {
166
167
using namespace mozilla::gfx;
168
169
class ScheduleObserveLayersUpdate : public wr::NotificationHandler {
170
public:
171
ScheduleObserveLayersUpdate(RefPtr<CompositorBridgeParentBase> aBridge,
172
LayersId aLayersId, LayersObserverEpoch aEpoch,
173
bool aIsActive)
174
: mBridge(aBridge),
175
mLayersId(aLayersId),
176
mObserverEpoch(aEpoch),
177
mIsActive(aIsActive) {}
178
179
void Notify(wr::Checkpoint) override {
180
CompositorThreadHolder::Loop()->PostTask(
181
NewRunnableMethod<LayersId, LayersObserverEpoch, int>(
182
"ObserveLayersUpdate", mBridge,
183
&CompositorBridgeParentBase::ObserveLayersUpdate, mLayersId,
184
mObserverEpoch, mIsActive));
185
}
186
187
protected:
188
RefPtr<CompositorBridgeParentBase> mBridge;
189
LayersId mLayersId;
190
LayersObserverEpoch mObserverEpoch;
191
bool mIsActive;
192
};
193
194
class SceneBuiltNotification : public wr::NotificationHandler {
195
public:
196
SceneBuiltNotification(WebRenderBridgeParent* aParent, wr::Epoch aEpoch,
197
TimeStamp aTxnStartTime)
198
: mParent(aParent), mEpoch(aEpoch), mTxnStartTime(aTxnStartTime) {}
199
200
void Notify(wr::Checkpoint) override {
201
auto startTime = this->mTxnStartTime;
202
RefPtr<WebRenderBridgeParent> parent = mParent;
203
wr::Epoch epoch = mEpoch;
204
CompositorThreadHolder::Loop()->PostTask(NS_NewRunnableFunction(
205
"SceneBuiltNotificationRunnable", [parent, epoch, startTime]() {
206
auto endTime = TimeStamp::Now();
207
#ifdef MOZ_GECKO_PROFILER
208
if (profiler_is_active()) {
209
class ContentFullPaintPayload : public ProfilerMarkerPayload {
210
public:
211
ContentFullPaintPayload(const mozilla::TimeStamp& aStartTime,
212
const mozilla::TimeStamp& aEndTime)
213
: ProfilerMarkerPayload(aStartTime, aEndTime) {}
214
void StreamPayload(SpliceableJSONWriter& aWriter,
215
const TimeStamp& aProcessStartTime,
216
UniqueStacks& aUniqueStacks) override {
217
StreamCommonProps("CONTENT_FULL_PAINT_TIME", aWriter,
218
aProcessStartTime, aUniqueStacks);
219
}
220
};
221
222
AUTO_PROFILER_STATS(add_marker_with_ContentFullPaintPayload);
223
profiler_add_marker_for_thread(
224
profiler_current_thread_id(),
225
JS::ProfilingCategoryPair::GRAPHICS, "CONTENT_FULL_PAINT_TIME",
226
MakeUnique<ContentFullPaintPayload>(startTime, endTime));
227
}
228
#endif
229
Telemetry::Accumulate(
230
Telemetry::CONTENT_FULL_PAINT_TIME,
231
static_cast<uint32_t>((endTime - startTime).ToMilliseconds()));
232
parent->NotifySceneBuiltForEpoch(epoch, endTime);
233
}));
234
}
235
236
protected:
237
RefPtr<WebRenderBridgeParent> mParent;
238
wr::Epoch mEpoch;
239
TimeStamp mTxnStartTime;
240
};
241
242
class WebRenderBridgeParent::ScheduleSharedSurfaceRelease final
243
: public wr::NotificationHandler {
244
public:
245
explicit ScheduleSharedSurfaceRelease(WebRenderBridgeParent* aWrBridge)
246
: mWrBridge(aWrBridge), mSurfaces(20) {}
247
248
void Add(const wr::ImageKey& aKey, const wr::ExternalImageId& aId) {
249
mSurfaces.AppendElement(wr::ExternalImageKeyPair{aKey, aId});
250
}
251
252
void Notify(wr::Checkpoint) override {
253
CompositorThreadHolder::Loop()->PostTask(
254
NewRunnableMethod<nsTArray<wr::ExternalImageKeyPair>>(
255
"ObserveSharedSurfaceRelease", mWrBridge,
256
&WebRenderBridgeParent::ObserveSharedSurfaceRelease,
257
std::move(mSurfaces)));
258
}
259
260
private:
261
RefPtr<WebRenderBridgeParent> mWrBridge;
262
nsTArray<wr::ExternalImageKeyPair> mSurfaces;
263
};
264
265
class MOZ_STACK_CLASS AutoWebRenderBridgeParentAsyncMessageSender final {
266
public:
267
explicit AutoWebRenderBridgeParentAsyncMessageSender(
268
WebRenderBridgeParent* aWebRenderBridgeParent,
269
nsTArray<OpDestroy>* aDestroyActors = nullptr)
270
: mWebRenderBridgeParent(aWebRenderBridgeParent),
271
mActorsToDestroy(aDestroyActors) {
272
mWebRenderBridgeParent->SetAboutToSendAsyncMessages();
273
}
274
275
~AutoWebRenderBridgeParentAsyncMessageSender() {
276
mWebRenderBridgeParent->SendPendingAsyncMessages();
277
if (mActorsToDestroy) {
278
// Destroy the actors after sending the async messages because the latter
279
// may contain references to some actors.
280
for (const auto& op : *mActorsToDestroy) {
281
mWebRenderBridgeParent->DestroyActor(op);
282
}
283
}
284
}
285
286
private:
287
WebRenderBridgeParent* mWebRenderBridgeParent;
288
nsTArray<OpDestroy>* mActorsToDestroy;
289
};
290
291
WebRenderBridgeParent::WebRenderBridgeParent(
292
CompositorBridgeParentBase* aCompositorBridge,
293
const wr::PipelineId& aPipelineId, widget::CompositorWidget* aWidget,
294
CompositorVsyncScheduler* aScheduler,
295
nsTArray<RefPtr<wr::WebRenderAPI>>&& aApis,
296
RefPtr<AsyncImagePipelineManager>&& aImageMgr,
297
RefPtr<CompositorAnimationStorage>&& aAnimStorage, TimeDuration aVsyncRate)
298
: mCompositorBridge(aCompositorBridge),
299
mPipelineId(aPipelineId),
300
mWidget(aWidget),
301
mAsyncImageManager(aImageMgr),
302
mCompositorScheduler(aScheduler),
303
mAnimStorage(aAnimStorage),
304
mVsyncRate(aVsyncRate),
305
mChildLayersObserverEpoch{0},
306
mParentLayersObserverEpoch{0},
307
mWrEpoch{0},
308
mIdNamespace(aApis[0]->GetNamespace()),
309
mRenderRootRectMutex("WebRenderBridgeParent::mRenderRootRectMutex"),
310
mPaused(false),
311
mDestroyed(false),
312
mReceivedDisplayList(false),
313
mIsFirstPaint(true),
314
mSkippedComposite(false) {
315
MOZ_ASSERT(mAsyncImageManager);
316
MOZ_ASSERT(mAnimStorage);
317
mAsyncImageManager->AddPipeline(mPipelineId, this);
318
if (IsRootWebRenderBridgeParent()) {
319
MOZ_ASSERT(!mCompositorScheduler);
320
mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
321
}
322
323
if (IsRootWebRenderBridgeParent() ||
324
!StaticPrefs::gfx_webrender_split_render_roots_AtStartup()) {
325
mRenderRoot = Some(wr::RenderRoot::Default);
326
}
327
328
for (auto& api : aApis) {
329
MOZ_ASSERT(api);
330
mApis[api->GetRenderRoot()] = api;
331
}
332
}
333
334
WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId)
335
: mCompositorBridge(nullptr),
336
mPipelineId(aPipelineId),
337
mChildLayersObserverEpoch{0},
338
mParentLayersObserverEpoch{0},
339
mWrEpoch{0},
340
mIdNamespace{0},
341
mRenderRootRectMutex("WebRenderBridgeParent::mRenderRootRectMutex"),
342
mPaused(false),
343
mDestroyed(true),
344
mReceivedDisplayList(false),
345
mIsFirstPaint(false),
346
mSkippedComposite(false) {}
347
348
WebRenderBridgeParent::~WebRenderBridgeParent() {
349
if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
350
root->RemoveDeferredPipeline(mPipelineId);
351
}
352
}
353
354
bool WebRenderBridgeParent::RenderRootIsValid(wr::RenderRoot aRenderRoot) {
355
if (StaticPrefs::gfx_webrender_split_render_roots_AtStartup() &&
356
IsRootWebRenderBridgeParent()) {
357
return aRenderRoot <= wr::kHighestRenderRoot;
358
} else {
359
return aRenderRoot == wr::RenderRoot::Default;
360
}
361
}
362
363
void WebRenderBridgeParent::RemoveDeferredPipeline(wr::PipelineId aPipelineId) {
364
MOZ_ASSERT(IsRootWebRenderBridgeParent());
365
mPipelineRenderRoots.Remove(wr::AsUint64(aPipelineId));
366
if (auto entry = mPipelineDeferredUpdates.Lookup(wr::AsUint64(aPipelineId))) {
367
RefPtr<WebRenderBridgeParent> self = this;
368
for (auto& variant : entry.Data()) {
369
variant.match(
370
[=](RenderRootDisplayListData& x) {
371
wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mSmallShmems);
372
wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mLargeShmems);
373
},
374
[=](RenderRootUpdates& x) {
375
wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mSmallShmems);
376
wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mLargeShmems);
377
},
378
[=](ResourceUpdates& x) {
379
wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mSmallShmems);
380
wr::IpcResourceUpdateQueue::ReleaseShmems(self, x.mLargeShmems);
381
},
382
[=](ParentCommands& x) {}, [=](FocusTarget& x) {});
383
}
384
entry.Remove();
385
}
386
}
387
388
/* static */
389
WebRenderBridgeParent* WebRenderBridgeParent::CreateDestroyed(
390
const wr::PipelineId& aPipelineId) {
391
return new WebRenderBridgeParent(aPipelineId);
392
}
393
394
void WebRenderBridgeParent::PushDeferredPipelineData(
395
RenderRootDeferredData&& aDeferredData) {
396
MOZ_ASSERT(!IsRootWebRenderBridgeParent());
397
if (RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent()) {
398
uint64_t key = wr::AsUint64(mPipelineId);
399
root->mPipelineDeferredUpdates.LookupForAdd(key)
400
.OrInsert([]() { return nsTArray<RenderRootDeferredData>(); })
401
.AppendElement(std::move(aDeferredData));
402
}
403
}
404
405
bool WebRenderBridgeParent::HandleDeferredPipelineData(
406
nsTArray<RenderRootDeferredData>& aDeferredData,
407
const TimeStamp& aTxnStartTime) {
408
MOZ_ASSERT(!IsRootWebRenderBridgeParent());
409
for (auto& entry : aDeferredData) {
410
bool success = entry.match(
411
[&](RenderRootDisplayListData& data) {
412
// We ensure this with RenderRootIsValid before calling
413
// PushDeferredPipelineData:
414
MOZ_ASSERT(data.mRenderRoot == wr::RenderRoot::Default);
415
wr::Epoch wrEpoch = GetNextWrEpoch();
416
bool validTransaction = data.mIdNamespace == mIdNamespace;
417
418
if (!ProcessRenderRootDisplayListData(data, wrEpoch, aTxnStartTime,
419
validTransaction, false)) {
420
return false;
421
}
422
423
wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mSmallShmems);
424
wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mLargeShmems);
425
return true;
426
},
427
[&](RenderRootUpdates& data) {
428
// We ensure this with RenderRootIsValid before calling
429
// PushDeferredPipelineData:
430
MOZ_ASSERT(data.mRenderRoot == wr::RenderRoot::Default);
431
bool scheduleComposite;
432
if (!ProcessEmptyTransactionUpdates(data, &scheduleComposite)) {
433
return false;
434
}
435
if (scheduleComposite) {
436
ScheduleGenerateFrame(Nothing());
437
}
438
wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mSmallShmems);
439
wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mLargeShmems);
440
return true;
441
},
442
[&](ResourceUpdates& data) {
443
wr::TransactionBuilder txn;
444
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
445
446
if (!UpdateResources(data.mResourceUpdates, data.mSmallShmems,
447
data.mLargeShmems, txn)) {
448
return false;
449
}
450
451
Api(wr::RenderRoot::Default)->SendTransaction(txn);
452
wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mSmallShmems);
453
wr::IpcResourceUpdateQueue::ReleaseShmems(this, data.mLargeShmems);
454
return true;
455
},
456
[&](ParentCommands& data) {
457
wr::TransactionBuilder txn;
458
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
459
if (!ProcessWebRenderParentCommands(data.mCommands, txn,
460
wr::RenderRoot::Default)) {
461
return false;
462
}
463
464
Api(wr::RenderRoot::Default)->SendTransaction(txn);
465
return true;
466
},
467
[&](FocusTarget& data) {
468
UpdateAPZFocusState(data);
469
return true;
470
});
471
472
if (!success) {
473
return false;
474
}
475
}
476
aDeferredData.Clear();
477
return true;
478
}
479
480
bool WebRenderBridgeParent::MaybeHandleDeferredPipelineDataForPipeline(
481
wr::RenderRoot aRenderRoot, wr::PipelineId aPipelineId,
482
const TimeStamp& aTxnStartTime) {
483
MOZ_ASSERT(IsRootWebRenderBridgeParent());
484
485
uint64_t key = wr::AsUint64(aPipelineId);
486
auto entry = mPipelineRenderRoots.LookupForAdd(key);
487
if (!entry) {
488
entry.OrInsert([=]() { return aRenderRoot; });
489
490
CompositorBridgeParent::LayerTreeState* lts =
491
CompositorBridgeParent::GetIndirectShadowTree(
492
wr::AsLayersId(aPipelineId));
493
if (!lts) {
494
return true;
495
}
496
RefPtr<WebRenderBridgeParent> wrbp = lts->mWrBridge;
497
if (!wrbp) {
498
return true;
499
}
500
MOZ_ASSERT(wrbp->mRenderRoot.refOr(aRenderRoot) == aRenderRoot);
501
wrbp->mRenderRoot = Some(aRenderRoot);
502
503
if (auto entry = mPipelineDeferredUpdates.Lookup(key)) {
504
wrbp->HandleDeferredPipelineData(entry.Data(), aTxnStartTime);
505
entry.Remove();
506
507
for (auto it = wrbp->mChildPipelines.Iter(); !it.Done(); it.Next()) {
508
if (!MaybeHandleDeferredPipelineDataForPipeline(
509
aRenderRoot, wr::AsPipelineId(it.Get()->GetKey()),
510
aTxnStartTime)) {
511
return false;
512
}
513
}
514
}
515
}
516
517
return true;
518
}
519
520
bool WebRenderBridgeParent::MaybeHandleDeferredPipelineData(
521
wr::RenderRoot aRenderRoot, const nsTArray<wr::PipelineId>& aPipelineIds,
522
const TimeStamp& aTxnStartTime) {
523
MOZ_ASSERT(IsRootWebRenderBridgeParent());
524
if (!StaticPrefs::gfx_webrender_split_render_roots_AtStartup()) {
525
return true;
526
}
527
for (wr::PipelineId pipelineId : aPipelineIds) {
528
if (!MaybeHandleDeferredPipelineDataForPipeline(aRenderRoot, pipelineId,
529
aTxnStartTime)) {
530
return false;
531
}
532
}
533
534
return true;
535
}
536
537
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEnsureConnected(
538
TextureFactoryIdentifier* aTextureFactoryIdentifier,
539
MaybeIdNamespace* aMaybeIdNamespace) {
540
if (mDestroyed) {
541
*aTextureFactoryIdentifier =
542
TextureFactoryIdentifier(LayersBackend::LAYERS_NONE);
543
*aMaybeIdNamespace = Nothing();
544
return IPC_OK();
545
}
546
547
MOZ_ASSERT(mIdNamespace.mHandle != 0);
548
*aTextureFactoryIdentifier = GetTextureFactoryIdentifier();
549
*aMaybeIdNamespace = Some(mIdNamespace);
550
551
if (!mRenderRoot) {
552
RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent();
553
if (!root) {
554
return IPC_FAIL(this, "Root WRBP is missing (shutting down?)");
555
}
556
if (auto p = root->mPipelineRenderRoots.Lookup(wr::AsUint64(mPipelineId))) {
557
mRenderRoot.emplace(p.Data());
558
}
559
}
560
561
return IPC_OK();
562
}
563
564
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvShutdown() {
565
return HandleShutdown();
566
}
567
568
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvShutdownSync() {
569
return HandleShutdown();
570
}
571
572
mozilla::ipc::IPCResult WebRenderBridgeParent::HandleShutdown() {
573
Destroy();
574
IProtocol* mgr = Manager();
575
if (!Send__delete__(this)) {
576
return IPC_FAIL_NO_REASON(mgr);
577
}
578
return IPC_OK();
579
}
580
581
void WebRenderBridgeParent::Destroy() {
582
if (mDestroyed) {
583
return;
584
}
585
mDestroyed = true;
586
ClearResources();
587
}
588
589
bool WebRenderBridgeParent::UpdateResources(
590
const nsTArray<OpUpdateResource>& aResourceUpdates,
591
const nsTArray<RefCountedShmem>& aSmallShmems,
592
const nsTArray<ipc::Shmem>& aLargeShmems,
593
wr::TransactionBuilder& aUpdates) {
594
wr::ShmSegmentsReader reader(aSmallShmems, aLargeShmems);
595
UniquePtr<ScheduleSharedSurfaceRelease> scheduleRelease;
596
597
for (const auto& cmd : aResourceUpdates) {
598
switch (cmd.type()) {
599
case OpUpdateResource::TOpAddImage: {
600
const auto& op = cmd.get_OpAddImage();
601
wr::Vec<uint8_t> bytes;
602
if (!reader.Read(op.bytes(), bytes)) {
603
return false;
604
}
605
aUpdates.AddImage(op.key(), op.descriptor(), bytes);
606
break;
607
}
608
case OpUpdateResource::TOpUpdateImage: {
609
const auto& op = cmd.get_OpUpdateImage();
610
wr::Vec<uint8_t> bytes;
611
if (!reader.Read(op.bytes(), bytes)) {
612
return false;
613
}
614
aUpdates.UpdateImageBuffer(op.key(), op.descriptor(), bytes);
615
break;
616
}
617
case OpUpdateResource::TOpAddBlobImage: {
618
const auto& op = cmd.get_OpAddBlobImage();
619
wr::Vec<uint8_t> bytes;
620
if (!reader.Read(op.bytes(), bytes)) {
621
return false;
622
}
623
aUpdates.AddBlobImage(op.key(), op.descriptor(), bytes,
624
wr::ToDeviceIntRect(op.visibleRect()));
625
break;
626
}
627
case OpUpdateResource::TOpUpdateBlobImage: {
628
const auto& op = cmd.get_OpUpdateBlobImage();
629
wr::Vec<uint8_t> bytes;
630
if (!reader.Read(op.bytes(), bytes)) {
631
return false;
632
}
633
aUpdates.UpdateBlobImage(op.key(), op.descriptor(), bytes,
634
wr::ToDeviceIntRect(op.visibleRect()),
635
wr::ToLayoutIntRect(op.dirtyRect()));
636
break;
637
}
638
case OpUpdateResource::TOpSetBlobImageVisibleArea: {
639
const auto& op = cmd.get_OpSetBlobImageVisibleArea();
640
aUpdates.SetBlobImageVisibleArea(op.key(),
641
wr::ToDeviceIntRect(op.area()));
642
break;
643
}
644
case OpUpdateResource::TOpAddExternalImage: {
645
const auto& op = cmd.get_OpAddExternalImage();
646
if (!AddExternalImage(op.externalImageId(), op.key(), aUpdates)) {
647
return false;
648
}
649
break;
650
}
651
case OpUpdateResource::TOpPushExternalImageForTexture: {
652
const auto& op = cmd.get_OpPushExternalImageForTexture();
653
CompositableTextureHostRef texture;
654
texture = TextureHost::AsTextureHost(op.textureParent());
655
if (!PushExternalImageForTexture(op.externalImageId(), op.key(),
656
texture, op.isUpdate(), aUpdates)) {
657
return false;
658
}
659
break;
660
}
661
case OpUpdateResource::TOpUpdateExternalImage: {
662
const auto& op = cmd.get_OpUpdateExternalImage();
663
if (!UpdateExternalImage(op.externalImageId(), op.key(), op.dirtyRect(),
664
aUpdates, scheduleRelease)) {
665
return false;
666
}
667
break;
668
}
669
case OpUpdateResource::TOpAddRawFont: {
670
const auto& op = cmd.get_OpAddRawFont();
671
wr::Vec<uint8_t> bytes;
672
if (!reader.Read(op.bytes(), bytes)) {
673
return false;
674
}
675
aUpdates.AddRawFont(op.key(), bytes, op.fontIndex());
676
break;
677
}
678
case OpUpdateResource::TOpAddFontDescriptor: {
679
const auto& op = cmd.get_OpAddFontDescriptor();
680
wr::Vec<uint8_t> bytes;
681
if (!reader.Read(op.bytes(), bytes)) {
682
return false;
683
}
684
aUpdates.AddFontDescriptor(op.key(), bytes, op.fontIndex());
685
break;
686
}
687
case OpUpdateResource::TOpAddFontInstance: {
688
const auto& op = cmd.get_OpAddFontInstance();
689
wr::Vec<uint8_t> variations;
690
if (!reader.Read(op.variations(), variations)) {
691
return false;
692
}
693
aUpdates.AddFontInstance(op.instanceKey(), op.fontKey(), op.glyphSize(),
694
op.options().ptrOr(nullptr),
695
op.platformOptions().ptrOr(nullptr),
696
variations);
697
break;
698
}
699
case OpUpdateResource::TOpDeleteImage: {
700
const auto& op = cmd.get_OpDeleteImage();
701
DeleteImage(op.key(), aUpdates);
702
break;
703
}
704
case OpUpdateResource::TOpDeleteBlobImage: {
705
const auto& op = cmd.get_OpDeleteBlobImage();
706
aUpdates.DeleteBlobImage(op.key());
707
break;
708
}
709
case OpUpdateResource::TOpDeleteFont: {
710
const auto& op = cmd.get_OpDeleteFont();
711
aUpdates.DeleteFont(op.key());
712
break;
713
}
714
case OpUpdateResource::TOpDeleteFontInstance: {
715
const auto& op = cmd.get_OpDeleteFontInstance();
716
aUpdates.DeleteFontInstance(op.key());
717
break;
718
}
719
case OpUpdateResource::T__None:
720
break;
721
}
722
}
723
724
if (scheduleRelease) {
725
aUpdates.Notify(wr::Checkpoint::FrameTexturesUpdated,
726
std::move(scheduleRelease));
727
}
728
return true;
729
}
730
731
bool WebRenderBridgeParent::AddExternalImage(
732
wr::ExternalImageId aExtId, wr::ImageKey aKey,
733
wr::TransactionBuilder& aResources) {
734
Range<wr::ImageKey> keys(&aKey, 1);
735
// Check if key is obsoleted.
736
if (keys[0].mNamespace != mIdNamespace) {
737
return true;
738
}
739
740
auto key = wr::AsUint64(aKey);
741
auto it = mSharedSurfaceIds.find(key);
742
if (it != mSharedSurfaceIds.end()) {
743
gfxCriticalNote << "Readding known shared surface: " << key;
744
return false;
745
}
746
747
RefPtr<DataSourceSurface> dSurf = SharedSurfacesParent::Acquire(aExtId);
748
if (!dSurf) {
749
gfxCriticalNote
750
<< "DataSourceSurface of SharedSurfaces does not exist for extId:"
751
<< wr::AsUint64(aExtId);
752
return false;
753
}
754
755
mSharedSurfaceIds.insert(std::make_pair(key, aExtId));
756
757
if (!gfxEnv::EnableWebRenderRecording()) {
758
wr::ImageDescriptor descriptor(dSurf->GetSize(), dSurf->Stride(),
759
dSurf->GetFormat());
760
aResources.AddExternalImage(aKey, descriptor, aExtId,
761
wr::ExternalImageType::Buffer(), 0);
762
return true;
763
}
764
765
DataSourceSurface::MappedSurface map;
766
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
767
gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:"
768
<< wr::AsUint64(aExtId);
769
return false;
770
}
771
772
IntSize size = dSurf->GetSize();
773
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
774
wr::Vec<uint8_t> data;
775
data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
776
aResources.AddImage(keys[0], descriptor, data);
777
dSurf->Unmap();
778
779
return true;
780
}
781
782
bool WebRenderBridgeParent::PushExternalImageForTexture(
783
wr::ExternalImageId aExtId, wr::ImageKey aKey, TextureHost* aTexture,
784
bool aIsUpdate, wr::TransactionBuilder& aResources) {
785
auto op = aIsUpdate ? TextureHost::UPDATE_IMAGE : TextureHost::ADD_IMAGE;
786
Range<wr::ImageKey> keys(&aKey, 1);
787
// Check if key is obsoleted.
788
if (keys[0].mNamespace != mIdNamespace) {
789
return true;
790
}
791
792
if (!aTexture) {
793
gfxCriticalNote << "TextureHost does not exist for extId:"
794
<< wr::AsUint64(aExtId);
795
return false;
796
}
797
798
if (!gfxEnv::EnableWebRenderRecording()) {
799
WebRenderTextureHost* wrTexture = aTexture->AsWebRenderTextureHost();
800
if (wrTexture) {
801
wrTexture->PushResourceUpdates(aResources, op, keys,
802
wrTexture->GetExternalImageKey());
803
auto it = mTextureHosts.find(wr::AsUint64(aKey));
804
MOZ_ASSERT((it == mTextureHosts.end() && !aIsUpdate) ||
805
(it != mTextureHosts.end() && aIsUpdate));
806
if (it != mTextureHosts.end()) {
807
// Release Texture if it exists.
808
ReleaseTextureOfImage(aKey);
809
}
810
mTextureHosts.emplace(wr::AsUint64(aKey),
811
CompositableTextureHostRef(aTexture));
812
return true;
813
}
814
}
815
RefPtr<DataSourceSurface> dSurf = aTexture->GetAsSurface();
816
if (!dSurf) {
817
gfxCriticalNote
818
<< "TextureHost does not return DataSourceSurface for extId:"
819
<< wr::AsUint64(aExtId);
820
return false;
821
}
822
823
DataSourceSurface::MappedSurface map;
824
if (!dSurf->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
825
gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:"
826
<< wr::AsUint64(aExtId);
827
return false;
828
}
829
830
IntSize size = dSurf->GetSize();
831
wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
832
wr::Vec<uint8_t> data;
833
data.PushBytes(Range<uint8_t>(map.mData, size.height * map.mStride));
834
835
if (op == TextureHost::UPDATE_IMAGE) {
836
aResources.UpdateImageBuffer(keys[0], descriptor, data);
837
} else {
838
aResources.AddImage(keys[0], descriptor, data);
839
}
840
841
dSurf->Unmap();
842
843
return true;
844
}
845
846
bool WebRenderBridgeParent::UpdateExternalImage(
847
wr::ExternalImageId aExtId, wr::ImageKey aKey,
848
const ImageIntRect& aDirtyRect, wr::TransactionBuilder& aResources,
849
UniquePtr<ScheduleSharedSurfaceRelease>& aScheduleRelease) {
850
Range<wr::ImageKey> keys(&aKey, 1);
851
// Check if key is obsoleted.
852
if (keys[0].mNamespace != mIdNamespace) {
853
return true;
854
}
855
856
auto key = wr::AsUint64(aKey);
857
auto it = mSharedSurfaceIds.find(key);
858
if (it == mSharedSurfaceIds.end()) {
859
gfxCriticalNote << "Updating unknown shared surface: " << key;
860
return false;
861
}
862
863
RefPtr<DataSourceSurface> dSurf;
864
if (it->second == aExtId) {
865
dSurf = SharedSurfacesParent::Get(aExtId);
866
} else {
867
dSurf = SharedSurfacesParent::Acquire(aExtId);
868
}
869
870
if (!dSurf) {
871
gfxCriticalNote << "Shared surface does not exist for extId:"
872
<< wr::AsUint64(aExtId);
873
return false;
874
}
875
876
if (!(it->second == aExtId)) {
877
// We already have a mapping for this image key, so ensure we release the
878
// previous external image ID. This can happen when an image is animated,
879
// and it is changing the external image that the animation points to.
880
if (!aScheduleRelease) {
881
aScheduleRelease = MakeUnique<ScheduleSharedSurfaceRelease>(this);
882
}
883
aScheduleRelease->Add(aKey, it->second);
884
it->second = aExtId;
885
}
886
887
if (!gfxEnv::EnableWebRenderRecording()) {
888
wr::ImageDescriptor descriptor(dSurf->GetSize(), dSurf->Stride(),
889
dSurf->GetFormat());
890
aResources.UpdateExternalImageWithDirtyRect(
891
aKey, descriptor, aExtId, wr::ExternalImageType::Buffer(),
892
wr::ToDeviceIntRect(aDirtyRect), 0);
893
return true;
894
}
895
896
DataSourceSurface::ScopedMap map(dSurf, DataSourceSurface::READ);
897
if (!map.IsMapped()) {
898
gfxCriticalNote << "DataSourceSurface failed to map for Image for extId:"
899
<< wr::AsUint64(aExtId);
900
return false;
901
}
902
903
IntSize size = dSurf->GetSize();
904
wr::ImageDescriptor descriptor(size, map.GetStride(), dSurf->GetFormat());
905
wr::Vec<uint8_t> data;
906
data.PushBytes(Range<uint8_t>(map.GetData(), size.height * map.GetStride()));
907
aResources.UpdateImageBuffer(keys[0], descriptor, data);
908
return true;
909
}
910
911
void WebRenderBridgeParent::ObserveSharedSurfaceRelease(
912
const nsTArray<wr::ExternalImageKeyPair>& aPairs) {
913
if (!mDestroyed) {
914
Unused << SendWrReleasedImages(aPairs);
915
}
916
for (const auto& pair : aPairs) {
917
SharedSurfacesParent::Release(pair.id);
918
}
919
}
920
921
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvUpdateResources(
922
nsTArray<OpUpdateResource>&& aResourceUpdates,
923
nsTArray<RefCountedShmem>&& aSmallShmems,
924
nsTArray<ipc::Shmem>&& aLargeShmems, const wr::RenderRoot& aRenderRoot) {
925
if (mDestroyed) {
926
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
927
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
928
return IPC_OK();
929
}
930
931
if (!RenderRootIsValid(aRenderRoot)) {
932
return IPC_FAIL(this, "Received an invalid renderRoot");
933
}
934
935
if (!mRenderRoot) {
936
PushDeferredPipelineData(AsVariant(ResourceUpdates{
937
std::move(aResourceUpdates),
938
std::move(aSmallShmems),
939
std::move(aLargeShmems),
940
}));
941
return IPC_OK();
942
}
943
944
wr::TransactionBuilder txn;
945
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
946
947
bool success =
948
UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems, txn);
949
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aSmallShmems);
950
wr::IpcResourceUpdateQueue::ReleaseShmems(this, aLargeShmems);
951
952
if (!success) {
953
return IPC_FAIL(this, "Invalid WebRender resource data shmem or address.");
954
}
955
956
Api(aRenderRoot)->SendTransaction(txn);
957
958
return IPC_OK();
959
}
960
961
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvDeleteCompositorAnimations(
962
nsTArray<uint64_t>&& aIds) {
963
if (mDestroyed) {
964
return IPC_OK();
965
}
966
967
// Once mWrEpoch has been rendered, we can delete these compositor animations
968
mCompositorAnimationsToDelete.push(
969
CompositorAnimationIdsForEpoch(mWrEpoch, std::move(aIds)));
970
return IPC_OK();
971
}
972
973
void WebRenderBridgeParent::RemoveEpochDataPriorTo(
974
const wr::Epoch& aRenderedEpoch) {
975
while (!mCompositorAnimationsToDelete.empty()) {
976
if (aRenderedEpoch < mCompositorAnimationsToDelete.front().mEpoch) {
977
break;
978
}
979
for (uint64_t id : mCompositorAnimationsToDelete.front().mIds) {
980
const auto activeAnim = mActiveAnimations.find(id);
981
if (activeAnim == mActiveAnimations.end()) {
982
NS_ERROR("Tried to delete invalid animation");
983
continue;
984
}
985
// Check if animation delete request is still valid.
986
if (activeAnim->second <= mCompositorAnimationsToDelete.front().mEpoch) {
987
mAnimStorage->ClearById(id);
988
mActiveAnimations.erase(activeAnim);
989
}
990
}
991
mCompositorAnimationsToDelete.pop();
992
}
993
}
994
995
bool WebRenderBridgeParent::IsRootWebRenderBridgeParent() const {
996
return !!mWidget;
997
}
998
999
void WebRenderBridgeParent::SetCompositionRecorder(
1000
UniquePtr<layers::WebRenderCompositionRecorder> aRecorder) {
1001
Api(wr::RenderRoot::Default)->SetCompositionRecorder(std::move(aRecorder));
1002
}
1003
1004
void WebRenderBridgeParent::WriteCollectedFrames() {
1005
Api(wr::RenderRoot::Default)->WriteCollectedFrames();
1006
}
1007
1008
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>
1032
WebRenderBridgeParent::GetRootWebRenderBridgeParent() const {
1033
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1034
if (!cbp) {
1035
return nullptr;
1036
}
1037
1038
return cbp->GetWebRenderBridgeParent();
1039
}
1040
1041
void WebRenderBridgeParent::UpdateAPZFocusState(const FocusTarget& aFocus) {
1042
if (!mRenderRoot) {
1043
PushDeferredPipelineData(AsVariant(aFocus));
1044
return;
1045
}
1046
1047
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1048
if (!cbp) {
1049
return;
1050
}
1051
LayersId rootLayersId = cbp->RootLayerTreeId();
1052
if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
1053
apz->UpdateFocusState(rootLayersId, WRRootId(GetLayersId(), *mRenderRoot),
1054
aFocus);
1055
}
1056
}
1057
1058
void WebRenderBridgeParent::UpdateAPZScrollData(const wr::Epoch& aEpoch,
1059
WebRenderScrollData&& aData,
1060
wr::RenderRoot aRenderRoot) {
1061
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1062
if (!cbp) {
1063
return;
1064
}
1065
LayersId rootLayersId = cbp->RootLayerTreeId();
1066
if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
1067
apz->UpdateScrollDataAndTreeState(
1068
WRRootId(rootLayersId, wr::RenderRoot::Default),
1069
WRRootId(GetLayersId(), RenderRootForExternal(aRenderRoot)), aEpoch,
1070
std::move(aData));
1071
}
1072
}
1073
1074
void WebRenderBridgeParent::UpdateAPZScrollOffsets(
1075
ScrollUpdatesMap&& aUpdates, uint32_t aPaintSequenceNumber,
1076
wr::RenderRoot aRenderRoot) {
1077
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1078
if (!cbp) {
1079
return;
1080
}
1081
LayersId rootLayersId = cbp->RootLayerTreeId();
1082
if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
1083
apz->UpdateScrollOffsets(
1084
WRRootId(rootLayersId, wr::RenderRoot::Default),
1085
WRRootId(GetLayersId(), RenderRootForExternal(aRenderRoot)),
1086
std::move(aUpdates), aPaintSequenceNumber);
1087
}
1088
}
1089
1090
void WebRenderBridgeParent::SetAPZSampleTime() {
1091
CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
1092
if (!cbp) {
1093
return;
1094
}
1095
if (RefPtr<APZSampler> apz = cbp->GetAPZSampler()) {
1096
TimeStamp animationTime = cbp->GetTestingTimeStamp().valueOr(
1097
mCompositorScheduler->GetLastComposeTime());
1098
TimeDuration frameInterval = cbp->GetVsyncInterval();
1099
// As with the non-webrender codepath in AsyncCompositionManager, we want to
1100
// use the timestamp for the next vsync when advancing animations.
1101
if (frameInterval != TimeDuration::Forever()) {
1102
animationTime += frameInterval;
1103
}
1104
apz->SetSampleTime(animationTime);
1105
}
1106
}
1107
1108
bool WebRenderBridgeParent::SetDisplayList(
1109
wr::RenderRoot aRenderRoot, const LayoutDeviceRect& aRect,
1110
const wr::LayoutSize& aContentSize, ipc::ByteBuf&& aDL,
1111
const wr::BuiltDisplayListDescriptor& aDLDesc,
1112
const nsTArray<OpUpdateResource>& aResourceUpdates,
1113
const nsTArray<RefCountedShmem>& aSmallShmems,
1114
const nsTArray<ipc::Shmem>& aLargeShmems, const TimeStamp& aTxnStartTime,
1115
wr::TransactionBuilder& aTxn, wr::Epoch aWrEpoch, bool aValidTransaction,
1116
bool aObserveLayersUpdate) {
1117
if (NS_WARN_IF(!UpdateResources(aResourceUpdates, aSmallShmems, aLargeShmems,
1118
aTxn))) {
1119
return false;
1120
}
1121
1122
wr::Vec<uint8_t> dlData(std::move(aDL));
1123
1124
if (aValidTransaction) {
1125
if (IsRootWebRenderBridgeParent()) {
1126
if (aRenderRoot != wr::RenderRoot::Default) {
1127
MutexAutoLock lock(mRenderRootRectMutex);
1128
mRenderRootRects[aRenderRoot] = ViewAs<ScreenPixel>(
1129
aRect, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
1130
}
1131
LayoutDeviceIntSize widgetSize = mWidget->GetClientSize();
1132
LayoutDeviceIntRect rect;
1133
if (StaticPrefs::gfx_webrender_split_render_roots_AtStartup()) {
1134
rect = RoundedToInt(aRect);
1135
rect.SetWidth(
1136
std::max(0, std::min(widgetSize.width - rect.X(), rect.Width())));
1137
rect.SetHeight(
1138
std::max(0, std::min(widgetSize.height - rect.Y(), rect.Height())));
1139
} else {
1140
// XXX: If we can't have multiple documents, just use the
1141
// pre-document- splitting behavior of directly applying the client
1142
// size. This is a speculative and temporary attempt to address bug
1143
// 1538540, as an incorrect rect supplied to SetDocumentView can cause
1144
// us to not build a frame and potentially render with stale texture
1145
// cache items.
1146
rect = LayoutDeviceIntRect(LayoutDeviceIntPoint(), widgetSize);
1147
}
1148
aTxn.SetDocumentView(rect);
1149
}
1150
gfx::Color clearColor(0.f, 0.f, 0.f, 0.f);
1151
aTxn.SetDisplayList(clearColor, aWrEpoch,
1152
wr::ToLayoutSize(RoundedToInt(aRect).Size()),
1153
mPipelineId, aContentSize, aDLDesc, dlData);
1154
1155
if (aObserveLayersUpdate) {
1156
aTxn.Notify(wr::Checkpoint::SceneBuilt,
1157
MakeUnique<ScheduleObserveLayersUpdate>(
1158
mCompositorBridge, GetLayersId(),
1159
mChildLayersObserverEpoch, true));
1160
}
1161
1162
if (!IsRootWebRenderBridgeParent()) {
1163
aTxn.Notify(
1164
wr::Checkpoint::SceneBuilt,
1165
MakeUnique<SceneBuiltNotification>(this, aWrEpoch, aTxnStartTime));
1166
}
1167
1168
Api(aRenderRoot)->SendTransaction(aTxn);
1169
1170
// We will schedule generating a frame after the scene
1171
// build is done, so we don't need to do it here.
1172
}
1173
1174
return true;
1175
}
1176
1177
bool WebRenderBridgeParent::ProcessRenderRootDisplayListData(
1178
RenderRootDisplayListData& aDisplayList, wr::Epoch aWrEpoch,
1179
const TimeStamp& aTxnStartTime, bool aValidTransaction,
1180
bool aObserveLayersUpdate) {
1181
wr::TransactionBuilder txn;
1182
Maybe<wr::AutoTransactionSender> sender;
1183
1184
// Note that this needs to happen before the display list transaction is
1185
// sent to WebRender, so that the UpdateHitTestingTree call is guaranteed to
1186
// be in the updater queue at the time that the scene swap completes.
1187
if (aDisplayList.mScrollData) {
1188
UpdateAPZScrollData(aWrEpoch, std::move(aDisplayList.mScrollData.ref()),
1189
aDisplayList.mRenderRoot);
1190
}
1191
1192
MOZ_ASSERT(aDisplayList.mRenderRoot == wr::RenderRoot::Default ||
1193
IsRootWebRenderBridgeParent());
1194
auto renderRoot = aDisplayList.mRenderRoot;
1195
1196
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
1197
if (aValidTransaction) {
1198
MOZ_ASSERT(aDisplayList.mIdNamespace == mIdNamespace);
1199
sender.emplace(Api(renderRoot), &txn);
1200
}
1201
1202
if (NS_WARN_IF(!ProcessWebRenderParentCommands(aDisplayList.mCommands, txn,
1203
renderRoot))) {
1204
return false;
1205
}
1206
1207
if (aDisplayList.mDL &&
1208
!SetDisplayList(renderRoot, aDisplayList.mRect, aDisplayList.mContentSize,
1209
std::move(aDisplayList.mDL.ref()), aDisplayList.mDLDesc,
1210
aDisplayList.mResourceUpdates, aDisplayList.mSmallShmems,
1211
aDisplayList.mLargeShmems, aTxnStartTime, txn, aWrEpoch,
1212
aValidTransaction, aObserveLayersUpdate)) {
1213
return false;
1214
}
1215
return true;
1216
}
1217
1218
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetDisplayList(
1219
nsTArray<RenderRootDisplayListData>&& aDisplayLists,
1220
nsTArray<OpDestroy>&& aToDestroy, const uint64_t& aFwdTransactionId,
1221
const TransactionId& aTransactionId, const bool& aContainsSVGGroup,
1222
const VsyncId& aVsyncId, const TimeStamp& aVsyncStartTime,
1223
const TimeStamp& aRefreshStartTime, const TimeStamp& aTxnStartTime,
1224
const nsCString& aTxnURL, const TimeStamp& aFwdTime,
1225
nsTArray<CompositionPayload>&& aPayloads) {
1226
if (mDestroyed) {
1227
for (const auto& op : aToDestroy) {
1228
DestroyActor(op);
1229
}
1230
return IPC_OK();
1231
}
1232
1233
// Guard against malicious content processes
1234
if (aDisplayLists.Length() == 0) {
1235
return IPC_FAIL(this, "Must send at least one RenderRootDisplayListData.");
1236
}
1237
for (auto& displayList : aDisplayLists) {
1238
if (!RenderRootIsValid(displayList.mRenderRoot)) {
1239
return IPC_FAIL(this, "Received an invalid renderRoot");
1240
}
1241
}
1242
1243
if (!IsRootWebRenderBridgeParent()) {
1244
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aTxnURL);
1245
}
1246
1247
AUTO_PROFILER_TRACING("Paint", "SetDisplayList", GRAPHICS);
1248
UpdateFwdTransactionId(aFwdTransactionId);
1249
1250
// This ensures that destroy operations are always processed. It is not safe
1251
// to early-return from RecvDPEnd without doing so.
1252
AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(
1253
this, &aToDestroy);
1254
1255
wr::Epoch wrEpoch = GetNextWrEpoch();
1256
1257
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
1258
1259
mReceivedDisplayList = true;
1260
1261
// The IsFirstPaint() flag should be the same for all the non-empty
1262
// scrolldata across all the renderroot display lists in a given
1263
// transaction. We assert this below. So we can read the flag from any one
1264
// of them.
1265
Maybe<size_t> firstScrollDataIndex;
1266
for (size_t i = 1; i < aDisplayLists.Length(); i++) {
1267
auto& scrollData = aDisplayLists[i].mScrollData;
1268
if (scrollData) {
1269
if (firstScrollDataIndex.isNothing()) {
1270
firstScrollDataIndex = Some(i);
1271
if (scrollData && scrollData->IsFirstPaint()) {
1272
mIsFirstPaint = true;
1273
}
1274
} else {
1275
auto& firstNonEmpty = aDisplayLists[*firstScrollDataIndex].mScrollData;
1276
// Ensure the flag is the same on all of them.
1277
MOZ_RELEASE_ASSERT(scrollData->IsFirstPaint() ==
1278
firstNonEmpty->IsFirstPaint());
1279
}
1280
}
1281
}
1282
1283
if (!mRenderRoot) {
1284
// Only non-root WRBPs will ever have an unresolved mRenderRoot
1285
MOZ_ASSERT(!IsRootWebRenderBridgeParent());
1286
if (aDisplayLists.Length() != 1) {
1287
return IPC_FAIL(this,
1288
"Well-behaved content processes must only send a DL for "
1289
"a single renderRoot");
1290
}
1291
PushDeferredPipelineData(AsVariant(std::move(aDisplayLists[0])));
1292
aDisplayLists.Clear();
1293
}
1294
1295
for (auto& displayList : aDisplayLists) {
1296
if (IsRootWebRenderBridgeParent()) {
1297
if (!MaybeHandleDeferredPipelineData(displayList.mRenderRoot,
1298
displayList.mRemotePipelineIds,
1299
aTxnStartTime)) {
1300
return IPC_FAIL(this, "Failed processing deferred pipeline data");
1301
}
1302
} else {
1303
RefPtr<WebRenderBridgeParent> root = GetRootWebRenderBridgeParent();
1304
if (!root) {
1305
return IPC_FAIL(this, "Root WRBP is missing (shutting down?)");
1306
}
1307
1308
for (auto pipelineId : displayList.mRemotePipelineIds) {
1309
auto id = wr::AsUint64(pipelineId);
1310
root->mPipelineRenderRoots.Put(id, *mRenderRoot);
1311
mChildPipelines.PutEntry(id);
1312
}
1313
}
1314
}
1315
1316
bool validTransaction = aDisplayLists.Length() > 0 &&
1317
aDisplayLists[0].mIdNamespace == mIdNamespace;
1318
bool observeLayersUpdate = ShouldParentObserveEpoch();
1319
1320
for (auto& displayList : aDisplayLists) {
1321
if (!ProcessRenderRootDisplayListData(displayList, wrEpoch, aTxnStartTime,
1322
validTransaction,
1323
observeLayersUpdate)) {
1324
return IPC_FAIL(this, "Failed to process RenderRootDisplayListData.");
1325
}
1326
}
1327
1328
if (!validTransaction && observeLayersUpdate) {
1329
mCompositorBridge->ObserveLayersUpdate(GetLayersId(),
1330
mChildLayersObserverEpoch, true);
1331
}
1332
1333
if (!IsRootWebRenderBridgeParent()) {
1334
aPayloads.AppendElement(
1335
CompositionPayload{CompositionPayloadType::eContentPaint, aFwdTime});
1336
}
1337
1338
HoldPendingTransactionId(wrEpoch, aTransactionId, aContainsSVGGroup, aVsyncId,
1339
aVsyncStartTime, aRefreshStartTime, aTxnStartTime,
1340
aTxnURL, aFwdTime, mIsFirstPaint,
1341
std::move(aPayloads));
1342
mIsFirstPaint = false;
1343
1344
if (!validTransaction) {
1345
// Pretend we composited since someone is wating for this event,
1346
// though DisplayList was not pushed to webrender.
1347
if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
1348
TimeStamp now = TimeStamp::Now();
1349
cbp->NotifyPipelineRendered(mPipelineId, wrEpoch, VsyncId(), now, now,
1350
now);
1351
}
1352
}
1353
1354
for (auto& displayList : aDisplayLists) {
1355
wr::IpcResourceUpdateQueue::ReleaseShmems(this, displayList.mSmallShmems);
1356
wr::IpcResourceUpdateQueue::ReleaseShmems(this, displayList.mLargeShmems);
1357
}
1358
1359
return IPC_OK();
1360
}
1361
1362
bool WebRenderBridgeParent::ProcessEmptyTransactionUpdates(
1363
RenderRootUpdates& aUpdates, bool* aScheduleComposite) {
1364
*aScheduleComposite = false;
1365
wr::TransactionBuilder txn;
1366
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
1367
1368
MOZ_ASSERT(aUpdates.mRenderRoot == wr::RenderRoot::Default ||
1369
IsRootWebRenderBridgeParent());
1370
1371
if (!aUpdates.mScrollUpdates.IsEmpty()) {
1372
UpdateAPZScrollOffsets(std::move(aUpdates.mScrollUpdates),
1373
aUpdates.mPaintSequenceNumber, aUpdates.mRenderRoot);
1374
}
1375
1376
// Update WrEpoch for UpdateResources() and ProcessWebRenderParentCommands().
1377
// WrEpoch is used to manage ExternalImages lifetimes in
1378
// AsyncImagePipelineManager.
1379
Unused << GetNextWrEpoch();
1380
1381
if (!UpdateResources(aUpdates.mResourceUpdates, aUpdates.mSmallShmems,
1382
aUpdates.mLargeShmems, txn)) {
1383
return false;
1384
}
1385
1386
if (!aUpdates.mCommands.IsEmpty()) {
1387
mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
1388
if (!ProcessWebRenderParentCommands(aUpdates.mCommands, txn,
1389
aUpdates.mRenderRoot)) {
1390
return false;
1391
}
1392
}
1393
1394
if (ShouldParentObserveEpoch()) {
1395
txn.Notify(
1396
wr::Checkpoint::SceneBuilt,
1397
MakeUnique<ScheduleObserveLayersUpdate>(
1398
mCompositorBridge, GetLayersId(), mChildLayersObserverEpoch, true));
1399
}
1400
1401
// Even when txn.IsResourceUpdatesEmpty() is true, there could be resource
1402
// updates. It is handled by WebRenderTextureHostWrapper. In this case
1403
// txn.IsRenderedFrameInvalidated() becomes true.
1404
if (!txn.IsResourceUpdatesEmpty() || txn.IsRenderedFrameInvalidated()) {
1405
// There are resource updates, then we update Epoch of transaction.
1406
txn.UpdateEpoch(mPipelineId, mWrEpoch);
1407
*aScheduleComposite = true;
1408
} else {
1409
// If TransactionBuilder does not have resource updates nor display list,
1410
// ScheduleGenerateFrame is not triggered via SceneBuilder and there is no
1411
// need to update WrEpoch.
1412
// Then we want to rollback WrEpoch. See Bug 1490117.
1413
RollbackWrEpoch();
1414
}
1415
1416
if (!txn.IsEmpty()) {
1417
Api(aUpdates.mRenderRoot)->SendTransaction(txn);
1418
}
1419
1420
if (*aScheduleComposite) {
1421
mAsyncImageManager->SetWillGenerateFrame(aUpdates.mRenderRoot);
1422
}
1423
1424
return true;
1425
}
1426
1427
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEmptyTransaction(
1428
const FocusTarget& aFocusTarget,
1429
nsTArray<RenderRootUpdates>&& aRenderRootUpdates,
1430
nsTArray<OpDestroy>&& aToDestroy, const uint64_t& aFwdTransactionId,
1431
const TransactionId& aTransactionId, const VsyncId& aVsyncId,
1432
const TimeStamp& aVsyncStartTime, const TimeStamp& aRefreshStartTime,
1433
const TimeStamp& aTxnStartTime, const nsCString& aTxnURL,
1434
const TimeStamp& aFwdTime, nsTArray<CompositionPayload>&& aPayloads) {
1435
if (mDestroyed) {
1436
for (const auto& op : aToDestroy) {
1437
DestroyActor(op);
1438
}
1439
return IPC_OK();
1440
}
1441
1442
// Guard against malicious content processes
1443
for (auto& update : aRenderRootUpdates) {
1444
if (!RenderRootIsValid(update.mRenderRoot)) {
1445
return IPC_FAIL(this, "Received an invalid renderRoot");
1446
}
1447
}
1448
1449
if (!IsRootWebRenderBridgeParent()) {
1450
CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aTxnURL);
1451
}
1452
1453
AUTO_PROFILER_TRACING("Paint", "EmptyTransaction", GRAPHICS);
1454
UpdateFwdTransactionId(aFwdTransactionId);
1455
1456
// This ensures that destroy operations are always processed. It is not safe
1457
// to early-return without doing so.
1458
AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(
1459
this, &aToDestroy);
1460
1461
if (!mRenderRoot && aRenderRootUpdates.Length() > 0) {
1462
// Only non-root WRBPs will ever have an unresolved mRenderRoot
1463
MOZ_ASSERT(!IsRootWebRenderBridgeParent());
1464
if (aRenderRootUpdates.Length() != 1) {
1465
return IPC_FAIL(this,
1466
"Well-behaved content processes must only send a DL for "
1467
"a single renderRoot");
1468
}
1469
PushDeferredPipelineData(AsVariant(std::move(aRenderRootUpdates[0])));
1470
aRenderRootUpdates.Clear();
1471
}
1472
1473
UpdateAPZFocusState(aFocusTarget);
1474
1475
bool scheduleAnyComposite = false;
1476
1477
for (auto& update : aRenderRootUpdates) {
1478
MOZ_ASSERT(update.mRenderRoot == wr::RenderRoot::Default ||
1479
IsRootWebRenderBridgeParent());
1480
1481
bool scheduleComposite = false;
1482
if (!ProcessEmptyTransactionUpdates(update, &scheduleComposite)) {
1483
return IPC_FAIL(this, "Failed to process empty transaction update.");
1484
}
1485
scheduleAnyComposite = scheduleAnyComposite || scheduleComposite;
1486
}
1487
1488
// If we are going to kick off a new composite as a result of this
1489
// transaction, or if there are already composite-triggering pending
1490
// transactions inflight, then set sendDidComposite to false because we will
1491
// send the DidComposite message after the composite occurs.
1492
// If there are no pending transactions and we're not going to do a
1493
// composite, then we leave sendDidComposite as true so we just send
1494
// the DidComposite notification now.
1495
bool sendDidComposite =
1496
!scheduleAnyComposite && mPendingTransactionIds.empty();
1497
1498
// Only register a value for CONTENT_FRAME_TIME telemetry if we actually drew
1499
// something. It is for consistency with disabling WebRender.
1500
HoldPendingTransactionId(mWrEpoch, aTransactionId, false, aVsyncId,
1501
aVsyncStartTime, aRefreshStartTime, aTxnStartTime,
1502
aTxnURL, aFwdTime,
1503
/* aIsFirstPaint */ false, std::move(aPayloads),
1504
/* aUseForTelemetry */ scheduleAnyComposite);
1505
1506
if (scheduleAnyComposite) {
1507
ScheduleGenerateFrame(Nothing());
1508
} else if (sendDidComposite) {
1509
// The only thing in the pending transaction id queue should be the entry
1510
// we just added, and now we're going to pretend we rendered it
1511
MOZ_ASSERT(mPendingTransactionIds.size() == 1);
1512
if (CompositorBridgeParent* cbp = GetRootCompositorBridgeParent()) {
1513
TimeStamp now = TimeStamp::Now();
1514
cbp->NotifyPipelineRendered(mPipelineId, mWrEpoch, VsyncId(), now, now,
1515
now);
1516
}
1517
}
1518
1519
for (auto& update : aRenderRootUpdates) {
1520
wr::IpcResourceUpdateQueue::ReleaseShmems(this, update.mSmallShmems);
1521
wr::IpcResourceUpdateQueue::ReleaseShmems(this, update.mLargeShmems);
1522
}
1523
return IPC_OK();
1524
}
1525
1526
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetFocusTarget(
1527
const FocusTarget& aFocusTarget) {
1528
UpdateAPZFocusState(aFocusTarget);
1529
return IPC_OK();
1530
}
1531
1532
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvParentCommands(
1533
nsTArray<WebRenderParentCommand>&& aCommands,
1534
const wr::RenderRoot& aRenderRoot) {
1535
if (mDestroyed) {
1536
return IPC_OK();
1537
}
1538
1539
if (!mRenderRoot) {
1540
MOZ_ASSERT(aRenderRoot == RenderRoot::Default);
1541
PushDeferredPipelineData(AsVariant(ParentCommands{
1542
std::move(aCommands),
1543
}));
1544
return IPC_OK();
1545
}
1546
1547
wr::TransactionBuilder txn;
1548
txn.SetLowPriority(!IsRootWebRenderBridgeParent());
1549
if (!ProcessWebRenderParentCommands(aCommands, txn, aRenderRoot)) {
1550
return IPC_FAIL(this, "Invalid parent command found");
1551
}
1552
1553
Api(aRenderRoot)->SendTransaction(txn);
1554
return IPC_OK();
1555
}
1556
1557
bool WebRenderBridgeParent::ProcessWebRenderParentCommands(
1558
const nsTArray<WebRenderParentCommand>& aCommands,
1559
wr::TransactionBuilder& aTxn, wr::RenderRoot aRenderRoot) {
1560
// Transaction for async image pipeline that uses ImageBridge always need to
1561
// be non low priority.
1562
wr::TransactionBuilder txnForImageBridge;
1563
wr::AutoTransactionSender sender(Api(aRenderRoot), &txnForImageBridge);
1564
1565
for (nsTArray<WebRenderParentCommand>::index_type i = 0;
1566
i < aCommands.Length(); ++i) {
1567
const WebRenderParentCommand& cmd = aCommands[i];
1568
switch (cmd.type()) {
1569
case WebRenderParentCommand::TOpAddPipelineIdForCompositable: {
1570
const OpAddPipelineIdForCompositable& op =
1571
cmd.get_OpAddPipelineIdForCompositable();
1572
AddPipelineIdForCompositable(op.pipelineId(), op.handle(), op.isAsync(),
1573
aTxn, txnForImageBridge, aRenderRoot);
1574
break;
1575
}
1576
case WebRenderParentCommand::TOpRemovePipelineIdForCompositable: {
1577
const OpRemovePipelineIdForCompositable& op =
1578
cmd.get_OpRemovePipelineIdForCompositable();
1579
RemovePipelineIdForCompositable(op.pipelineId(), aTxn, aRenderRoot);
1580
break;
1581
}
1582
case WebRenderParentCommand::TOpReleaseTextureOfImage: {
1583
const OpReleaseTextureOfImage& op = cmd.get_OpReleaseTextureOfImage();
1584
ReleaseTextureOfImage(op.key());
1585
break;
1586
}
1587
case WebRenderParentCommand::TOpUpdateAsyncImagePipeline: {
1588
const OpUpdateAsyncImagePipeline& op =
1589
cmd.get_OpUpdateAsyncImagePipeline();
1590
mAsyncImageManager->UpdateAsyncImagePipeline(
1591
op.pipelineId(), op.scBounds(), op.scTransform(), op.scaleToSize(),
1592
op.filter(), op.mixBlendMode());
1593
mAsyncImageManager->ApplyAsyncImageForPipeline(
1594
op.pipelineId(), aTxn, txnForImageBridge,
1595
RenderRootForExternal(aRenderRoot));
1596
break;
1597
}
1598
case WebRenderParentCommand::TOpUpdatedAsyncImagePipeline: {
1599
const OpUpdatedAsyncImagePipeline& op =
1600
cmd.get_OpUpdatedAsyncImagePipeline();
1601
mAsyncImageManager->ApplyAsyncImageForPipeline(
1602
op.pipelineId(), aTxn, txnForImageBridge,
1603
RenderRootForExternal(aRenderRoot));
1604
break;
1605
}
1606
case WebRenderParentCommand::TCompositableOperation: {
1607
if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) {
1608
NS_ERROR("ReceiveCompositableUpdate failed");
1609
}
1610
break;
1611
}
1612
case WebRenderParentCommand::TOpAddCompositorAnimations: {
1613
const OpAddCompositorAnimations& op =
1614
cmd.get_OpAddCompositorAnimations();
1615
CompositorAnimations data(std::move(op.data()));
1616
// AnimationHelper::GetNextCompositorAnimationsId() encodes the child
1617
// process PID in the upper 32 bits of the id, verify that this is as
1618
// expected.
1619
if ((data.id() >> 32) != (uint64_t)OtherPid()) {
1620
return false;
1621
}
1622
if (data.animations().Length()) {
1623
mAnimStorage->SetAnimations(data.id(), data.animations(),
1624
RenderRootForExternal(aRenderRoot));
1625
const auto activeAnim = mActiveAnimations.find(data.id());
1626
if (activeAnim == mActiveAnimations.end()) {
1627
mActiveAnimations.emplace(data.id(), mWrEpoch);
1628
} else {
1629
// Update wr::Epoch if the animation already exists.
1630
activeAnim->second = mWrEpoch;
1631
}
1632
}
1633
break;
1634
}
1635
default: {
1636
// other commands are handle on the child
1637
break;
1638
}
1639
}
1640
}
1641
return true;
1642
}
1643
1644
void WebRenderBridgeParent::FlushSceneBuilds() {
1645
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1646
1647
// Since we are sending transactions through the scene builder thread, we need
1648
// to block until all the inflight transactions have been processed. This
1649
// flush message blocks until all previously sent scenes have been built
1650
// and received by the render backend thread.
1651
mApis[wr::RenderRoot::Default]->FlushSceneBuilder();
1652
// The post-swap hook for async-scene-building calls the
1653
// ScheduleRenderOnCompositorThread function from the scene builder thread,
1654
// which then triggers a call to ScheduleGenerateFrame() on the compositor
1655
// thread. But since *this* function is running on the compositor thread,
1656
// that scheduling will not happen until this call stack unwinds (or we
1657
// could spin a nested event loop, but that's more messy). Instead, we
1658
// simulate it ourselves by calling ScheduleGenerateFrame() directly.
1659
// Note also that the post-swap hook will run and do another
1660
// ScheduleGenerateFrame() after we unwind here, so we will end up with an
1661
// extra render/composite that is probably avoidable, but in practice we
1662
// shouldn't be calling this function all that much in production so this
1663
// is probably fine. If it becomes an issue we can add more state tracking
1664
// machinery to optimize it away.
1665
ScheduleGenerateFrameAllRenderRoots();
1666
}
1667
1668
void WebRenderBridgeParent::FlushFrameGeneration() {
1669
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1670
MOZ_ASSERT(IsRootWebRenderBridgeParent()); // This function is only useful on
1671
// the root WRBP
1672
1673
// This forces a new GenerateFrame transaction to be sent to the render
1674
// backend thread, if one is pending. This doesn't block on any other threads.
1675
if (mCompositorScheduler->NeedsComposite()) {
1676
mCompositorScheduler->CancelCurrentCompositeTask();
1677
// Update timestamp of scheduler for APZ and animation.
1678
mCompositorScheduler->UpdateLastComposeTime();
1679
MaybeGenerateFrame(VsyncId(), /* aForceGenerateFrame */ true);
1680
}
1681
}
1682
1683
void WebRenderBridgeParent::FlushFramePresentation() {
1684
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1685
1686
// This sends a message to the render backend thread to send a message
1687
// to the renderer thread, and waits for that message to be processed. So
1688
// this effectively blocks on the render backend and renderer threads,
1689
// following the same codepath that WebRender takes to render and composite
1690
// a frame.
1691
mApis[wr::RenderRoot::Default]->WaitFlushed();
1692
}
1693
1694
mozilla::ipc::IPCResult WebRenderBridgeParent::RecvGetSnapshot(
1695
PTextureParent* aTexture) {
1696
if (mDestroyed) {
1697
return IPC_OK();
1698
}
1699
MOZ_ASSERT(!mPaused);
1700
1701
// This function should only get called in the root WRBP. If this function
1702
// gets called in a non-root WRBP, we will set mForceRendering in this WRBP
1703
// but it will have no effect because CompositeToTarget (which reads the
1704
// flag) only gets invoked in the root WRBP. So we assert that this is the
1705
// root WRBP (i.e. has a non-null mWidget) to catch violations of this rule.
1706
MOZ_ASSERT(IsRootWebRenderBridgeParent());
1707
1708
RefPtr<TextureHost> texture = TextureHost::AsTextureHost(aTexture);
1709
if (!texture) {
1710
// We kill the content process rather than have it continue with an invalid
1711
// snapshot, that may be too harsh and we could decide to return some sort
1712
// of error to the child process and let it deal with it...
1713
return IPC_FAIL_NO_REASON(this);
1714
}
1715
1716
// XXX Add other TextureHost supports.
1717
// Only BufferTextureHost is supported now.
1718
BufferTextureHost* bufferTexture = texture->AsBufferTextureHost();
1719
if (!bufferTexture) {
1720
// We kill the content process rather than have it continue with an invalid
1721
// snapshot, that may be too harsh and we could decide to return some sort
1722
// of error to the child process and let it deal with it...
1723
return IPC_FAIL_NO_REASON(this);
1724
}
1725
1726
TimeStamp start = TimeStamp::Now();
1727
MOZ_ASSERT(bufferTexture->GetBufferDescriptor().type() ==
1728
BufferDescriptor::TRGBDescriptor);