tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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