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/. */
7 #include "AsyncImagePipelineManager.h"
12 #include "CompositableHost.h"
14 #include "mozilla/gfx/gfxVars.h"
15 #include "mozilla/layers/AsyncImagePipelineOp.h"
16 #include "mozilla/layers/CompositorThread.h"
17 #include "mozilla/layers/RemoteTextureHostWrapper.h"
18 #include "mozilla/layers/SharedSurfacesParent.h"
19 #include "mozilla/layers/WebRenderImageHost.h"
20 #include "mozilla/layers/WebRenderTextureHost.h"
21 #include "mozilla/webrender/RenderThread.h"
22 #include "mozilla/webrender/WebRenderAPI.h"
23 #include "mozilla/webrender/WebRenderTypes.h"
25 #ifdef MOZ_WIDGET_ANDROID
26 # include "mozilla/layers/TextureHostOGL.h"
32 AsyncImagePipelineManager::ForwardingExternalImage::~ForwardingExternalImage() {
33 DebugOnly
<bool> released
= SharedSurfacesParent::Release(mImageId
);
37 AsyncImagePipelineManager::AsyncImagePipeline::AsyncImagePipeline(
38 wr::PipelineId aPipelineId
, layers::WebRenderBackend aBackend
)
39 : mInitialised(false),
41 mUseExternalImage(false),
42 mRotation(wr::WrRotation::Degree0
),
43 mFilter(wr::ImageRendering::Auto
),
44 mMixBlendMode(wr::MixBlendMode::Normal
),
45 mDLBuilder(aPipelineId
, aBackend
) {}
47 AsyncImagePipelineManager::AsyncImagePipelineManager(
48 RefPtr
<wr::WebRenderAPI
>&& aApi
, bool aUseCompositorWnd
)
50 mUseCompositorWnd(aUseCompositorWnd
),
51 mIdNamespace(mApi
->GetNamespace()),
52 mUseTripleBuffering(mApi
->GetUseTripleBuffering()),
55 mWillGenerateFrame(false),
58 mUseWebRenderDCompVideoHwOverlayWin(
59 gfx::gfxVars::UseWebRenderDCompVideoHwOverlayWin()),
60 mUseWebRenderDCompVideoSwOverlayWin(
61 gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin()),
63 mRenderSubmittedUpdatesLock("SubmittedUpdatesLock"),
64 mLastCompletedFrameId(0) {
65 MOZ_COUNT_CTOR(AsyncImagePipelineManager
);
68 AsyncImagePipelineManager::~AsyncImagePipelineManager() {
69 MOZ_COUNT_DTOR(AsyncImagePipelineManager
);
72 void AsyncImagePipelineManager::Destroy() {
73 MOZ_ASSERT(!mDestroyed
);
75 mPipelineTexturesHolders
.Clear();
80 wr::ExternalImageId
AsyncImagePipelineManager::GetNextExternalImageId() {
81 static std::atomic
<uint64_t> sCounter
= 0;
83 uint64_t id
= ++sCounter
;
84 // Upper 32bit(namespace) needs to be 0.
85 // Namespace other than 0 might be used by others.
86 MOZ_RELEASE_ASSERT(id
!= UINT32_MAX
);
87 return wr::ToExternalImageId(id
);
90 void AsyncImagePipelineManager::SetWillGenerateFrame() {
91 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
93 mWillGenerateFrame
= true;
96 bool AsyncImagePipelineManager::GetAndResetWillGenerateFrame() {
97 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
99 bool ret
= mWillGenerateFrame
;
100 mWillGenerateFrame
= false;
104 void AsyncImagePipelineManager::AddPipeline(const wr::PipelineId
& aPipelineId
,
105 WebRenderBridgeParent
* aWrBridge
) {
110 mPipelineTexturesHolders
.WithEntryHandle(
111 wr::AsUint64(aPipelineId
), [&](auto&& holder
) {
113 // This could happen during tab move between different windows.
114 // Previously removed holder could be still alive for waiting
116 MOZ_ASSERT(holder
.Data()->mDestroyedEpoch
.isSome());
117 holder
.Data()->mDestroyedEpoch
= Nothing(); // Revive holder
118 holder
.Data()->mWrBridge
= aWrBridge
;
122 holder
.Insert(MakeUnique
<PipelineTexturesHolder
>())->mWrBridge
=
127 void AsyncImagePipelineManager::RemovePipeline(
128 const wr::PipelineId
& aPipelineId
, const wr::Epoch
& aEpoch
) {
133 PipelineTexturesHolder
* holder
=
134 mPipelineTexturesHolders
.Get(wr::AsUint64(aPipelineId
));
139 holder
->mWrBridge
= nullptr;
140 holder
->mDestroyedEpoch
= Some(aEpoch
);
143 WebRenderBridgeParent
* AsyncImagePipelineManager::GetWrBridge(
144 const wr::PipelineId
& aPipelineId
) {
149 PipelineTexturesHolder
* holder
=
150 mPipelineTexturesHolders
.Get(wr::AsUint64(aPipelineId
));
154 if (holder
->mWrBridge
) {
155 MOZ_ASSERT(holder
->mDestroyedEpoch
.isNothing());
156 return holder
->mWrBridge
;
162 void AsyncImagePipelineManager::AddAsyncImagePipeline(
163 const wr::PipelineId
& aPipelineId
, WebRenderImageHost
* aImageHost
) {
167 MOZ_ASSERT(aImageHost
);
168 uint64_t id
= wr::AsUint64(aPipelineId
);
170 MOZ_ASSERT(!mAsyncImagePipelines
.Contains(id
));
172 MakeUnique
<AsyncImagePipeline
>(aPipelineId
, mApi
->GetBackendType());
173 holder
->mImageHost
= aImageHost
;
174 mAsyncImagePipelines
.InsertOrUpdate(id
, std::move(holder
));
175 AddPipeline(aPipelineId
, /* aWrBridge */ nullptr);
178 void AsyncImagePipelineManager::RemoveAsyncImagePipeline(
179 const wr::PipelineId
& aPipelineId
, wr::TransactionBuilder
& aTxn
) {
184 uint64_t id
= wr::AsUint64(aPipelineId
);
185 if (auto entry
= mAsyncImagePipelines
.Lookup(id
)) {
186 const auto& holder
= entry
.Data();
187 wr::Epoch epoch
= GetNextImageEpoch();
188 aTxn
.ClearDisplayList(epoch
, aPipelineId
);
189 for (wr::ImageKey key
: holder
->mKeys
) {
190 aTxn
.DeleteImage(key
);
193 RemovePipeline(aPipelineId
, epoch
);
197 void AsyncImagePipelineManager::UpdateAsyncImagePipeline(
198 const wr::PipelineId
& aPipelineId
, const LayoutDeviceRect
& aScBounds
,
199 const wr::WrRotation aRotation
, const wr::ImageRendering
& aFilter
,
200 const wr::MixBlendMode
& aMixBlendMode
) {
204 AsyncImagePipeline
* pipeline
=
205 mAsyncImagePipelines
.Get(wr::AsUint64(aPipelineId
));
209 pipeline
->mInitialised
= true;
210 pipeline
->Update(aScBounds
, aRotation
, aFilter
, aMixBlendMode
);
213 Maybe
<TextureHost::ResourceUpdateOp
> AsyncImagePipelineManager::UpdateImageKeys(
214 const wr::Epoch
& aEpoch
, const wr::PipelineId
& aPipelineId
,
215 AsyncImagePipeline
* aPipeline
, TextureHost
* aTexture
,
216 nsTArray
<wr::ImageKey
>& aKeys
, wr::TransactionBuilder
& aSceneBuilderTxn
,
217 wr::TransactionBuilder
& aMaybeFastTxn
) {
218 MOZ_ASSERT(aKeys
.IsEmpty());
219 MOZ_ASSERT(aPipeline
);
221 TextureHost
* previousTexture
= aPipeline
->mCurrentTexture
.get();
223 if (aTexture
== previousTexture
) {
224 // The texture has not changed, just reuse previous ImageKeys.
225 aKeys
= aPipeline
->mKeys
.Clone();
229 auto* wrapper
= aTexture
? aTexture
->AsRemoteTextureHostWrapper() : nullptr;
230 if (wrapper
&& !aPipeline
->mImageHost
->GetAsyncRef()) {
231 std::function
<void(const RemoteTextureInfo
&)> function
;
232 RemoteTextureMap::Get()->GetRemoteTexture(wrapper
, std::move(function
));
235 if (!aTexture
|| aTexture
->NumSubTextures() == 0) {
236 // We don't have a new texture or texture does not have SubTextures, there
237 // isn't much we can do.
238 aKeys
= aPipeline
->mKeys
.Clone();
242 aPipeline
->mCurrentTexture
= aTexture
;
244 WebRenderTextureHost
* wrTexture
= aTexture
->AsWebRenderTextureHost();
245 MOZ_ASSERT(wrTexture
);
247 gfxCriticalNote
<< "WebRenderTextureHost is not used";
250 bool useExternalImage
= !!wrTexture
;
251 aPipeline
->mUseExternalImage
= useExternalImage
;
253 // The non-external image code path falls back to converting the texture into
255 auto numKeys
= useExternalImage
? aTexture
->NumSubTextures() : 1;
256 MOZ_ASSERT(numKeys
> 0);
258 // If we already had a texture and the format hasn't changed, better to reuse
259 // the image keys than create new ones.
260 auto backend
= aSceneBuilderTxn
.GetBackendType();
263 previousTexture
->GetTextureHostType() == aTexture
->GetTextureHostType() &&
264 previousTexture
->GetSize() == aTexture
->GetSize() &&
265 previousTexture
->GetFormat() == aTexture
->GetFormat() &&
266 previousTexture
->GetColorDepth() == aTexture
->GetColorDepth() &&
267 previousTexture
->NeedsYFlip() == aTexture
->NeedsYFlip() &&
268 previousTexture
->SupportsExternalCompositing(backend
) ==
269 aTexture
->SupportsExternalCompositing(backend
) &&
270 aPipeline
->mKeys
.Length() == numKeys
;
273 for (auto key
: aPipeline
->mKeys
) {
274 // Destroy ImageKeys on transaction of scene builder thread, since
275 // DisplayList is updated on SceneBuilder thread. It prevents too early
276 // ImageKey deletion.
277 aSceneBuilderTxn
.DeleteImage(key
);
279 aPipeline
->mKeys
.Clear();
280 for (uint32_t i
= 0; i
< numKeys
; ++i
) {
281 aPipeline
->mKeys
.AppendElement(GenerateImageKey());
285 aKeys
= aPipeline
->mKeys
.Clone();
287 auto op
= canUpdate
? TextureHost::UPDATE_IMAGE
: TextureHost::ADD_IMAGE
;
289 if (!useExternalImage
) {
290 return UpdateWithoutExternalImage(aTexture
, aKeys
[0], op
, aMaybeFastTxn
);
293 wrTexture
->MaybeNotifyForUse(aMaybeFastTxn
);
295 Range
<wr::ImageKey
> keys(&aKeys
[0], aKeys
.Length());
296 auto externalImageKey
= wrTexture
->GetExternalImageKey();
297 wrTexture
->PushResourceUpdates(aMaybeFastTxn
, op
, keys
, externalImageKey
);
302 Maybe
<TextureHost::ResourceUpdateOp
>
303 AsyncImagePipelineManager::UpdateWithoutExternalImage(
304 TextureHost
* aTexture
, wr::ImageKey aKey
, TextureHost::ResourceUpdateOp aOp
,
305 wr::TransactionBuilder
& aTxn
) {
306 MOZ_ASSERT(aTexture
);
308 RefPtr
<gfx::DataSourceSurface
> dSurf
= aTexture
->GetAsSurface();
310 NS_ERROR("TextureHost does not return DataSourceSurface");
313 gfx::DataSourceSurface::MappedSurface map
;
314 if (!dSurf
->Map(gfx::DataSourceSurface::MapType::READ
, &map
)) {
315 NS_ERROR("DataSourceSurface failed to map");
319 gfx::IntSize size
= dSurf
->GetSize();
320 wr::ImageDescriptor
descriptor(size
, map
.mStride
, dSurf
->GetFormat());
322 // Costly copy right here...
323 wr::Vec
<uint8_t> bytes
;
324 bytes
.PushBytes(Range
<uint8_t>(map
.mData
, size
.height
* map
.mStride
));
326 if (aOp
== TextureHost::UPDATE_IMAGE
) {
327 aTxn
.UpdateImageBuffer(aKey
, descriptor
, bytes
);
329 aTxn
.AddImage(aKey
, descriptor
, bytes
);
337 void AsyncImagePipelineManager::ApplyAsyncImagesOfImageBridge(
338 wr::TransactionBuilder
& aSceneBuilderTxn
,
339 wr::TransactionBuilder
& aFastTxn
) {
340 if (mDestroyed
|| mAsyncImagePipelines
.Count() == 0) {
345 // UseWebRenderDCompVideoHwOverlayWin() and
346 // UseWebRenderDCompVideoSwOverlayWin() could be changed from true to false,
347 // when DCompVideoOverlay task is failed. In this case, DisplayItems need to
348 // be re-pushed to WebRender for disabling video overlay.
349 bool isChanged
= (mUseWebRenderDCompVideoHwOverlayWin
!=
350 gfx::gfxVars::UseWebRenderDCompVideoHwOverlayWin()) ||
351 (mUseWebRenderDCompVideoSwOverlayWin
!=
352 gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin());
355 mUseWebRenderDCompVideoHwOverlayWin
=
356 gfx::gfxVars::UseWebRenderDCompVideoHwOverlayWin();
357 mUseWebRenderDCompVideoSwOverlayWin
=
358 gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin();
362 wr::Epoch epoch
= GetNextImageEpoch();
364 // We use a pipeline with a very small display list for each video element.
365 // Update each of them if needed.
366 for (const auto& entry
: mAsyncImagePipelines
) {
367 wr::PipelineId pipelineId
= wr::AsPipelineId(entry
.GetKey());
368 AsyncImagePipeline
* pipeline
= entry
.GetWeak();
372 pipeline
->mIsChanged
= true;
376 // If aync image pipeline does not use ImageBridge, do not need to apply.
377 if (!pipeline
->mImageHost
->GetAsyncRef()) {
380 TextureHost
* texture
=
381 pipeline
->mImageHost
->GetAsTextureHostForComposite(this);
383 ApplyAsyncImageForPipeline(epoch
, pipelineId
, pipeline
, texture
,
384 aSceneBuilderTxn
, aFastTxn
);
388 void AsyncImagePipelineManager::ApplyAsyncImageForPipeline(
389 const wr::Epoch
& aEpoch
, const wr::PipelineId
& aPipelineId
,
390 AsyncImagePipeline
* aPipeline
, TextureHost
* aTexture
,
391 wr::TransactionBuilder
& aSceneBuilderTxn
,
392 wr::TransactionBuilder
& aMaybeFastTxn
) {
393 nsTArray
<wr::ImageKey
> keys
;
394 auto op
= UpdateImageKeys(aEpoch
, aPipelineId
, aPipeline
, aTexture
, keys
,
395 aSceneBuilderTxn
, aMaybeFastTxn
);
397 bool updateDisplayList
=
398 aPipeline
->mInitialised
&&
399 (aPipeline
->mIsChanged
|| op
== Some(TextureHost::ADD_IMAGE
)) &&
400 !!aPipeline
->mCurrentTexture
;
402 if (!updateDisplayList
) {
403 // We don't need to update the display list, either because we can't or
404 // because the previous one is still up to date. We may, however, have
405 // updated some resources.
407 // Use transaction of scene builder thread to notify epoch.
408 // It is for making epoch update consistent.
409 aSceneBuilderTxn
.UpdateEpoch(aPipelineId
, aEpoch
);
410 if (aPipeline
->mCurrentTexture
) {
411 HoldExternalImage(aPipelineId
, aEpoch
, aPipeline
->mCurrentTexture
);
416 aPipeline
->mIsChanged
= false;
417 aPipeline
->mDLBuilder
.Begin();
419 float opacity
= 1.0f
;
420 wr::StackingContextParams params
;
421 params
.opacity
= &opacity
;
422 params
.mix_blend_mode
= aPipeline
->mMixBlendMode
;
424 wr::WrComputedTransformData computedTransform
;
425 computedTransform
.vertical_flip
=
426 aPipeline
->mCurrentTexture
&& aPipeline
->mCurrentTexture
->NeedsYFlip();
427 computedTransform
.scale_from
= {
428 float(aPipeline
->mCurrentTexture
->GetSize().width
),
429 float(aPipeline
->mCurrentTexture
->GetSize().height
)};
430 computedTransform
.rotation
= aPipeline
->mRotation
;
431 // We don't have a frame / per-frame key here, but we can use the pipeline id
432 // and the key kind to create a unique stable key.
433 computedTransform
.key
= wr::SpatialKey(
434 aPipelineId
.mNamespace
, aPipelineId
.mHandle
, wr::SpatialKeyKind::APZ
);
435 params
.computed_transform
= &computedTransform
;
437 Maybe
<wr::WrSpatialId
> referenceFrameId
=
438 aPipeline
->mDLBuilder
.PushStackingContext(
439 params
, wr::ToLayoutRect(aPipeline
->mScBounds
),
440 // This is fine to do unconditionally because we only push images
442 wr::RasterSpace::Screen());
444 Maybe
<wr::SpaceAndClipChainHelper
> spaceAndClipChainHelper
;
445 if (referenceFrameId
) {
446 spaceAndClipChainHelper
.emplace(aPipeline
->mDLBuilder
,
447 referenceFrameId
.ref());
450 if (aPipeline
->mCurrentTexture
&& !keys
.IsEmpty()) {
451 LayoutDeviceRect
rect(0, 0, aPipeline
->mCurrentTexture
->GetSize().width
,
452 aPipeline
->mCurrentTexture
->GetSize().height
);
454 if (aPipeline
->mUseExternalImage
) {
455 MOZ_ASSERT(aPipeline
->mCurrentTexture
->AsWebRenderTextureHost());
456 Range
<wr::ImageKey
> range_keys(&keys
[0], keys
.Length());
457 TextureHost::PushDisplayItemFlagSet flags
;
458 flags
+= TextureHost::PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE
;
459 if (mApi
->SupportsExternalBufferTextures()) {
461 TextureHost::PushDisplayItemFlag::SUPPORTS_EXTERNAL_BUFFER_TEXTURES
;
463 aPipeline
->mCurrentTexture
->PushDisplayItems(
464 aPipeline
->mDLBuilder
, wr::ToLayoutRect(rect
), wr::ToLayoutRect(rect
),
465 aPipeline
->mFilter
, range_keys
, flags
);
466 HoldExternalImage(aPipelineId
, aEpoch
, aPipeline
->mCurrentTexture
);
468 MOZ_ASSERT(keys
.Length() == 1);
469 aPipeline
->mDLBuilder
.PushImage(wr::ToLayoutRect(rect
),
470 wr::ToLayoutRect(rect
), true, false,
471 aPipeline
->mFilter
, keys
[0]);
475 spaceAndClipChainHelper
.reset();
476 aPipeline
->mDLBuilder
.PopStackingContext(referenceFrameId
.isSome());
478 wr::BuiltDisplayList dl
;
479 aPipeline
->mDLBuilder
.End(dl
);
480 aSceneBuilderTxn
.SetDisplayList(aEpoch
, aPipelineId
, dl
.dl_desc
, dl
.dl_items
,
481 dl
.dl_cache
, dl
.dl_spatial_tree
);
484 void AsyncImagePipelineManager::ApplyAsyncImageForPipeline(
485 const wr::PipelineId
& aPipelineId
, wr::TransactionBuilder
& aTxn
,
486 wr::TransactionBuilder
& aTxnForImageBridge
,
487 AsyncImagePipelineOps
* aPendingOps
,
488 RemoteTextureInfoList
* aPendingRemoteTextures
) {
489 AsyncImagePipeline
* pipeline
=
490 mAsyncImagePipelines
.Get(wr::AsUint64(aPipelineId
));
495 // ready event of RemoteTexture that uses ImageBridge do not need to be
497 if (pipeline
->mImageHost
->GetAsyncRef()) {
498 aPendingRemoteTextures
= nullptr;
501 wr::TransactionBuilder
fastTxn(mApi
, /* aUseSceneBuilderThread */ false);
502 wr::AutoTransactionSender
sender(mApi
, &fastTxn
);
504 // Transaction for async image pipeline that uses ImageBridge always need to
505 // be non low priority.
506 auto& sceneBuilderTxn
=
507 pipeline
->mImageHost
->GetAsyncRef() ? aTxnForImageBridge
: aTxn
;
509 // Use transaction of using non scene builder thread when ImageHost uses
510 // ImageBridge. ApplyAsyncImagesOfImageBridge() handles transaction of adding
511 // and updating wr::ImageKeys of ImageHosts that uses ImageBridge. Then
512 // AsyncImagePipelineManager always needs to use non scene builder thread
513 // transaction for adding and updating wr::ImageKeys of ImageHosts that uses
514 // ImageBridge. Otherwise, ordering of wr::ImageKeys updating in webrender
515 // becomes inconsistent.
516 auto& maybeFastTxn
= pipeline
->mImageHost
->GetAsyncRef() ? fastTxn
: aTxn
;
518 wr::Epoch epoch
= GetNextImageEpoch();
519 TextureHost
* texture
=
520 pipeline
->mImageHost
->GetAsTextureHostForComposite(this);
521 auto* wrapper
= texture
? texture
->AsRemoteTextureHostWrapper() : nullptr;
523 // Store pending remote texture that is used for waiting at WebRenderAPI.
524 if (aPendingRemoteTextures
&& texture
&&
525 texture
!= pipeline
->mCurrentTexture
&& wrapper
) {
526 aPendingRemoteTextures
->mList
.emplace(wrapper
->mTextureId
,
527 wrapper
->mOwnerId
, wrapper
->mForPid
);
530 if (aPendingOps
&& !pipeline
->mImageHost
->GetAsyncRef()) {
531 aPendingOps
->mList
.emplace(AsyncImagePipelineOp::ApplyAsyncImageForPipeline(
532 this, aPipelineId
, texture
));
536 ApplyAsyncImageForPipeline(epoch
, aPipelineId
, pipeline
, texture
,
537 sceneBuilderTxn
, maybeFastTxn
);
540 void AsyncImagePipelineManager::ApplyAsyncImageForPipeline(
541 const wr::PipelineId
& aPipelineId
, TextureHost
* aTexture
,
542 wr::TransactionBuilder
& aTxn
) {
543 AsyncImagePipeline
* pipeline
=
544 mAsyncImagePipelines
.Get(wr::AsUint64(aPipelineId
));
548 MOZ_ASSERT(!pipeline
->mImageHost
->GetAsyncRef());
550 wr::Epoch epoch
= GetNextImageEpoch();
551 ApplyAsyncImageForPipeline(epoch
, aPipelineId
, pipeline
, aTexture
, aTxn
,
555 void AsyncImagePipelineManager::SetEmptyDisplayList(
556 const wr::PipelineId
& aPipelineId
, wr::TransactionBuilder
& aTxn
,
557 wr::TransactionBuilder
& aTxnForImageBridge
) {
558 AsyncImagePipeline
* pipeline
=
559 mAsyncImagePipelines
.Get(wr::AsUint64(aPipelineId
));
564 // Transaction for async image pipeline that uses ImageBridge always need to
565 // be non low priority.
566 auto& txn
= pipeline
->mImageHost
->GetAsyncRef() ? aTxnForImageBridge
: aTxn
;
568 wr::Epoch epoch
= GetNextImageEpoch();
569 wr::DisplayListBuilder
builder(aPipelineId
, mApi
->GetBackendType());
572 wr::BuiltDisplayList dl
;
574 txn
.SetDisplayList(epoch
, aPipelineId
, dl
.dl_desc
, dl
.dl_items
, dl
.dl_cache
,
578 void AsyncImagePipelineManager::HoldExternalImage(
579 const wr::PipelineId
& aPipelineId
, const wr::Epoch
& aEpoch
,
580 TextureHost
* aTexture
) {
584 MOZ_ASSERT(aTexture
);
586 PipelineTexturesHolder
* holder
=
587 mPipelineTexturesHolders
.Get(wr::AsUint64(aPipelineId
));
592 if (aTexture
->NeedsDeferredDeletion()) {
593 // Hold WebRenderTextureHost until rendering completed.
594 holder
->mTextureHostsUntilRenderCompleted
.emplace_back(
595 MakeUnique
<ForwardingTextureHost
>(aEpoch
, aTexture
));
597 // Hold WebRenderTextureHost until submitted for rendering.
598 holder
->mTextureHostsUntilRenderSubmitted
.emplace_back(aEpoch
, aTexture
);
602 void AsyncImagePipelineManager::HoldExternalImage(
603 const wr::PipelineId
& aPipelineId
, const wr::Epoch
& aEpoch
,
604 const wr::ExternalImageId
& aImageId
) {
606 SharedSurfacesParent::Release(aImageId
);
610 PipelineTexturesHolder
* holder
=
611 mPipelineTexturesHolders
.Get(wr::AsUint64(aPipelineId
));
614 SharedSurfacesParent::Release(aImageId
);
618 holder
->mExternalImages
.emplace_back(
619 MakeUnique
<ForwardingExternalImage
>(aEpoch
, aImageId
));
622 void AsyncImagePipelineManager::NotifyPipelinesUpdated(
623 RefPtr
<const wr::WebRenderPipelineInfo
> aInfo
,
624 wr::RenderedFrameId aLatestFrameId
,
625 wr::RenderedFrameId aLastCompletedFrameId
, ipc::FileDescriptor
&& aFenceFd
) {
626 MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
627 MOZ_ASSERT(mLastCompletedFrameId
<= aLastCompletedFrameId
.mId
);
628 MOZ_ASSERT(aLatestFrameId
.IsValid());
630 mLastCompletedFrameId
= aLastCompletedFrameId
.mId
;
633 // We need to lock for mRenderSubmittedUpdates because it can be accessed
634 // on the compositor thread.
635 MutexAutoLock
lock(mRenderSubmittedUpdatesLock
);
637 // Move the pending updates into the submitted ones.
638 mRenderSubmittedUpdates
.emplace_back(
640 WebRenderPipelineInfoHolder(std::move(aInfo
), std::move(aFenceFd
)));
643 // Queue a runnable on the compositor thread to process the updates.
644 // This will also call CheckForTextureHostsNotUsedByGPU.
645 layers::CompositorThread()->Dispatch(
646 NewRunnableMethod("ProcessPipelineUpdates", this,
647 &AsyncImagePipelineManager::ProcessPipelineUpdates
));
650 void AsyncImagePipelineManager::ProcessPipelineUpdates() {
651 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
657 std::vector
<std::pair
<wr::RenderedFrameId
, WebRenderPipelineInfoHolder
>>
660 // We need to lock for mRenderSubmittedUpdates because it can be accessed on
661 // the compositor thread.
662 MutexAutoLock
lock(mRenderSubmittedUpdatesLock
);
663 mRenderSubmittedUpdates
.swap(submittedUpdates
);
666 // submittedUpdates is a vector of RenderedFrameIds paired with vectors of
667 // WebRenderPipelineInfo.
668 for (auto update
: submittedUpdates
) {
669 auto& holder
= update
.second
;
670 const auto& info
= holder
.mInfo
->Raw();
672 mReleaseFenceFd
= std::move(holder
.mFenceFd
);
674 for (auto& epoch
: info
.epochs
) {
675 ProcessPipelineRendered(epoch
.pipeline_id
, epoch
.epoch
, update
.first
);
677 for (auto& removedPipeline
: info
.removed_pipelines
) {
678 ProcessPipelineRemoved(removedPipeline
, update
.first
);
681 CheckForTextureHostsNotUsedByGPU();
684 void AsyncImagePipelineManager::ProcessPipelineRendered(
685 const wr::PipelineId
& aPipelineId
, const wr::Epoch
& aEpoch
,
686 wr::RenderedFrameId aRenderedFrameId
) {
687 if (auto entry
= mPipelineTexturesHolders
.Lookup(wr::AsUint64(aPipelineId
))) {
688 const auto& holder
= entry
.Data();
689 // For TextureHosts that can be released on render submission, using aEpoch
690 // find the first that we can't release and then release all prior to that.
691 auto firstSubmittedHostToKeep
= std::find_if(
692 holder
->mTextureHostsUntilRenderSubmitted
.begin(),
693 holder
->mTextureHostsUntilRenderSubmitted
.end(),
694 [&aEpoch
](const auto& entry
) { return aEpoch
<= entry
.mEpoch
; });
695 #ifdef MOZ_WIDGET_ANDROID
696 // Set release fence if TextureHost owns AndroidHardwareBuffer.
697 // The TextureHost handled by mTextureHostsUntilRenderSubmitted instead of
698 // mTextureHostsUntilRenderCompleted, since android fence could be used
699 // to wait until its end of usage by GPU.
700 for (auto it
= holder
->mTextureHostsUntilRenderSubmitted
.begin();
701 it
!= firstSubmittedHostToKeep
; ++it
) {
702 const auto& entry
= it
;
703 if (entry
->mTexture
->GetAndroidHardwareBuffer() &&
704 mReleaseFenceFd
.IsValid()) {
705 ipc::FileDescriptor fenceFd
= mReleaseFenceFd
;
706 entry
->mTexture
->SetReleaseFence(std::move(fenceFd
));
710 holder
->mTextureHostsUntilRenderSubmitted
.erase(
711 holder
->mTextureHostsUntilRenderSubmitted
.begin(),
712 firstSubmittedHostToKeep
);
714 // For TextureHosts that need to wait until render completed, find the first
715 // that is later than aEpoch and then move all prior to that to
716 // mTexturesInUseByGPU paired with aRenderedFrameId. These will be released
717 // once rendering has completed for aRenderedFrameId.
718 auto firstCompletedHostToKeep
= std::find_if(
719 holder
->mTextureHostsUntilRenderCompleted
.begin(),
720 holder
->mTextureHostsUntilRenderCompleted
.end(),
721 [&aEpoch
](const auto& entry
) { return aEpoch
<= entry
->mEpoch
; });
722 if (firstCompletedHostToKeep
!=
723 holder
->mTextureHostsUntilRenderCompleted
.begin()) {
724 std::vector
<UniquePtr
<ForwardingTextureHost
>> hostsUntilCompleted(
725 std::make_move_iterator(
726 holder
->mTextureHostsUntilRenderCompleted
.begin()),
727 std::make_move_iterator(firstCompletedHostToKeep
));
728 mTexturesInUseByGPU
.emplace_back(aRenderedFrameId
,
729 std::move(hostsUntilCompleted
));
730 holder
->mTextureHostsUntilRenderCompleted
.erase(
731 holder
->mTextureHostsUntilRenderCompleted
.begin(),
732 firstCompletedHostToKeep
);
735 // Using aEpoch, find the first external image that we can't release and
736 // then release all prior to that.
737 auto firstImageToKeep
= std::find_if(
738 holder
->mExternalImages
.begin(), holder
->mExternalImages
.end(),
739 [&aEpoch
](const auto& entry
) { return aEpoch
<= entry
->mEpoch
; });
740 holder
->mExternalImages
.erase(holder
->mExternalImages
.begin(),
745 void AsyncImagePipelineManager::ProcessPipelineRemoved(
746 const wr::RemovedPipeline
& aRemovedPipeline
,
747 wr::RenderedFrameId aRenderedFrameId
) {
751 if (auto entry
= mPipelineTexturesHolders
.Lookup(
752 wr::AsUint64(aRemovedPipeline
.pipeline_id
))) {
753 const auto& holder
= entry
.Data();
754 if (holder
->mDestroyedEpoch
.isSome()) {
755 if (!holder
->mTextureHostsUntilRenderCompleted
.empty()) {
756 // Move all TextureHosts that must be held until render completed to
757 // mTexturesInUseByGPU paired with aRenderedFrameId.
758 mTexturesInUseByGPU
.emplace_back(
760 std::move(holder
->mTextureHostsUntilRenderCompleted
));
763 // Remove Pipeline releasing all remaining TextureHosts and external
768 // If mDestroyedEpoch contains nothing it means we reused the same pipeline
769 // id (probably because we moved the tab to another window). In this case we
770 // need to keep the holder.
774 void AsyncImagePipelineManager::CheckForTextureHostsNotUsedByGPU() {
775 uint64_t lastCompletedFrameId
= mLastCompletedFrameId
;
777 // Find first entry after mLastCompletedFrameId and release all prior ones.
778 auto firstTexturesToKeep
=
779 std::find_if(mTexturesInUseByGPU
.begin(), mTexturesInUseByGPU
.end(),
780 [lastCompletedFrameId
](const auto& entry
) {
781 return lastCompletedFrameId
< entry
.first
.mId
;
783 mTexturesInUseByGPU
.erase(mTexturesInUseByGPU
.begin(), firstTexturesToKeep
);
786 wr::Epoch
AsyncImagePipelineManager::GetNextImageEpoch() {
787 mAsyncImageEpoch
.mHandle
++;
788 return mAsyncImageEpoch
;
791 AsyncImagePipelineManager::WebRenderPipelineInfoHolder::
792 WebRenderPipelineInfoHolder(RefPtr
<const wr::WebRenderPipelineInfo
>&& aInfo
,
793 ipc::FileDescriptor
&& aFenceFd
)
794 : mInfo(aInfo
), mFenceFd(aFenceFd
) {}
796 AsyncImagePipelineManager::WebRenderPipelineInfoHolder::
797 ~WebRenderPipelineInfoHolder() = default;
799 } // namespace layers
800 } // namespace mozilla