Bug 1927094 - optimize lineScrollAmount so it doesn't iterate over all tabs, r=mconley
[gecko.git] / gfx / layers / RemoteTextureMap.cpp
blobab242ba0e94bf0fef0e2647454a5e04d551ef724
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"
9 #include <algorithm>
10 #include <vector>
12 #include "CompositableHost.h"
13 #include "mozilla/ipc/ProtocolUtils.h"
14 #include "mozilla/gfx/gfxVars.h"
15 #include "mozilla/layers/AsyncImagePipelineManager.h"
16 #include "mozilla/layers/BufferTexture.h"
17 #include "mozilla/layers/CompositorThread.h"
18 #include "mozilla/layers/ImageDataSerializer.h"
19 #include "mozilla/layers/RemoteTextureHostWrapper.h"
20 #include "mozilla/layers/TextureClientSharedSurface.h"
21 #include "mozilla/layers/WebRenderTextureHost.h"
22 #include "mozilla/StaticPrefs_gfx.h"
23 #include "mozilla/StaticPrefs_webgl.h"
24 #include "mozilla/webgpu/ExternalTexture.h"
25 #include "mozilla/webrender/RenderThread.h"
26 #include "SharedSurface.h"
28 namespace mozilla::layers {
30 RemoteTextureRecycleBin::RemoteTextureRecycleBin(bool aIsShared)
31 : mIsShared(aIsShared) {}
33 RemoteTextureRecycleBin::~RemoteTextureRecycleBin() = default;
35 RemoteTextureOwnerClient::RemoteTextureOwnerClient(
36 const base::ProcessId aForPid)
37 : mForPid(aForPid) {}
39 RemoteTextureOwnerClient::~RemoteTextureOwnerClient() = default;
41 bool RemoteTextureOwnerClient::IsRegistered(
42 const RemoteTextureOwnerId aOwnerId) {
43 auto it = mOwnerIds.find(aOwnerId);
44 if (it == mOwnerIds.end()) {
45 return false;
47 return true;
50 void RemoteTextureOwnerClient::RegisterTextureOwner(
51 const RemoteTextureOwnerId aOwnerId, bool aSharedRecycling) {
52 MOZ_ASSERT(mOwnerIds.find(aOwnerId) == mOwnerIds.end());
53 mOwnerIds.emplace(aOwnerId);
54 RefPtr<RemoteTextureRecycleBin> recycleBin;
55 if (aSharedRecycling) {
56 if (!mSharedRecycleBin) {
57 mSharedRecycleBin = new RemoteTextureRecycleBin(true);
59 recycleBin = mSharedRecycleBin;
61 RemoteTextureMap::Get()->RegisterTextureOwner(aOwnerId, mForPid, recycleBin);
64 void RemoteTextureOwnerClient::UnregisterTextureOwner(
65 const RemoteTextureOwnerId aOwnerId) {
66 auto it = mOwnerIds.find(aOwnerId);
67 if (it == mOwnerIds.end()) {
68 return;
70 mOwnerIds.erase(it);
71 RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId, mForPid);
74 void RemoteTextureOwnerClient::UnregisterAllTextureOwners() {
75 if (mOwnerIds.empty()) {
76 return;
78 RemoteTextureMap::Get()->UnregisterTextureOwners(mOwnerIds, mForPid);
79 mOwnerIds.clear();
80 mSharedRecycleBin = nullptr;
83 bool RemoteTextureOwnerClient::WaitForTxn(const RemoteTextureOwnerId aOwnerId,
84 RemoteTextureTxnType aTxnType,
85 RemoteTextureTxnId aTxnId) {
86 auto it = mOwnerIds.find(aOwnerId);
87 if (it == mOwnerIds.end() || !aTxnType || !aTxnId) {
88 return false;
90 return RemoteTextureMap::Get()->WaitForTxn(aOwnerId, mForPid, aTxnType,
91 aTxnId);
94 void RemoteTextureOwnerClient::ClearRecycledTextures() {
95 RemoteTextureMap::Get()->ClearRecycledTextures(mOwnerIds, mForPid,
96 mSharedRecycleBin);
99 void RemoteTextureOwnerClient::NotifyContextLost(
100 const RemoteTextureOwnerIdSet* aOwnerIds) {
101 if (aOwnerIds) {
102 for (const auto& id : *aOwnerIds) {
103 if (mOwnerIds.find(id) == mOwnerIds.end()) {
104 MOZ_ASSERT_UNREACHABLE("owner id not registered by client");
105 return;
108 } else {
109 aOwnerIds = &mOwnerIds;
111 if (aOwnerIds->empty()) {
112 return;
114 RemoteTextureMap::Get()->NotifyContextLost(*aOwnerIds, mForPid);
117 void RemoteTextureOwnerClient::NotifyContextRestored(
118 const RemoteTextureOwnerIdSet* aOwnerIds) {
119 if (aOwnerIds) {
120 for (const auto& id : *aOwnerIds) {
121 if (mOwnerIds.find(id) == mOwnerIds.end()) {
122 MOZ_ASSERT_UNREACHABLE("owner id not registered by client");
123 return;
126 } else {
127 aOwnerIds = &mOwnerIds;
129 if (aOwnerIds->empty()) {
130 return;
132 RemoteTextureMap::Get()->NotifyContextRestored(*aOwnerIds, mForPid);
135 void RemoteTextureOwnerClient::PushTexture(
136 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
137 UniquePtr<TextureData>&& aTextureData) {
138 MOZ_ASSERT(IsRegistered(aOwnerId));
140 RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture(
141 aTextureData.get(), TextureFlags::DEFAULT);
142 if (!textureHost) {
143 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
144 return;
147 RemoteTextureMap::Get()->PushTexture(aTextureId, aOwnerId, mForPid,
148 std::move(aTextureData), textureHost,
149 /* aResourceWrapper */ nullptr);
152 void RemoteTextureOwnerClient::PushTexture(
153 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
154 const std::shared_ptr<gl::SharedSurface>& aSharedSurface,
155 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
156 const SurfaceDescriptor& aDesc) {
157 MOZ_ASSERT(IsRegistered(aOwnerId));
159 UniquePtr<TextureData> textureData =
160 MakeUnique<SharedSurfaceTextureData>(aDesc, aFormat, aSize);
161 RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture(
162 textureData.get(), TextureFlags::DEFAULT);
163 if (!textureHost) {
164 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
165 return;
168 RemoteTextureMap::Get()->PushTexture(
169 aTextureId, aOwnerId, mForPid, std::move(textureData), textureHost,
170 SharedResourceWrapper::SharedSurface(aSharedSurface));
173 void RemoteTextureOwnerClient::PushTexture(
174 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
175 const std::shared_ptr<webgpu::ExternalTexture>& aExternalTexture,
176 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
177 const SurfaceDescriptor& aDesc) {
178 MOZ_ASSERT(IsRegistered(aOwnerId));
180 UniquePtr<TextureData> textureData =
181 MakeUnique<SharedSurfaceTextureData>(aDesc, aFormat, aSize);
182 RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture(
183 textureData.get(), TextureFlags::DEFAULT);
184 if (!textureHost) {
185 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
186 return;
189 RemoteTextureMap::Get()->PushTexture(
190 aTextureId, aOwnerId, mForPid, std::move(textureData), textureHost,
191 SharedResourceWrapper::ExternalTexture(aExternalTexture));
194 void RemoteTextureOwnerClient::PushDummyTexture(
195 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId) {
196 MOZ_ASSERT(IsRegistered(aOwnerId));
198 auto flags = TextureFlags::DEALLOCATE_CLIENT | TextureFlags::REMOTE_TEXTURE |
199 TextureFlags::DUMMY_TEXTURE;
200 auto* rawData = BufferTextureData::Create(
201 gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8, gfx::BackendType::SKIA,
202 LayersBackend::LAYERS_WR, flags, ALLOC_DEFAULT, nullptr);
203 if (!rawData) {
204 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
205 return;
208 auto textureData = UniquePtr<TextureData>(rawData);
210 RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture(
211 textureData.get(), TextureFlags::DUMMY_TEXTURE);
212 if (!textureHost) {
213 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
214 return;
217 RemoteTextureMap::Get()->PushTexture(aTextureId, aOwnerId, mForPid,
218 std::move(textureData), textureHost,
219 /* aResourceWrapper */ nullptr);
222 void RemoteTextureOwnerClient::GetLatestBufferSnapshot(
223 const RemoteTextureOwnerId aOwnerId, const mozilla::ipc::Shmem& aDestShmem,
224 const gfx::IntSize& aSize) {
225 MOZ_ASSERT(IsRegistered(aOwnerId));
226 RemoteTextureMap::Get()->GetLatestBufferSnapshot(aOwnerId, mForPid,
227 aDestShmem, aSize);
230 UniquePtr<TextureData> RemoteTextureOwnerClient::GetRecycledTextureData(
231 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
232 TextureType aTextureType, RemoteTextureOwnerId aOwnerId) {
233 return RemoteTextureMap::Get()->GetRecycledTextureData(
234 aOwnerId, mForPid, mSharedRecycleBin, aSize, aFormat, aTextureType);
237 UniquePtr<TextureData>
238 RemoteTextureOwnerClient::CreateOrRecycleBufferTextureData(
239 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
240 RemoteTextureOwnerId aOwnerId) {
241 auto texture =
242 GetRecycledTextureData(aSize, aFormat, TextureType::Unknown, aOwnerId);
243 if (texture) {
244 return texture;
247 auto flags = TextureFlags::DEALLOCATE_CLIENT | TextureFlags::REMOTE_TEXTURE;
248 auto* data = BufferTextureData::Create(aSize, aFormat, gfx::BackendType::SKIA,
249 LayersBackend::LAYERS_WR, flags,
250 ALLOC_DEFAULT, nullptr);
251 return UniquePtr<TextureData>(data);
254 std::shared_ptr<gl::SharedSurface>
255 RemoteTextureOwnerClient::GetRecycledSharedSurface(
256 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
257 SurfaceDescriptor::Type aType, RemoteTextureOwnerId aOwnerId) {
258 UniquePtr<SharedResourceWrapper> wrapper =
259 RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedTexture(
260 aOwnerId, mForPid, mSharedRecycleBin, aSize, aFormat, aType);
261 if (!wrapper) {
262 return nullptr;
264 MOZ_ASSERT(wrapper->mSharedSurface);
265 return wrapper->mSharedSurface;
268 std::shared_ptr<webgpu::ExternalTexture>
269 RemoteTextureOwnerClient::GetRecycledExternalTexture(
270 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
271 SurfaceDescriptor::Type aType, RemoteTextureOwnerId aOwnerId) {
272 UniquePtr<SharedResourceWrapper> wrapper =
273 RemoteTextureMap::Get()->RemoteTextureMap::GetRecycledSharedTexture(
274 aOwnerId, mForPid, mSharedRecycleBin, aSize, aFormat, aType);
275 if (!wrapper) {
276 return nullptr;
278 MOZ_ASSERT(wrapper->mExternalTexture);
279 return wrapper->mExternalTexture;
282 StaticAutoPtr<RemoteTextureMap> RemoteTextureMap::sInstance;
284 /* static */
285 void RemoteTextureMap::Init() {
286 MOZ_ASSERT(!sInstance);
287 sInstance = new RemoteTextureMap();
290 /* static */
291 void RemoteTextureMap::Shutdown() {
292 if (sInstance) {
293 sInstance = nullptr;
297 RemoteTextureMap::RemoteTextureMap() : mMonitor("RemoteTextureMap::mMonitor") {}
299 RemoteTextureMap::~RemoteTextureMap() = default;
301 bool RemoteTextureMap::RecycleTexture(
302 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin,
303 TextureDataHolder& aHolder, bool aExpireOldTextures) {
304 if (!aHolder.mTextureData ||
305 (aHolder.mTextureHost &&
306 aHolder.mTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) {
307 return false;
310 // Expire old textures so they don't sit in the list forever if unused.
311 constexpr size_t kSharedTextureLimit = 21;
312 constexpr size_t kTextureLimit = 7;
313 while (aRecycleBin->mRecycledTextures.size() >=
314 (aRecycleBin->mIsShared ? kSharedTextureLimit : kTextureLimit)) {
315 if (!aExpireOldTextures) {
316 // There are too many textures, and we can't expire any to make room.
317 return false;
319 aRecycleBin->mRecycledTextures.pop_front();
322 TextureData::Info info;
323 aHolder.mTextureData->FillInfo(info);
324 RemoteTextureRecycleBin::RecycledTextureHolder recycled{info.size,
325 info.format};
326 if (aHolder.mResourceWrapper) {
327 // Don't attempt to recycle non-recyclable shared surfaces
328 if (aHolder.mResourceWrapper->mSharedSurface &&
329 !aHolder.mResourceWrapper->mSharedSurface->mDesc.canRecycle) {
330 return false;
333 // Recycle shared texture
334 SurfaceDescriptor desc;
335 if (!aHolder.mTextureData->Serialize(desc)) {
336 return false;
338 recycled.mType = desc.type();
339 recycled.mResourceWrapper = std::move(aHolder.mResourceWrapper);
340 } else {
341 // Recycle texture data
342 recycled.mTextureData = std::move(aHolder.mTextureData);
344 if (!StaticPrefs::gfx_remote_texture_recycle_disabled()) {
345 aRecycleBin->mRecycledTextures.push_back(std::move(recycled));
348 return true;
351 void RemoteTextureMap::PushTexture(
352 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
353 const base::ProcessId aForPid, UniquePtr<TextureData>&& aTextureData,
354 RefPtr<TextureHost>& aTextureHost,
355 UniquePtr<SharedResourceWrapper>&& aResourceWrapper) {
356 MOZ_RELEASE_ASSERT(aTextureHost);
358 std::vector<RefPtr<TextureHost>>
359 releasingTextures; // Release outside the monitor
360 std::vector<std::function<void(const RemoteTextureInfo&)>>
361 renderingReadyCallbacks; // Call outside the monitor
363 MonitorAutoLock lock(mMonitor);
365 auto* owner = GetTextureOwner(lock, aOwnerId, aForPid);
366 if (!owner) {
367 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
368 return;
371 if (owner->mIsContextLost &&
372 !(aTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) {
373 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
374 gfxCriticalNoteOnce << "Texture pushed during context lost";
377 auto textureData = MakeUnique<TextureDataHolder>(
378 aTextureId, aTextureHost, std::move(aTextureData),
379 std::move(aResourceWrapper));
381 MOZ_ASSERT(owner->mLatestPushedTextureId < aTextureId);
382 if (owner->mLatestPushedTextureId < aTextureId) {
383 owner->mLatestPushedTextureId = aTextureId;
385 MOZ_ASSERT(owner->mLatestUsingTextureId < aTextureId);
387 owner->mWaitingTextureDataHolders.push_back(std::move(textureData));
390 GetRenderingReadyCallbacks(lock, owner, aTextureId,
391 renderingReadyCallbacks);
392 // Update mRemoteTextureHost.
393 // This happens when PushTexture() with RemoteTextureId is called after
394 // GetRemoteTexture() with the RemoteTextureId.
395 const auto key = std::pair(aForPid, aTextureId);
396 auto it = mRemoteTextureHostWrapperHolders.find(key);
397 if (it != mRemoteTextureHostWrapperHolders.end()) {
398 MOZ_ASSERT(!it->second->mRemoteTextureHost);
399 it->second->mRemoteTextureHost = aTextureHost;
403 mMonitor.Notify();
405 // Release owner->mReleasingRenderedTextureHosts before checking
406 // NumCompositableRefs()
407 if (!owner->mReleasingRenderedTextureHosts.empty()) {
408 std::transform(
409 owner->mReleasingRenderedTextureHosts.begin(),
410 owner->mReleasingRenderedTextureHosts.end(),
411 std::back_inserter(releasingTextures),
412 [](CompositableTextureHostRef& aRef) { return aRef.get(); });
413 owner->mReleasingRenderedTextureHosts.clear();
416 // Drop obsoleted remote textures.
417 while (!owner->mUsingTextureDataHolders.empty()) {
418 auto& front = owner->mUsingTextureDataHolders.front();
419 // If mLatestRenderedTextureHost is last compositable ref of remote
420 // texture's TextureHost, its RemoteTextureHostWrapper is already
421 // unregistered. It happens when pushed remote textures that follow are
422 // not rendered since last mLatestRenderedTextureHost update. In this
423 // case, remove the TextureHost from mUsingTextureDataHolders. It is for
424 // unblocking remote texture recyclieng.
425 if (front->mTextureHost &&
426 front->mTextureHost->NumCompositableRefs() == 1 &&
427 front->mTextureHost == owner->mLatestRenderedTextureHost) {
428 owner->mUsingTextureDataHolders.pop_front();
429 continue;
431 // When compositable ref of TextureHost becomes 0, the TextureHost is not
432 // used by WebRender anymore.
433 if (front->mTextureHost &&
434 front->mTextureHost->NumCompositableRefs() == 0) {
435 owner->mReleasingTextureDataHolders.push_back(std::move(front));
436 owner->mUsingTextureDataHolders.pop_front();
437 } else if (front->mTextureHost &&
438 front->mTextureHost->NumCompositableRefs() >= 0) {
439 // Remote texture is still in use by WebRender.
440 break;
441 } else {
442 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
443 owner->mUsingTextureDataHolders.pop_front();
446 while (!owner->mReleasingTextureDataHolders.empty()) {
447 RecycleTexture(owner->mRecycleBin,
448 *owner->mReleasingTextureDataHolders.front(), true);
449 owner->mReleasingTextureDataHolders.pop_front();
453 const auto info = RemoteTextureInfo(aTextureId, aOwnerId, aForPid);
454 for (auto& callback : renderingReadyCallbacks) {
455 callback(info);
459 bool RemoteTextureMap::RemoveTexture(const RemoteTextureId aTextureId,
460 const RemoteTextureOwnerId aOwnerId,
461 const base::ProcessId aForPid) {
462 MonitorAutoLock lock(mMonitor);
464 auto* owner = GetTextureOwner(lock, aOwnerId, aForPid);
465 if (!owner) {
466 return false;
469 for (auto it = owner->mWaitingTextureDataHolders.begin();
470 it != owner->mWaitingTextureDataHolders.end(); it++) {
471 auto& data = *it;
472 if (data->mTextureId == aTextureId) {
473 if (mRemoteTextureHostWrapperHolders.find(std::pair(
474 aForPid, aTextureId)) != mRemoteTextureHostWrapperHolders.end()) {
475 return false;
477 if (!RecycleTexture(owner->mRecycleBin, *data, false)) {
478 owner->mReleasingTextureDataHolders.push_back(std::move(data));
480 owner->mWaitingTextureDataHolders.erase(it);
481 return true;
485 return false;
488 void RemoteTextureMap::GetLatestBufferSnapshot(
489 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
490 const mozilla::ipc::Shmem& aDestShmem, const gfx::IntSize& aSize) {
491 // The compositable ref of remote texture should be updated in mMonitor lock.
492 CompositableTextureHostRef textureHostRef;
493 RefPtr<TextureHost> releasingTexture; // Release outside the monitor
494 std::shared_ptr<webgpu::ExternalTexture> externalTexture;
496 MonitorAutoLock lock(mMonitor);
498 auto* owner = GetTextureOwner(lock, aOwnerId, aForPid);
499 if (!owner) {
500 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
501 return;
504 // Get latest TextureHost of remote Texture.
505 if (owner->mWaitingTextureDataHolders.empty() &&
506 owner->mUsingTextureDataHolders.empty()) {
507 return;
509 const auto* holder = !owner->mWaitingTextureDataHolders.empty()
510 ? owner->mWaitingTextureDataHolders.back().get()
511 : owner->mUsingTextureDataHolders.back().get();
512 TextureHost* textureHost = holder->mTextureHost;
514 if (textureHost->GetSize() != aSize) {
515 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
516 return;
518 if (textureHost->GetFormat() != gfx::SurfaceFormat::R8G8B8A8 &&
519 textureHost->GetFormat() != gfx::SurfaceFormat::B8G8R8A8) {
520 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
521 return;
523 if (holder->mResourceWrapper &&
524 holder->mResourceWrapper->mExternalTexture) {
525 // Increment compositable ref to prevent that TextureDataHolder is removed
526 // during memcpy.
527 textureHostRef = textureHost;
528 externalTexture = holder->mResourceWrapper->mExternalTexture;
529 } else if (textureHost->AsBufferTextureHost()) {
530 // Increment compositable ref to prevent that TextureDataHolder is removed
531 // during memcpy.
532 textureHostRef = textureHost;
533 } else {
534 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
535 return;
539 if (!textureHostRef) {
540 return;
543 if (externalTexture) {
544 externalTexture->GetSnapshot(aDestShmem, aSize);
545 } else if (auto* bufferTextureHost = textureHostRef->AsBufferTextureHost()) {
546 uint32_t stride = ImageDataSerializer::ComputeRGBStride(
547 bufferTextureHost->GetFormat(), aSize.width);
548 uint32_t bufferSize = stride * aSize.height;
549 uint8_t* dst = aDestShmem.get<uint8_t>();
550 uint8_t* src = bufferTextureHost->GetBuffer();
552 MOZ_ASSERT(bufferSize <= aDestShmem.Size<uint8_t>());
553 memcpy(dst, src, bufferSize);
557 MonitorAutoLock lock(mMonitor);
558 // Release compositable ref in mMonitor lock, but release RefPtr outside the
559 // monitor
560 releasingTexture = textureHostRef;
561 textureHostRef = nullptr;
565 void RemoteTextureMap::RegisterTextureOwner(
566 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
567 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin) {
568 MonitorAutoLock lock(mMonitor);
570 const auto key = std::pair(aForPid, aOwnerId);
571 auto it = mTextureOwners.find(key);
572 if (it != mTextureOwners.end()) {
573 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
574 return;
576 auto owner = MakeUnique<TextureOwner>();
577 if (aRecycleBin) {
578 owner->mRecycleBin = aRecycleBin;
579 } else {
580 owner->mRecycleBin = new RemoteTextureRecycleBin(false);
583 auto itWaiting = mWaitingTextureOwners.find(key);
584 if (itWaiting != mWaitingTextureOwners.end()) {
585 owner->mRenderingReadyCallbackHolders.swap(
586 itWaiting->second->mRenderingReadyCallbackHolders);
587 mWaitingTextureOwners.erase(itWaiting);
590 mTextureOwners.emplace(key, std::move(owner));
593 void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary(
594 const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner,
595 std::deque<UniquePtr<TextureDataHolder>>& aHolders) {
596 for (auto& holder : aHolders) {
597 // If remote texture of TextureHost still exist, keep
598 // SharedResourceWrapper/TextureData alive while the TextureHost is alive.
599 if (holder->mTextureHost &&
600 holder->mTextureHost->NumCompositableRefs() > 0) {
601 RefPtr<nsISerialEventTarget> eventTarget = GetCurrentSerialEventTarget();
602 RefPtr<Runnable> runnable = NS_NewRunnableFunction(
603 "RemoteTextureMap::UnregisterTextureOwner::Runnable",
604 [data = std::move(holder->mTextureData),
605 wrapper = std::move(holder->mResourceWrapper)]() {});
607 auto destroyedCallback = [eventTarget = std::move(eventTarget),
608 runnable = std::move(runnable)]() mutable {
609 eventTarget->Dispatch(runnable.forget());
612 holder->mTextureHost->SetDestroyedCallback(destroyedCallback);
613 } else {
614 RecycleTexture(aOwner->mRecycleBin, *holder, true);
619 UniquePtr<RemoteTextureMap::TextureOwner>
620 RemoteTextureMap::UnregisterTextureOwner(
621 MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId,
622 const base::ProcessId aForPid,
623 std::vector<RefPtr<TextureHost>>& aReleasingTextures,
624 std::vector<std::function<void(const RemoteTextureInfo&)>>&
625 aRenderingReadyCallbacks) {
626 const auto key = std::pair(aForPid, aOwnerId);
627 auto it = mTextureOwners.find(key);
628 if (it == mTextureOwners.end()) {
629 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
630 return nullptr;
633 auto* owner = it->second.get();
634 // If waiting for a last use, and it hasn't arrived yet, then defer
635 // unregistering.
636 if (owner->mWaitForTxn) {
637 owner->mDeferUnregister = GetCurrentSerialEventTarget();
638 // If another thread is waiting on this owner to produce textures,
639 // it must be notified that owner is going away.
640 if (!owner->mLatestTextureHost &&
641 owner->mWaitingTextureDataHolders.empty()) {
642 aProofOfLock.Notify();
644 return nullptr;
647 if (owner->mLatestTextureHost) {
648 // Release CompositableRef in mMonitor
649 aReleasingTextures.emplace_back(owner->mLatestTextureHost);
650 owner->mLatestTextureHost = nullptr;
653 // mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could
654 // simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts in
655 // mUsingTextureDataHolders alive. They need to be cleared before
656 // KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses
657 // NumCompositableRefs().
658 if (!owner->mReleasingRenderedTextureHosts.empty()) {
659 std::transform(owner->mReleasingRenderedTextureHosts.begin(),
660 owner->mReleasingRenderedTextureHosts.end(),
661 std::back_inserter(aReleasingTextures),
662 [](CompositableTextureHostRef& aRef) { return aRef.get(); });
663 owner->mReleasingRenderedTextureHosts.clear();
665 if (owner->mLatestRenderedTextureHost) {
666 owner->mLatestRenderedTextureHost = nullptr;
669 GetAllRenderingReadyCallbacks(aProofOfLock, owner, aRenderingReadyCallbacks);
671 KeepTextureDataAliveForTextureHostIfNecessary(
672 aProofOfLock, owner, owner->mWaitingTextureDataHolders);
674 KeepTextureDataAliveForTextureHostIfNecessary(
675 aProofOfLock, owner, owner->mUsingTextureDataHolders);
677 KeepTextureDataAliveForTextureHostIfNecessary(
678 aProofOfLock, owner, owner->mReleasingTextureDataHolders);
680 UniquePtr<TextureOwner> releasingOwner = std::move(it->second);
681 mTextureOwners.erase(it);
682 return releasingOwner;
685 void RemoteTextureMap::UnregisterTextureOwner(
686 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) {
687 UniquePtr<TextureOwner> releasingOwner; // Release outside the monitor
688 std::vector<RefPtr<TextureHost>>
689 releasingTextures; // Release outside the monitor
690 std::vector<std::function<void(const RemoteTextureInfo&)>>
691 renderingReadyCallbacks; // Call outside the monitor
693 MonitorAutoLock lock(mMonitor);
695 releasingOwner = UnregisterTextureOwner(
696 lock, aOwnerId, aForPid, releasingTextures, renderingReadyCallbacks);
697 if (!releasingOwner) {
698 return;
701 mMonitor.Notify();
704 const auto info =
705 RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0);
706 for (auto& callback : renderingReadyCallbacks) {
707 callback(info);
711 void RemoteTextureMap::UnregisterTextureOwners(
712 const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) {
713 std::vector<UniquePtr<TextureOwner>>
714 releasingOwners; // Release outside the monitor
715 std::vector<RefPtr<TextureHost>>
716 releasingTextures; // Release outside the monitor
717 std::vector<std::function<void(const RemoteTextureInfo&)>>
718 renderingReadyCallbacks; // Call outside the monitor
720 MonitorAutoLock lock(mMonitor);
722 for (const auto& id : aOwnerIds) {
723 if (auto releasingOwner = UnregisterTextureOwner(
724 lock, id, aForPid, releasingTextures, renderingReadyCallbacks)) {
725 releasingOwners.push_back(std::move(releasingOwner));
729 if (releasingOwners.empty()) {
730 return;
733 mMonitor.Notify();
736 const auto info =
737 RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0);
738 for (auto& callback : renderingReadyCallbacks) {
739 callback(info);
743 already_AddRefed<RemoteTextureTxnScheduler>
744 RemoteTextureMap::RegisterTxnScheduler(base::ProcessId aForPid,
745 RemoteTextureTxnType aType) {
746 MonitorAutoLock lock(mMonitor);
748 const auto key = std::pair(aForPid, aType);
749 auto it = mTxnSchedulers.find(key);
750 if (it != mTxnSchedulers.end()) {
751 return do_AddRef(it->second);
754 RefPtr<RemoteTextureTxnScheduler> scheduler(
755 new RemoteTextureTxnScheduler(aForPid, aType));
756 mTxnSchedulers.emplace(key, scheduler.get());
757 return scheduler.forget();
760 void RemoteTextureMap::UnregisterTxnScheduler(base::ProcessId aForPid,
761 RemoteTextureTxnType aType) {
762 MonitorAutoLock lock(mMonitor);
764 const auto key = std::pair(aForPid, aType);
765 auto it = mTxnSchedulers.find(key);
766 if (it == mTxnSchedulers.end()) {
767 MOZ_ASSERT_UNREACHABLE("Remote texture txn scheduler does not exist.");
768 return;
770 mTxnSchedulers.erase(it);
773 already_AddRefed<RemoteTextureTxnScheduler> RemoteTextureTxnScheduler::Create(
774 mozilla::ipc::IProtocol* aProtocol) {
775 if (auto* instance = RemoteTextureMap::Get()) {
776 if (auto* toplevel = aProtocol->ToplevelProtocol()) {
777 auto pid = toplevel->OtherPidMaybeInvalid();
778 if (pid != base::kInvalidProcessId) {
779 return instance->RegisterTxnScheduler(pid, toplevel->GetProtocolId());
783 return nullptr;
786 RemoteTextureTxnScheduler::~RemoteTextureTxnScheduler() {
787 NotifyTxn(std::numeric_limits<RemoteTextureTxnId>::max());
788 RemoteTextureMap::Get()->UnregisterTxnScheduler(mForPid, mType);
791 void RemoteTextureTxnScheduler::NotifyTxn(RemoteTextureTxnId aTxnId) {
792 MonitorAutoLock lock(RemoteTextureMap::Get()->mMonitor);
794 mLastTxnId = aTxnId;
796 for (; !mWaits.empty(); mWaits.pop_front()) {
797 auto& wait = mWaits.front();
798 if (wait.mTxnId > aTxnId) {
799 break;
801 RemoteTextureMap::Get()->NotifyTxn(lock, wait.mOwnerId, mForPid);
805 bool RemoteTextureTxnScheduler::WaitForTxn(const MonitorAutoLock& aProofOfLock,
806 RemoteTextureOwnerId aOwnerId,
807 RemoteTextureTxnId aTxnId) {
808 if (aTxnId <= mLastTxnId) {
809 return false;
811 mWaits.insert(std::upper_bound(mWaits.begin(), mWaits.end(), aTxnId),
812 Wait{aOwnerId, aTxnId});
813 return true;
816 void RemoteTextureMap::ClearRecycledTextures(
817 const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid,
818 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin) {
819 std::list<RemoteTextureRecycleBin::RecycledTextureHolder>
820 releasingTextures; // Release outside the monitor
822 MonitorAutoLock lock(mMonitor);
824 if (aRecycleBin) {
825 releasingTextures.splice(releasingTextures.end(),
826 aRecycleBin->mRecycledTextures);
829 for (const auto& id : aOwnerIds) {
830 const auto key = std::pair(aForPid, id);
831 auto it = mTextureOwners.find(key);
832 if (it == mTextureOwners.end()) {
833 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
834 continue;
836 auto& owner = it->second;
838 releasingTextures.splice(releasingTextures.end(),
839 owner->mRecycleBin->mRecycledTextures);
844 void RemoteTextureMap::NotifyContextLost(
845 const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) {
846 MonitorAutoLock lock(mMonitor);
848 bool changed = false;
849 for (const auto& id : aOwnerIds) {
850 const auto key = std::pair(aForPid, id);
851 auto it = mTextureOwners.find(key);
852 if (it == mTextureOwners.end()) {
853 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
854 continue;
856 auto& owner = it->second;
857 if (!owner->mIsContextLost) {
858 owner->mIsContextLost = true;
859 changed = true;
863 if (changed) {
864 mMonitor.Notify();
868 void RemoteTextureMap::NotifyContextRestored(
869 const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) {
870 MonitorAutoLock lock(mMonitor);
872 bool changed = false;
873 for (const auto& id : aOwnerIds) {
874 const auto key = std::pair(aForPid, id);
875 auto it = mTextureOwners.find(key);
876 if (it == mTextureOwners.end()) {
877 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
878 continue;
880 auto& owner = it->second;
881 if (owner->mIsContextLost) {
882 owner->mIsContextLost = false;
883 changed = true;
887 if (changed) {
888 mMonitor.Notify();
892 /* static */
893 RefPtr<TextureHost> RemoteTextureMap::CreateRemoteTexture(
894 TextureData* aTextureData, TextureFlags aTextureFlags) {
895 SurfaceDescriptor desc;
896 DebugOnly<bool> ret = aTextureData->Serialize(desc);
897 MOZ_ASSERT(ret);
898 TextureFlags flags = aTextureFlags | TextureFlags::REMOTE_TEXTURE |
899 TextureFlags::DEALLOCATE_CLIENT;
901 Maybe<wr::ExternalImageId> externalImageId = Nothing();
902 RefPtr<TextureHost> textureHost =
903 TextureHost::Create(desc, null_t(), nullptr, LayersBackend::LAYERS_WR,
904 flags, externalImageId);
905 MOZ_ASSERT(textureHost);
906 if (!textureHost) {
907 gfxCriticalNoteOnce << "Failed to create remote texture";
908 return nullptr;
911 textureHost->EnsureRenderTexture(Nothing());
913 return textureHost;
916 void RemoteTextureMap::UpdateTexture(const MonitorAutoLock& aProofOfLock,
917 RemoteTextureMap::TextureOwner* aOwner,
918 const RemoteTextureId aTextureId) {
919 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
920 MOZ_ASSERT(aOwner);
921 MOZ_ASSERT(aTextureId >= aOwner->mLatestUsingTextureId);
923 if (aTextureId == aOwner->mLatestUsingTextureId) {
924 // No need to update texture.
925 return;
928 // Move remote textures to mUsingTextureDataHolders.
929 while (!aOwner->mWaitingTextureDataHolders.empty()) {
930 auto& front = aOwner->mWaitingTextureDataHolders.front();
931 if (aTextureId < front->mTextureId) {
932 break;
934 MOZ_RELEASE_ASSERT(front->mTextureHost);
935 aOwner->mLatestTextureHost = front->mTextureHost;
936 aOwner->mLatestUsingTextureId = front->mTextureId;
938 UniquePtr<TextureDataHolder> holder = std::move(front);
939 aOwner->mWaitingTextureDataHolders.pop_front();
940 // If there are textures not being used by the compositor that will be
941 // obsoleted by this new texture, then queue them for removal later on
942 // the creating thread.
943 while (!aOwner->mUsingTextureDataHolders.empty()) {
944 auto& back = aOwner->mUsingTextureDataHolders.back();
945 if (back->mTextureHost &&
946 back->mTextureHost->NumCompositableRefs() == 0) {
947 if (!RecycleTexture(aOwner->mRecycleBin, *back, false)) {
948 aOwner->mReleasingTextureDataHolders.push_back(std::move(back));
950 aOwner->mUsingTextureDataHolders.pop_back();
951 continue;
953 break;
955 aOwner->mUsingTextureDataHolders.push_back(std::move(holder));
959 void RemoteTextureMap::GetRenderingReadyCallbacks(
960 const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner,
961 const RemoteTextureId aTextureId,
962 std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions) {
963 MOZ_ASSERT(aOwner);
965 while (!aOwner->mRenderingReadyCallbackHolders.empty()) {
966 auto& front = aOwner->mRenderingReadyCallbackHolders.front();
967 if (aTextureId < front->mTextureId) {
968 break;
970 if (front->mCallback) {
971 aFunctions.push_back(std::move(front->mCallback));
973 aOwner->mRenderingReadyCallbackHolders.pop_front();
977 void RemoteTextureMap::GetAllRenderingReadyCallbacks(
978 const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner,
979 std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions) {
980 GetRenderingReadyCallbacks(aProofOfLock, aOwner, RemoteTextureId::Max(),
981 aFunctions);
982 MOZ_ASSERT(aOwner->mRenderingReadyCallbackHolders.empty());
985 bool RemoteTextureMap::WaitForRemoteTextureOwner(
986 RemoteTextureHostWrapper* aTextureHostWrapper) {
987 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
988 MOZ_ASSERT(aTextureHostWrapper);
990 const auto& ownerId = aTextureHostWrapper->mOwnerId;
991 const auto& forPid = aTextureHostWrapper->mForPid;
993 MonitorAutoLock lock(mMonitor);
995 auto* owner = GetTextureOwner(lock, ownerId, forPid);
996 // If there is no texture owner yet, then we might need to wait for one to
997 // be created, if allowed. If so, we must also wait for an initial texture
998 // host to be created so we can use it.
999 if (!owner || (!owner->mLatestTextureHost &&
1000 owner->mWaitingTextureDataHolders.empty())) {
1001 const TimeDuration timeout = TimeDuration::FromMilliseconds(10000);
1002 while (!owner || (!owner->mLatestTextureHost &&
1003 owner->mWaitingTextureDataHolders.empty())) {
1004 if (owner && (owner->mIsContextLost || owner->mDeferUnregister)) {
1005 // If the context was lost, no further updates are expected.
1006 return false;
1008 CVStatus status = mMonitor.Wait(timeout);
1009 if (status == CVStatus::Timeout) {
1010 return false;
1012 owner = GetTextureOwner(lock, ownerId, forPid);
1015 return true;
1018 void RemoteTextureMap::GetRemoteTexture(
1019 RemoteTextureHostWrapper* aTextureHostWrapper) {
1020 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1021 MOZ_ASSERT(aTextureHostWrapper);
1023 if (aTextureHostWrapper->IsReadyForRendering()) {
1024 return;
1027 const auto& textureId = aTextureHostWrapper->mTextureId;
1028 const auto& ownerId = aTextureHostWrapper->mOwnerId;
1029 const auto& forPid = aTextureHostWrapper->mForPid;
1030 const auto& size = aTextureHostWrapper->mSize;
1032 RefPtr<TextureHost> textureHost;
1034 MonitorAutoLock lock(mMonitor);
1036 auto* owner = GetTextureOwner(lock, ownerId, forPid);
1037 if (!owner) {
1038 return;
1041 UpdateTexture(lock, owner, textureId);
1043 if (owner->mLatestTextureHost &&
1044 (owner->mLatestTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) {
1045 // Remote texture allocation was failed.
1046 return;
1049 if (textureId == owner->mLatestUsingTextureId) {
1050 MOZ_ASSERT(owner->mLatestTextureHost);
1051 MOZ_ASSERT(owner->mLatestTextureHost->GetSize() == size);
1052 if (owner->mLatestTextureHost->GetSize() != size) {
1053 gfxCriticalNoteOnce << "unexpected remote texture size: "
1054 << owner->mLatestTextureHost->GetSize()
1055 << " expected: " << size;
1057 textureHost = owner->mLatestTextureHost;
1060 // Update mRemoteTextureHost
1061 if (textureId == owner->mLatestUsingTextureId) {
1062 const auto key = std::pair(forPid, textureId);
1063 auto it = mRemoteTextureHostWrapperHolders.find(key);
1064 if (it != mRemoteTextureHostWrapperHolders.end() &&
1065 !it->second->mRemoteTextureHost) {
1066 it->second->mRemoteTextureHost = owner->mLatestTextureHost;
1067 } else {
1068 MOZ_ASSERT(it->second->mRemoteTextureHost == owner->mLatestTextureHost);
1072 if (textureHost) {
1073 aTextureHostWrapper->SetRemoteTextureHost(lock, textureHost);
1074 aTextureHostWrapper->ApplyTextureFlagsToRemoteTexture();
1079 void RemoteTextureMap::NotifyTxn(const MonitorAutoLock& aProofOfLock,
1080 const RemoteTextureOwnerId aOwnerId,
1081 const base::ProcessId aForPid) {
1082 if (auto* owner = GetTextureOwner(aProofOfLock, aOwnerId, aForPid)) {
1083 if (!owner->mWaitForTxn) {
1084 MOZ_ASSERT_UNREACHABLE("Expected texture owner to wait for txn.");
1085 return;
1087 owner->mWaitForTxn = false;
1088 if (!owner->mDeferUnregister) {
1089 // If unregistering was not deferred, then don't try to force
1090 // unregistering yet.
1091 return;
1093 owner->mDeferUnregister->Dispatch(NS_NewRunnableFunction(
1094 "RemoteTextureMap::SetLastRemoteTextureUse::Runnable",
1095 [aOwnerId, aForPid]() {
1096 RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId, aForPid);
1097 }));
1101 bool RemoteTextureMap::WaitForTxn(const RemoteTextureOwnerId aOwnerId,
1102 const base::ProcessId aForPid,
1103 RemoteTextureTxnType aTxnType,
1104 RemoteTextureTxnId aTxnId) {
1105 MonitorAutoLock lock(mMonitor);
1106 if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) {
1107 if (owner->mDeferUnregister) {
1108 MOZ_ASSERT_UNREACHABLE(
1109 "Texture owner must wait for txn before unregistering.");
1110 return false;
1112 if (owner->mWaitForTxn) {
1113 MOZ_ASSERT_UNREACHABLE("Texture owner already waiting for txn.");
1114 return false;
1116 const auto key = std::pair(aForPid, aTxnType);
1117 auto it = mTxnSchedulers.find(key);
1118 if (it == mTxnSchedulers.end()) {
1119 // During shutdown, different toplevel protocols may go away in
1120 // disadvantageous orders, causing us to sometimes be processing
1121 // waits even though the source of transactions upon which the
1122 // wait depends shut down. This is generally harmless to ignore,
1123 // as it means no further transactions will be generated of that
1124 // type and all such transactions have been processed before it
1125 // unregistered.
1126 NS_WARNING("Could not find scheduler for txn type.");
1127 return false;
1129 if (it->second->WaitForTxn(lock, aOwnerId, aTxnId)) {
1130 owner->mWaitForTxn = true;
1132 return true;
1134 return false;
1137 void RemoteTextureMap::ReleaseRemoteTextureHost(
1138 RemoteTextureHostWrapper* aTextureHostWrapper) {
1139 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1140 MOZ_ASSERT(aTextureHostWrapper);
1142 RefPtr<TextureHost> releasingTexture; // Release outside the mutex
1144 MonitorAutoLock lock(mMonitor);
1145 releasingTexture = aTextureHostWrapper->GetRemoteTextureHost(lock);
1146 aTextureHostWrapper->ClearRemoteTextureHost(lock);
1150 RefPtr<TextureHost> RemoteTextureMap::GetOrCreateRemoteTextureHostWrapper(
1151 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
1152 const base::ProcessId aForPid, const gfx::IntSize& aSize,
1153 const TextureFlags aFlags) {
1154 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1155 MonitorAutoLock lock(mMonitor);
1157 const auto key = std::pair(aForPid, aTextureId);
1158 auto it = mRemoteTextureHostWrapperHolders.find(key);
1159 if (it != mRemoteTextureHostWrapperHolders.end()) {
1160 return it->second->mRemoteTextureHostWrapper;
1163 auto wrapper = RemoteTextureHostWrapper::Create(aTextureId, aOwnerId, aForPid,
1164 aSize, aFlags);
1165 auto wrapperHolder = MakeUnique<RemoteTextureHostWrapperHolder>(wrapper);
1167 mRemoteTextureHostWrapperHolders.emplace(key, std::move(wrapperHolder));
1169 return wrapper;
1172 void RemoteTextureMap::UnregisterRemoteTextureHostWrapper(
1173 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
1174 const base::ProcessId aForPid) {
1175 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1177 std::vector<RefPtr<TextureHost>>
1178 releasingTextures; // Release outside the monitor
1180 MonitorAutoLock lock(mMonitor);
1182 const auto key = std::pair(aForPid, aTextureId);
1183 auto it = mRemoteTextureHostWrapperHolders.find(key);
1184 if (it == mRemoteTextureHostWrapperHolders.end()) {
1185 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1186 return;
1188 releasingTextures.emplace_back(it->second->mRemoteTextureHostWrapper);
1189 if (it->second->mRemoteTextureHost) {
1190 releasingTextures.emplace_back(it->second->mRemoteTextureHost);
1193 mRemoteTextureHostWrapperHolders.erase(it);
1194 mMonitor.Notify();
1198 bool RemoteTextureMap::CheckRemoteTextureReady(
1199 const RemoteTextureInfo& aInfo,
1200 std::function<void(const RemoteTextureInfo&)>&& aCallback) {
1201 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1203 MonitorAutoLock lock(mMonitor);
1205 auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid);
1206 if (aInfo.mWaitForRemoteTextureOwner && !owner) {
1207 // Remote texture owner is not registered yet. Waiting for remote texture
1208 // owner
1210 const auto key = std::pair(aInfo.mForPid, aInfo.mOwnerId);
1211 if (!mWaitingTextureOwners[key]) {
1212 auto waitingOwner = MakeUnique<WaitingTextureOwner>();
1213 mWaitingTextureOwners[key] = std::move(waitingOwner);
1216 MOZ_ASSERT(mWaitingTextureOwners[key]);
1218 WaitingTextureOwner* waitingOwner = mWaitingTextureOwners[key].get();
1220 auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>(
1221 aInfo.mTextureId, std::move(aCallback));
1222 waitingOwner->mRenderingReadyCallbackHolders.push_back(
1223 std::move(callbackHolder));
1225 return false;
1228 if (!owner || owner->mIsContextLost) {
1229 // Owner is already removed or context lost. No need to wait texture ready.
1230 return true;
1233 const auto key = std::pair(aInfo.mForPid, aInfo.mTextureId);
1234 auto it = mRemoteTextureHostWrapperHolders.find(key);
1235 if (it == mRemoteTextureHostWrapperHolders.end()) {
1236 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1237 gfxCriticalNoteOnce << "Remote texture does not exist id:"
1238 << uint64_t(aInfo.mTextureId);
1239 return true;
1242 if (owner->mLatestPushedTextureId >= aInfo.mTextureId) {
1243 return true;
1246 auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>(
1247 aInfo.mTextureId, std::move(aCallback));
1248 owner->mRenderingReadyCallbackHolders.push_back(std::move(callbackHolder));
1250 return false;
1253 bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo& aInfo) {
1254 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1256 MonitorAutoLock lock(mMonitor);
1258 auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid);
1259 if (aInfo.mWaitForRemoteTextureOwner &&
1260 (!owner || (!owner->mLatestTextureHost &&
1261 owner->mWaitingTextureDataHolders.empty()))) {
1262 const TimeDuration timeout = TimeDuration::FromMilliseconds(10000);
1263 while (!owner || (!owner->mLatestTextureHost &&
1264 owner->mWaitingTextureDataHolders.empty())) {
1265 if (owner && (owner->mIsContextLost || owner->mDeferUnregister)) {
1266 // If the context was lost, no further updates are expected.
1267 return false;
1269 CVStatus status = mMonitor.Wait(timeout);
1270 if (status == CVStatus::Timeout) {
1271 return false;
1273 owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid);
1277 if (!owner || owner->mIsContextLost) {
1278 // Owner is already removed or context lost.
1279 return false;
1282 const auto key = std::pair(aInfo.mForPid, aInfo.mTextureId);
1283 auto it = mRemoteTextureHostWrapperHolders.find(key);
1284 if (it == mRemoteTextureHostWrapperHolders.end()) {
1285 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1286 gfxCriticalNoteOnce << "Remote texture does not exist id:"
1287 << uint64_t(aInfo.mTextureId);
1288 return false;
1291 const TimeDuration timeout = TimeDuration::FromMilliseconds(1000);
1293 while (owner->mLatestPushedTextureId < aInfo.mTextureId) {
1294 CVStatus status = mMonitor.Wait(timeout);
1295 if (status == CVStatus::Timeout) {
1296 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1297 gfxCriticalNoteOnce << "Remote texture wait time out id:"
1298 << uint64_t(aInfo.mTextureId);
1299 return false;
1302 auto it = mRemoteTextureHostWrapperHolders.find(key);
1303 if (it == mRemoteTextureHostWrapperHolders.end()) {
1304 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1305 return false;
1308 auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid);
1309 // When owner is alreay unregistered, remote texture will not be pushed.
1310 if (!owner || owner->mIsContextLost) {
1311 // This could happen with IPC abnormal shutdown
1312 return false;
1316 return true;
1319 void RemoteTextureMap::SuppressRemoteTextureReadyCheck(
1320 const RemoteTextureInfo& aInfo) {
1321 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
1322 MonitorAutoLock lock(mMonitor);
1324 // Clear if WaitingTextureOwner exists.
1325 auto itWaiting =
1326 mWaitingTextureOwners.find(std::pair(aInfo.mForPid, aInfo.mOwnerId));
1327 if (itWaiting != mWaitingTextureOwners.end()) {
1328 mWaitingTextureOwners.erase(itWaiting);
1331 const auto key = std::pair(aInfo.mForPid, aInfo.mTextureId);
1332 auto it = mRemoteTextureHostWrapperHolders.find(key);
1333 if (it == mRemoteTextureHostWrapperHolders.end()) {
1334 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1335 return;
1337 it->second->mReadyCheckSuppressed = true;
1340 UniquePtr<TextureData> RemoteTextureMap::GetRecycledTextureData(
1341 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
1342 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin,
1343 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
1344 TextureType aTextureType) {
1345 MonitorAutoLock lock(mMonitor);
1347 RefPtr<RemoteTextureRecycleBin> bin;
1348 if (aOwnerId.IsValid()) {
1349 if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) {
1350 bin = owner->mRecycleBin;
1352 } else {
1353 bin = aRecycleBin;
1355 if (!bin) {
1356 return nullptr;
1359 for (auto it = bin->mRecycledTextures.begin();
1360 it != bin->mRecycledTextures.end(); it++) {
1361 auto& holder = *it;
1362 if (holder.mTextureData &&
1363 holder.mTextureData->GetTextureType() == aTextureType &&
1364 holder.mSize == aSize && holder.mFormat == aFormat) {
1365 UniquePtr<TextureData> texture = std::move(holder.mTextureData);
1366 bin->mRecycledTextures.erase(it);
1367 return texture;
1371 return nullptr;
1374 UniquePtr<SharedResourceWrapper> RemoteTextureMap::GetRecycledSharedTexture(
1375 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
1376 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin,
1377 const gfx::IntSize& aSize, const gfx::SurfaceFormat aFormat,
1378 SurfaceDescriptor::Type aType) {
1379 MonitorAutoLock lock(mMonitor);
1381 RefPtr<RemoteTextureRecycleBin> bin;
1382 if (aOwnerId.IsValid()) {
1383 if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) {
1384 bin = owner->mRecycleBin;
1386 } else {
1387 bin = aRecycleBin;
1389 if (!bin) {
1390 return nullptr;
1393 for (auto it = bin->mRecycledTextures.begin();
1394 it != bin->mRecycledTextures.end(); it++) {
1395 auto& holder = *it;
1396 if (holder.mType == aType && holder.mSize == aSize &&
1397 holder.mFormat == aFormat) {
1398 UniquePtr<SharedResourceWrapper> wrapper =
1399 std::move(holder.mResourceWrapper);
1400 bin->mRecycledTextures.erase(it);
1401 return wrapper;
1405 return nullptr;
1408 RemoteTextureMap::TextureOwner* RemoteTextureMap::GetTextureOwner(
1409 const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId,
1410 const base::ProcessId aForPid) {
1411 const auto key = std::pair(aForPid, aOwnerId);
1412 auto it = mTextureOwners.find(key);
1413 if (it == mTextureOwners.end()) {
1414 return nullptr;
1416 return it->second.get();
1419 RemoteTextureMap::TextureDataHolder::TextureDataHolder(
1420 const RemoteTextureId aTextureId, RefPtr<TextureHost> aTextureHost,
1421 UniquePtr<TextureData>&& aTextureData,
1422 UniquePtr<SharedResourceWrapper>&& aResourceWrapper)
1423 : mTextureId(aTextureId),
1424 mTextureHost(aTextureHost),
1425 mTextureData(std::move(aTextureData)),
1426 mResourceWrapper(std::move(aResourceWrapper)) {}
1428 RemoteTextureMap::RenderingReadyCallbackHolder::RenderingReadyCallbackHolder(
1429 const RemoteTextureId aTextureId,
1430 std::function<void(const RemoteTextureInfo&)>&& aCallback)
1431 : mTextureId(aTextureId), mCallback(aCallback) {}
1433 RemoteTextureMap::RemoteTextureHostWrapperHolder::
1434 RemoteTextureHostWrapperHolder(
1435 RefPtr<TextureHost> aRemoteTextureHostWrapper)
1436 : mRemoteTextureHostWrapper(aRemoteTextureHostWrapper) {}
1438 } // namespace mozilla::layers