tor-browser

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

TextureHost.cpp (30087B)


      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 "TextureHost.h"
      8 
      9 #include "CompositableHost.h"  // for CompositableHost
     10 #include "mozilla/gfx/2D.h"    // for DataSourceSurface, Factory
     11 #include "mozilla/gfx/CanvasManagerParent.h"
     12 #include "mozilla/gfx/gfxVars.h"
     13 #include "mozilla/ipc/Shmem.h"  // for Shmem
     14 #include "mozilla/layers/AsyncImagePipelineManager.h"
     15 #include "mozilla/layers/BufferTexture.h"
     16 #include "mozilla/layers/CompositableTransactionParent.h"  // for CompositableParentManager
     17 #include "mozilla/layers/CompositorBridgeParent.h"
     18 #include "mozilla/layers/Compositor.h"         // for Compositor
     19 #include "mozilla/layers/ISurfaceAllocator.h"  // for ISurfaceAllocator
     20 #include "mozilla/layers/ImageBridgeParent.h"  // for ImageBridgeParent
     21 #include "mozilla/layers/LayersSurfaces.h"     // for SurfaceDescriptor, etc
     22 #include "mozilla/layers/RemoteTextureMap.h"
     23 #include "mozilla/layers/TextureHostOGL.h"  // for TextureHostOGL
     24 #include "mozilla/layers/ImageDataSerializer.h"
     25 #include "mozilla/layers/TextureClient.h"
     26 #include "mozilla/layers/GPUVideoTextureHost.h"
     27 #include "mozilla/layers/WebRenderTextureHost.h"
     28 #include "mozilla/StaticPrefs_layers.h"
     29 #include "mozilla/StaticPrefs_gfx.h"
     30 #include "mozilla/webrender/RenderBufferTextureHost.h"
     31 #include "mozilla/webrender/RenderExternalTextureHost.h"
     32 #include "mozilla/webrender/RenderThread.h"
     33 #include "mozilla/webrender/WebRenderAPI.h"
     34 #include "nsAString.h"
     35 #include "mozilla/RefPtr.h"   // for nsRefPtr
     36 #include "nsPrintfCString.h"  // for nsPrintfCString
     37 #include "mozilla/layers/PTextureParent.h"
     38 #include <limits>
     39 #include "../opengl/CompositorOGL.h"
     40 
     41 #include "gfxUtils.h"
     42 #include "IPDLActor.h"
     43 
     44 #ifdef XP_MACOSX
     45 #  include "../opengl/MacIOSurfaceTextureHostOGL.h"
     46 #endif
     47 
     48 #ifdef XP_WIN
     49 #  include "../d3d11/CompositorD3D11.h"
     50 #  include "mozilla/layers/TextureD3D11.h"
     51 #  ifdef MOZ_WMF_MEDIA_ENGINE
     52 #    include "mozilla/layers/DcompSurfaceImage.h"
     53 #  endif
     54 #endif
     55 
     56 #if 0
     57 #  define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
     58 #else
     59 #  define RECYCLE_LOG(...) \
     60    do {                   \
     61    } while (0)
     62 #endif
     63 
     64 namespace mozilla {
     65 namespace layers {
     66 
     67 /**
     68 * TextureParent is the host-side IPDL glue between TextureClient and
     69 * TextureHost. It is an IPDL actor just like LayerParent, CompositableParent,
     70 * etc.
     71 */
     72 class TextureParent : public ParentActor<PTextureParent> {
     73 public:
     74  TextureParent(HostIPCAllocator* aAllocator,
     75                const dom::ContentParentId& aContentId, uint64_t aSerial,
     76                const wr::MaybeExternalImageId& aExternalImageId);
     77 
     78  virtual ~TextureParent();
     79 
     80  bool Init(const SurfaceDescriptor& aSharedData,
     81            ReadLockDescriptor&& aReadLock, const LayersBackend& aLayersBackend,
     82            const TextureFlags& aFlags);
     83 
     84  void NotifyNotUsed(uint64_t aTransactionId);
     85 
     86  mozilla::ipc::IPCResult RecvRecycleTexture(
     87      const TextureFlags& aTextureFlags) final;
     88 
     89  TextureHost* GetTextureHost() { return mTextureHost; }
     90 
     91  void Destroy() override;
     92 
     93  const dom::ContentParentId& GetContentId() const { return mContentId; }
     94 
     95  uint64_t GetSerial() const { return mSerial; }
     96 
     97  HostIPCAllocator* mSurfaceAllocator;
     98  RefPtr<TextureHost> mTextureHost;
     99  dom::ContentParentId mContentId;
    100  // mSerial is unique in TextureClient's process.
    101  const uint64_t mSerial;
    102  wr::MaybeExternalImageId mExternalImageId;
    103 };
    104 
    105 static bool WrapWithWebRenderTextureHost(ISurfaceAllocator* aDeallocator,
    106                                         LayersBackend aBackend,
    107                                         TextureFlags aFlags) {
    108  if (!aDeallocator) {
    109    return false;
    110  }
    111  if ((aFlags & TextureFlags::SNAPSHOT) ||
    112      (!aDeallocator->UsesImageBridge() &&
    113       !aDeallocator->AsCompositorBridgeParentBase())) {
    114    return false;
    115  }
    116  return true;
    117 }
    118 
    119 ////////////////////////////////////////////////////////////////////////////////
    120 PTextureParent* TextureHost::CreateIPDLActor(
    121    HostIPCAllocator* aAllocator, const SurfaceDescriptor& aSharedData,
    122    ReadLockDescriptor&& aReadLock, LayersBackend aLayersBackend,
    123    TextureFlags aFlags, const dom::ContentParentId& aContentId,
    124    uint64_t aSerial, const wr::MaybeExternalImageId& aExternalImageId) {
    125  TextureParent* actor =
    126      new TextureParent(aAllocator, aContentId, aSerial, aExternalImageId);
    127  if (!actor->Init(aSharedData, std::move(aReadLock), aLayersBackend, aFlags)) {
    128    actor->ActorDestroy(ipc::IProtocol::ActorDestroyReason::FailedConstructor);
    129    delete actor;
    130    return nullptr;
    131  }
    132  return actor;
    133 }
    134 
    135 // static
    136 bool TextureHost::DestroyIPDLActor(PTextureParent* actor) {
    137  delete actor;
    138  return true;
    139 }
    140 
    141 // static
    142 bool TextureHost::SendDeleteIPDLActor(PTextureParent* actor) {
    143  return PTextureParent::Send__delete__(actor);
    144 }
    145 
    146 // static
    147 TextureHost* TextureHost::AsTextureHost(PTextureParent* actor) {
    148  if (!actor) {
    149    return nullptr;
    150  }
    151  return static_cast<TextureParent*>(actor)->mTextureHost;
    152 }
    153 
    154 // static
    155 uint64_t TextureHost::GetTextureSerial(PTextureParent* actor) {
    156  if (!actor) {
    157    return UINT64_MAX;
    158  }
    159  return static_cast<TextureParent*>(actor)->mSerial;
    160 }
    161 
    162 // static
    163 dom::ContentParentId TextureHost::GetTextureContentId(PTextureParent* actor) {
    164  if (!actor) {
    165    return dom::ContentParentId();
    166  }
    167  return static_cast<TextureParent*>(actor)->mContentId;
    168 }
    169 
    170 PTextureParent* TextureHost::GetIPDLActor() { return mActor; }
    171 
    172 void TextureHost::SetLastFwdTransactionId(uint64_t aTransactionId) {
    173  MOZ_ASSERT(mFwdTransactionId <= aTransactionId);
    174  mFwdTransactionId = aTransactionId;
    175 }
    176 
    177 already_AddRefed<TextureHost> CreateDummyBufferTextureHost(
    178    mozilla::layers::LayersBackend aBackend,
    179    mozilla::layers::TextureFlags aFlags) {
    180  // Ensure that the host will delete the memory.
    181  aFlags &= ~TextureFlags::DEALLOCATE_CLIENT;
    182  aFlags |= TextureFlags::DUMMY_TEXTURE;
    183  UniquePtr<TextureData> textureData(BufferTextureData::Create(
    184      gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8, gfx::BackendType::SKIA,
    185      aBackend, aFlags, TextureAllocationFlags::ALLOC_DEFAULT, nullptr));
    186  SurfaceDescriptor surfDesc;
    187  textureData->Serialize(surfDesc);
    188  const SurfaceDescriptorBuffer& bufferDesc =
    189      surfDesc.get_SurfaceDescriptorBuffer();
    190  const MemoryOrShmem& data = bufferDesc.data();
    191  RefPtr<TextureHost> host =
    192      new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
    193                            bufferDesc.desc(), aFlags);
    194  return host.forget();
    195 }
    196 
    197 already_AddRefed<TextureHost> TextureHost::Create(
    198    const SurfaceDescriptor& aDesc, ReadLockDescriptor&& aReadLock,
    199    HostIPCAllocator* aDeallocator, LayersBackend aBackend, TextureFlags aFlags,
    200    wr::MaybeExternalImageId& aExternalImageId) {
    201  RefPtr<TextureHost> result;
    202 
    203  switch (aDesc.type()) {
    204    case SurfaceDescriptor::TSurfaceDescriptorBuffer:
    205    case SurfaceDescriptor::TSurfaceDescriptorGPUVideo:
    206      result = CreateBackendIndependentTextureHost(aDesc, aDeallocator,
    207                                                   aBackend, aFlags);
    208      break;
    209 
    210    case SurfaceDescriptor::TEGLImageDescriptor:
    211    case SurfaceDescriptor::TSurfaceTextureDescriptor:
    212    case SurfaceDescriptor::TSurfaceDescriptorAndroidHardwareBuffer:
    213    case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:
    214    case SurfaceDescriptor::TSurfaceDescriptorDMABuf:
    215      result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
    216      break;
    217 
    218    case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
    219      result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
    220      break;
    221 
    222 #ifdef XP_WIN
    223    case SurfaceDescriptor::TSurfaceDescriptorD3D10:
    224    case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:
    225      result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags);
    226      break;
    227 #  ifdef MOZ_WMF_MEDIA_ENGINE
    228    case SurfaceDescriptor::TSurfaceDescriptorDcompSurface:
    229      result =
    230          CreateTextureHostDcompSurface(aDesc, aDeallocator, aBackend, aFlags);
    231      break;
    232 #  endif
    233 #endif
    234    default:
    235      MOZ_CRASH("GFX: Unsupported Surface type host");
    236  }
    237 
    238  if (!result) {
    239    gfxCriticalNote << "TextureHost creation failure type=" << aDesc.type();
    240  }
    241 
    242  if (result && WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) {
    243    MOZ_ASSERT(aExternalImageId.isSome());
    244    result = new WebRenderTextureHost(aFlags, result, aExternalImageId.ref());
    245  }
    246 
    247  if (result) {
    248    result->DeserializeReadLock(std::move(aReadLock), aDeallocator);
    249  }
    250 
    251  return result.forget();
    252 }
    253 
    254 already_AddRefed<TextureHost> CreateBackendIndependentTextureHost(
    255    const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
    256    LayersBackend aBackend, TextureFlags aFlags) {
    257  RefPtr<TextureHost> result;
    258  switch (aDesc.type()) {
    259    case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
    260      const SurfaceDescriptorBuffer& bufferDesc =
    261          aDesc.get_SurfaceDescriptorBuffer();
    262      const MemoryOrShmem& data = bufferDesc.data();
    263      switch (data.type()) {
    264        case MemoryOrShmem::TShmem: {
    265          const ipc::Shmem& shmem = data.get_Shmem();
    266          const BufferDescriptor& desc = bufferDesc.desc();
    267          if (!shmem.IsReadable()) {
    268            // We failed to map the shmem so we can't verify its size. This
    269            // should not be a fatal error, so just create the texture with
    270            // nothing backing it.
    271            result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
    272            break;
    273          }
    274 
    275          size_t bufSize = shmem.Size<char>();
    276          size_t reqSize = SIZE_MAX;
    277          switch (desc.type()) {
    278            case BufferDescriptor::TYCbCrDescriptor: {
    279              const YCbCrDescriptor& ycbcr = desc.get_YCbCrDescriptor();
    280              reqSize = ImageDataSerializer::ComputeYCbCrBufferSize(
    281                  ycbcr.ySize(), ycbcr.yStride(), ycbcr.cbCrSize(),
    282                  ycbcr.cbCrStride(), ycbcr.yOffset(), ycbcr.cbOffset(),
    283                  ycbcr.crOffset());
    284              break;
    285            }
    286            case BufferDescriptor::TRGBDescriptor: {
    287              const RGBDescriptor& rgb = desc.get_RGBDescriptor();
    288              reqSize = ImageDataSerializer::ComputeRGBBufferSize(rgb.size(),
    289                                                                  rgb.format());
    290              break;
    291            }
    292            default:
    293              gfxCriticalError()
    294                  << "Bad buffer host descriptor " << (int)desc.type();
    295              MOZ_CRASH("GFX: Bad descriptor");
    296          }
    297 
    298          if (reqSize == 0 || bufSize < reqSize) {
    299            NS_ERROR(
    300                "A client process gave a shmem too small to fit for its "
    301                "descriptor!");
    302            return nullptr;
    303          }
    304 
    305          result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
    306          break;
    307        }
    308        case MemoryOrShmem::Tuintptr_t: {
    309          if (aDeallocator && !aDeallocator->IsSameProcess()) {
    310            NS_ERROR(
    311                "A client process is trying to peek at our address space using "
    312                "a MemoryTexture!");
    313            return nullptr;
    314          }
    315 
    316          result = new MemoryTextureHost(
    317              reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
    318              bufferDesc.desc(), aFlags);
    319          break;
    320        }
    321        default:
    322          gfxCriticalError()
    323              << "Failed texture host for backend " << (int)data.type();
    324          MOZ_CRASH("GFX: No texture host for backend");
    325      }
    326      break;
    327    }
    328    case SurfaceDescriptor::TSurfaceDescriptorGPUVideo: {
    329      MOZ_ASSERT(aDesc.get_SurfaceDescriptorGPUVideo().type() ==
    330                 SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder);
    331      result = GPUVideoTextureHost::CreateFromDescriptor(
    332          aDeallocator->GetContentId(), aFlags,
    333          aDesc.get_SurfaceDescriptorGPUVideo());
    334      break;
    335    }
    336    default: {
    337      NS_WARNING("No backend independent TextureHost for this descriptor type");
    338    }
    339  }
    340  return result.forget();
    341 }
    342 
    343 TextureHost::TextureHost(TextureHostType aType, TextureFlags aFlags)
    344    : AtomicRefCountedWithFinalize("TextureHost"),
    345      mTextureHostType(aType),
    346      mActor(nullptr),
    347      mFlags(aFlags),
    348      mCompositableCount(0),
    349      mFwdTransactionId(0),
    350      mReadLocked(false) {}
    351 
    352 TextureHost::~TextureHost() {
    353  MOZ_ASSERT(mExternalImageId.isNothing());
    354 
    355  if (mReadLocked) {
    356    // If we still have a ReadLock, unlock it. At this point we don't care about
    357    // the texture client being written into on the other side since it should
    358    // be destroyed by now. But we will hit assertions if we don't ReadUnlock
    359    // before destroying the lock itself.
    360    ReadUnlock();
    361  }
    362  if (mDestroyedCallback) {
    363    mDestroyedCallback();
    364  }
    365 }
    366 
    367 void TextureHost::Finalize() {
    368  MaybeDestroyRenderTexture();
    369 
    370  if (!(GetFlags() & TextureFlags::DEALLOCATE_CLIENT)) {
    371    DeallocateSharedData();
    372    DeallocateDeviceData();
    373  }
    374 }
    375 
    376 void TextureHost::UnbindTextureSource() {
    377  if (mReadLocked) {
    378    ReadUnlock();
    379  }
    380 }
    381 
    382 void TextureHost::RecycleTexture(TextureFlags aFlags) {
    383  MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
    384  MOZ_ASSERT(aFlags & TextureFlags::RECYCLE);
    385  mFlags = aFlags;
    386 }
    387 
    388 void TextureHost::PrepareForUse() {}
    389 
    390 void TextureHost::NotifyNotUsed() {
    391  if (!mActor) {
    392    if ((mFlags & TextureFlags::REMOTE_TEXTURE) && AsSurfaceTextureHost()) {
    393      MOZ_ASSERT(mExternalImageId.isSome());
    394      wr::RenderThread::Get()->NotifyNotUsed(*mExternalImageId);
    395    }
    396    return;
    397  }
    398 
    399  // Do not need to call NotifyNotUsed() if TextureHost does not have
    400  // TextureFlags::RECYCLE flag nor TextureFlags::WAIT_HOST_USAGE_END flag.
    401  if (!(GetFlags() & TextureFlags::RECYCLE) &&
    402      !(GetFlags() & TextureFlags::WAIT_HOST_USAGE_END)) {
    403    return;
    404  }
    405 
    406  static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
    407 }
    408 
    409 void TextureHost::CallNotifyNotUsed() {
    410  if (!mActor) {
    411    return;
    412  }
    413  static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
    414 }
    415 
    416 void TextureHost::MaybeDestroyRenderTexture() {
    417  if (mExternalImageId.isNothing()) {
    418    // RenderTextureHost was not created
    419    return;
    420  }
    421  // When TextureHost created RenderTextureHost, delete it here.
    422  TextureHost::DestroyRenderTexture(mExternalImageId.ref());
    423  mExternalImageId = Nothing();
    424 }
    425 
    426 void TextureHost::DestroyRenderTexture(
    427    const wr::ExternalImageId& aExternalImageId) {
    428  wr::RenderThread::Get()->UnregisterExternalImage(aExternalImageId);
    429 }
    430 
    431 void TextureHost::EnsureRenderTexture(
    432    const wr::MaybeExternalImageId& aExternalImageId) {
    433  if (aExternalImageId.isNothing()) {
    434    // TextureHost is wrapped by GPUVideoTextureHost.
    435    if (mExternalImageId.isSome()) {
    436      // RenderTextureHost was already created.
    437      return;
    438    }
    439    mExternalImageId =
    440        Some(AsyncImagePipelineManager::GetNextExternalImageId());
    441  } else {
    442    // TextureHost is wrapped by WebRenderTextureHost.
    443    if (aExternalImageId == mExternalImageId) {
    444      // The texture has already been created.
    445      return;
    446    }
    447    MOZ_ASSERT(mExternalImageId.isNothing());
    448    mExternalImageId = aExternalImageId;
    449  }
    450  CreateRenderTexture(mExternalImageId.ref());
    451 }
    452 
    453 TextureSource::TextureSource() : mCompositableCount(0) {}
    454 
    455 TextureSource::~TextureSource() = default;
    456 BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc,
    457                                     TextureFlags aFlags)
    458    : TextureHost(TextureHostType::Buffer, aFlags), mLocked(false) {
    459  mDescriptor = aDesc;
    460  switch (mDescriptor.type()) {
    461    case BufferDescriptor::TYCbCrDescriptor: {
    462      const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor();
    463      mSize = ycbcr.display().Size();
    464      mFormat = gfx::SurfaceFormat::YUV420;
    465      break;
    466    }
    467    case BufferDescriptor::TRGBDescriptor: {
    468      const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
    469      mSize = rgb.size();
    470      mFormat = rgb.format();
    471      break;
    472    }
    473    default:
    474      gfxCriticalError() << "Bad buffer host descriptor "
    475                         << (int)mDescriptor.type();
    476      MOZ_CRASH("GFX: Bad descriptor");
    477  }
    478 
    479 #ifdef XP_MACOSX
    480  const int kMinSize = 1024;
    481  const int kMaxSize = 4096;
    482  mUseExternalTextures =
    483      kMaxSize >= mSize.width && mSize.width >= kMinSize &&
    484      kMaxSize >= mSize.height && mSize.height >= kMinSize &&
    485      StaticPrefs::gfx_webrender_enable_client_storage_AtStartup();
    486 #else
    487  mUseExternalTextures = false;
    488 #endif
    489 }
    490 
    491 BufferTextureHost::~BufferTextureHost() = default;
    492 
    493 void BufferTextureHost::DeallocateDeviceData() {}
    494 
    495 void BufferTextureHost::CreateRenderTexture(
    496    const wr::ExternalImageId& aExternalImageId) {
    497  MOZ_ASSERT(mExternalImageId.isSome());
    498 
    499  RefPtr<wr::RenderTextureHost> texture;
    500 
    501  if (UseExternalTextures()) {
    502    texture =
    503        new wr::RenderExternalTextureHost(GetBuffer(), GetBufferDescriptor());
    504  } else {
    505    texture =
    506        new wr::RenderBufferTextureHost(GetBuffer(), GetBufferDescriptor());
    507  }
    508 
    509  wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
    510                                                 texture.forget());
    511 }
    512 
    513 uint32_t BufferTextureHost::NumSubTextures() {
    514  if (GetFormat() == gfx::SurfaceFormat::YUV420) {
    515    return 3;
    516  }
    517 
    518  return 1;
    519 }
    520 
    521 void BufferTextureHost::PushResourceUpdates(
    522    wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
    523    const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
    524  auto method = aOp == TextureHost::ADD_IMAGE
    525                    ? &wr::TransactionBuilder::AddExternalImage
    526                    : &wr::TransactionBuilder::UpdateExternalImage;
    527 
    528  // Use native textures if our backend requires it, or if our backend doesn't
    529  // forbid it and we want to use them.
    530  NativeTexturePolicy policy =
    531      BackendNativeTexturePolicy(aResources.GetBackendType(), GetSize());
    532  bool useNativeTexture =
    533      (policy == REQUIRE) || (policy != FORBID && UseExternalTextures());
    534  auto imageType = useNativeTexture ? wr::ExternalImageType::TextureHandle(
    535                                          wr::ImageBufferKind::TextureRect)
    536                                    : wr::ExternalImageType::Buffer();
    537 
    538  if (GetFormat() != gfx::SurfaceFormat::YUV420) {
    539    MOZ_ASSERT(aImageKeys.length() == 1);
    540 
    541    wr::ImageDescriptor descriptor(
    542        GetSize(),
    543        ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width),
    544        GetFormat());
    545    (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0,
    546                         /* aNormalizedUvs */ false);
    547  } else {
    548    MOZ_ASSERT(aImageKeys.length() == 3);
    549 
    550    const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    551    gfx::IntSize ySize = desc.display().Size();
    552    gfx::IntSize cbcrSize = ImageDataSerializer::GetCroppedCbCrSize(desc);
    553    wr::ImageDescriptor yDescriptor(
    554        ySize, desc.yStride(), SurfaceFormatForColorDepth(desc.colorDepth()));
    555    wr::ImageDescriptor cbcrDescriptor(
    556        cbcrSize, desc.cbCrStride(),
    557        SurfaceFormatForColorDepth(desc.colorDepth()));
    558    (aResources.*method)(aImageKeys[0], yDescriptor, aExtID, imageType, 0,
    559                         /* aNormalizedUvs */ false);
    560    (aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, imageType, 1,
    561                         /* aNormalizedUvs */ false);
    562    (aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, imageType, 2,
    563                         /* aNormalizedUvs */ false);
    564  }
    565 }
    566 
    567 void BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
    568                                         const wr::LayoutRect& aBounds,
    569                                         const wr::LayoutRect& aClip,
    570                                         wr::ImageRendering aFilter,
    571                                         const Range<wr::ImageKey>& aImageKeys,
    572                                         PushDisplayItemFlagSet aFlags) {
    573  // SWGL should always try to bypass shaders and composite directly.
    574  bool preferCompositorSurface =
    575      aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE);
    576  bool useExternalSurface =
    577      aFlags.contains(PushDisplayItemFlag::SUPPORTS_EXTERNAL_BUFFER_TEXTURES);
    578  if (GetFormat() != gfx::SurfaceFormat::YUV420) {
    579    MOZ_ASSERT(aImageKeys.length() == 1);
    580    aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0],
    581                       !(mFlags & TextureFlags::NON_PREMULTIPLIED),
    582                       wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
    583                       preferCompositorSurface, useExternalSurface);
    584  } else {
    585    MOZ_ASSERT(aImageKeys.length() == 3);
    586    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    587    aBuilder.PushYCbCrPlanarImage(
    588        aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2],
    589        wr::ToWrColorDepth(desc.colorDepth()),
    590        wr::ToWrYuvColorSpace(desc.yUVColorSpace()),
    591        wr::ToWrColorRange(desc.colorRange()), aFilter, preferCompositorSurface,
    592        useExternalSurface);
    593  }
    594 }
    595 
    596 void TextureHost::DeserializeReadLock(ReadLockDescriptor&& aDesc,
    597                                      ISurfaceAllocator* aAllocator) {
    598  if (mReadLock) {
    599    return;
    600  }
    601 
    602  mReadLock = TextureReadLock::Deserialize(std::move(aDesc), aAllocator);
    603 }
    604 
    605 void TextureHost::SetReadLocked() {
    606  if (!mReadLock) {
    607    return;
    608  }
    609  // If mReadLocked is true it means we haven't read unlocked yet and the
    610  // content side should not have been able to write into this texture and read
    611  // lock again!
    612  MOZ_ASSERT(!mReadLocked);
    613  mReadLocked = true;
    614 }
    615 
    616 void TextureHost::ReadUnlock() {
    617  if (mReadLock && mReadLocked) {
    618    mReadLock->ReadUnlock();
    619    mReadLocked = false;
    620  }
    621 }
    622 
    623 bool TextureHost::NeedsYFlip() const {
    624  return bool(mFlags & TextureFlags::ORIGIN_BOTTOM_LEFT);
    625 }
    626 
    627 void BufferTextureHost::UnbindTextureSource() {
    628  // This texture is not used by any layer anymore.
    629  // If the texture has an intermediate buffer we don't care either because
    630  // texture uploads are also performed synchronously for BufferTextureHost.
    631  ReadUnlock();
    632 }
    633 
    634 gfx::SurfaceFormat BufferTextureHost::GetFormat() const { return mFormat; }
    635 
    636 gfx::YUVColorSpace BufferTextureHost::GetYUVColorSpace() const {
    637  if (mFormat == gfx::SurfaceFormat::YUV420) {
    638    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    639    return desc.yUVColorSpace();
    640  }
    641  return gfx::YUVColorSpace::Identity;
    642 }
    643 
    644 gfx::ColorDepth BufferTextureHost::GetColorDepth() const {
    645  if (mFormat == gfx::SurfaceFormat::YUV420) {
    646    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    647    return desc.colorDepth();
    648  }
    649  return gfx::ColorDepth::COLOR_8;
    650 }
    651 
    652 gfx::ColorRange BufferTextureHost::GetColorRange() const {
    653  if (mFormat == gfx::SurfaceFormat::YUV420) {
    654    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    655    return desc.colorRange();
    656  }
    657  return TextureHost::GetColorRange();
    658 }
    659 
    660 gfx::ChromaSubsampling BufferTextureHost::GetChromaSubsampling() const {
    661  if (mFormat == gfx::SurfaceFormat::YUV420) {
    662    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    663    return desc.chromaSubsampling();
    664  }
    665  return gfx::ChromaSubsampling::FULL;
    666 }
    667 
    668 uint8_t* BufferTextureHost::GetYChannel() {
    669  if (mFormat == gfx::SurfaceFormat::YUV420) {
    670    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    671    return ImageDataSerializer::GetYChannel(GetBuffer(), desc);
    672  }
    673  return nullptr;
    674 }
    675 
    676 uint8_t* BufferTextureHost::GetCbChannel() {
    677  if (mFormat == gfx::SurfaceFormat::YUV420) {
    678    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    679    return ImageDataSerializer::GetCbChannel(GetBuffer(), desc);
    680  }
    681  return nullptr;
    682 }
    683 
    684 uint8_t* BufferTextureHost::GetCrChannel() {
    685  if (mFormat == gfx::SurfaceFormat::YUV420) {
    686    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    687    return ImageDataSerializer::GetCrChannel(GetBuffer(), desc);
    688  }
    689  return nullptr;
    690 }
    691 
    692 int32_t BufferTextureHost::GetYStride() const {
    693  if (mFormat == gfx::SurfaceFormat::YUV420) {
    694    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    695    return desc.yStride();
    696  }
    697  return 0;
    698 }
    699 
    700 int32_t BufferTextureHost::GetCbCrStride() const {
    701  if (mFormat == gfx::SurfaceFormat::YUV420) {
    702    const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
    703    return desc.cbCrStride();
    704  }
    705  return 0;
    706 }
    707 
    708 already_AddRefed<gfx::DataSourceSurface> BufferTextureHost::GetAsSurface(
    709    gfx::DataSourceSurface* aSurface) {
    710  RefPtr<gfx::DataSourceSurface> result;
    711  if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
    712    NS_WARNING("BufferTextureHost: unsupported format!");
    713    return nullptr;
    714  }
    715  if (mFormat == gfx::SurfaceFormat::YUV420) {
    716    result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
    717        GetBuffer(), mDescriptor.get_YCbCrDescriptor(), aSurface);
    718    if (NS_WARN_IF(!result)) {
    719      return nullptr;
    720    }
    721  } else {
    722    result = gfx::Factory::CreateWrappingDataSourceSurface(
    723        GetBuffer(),
    724        ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
    725        mSize, mFormat);
    726  }
    727  return result.forget();
    728 }
    729 
    730 ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem,
    731                                   const BufferDescriptor& aDesc,
    732                                   ISurfaceAllocator* aDeallocator,
    733                                   TextureFlags aFlags)
    734    : BufferTextureHost(aDesc, aFlags), mDeallocator(aDeallocator) {
    735  if (aShmem.IsReadable()) {
    736    mShmem = MakeUnique<ipc::Shmem>(aShmem);
    737  } else {
    738    // This can happen if we failed to map the shmem on this process, perhaps
    739    // because it was big and we didn't have enough contiguous address space
    740    // available, even though we did on the child process.
    741    // As a result this texture will be in an invalid state and Lock will
    742    // always fail.
    743 
    744    gfxCriticalNote << "Failed to create a valid ShmemTextureHost";
    745  }
    746 
    747  MOZ_COUNT_CTOR(ShmemTextureHost);
    748 }
    749 
    750 ShmemTextureHost::~ShmemTextureHost() {
    751  MOZ_ASSERT(!mShmem || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
    752             "Leaking our buffer");
    753  DeallocateDeviceData();
    754  MOZ_COUNT_DTOR(ShmemTextureHost);
    755 }
    756 
    757 void ShmemTextureHost::DeallocateSharedData() {
    758  if (mShmem) {
    759    MOZ_ASSERT(mDeallocator,
    760               "Shared memory would leak without a ISurfaceAllocator");
    761    mDeallocator->AsShmemAllocator()->DeallocShmem(*mShmem);
    762    mShmem = nullptr;
    763  }
    764 }
    765 
    766 void ShmemTextureHost::ForgetSharedData() {
    767  if (mShmem) {
    768    mShmem = nullptr;
    769  }
    770 }
    771 
    772 void ShmemTextureHost::OnShutdown() { mShmem = nullptr; }
    773 
    774 uint8_t* ShmemTextureHost::GetBuffer() const {
    775  return mShmem ? mShmem->get<uint8_t>() : nullptr;
    776 }
    777 
    778 size_t ShmemTextureHost::GetBufferSize() const {
    779  return mShmem ? mShmem->Size<uint8_t>() : 0;
    780 }
    781 
    782 MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer,
    783                                     const BufferDescriptor& aDesc,
    784                                     TextureFlags aFlags)
    785    : BufferTextureHost(aDesc, aFlags), mBuffer(aBuffer) {
    786  MOZ_COUNT_CTOR(MemoryTextureHost);
    787 }
    788 
    789 MemoryTextureHost::~MemoryTextureHost() {
    790  MOZ_ASSERT(!mBuffer || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
    791             "Leaking our buffer");
    792  DeallocateDeviceData();
    793  MOZ_COUNT_DTOR(MemoryTextureHost);
    794 }
    795 
    796 void MemoryTextureHost::DeallocateSharedData() {
    797  if (mBuffer) {
    798    GfxMemoryImageReporter::WillFree(mBuffer);
    799  }
    800  delete[] mBuffer;
    801  mBuffer = nullptr;
    802 }
    803 
    804 void MemoryTextureHost::ForgetSharedData() { mBuffer = nullptr; }
    805 
    806 uint8_t* MemoryTextureHost::GetBuffer() const { return mBuffer; }
    807 
    808 size_t MemoryTextureHost::GetBufferSize() const {
    809  // MemoryTextureHost just trusts that the buffer size is large enough to read
    810  // anything we need to. That's because MemoryTextureHost has to trust the
    811  // buffer pointer anyway, so the security model here is just that
    812  // MemoryTexture's are restricted to same-process clients.
    813  return std::numeric_limits<size_t>::max();
    814 }
    815 
    816 TextureParent::TextureParent(HostIPCAllocator* aSurfaceAllocator,
    817                             const dom::ContentParentId& aContentId,
    818                             uint64_t aSerial,
    819                             const wr::MaybeExternalImageId& aExternalImageId)
    820    : mSurfaceAllocator(aSurfaceAllocator),
    821      mContentId(aContentId),
    822      mSerial(aSerial),
    823      mExternalImageId(aExternalImageId) {
    824  MOZ_COUNT_CTOR(TextureParent);
    825 }
    826 
    827 TextureParent::~TextureParent() { MOZ_COUNT_DTOR(TextureParent); }
    828 
    829 void TextureParent::NotifyNotUsed(uint64_t aTransactionId) {
    830  if (!mTextureHost) {
    831    return;
    832  }
    833  mSurfaceAllocator->NotifyNotUsed(this, aTransactionId);
    834 }
    835 
    836 bool TextureParent::Init(const SurfaceDescriptor& aSharedData,
    837                         ReadLockDescriptor&& aReadLock,
    838                         const LayersBackend& aBackend,
    839                         const TextureFlags& aFlags) {
    840  mTextureHost =
    841      TextureHost::Create(aSharedData, std::move(aReadLock), mSurfaceAllocator,
    842                          aBackend, aFlags, mExternalImageId);
    843  if (mTextureHost) {
    844    mTextureHost->mActor = this;
    845  }
    846 
    847  return !!mTextureHost;
    848 }
    849 
    850 void TextureParent::Destroy() {
    851  if (!mTextureHost) {
    852    return;
    853  }
    854 
    855  if (mTextureHost->mReadLocked) {
    856    // ReadUnlock here to make sure the ReadLock's shmem does not outlive the
    857    // protocol that created it.
    858    mTextureHost->ReadUnlock();
    859  }
    860 
    861  if (mTextureHost->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
    862    mTextureHost->ForgetSharedData();
    863  }
    864 
    865  mTextureHost->mActor = nullptr;
    866  mTextureHost = nullptr;
    867 }
    868 
    869 void TextureHost::ReceivedDestroy(PTextureParent* aActor) {
    870  static_cast<TextureParent*>(aActor)->RecvDestroy();
    871 }
    872 
    873 mozilla::ipc::IPCResult TextureParent::RecvRecycleTexture(
    874    const TextureFlags& aTextureFlags) {
    875  if (!mTextureHost) {
    876    return IPC_OK();
    877  }
    878  mTextureHost->RecycleTexture(aTextureFlags);
    879  return IPC_OK();
    880 }
    881 
    882 ////////////////////////////////////////////////////////////////////////////////
    883 
    884 }  // namespace layers
    885 }  // namespace mozilla