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/webgpu/ExternalTexture.h"
21 #include "mozilla/webrender/RenderThread.h"
22 #include "SharedSurface.h"
24 namespace mozilla::layers
{
26 RemoteTextureOwnerClient::RemoteTextureOwnerClient(
27 const base::ProcessId aForPid
)
30 RemoteTextureOwnerClient::~RemoteTextureOwnerClient() = default;
32 bool RemoteTextureOwnerClient::IsRegistered(
33 const RemoteTextureOwnerId aOwnerId
) {
34 auto it
= mOwnerIds
.find(aOwnerId
);
35 if (it
== mOwnerIds
.end()) {
41 void RemoteTextureOwnerClient::RegisterTextureOwner(
42 const RemoteTextureOwnerId aOwnerId
, bool aIsSyncMode
) {
43 MOZ_ASSERT(mOwnerIds
.find(aOwnerId
) == mOwnerIds
.end());
44 mOwnerIds
.emplace(aOwnerId
);
45 RemoteTextureMap::Get()->RegisterTextureOwner(aOwnerId
, mForPid
, aIsSyncMode
);
48 void RemoteTextureOwnerClient::UnregisterTextureOwner(
49 const RemoteTextureOwnerId aOwnerId
) {
50 auto it
= mOwnerIds
.find(aOwnerId
);
51 if (it
== mOwnerIds
.end()) {
55 RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId
, mForPid
);
58 void RemoteTextureOwnerClient::UnregisterAllTextureOwners() {
59 if (mOwnerIds
.empty()) {
62 RemoteTextureMap::Get()->UnregisterTextureOwners(mOwnerIds
, mForPid
);
66 void RemoteTextureOwnerClient::NotifyContextLost() {
67 if (mOwnerIds
.empty()) {
70 RemoteTextureMap::Get()->NotifyContextLost(mOwnerIds
, mForPid
);
73 void RemoteTextureOwnerClient::PushTexture(
74 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
75 UniquePtr
<TextureData
>&& aTextureData
) {
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
,
87 /* aResourceWrapper */ nullptr);
90 void RemoteTextureOwnerClient::PushTexture(
91 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
92 UniquePtr
<TextureData
>&& aTextureData
,
93 const std::shared_ptr
<gl::SharedSurface
>& aSharedSurface
) {
94 MOZ_ASSERT(IsRegistered(aOwnerId
));
96 RefPtr
<TextureHost
> textureHost
= RemoteTextureMap::CreateRemoteTexture(
97 aTextureData
.get(), TextureFlags::DEFAULT
);
99 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
103 RemoteTextureMap::Get()->PushTexture(
104 aTextureId
, aOwnerId
, mForPid
, std::move(aTextureData
), textureHost
,
105 SharedResourceWrapper::SharedSurface(aSharedSurface
));
108 void RemoteTextureOwnerClient::PushTexture(
109 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
110 UniquePtr
<TextureData
>&& aTextureData
,
111 const std::shared_ptr
<webgpu::ExternalTexture
>& aExternalTexture
) {
112 MOZ_ASSERT(IsRegistered(aOwnerId
));
114 RefPtr
<TextureHost
> textureHost
= RemoteTextureMap::CreateRemoteTexture(
115 aTextureData
.get(), TextureFlags::DEFAULT
);
117 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
121 RemoteTextureMap::Get()->PushTexture(
122 aTextureId
, aOwnerId
, mForPid
, std::move(aTextureData
), textureHost
,
123 SharedResourceWrapper::ExternalTexture(aExternalTexture
));
126 void RemoteTextureOwnerClient::PushDummyTexture(
127 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
) {
128 MOZ_ASSERT(IsRegistered(aOwnerId
));
130 auto flags
= TextureFlags::DEALLOCATE_CLIENT
| TextureFlags::REMOTE_TEXTURE
|
131 TextureFlags::DUMMY_TEXTURE
;
132 auto* rawData
= BufferTextureData::Create(
133 gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8
, gfx::BackendType::SKIA
,
134 LayersBackend::LAYERS_WR
, flags
, ALLOC_DEFAULT
, nullptr);
136 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
140 auto textureData
= UniquePtr
<TextureData
>(rawData
);
142 RefPtr
<TextureHost
> textureHost
= RemoteTextureMap::CreateRemoteTexture(
143 textureData
.get(), TextureFlags::DUMMY_TEXTURE
);
145 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
149 RemoteTextureMap::Get()->PushTexture(aTextureId
, aOwnerId
, mForPid
,
150 std::move(textureData
), textureHost
,
151 /* aResourceWrapper */ nullptr);
154 void RemoteTextureOwnerClient::GetLatestBufferSnapshot(
155 const RemoteTextureOwnerId aOwnerId
, const mozilla::ipc::Shmem
& aDestShmem
,
156 const gfx::IntSize
& aSize
) {
157 MOZ_ASSERT(IsRegistered(aOwnerId
));
158 RemoteTextureMap::Get()->GetLatestBufferSnapshot(aOwnerId
, mForPid
,
162 UniquePtr
<TextureData
>
163 RemoteTextureOwnerClient::CreateOrRecycleBufferTextureData(
164 const RemoteTextureOwnerId aOwnerId
, gfx::IntSize aSize
,
165 gfx::SurfaceFormat aFormat
) {
166 auto texture
= RemoteTextureMap::Get()->GetRecycledBufferTextureData(
167 aOwnerId
, mForPid
, aSize
, aFormat
);
172 auto flags
= TextureFlags::DEALLOCATE_CLIENT
| TextureFlags::REMOTE_TEXTURE
;
173 auto* data
= BufferTextureData::Create(aSize
, aFormat
, gfx::BackendType::SKIA
,
174 LayersBackend::LAYERS_WR
, flags
,
175 ALLOC_DEFAULT
, nullptr);
176 return UniquePtr
<TextureData
>(data
);
179 std::shared_ptr
<gl::SharedSurface
>
180 RemoteTextureOwnerClient::GetRecycledSharedSurface(
181 const RemoteTextureOwnerId aOwnerId
) {
182 UniquePtr
<SharedResourceWrapper
> wrapper
=
183 RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedTexture(
188 MOZ_ASSERT(wrapper
->mSharedSurface
);
189 return wrapper
->mSharedSurface
;
192 std::shared_ptr
<webgpu::ExternalTexture
>
193 RemoteTextureOwnerClient::GetRecycledExternalTexture(
194 const RemoteTextureOwnerId aOwnerId
) {
195 UniquePtr
<SharedResourceWrapper
> wrapper
=
196 RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedTexture(
201 MOZ_ASSERT(wrapper
->mExternalTexture
);
202 return wrapper
->mExternalTexture
;
205 StaticAutoPtr
<RemoteTextureMap
> RemoteTextureMap::sInstance
;
208 void RemoteTextureMap::Init() {
209 MOZ_ASSERT(!sInstance
);
210 sInstance
= new RemoteTextureMap();
214 void RemoteTextureMap::Shutdown() {
220 RemoteTextureMap::RemoteTextureMap() : mMonitor("D3D11TextureMap::mMonitor") {}
222 RemoteTextureMap::~RemoteTextureMap() = default;
224 void RemoteTextureMap::PushTexture(
225 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
226 const base::ProcessId aForPid
, UniquePtr
<TextureData
>&& aTextureData
,
227 RefPtr
<TextureHost
>& aTextureHost
,
228 UniquePtr
<SharedResourceWrapper
>&& aResourceWrapper
) {
229 MOZ_RELEASE_ASSERT(aTextureHost
);
231 std::vector
<RefPtr
<TextureHost
>>
232 releasingTextures
; // Release outside the monitor
233 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
234 renderingReadyCallbacks
; // Call outside the monitor
236 MonitorAutoLock
lock(mMonitor
);
238 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
240 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
244 if (owner
->mIsContextLost
&&
245 !(aTextureHost
->GetFlags() & TextureFlags::DUMMY_TEXTURE
)) {
246 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
247 gfxCriticalNoteOnce
<< "Texture pushed during context lost";
250 const auto key
= std::pair(aForPid
, aOwnerId
);
251 auto it
= mRemoteTexturePushListeners
.find(key
);
252 // Notify a new texture if callback is requested
253 if (it
!= mRemoteTexturePushListeners
.end()) {
254 RefPtr
<CompositableHost
> compositableHost
= it
->second
;
255 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
256 "RemoteTextureMap::PushTexture::Runnable",
257 [compositableHost
, aTextureId
, aOwnerId
, aForPid
]() {
258 compositableHost
->NotifyPushTexture(aTextureId
, aOwnerId
, aForPid
);
260 CompositorThread()->Dispatch(runnable
.forget());
263 auto textureData
= MakeUnique
<TextureDataHolder
>(
264 aTextureId
, aTextureHost
, std::move(aTextureData
),
265 std::move(aResourceWrapper
));
267 MOZ_ASSERT(owner
->mLatestTextureId
< aTextureId
);
269 owner
->mWaitingTextureDataHolders
.push_back(std::move(textureData
));
271 if (!owner
->mIsSyncMode
) {
272 renderingReadyCallbacks
=
273 GetRenderingReadyCallbacks(lock
, owner
, aTextureId
);
274 // Update mAsyncRemoteTextureHost for async mode.
275 // This happens when PushTexture() with RemoteTextureId is called after
276 // GetRemoteTextureForDisplayList() with the RemoteTextureId.
277 const auto key
= std::pair(aForPid
, aTextureId
);
278 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
279 if (it
!= mRemoteTextureHostWrapperHolders
.end()) {
280 MOZ_ASSERT(!it
->second
->mAsyncRemoteTextureHost
);
281 it
->second
->mAsyncRemoteTextureHost
= aTextureHost
;
287 // Release owner->mReleasingRenderedTextureHosts before checking
288 // NumCompositableRefs()
289 if (!owner
->mReleasingRenderedTextureHosts
.empty()) {
291 owner
->mReleasingRenderedTextureHosts
.begin(),
292 owner
->mReleasingRenderedTextureHosts
.end(),
293 std::back_inserter(releasingTextures
),
294 [](CompositableTextureHostRef
& aRef
) { return aRef
.get(); });
295 owner
->mReleasingRenderedTextureHosts
.clear();
298 // Drop obsoleted remote textures.
299 while (!owner
->mUsingTextureDataHolders
.empty()) {
300 auto& front
= owner
->mUsingTextureDataHolders
.front();
301 // If mLatestRenderedTextureHost is last compositable ref of remote
302 // texture's TextureHost, its RemoteTextureHostWrapper is already
303 // unregistered. It happens when pushed remote textures that follow are
304 // not rendered since last mLatestRenderedTextureHost update. In this
305 // case, remove the TextureHost from mUsingTextureDataHolders. It is for
306 // unblocking remote texture recyclieng.
307 if (front
->mTextureHost
&&
308 front
->mTextureHost
->NumCompositableRefs() == 1 &&
309 front
->mTextureHost
== owner
->mLatestRenderedTextureHost
) {
310 owner
->mUsingTextureDataHolders
.pop_front();
313 // When compositable ref of TextureHost becomes 0, the TextureHost is not
314 // used by WebRender anymore.
315 if (front
->mTextureHost
&&
316 front
->mTextureHost
->NumCompositableRefs() == 0) {
317 // Recycle SharedTexture
318 if (front
->mResourceWrapper
) {
319 owner
->mRecycledSharedTextures
.push(
320 std::move(front
->mResourceWrapper
));
322 // Recycle BufferTextureData
323 if (!(front
->mTextureHost
->GetFlags() & TextureFlags::DUMMY_TEXTURE
) &&
324 (front
->mTextureData
&&
325 front
->mTextureData
->AsBufferTextureData())) {
326 owner
->mRecycledTextures
.push(std::move(front
->mTextureData
));
328 owner
->mUsingTextureDataHolders
.pop_front();
329 } else if (front
->mTextureHost
&&
330 front
->mTextureHost
->NumCompositableRefs() >= 0) {
331 // Remote texture is still in use by WebRender.
334 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
335 owner
->mUsingTextureDataHolders
.pop_front();
340 const auto info
= RemoteTextureInfo(aTextureId
, aOwnerId
, aForPid
);
341 for (auto& callback
: renderingReadyCallbacks
) {
346 void RemoteTextureMap::GetLatestBufferSnapshot(
347 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
,
348 const mozilla::ipc::Shmem
& aDestShmem
, const gfx::IntSize
& aSize
) {
349 // The compositable ref of remote texture should be updated in mMonitor lock.
350 CompositableTextureHostRef textureHostRef
;
351 RefPtr
<TextureHost
> releasingTexture
; // Release outside the monitor
353 MonitorAutoLock
lock(mMonitor
);
355 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
357 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
361 // Get latest TextureHost of remote Texture.
362 if (owner
->mWaitingTextureDataHolders
.empty() &&
363 !owner
->mLatestTextureHost
) {
366 TextureHost
* textureHost
=
367 !owner
->mWaitingTextureDataHolders
.empty()
368 ? owner
->mWaitingTextureDataHolders
.back()->mTextureHost
369 : owner
->mLatestTextureHost
;
370 if (!textureHost
->AsBufferTextureHost()) {
371 // Only BufferTextureHost is supported for now.
372 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
375 if (textureHost
->GetSize() != aSize
) {
376 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
379 if (textureHost
->GetFormat() != gfx::SurfaceFormat::R8G8B8A8
&&
380 textureHost
->GetFormat() != gfx::SurfaceFormat::B8G8R8A8
) {
381 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
384 // Increment compositable ref to prevent that TextureHost is removed during
386 textureHostRef
= textureHost
;
389 if (!textureHostRef
) {
393 auto* bufferTextureHost
= textureHostRef
->AsBufferTextureHost();
394 if (bufferTextureHost
) {
395 uint32_t stride
= ImageDataSerializer::ComputeRGBStride(
396 bufferTextureHost
->GetFormat(), aSize
.width
);
397 uint32_t bufferSize
= stride
* aSize
.height
;
398 uint8_t* dst
= aDestShmem
.get
<uint8_t>();
399 uint8_t* src
= bufferTextureHost
->GetBuffer();
401 MOZ_ASSERT(bufferSize
<= aDestShmem
.Size
<uint8_t>());
402 memcpy(dst
, src
, bufferSize
);
406 MonitorAutoLock
lock(mMonitor
);
407 // Release compositable ref in mMonitor lock, but release RefPtr outside the
409 releasingTexture
= textureHostRef
;
410 textureHostRef
= nullptr;
414 void RemoteTextureMap::RegisterTextureOwner(const RemoteTextureOwnerId aOwnerId
,
415 const base::ProcessId aForPid
,
417 MonitorAutoLock
lock(mMonitor
);
419 const auto key
= std::pair(aForPid
, aOwnerId
);
420 auto it
= mTextureOwners
.find(key
);
421 if (it
!= mTextureOwners
.end()) {
422 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
425 auto owner
= MakeUnique
<TextureOwner
>();
426 owner
->mIsSyncMode
= aIsSyncMode
;
428 mTextureOwners
.emplace(key
, std::move(owner
));
431 void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary(
432 const MonitorAutoLock
& aProofOfLock
,
433 std::deque
<UniquePtr
<TextureDataHolder
>>& aHolders
) {
434 for (auto& holder
: aHolders
) {
435 // If remote texture of TextureHost still exist, keep
436 // SharedResourceWrapper/TextureData alive while the TextureHost is alive.
437 if (holder
->mTextureHost
&&
438 holder
->mTextureHost
->NumCompositableRefs() >= 0) {
439 RefPtr
<nsISerialEventTarget
> eventTarget
=
440 MessageLoop::current()->SerialEventTarget();
441 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
442 "RemoteTextureMap::UnregisterTextureOwner::Runnable",
443 [data
= std::move(holder
->mTextureData
),
444 wrapper
= std::move(holder
->mResourceWrapper
)]() {});
446 auto destroyedCallback
= [eventTarget
= std::move(eventTarget
),
447 runnable
= std::move(runnable
)]() mutable {
448 eventTarget
->Dispatch(runnable
.forget());
451 holder
->mTextureHost
->SetDestroyedCallback(destroyedCallback
);
456 void RemoteTextureMap::UnregisterTextureOwner(
457 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
) {
458 UniquePtr
<TextureOwner
> releasingOwner
; // Release outside the monitor
459 std::vector
<RefPtr
<TextureHost
>>
460 releasingTextures
; // Release outside the monitor
461 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
462 renderingReadyCallbacks
; // Call outside the monitor
464 MonitorAutoLock
lock(mMonitor
);
466 const auto key
= std::pair(aForPid
, aOwnerId
);
467 auto it
= mTextureOwners
.find(key
);
468 if (it
== mTextureOwners
.end()) {
469 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
473 if (it
->second
->mLatestTextureHost
) {
474 // Release CompositableRef in mMonitor
475 releasingTextures
.emplace_back(it
->second
->mLatestTextureHost
);
476 it
->second
->mLatestTextureHost
= nullptr;
479 // mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could
480 // simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts in
481 // mUsingTextureDataHolders alive. They need to be cleared before
482 // KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses
483 // NumCompositableRefs().
484 if (!it
->second
->mReleasingRenderedTextureHosts
.empty()) {
486 it
->second
->mReleasingRenderedTextureHosts
.begin(),
487 it
->second
->mReleasingRenderedTextureHosts
.end(),
488 std::back_inserter(releasingTextures
),
489 [](CompositableTextureHostRef
& aRef
) { return aRef
.get(); });
490 it
->second
->mReleasingRenderedTextureHosts
.clear();
492 if (it
->second
->mLatestRenderedTextureHost
) {
493 it
->second
->mLatestRenderedTextureHost
= nullptr;
496 renderingReadyCallbacks
=
497 GetAllRenderingReadyCallbacks(lock
, it
->second
.get());
499 KeepTextureDataAliveForTextureHostIfNecessary(
500 lock
, it
->second
->mWaitingTextureDataHolders
);
502 KeepTextureDataAliveForTextureHostIfNecessary(
503 lock
, it
->second
->mUsingTextureDataHolders
);
505 releasingOwner
= std::move(it
->second
);
506 mTextureOwners
.erase(it
);
512 RemoteTextureInfo(RemoteTextureId
{0}, RemoteTextureOwnerId
{0}, 0);
513 for (auto& callback
: renderingReadyCallbacks
) {
518 void RemoteTextureMap::UnregisterTextureOwners(
519 const std::unordered_set
<RemoteTextureOwnerId
,
520 RemoteTextureOwnerId::HashFn
>& aOwnerIds
,
521 const base::ProcessId aForPid
) {
522 std::vector
<UniquePtr
<TextureOwner
>>
523 releasingOwners
; // Release outside the monitor
524 std::vector
<RefPtr
<TextureHost
>>
525 releasingTextures
; // Release outside the monitor
526 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
527 renderingReadyCallbacks
; // Call outside the monitor
529 MonitorAutoLock
lock(mMonitor
);
531 for (auto id
: aOwnerIds
) {
532 const auto key
= std::pair(aForPid
, id
);
533 auto it
= mTextureOwners
.find(key
);
534 if (it
== mTextureOwners
.end()) {
535 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
539 if (it
->second
->mLatestTextureHost
) {
540 // Release CompositableRef in mMonitor
541 releasingTextures
.emplace_back(it
->second
->mLatestTextureHost
);
542 it
->second
->mLatestTextureHost
= nullptr;
545 // mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could
546 // simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts
547 // in mUsingTextureDataHolders alive. They need to be cleared before
548 // KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses
549 // NumCompositableRefs().
550 if (!it
->second
->mReleasingRenderedTextureHosts
.empty()) {
552 it
->second
->mReleasingRenderedTextureHosts
.begin(),
553 it
->second
->mReleasingRenderedTextureHosts
.end(),
554 std::back_inserter(releasingTextures
),
555 [](CompositableTextureHostRef
& aRef
) { return aRef
.get(); });
556 it
->second
->mReleasingRenderedTextureHosts
.clear();
558 if (it
->second
->mLatestRenderedTextureHost
) {
559 it
->second
->mLatestRenderedTextureHost
= nullptr;
562 renderingReadyCallbacks
=
563 GetAllRenderingReadyCallbacks(lock
, it
->second
.get());
565 KeepTextureDataAliveForTextureHostIfNecessary(
566 lock
, it
->second
->mWaitingTextureDataHolders
);
568 KeepTextureDataAliveForTextureHostIfNecessary(
569 lock
, it
->second
->mUsingTextureDataHolders
);
571 releasingOwners
.push_back(std::move(it
->second
));
572 mTextureOwners
.erase(it
);
579 RemoteTextureInfo(RemoteTextureId
{0}, RemoteTextureOwnerId
{0}, 0);
580 for (auto& callback
: renderingReadyCallbacks
) {
585 void RemoteTextureMap::NotifyContextLost(
586 const std::unordered_set
<RemoteTextureOwnerId
,
587 RemoteTextureOwnerId::HashFn
>& aOwnerIds
,
588 const base::ProcessId aForPid
) {
589 MonitorAutoLock
lock(mMonitor
);
591 for (auto id
: aOwnerIds
) {
592 const auto key
= std::pair(aForPid
, id
);
593 auto it
= mTextureOwners
.find(key
);
594 if (it
== mTextureOwners
.end()) {
595 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
598 it
->second
->mIsContextLost
= true;
604 RefPtr
<TextureHost
> RemoteTextureMap::CreateRemoteTexture(
605 TextureData
* aTextureData
, TextureFlags aTextureFlags
) {
606 SurfaceDescriptor desc
;
607 DebugOnly
<bool> ret
= aTextureData
->Serialize(desc
);
609 TextureFlags flags
= aTextureFlags
| TextureFlags::REMOTE_TEXTURE
|
610 TextureFlags::DEALLOCATE_CLIENT
;
612 Maybe
<wr::ExternalImageId
> externalImageId
= Nothing();
613 RefPtr
<TextureHost
> textureHost
=
614 TextureHost::Create(desc
, null_t(), nullptr, LayersBackend::LAYERS_WR
,
615 flags
, externalImageId
);
616 MOZ_ASSERT(textureHost
);
618 gfxCriticalNoteOnce
<< "Failed to create remote texture";
622 textureHost
->EnsureRenderTexture(Nothing());
627 void RemoteTextureMap::UpdateTexture(const MonitorAutoLock
& aProofOfLock
,
628 RemoteTextureMap::TextureOwner
* aOwner
,
629 const RemoteTextureId aTextureId
) {
630 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
632 MOZ_ASSERT(aTextureId
>= aOwner
->mLatestTextureId
);
634 if (aTextureId
== aOwner
->mLatestTextureId
) {
635 // No need to update texture.
639 // Move remote textures to mUsingTextureDataHolders.
640 while (!aOwner
->mWaitingTextureDataHolders
.empty()) {
641 auto& front
= aOwner
->mWaitingTextureDataHolders
.front();
642 if (aTextureId
< front
->mTextureId
) {
645 MOZ_RELEASE_ASSERT(front
->mTextureHost
);
646 aOwner
->mLatestTextureHost
= front
->mTextureHost
;
647 aOwner
->mLatestTextureId
= front
->mTextureId
;
649 UniquePtr
<TextureDataHolder
> holder
= std::move(front
);
650 aOwner
->mWaitingTextureDataHolders
.pop_front();
651 aOwner
->mUsingTextureDataHolders
.push_back(std::move(holder
));
655 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
656 RemoteTextureMap::GetRenderingReadyCallbacks(
657 const MonitorAutoLock
& aProofOfLock
, RemoteTextureMap::TextureOwner
* aOwner
,
658 const RemoteTextureId aTextureId
) {
661 std::vector
<std::function
<void(const RemoteTextureInfo
&)>> functions
;
663 while (!aOwner
->mRenderingReadyCallbackHolders
.empty()) {
664 auto& front
= aOwner
->mRenderingReadyCallbackHolders
.front();
665 if (aTextureId
< front
->mTextureId
) {
668 if (front
->mCallback
) {
669 functions
.push_back(std::move(front
->mCallback
));
671 aOwner
->mRenderingReadyCallbackHolders
.pop_front();
677 std::vector
<std::function
<void(const RemoteTextureInfo
&)>>
678 RemoteTextureMap::GetAllRenderingReadyCallbacks(
679 const MonitorAutoLock
& aProofOfLock
,
680 RemoteTextureMap::TextureOwner
* aOwner
) {
682 GetRenderingReadyCallbacks(aProofOfLock
, aOwner
, RemoteTextureId::Max());
683 MOZ_ASSERT(aOwner
->mRenderingReadyCallbackHolders
.empty());
688 bool RemoteTextureMap::GetRemoteTextureForDisplayList(
689 RemoteTextureHostWrapper
* aTextureHostWrapper
,
690 std::function
<void(const RemoteTextureInfo
&)>&& aReadyCallback
) {
691 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
692 MOZ_ASSERT(aTextureHostWrapper
);
694 if (aTextureHostWrapper
->IsReadyForRendering()) {
698 const auto& textureId
= aTextureHostWrapper
->mTextureId
;
699 const auto& ownerId
= aTextureHostWrapper
->mOwnerId
;
700 const auto& forPid
= aTextureHostWrapper
->mForPid
;
701 const auto& size
= aTextureHostWrapper
->mSize
;
703 RefPtr
<TextureHost
> textureHost
;
705 MonitorAutoLock
lock(mMonitor
);
707 auto* owner
= GetTextureOwner(lock
, ownerId
, forPid
);
712 UpdateTexture(lock
, owner
, textureId
);
714 if (owner
->mLatestTextureHost
&&
715 (owner
->mLatestTextureHost
->GetFlags() & TextureFlags::DUMMY_TEXTURE
)) {
716 // Remote texture allocation was failed.
720 bool syncMode
= owner
->mIsSyncMode
|| bool(aReadyCallback
);
723 // remote texture sync ipc
724 if (textureId
== owner
->mLatestTextureId
) {
725 MOZ_ASSERT(owner
->mLatestTextureHost
);
726 MOZ_ASSERT(owner
->mLatestTextureHost
->GetSize() == size
);
727 if (owner
->mLatestTextureHost
->GetSize() != size
) {
728 gfxCriticalNoteOnce
<< "unexpected remote texture size: "
729 << owner
->mLatestTextureHost
->GetSize()
730 << " expected: " << size
;
732 textureHost
= owner
->mLatestTextureHost
;
734 if (aReadyCallback
) {
735 auto callbackHolder
= MakeUnique
<RenderingReadyCallbackHolder
>(
736 textureId
, std::move(aReadyCallback
));
737 owner
->mRenderingReadyCallbackHolders
.push_back(
738 std::move(callbackHolder
));
741 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
745 // remote texture async ipc
746 if (owner
->mLatestTextureHost
) {
747 if (owner
->mLatestTextureHost
->GetSize() == size
) {
748 textureHost
= owner
->mLatestTextureHost
;
750 gfxCriticalNoteOnce
<< "unexpected remote texture size: "
751 << owner
->mLatestTextureHost
->GetSize()
752 << " expected: " << size
;
753 if (!owner
->mIsContextLost
) {
754 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
758 gfxCriticalNoteOnce
<< "remote texture does not exist";
759 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
762 // Update mAsyncRemoteTextureHost for async mode
763 if (textureId
== owner
->mLatestTextureId
) {
764 const auto key
= std::pair(forPid
, textureId
);
765 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
766 if (it
!= mRemoteTextureHostWrapperHolders
.end() &&
767 !it
->second
->mAsyncRemoteTextureHost
) {
768 it
->second
->mAsyncRemoteTextureHost
= owner
->mLatestTextureHost
;
770 MOZ_ASSERT(it
->second
->mAsyncRemoteTextureHost
==
771 owner
->mLatestTextureHost
);
777 aTextureHostWrapper
->SetRemoteTextureHostForDisplayList(lock
, textureHost
,
779 aTextureHostWrapper
->ApplyTextureFlagsToRemoteTexture();
786 wr::MaybeExternalImageId
RemoteTextureMap::GetExternalImageIdOfRemoteTexture(
787 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
788 const base::ProcessId aForPid
) {
789 MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
790 MonitorAutoLock
lock(mMonitor
);
792 const auto key
= std::pair(aForPid
, aTextureId
);
793 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
794 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
795 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
799 TextureHost
* remoteTexture
= it
->second
->mAsyncRemoteTextureHost
;
801 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
803 if (!remoteTexture
) {
804 // This could happen with IPC abnormal shutdown
807 return remoteTexture
->GetMaybeExternalImageId();
811 remoteTexture
->GetFlags() & TextureFlags::DUMMY_TEXTURE
) {
812 // Remote texture allocation was failed.
815 MOZ_ASSERT(!(remoteTexture
&&
816 remoteTexture
->GetFlags() & TextureFlags::DUMMY_TEXTURE
));
820 if (!remoteTexture
) {
821 // Use mLatestRenderedTextureHost for rendering. Remote texture of
822 // aTextureId does not exist.
823 remoteTexture
= owner
->mLatestRenderedTextureHost
;
824 if (!it
->second
->mReadyCheckSuppressed
&& !owner
->mIsContextLost
) {
825 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
826 gfxCriticalNoteOnce
<< "remote texture for rendering does not exist id:"
827 << uint64_t(aTextureId
);
830 // Update mLatestRenderedTextureHost
831 if (owner
->mLatestRenderedTextureHost
) {
832 owner
->mReleasingRenderedTextureHosts
.push_back(
833 owner
->mLatestRenderedTextureHost
);
834 owner
->mLatestRenderedTextureHost
= nullptr;
836 owner
->mLatestRenderedTextureHost
= remoteTexture
;
839 if (!remoteTexture
) {
843 return remoteTexture
->GetMaybeExternalImageId();
846 void RemoteTextureMap::ReleaseRemoteTextureHostForDisplayList(
847 RemoteTextureHostWrapper
* aTextureHostWrapper
) {
848 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
849 MOZ_ASSERT(aTextureHostWrapper
);
851 RefPtr
<TextureHost
> releasingTexture
; // Release outside the mutex
853 MonitorAutoLock
lock(mMonitor
);
855 aTextureHostWrapper
->GetRemoteTextureHostForDisplayList(lock
);
856 aTextureHostWrapper
->ClearRemoteTextureHostForDisplayList(lock
);
860 RefPtr
<TextureHost
> RemoteTextureMap::GetOrCreateRemoteTextureHostWrapper(
861 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
862 const base::ProcessId aForPid
, const gfx::IntSize aSize
,
863 const TextureFlags aFlags
) {
864 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
865 MonitorAutoLock
lock(mMonitor
);
867 const auto key
= std::pair(aForPid
, aTextureId
);
868 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
869 if (it
!= mRemoteTextureHostWrapperHolders
.end()) {
870 return it
->second
->mRemoteTextureHostWrapper
;
873 auto wrapper
= RemoteTextureHostWrapper::Create(aTextureId
, aOwnerId
, aForPid
,
875 auto wrapperHolder
= MakeUnique
<RemoteTextureHostWrapperHolder
>(wrapper
);
877 mRemoteTextureHostWrapperHolders
.emplace(key
, std::move(wrapperHolder
));
882 void RemoteTextureMap::UnregisterRemoteTextureHostWrapper(
883 const RemoteTextureId aTextureId
, const RemoteTextureOwnerId aOwnerId
,
884 const base::ProcessId aForPid
) {
885 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
887 std::vector
<RefPtr
<TextureHost
>>
888 releasingTextures
; // Release outside the monitor
890 MonitorAutoLock
lock(mMonitor
);
892 const auto key
= std::pair(aForPid
, aTextureId
);
893 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
894 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
895 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
898 releasingTextures
.emplace_back(it
->second
->mRemoteTextureHostWrapper
);
899 if (it
->second
->mAsyncRemoteTextureHost
) {
900 releasingTextures
.emplace_back(it
->second
->mAsyncRemoteTextureHost
);
903 mRemoteTextureHostWrapperHolders
.erase(it
);
908 void RemoteTextureMap::RegisterRemoteTexturePushListener(
909 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
,
910 CompositableHost
* aListener
) {
911 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
913 RefPtr
<CompositableHost
>
914 releasingCompositableHost
; // Release outside the monitor
916 MonitorAutoLock
lock(mMonitor
);
918 const auto key
= std::pair(aForPid
, aOwnerId
);
919 auto it
= mRemoteTexturePushListeners
.find(key
);
920 // Remove obsoleted CompositableHost.
921 if (it
!= mRemoteTexturePushListeners
.end()) {
922 releasingCompositableHost
= std::move(it
->second
);
923 mRemoteTexturePushListeners
.erase(it
);
925 mRemoteTexturePushListeners
.emplace(key
, aListener
);
927 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
931 if (owner
->mWaitingTextureDataHolders
.empty() &&
932 !owner
->mLatestTextureHost
) {
936 // Get latest RemoteTextureId.
937 auto textureId
= !owner
->mWaitingTextureDataHolders
.empty()
938 ? owner
->mWaitingTextureDataHolders
.back()->mTextureId
939 : owner
->mLatestTextureId
;
941 // Notify the RemoteTextureId to callback
942 RefPtr
<CompositableHost
> compositableHost
= aListener
;
943 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
944 "RemoteTextureMap::RegisterRemoteTexturePushListener::Runnable",
945 [compositableHost
, textureId
, aOwnerId
, aForPid
]() {
946 compositableHost
->NotifyPushTexture(textureId
, aOwnerId
, aForPid
);
948 CompositorThread()->Dispatch(runnable
.forget());
952 void RemoteTextureMap::UnregisterRemoteTexturePushListener(
953 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
,
954 CompositableHost
* aListener
) {
955 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
957 RefPtr
<CompositableHost
>
958 releasingCompositableHost
; // Release outside the monitor
960 MonitorAutoLock
lock(mMonitor
);
962 const auto key
= std::pair(aForPid
, aOwnerId
);
963 auto it
= mRemoteTexturePushListeners
.find(key
);
964 if (it
== mRemoteTexturePushListeners
.end()) {
967 if (aListener
!= it
->second
) {
968 // aListener was alredy obsoleted.
971 releasingCompositableHost
= std::move(it
->second
);
972 mRemoteTexturePushListeners
.erase(it
);
976 bool RemoteTextureMap::CheckRemoteTextureReady(
977 const RemoteTextureInfo
& aInfo
,
978 std::function
<void(const RemoteTextureInfo
&)>&& aCallback
) {
979 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
981 MonitorAutoLock
lock(mMonitor
);
983 auto* owner
= GetTextureOwner(lock
, aInfo
.mOwnerId
, aInfo
.mForPid
);
984 if (!owner
|| owner
->mIsContextLost
) {
985 // Owner is already removed or context lost.
989 const auto key
= std::pair(aInfo
.mForPid
, aInfo
.mTextureId
);
990 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
991 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
992 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
993 gfxCriticalNoteOnce
<< "Remote texture does not exist id:"
994 << uint64_t(aInfo
.mTextureId
);
998 if (it
->second
->mAsyncRemoteTextureHost
) {
1001 MOZ_ASSERT(!it
->second
->mAsyncRemoteTextureHost
);
1003 // Check if RemoteTextureId is as expected.
1004 if (!owner
->mRenderingReadyCallbackHolders
.empty()) {
1005 auto& front
= owner
->mRenderingReadyCallbackHolders
.front();
1006 MOZ_RELEASE_ASSERT(aInfo
.mTextureId
>= front
->mTextureId
);
1009 auto callbackHolder
= MakeUnique
<RenderingReadyCallbackHolder
>(
1010 aInfo
.mTextureId
, std::move(aCallback
));
1011 owner
->mRenderingReadyCallbackHolders
.push_back(std::move(callbackHolder
));
1016 bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo
& aInfo
) {
1017 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1019 MonitorAutoLock
lock(mMonitor
);
1021 auto* owner
= GetTextureOwner(lock
, aInfo
.mOwnerId
, aInfo
.mForPid
);
1022 if (!owner
|| owner
->mIsContextLost
) {
1023 // Owner is already removed or context lost.
1027 const auto key
= std::pair(aInfo
.mForPid
, aInfo
.mTextureId
);
1028 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
1029 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
1030 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1031 gfxCriticalNoteOnce
<< "Remote texture does not exist id:"
1032 << uint64_t(aInfo
.mTextureId
);
1036 const TimeDuration timeout
= TimeDuration::FromMilliseconds(1000);
1037 TextureHost
* remoteTexture
= it
->second
->mAsyncRemoteTextureHost
;
1039 while (!remoteTexture
) {
1040 CVStatus status
= mMonitor
.Wait(timeout
);
1041 if (status
== CVStatus::Timeout
) {
1042 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1043 gfxCriticalNoteOnce
<< "Remote texture wait time out id:"
1044 << uint64_t(aInfo
.mTextureId
);
1048 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
1049 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
1050 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1054 remoteTexture
= it
->second
->mAsyncRemoteTextureHost
;
1055 if (!remoteTexture
) {
1056 auto* owner
= GetTextureOwner(lock
, aInfo
.mOwnerId
, aInfo
.mForPid
);
1057 // When owner is alreay unregistered, remote texture will not be pushed.
1058 if (!owner
|| owner
->mIsContextLost
) {
1059 // This could happen with IPC abnormal shutdown
1068 void RemoteTextureMap::SuppressRemoteTextureReadyCheck(
1069 const RemoteTextureId aTextureId
, const base::ProcessId aForPid
) {
1070 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1071 MonitorAutoLock
lock(mMonitor
);
1073 const auto key
= std::pair(aForPid
, aTextureId
);
1074 auto it
= mRemoteTextureHostWrapperHolders
.find(key
);
1075 if (it
== mRemoteTextureHostWrapperHolders
.end()) {
1076 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1079 it
->second
->mReadyCheckSuppressed
= true;
1082 UniquePtr
<TextureData
> RemoteTextureMap::GetRecycledBufferTextureData(
1083 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
,
1084 gfx::IntSize aSize
, gfx::SurfaceFormat aFormat
) {
1085 std::stack
<UniquePtr
<TextureData
>>
1086 releasingTextures
; // Release outside the monitor
1087 UniquePtr
<TextureData
> texture
;
1089 MonitorAutoLock
lock(mMonitor
);
1091 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
1096 if (owner
->mRecycledTextures
.empty()) {
1100 if (!owner
->mRecycledTextures
.empty()) {
1101 auto& top
= owner
->mRecycledTextures
.top();
1102 auto* bufferTexture
= top
->AsBufferTextureData();
1104 if (bufferTexture
&& bufferTexture
->GetSize() == aSize
&&
1105 bufferTexture
->GetFormat() == aFormat
) {
1106 texture
= std::move(top
);
1107 owner
->mRecycledTextures
.pop();
1109 // If size or format are different, release all textures.
1110 owner
->mRecycledTextures
.swap(releasingTextures
);
1117 UniquePtr
<SharedResourceWrapper
> RemoteTextureMap::GetRecycledSharedTexture(
1118 const RemoteTextureOwnerId aOwnerId
, const base::ProcessId aForPid
) {
1119 UniquePtr
<SharedResourceWrapper
> wrapper
;
1121 MonitorAutoLock
lock(mMonitor
);
1123 auto* owner
= GetTextureOwner(lock
, aOwnerId
, aForPid
);
1128 if (owner
->mRecycledSharedTextures
.empty()) {
1132 auto& front
= owner
->mRecycledSharedTextures
.front();
1133 wrapper
= std::move(front
);
1134 owner
->mRecycledSharedTextures
.pop();
1139 RemoteTextureMap::TextureOwner
* RemoteTextureMap::GetTextureOwner(
1140 const MonitorAutoLock
& aProofOfLock
, const RemoteTextureOwnerId aOwnerId
,
1141 const base::ProcessId aForPid
) {
1142 const auto key
= std::pair(aForPid
, aOwnerId
);
1143 auto it
= mTextureOwners
.find(key
);
1144 if (it
== mTextureOwners
.end()) {
1147 return it
->second
.get();
1150 RemoteTextureMap::TextureDataHolder::TextureDataHolder(
1151 const RemoteTextureId aTextureId
, RefPtr
<TextureHost
> aTextureHost
,
1152 UniquePtr
<TextureData
>&& aTextureData
,
1153 UniquePtr
<SharedResourceWrapper
>&& aResourceWrapper
)
1154 : mTextureId(aTextureId
),
1155 mTextureHost(aTextureHost
),
1156 mTextureData(std::move(aTextureData
)),
1157 mResourceWrapper(std::move(aResourceWrapper
)) {}
1159 RemoteTextureMap::RenderingReadyCallbackHolder::RenderingReadyCallbackHolder(
1160 const RemoteTextureId aTextureId
,
1161 std::function
<void(const RemoteTextureInfo
&)>&& aCallback
)
1162 : mTextureId(aTextureId
), mCallback(aCallback
) {}
1164 RemoteTextureMap::RemoteTextureHostWrapperHolder::
1165 RemoteTextureHostWrapperHolder(
1166 RefPtr
<TextureHost
> aRemoteTextureHostWrapper
)
1167 : mRemoteTextureHostWrapper(aRemoteTextureHostWrapper
) {}
1169 } // namespace mozilla::layers