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 "mozilla/layers/RemoteTextureMap.h"
11 #include "CompositableHost.h"
12 #include "mozilla/gfx/gfxVars.h"
13 #include "mozilla/layers/AsyncImagePipelineManager.h"
14 #include "mozilla/layers/BufferTexture.h"
15 #include "mozilla/layers/CompositorThread.h"
16 #include "mozilla/layers/ImageDataSerializer.h"
17 #include "mozilla/layers/RemoteTextureHostWrapper.h"
18 #include "mozilla/layers/WebRenderTextureHost.h"
19 #include "mozilla/StaticPrefs_webgl.h"
20 #include "mozilla/webrender/RenderThread.h"
21 #include "SharedSurface.h"
23 namespace mozilla::layers
{
25 RemoteTextureOwnerClient::RemoteTextureOwnerClient(
26 const base::ProcessId aForPid
)
29 RemoteTextureOwnerClient::~RemoteTextureOwnerClient() = default;
31 bool RemoteTextureOwnerClient::IsRegistered(
32 const RemoteTextureOwnerId aOwnerId
) {
33 auto it
= mOwnerIds
.find(aOwnerId
);
34 if (it
== mOwnerIds
.end()) {
40 void RemoteTextureOwnerClient::RegisterTextureOwner(
41 const RemoteTextureOwnerId aOwnerId
, bool aIsSyncMode
) {
42 MOZ_ASSERT(mOwnerIds
.find(aOwnerId
) == mOwnerIds
.end());
43 mOwnerIds
.emplace(aOwnerId
);
44 RemoteTextureMap::Get()->RegisterTextureOwner(aOwnerId
, mForPid
, aIsSyncMode
);
47 void RemoteTextureOwnerClient::UnregisterTextureOwner(
48 const RemoteTextureOwnerId aOwnerId
) {
49 auto it
= mOwnerIds
.find(aOwnerId
);
50 if (it
== mOwnerIds
.end()) {
54 RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId
, mForPid
);
57 void RemoteTextureOwnerClient::UnregisterAllTextureOwners() {
58 if (mOwnerIds
.empty()) {
61 RemoteTextureMap::Get()->UnregisterTextureOwners(mOwnerIds
, mForPid
);
65 void RemoteTextureOwnerClient::NotifyContextLost() {
66 if (mOwnerIds
.empty()) {
69 RemoteTextureMap::Get()->NotifyContextLost(mOwnerIds
, mForPid
);
72 void RemoteTextureOwnerClient::PushTexture(
73 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
74 UniquePtr
<TextureData
>&& aTextureData
,
75 const std::shared_ptr
<gl::SharedSurface
>& aSharedSurface
) {
76 MOZ_ASSERT(IsRegistered(aOwnerId
));
78 RefPtr
<TextureHost
> textureHost
= RemoteTextureMap::CreateRemoteTexture(
79 aTextureData
.get(), TextureFlags::DEFAULT
);
81 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
85 RemoteTextureMap::Get()->PushTexture(aTextureId
, aOwnerId
, mForPid
,
86 std::move(aTextureData
), textureHost
,
90 void RemoteTextureOwnerClient::PushDummyTexture(
91 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
) {
92 MOZ_ASSERT(IsRegistered(aOwnerId
));
94 auto flags
= TextureFlags::DEALLOCATE_CLIENT
| TextureFlags::REMOTE_TEXTURE
|
95 TextureFlags::DUMMY_TEXTURE
;
96 auto* rawData
= BufferTextureData::Create(
97 gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8
, gfx::BackendType::SKIA
,
98 LayersBackend::LAYERS_WR
, flags
, ALLOC_DEFAULT
, nullptr);
100 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
104 auto textureData
= UniquePtr
<TextureData
>(rawData
);
106 RefPtr
<TextureHost
> textureHost
= RemoteTextureMap::CreateRemoteTexture(
107 textureData
.get(), TextureFlags::DUMMY_TEXTURE
);
109 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
113 RemoteTextureMap::Get()->PushTexture(aTextureId
, aOwnerId
, mForPid
,
114 std::move(textureData
), textureHost
,
115 /* aSharedSurface */ nullptr);
118 void RemoteTextureOwnerClient::GetLatestBufferSnapshot(
119 const RemoteTextureOwnerId aOwnerId
, const mozilla::ipc::Shmem
& aDestShmem
,
120 const gfx::IntSize
& aSize
) {
121 MOZ_ASSERT(IsRegistered(aOwnerId
));
122 RemoteTextureMap::Get()->GetLatestBufferSnapshot(aOwnerId
, mForPid
,
126 UniquePtr
<TextureData
>
127 RemoteTextureOwnerClient::CreateOrRecycleBufferTextureData(
128 const RemoteTextureOwnerId aOwnerId
, gfx::IntSize aSize
,
129 gfx::SurfaceFormat aFormat
) {
130 auto texture
= RemoteTextureMap::Get()->GetRecycledBufferTextureData(
131 aOwnerId
, mForPid
, aSize
, aFormat
);
136 auto flags
= TextureFlags::DEALLOCATE_CLIENT
| TextureFlags::REMOTE_TEXTURE
;
137 auto* data
= BufferTextureData::Create(aSize
, aFormat
, gfx::BackendType::SKIA
,
138 LayersBackend::LAYERS_WR
, flags
,
139 ALLOC_DEFAULT
, nullptr);
140 return UniquePtr
<TextureData
>(data
);
143 std::shared_ptr
<gl::SharedSurface
>
144 RemoteTextureOwnerClient::GetRecycledSharedSurface(
145 const RemoteTextureOwnerId aOwnerId
) {
146 return RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedSurface(
150 StaticAutoPtr
<RemoteTextureMap
> RemoteTextureMap::sInstance
;
153 void RemoteTextureMap::Init() {
154 MOZ_ASSERT(!sInstance
);
155 sInstance
= new RemoteTextureMap();
159 void RemoteTextureMap::Shutdown() {
165 RemoteTextureMap::RemoteTextureMap() : mMonitor("D3D11TextureMap::mMonitor") {}
167 RemoteTextureMap::~RemoteTextureMap() = default;
169 void RemoteTextureMap::PushTexture(
170 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
171 const base::ProcessId aForPid
, UniquePtr
<TextureData
>&& aTextureData
,
172 RefPtr
<TextureHost
>& aTextureHost
,
173 const std::shared_ptr
<gl::SharedSurface
>& aSharedSurface
) {
174 MOZ_RELEASE_ASSERT(aTextureHost
);
176 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
177 renderingReadyCallbacks
; // Call outside the monitor
179 MonitorAutoLock
lock(mMonitor
);
181 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
183 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
187 if (owner
->mIsContextLost
&&
188 !(aTextureHost
->GetFlags() & TextureFlags::DUMMY_TEXTURE
)) {
189 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
190 gfxCriticalNoteOnce
<< "Texture pushed during context lost";
193 const auto key
= std::pair(aForPid
, aOwnerId
);
194 auto it
= mRemoteTexturePushListeners
.find(key
);
195 // Notify a new texture if callback is requested
196 if (it
!= mRemoteTexturePushListeners
.end()) {
197 RefPtr
<CompositableHost
> compositableHost
= it
->second
;
198 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
199 "RemoteTextureMap::PushTexture::Runnable",
200 [compositableHost
, aTextureId
, aOwnerId
, aForPid
]() {
201 compositableHost
->NotifyPushTexture(aTextureId
, aOwnerId
, aForPid
);
203 CompositorThread()->Dispatch(runnable
.forget());
206 auto textureData
= MakeUnique
<TextureDataHolder
>(
207 aTextureId
, aTextureHost
, std::move(aTextureData
), aSharedSurface
);
209 MOZ_ASSERT(owner
->mLatestTextureId
< aTextureId
);
211 owner
->mWaitingTextureDataHolders
.push_back(std::move(textureData
));
213 if (!owner
->mIsSyncMode
) {
214 renderingReadyCallbacks
=
215 GetRenderingReadyCallbacks(lock
, owner
, aTextureId
);
216 // Update mAsyncRemoteTextureHost for async mode.
217 // This happens when PushTexture() with RemoteTextureId is called after
218 // GetRemoteTextureForDisplayList() with the RemoteTextureId.
219 const auto key
= std::pair(aForPid
, aTextureId
);
220 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
221 if (it
!= mRemoteTextureHostWrapperHolders
.end()) {
222 MOZ_ASSERT(!it
->second
->mAsyncRemoteTextureHost
);
223 it
->second
->mAsyncRemoteTextureHost
= aTextureHost
;
229 // Release owner->mReleasingRenderedTextureHosts before checking
230 // NumCompositableRefs()
231 if (!owner
->mReleasingRenderedTextureHosts
.empty()) {
232 owner
->mReleasingRenderedTextureHosts
.clear();
235 // Drop obsoleted remote textures.
236 while (!owner
->mUsingTextureDataHolders
.empty()) {
237 auto& front
= owner
->mUsingTextureDataHolders
.front();
238 // When compositable ref of TextureHost becomes 0, the TextureHost is not
239 // used by WebRender anymore.
240 if (front
->mTextureHost
&&
241 front
->mTextureHost
->NumCompositableRefs() == 0) {
242 // Recycle gl::SharedSurface
243 if (front
->mSharedSurface
) {
244 owner
->mRecycledSharedSurfaces
.push(front
->mSharedSurface
);
245 front
->mSharedSurface
= nullptr;
247 // Recycle BufferTextureData
248 if (!(front
->mTextureHost
->GetFlags() & TextureFlags::DUMMY_TEXTURE
) &&
249 (front
->mTextureData
&&
250 front
->mTextureData
->AsBufferTextureData())) {
251 owner
->mRecycledTextures
.push(std::move(front
->mTextureData
));
253 owner
->mUsingTextureDataHolders
.pop_front();
254 } else if (front
->mTextureHost
&&
255 front
->mTextureHost
->NumCompositableRefs() >= 0) {
256 // Remote texture is still in use by WebRender.
259 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
260 owner
->mUsingTextureDataHolders
.pop_front();
265 const auto info
= RemoteTextureInfo(aTextureId
, aOwnerId
, aForPid
);
266 for (auto& callback
: renderingReadyCallbacks
) {
271 void RemoteTextureMap::GetLatestBufferSnapshot(
272 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
,
273 const mozilla::ipc::Shmem
& aDestShmem
, const gfx::IntSize
& aSize
) {
274 // The compositable ref of remote texture should be updated in mMonitor lock.
275 CompositableTextureHostRef textureHostRef
;
276 RefPtr
<TextureHost
> releasingTexture
; // Release outside the monitor
278 MonitorAutoLock
lock(mMonitor
);
280 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
282 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
286 // Get latest TextureHost of remote Texture.
287 if (owner
->mWaitingTextureDataHolders
.empty() &&
288 !owner
->mLatestTextureHost
) {
291 TextureHost
* textureHost
=
292 !owner
->mWaitingTextureDataHolders
.empty()
293 ? owner
->mWaitingTextureDataHolders
.back()->mTextureHost
294 : owner
->mLatestTextureHost
;
295 if (!textureHost
->AsBufferTextureHost()) {
296 // Only BufferTextureHost is supported for now.
297 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
300 if (textureHost
->GetSize() != aSize
) {
301 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
304 if (textureHost
->GetFormat() != gfx::SurfaceFormat::R8G8B8A8
&&
305 textureHost
->GetFormat() != gfx::SurfaceFormat::B8G8R8A8
) {
306 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
309 // Increment compositable ref to prevent that TextureHost is removed during
311 textureHostRef
= textureHost
;
314 if (!textureHostRef
) {
318 auto* bufferTextureHost
= textureHostRef
->AsBufferTextureHost();
319 if (bufferTextureHost
) {
320 uint32_t stride
= ImageDataSerializer::ComputeRGBStride(
321 bufferTextureHost
->GetFormat(), aSize
.width
);
322 uint32_t bufferSize
= stride
* aSize
.height
;
323 uint8_t* dst
= aDestShmem
.get
<uint8_t>();
324 uint8_t* src
= bufferTextureHost
->GetBuffer();
326 MOZ_ASSERT(bufferSize
<= aDestShmem
.Size
<uint8_t>());
327 memcpy(dst
, src
, bufferSize
);
331 MonitorAutoLock
lock(mMonitor
);
332 // Release compositable ref in mMonitor lock, but release RefPtr outside the
334 releasingTexture
= textureHostRef
;
335 textureHostRef
= nullptr;
339 void RemoteTextureMap::RegisterTextureOwner(const RemoteTextureOwnerId aOwnerId
,
340 const base::ProcessId aForPid
,
342 MonitorAutoLock
lock(mMonitor
);
344 const auto key
= std::pair(aForPid
, aOwnerId
);
345 auto it
= mTextureOwners
.find(key
);
346 if (it
!= mTextureOwners
.end()) {
347 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
350 auto owner
= MakeUnique
<TextureOwner
>();
351 owner
->mIsSyncMode
= aIsSyncMode
;
353 mTextureOwners
.emplace(key
, std::move(owner
));
356 void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary(
357 const MonitorAutoLock
& aProofOfLock
,
358 std::deque
<UniquePtr
<TextureDataHolder
>>& aHolders
) {
359 for (auto& holder
: aHolders
) {
360 // If remote texture of TextureHost still exist, keep
361 // gl::SharedSurface/TextureData alive while the TextureHost is alive.
362 if (holder
->mTextureHost
&&
363 holder
->mTextureHost
->NumCompositableRefs() >= 0) {
364 RefPtr
<nsISerialEventTarget
> eventTarget
=
365 MessageLoop::current()->SerialEventTarget();
366 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
367 "RemoteTextureMap::UnregisterTextureOwner::Runnable",
368 [data
= std::move(holder
->mTextureData
),
369 surface
= std::move(holder
->mSharedSurface
)]() {});
371 auto destroyedCallback
= [eventTarget
= std::move(eventTarget
),
372 runnable
= std::move(runnable
)]() mutable {
373 eventTarget
->Dispatch(runnable
.forget());
376 holder
->mTextureHost
->SetDestroyedCallback(destroyedCallback
);
381 void RemoteTextureMap::UnregisterTextureOwner(
382 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
) {
383 UniquePtr
<TextureOwner
> releasingOwner
; // Release outside the monitor
384 RefPtr
<TextureHost
> releasingTexture
; // Release outside the monitor
385 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
386 renderingReadyCallbacks
; // Call outside the monitor
388 MonitorAutoLock
lock(mMonitor
);
390 const auto key
= std::pair(aForPid
, aOwnerId
);
391 auto it
= mTextureOwners
.find(key
);
392 if (it
== mTextureOwners
.end()) {
393 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
397 if (it
->second
->mLatestTextureHost
) {
398 // Release CompositableRef in mMonitor
399 releasingTexture
= it
->second
->mLatestTextureHost
;
400 it
->second
->mLatestTextureHost
= nullptr;
403 // mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could
404 // simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts in
405 // mUsingTextureDataHolders alive. They need to be cleared before
406 // KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses
407 // NumCompositableRefs().
408 if (!it
->second
->mReleasingRenderedTextureHosts
.empty()) {
409 it
->second
->mReleasingRenderedTextureHosts
.clear();
411 if (it
->second
->mLatestRenderedTextureHost
) {
412 it
->second
->mLatestRenderedTextureHost
= nullptr;
415 renderingReadyCallbacks
=
416 GetAllRenderingReadyCallbacks(lock
, it
->second
.get());
418 KeepTextureDataAliveForTextureHostIfNecessary(
419 lock
, it
->second
->mWaitingTextureDataHolders
);
421 KeepTextureDataAliveForTextureHostIfNecessary(
422 lock
, it
->second
->mUsingTextureDataHolders
);
424 releasingOwner
= std::move(it
->second
);
425 mTextureOwners
.erase(it
);
431 RemoteTextureInfo(RemoteTextureId
{0}, RemoteTextureOwnerId
{0}, 0);
432 for (auto& callback
: renderingReadyCallbacks
) {
437 void RemoteTextureMap::UnregisterTextureOwners(
438 const std::unordered_set
<RemoteTextureOwnerId
,
439 RemoteTextureOwnerId::HashFn
>& aOwnerIds
,
440 const base::ProcessId aForPid
) {
441 std::vector
<UniquePtr
<TextureOwner
>>
442 releasingOwners
; // Release outside the monitor
443 std::vector
<RefPtr
<TextureHost
>>
444 releasingTextures
; // Release outside the monitor
445 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
446 renderingReadyCallbacks
; // Call outside the monitor
448 MonitorAutoLock
lock(mMonitor
);
450 for (auto id
: aOwnerIds
) {
451 const auto key
= std::pair(aForPid
, id
);
452 auto it
= mTextureOwners
.find(key
);
453 if (it
== mTextureOwners
.end()) {
454 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
458 if (it
->second
->mLatestTextureHost
) {
459 // Release CompositableRef in mMonitor
460 releasingTextures
.emplace_back(it
->second
->mLatestTextureHost
);
461 it
->second
->mLatestTextureHost
= nullptr;
464 // mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could
465 // simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts
466 // in mUsingTextureDataHolders alive. They need to be cleared before
467 // KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses
468 // NumCompositableRefs().
469 if (!it
->second
->mReleasingRenderedTextureHosts
.empty()) {
470 it
->second
->mReleasingRenderedTextureHosts
.clear();
472 if (it
->second
->mLatestRenderedTextureHost
) {
473 it
->second
->mLatestRenderedTextureHost
= nullptr;
476 renderingReadyCallbacks
=
477 GetAllRenderingReadyCallbacks(lock
, it
->second
.get());
479 KeepTextureDataAliveForTextureHostIfNecessary(
480 lock
, it
->second
->mWaitingTextureDataHolders
);
482 KeepTextureDataAliveForTextureHostIfNecessary(
483 lock
, it
->second
->mUsingTextureDataHolders
);
485 releasingOwners
.push_back(std::move(it
->second
));
486 mTextureOwners
.erase(it
);
493 RemoteTextureInfo(RemoteTextureId
{0}, RemoteTextureOwnerId
{0}, 0);
494 for (auto& callback
: renderingReadyCallbacks
) {
499 void RemoteTextureMap::NotifyContextLost(
500 const std::unordered_set
<RemoteTextureOwnerId
,
501 RemoteTextureOwnerId::HashFn
>& aOwnerIds
,
502 const base::ProcessId aForPid
) {
503 MonitorAutoLock
lock(mMonitor
);
505 for (auto id
: aOwnerIds
) {
506 const auto key
= std::pair(aForPid
, id
);
507 auto it
= mTextureOwners
.find(key
);
508 if (it
== mTextureOwners
.end()) {
509 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
512 it
->second
->mIsContextLost
= true;
518 RefPtr
<TextureHost
> RemoteTextureMap::CreateRemoteTexture(
519 TextureData
* aTextureData
, TextureFlags aTextureFlags
) {
520 SurfaceDescriptor desc
;
521 DebugOnly
<bool> ret
= aTextureData
->Serialize(desc
);
523 TextureFlags flags
= aTextureFlags
| TextureFlags::REMOTE_TEXTURE
|
524 TextureFlags::DEALLOCATE_CLIENT
;
526 Maybe
<wr::ExternalImageId
> externalImageId
= Nothing();
527 RefPtr
<TextureHost
> textureHost
=
528 TextureHost::Create(desc
, null_t(), nullptr, LayersBackend::LAYERS_WR
,
529 flags
, externalImageId
);
530 MOZ_ASSERT(textureHost
);
532 gfxCriticalNoteOnce
<< "Failed to create remote texture";
536 textureHost
->EnsureRenderTexture(Nothing());
541 void RemoteTextureMap::UpdateTexture(const MonitorAutoLock
& aProofOfLock
,
542 RemoteTextureMap::TextureOwner
* aOwner
,
543 const RemoteTextureId aTextureId
) {
544 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
546 MOZ_ASSERT(aTextureId
>= aOwner
->mLatestTextureId
);
548 if (aTextureId
== aOwner
->mLatestTextureId
) {
549 // No need to update texture.
553 // Move remote textures to mUsingTextureDataHolders.
554 while (!aOwner
->mWaitingTextureDataHolders
.empty()) {
555 auto& front
= aOwner
->mWaitingTextureDataHolders
.front();
556 if (aTextureId
< front
->mTextureId
) {
559 MOZ_RELEASE_ASSERT(front
->mTextureHost
);
560 aOwner
->mLatestTextureHost
= front
->mTextureHost
;
561 aOwner
->mLatestTextureId
= front
->mTextureId
;
563 UniquePtr
<TextureDataHolder
> holder
= std::move(front
);
564 aOwner
->mWaitingTextureDataHolders
.pop_front();
565 aOwner
->mUsingTextureDataHolders
.push_back(std::move(holder
));
569 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
570 RemoteTextureMap::GetRenderingReadyCallbacks(
571 const MonitorAutoLock
& aProofOfLock
, RemoteTextureMap::TextureOwner
* aOwner
,
572 const RemoteTextureId aTextureId
) {
575 std::vector
<std::function
<void(const RemoteTextureInfo
&)>> functions
;
577 while (!aOwner
->mRenderingReadyCallbackHolders
.empty()) {
578 auto& front
= aOwner
->mRenderingReadyCallbackHolders
.front();
579 if (aTextureId
< front
->mTextureId
) {
582 if (front
->mCallback
) {
583 functions
.push_back(std::move(front
->mCallback
));
585 aOwner
->mRenderingReadyCallbackHolders
.pop_front();
591 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
592 RemoteTextureMap::GetAllRenderingReadyCallbacks(
593 const MonitorAutoLock
& aProofOfLock
,
594 RemoteTextureMap::TextureOwner
* aOwner
) {
596 GetRenderingReadyCallbacks(aProofOfLock
, aOwner
, RemoteTextureId::Max());
597 MOZ_ASSERT(aOwner
->mRenderingReadyCallbackHolders
.empty());
602 bool RemoteTextureMap::GetRemoteTextureForDisplayList(
603 RemoteTextureHostWrapper
* aTextureHostWrapper
,
604 std::function
<void(const RemoteTextureInfo
&)>&& aReadyCallback
) {
605 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
606 MOZ_ASSERT(aTextureHostWrapper
);
608 if (aTextureHostWrapper
->IsReadyForRendering()) {
612 const auto& textureId
= aTextureHostWrapper
->mTextureId
;
613 const auto& ownerId
= aTextureHostWrapper
->mOwnerId
;
614 const auto& forPid
= aTextureHostWrapper
->mForPid
;
615 const auto& size
= aTextureHostWrapper
->mSize
;
617 RefPtr
<TextureHost
> textureHost
;
619 MonitorAutoLock
lock(mMonitor
);
621 auto* owner
= GetTextureOwner(lock
, ownerId
, forPid
);
626 UpdateTexture(lock
, owner
, textureId
);
628 if (owner
->mLatestTextureHost
&&
629 (owner
->mLatestTextureHost
->GetFlags() & TextureFlags::DUMMY_TEXTURE
)) {
630 // Remote texture allocation was failed.
634 bool syncMode
= owner
->mIsSyncMode
|| bool(aReadyCallback
);
637 // remote texture sync ipc
638 if (textureId
== owner
->mLatestTextureId
) {
639 MOZ_ASSERT(owner
->mLatestTextureHost
);
640 MOZ_ASSERT(owner
->mLatestTextureHost
->GetSize() == size
);
641 if (owner
->mLatestTextureHost
->GetSize() != size
) {
642 gfxCriticalNoteOnce
<< "unexpected remote texture size: "
643 << owner
->mLatestTextureHost
->GetSize()
644 << " expected: " << size
;
646 textureHost
= owner
->mLatestTextureHost
;
648 if (aReadyCallback
) {
649 auto callbackHolder
= MakeUnique
<RenderingReadyCallbackHolder
>(
650 textureId
, std::move(aReadyCallback
));
651 owner
->mRenderingReadyCallbackHolders
.push_back(
652 std::move(callbackHolder
));
655 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
659 // remote texture async ipc
660 if (owner
->mLatestTextureHost
) {
661 if (owner
->mLatestTextureHost
->GetSize() == size
) {
662 textureHost
= owner
->mLatestTextureHost
;
664 gfxCriticalNoteOnce
<< "unexpected remote texture size: "
665 << owner
->mLatestTextureHost
->GetSize()
666 << " expected: " << size
;
667 if (!owner
->mIsContextLost
) {
668 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
672 gfxCriticalNoteOnce
<< "remote texture does not exist";
673 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
676 // Update mAsyncRemoteTextureHost for async mode
677 if (textureId
== owner
->mLatestTextureId
) {
678 const auto key
= std::pair(forPid
, textureId
);
679 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
680 if (it
!= mRemoteTextureHostWrapperHolders
.end() &&
681 !it
->second
->mAsyncRemoteTextureHost
) {
682 it
->second
->mAsyncRemoteTextureHost
= owner
->mLatestTextureHost
;
684 MOZ_ASSERT(it
->second
->mAsyncRemoteTextureHost
==
685 owner
->mLatestTextureHost
);
691 aTextureHostWrapper
->SetRemoteTextureHostForDisplayList(lock
, textureHost
,
693 aTextureHostWrapper
->ApplyTextureFlagsToRemoteTexture();
700 wr::MaybeExternalImageId
RemoteTextureMap::GetExternalImageIdOfRemoteTexture(
701 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
702 const base::ProcessId aForPid
) {
703 MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
704 MonitorAutoLock
lock(mMonitor
);
706 const auto key
= std::pair(aForPid
, aTextureId
);
707 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
708 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
709 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
713 TextureHost
* remoteTexture
= it
->second
->mAsyncRemoteTextureHost
;
715 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
717 if (!remoteTexture
) {
718 // This could happen with IPC abnormal shutdown
721 return remoteTexture
->GetMaybeExternalImageId();
725 remoteTexture
->GetFlags() & TextureFlags::DUMMY_TEXTURE
) {
726 // Remote texture allocation was failed.
729 MOZ_ASSERT(!(remoteTexture
&&
730 remoteTexture
->GetFlags() & TextureFlags::DUMMY_TEXTURE
));
734 if (!remoteTexture
) {
735 // Use mLatestRenderedTextureHost for rendering. Remote texture of
736 // aTextureId does not exist.
737 remoteTexture
= owner
->mLatestRenderedTextureHost
;
738 if (!it
->second
->mReadyCheckSuppressed
&& !owner
->mIsContextLost
) {
739 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
740 gfxCriticalNoteOnce
<< "remote texture for rendering does not exist id:"
741 << uint64_t(aTextureId
);
744 // Update mLatestRenderedTextureHost
745 if (owner
->mLatestRenderedTextureHost
) {
746 owner
->mReleasingRenderedTextureHosts
.push_back(
747 owner
->mLatestRenderedTextureHost
);
748 owner
->mLatestRenderedTextureHost
= nullptr;
750 owner
->mLatestRenderedTextureHost
= remoteTexture
;
753 if (!remoteTexture
) {
757 return remoteTexture
->GetMaybeExternalImageId();
760 void RemoteTextureMap::ReleaseRemoteTextureHostForDisplayList(
761 RemoteTextureHostWrapper
* aTextureHostWrapper
) {
762 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
763 MOZ_ASSERT(aTextureHostWrapper
);
765 RefPtr
<TextureHost
> releasingTexture
; // Release outside the mutex
767 MonitorAutoLock
lock(mMonitor
);
769 aTextureHostWrapper
->GetRemoteTextureHostForDisplayList(lock
);
770 aTextureHostWrapper
->ClearRemoteTextureHostForDisplayList(lock
);
774 RefPtr
<TextureHost
> RemoteTextureMap::GetOrCreateRemoteTextureHostWrapper(
775 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
776 const base::ProcessId aForPid
, const gfx::IntSize aSize
,
777 const TextureFlags aFlags
) {
778 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
779 MonitorAutoLock
lock(mMonitor
);
781 const auto key
= std::pair(aForPid
, aTextureId
);
782 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
783 if (it
!= mRemoteTextureHostWrapperHolders
.end()) {
784 return it
->second
->mRemoteTextureHostWrapper
;
787 auto wrapper
= RemoteTextureHostWrapper::Create(aTextureId
, aOwnerId
, aForPid
,
789 auto wrapperHolder
= MakeUnique
<RemoteTextureHostWrapperHolder
>(wrapper
);
791 mRemoteTextureHostWrapperHolders
.emplace(key
, std::move(wrapperHolder
));
796 void RemoteTextureMap::UnregisterRemoteTextureHostWrapper(
797 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
798 const base::ProcessId aForPid
) {
799 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
801 std::vector
<RefPtr
<TextureHost
>>
802 releasingTextures
; // Release outside the monitor
804 MonitorAutoLock
lock(mMonitor
);
806 const auto key
= std::pair(aForPid
, aTextureId
);
807 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
808 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
809 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
812 releasingTextures
.emplace_back(it
->second
->mRemoteTextureHostWrapper
);
813 if (it
->second
->mAsyncRemoteTextureHost
) {
814 releasingTextures
.emplace_back(it
->second
->mAsyncRemoteTextureHost
);
817 mRemoteTextureHostWrapperHolders
.erase(it
);
822 void RemoteTextureMap::RegisterRemoteTexturePushListener(
823 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
,
824 CompositableHost
* aListener
) {
825 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
827 RefPtr
<CompositableHost
>
828 releasingCompositableHost
; // Release outside the monitor
830 MonitorAutoLock
lock(mMonitor
);
832 const auto key
= std::pair(aForPid
, aOwnerId
);
833 auto it
= mRemoteTexturePushListeners
.find(key
);
834 // Remove obsoleted CompositableHost.
835 if (it
!= mRemoteTexturePushListeners
.end()) {
836 releasingCompositableHost
= std::move(it
->second
);
837 mRemoteTexturePushListeners
.erase(it
);
839 mRemoteTexturePushListeners
.emplace(key
, aListener
);
841 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
845 if (owner
->mWaitingTextureDataHolders
.empty() &&
846 !owner
->mLatestTextureHost
) {
850 // Get latest RemoteTextureId.
851 auto textureId
= !owner
->mWaitingTextureDataHolders
.empty()
852 ? owner
->mWaitingTextureDataHolders
.back()->mTextureId
853 : owner
->mLatestTextureId
;
855 // Notify the RemoteTextureId to callback
856 RefPtr
<CompositableHost
> compositableHost
= aListener
;
857 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
858 "RemoteTextureMap::RegisterRemoteTexturePushListener::Runnable",
859 [compositableHost
, textureId
, aOwnerId
, aForPid
]() {
860 compositableHost
->NotifyPushTexture(textureId
, aOwnerId
, aForPid
);
862 CompositorThread()->Dispatch(runnable
.forget());
866 void RemoteTextureMap::UnregisterRemoteTexturePushListener(
867 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
,
868 CompositableHost
* aListener
) {
869 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
871 RefPtr
<CompositableHost
>
872 releasingCompositableHost
; // Release outside the monitor
874 MonitorAutoLock
lock(mMonitor
);
876 const auto key
= std::pair(aForPid
, aOwnerId
);
877 auto it
= mRemoteTexturePushListeners
.find(key
);
878 if (it
== mRemoteTexturePushListeners
.end()) {
881 if (aListener
!= it
->second
) {
882 // aListener was alredy obsoleted.
885 releasingCompositableHost
= std::move(it
->second
);
886 mRemoteTexturePushListeners
.erase(it
);
890 bool RemoteTextureMap::CheckRemoteTextureReady(
891 const RemoteTextureInfo
& aInfo
,
892 std::function
<void(const RemoteTextureInfo
&)>&& aCallback
) {
893 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
895 MonitorAutoLock
lock(mMonitor
);
897 auto* owner
= GetTextureOwner(lock
, aInfo
.mOwnerId
, aInfo
.mForPid
);
898 if (!owner
|| owner
->mIsContextLost
) {
899 // Owner is already removed or context lost.
903 const auto key
= std::pair(aInfo
.mForPid
, aInfo
.mTextureId
);
904 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
905 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
906 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
907 gfxCriticalNoteOnce
<< "Remote texture does not exist id:"
908 << uint64_t(aInfo
.mTextureId
);
912 if (it
->second
->mAsyncRemoteTextureHost
) {
915 MOZ_ASSERT(!it
->second
->mAsyncRemoteTextureHost
);
917 // Check if RemoteTextureId is as expected.
918 if (!owner
->mRenderingReadyCallbackHolders
.empty()) {
919 auto& front
= owner
->mRenderingReadyCallbackHolders
.front();
920 MOZ_RELEASE_ASSERT(aInfo
.mTextureId
>= front
->mTextureId
);
923 auto callbackHolder
= MakeUnique
<RenderingReadyCallbackHolder
>(
924 aInfo
.mTextureId
, std::move(aCallback
));
925 owner
->mRenderingReadyCallbackHolders
.push_back(std::move(callbackHolder
));
930 bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo
& aInfo
) {
931 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
933 MonitorAutoLock
lock(mMonitor
);
935 auto* owner
= GetTextureOwner(lock
, aInfo
.mOwnerId
, aInfo
.mForPid
);
936 if (!owner
|| owner
->mIsContextLost
) {
937 // Owner is already removed or context lost.
941 const auto key
= std::pair(aInfo
.mForPid
, aInfo
.mTextureId
);
942 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
943 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
944 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
945 gfxCriticalNoteOnce
<< "Remote texture does not exist id:"
946 << uint64_t(aInfo
.mTextureId
);
950 const TimeDuration timeout
= TimeDuration::FromMilliseconds(1000);
951 TextureHost
* remoteTexture
= it
->second
->mAsyncRemoteTextureHost
;
953 while (!remoteTexture
) {
954 CVStatus status
= mMonitor
.Wait(timeout
);
955 if (status
== CVStatus::Timeout
) {
956 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
957 gfxCriticalNoteOnce
<< "Remote texture wait time out id:"
958 << uint64_t(aInfo
.mTextureId
);
962 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
963 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
964 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
968 remoteTexture
= it
->second
->mAsyncRemoteTextureHost
;
969 if (!remoteTexture
) {
970 auto* owner
= GetTextureOwner(lock
, aInfo
.mOwnerId
, aInfo
.mForPid
);
971 // When owner is alreay unregistered, remote texture will not be pushed.
972 if (!owner
|| owner
->mIsContextLost
) {
973 // This could happen with IPC abnormal shutdown
982 void RemoteTextureMap::SuppressRemoteTextureReadyCheck(
983 const RemoteTextureId aTextureId
, const base::ProcessId aForPid
) {
984 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
985 MonitorAutoLock
lock(mMonitor
);
987 const auto key
= std::pair(aForPid
, aTextureId
);
988 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
989 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
990 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
993 it
->second
->mReadyCheckSuppressed
= true;
996 UniquePtr
<TextureData
> RemoteTextureMap::GetRecycledBufferTextureData(
997 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
,
998 gfx::IntSize aSize
, gfx::SurfaceFormat aFormat
) {
999 std::stack
<UniquePtr
<TextureData
>>
1000 releasingTextures
; // Release outside the monitor
1001 UniquePtr
<TextureData
> texture
;
1003 MonitorAutoLock
lock(mMonitor
);
1005 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
1010 if (owner
->mRecycledTextures
.empty()) {
1014 if (!owner
->mRecycledTextures
.empty()) {
1015 auto& top
= owner
->mRecycledTextures
.top();
1016 auto* bufferTexture
= top
->AsBufferTextureData();
1018 if (bufferTexture
&& bufferTexture
->GetSize() == aSize
&&
1019 bufferTexture
->GetFormat() == aFormat
) {
1020 texture
= std::move(top
);
1021 owner
->mRecycledTextures
.pop();
1023 // If size or format are different, release all textures.
1024 owner
->mRecycledTextures
.swap(releasingTextures
);
1031 std::shared_ptr
<gl::SharedSurface
> RemoteTextureMap::GetRecycledSharedSurface(
1032 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
) {
1033 std::shared_ptr
<gl::SharedSurface
> sharedSurface
;
1035 MonitorAutoLock
lock(mMonitor
);
1037 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
1042 if (owner
->mRecycledSharedSurfaces
.empty()) {
1046 if (!owner
->mRecycledSharedSurfaces
.empty()) {
1047 sharedSurface
= owner
->mRecycledSharedSurfaces
.front();
1048 owner
->mRecycledSharedSurfaces
.pop();
1051 return sharedSurface
;
1054 RemoteTextureMap::TextureOwner
* RemoteTextureMap::GetTextureOwner(
1055 const MonitorAutoLock
& aProofOfLock
, const RemoteTextureOwnerId aOwnerId
,
1056 const base::ProcessId aForPid
) {
1057 const auto key
= std::pair(aForPid
, aOwnerId
);
1058 auto it
= mTextureOwners
.find(key
);
1059 if (it
== mTextureOwners
.end()) {
1062 return it
->second
.get();
1065 RemoteTextureMap::TextureDataHolder::TextureDataHolder(
1066 const RemoteTextureId aTextureId
, RefPtr
<TextureHost
> aTextureHost
,
1067 UniquePtr
<TextureData
>&& aTextureData
,
1068 const std::shared_ptr
<gl::SharedSurface
>& aSharedSurface
)
1069 : mTextureId(aTextureId
),
1070 mTextureHost(aTextureHost
),
1071 mTextureData(std::move(aTextureData
)),
1072 mSharedSurface(aSharedSurface
) {}
1074 RemoteTextureMap::RenderingReadyCallbackHolder::RenderingReadyCallbackHolder(
1075 const RemoteTextureId aTextureId
,
1076 std::function
<void(const RemoteTextureInfo
&)>&& aCallback
)
1077 : mTextureId(aTextureId
), mCallback(aCallback
) {}
1079 RemoteTextureMap::RemoteTextureHostWrapperHolder::
1080 RemoteTextureHostWrapperHolder(
1081 RefPtr
<TextureHost
> aRemoteTextureHostWrapper
)
1082 : mRemoteTextureHostWrapper(aRemoteTextureHostWrapper
) {}
1084 } // namespace mozilla::layers