RemoteTextureMap.cpp (50515B)
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/. */ 6 7 #include "mozilla/layers/RemoteTextureMap.h" 8 9 #include <algorithm> 10 #include <vector> 11 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/SharedTexture.h" 25 #include "mozilla/webrender/RenderThread.h" 26 #include "SharedSurface.h" 27 28 namespace mozilla::layers { 29 30 RemoteTextureRecycleBin::RemoteTextureRecycleBin(bool aIsShared) 31 : mIsShared(aIsShared) {} 32 33 RemoteTextureRecycleBin::~RemoteTextureRecycleBin() = default; 34 35 RemoteTextureOwnerClient::RemoteTextureOwnerClient( 36 const base::ProcessId aForPid) 37 : mForPid(aForPid) {} 38 39 RemoteTextureOwnerClient::~RemoteTextureOwnerClient() = default; 40 41 bool RemoteTextureOwnerClient::IsRegistered( 42 const RemoteTextureOwnerId aOwnerId) { 43 auto it = mOwnerIds.find(aOwnerId); 44 if (it == mOwnerIds.end()) { 45 return false; 46 } 47 return true; 48 } 49 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); 58 } 59 recycleBin = mSharedRecycleBin; 60 } 61 RemoteTextureMap::Get()->RegisterTextureOwner(aOwnerId, mForPid, recycleBin); 62 } 63 64 void RemoteTextureOwnerClient::UnregisterTextureOwner( 65 const RemoteTextureOwnerId aOwnerId) { 66 auto it = mOwnerIds.find(aOwnerId); 67 if (it == mOwnerIds.end()) { 68 return; 69 } 70 mOwnerIds.erase(it); 71 RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId, mForPid); 72 } 73 74 void RemoteTextureOwnerClient::UnregisterAllTextureOwners() { 75 if (mOwnerIds.empty()) { 76 return; 77 } 78 RemoteTextureMap::Get()->UnregisterTextureOwners(mOwnerIds, mForPid); 79 mOwnerIds.clear(); 80 mSharedRecycleBin = nullptr; 81 } 82 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; 89 } 90 return RemoteTextureMap::Get()->WaitForTxn(aOwnerId, mForPid, aTxnType, 91 aTxnId); 92 } 93 94 void RemoteTextureOwnerClient::ClearRecycledTextures() { 95 RemoteTextureMap::Get()->ClearRecycledTextures(mOwnerIds, mForPid, 96 mSharedRecycleBin); 97 } 98 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; 106 } 107 } 108 } else { 109 aOwnerIds = &mOwnerIds; 110 } 111 if (aOwnerIds->empty()) { 112 return; 113 } 114 RemoteTextureMap::Get()->NotifyContextLost(*aOwnerIds, mForPid); 115 } 116 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; 124 } 125 } 126 } else { 127 aOwnerIds = &mOwnerIds; 128 } 129 if (aOwnerIds->empty()) { 130 return; 131 } 132 RemoteTextureMap::Get()->NotifyContextRestored(*aOwnerIds, mForPid); 133 } 134 135 void RemoteTextureOwnerClient::PushTexture( 136 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, 137 UniquePtr<TextureData>&& aTextureData) { 138 MOZ_ASSERT(IsRegistered(aOwnerId)); 139 140 RefPtr<TextureHost> textureHost = RemoteTextureMap::CreateRemoteTexture( 141 aTextureData.get(), TextureFlags::DEFAULT); 142 if (!textureHost) { 143 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 144 return; 145 } 146 147 RemoteTextureMap::Get()->PushTexture(aTextureId, aOwnerId, mForPid, 148 std::move(aTextureData), textureHost, 149 /* aResourceWrapper */ nullptr); 150 } 151 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)); 158 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; 166 } 167 168 RemoteTextureMap::Get()->PushTexture( 169 aTextureId, aOwnerId, mForPid, std::move(textureData), textureHost, 170 SharedResourceWrapper::SharedSurface(aSharedSurface)); 171 } 172 173 void RemoteTextureOwnerClient::PushTexture( 174 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, 175 const std::shared_ptr<webgpu::SharedTexture>& aSharedTexture, 176 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, 177 const SurfaceDescriptor& aDesc) { 178 MOZ_ASSERT(IsRegistered(aOwnerId)); 179 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; 187 } 188 189 RemoteTextureMap::Get()->PushTexture( 190 aTextureId, aOwnerId, mForPid, std::move(textureData), textureHost, 191 SharedResourceWrapper::SharedTexture(aSharedTexture)); 192 } 193 194 void RemoteTextureOwnerClient::PushDummyTexture( 195 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId) { 196 MOZ_ASSERT(IsRegistered(aOwnerId)); 197 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; 206 } 207 208 auto textureData = UniquePtr<TextureData>(rawData); 209 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; 215 } 216 217 RemoteTextureMap::Get()->PushTexture(aTextureId, aOwnerId, mForPid, 218 std::move(textureData), textureHost, 219 /* aResourceWrapper */ nullptr); 220 } 221 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); 228 } 229 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); 235 } 236 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; 245 } 246 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); 252 } 253 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; 263 } 264 MOZ_ASSERT(wrapper->mSharedSurface); 265 return wrapper->mSharedSurface; 266 } 267 268 std::shared_ptr<webgpu::SharedTexture> 269 RemoteTextureOwnerClient::GetRecycledSharedTexture( 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; 277 } 278 MOZ_ASSERT(wrapper->mSharedTexture); 279 return wrapper->mSharedTexture; 280 } 281 282 StaticAutoPtr<RemoteTextureMap> RemoteTextureMap::sInstance; 283 284 /* static */ 285 void RemoteTextureMap::Init() { 286 MOZ_ASSERT(!sInstance); 287 sInstance = new RemoteTextureMap(); 288 } 289 290 /* static */ 291 void RemoteTextureMap::Shutdown() { 292 if (sInstance) { 293 sInstance = nullptr; 294 } 295 } 296 297 RemoteTextureMap::RemoteTextureMap() : mMonitor("RemoteTextureMap::mMonitor") {} 298 299 RemoteTextureMap::~RemoteTextureMap() = default; 300 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; 308 } 309 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; 318 } 319 aRecycleBin->mRecycledTextures.pop_front(); 320 } 321 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; 331 } 332 333 // Recycle shared texture 334 SurfaceDescriptor desc; 335 if (!aHolder.mTextureData->Serialize(desc)) { 336 return false; 337 } 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); 343 } 344 if (!StaticPrefs::gfx_remote_texture_recycle_disabled()) { 345 aRecycleBin->mRecycledTextures.push_back(std::move(recycled)); 346 } 347 348 return true; 349 } 350 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); 357 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 362 { 363 MonitorAutoLock lock(mMonitor); 364 365 auto* owner = GetTextureOwner(lock, aOwnerId, aForPid); 366 if (!owner) { 367 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 368 return; 369 } 370 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"; 375 } 376 377 auto textureData = MakeUnique<TextureDataHolder>( 378 aTextureId, aTextureHost, std::move(aTextureData), 379 std::move(aResourceWrapper)); 380 381 MOZ_ASSERT(owner->mLatestPushedTextureId < aTextureId); 382 if (owner->mLatestPushedTextureId < aTextureId) { 383 owner->mLatestPushedTextureId = aTextureId; 384 } 385 MOZ_ASSERT(owner->mLatestUsingTextureId < aTextureId); 386 387 owner->mWaitingTextureDataHolders.push_back(std::move(textureData)); 388 389 { 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; 400 } 401 } 402 403 mMonitor.Notify(); 404 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(); 414 } 415 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; 430 } 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(); 444 } 445 } 446 while (!owner->mReleasingTextureDataHolders.empty()) { 447 RecycleTexture(owner->mRecycleBin, 448 *owner->mReleasingTextureDataHolders.front(), true); 449 owner->mReleasingTextureDataHolders.pop_front(); 450 } 451 } 452 453 const auto info = RemoteTextureInfo(aTextureId, aOwnerId, aForPid); 454 for (auto& callback : renderingReadyCallbacks) { 455 callback(info); 456 } 457 } 458 459 bool RemoteTextureMap::RemoveTexture(const RemoteTextureId aTextureId, 460 const RemoteTextureOwnerId aOwnerId, 461 const base::ProcessId aForPid) { 462 MonitorAutoLock lock(mMonitor); 463 464 auto* owner = GetTextureOwner(lock, aOwnerId, aForPid); 465 if (!owner) { 466 return false; 467 } 468 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; 476 } 477 if (!RecycleTexture(owner->mRecycleBin, *data, false)) { 478 owner->mReleasingTextureDataHolders.push_back(std::move(data)); 479 } 480 owner->mWaitingTextureDataHolders.erase(it); 481 return true; 482 } 483 } 484 485 return false; 486 } 487 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::SharedTexture> sharedTexture; 495 { 496 MonitorAutoLock lock(mMonitor); 497 498 auto* owner = GetTextureOwner(lock, aOwnerId, aForPid); 499 if (!owner) { 500 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 501 return; 502 } 503 504 // Get latest TextureHost of remote Texture. 505 if (owner->mWaitingTextureDataHolders.empty() && 506 owner->mUsingTextureDataHolders.empty()) { 507 return; 508 } 509 const auto* holder = !owner->mWaitingTextureDataHolders.empty() 510 ? owner->mWaitingTextureDataHolders.back().get() 511 : owner->mUsingTextureDataHolders.back().get(); 512 TextureHost* textureHost = holder->mTextureHost; 513 514 if (textureHost->GetSize() != aSize) { 515 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 516 return; 517 } 518 if (textureHost->GetFormat() != gfx::SurfaceFormat::R8G8B8A8 && 519 textureHost->GetFormat() != gfx::SurfaceFormat::B8G8R8A8) { 520 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 521 return; 522 } 523 if (holder->mResourceWrapper && holder->mResourceWrapper->mSharedTexture) { 524 // Increment compositable ref to prevent that TextureDataHolder is removed 525 // during memcpy. 526 textureHostRef = textureHost; 527 sharedTexture = holder->mResourceWrapper->mSharedTexture; 528 } else if (textureHost->AsBufferTextureHost()) { 529 // Increment compositable ref to prevent that TextureDataHolder is removed 530 // during memcpy. 531 textureHostRef = textureHost; 532 } else { 533 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 534 return; 535 } 536 } 537 538 if (!textureHostRef) { 539 return; 540 } 541 542 if (sharedTexture) { 543 sharedTexture->GetSnapshot(aDestShmem, aSize); 544 } else if (auto* bufferTextureHost = textureHostRef->AsBufferTextureHost()) { 545 uint32_t stride = ImageDataSerializer::ComputeRGBStride( 546 bufferTextureHost->GetFormat(), aSize.width); 547 uint32_t bufferSize = stride * aSize.height; 548 uint8_t* dst = aDestShmem.get<uint8_t>(); 549 uint8_t* src = bufferTextureHost->GetBuffer(); 550 551 MOZ_ASSERT(bufferSize <= aDestShmem.Size<uint8_t>()); 552 memcpy(dst, src, bufferSize); 553 } 554 555 { 556 MonitorAutoLock lock(mMonitor); 557 // Release compositable ref in mMonitor lock, but release RefPtr outside the 558 // monitor 559 releasingTexture = textureHostRef; 560 textureHostRef = nullptr; 561 } 562 } 563 564 void RemoteTextureMap::RegisterTextureOwner( 565 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, 566 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin) { 567 MonitorAutoLock lock(mMonitor); 568 569 const auto key = std::pair(aForPid, aOwnerId); 570 auto it = mTextureOwners.find(key); 571 if (it != mTextureOwners.end()) { 572 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 573 return; 574 } 575 auto owner = MakeUnique<TextureOwner>(); 576 if (aRecycleBin) { 577 owner->mRecycleBin = aRecycleBin; 578 } else { 579 owner->mRecycleBin = new RemoteTextureRecycleBin(false); 580 } 581 582 auto itWaiting = mWaitingTextureOwners.find(key); 583 if (itWaiting != mWaitingTextureOwners.end()) { 584 owner->mRenderingReadyCallbackHolders.swap( 585 itWaiting->second->mRenderingReadyCallbackHolders); 586 mWaitingTextureOwners.erase(itWaiting); 587 } 588 589 mTextureOwners.emplace(key, std::move(owner)); 590 } 591 592 void RemoteTextureMap::KeepTextureDataAliveForTextureHostIfNecessary( 593 const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, 594 std::deque<UniquePtr<TextureDataHolder>>& aHolders) { 595 for (auto& holder : aHolders) { 596 // If remote texture of TextureHost still exist, keep 597 // SharedResourceWrapper/TextureData alive while the TextureHost is alive. 598 if (holder->mTextureHost && 599 holder->mTextureHost->NumCompositableRefs() > 0) { 600 RefPtr<nsISerialEventTarget> eventTarget = GetCurrentSerialEventTarget(); 601 RefPtr<Runnable> runnable = NS_NewRunnableFunction( 602 "RemoteTextureMap::UnregisterTextureOwner::Runnable", 603 [data = std::move(holder->mTextureData), 604 wrapper = std::move(holder->mResourceWrapper)]() {}); 605 606 auto destroyedCallback = [eventTarget = std::move(eventTarget), 607 runnable = std::move(runnable)]() mutable { 608 eventTarget->Dispatch(runnable.forget()); 609 }; 610 611 holder->mTextureHost->SetDestroyedCallback(destroyedCallback); 612 } else { 613 RecycleTexture(aOwner->mRecycleBin, *holder, true); 614 } 615 } 616 } 617 618 UniquePtr<RemoteTextureMap::TextureOwner> 619 RemoteTextureMap::UnregisterTextureOwner( 620 MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, 621 const base::ProcessId aForPid, 622 std::vector<RefPtr<TextureHost>>& aReleasingTextures, 623 std::vector<std::function<void(const RemoteTextureInfo&)>>& 624 aRenderingReadyCallbacks) { 625 const auto key = std::pair(aForPid, aOwnerId); 626 auto it = mTextureOwners.find(key); 627 if (it == mTextureOwners.end()) { 628 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 629 return nullptr; 630 } 631 632 auto* owner = it->second.get(); 633 // If waiting for a last use, and it hasn't arrived yet, then defer 634 // unregistering. 635 if (owner->mWaitForTxn) { 636 owner->mDeferUnregister = GetCurrentSerialEventTarget(); 637 // If another thread is waiting on this owner to produce textures, 638 // it must be notified that owner is going away. 639 if (!owner->mLatestTextureHost && 640 owner->mWaitingTextureDataHolders.empty()) { 641 aProofOfLock.Notify(); 642 } 643 return nullptr; 644 } 645 646 if (owner->mLatestTextureHost) { 647 // Release CompositableRef in mMonitor 648 aReleasingTextures.emplace_back(owner->mLatestTextureHost); 649 owner->mLatestTextureHost = nullptr; 650 } 651 652 // mReleasingRenderedTextureHosts and mLatestRenderedTextureHost could 653 // simply be cleared. Since NumCompositableRefs() > 0 keeps TextureHosts in 654 // mUsingTextureDataHolders alive. They need to be cleared before 655 // KeepTextureDataAliveForTextureHostIfNecessary() call. The function uses 656 // NumCompositableRefs(). 657 if (!owner->mReleasingRenderedTextureHosts.empty()) { 658 std::transform(owner->mReleasingRenderedTextureHosts.begin(), 659 owner->mReleasingRenderedTextureHosts.end(), 660 std::back_inserter(aReleasingTextures), 661 [](CompositableTextureHostRef& aRef) { return aRef.get(); }); 662 owner->mReleasingRenderedTextureHosts.clear(); 663 } 664 if (owner->mLatestRenderedTextureHost) { 665 owner->mLatestRenderedTextureHost = nullptr; 666 } 667 668 GetAllRenderingReadyCallbacks(aProofOfLock, owner, aRenderingReadyCallbacks); 669 670 KeepTextureDataAliveForTextureHostIfNecessary( 671 aProofOfLock, owner, owner->mWaitingTextureDataHolders); 672 673 KeepTextureDataAliveForTextureHostIfNecessary( 674 aProofOfLock, owner, owner->mUsingTextureDataHolders); 675 676 KeepTextureDataAliveForTextureHostIfNecessary( 677 aProofOfLock, owner, owner->mReleasingTextureDataHolders); 678 679 UniquePtr<TextureOwner> releasingOwner = std::move(it->second); 680 mTextureOwners.erase(it); 681 return releasingOwner; 682 } 683 684 void RemoteTextureMap::UnregisterTextureOwner( 685 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid) { 686 UniquePtr<TextureOwner> releasingOwner; // Release outside the monitor 687 std::vector<RefPtr<TextureHost>> 688 releasingTextures; // Release outside the monitor 689 std::vector<std::function<void(const RemoteTextureInfo&)>> 690 renderingReadyCallbacks; // Call outside the monitor 691 { 692 MonitorAutoLock lock(mMonitor); 693 694 releasingOwner = UnregisterTextureOwner( 695 lock, aOwnerId, aForPid, releasingTextures, renderingReadyCallbacks); 696 if (!releasingOwner) { 697 return; 698 } 699 700 mMonitor.Notify(); 701 } 702 703 const auto info = 704 RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0); 705 for (auto& callback : renderingReadyCallbacks) { 706 callback(info); 707 } 708 } 709 710 void RemoteTextureMap::UnregisterTextureOwners( 711 const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) { 712 std::vector<UniquePtr<TextureOwner>> 713 releasingOwners; // Release outside the monitor 714 std::vector<RefPtr<TextureHost>> 715 releasingTextures; // Release outside the monitor 716 std::vector<std::function<void(const RemoteTextureInfo&)>> 717 renderingReadyCallbacks; // Call outside the monitor 718 { 719 MonitorAutoLock lock(mMonitor); 720 721 for (const auto& id : aOwnerIds) { 722 if (auto releasingOwner = UnregisterTextureOwner( 723 lock, id, aForPid, releasingTextures, renderingReadyCallbacks)) { 724 releasingOwners.push_back(std::move(releasingOwner)); 725 } 726 } 727 728 if (releasingOwners.empty()) { 729 return; 730 } 731 732 mMonitor.Notify(); 733 } 734 735 const auto info = 736 RemoteTextureInfo(RemoteTextureId{0}, RemoteTextureOwnerId{0}, 0); 737 for (auto& callback : renderingReadyCallbacks) { 738 callback(info); 739 } 740 } 741 742 already_AddRefed<RemoteTextureTxnScheduler> 743 RemoteTextureMap::RegisterTxnScheduler(base::ProcessId aForPid, 744 RemoteTextureTxnType aType) { 745 MonitorAutoLock lock(mMonitor); 746 747 const auto key = std::pair(aForPid, aType); 748 auto it = mTxnSchedulers.find(key); 749 if (it != mTxnSchedulers.end()) { 750 return do_AddRef(it->second); 751 } 752 753 RefPtr<RemoteTextureTxnScheduler> scheduler( 754 new RemoteTextureTxnScheduler(aForPid, aType)); 755 mTxnSchedulers.emplace(key, scheduler.get()); 756 return scheduler.forget(); 757 } 758 759 void RemoteTextureMap::UnregisterTxnScheduler(base::ProcessId aForPid, 760 RemoteTextureTxnType aType) { 761 MonitorAutoLock lock(mMonitor); 762 763 const auto key = std::pair(aForPid, aType); 764 auto it = mTxnSchedulers.find(key); 765 if (it == mTxnSchedulers.end()) { 766 MOZ_ASSERT_UNREACHABLE("Remote texture txn scheduler does not exist."); 767 return; 768 } 769 mTxnSchedulers.erase(it); 770 } 771 772 already_AddRefed<RemoteTextureTxnScheduler> RemoteTextureTxnScheduler::Create( 773 mozilla::ipc::IProtocol* aProtocol) { 774 if (auto* instance = RemoteTextureMap::Get()) { 775 if (auto* toplevel = aProtocol->ToplevelProtocol()) { 776 auto pid = toplevel->OtherPidMaybeInvalid(); 777 if (pid != base::kInvalidProcessId) { 778 return instance->RegisterTxnScheduler(pid, toplevel->GetProtocolId()); 779 } 780 } 781 } 782 return nullptr; 783 } 784 785 RemoteTextureTxnScheduler::~RemoteTextureTxnScheduler() { 786 NotifyTxn(std::numeric_limits<RemoteTextureTxnId>::max()); 787 RemoteTextureMap::Get()->UnregisterTxnScheduler(mForPid, mType); 788 } 789 790 void RemoteTextureTxnScheduler::NotifyTxn(RemoteTextureTxnId aTxnId) { 791 MonitorAutoLock lock(RemoteTextureMap::Get()->mMonitor); 792 793 mLastTxnId = aTxnId; 794 795 for (; !mWaits.empty(); mWaits.pop_front()) { 796 auto& wait = mWaits.front(); 797 if (wait.mTxnId > aTxnId) { 798 break; 799 } 800 RemoteTextureMap::Get()->NotifyTxn(lock, wait.mOwnerId, mForPid); 801 } 802 } 803 804 bool RemoteTextureTxnScheduler::WaitForTxn(const MonitorAutoLock& aProofOfLock, 805 RemoteTextureOwnerId aOwnerId, 806 RemoteTextureTxnId aTxnId) { 807 if (aTxnId <= mLastTxnId) { 808 return false; 809 } 810 mWaits.insert(std::upper_bound(mWaits.begin(), mWaits.end(), aTxnId), 811 Wait{aOwnerId, aTxnId}); 812 return true; 813 } 814 815 void RemoteTextureMap::ClearRecycledTextures( 816 const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid, 817 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin) { 818 std::list<RemoteTextureRecycleBin::RecycledTextureHolder> 819 releasingTextures; // Release outside the monitor 820 { 821 MonitorAutoLock lock(mMonitor); 822 823 if (aRecycleBin) { 824 releasingTextures.splice(releasingTextures.end(), 825 aRecycleBin->mRecycledTextures); 826 } 827 828 for (const auto& id : aOwnerIds) { 829 const auto key = std::pair(aForPid, id); 830 auto it = mTextureOwners.find(key); 831 if (it == mTextureOwners.end()) { 832 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 833 continue; 834 } 835 auto& owner = it->second; 836 837 releasingTextures.splice(releasingTextures.end(), 838 owner->mRecycleBin->mRecycledTextures); 839 } 840 } 841 } 842 843 void RemoteTextureMap::NotifyContextLost( 844 const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) { 845 MonitorAutoLock lock(mMonitor); 846 847 bool changed = false; 848 for (const auto& id : aOwnerIds) { 849 const auto key = std::pair(aForPid, id); 850 auto it = mTextureOwners.find(key); 851 if (it == mTextureOwners.end()) { 852 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 853 continue; 854 } 855 auto& owner = it->second; 856 if (!owner->mIsContextLost) { 857 owner->mIsContextLost = true; 858 changed = true; 859 } 860 } 861 862 if (changed) { 863 mMonitor.Notify(); 864 } 865 } 866 867 void RemoteTextureMap::NotifyContextRestored( 868 const RemoteTextureOwnerIdSet& aOwnerIds, const base::ProcessId aForPid) { 869 MonitorAutoLock lock(mMonitor); 870 871 bool changed = false; 872 for (const auto& id : aOwnerIds) { 873 const auto key = std::pair(aForPid, id); 874 auto it = mTextureOwners.find(key); 875 if (it == mTextureOwners.end()) { 876 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 877 continue; 878 } 879 auto& owner = it->second; 880 if (owner->mIsContextLost) { 881 owner->mIsContextLost = false; 882 changed = true; 883 } 884 } 885 886 if (changed) { 887 mMonitor.Notify(); 888 } 889 } 890 891 /* static */ 892 RefPtr<TextureHost> RemoteTextureMap::CreateRemoteTexture( 893 TextureData* aTextureData, TextureFlags aTextureFlags) { 894 SurfaceDescriptor desc; 895 DebugOnly<bool> ret = aTextureData->Serialize(desc); 896 MOZ_ASSERT(ret); 897 TextureFlags flags = aTextureFlags | TextureFlags::REMOTE_TEXTURE | 898 TextureFlags::DEALLOCATE_CLIENT; 899 900 Maybe<wr::ExternalImageId> externalImageId = Nothing(); 901 RefPtr<TextureHost> textureHost = 902 TextureHost::Create(desc, null_t(), nullptr, LayersBackend::LAYERS_WR, 903 flags, externalImageId); 904 MOZ_ASSERT(textureHost); 905 if (!textureHost) { 906 gfxCriticalNoteOnce << "Failed to create remote texture"; 907 return nullptr; 908 } 909 910 textureHost->EnsureRenderTexture(Nothing()); 911 912 return textureHost; 913 } 914 915 void RemoteTextureMap::UpdateTexture(const MonitorAutoLock& aProofOfLock, 916 RemoteTextureMap::TextureOwner* aOwner, 917 const RemoteTextureId aTextureId) { 918 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 919 MOZ_ASSERT(aOwner); 920 MOZ_ASSERT(aTextureId >= aOwner->mLatestUsingTextureId); 921 922 if (aTextureId == aOwner->mLatestUsingTextureId) { 923 // No need to update texture. 924 return; 925 } 926 927 // Move remote textures to mUsingTextureDataHolders. 928 while (!aOwner->mWaitingTextureDataHolders.empty()) { 929 auto& front = aOwner->mWaitingTextureDataHolders.front(); 930 if (aTextureId < front->mTextureId) { 931 break; 932 } 933 MOZ_RELEASE_ASSERT(front->mTextureHost); 934 aOwner->mLatestTextureHost = front->mTextureHost; 935 aOwner->mLatestUsingTextureId = front->mTextureId; 936 937 UniquePtr<TextureDataHolder> holder = std::move(front); 938 aOwner->mWaitingTextureDataHolders.pop_front(); 939 // If there are textures not being used by the compositor that will be 940 // obsoleted by this new texture, then queue them for removal later on 941 // the creating thread. 942 while (!aOwner->mUsingTextureDataHolders.empty()) { 943 auto& back = aOwner->mUsingTextureDataHolders.back(); 944 if (back->mTextureHost && 945 back->mTextureHost->NumCompositableRefs() == 0) { 946 if (!RecycleTexture(aOwner->mRecycleBin, *back, false)) { 947 aOwner->mReleasingTextureDataHolders.push_back(std::move(back)); 948 } 949 aOwner->mUsingTextureDataHolders.pop_back(); 950 continue; 951 } 952 break; 953 } 954 aOwner->mUsingTextureDataHolders.push_back(std::move(holder)); 955 } 956 } 957 958 void RemoteTextureMap::GetRenderingReadyCallbacks( 959 const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, 960 const RemoteTextureId aTextureId, 961 std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions) { 962 MOZ_ASSERT(aOwner); 963 964 while (!aOwner->mRenderingReadyCallbackHolders.empty()) { 965 auto& front = aOwner->mRenderingReadyCallbackHolders.front(); 966 if (aTextureId < front->mTextureId) { 967 break; 968 } 969 if (front->mCallback) { 970 aFunctions.push_back(std::move(front->mCallback)); 971 } 972 aOwner->mRenderingReadyCallbackHolders.pop_front(); 973 } 974 } 975 976 void RemoteTextureMap::GetAllRenderingReadyCallbacks( 977 const MonitorAutoLock& aProofOfLock, RemoteTextureMap::TextureOwner* aOwner, 978 std::vector<std::function<void(const RemoteTextureInfo&)>>& aFunctions) { 979 GetRenderingReadyCallbacks(aProofOfLock, aOwner, RemoteTextureId::Max(), 980 aFunctions); 981 MOZ_ASSERT(aOwner->mRenderingReadyCallbackHolders.empty()); 982 } 983 984 bool RemoteTextureMap::WaitForRemoteTextureOwner( 985 RemoteTextureHostWrapper* aTextureHostWrapper) { 986 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 987 MOZ_ASSERT(aTextureHostWrapper); 988 989 const auto& ownerId = aTextureHostWrapper->mOwnerId; 990 const auto& forPid = aTextureHostWrapper->mForPid; 991 992 MonitorAutoLock lock(mMonitor); 993 994 auto* owner = GetTextureOwner(lock, ownerId, forPid); 995 // If there is no texture owner yet, then we might need to wait for one to 996 // be created, if allowed. If so, we must also wait for an initial texture 997 // host to be created so we can use it. 998 if (!owner || (!owner->mLatestTextureHost && 999 owner->mWaitingTextureDataHolders.empty())) { 1000 const TimeDuration timeout = TimeDuration::FromMilliseconds(10000); 1001 while (!owner || (!owner->mLatestTextureHost && 1002 owner->mWaitingTextureDataHolders.empty())) { 1003 if (owner && (owner->mIsContextLost || owner->mDeferUnregister)) { 1004 // If the context was lost, no further updates are expected. 1005 return false; 1006 } 1007 CVStatus status = mMonitor.Wait(timeout); 1008 if (status == CVStatus::Timeout) { 1009 return false; 1010 } 1011 owner = GetTextureOwner(lock, ownerId, forPid); 1012 } 1013 } 1014 return true; 1015 } 1016 1017 void RemoteTextureMap::GetRemoteTexture( 1018 RemoteTextureHostWrapper* aTextureHostWrapper) { 1019 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1020 MOZ_ASSERT(aTextureHostWrapper); 1021 1022 if (aTextureHostWrapper->IsReadyForRendering()) { 1023 return; 1024 } 1025 1026 const auto& textureId = aTextureHostWrapper->mTextureId; 1027 const auto& ownerId = aTextureHostWrapper->mOwnerId; 1028 const auto& forPid = aTextureHostWrapper->mForPid; 1029 const auto& size = aTextureHostWrapper->mSize; 1030 1031 RefPtr<TextureHost> textureHost; 1032 { 1033 MonitorAutoLock lock(mMonitor); 1034 1035 auto* owner = GetTextureOwner(lock, ownerId, forPid); 1036 if (!owner) { 1037 return; 1038 } 1039 1040 UpdateTexture(lock, owner, textureId); 1041 1042 if (owner->mLatestTextureHost && 1043 (owner->mLatestTextureHost->GetFlags() & TextureFlags::DUMMY_TEXTURE)) { 1044 // Remote texture allocation was failed. 1045 return; 1046 } 1047 1048 if (textureId == owner->mLatestUsingTextureId) { 1049 MOZ_ASSERT(owner->mLatestTextureHost); 1050 MOZ_ASSERT(owner->mLatestTextureHost->GetSize() == size); 1051 if (owner->mLatestTextureHost->GetSize() != size) { 1052 gfxCriticalNoteOnce << "unexpected remote texture size: " 1053 << owner->mLatestTextureHost->GetSize() 1054 << " expected: " << size; 1055 } 1056 textureHost = owner->mLatestTextureHost; 1057 } 1058 1059 // Update mRemoteTextureHost 1060 if (textureId == owner->mLatestUsingTextureId) { 1061 const auto key = std::pair(forPid, textureId); 1062 auto it = mRemoteTextureHostWrapperHolders.find(key); 1063 if (it != mRemoteTextureHostWrapperHolders.end() && 1064 !it->second->mRemoteTextureHost) { 1065 it->second->mRemoteTextureHost = owner->mLatestTextureHost; 1066 } else { 1067 MOZ_ASSERT(it->second->mRemoteTextureHost == owner->mLatestTextureHost); 1068 } 1069 } 1070 1071 if (textureHost) { 1072 aTextureHostWrapper->SetRemoteTextureHost(lock, textureHost); 1073 aTextureHostWrapper->ApplyTextureFlagsToRemoteTexture(); 1074 } 1075 } 1076 } 1077 1078 void RemoteTextureMap::NotifyTxn(const MonitorAutoLock& aProofOfLock, 1079 const RemoteTextureOwnerId aOwnerId, 1080 const base::ProcessId aForPid) { 1081 if (auto* owner = GetTextureOwner(aProofOfLock, aOwnerId, aForPid)) { 1082 if (!owner->mWaitForTxn) { 1083 MOZ_ASSERT_UNREACHABLE("Expected texture owner to wait for txn."); 1084 return; 1085 } 1086 owner->mWaitForTxn = false; 1087 if (!owner->mDeferUnregister) { 1088 // If unregistering was not deferred, then don't try to force 1089 // unregistering yet. 1090 return; 1091 } 1092 owner->mDeferUnregister->Dispatch(NS_NewRunnableFunction( 1093 "RemoteTextureMap::SetLastRemoteTextureUse::Runnable", 1094 [aOwnerId, aForPid]() { 1095 RemoteTextureMap::Get()->UnregisterTextureOwner(aOwnerId, aForPid); 1096 })); 1097 } 1098 } 1099 1100 bool RemoteTextureMap::WaitForTxn(const RemoteTextureOwnerId aOwnerId, 1101 const base::ProcessId aForPid, 1102 RemoteTextureTxnType aTxnType, 1103 RemoteTextureTxnId aTxnId) { 1104 MonitorAutoLock lock(mMonitor); 1105 if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) { 1106 if (owner->mDeferUnregister) { 1107 MOZ_ASSERT_UNREACHABLE( 1108 "Texture owner must wait for txn before unregistering."); 1109 return false; 1110 } 1111 if (owner->mWaitForTxn) { 1112 MOZ_ASSERT_UNREACHABLE("Texture owner already waiting for txn."); 1113 return false; 1114 } 1115 const auto key = std::pair(aForPid, aTxnType); 1116 auto it = mTxnSchedulers.find(key); 1117 if (it == mTxnSchedulers.end()) { 1118 // During shutdown, different toplevel protocols may go away in 1119 // disadvantageous orders, causing us to sometimes be processing 1120 // waits even though the source of transactions upon which the 1121 // wait depends shut down. This is generally harmless to ignore, 1122 // as it means no further transactions will be generated of that 1123 // type and all such transactions have been processed before it 1124 // unregistered. 1125 NS_WARNING("Could not find scheduler for txn type."); 1126 return false; 1127 } 1128 if (it->second->WaitForTxn(lock, aOwnerId, aTxnId)) { 1129 owner->mWaitForTxn = true; 1130 } 1131 return true; 1132 } 1133 return false; 1134 } 1135 1136 void RemoteTextureMap::ReleaseRemoteTextureHost( 1137 RemoteTextureHostWrapper* aTextureHostWrapper) { 1138 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1139 MOZ_ASSERT(aTextureHostWrapper); 1140 1141 RefPtr<TextureHost> releasingTexture; // Release outside the mutex 1142 { 1143 MonitorAutoLock lock(mMonitor); 1144 releasingTexture = aTextureHostWrapper->GetRemoteTextureHost(lock); 1145 aTextureHostWrapper->ClearRemoteTextureHost(lock); 1146 } 1147 } 1148 1149 RefPtr<TextureHost> RemoteTextureMap::GetOrCreateRemoteTextureHostWrapper( 1150 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, 1151 const base::ProcessId aForPid, const gfx::IntSize& aSize, 1152 const TextureFlags aFlags) { 1153 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1154 MonitorAutoLock lock(mMonitor); 1155 1156 const auto key = std::pair(aForPid, aTextureId); 1157 auto it = mRemoteTextureHostWrapperHolders.find(key); 1158 if (it != mRemoteTextureHostWrapperHolders.end()) { 1159 return it->second->mRemoteTextureHostWrapper; 1160 } 1161 1162 auto wrapper = RemoteTextureHostWrapper::Create(aTextureId, aOwnerId, aForPid, 1163 aSize, aFlags); 1164 auto wrapperHolder = MakeUnique<RemoteTextureHostWrapperHolder>(wrapper); 1165 1166 mRemoteTextureHostWrapperHolders.emplace(key, std::move(wrapperHolder)); 1167 1168 return wrapper; 1169 } 1170 1171 void RemoteTextureMap::UnregisterRemoteTextureHostWrapper( 1172 const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId, 1173 const base::ProcessId aForPid) { 1174 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1175 1176 std::vector<RefPtr<TextureHost>> 1177 releasingTextures; // Release outside the monitor 1178 { 1179 MonitorAutoLock lock(mMonitor); 1180 1181 const auto key = std::pair(aForPid, aTextureId); 1182 auto it = mRemoteTextureHostWrapperHolders.find(key); 1183 if (it == mRemoteTextureHostWrapperHolders.end()) { 1184 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1185 return; 1186 } 1187 releasingTextures.emplace_back(it->second->mRemoteTextureHostWrapper); 1188 if (it->second->mRemoteTextureHost) { 1189 releasingTextures.emplace_back(it->second->mRemoteTextureHost); 1190 } 1191 1192 mRemoteTextureHostWrapperHolders.erase(it); 1193 mMonitor.Notify(); 1194 } 1195 } 1196 1197 bool RemoteTextureMap::CheckRemoteTextureReady( 1198 const RemoteTextureInfo& aInfo, 1199 std::function<void(const RemoteTextureInfo&)>&& aCallback) { 1200 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1201 1202 MonitorAutoLock lock(mMonitor); 1203 1204 auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); 1205 if (aInfo.mWaitForRemoteTextureOwner && !owner) { 1206 // Remote texture owner is not registered yet. Waiting for remote texture 1207 // owner 1208 1209 const auto key = std::pair(aInfo.mForPid, aInfo.mOwnerId); 1210 if (!mWaitingTextureOwners[key]) { 1211 auto waitingOwner = MakeUnique<WaitingTextureOwner>(); 1212 mWaitingTextureOwners[key] = std::move(waitingOwner); 1213 } 1214 1215 MOZ_ASSERT(mWaitingTextureOwners[key]); 1216 1217 WaitingTextureOwner* waitingOwner = mWaitingTextureOwners[key].get(); 1218 1219 auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>( 1220 aInfo.mTextureId, std::move(aCallback)); 1221 waitingOwner->mRenderingReadyCallbackHolders.push_back( 1222 std::move(callbackHolder)); 1223 1224 return false; 1225 } 1226 1227 if (!owner || owner->mIsContextLost) { 1228 // Owner is already removed or context lost. No need to wait texture ready. 1229 return true; 1230 } 1231 1232 const auto key = std::pair(aInfo.mForPid, aInfo.mTextureId); 1233 auto it = mRemoteTextureHostWrapperHolders.find(key); 1234 if (it == mRemoteTextureHostWrapperHolders.end()) { 1235 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1236 gfxCriticalNoteOnce << "Remote texture does not exist id:" 1237 << uint64_t(aInfo.mTextureId); 1238 return true; 1239 } 1240 1241 if (owner->mLatestPushedTextureId >= aInfo.mTextureId) { 1242 return true; 1243 } 1244 1245 auto callbackHolder = MakeUnique<RenderingReadyCallbackHolder>( 1246 aInfo.mTextureId, std::move(aCallback)); 1247 owner->mRenderingReadyCallbackHolders.push_back(std::move(callbackHolder)); 1248 1249 return false; 1250 } 1251 1252 bool RemoteTextureMap::WaitRemoteTextureReady(const RemoteTextureInfo& aInfo) { 1253 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1254 1255 MonitorAutoLock lock(mMonitor); 1256 1257 auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); 1258 if (aInfo.mWaitForRemoteTextureOwner && 1259 (!owner || (!owner->mLatestTextureHost && 1260 owner->mWaitingTextureDataHolders.empty()))) { 1261 const TimeDuration timeout = TimeDuration::FromMilliseconds(10000); 1262 while (!owner || (!owner->mLatestTextureHost && 1263 owner->mWaitingTextureDataHolders.empty())) { 1264 if (owner && (owner->mIsContextLost || owner->mDeferUnregister)) { 1265 // If the context was lost, no further updates are expected. 1266 return false; 1267 } 1268 CVStatus status = mMonitor.Wait(timeout); 1269 if (status == CVStatus::Timeout) { 1270 return false; 1271 } 1272 owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); 1273 } 1274 } 1275 1276 if (!owner || owner->mIsContextLost) { 1277 // Owner is already removed or context lost. 1278 return false; 1279 } 1280 1281 const auto key = std::pair(aInfo.mForPid, aInfo.mTextureId); 1282 auto it = mRemoteTextureHostWrapperHolders.find(key); 1283 if (it == mRemoteTextureHostWrapperHolders.end()) { 1284 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1285 gfxCriticalNoteOnce << "Remote texture does not exist id:" 1286 << uint64_t(aInfo.mTextureId); 1287 return false; 1288 } 1289 1290 const TimeDuration timeout = TimeDuration::FromMilliseconds(1000); 1291 1292 while (owner->mLatestPushedTextureId < aInfo.mTextureId) { 1293 CVStatus status = mMonitor.Wait(timeout); 1294 if (status == CVStatus::Timeout) { 1295 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1296 gfxCriticalNoteOnce << "Remote texture wait time out id:" 1297 << uint64_t(aInfo.mTextureId); 1298 return false; 1299 } 1300 1301 auto it = mRemoteTextureHostWrapperHolders.find(key); 1302 if (it == mRemoteTextureHostWrapperHolders.end()) { 1303 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1304 return false; 1305 } 1306 1307 auto* owner = GetTextureOwner(lock, aInfo.mOwnerId, aInfo.mForPid); 1308 // When owner is alreay unregistered, remote texture will not be pushed. 1309 if (!owner || owner->mIsContextLost) { 1310 // This could happen with IPC abnormal shutdown 1311 return false; 1312 } 1313 } 1314 1315 return true; 1316 } 1317 1318 void RemoteTextureMap::SuppressRemoteTextureReadyCheck( 1319 const RemoteTextureInfo& aInfo) { 1320 MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); 1321 MonitorAutoLock lock(mMonitor); 1322 1323 // Clear if WaitingTextureOwner exists. 1324 auto itWaiting = 1325 mWaitingTextureOwners.find(std::pair(aInfo.mForPid, aInfo.mOwnerId)); 1326 if (itWaiting != mWaitingTextureOwners.end()) { 1327 mWaitingTextureOwners.erase(itWaiting); 1328 } 1329 1330 const auto key = std::pair(aInfo.mForPid, aInfo.mTextureId); 1331 auto it = mRemoteTextureHostWrapperHolders.find(key); 1332 if (it == mRemoteTextureHostWrapperHolders.end()) { 1333 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1334 return; 1335 } 1336 it->second->mReadyCheckSuppressed = true; 1337 } 1338 1339 UniquePtr<TextureData> RemoteTextureMap::GetRecycledTextureData( 1340 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, 1341 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin, 1342 const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, 1343 TextureType aTextureType) { 1344 MonitorAutoLock lock(mMonitor); 1345 1346 RefPtr<RemoteTextureRecycleBin> bin; 1347 if (aOwnerId.IsValid()) { 1348 if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) { 1349 bin = owner->mRecycleBin; 1350 } 1351 } else { 1352 bin = aRecycleBin; 1353 } 1354 if (!bin) { 1355 return nullptr; 1356 } 1357 1358 for (auto it = bin->mRecycledTextures.begin(); 1359 it != bin->mRecycledTextures.end(); it++) { 1360 auto& holder = *it; 1361 if (holder.mTextureData && 1362 holder.mTextureData->GetTextureType() == aTextureType && 1363 holder.mSize == aSize && holder.mFormat == aFormat) { 1364 UniquePtr<TextureData> texture = std::move(holder.mTextureData); 1365 bin->mRecycledTextures.erase(it); 1366 return texture; 1367 } 1368 } 1369 1370 return nullptr; 1371 } 1372 1373 UniquePtr<SharedResourceWrapper> RemoteTextureMap::GetRecycledSharedTexture( 1374 const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid, 1375 const RefPtr<RemoteTextureRecycleBin>& aRecycleBin, 1376 const gfx::IntSize& aSize, const gfx::SurfaceFormat aFormat, 1377 SurfaceDescriptor::Type aType) { 1378 MonitorAutoLock lock(mMonitor); 1379 1380 RefPtr<RemoteTextureRecycleBin> bin; 1381 if (aOwnerId.IsValid()) { 1382 if (auto* owner = GetTextureOwner(lock, aOwnerId, aForPid)) { 1383 bin = owner->mRecycleBin; 1384 } 1385 } else { 1386 bin = aRecycleBin; 1387 } 1388 if (!bin) { 1389 return nullptr; 1390 } 1391 1392 for (auto it = bin->mRecycledTextures.begin(); 1393 it != bin->mRecycledTextures.end(); it++) { 1394 auto& holder = *it; 1395 if (holder.mType == aType && holder.mSize == aSize && 1396 holder.mFormat == aFormat) { 1397 UniquePtr<SharedResourceWrapper> wrapper = 1398 std::move(holder.mResourceWrapper); 1399 bin->mRecycledTextures.erase(it); 1400 return wrapper; 1401 } 1402 } 1403 1404 return nullptr; 1405 } 1406 1407 RemoteTextureMap::TextureOwner* RemoteTextureMap::GetTextureOwner( 1408 const MonitorAutoLock& aProofOfLock, const RemoteTextureOwnerId aOwnerId, 1409 const base::ProcessId aForPid) { 1410 const auto key = std::pair(aForPid, aOwnerId); 1411 auto it = mTextureOwners.find(key); 1412 if (it == mTextureOwners.end()) { 1413 return nullptr; 1414 } 1415 return it->second.get(); 1416 } 1417 1418 RemoteTextureMap::TextureDataHolder::TextureDataHolder( 1419 const RemoteTextureId aTextureId, RefPtr<TextureHost> aTextureHost, 1420 UniquePtr<TextureData>&& aTextureData, 1421 UniquePtr<SharedResourceWrapper>&& aResourceWrapper) 1422 : mTextureId(aTextureId), 1423 mTextureHost(aTextureHost), 1424 mTextureData(std::move(aTextureData)), 1425 mResourceWrapper(std::move(aResourceWrapper)) {} 1426 1427 RemoteTextureMap::RenderingReadyCallbackHolder::RenderingReadyCallbackHolder( 1428 const RemoteTextureId aTextureId, 1429 std::function<void(const RemoteTextureInfo&)>&& aCallback) 1430 : mTextureId(aTextureId), mCallback(aCallback) {} 1431 1432 RemoteTextureMap::RemoteTextureHostWrapperHolder:: 1433 RemoteTextureHostWrapperHolder( 1434 RefPtr<TextureHost> aRemoteTextureHostWrapper) 1435 : mRemoteTextureHostWrapper(aRemoteTextureHostWrapper) {} 1436 1437 } // namespace mozilla::layers