Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / gfx / layers / RemoteTextureMap.cpp
blob437606f2270c1e9c9e2b6296960eacf701a344ca
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 <vector>
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)
28 : mForPid(aForPid) {}
30 RemoteTextureOwnerClient::~RemoteTextureOwnerClient() = default;
32 bool RemoteTextureOwnerClient::IsRegistered(
33 const RemoteTextureOwnerId aOwnerId) {
34 auto it = mOwnerIds.find(aOwnerId);
35 if (it == mOwnerIds.end()) {
36 return false;
38 return true;
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()) {
52 return;
54 mOwnerIds.erase(it);
55 RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId, mForPid);
58 void RemoteTextureOwnerClient::UnregisterAllTextureOwners() {
59 if (mOwnerIds.empty()) {
60 return;
62 RemoteTextureMap::Get()->UnregisterTextureOwners(mOwnerIds, mForPid);
63 mOwnerIds.clear();
66 void RemoteTextureOwnerClient::NotifyContextLost() {
67 if (mOwnerIds.empty()) {
68 return;
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);
80 if (!textureHost) {
81 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
82 return;
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);
98 if (!textureHost) {
99 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
100 return;
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);
116 if (!textureHost) {
117 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
118 return;
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);
135 if (!rawData) {
136 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
137 return;
140 auto textureData = UniquePtr<TextureData>(rawData);
142 RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture(
143 textureData.get(), TextureFlags::DUMMY_TEXTURE);
144 if (!textureHost) {
145 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
146 return;
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,
159 aDestShmem, aSize);
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);
168 if (texture) {
169 return texture;
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(
184 aOwnerId, mForPid);
185 if (!wrapper) {
186 return nullptr;
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(
197 aOwnerId, mForPid);
198 if (!wrapper) {
199 return nullptr;
201 MOZ_ASSERT(wrapper->mExternalTexture);
202 return wrapper->mExternalTexture;
205 StaticAutoPtr<RemoteTextureMap> RemoteTextureMap::sInstance;
207 /* static */
208 void RemoteTextureMap::Init() {
209 MOZ_ASSERT(!sInstance);
210 sInstance = new RemoteTextureMap();
213 /* static */
214 void RemoteTextureMap::Shutdown() {
215 if (sInstance) {
216 sInstance = nullptr;
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);
239 if (!owner) {
240 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
241 return;
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;
285 mMonitor.Notify();
287 // Release owner->mReleasingRenderedTextureHosts before checking
288 // NumCompositableRefs()
289 if (!owner->mReleasingRenderedTextureHosts.empty()) {
290 std::transform(
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();
311 continue;
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.
332 break;
333 } else {
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) {
342 callback(info);
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);
356 if (!owner) {
357 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
358 return;
361 // Get latest TextureHost of remote Texture.
362 if (owner->mWaitingTextureDataHolders.empty() &&
363 !owner->mLatestTextureHost) {
364 return;
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");
373 return;
375 if (textureHost->GetSize() != aSize) {
376 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
377 return;
379 if (textureHost->GetFormat() != gfx::SurfaceFormat::R8G8B8A8 &&
380 textureHost->GetFormat() != gfx::SurfaceFormat::B8G8R8A8) {
381 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
382 return;
384 // Increment compositable ref to prevent that TextureHost is removed during
385 // memcpy.
386 textureHostRef = textureHost;
389 if (!textureHostRef) {
390 return;
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
408 // monitor
409 releasingTexture = textureHostRef;
410 textureHostRef = nullptr;
414 void RemoteTextureMap::RegisterTextureOwner(const RemoteTextureOwnerId aOwnerId,
415 const base::ProcessId aForPid,
416 bool aIsSyncMode) {
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");
423 return;
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");
470 return;
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()) {
485 std::transform(
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);
508 mMonitor.Notify();
511 const auto info =
512 RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0);
513 for (auto& callback : renderingReadyCallbacks) {
514 callback(info);
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");
536 continue;
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()) {
551 std::transform(
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);
575 mMonitor.Notify();
578 const auto info =
579 RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0);
580 for (auto& callback : renderingReadyCallbacks) {
581 callback(info);
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");
596 continue;
598 it->second->mIsContextLost = true;
600 mMonitor.Notify();
603 /* static */
604 RefPtr<TextureHost> RemoteTextureMap::CreateRemoteTexture(
605 TextureData* aTextureData, TextureFlags aTextureFlags) {
606 SurfaceDescriptor desc;
607 DebugOnly<bool> ret = aTextureData->Serialize(desc);
608 MOZ_ASSERT(ret);
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);
617 if (!textureHost) {
618 gfxCriticalNoteOnce << "Failed to create remote texture";
619 return nullptr;
622 textureHost->EnsureRenderTexture(Nothing());
624 return textureHost;
627 void RemoteTextureMap::UpdateTexture(const MonitorAutoLock& aProofOfLock,
628 RemoteTextureMap::TextureOwner* aOwner,
629 const RemoteTextureId aTextureId) {
630 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
631 MOZ_ASSERT(aOwner);
632 MOZ_ASSERT(aTextureId >= aOwner->mLatestTextureId);
634 if (aTextureId == aOwner->mLatestTextureId) {
635 // No need to update texture.
636 return;
639 // Move remote textures to mUsingTextureDataHolders.
640 while (!aOwner->mWaitingTextureDataHolders.empty()) {
641 auto& front = aOwner->mWaitingTextureDataHolders.front();
642 if (aTextureId < front->mTextureId) {
643 break;
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) {
659 MOZ_ASSERT(aOwner);
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) {
666 break;
668 if (front->mCallback) {
669 functions.push_back(std::move(front->mCallback));
671 aOwner->mRenderingReadyCallbackHolders.pop_front();
674 return functions;
677 std::vector<std::function<void(const RemoteTextureInfo&)>>
678 RemoteTextureMap::GetAllRenderingReadyCallbacks(
679 const MonitorAutoLock& aProofOfLock,
680 RemoteTextureMap::TextureOwner* aOwner) {
681 auto functions =
682 GetRenderingReadyCallbacks(aProofOfLock, aOwner, RemoteTextureId::Max());
683 MOZ_ASSERT(aOwner->mRenderingReadyCallbackHolders.empty());
685 return functions;
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()) {
695 return false;
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);
708 if (!owner) {
709 return false;
712 UpdateTexture(lock, owner, textureId);
714 if (owner->mLatestTextureHost &&
715 (owner->mLatestTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) {
716 // Remote texture allocation was failed.
717 return false;
720 bool syncMode = owner->mIsSyncMode || bool(aReadyCallback);
722 if (syncMode) {
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;
733 } else {
734 if (aReadyCallback) {
735 auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>(
736 textureId, std::move(aReadyCallback));
737 owner->mRenderingReadyCallbackHolders.push_back(
738 std::move(callbackHolder));
739 return true;
740 } else {
741 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
744 } else {
745 // remote texture async ipc
746 if (owner->mLatestTextureHost) {
747 if (owner->mLatestTextureHost->GetSize() == size) {
748 textureHost = owner->mLatestTextureHost;
749 } else {
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");
757 } else {
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;
769 } else {
770 MOZ_ASSERT(it->second->mAsyncRemoteTextureHost ==
771 owner->mLatestTextureHost);
776 if (textureHost) {
777 aTextureHostWrapper->SetRemoteTextureHostForDisplayList(lock, textureHost,
778 syncMode);
779 aTextureHostWrapper->ApplyTextureFlagsToRemoteTexture();
783 return false;
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");
796 return Nothing();
799 TextureHost* remoteTexture = it->second->mAsyncRemoteTextureHost;
801 auto* owner = GetTextureOwner(lock, aOwnerId, aForPid);
802 if (!owner) {
803 if (!remoteTexture) {
804 // This could happen with IPC abnormal shutdown
805 return Nothing();
807 return remoteTexture->GetMaybeExternalImageId();
810 if (remoteTexture &&
811 remoteTexture->GetFlags() & TextureFlags::DUMMY_TEXTURE) {
812 // Remote texture allocation was failed.
813 return Nothing();
815 MOZ_ASSERT(!(remoteTexture &&
816 remoteTexture->GetFlags() & TextureFlags::DUMMY_TEXTURE));
818 MOZ_ASSERT(owner);
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);
829 } else {
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) {
840 return Nothing();
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);
854 releasingTexture =
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,
874 aSize, aFlags);
875 auto wrapperHolder = MakeUnique<RemoteTextureHostWrapperHolder>(wrapper);
877 mRemoteTextureHostWrapperHolders.emplace(key, std::move(wrapperHolder));
879 return wrapper;
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");
896 return;
898 releasingTextures.emplace_back(it->second->mRemoteTextureHostWrapper);
899 if (it->second->mAsyncRemoteTextureHost) {
900 releasingTextures.emplace_back(it->second->mAsyncRemoteTextureHost);
903 mRemoteTextureHostWrapperHolders.erase(it);
904 mMonitor.Notify();
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);
928 if (!owner) {
929 return;
931 if (owner->mWaitingTextureDataHolders.empty() &&
932 !owner->mLatestTextureHost) {
933 return;
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()) {
965 return;
967 if (aListener != it->second) {
968 // aListener was alredy obsoleted.
969 return;
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.
986 return false;
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);
995 return true;
998 if (it->second->mAsyncRemoteTextureHost) {
999 return true;
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));
1013 return false;
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.
1024 return false;
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);
1033 return false;
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);
1045 return false;
1048 auto it = mRemoteTextureHostWrapperHolders.find(key);
1049 if (it == mRemoteTextureHostWrapperHolders.end()) {
1050 MOZ_ASSERT_UNREACHABLE("unexpected to be called");
1051 return false;
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
1060 return false;
1065 return true;
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");
1077 return;
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);
1092 if (!owner) {
1093 return nullptr;
1096 if (owner->mRecycledTextures.empty()) {
1097 return nullptr;
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();
1108 } else {
1109 // If size or format are different, release all textures.
1110 owner->mRecycledTextures.swap(releasingTextures);
1114 return texture;
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);
1124 if (!owner) {
1125 return nullptr;
1128 if (owner->mRecycledSharedTextures.empty()) {
1129 return nullptr;
1132 auto& front = owner->mRecycledSharedTextures.front();
1133 wrapper = std::move(front);
1134 owner->mRecycledSharedTextures.pop();
1136 return wrapper;
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()) {
1145 return nullptr;
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