tor-browser

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

ImageContainer.h (35027B)


      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 #ifndef GFX_IMAGECONTAINER_H
      8 #define GFX_IMAGECONTAINER_H
      9 
     10 #include <stdint.h>      // for int32_t, uint32_t, uint8_t, uint64_t
     11 #include "ImageTypes.h"  // for ImageFormat, etc
     12 #include "mozilla/AlreadyAddRefed.h"
     13 #include "mozilla/Assertions.h"      // for MOZ_ASSERT_HELPER2
     14 #include "mozilla/Mutex.h"           // for Mutex
     15 #include "mozilla/RecursiveMutex.h"  // for RecursiveMutex, etc
     16 #include "mozilla/ThreadSafeWeakPtr.h"
     17 #include "mozilla/TimeStamp.h"  // for TimeStamp
     18 #include "mozilla/gfx/Point.h"  // For IntSize
     19 #include "mozilla/gfx/Rect.h"
     20 #include "mozilla/gfx/Types.h"           // For ColorDepth
     21 #include "mozilla/layers/LayersTypes.h"  // for LayersBackend, etc
     22 #include "mozilla/layers/CompositorTypes.h"
     23 #include "mozilla/mozalloc.h"  // for operator delete, etc
     24 #include "mozilla/TypedEnumBits.h"
     25 #include "nsDebug.h"          // for NS_ASSERTION
     26 #include "nsISupportsImpl.h"  // for Image::Release, etc
     27 #include "nsTArray.h"         // for nsTArray
     28 #include "nsThreadUtils.h"    // for NS_IsMainThread
     29 #include "mozilla/Atomics.h"
     30 #include "mozilla/gfx/2D.h"
     31 #include "mozilla/EnumeratedArray.h"
     32 #include "mozilla/UniquePtr.h"
     33 #include "nsTHashMap.h"
     34 #include "TimeUnits.h"
     35 #include "MediaData.h"
     36 
     37 #ifdef XP_WIN
     38 struct ID3D10Texture2D;
     39 struct ID3D10Device;
     40 struct ID3D10ShaderResourceView;
     41 #endif
     42 
     43 typedef void* HANDLE;
     44 
     45 namespace mozilla {
     46 
     47 enum class VideoRotation;
     48 
     49 namespace layers {
     50 
     51 class GPUVideoImage;
     52 class ImageClient;
     53 class ImageCompositeNotification;
     54 class ImageContainer;
     55 class ImageContainerChild;
     56 class SharedPlanarYCbCrImage;
     57 class SurfaceDescriptor;
     58 class PlanarYCbCrImage;
     59 class TextureClient;
     60 class TextureClientRecycleAllocator;
     61 class KnowsCompositor;
     62 class NVImage;
     63 class MemoryOrShmem;
     64 #ifdef XP_WIN
     65 class D3D11RecycleAllocator;
     66 class D3D11YCbCrRecycleAllocator;
     67 #endif
     68 #ifdef XP_DARWIN
     69 class MacIOSurfaceRecycleAllocator;
     70 #endif
     71 class SurfaceDescriptorBuffer;
     72 enum class VideoBridgeSource : uint8_t;
     73 
     74 struct ImageBackendData {
     75  virtual ~ImageBackendData() = default;
     76 
     77 protected:
     78  ImageBackendData() = default;
     79 };
     80 
     81 /* Forward declarations for Image derivatives. */
     82 class GLImage;
     83 class SharedRGBImage;
     84 #ifdef MOZ_WIDGET_ANDROID
     85 class SurfaceTextureImage;
     86 #elif defined(XP_DARWIN)
     87 class MacIOSurfaceImage;
     88 #elif MOZ_WIDGET_GTK
     89 class DMABUFSurfaceImage;
     90 #endif
     91 
     92 /**
     93 * A class representing a buffer of pixel data. The data can be in one
     94 * of various formats including YCbCr.
     95 *
     96 * Create an image using an ImageContainer. Fill the image with data, and
     97 * then call ImageContainer::SetImage to display it. An image must not be
     98 * modified after calling SetImage. Image implementations do not need to
     99 * perform locking; when filling an Image, the Image client is responsible
    100 * for ensuring only one thread accesses the Image at a time, and after
    101 * SetImage the image is immutable.
    102 *
    103 * When resampling an Image, only pixels within the buffer should be
    104 * sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
    105 */
    106 class Image {
    107  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image)
    108 
    109 public:
    110  ImageFormat GetFormat() const { return mFormat; }
    111  void* GetImplData() const { return mImplData; }
    112 
    113  virtual gfx::IntSize GetSize() const = 0;
    114  virtual gfx::IntPoint GetOrigin() const { return gfx::IntPoint(0, 0); }
    115  virtual gfx::IntRect GetPictureRect() const {
    116    return gfx::IntRect(GetOrigin().x, GetOrigin().y, GetSize().width,
    117                        GetSize().height);
    118  }
    119  virtual gfx::ColorDepth GetColorDepth() const {
    120    return gfx::ColorDepth::COLOR_8;
    121  }
    122 
    123  ImageBackendData* GetBackendData(LayersBackend aBackend) {
    124    return mBackendData[aBackend].get();
    125  }
    126  void SetBackendData(LayersBackend aBackend, ImageBackendData* aData) {
    127    mBackendData[aBackend] = mozilla::WrapUnique(aData);
    128  }
    129 
    130  int32_t GetSerial() const { return mSerial; }
    131 
    132  bool IsDRM() const { return mIsDRM; }
    133  virtual void SetIsDRM(bool aIsDRM) { mIsDRM = aIsDRM; }
    134 
    135  virtual void OnPrepareForwardToHost() {}
    136  virtual void OnAbandonForwardToHost() {}
    137  virtual void OnSetCurrent() {}
    138 
    139  virtual already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() = 0;
    140 
    141  enum class BuildSdbFlags : uint8_t {
    142    Default = 0,
    143    RgbOnly = 1 << 0,
    144  };
    145 
    146  virtual nsresult BuildSurfaceDescriptorBuffer(
    147      SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags,
    148      const std::function<MemoryOrShmem(uint32_t)>& aAllocate);
    149 
    150  /**
    151   * Get a SurfaceDescriptorGPUVideo if possible, with the source matching aDest
    152   * if given. Otherwise copy the data into a SurfaceDescriptorBuffer.
    153   */
    154  nsresult BuildSurfaceDescriptorGPUVideoOrBuffer(
    155      SurfaceDescriptor& aSd, BuildSdbFlags aFlags,
    156      const Maybe<VideoBridgeSource>& aDest,
    157      const std::function<MemoryOrShmem(uint32_t)>& aAllocate,
    158      const std::function<void(MemoryOrShmem&&)>& aFree);
    159 
    160  virtual bool IsValid() const { return true; }
    161 
    162  /**
    163   * For use with the TextureForwarder only (so that the later can
    164   * synchronize the TextureClient with the TextureHost).
    165   */
    166  virtual TextureClient* GetTextureClient(KnowsCompositor* aKnowsCompositor) {
    167    return nullptr;
    168  }
    169 
    170  /* Access to derived classes. */
    171  virtual GLImage* AsGLImage() { return nullptr; }
    172  virtual GPUVideoImage* AsGPUVideoImage() { return nullptr; }
    173 #ifdef MOZ_WIDGET_ANDROID
    174  virtual SurfaceTextureImage* AsSurfaceTextureImage() { return nullptr; }
    175 #endif
    176 #ifdef XP_DARWIN
    177  virtual MacIOSurfaceImage* AsMacIOSurfaceImage() { return nullptr; }
    178 #endif
    179  virtual PlanarYCbCrImage* AsPlanarYCbCrImage() { return nullptr; }
    180 #ifdef MOZ_WIDGET_GTK
    181  virtual DMABUFSurfaceImage* AsDMABUFSurfaceImage() { return nullptr; }
    182 #endif
    183 
    184  virtual NVImage* AsNVImage() { return nullptr; }
    185 
    186  virtual Maybe<SurfaceDescriptor> GetDesc();
    187 
    188  static nsresult AllocateSurfaceDescriptorBufferRgb(
    189      const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat,
    190      uint8_t*& aOutBuffer, SurfaceDescriptorBuffer& aSdBuffer,
    191      int32_t& aStride,
    192      const std::function<layers::MemoryOrShmem(uint32_t)>& aAllocate);
    193 
    194 protected:
    195  Maybe<SurfaceDescriptor> GetDescFromTexClient(
    196      TextureClient* tcOverride = nullptr);
    197 
    198  Image(void* aImplData, ImageFormat aFormat)
    199      : mImplData(aImplData),
    200        mSerial(++sSerialCounter),
    201        mFormat(aFormat),
    202        mIsDRM(false) {}
    203 
    204  // Protected destructor, to discourage deletion outside of Release():
    205  virtual ~Image() = default;
    206 
    207  mozilla::EnumeratedArray<mozilla::layers::LayersBackend,
    208                           UniquePtr<ImageBackendData>,
    209                           size_t(mozilla::layers::LayersBackend::LAYERS_LAST)>
    210      mBackendData;
    211 
    212  void* mImplData;
    213  int32_t mSerial;
    214  ImageFormat mFormat;
    215  bool mIsDRM;
    216 
    217  static mozilla::Atomic<int32_t> sSerialCounter;
    218 };
    219 
    220 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Image::BuildSdbFlags)
    221 
    222 /**
    223 * A RecycleBin is owned by an ImageContainer. We store buffers in it that we
    224 * want to recycle from one image to the next.It's a separate object from
    225 * ImageContainer because images need to store a strong ref to their RecycleBin
    226 * and we must avoid creating a reference loop between an ImageContainer and
    227 * its active image.
    228 */
    229 class BufferRecycleBin final {
    230  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BufferRecycleBin)
    231 
    232  // typedef mozilla::gl::GLContext GLContext;
    233 
    234 public:
    235  BufferRecycleBin();
    236 
    237  void RecycleBuffer(mozilla::UniquePtr<uint8_t[]> aBuffer, uint32_t aSize);
    238  // Returns a recycled buffer of the right size, or allocates a new buffer.
    239  mozilla::UniquePtr<uint8_t[]> GetBuffer(uint32_t aSize);
    240  void ClearRecycledBuffers();
    241 
    242 private:
    243  typedef mozilla::Mutex Mutex;
    244 
    245  // Private destructor, to discourage deletion outside of Release():
    246  ~BufferRecycleBin() = default;
    247 
    248  // This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures
    249  // and mRecycledTextureSizes
    250  Mutex mLock;
    251 
    252  // We should probably do something to prune this list on a timer so we don't
    253  // eat excess memory while video is paused...
    254  nsTArray<mozilla::UniquePtr<uint8_t[]>> mRecycledBuffers
    255      MOZ_GUARDED_BY(mLock);
    256  // This is only valid if mRecycledBuffers is non-empty
    257  uint32_t mRecycledBufferSize MOZ_GUARDED_BY(mLock);
    258 };
    259 
    260 /**
    261 * A class that manages Image creation for a LayerManager. The only reason
    262 * we need a separate class here is that LayerManagers aren't threadsafe
    263 * (because layers can only be used on the main thread) and we want to
    264 * be able to create images from any thread, to facilitate video playback
    265 * without involving the main thread, for example.
    266 * Different layer managers can implement child classes of this making it
    267 * possible to create layer manager specific images.
    268 * This class is not meant to be used directly but rather can be set on an
    269 * image container. This is usually done by the layer system internally and
    270 * not explicitly by users. For PlanarYCbCr or Cairo images the default
    271 * implementation will creates images whose data lives in system memory, for
    272 * MacIOSurfaces the default implementation will be a simple MacIOSurface
    273 * wrapper.
    274 */
    275 
    276 class ImageFactory {
    277  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageFactory)
    278 protected:
    279  friend class ImageContainer;
    280 
    281  ImageFactory() = default;
    282  virtual ~ImageFactory() = default;
    283 
    284  virtual RefPtr<PlanarYCbCrImage> CreatePlanarYCbCrImage(
    285      const gfx::IntSize& aScaleHint, BufferRecycleBin* aRecycleBin);
    286 };
    287 
    288 // Used to notify ImageContainer::NotifyComposite()
    289 class ImageContainerListener final {
    290  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageContainerListener)
    291 
    292 public:
    293  explicit ImageContainerListener(ImageContainer* aImageContainer);
    294 
    295  void NotifyComposite(const ImageCompositeNotification& aNotification);
    296  void NotifyDropped(uint32_t aDropped);
    297  void ClearImageContainer();
    298  void DropImageClient();
    299 
    300 private:
    301  typedef mozilla::Mutex Mutex;
    302 
    303  ~ImageContainerListener();
    304 
    305  Mutex mLock;
    306  ImageContainer* mImageContainer MOZ_GUARDED_BY(mLock);
    307 };
    308 
    309 enum class ClearImagesType { All, CacheOnly };
    310 
    311 /**
    312 * A class that manages Images for an ImageLayer. The only reason
    313 * we need a separate class here is that ImageLayers aren't threadsafe
    314 * (because layers can only be used on the main thread) and we want to
    315 * be able to set the current Image from any thread, to facilitate
    316 * video playback without involving the main thread, for example.
    317 *
    318 * An ImageContainer can operate in one of these modes:
    319 * 1) Normal. Triggered by constructing the ImageContainer with
    320 * DISABLE_ASYNC or when compositing is happening on the main thread.
    321 * SetCurrentImages changes ImageContainer state but nothing is sent to the
    322 * compositor until the next layer transaction.
    323 * 2) Asynchronous. Initiated by constructing the ImageContainer with
    324 * ENABLE_ASYNC when compositing is happening on the main thread.
    325 * SetCurrentImages sends a message through the ImageBridge to the compositor
    326 * thread to update the image, without going through the main thread or
    327 * a layer transaction.
    328 * The ImageContainer uses a shared memory block containing a cross-process
    329 * mutex to communicate with the compositor thread. SetCurrentImage
    330 * synchronously updates the shared state to point to the new image and the old
    331 * image is immediately released (not true in Normal or Asynchronous modes).
    332 */
    333 class ImageContainer final : public SupportsThreadSafeWeakPtr<ImageContainer> {
    334  friend class ImageContainerChild;
    335 
    336 public:
    337  MOZ_DECLARE_REFCOUNTED_TYPENAME(ImageContainer)
    338 
    339  enum Mode { SYNCHRONOUS = 0x0, ASYNCHRONOUS = 0x01 };
    340 
    341  static const uint64_t sInvalidAsyncContainerId = 0;
    342 
    343  ImageContainer(ImageUsageType aUsageType, ImageContainer::Mode aFlag);
    344 
    345  ~ImageContainer();
    346 
    347  using FrameID = ContainerFrameID;
    348  using ProducerID = ContainerProducerID;
    349  using CaptureTime = ContainerCaptureTime;
    350  using ReceiveTime = ContainerReceiveTime;
    351  using RtpTimestamp = ContainerRtpTimestamp;
    352 
    353  RefPtr<PlanarYCbCrImage> CreatePlanarYCbCrImage();
    354 
    355  // Factory methods for shared image types.
    356  RefPtr<SharedRGBImage> CreateSharedRGBImage();
    357 
    358  struct NonOwningImage {
    359    explicit NonOwningImage(
    360        Image* aImage = nullptr, TimeStamp aTimeStamp = TimeStamp(),
    361        FrameID aFrameID = 0, ProducerID aProducerID = 0,
    362        media::TimeUnit aProcessingDuration = media::TimeUnit::Invalid(),
    363        media::TimeUnit aMediaTime = media::TimeUnit::Invalid(),
    364        const CaptureTime& aWebrtcCaptureTime = AsVariant(Nothing()),
    365        const ReceiveTime& aWebrtcReceiveTime = Nothing(),
    366        const RtpTimestamp& aRtpTimestamp = Nothing())
    367        : mImage(aImage),
    368          mTimeStamp(aTimeStamp),
    369          mFrameID(aFrameID),
    370          mProducerID(aProducerID),
    371          mProcessingDuration(aProcessingDuration),
    372          mMediaTime(aMediaTime),
    373          mWebrtcCaptureTime(aWebrtcCaptureTime),
    374          mWebrtcReceiveTime(aWebrtcReceiveTime),
    375          mRtpTimestamp(aRtpTimestamp) {}
    376    Image* mImage;
    377    TimeStamp mTimeStamp;
    378    FrameID mFrameID;
    379    ProducerID mProducerID;
    380    media::TimeUnit mProcessingDuration = media::TimeUnit::Invalid();
    381    media::TimeUnit mMediaTime = media::TimeUnit::Invalid();
    382    CaptureTime mWebrtcCaptureTime = AsVariant(Nothing());
    383    ReceiveTime mWebrtcReceiveTime;
    384    RtpTimestamp mRtpTimestamp;
    385  };
    386  /**
    387   * Set aImages as the list of timestamped to display. The Images must have
    388   * been created by this ImageContainer.
    389   * Can be called on any thread. This method takes mRecursiveMutex
    390   * when accessing thread-shared state.
    391   * aImages must be non-empty. The first timestamp in the list may be
    392   * null but the others must not be, and the timestamps must increase.
    393   * Every element of aImages must have non-null mImage.
    394   * mFrameID can be zero, in which case you won't get meaningful
    395   * painted/dropped frame counts. Otherwise you should use a unique and
    396   * increasing ID for each decoded and submitted frame (but it's OK to
    397   * pass the same frame to SetCurrentImages).
    398   * mProducerID is a unique ID for the stream of images. A change in the
    399   * mProducerID means changing to a new mFrameID namespace. All frames in
    400   * aImages must have the same mProducerID.
    401   *
    402   * The Image data must not be modified after this method is called!
    403   * Note that this must not be called if ENABLE_ASYNC has not been set.
    404   *
    405   * The implementation calls CurrentImageChanged() while holding
    406   * mRecursiveMutex.
    407   *
    408   * If this ImageContainer has an ImageClient for async video:
    409   * Schedule a task to send the image to the compositor using the
    410   * PImageBridge protcol without using the main thread.
    411   */
    412  void SetCurrentImages(const nsTArray<NonOwningImage>& aImages);
    413 
    414  /**
    415   * Clear images in host. It could be used only with async ImageContainer.
    416   * Because we may release the lock after acquiring it in this method, it
    417   * cannot be called with the lock held.
    418   */
    419  void ClearImagesInHost(ClearImagesType aType) MOZ_EXCLUDES(mRecursiveMutex);
    420 
    421  /**
    422   * Clear any resources that are not immediately necessary. This may be called
    423   * in low-memory conditions.
    424   */
    425  void ClearCachedResources();
    426 
    427  /**
    428   * Clear the current images.
    429   * This function is expect to be called only from a CompositableClient
    430   * that belongs to ImageBridgeChild. Created to prevent dead lock.
    431   * See Bug 901224.
    432   */
    433  void ClearImagesFromImageBridge();
    434 
    435  /**
    436   * Set an Image as the current image to display. The Image must have
    437   * been created by this ImageContainer.
    438   * Must be called on the main thread, within a layers transaction.
    439   *
    440   * This method takes mRecursiveMutex
    441   * when accessing thread-shared state.
    442   * aImage can be null. While it's null, nothing will be painted.
    443   *
    444   * The Image data must not be modified after this method is called!
    445   * Note that this must not be called if ENABLE_ASYNC been set.
    446   *
    447   * You won't get meaningful painted/dropped counts when using this method.
    448   */
    449  void SetCurrentImageInTransaction(Image* aImage);
    450  void SetCurrentImagesInTransaction(const nsTArray<NonOwningImage>& aImages);
    451 
    452  /**
    453   * Returns true if this ImageContainer uses the ImageBridge IPDL protocol.
    454   *
    455   * Can be called from any thread.
    456   */
    457  bool IsAsync() const;
    458 
    459  /**
    460   * If this ImageContainer uses ImageBridge, returns the ID associated to
    461   * this container, for use in the ImageBridge protocol.
    462   * Returns 0 if this ImageContainer does not use ImageBridge. Note that
    463   * 0 is always an invalid ID for asynchronous image containers.
    464   *
    465   * Can be called from any thread.
    466   */
    467  CompositableHandle GetAsyncContainerHandle();
    468 
    469  /**
    470   * Returns if the container currently has an image.
    471   * Can be called on any thread. This method takes mRecursiveMutex
    472   * when accessing thread-shared state.
    473   */
    474  bool HasCurrentImage();
    475 
    476  struct OwningImage {
    477    RefPtr<Image> mImage;
    478    TimeStamp mTimeStamp;
    479    media::TimeUnit mProcessingDuration = media::TimeUnit::Invalid();
    480    media::TimeUnit mMediaTime = media::TimeUnit::Invalid();
    481    CaptureTime mWebrtcCaptureTime = AsVariant(Nothing());
    482    ReceiveTime mWebrtcReceiveTime;
    483    RtpTimestamp mRtpTimestamp;
    484    FrameID mFrameID = 0;
    485    ProducerID mProducerID = 0;
    486    bool mComposited = false;
    487  };
    488  /**
    489   * Copy the current Image list to aImages.
    490   * This has to add references since otherwise there are race conditions
    491   * where the current image is destroyed before the caller can add
    492   * a reference.
    493   * Can be called on any thread.
    494   * May return an empty list to indicate there is no current image.
    495   * If aGenerationCounter is non-null, sets *aGenerationCounter to a value
    496   * that's unique for this ImageContainer state.
    497   */
    498  void GetCurrentImages(nsTArray<OwningImage>* aImages,
    499                        uint32_t* aGenerationCounter = nullptr);
    500 
    501  /**
    502   * Returns the size of the image in pixels.
    503   * Can be called on any thread. This method takes mRecursiveMutex when
    504   * accessing thread-shared state.
    505   */
    506  gfx::IntSize GetCurrentSize();
    507 
    508  /**
    509   * Sets a size that the image is expected to be rendered at.
    510   * This is a hint for image backends to optimize scaling.
    511   * Default implementation in this class is to ignore the hint.
    512   * Can be called on any thread. This method takes mRecursiveMutex
    513   * when accessing thread-shared state.
    514   */
    515  void SetScaleHint(const gfx::IntSize& aScaleHint) {
    516    RecursiveMutexAutoLock lock(mRecursiveMutex);
    517    mScaleHint = aScaleHint;
    518  }
    519 
    520  const gfx::IntSize GetScaleHint() const {
    521    RecursiveMutexAutoLock lock(mRecursiveMutex);
    522    return mScaleHint;
    523  }
    524 
    525  void SetTransformHint(const gfx::Matrix& aTransformHint) {
    526    RecursiveMutexAutoLock lock(mRecursiveMutex);
    527    mTransformHint = aTransformHint;
    528  }
    529 
    530  const gfx::Matrix GetTransformHint() const {
    531    RecursiveMutexAutoLock lock(mRecursiveMutex);
    532    return mTransformHint;
    533  }
    534 
    535  void SetRotation(VideoRotation aRotation) {
    536    MOZ_ASSERT(NS_IsMainThread());
    537    mRotation = aRotation;
    538  }
    539 
    540  VideoRotation GetRotation() const {
    541    MOZ_ASSERT(NS_IsMainThread());
    542    return mRotation;
    543  }
    544 
    545  void SetImageFactory(ImageFactory* aFactory) {
    546    RecursiveMutexAutoLock lock(mRecursiveMutex);
    547    mImageFactory = aFactory ? aFactory : new ImageFactory();
    548  }
    549 
    550  already_AddRefed<ImageFactory> GetImageFactory() const {
    551    RecursiveMutexAutoLock lock(mRecursiveMutex);
    552    return do_AddRef(mImageFactory);
    553  }
    554 
    555  void EnsureRecycleAllocatorForRDD(KnowsCompositor* aKnowsCompositor);
    556 
    557 #ifdef XP_WIN
    558  already_AddRefed<D3D11RecycleAllocator> GetD3D11RecycleAllocator(
    559      KnowsCompositor* aKnowsCompositor, gfx::SurfaceFormat aPreferredFormat);
    560  already_AddRefed<D3D11YCbCrRecycleAllocator> GetD3D11YCbCrRecycleAllocator(
    561      KnowsCompositor* aKnowsCompositor);
    562 #endif
    563 
    564 #ifdef XP_DARWIN
    565  already_AddRefed<MacIOSurfaceRecycleAllocator>
    566  GetMacIOSurfaceRecycleAllocator();
    567 #endif
    568 
    569  /**
    570   * Returns the delay between the last composited image's presentation
    571   * timestamp and when it was first composited. It's possible for the delay
    572   * to be negative if the first image in the list passed to SetCurrentImages
    573   * has a presentation timestamp greater than "now".
    574   * Returns 0 if the composited image had a null timestamp, or if no
    575   * image has been composited yet.
    576   */
    577  TimeDuration GetPaintDelay() {
    578    RecursiveMutexAutoLock lock(mRecursiveMutex);
    579    return mPaintDelay;
    580  }
    581 
    582  /**
    583   * Returns the number of images which have been contained in this container
    584   * and painted at least once.  Can be called from any thread.
    585   */
    586  uint32_t GetPaintCount() {
    587    RecursiveMutexAutoLock lock(mRecursiveMutex);
    588    return mPaintCount;
    589  }
    590 
    591  /**
    592   * An entry in the current image list "expires" when the entry has an
    593   * non-null timestamp, and in a SetCurrentImages call the new image list is
    594   * non-empty, the timestamp of the first new image is non-null and greater
    595   * than the timestamp associated with the image, and the first new image's
    596   * frameID is not the same as the entry's.
    597   * Every expired image that is never composited is counted as dropped.
    598   */
    599  uint32_t GetDroppedImageCount() { return mDroppedImageCount; }
    600 
    601  void NotifyComposite(const ImageCompositeNotification& aNotification);
    602  void NotifyDropped(uint32_t aDropped);
    603 
    604  already_AddRefed<ImageContainerListener> GetImageContainerListener() const;
    605 
    606  /**
    607   * Get the ImageClient associated with this container. Returns only after
    608   * validating, and it will recreate the image client if that fails.
    609   * Returns nullptr if not applicable.
    610   */
    611  already_AddRefed<ImageClient> GetImageClient();
    612 
    613  /**
    614   * Main thread only.
    615   */
    616  static ProducerID AllocateProducerID();
    617 
    618  void DropImageClient();
    619 
    620  const ImageUsageType mUsageType;
    621  const bool mIsAsync;
    622 
    623 private:
    624  typedef mozilla::RecursiveMutex RecursiveMutex;
    625 
    626  void SetCurrentImageInternal(const nsTArray<NonOwningImage>& aImages);
    627 
    628  // This is called to ensure we have an active image, this may not be true
    629  // when we're storing image information in a RemoteImageData structure.
    630  // NOTE: If we have remote data mRemoteDataMutex should be locked when
    631  // calling this function!
    632  void EnsureActiveImage();
    633 
    634  void EnsureImageClient() MOZ_REQUIRES(mRecursiveMutex);
    635 
    636  bool HasImageClient() const {
    637    RecursiveMutexAutoLock lock(mRecursiveMutex);
    638    return !!mImageClient;
    639  }
    640 
    641  // RecursiveMutex to protect thread safe access to the "current
    642  // image", and any other state which is shared between threads.
    643  mutable RecursiveMutex mRecursiveMutex;
    644 
    645  RefPtr<TextureClientRecycleAllocator> mRecycleAllocator
    646      MOZ_GUARDED_BY(mRecursiveMutex);
    647 
    648 #ifdef XP_WIN
    649  RefPtr<D3D11RecycleAllocator> mD3D11RecycleAllocator
    650      MOZ_GUARDED_BY(mRecursiveMutex);
    651 
    652  RefPtr<D3D11YCbCrRecycleAllocator> mD3D11YCbCrRecycleAllocator
    653      MOZ_GUARDED_BY(mRecursiveMutex);
    654 #endif
    655 #ifdef XP_DARWIN
    656  RefPtr<MacIOSurfaceRecycleAllocator> mMacIOSurfaceRecycleAllocator
    657      MOZ_GUARDED_BY(mRecursiveMutex);
    658 #endif
    659 
    660  nsTArray<OwningImage> mCurrentImages MOZ_GUARDED_BY(mRecursiveMutex);
    661 
    662  // Updates every time mActiveImage changes
    663  uint32_t mGenerationCounter MOZ_GUARDED_BY(mRecursiveMutex);
    664 
    665  // Number of contained images that have been painted at least once.  It's up
    666  // to the ImageContainer implementation to ensure accesses to this are
    667  // threadsafe.
    668  uint32_t mPaintCount MOZ_GUARDED_BY(mRecursiveMutex);
    669 
    670  // See GetPaintDelay. Accessed only with mRecursiveMutex held.
    671  TimeDuration mPaintDelay MOZ_GUARDED_BY(mRecursiveMutex);
    672 
    673  // See GetDroppedImageCount.
    674  mozilla::Atomic<uint32_t> mDroppedImageCount;
    675 
    676  // This is the image factory used by this container, layer managers using
    677  // this container can set an alternative image factory that will be used to
    678  // create images for this container.
    679  RefPtr<ImageFactory> mImageFactory MOZ_GUARDED_BY(mRecursiveMutex);
    680 
    681  gfx::IntSize mScaleHint MOZ_GUARDED_BY(mRecursiveMutex);
    682 
    683  gfx::Matrix mTransformHint MOZ_GUARDED_BY(mRecursiveMutex);
    684 
    685  // Main thread only.
    686  VideoRotation mRotation;
    687 
    688  RefPtr<BufferRecycleBin> mRecycleBin MOZ_GUARDED_BY(mRecursiveMutex);
    689 
    690  // This member points to an ImageClient if this ImageContainer was
    691  // sucessfully created with ENABLE_ASYNC, or points to null otherwise.
    692  // 'unsuccessful' in this case only means that the ImageClient could not
    693  // be created, most likely because off-main-thread compositing is not enabled.
    694  // In this case the ImageContainer is perfectly usable, but it will forward
    695  // frames to the compositor through transactions in the main thread rather
    696  // than asynchronusly using the ImageBridge IPDL protocol.
    697  RefPtr<ImageClient> mImageClient MOZ_GUARDED_BY(mRecursiveMutex);
    698 
    699  CompositableHandle mAsyncContainerHandle MOZ_GUARDED_BY(mRecursiveMutex);
    700 
    701  // ProducerID for last current image(s)
    702  ProducerID mCurrentProducerID MOZ_GUARDED_BY(mRecursiveMutex);
    703 
    704  RefPtr<ImageContainerListener> mNotifyCompositeListener;
    705 
    706  static mozilla::Atomic<uint32_t> sGenerationCounter;
    707 };
    708 
    709 class AutoLockImage {
    710 public:
    711  explicit AutoLockImage(ImageContainer* aContainer) {
    712    aContainer->GetCurrentImages(&mImages);
    713  }
    714 
    715  bool HasImage() const { return !mImages.IsEmpty(); }
    716  Image* GetImage() const {
    717    return mImages.IsEmpty() ? nullptr : mImages[0].mImage.get();
    718  }
    719 
    720  const ImageContainer::OwningImage* GetOwningImage(
    721      TimeStamp aTimeStamp) const {
    722    if (mImages.IsEmpty()) {
    723      return nullptr;
    724    }
    725 
    726    MOZ_ASSERT(!aTimeStamp.IsNull());
    727    uint32_t chosenIndex = 0;
    728 
    729    while (chosenIndex + 1 < mImages.Length() &&
    730           mImages[chosenIndex + 1].mTimeStamp <= aTimeStamp) {
    731      ++chosenIndex;
    732    }
    733 
    734    return &mImages[chosenIndex];
    735  }
    736 
    737  Image* GetImage(TimeStamp aTimeStamp) const {
    738    if (const auto* owningImage = GetOwningImage(aTimeStamp)) {
    739      return owningImage->mImage.get();
    740    }
    741    return nullptr;
    742  }
    743 
    744 private:
    745  AutoTArray<ImageContainer::OwningImage, 4> mImages;
    746 };
    747 
    748 // This type is currently only used for AVIF and WebCodecs therefore makes some
    749 // specific assumptions (e.g., Alpha's bpc and stride is equal to Y's one)
    750 struct PlanarAlphaData {
    751  uint8_t* mChannel = nullptr;
    752  gfx::IntSize mSize = gfx::IntSize(0, 0);
    753  gfx::ColorDepth mDepth = gfx::ColorDepth::COLOR_8;
    754  bool mPremultiplied = false;
    755 };
    756 struct PlanarYCbCrData {
    757  // Luminance buffer
    758  uint8_t* mYChannel = nullptr;
    759  int32_t mYStride = 0;
    760  int32_t mYSkip = 0;
    761  // Chroma buffers
    762  uint8_t* mCbChannel = nullptr;
    763  uint8_t* mCrChannel = nullptr;
    764  int32_t mCbCrStride = 0;
    765  int32_t mCbSkip = 0;
    766  int32_t mCrSkip = 0;
    767  // Alpha buffer and its metadata
    768  Maybe<PlanarAlphaData> mAlpha = Nothing();
    769  // Picture region
    770  gfx::IntRect mPictureRect = gfx::IntRect(0, 0, 0, 0);
    771  StereoMode mStereoMode = StereoMode::MONO;
    772  gfx::ColorDepth mColorDepth = gfx::ColorDepth::COLOR_8;
    773  gfx::YUVColorSpace mYUVColorSpace = gfx::YUVColorSpace::Default;
    774  gfx::ColorSpace2 mColorPrimaries = gfx::ColorSpace2::UNKNOWN;
    775  gfx::TransferFunction mTransferFunction = gfx::TransferFunction::BT709;
    776  gfx::ColorRange mColorRange = gfx::ColorRange::LIMITED;
    777  gfx::ChromaSubsampling mChromaSubsampling = gfx::ChromaSubsampling::FULL;
    778 
    779  // The cropped picture size of the Y channel.
    780  gfx::IntSize YPictureSize() const { return mPictureRect.Size(); }
    781 
    782  // The cropped picture size of the Cb/Cr channels.
    783  gfx::IntSize CbCrPictureSize() const {
    784    return mCbCrStride > 0 ? gfx::ChromaSize(YPictureSize(), mChromaSubsampling)
    785                           : gfx::IntSize(0, 0);
    786  }
    787 
    788  // The total uncropped size of data in the Y channel.
    789  gfx::IntSize YDataSize() const {
    790    return gfx::IntSize(mPictureRect.XMost(), mPictureRect.YMost());
    791  }
    792 
    793  // The total uncropped size of data in the Cb/Cr channels.
    794  gfx::IntSize CbCrDataSize() const {
    795    return mCbCrStride > 0 ? gfx::ChromaSize(YDataSize(), mChromaSubsampling)
    796                           : gfx::IntSize(0, 0);
    797  }
    798 
    799  static Maybe<PlanarYCbCrData> From(const SurfaceDescriptorBuffer&);
    800  static Maybe<PlanarYCbCrData> From(const VideoData::YCbCrBuffer&);
    801 };
    802 
    803 /****** Image subtypes for the different formats ******/
    804 
    805 /**
    806 * We assume that the image data is in the REC 470M color space (see
    807 * Theora specification, section 4.3.1).
    808 *
    809 * The YCbCr format can be:
    810 *
    811 * 4:4:4 - CbCr width/height are the same as Y.
    812 * 4:2:2 - CbCr width is half that of Y. Height is the same.
    813 * 4:2:0 - CbCr width and height is half that of Y.
    814 *
    815 * mChromaSubsampling specifies which YCbCr subsampling scheme to use.
    816 *
    817 * The Image that is rendered is the picture region defined by mPictureRect.
    818 *
    819 * mYSkip, mCbSkip, mCrSkip are added to support various output
    820 * formats from hardware decoder. They are per-pixel skips in the
    821 * source image.
    822 *
    823 * For example when image width is 640, mYStride is 670, mYSkip is 2,
    824 * the mYChannel buffer looks like:
    825 *
    826 * |<----------------------- mYStride ----------------------------->|
    827 * |<----------------- YDataSize().width ---------->|
    828 *  0   3   6   9   12  15  18  21                639             669
    829 * |----------------------------------------------------------------|
    830 * |Y___Y___Y___Y___Y___Y___Y___Y...                |%%%%%%%%%%%%%%%|
    831 * |Y___Y___Y___Y___Y___Y___Y___Y...                |%%%%%%%%%%%%%%%|
    832 * |Y___Y___Y___Y___Y___Y___Y___Y...                |%%%%%%%%%%%%%%%|
    833 * |            |<->|
    834 *                mYSkip
    835 */
    836 class PlanarYCbCrImage : public Image {
    837 public:
    838  typedef PlanarYCbCrData Data;
    839 
    840  enum { MAX_DIMENSION = 16384 };
    841 
    842  virtual ~PlanarYCbCrImage();
    843 
    844  /**
    845   * This makes a copy of the data buffers, in order to support functioning
    846   * in all different layer managers.
    847   */
    848  virtual nsresult CopyData(const Data& aData) = 0;
    849 
    850  /**
    851   * This doesn't make a copy of the data buffers.
    852   */
    853  virtual nsresult AdoptData(const Data& aData);
    854 
    855  /**
    856   * This will create an empty data buffers according to the input data's size.
    857   */
    858  virtual nsresult CreateEmptyBuffer(const Data& aData,
    859                                     const gfx::IntSize& aYSize,
    860                                     const gfx::IntSize& aCbCrSize) {
    861    return NS_ERROR_NOT_IMPLEMENTED;
    862  }
    863 
    864  /**
    865   * Grab the original YUV data. This is optional.
    866   */
    867  virtual const Data* GetData() const { return &mData; }
    868 
    869  /**
    870   * Return the number of bytes of heap memory used to store this image.
    871   */
    872  uint32_t GetDataSize() const { return mBufferSize; }
    873 
    874  bool IsValid() const override { return !!mBufferSize; }
    875 
    876  gfx::IntSize GetSize() const override { return mSize; }
    877 
    878  gfx::IntPoint GetOrigin() const override { return mOrigin; }
    879 
    880  PlanarYCbCrImage();
    881 
    882  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
    883    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
    884  }
    885 
    886  virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const = 0;
    887 
    888  PlanarYCbCrImage* AsPlanarYCbCrImage() override { return this; }
    889 
    890  /**
    891   * Build a SurfaceDescriptorBuffer with this image.  A function to allocate
    892   * a MemoryOrShmem with the given capacity must be provided.
    893   */
    894  nsresult BuildSurfaceDescriptorBuffer(
    895      SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags,
    896      const std::function<MemoryOrShmem(uint32_t)>& aAllocate) override;
    897 
    898  void SetColorDepth(gfx::ColorDepth aColorDepth) { mColorDepth = aColorDepth; }
    899 
    900  gfx::ColorDepth GetColorDepth() const override { return mColorDepth; }
    901 
    902 protected:
    903  already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
    904 
    905  void SetOffscreenFormat(gfxImageFormat aFormat) {
    906    mOffscreenFormat = aFormat;
    907  }
    908  gfxImageFormat GetOffscreenFormat() const;
    909 
    910  Data mData;
    911  gfx::IntPoint mOrigin;
    912  gfx::IntSize mSize;
    913  gfx::ColorDepth mColorDepth = gfx::ColorDepth::COLOR_8;
    914  gfxImageFormat mOffscreenFormat;
    915  RefPtr<gfx::DataSourceSurface> mSourceSurface;
    916  uint32_t mBufferSize;
    917 };
    918 
    919 class RecyclingPlanarYCbCrImage : public PlanarYCbCrImage {
    920 public:
    921  explicit RecyclingPlanarYCbCrImage(BufferRecycleBin* aRecycleBin)
    922      : mRecycleBin(aRecycleBin) {}
    923  virtual ~RecyclingPlanarYCbCrImage();
    924  nsresult CopyData(const Data& aData) override;
    925  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
    926 
    927 protected:
    928  /**
    929   * Return a buffer to store image data in.
    930   */
    931  mozilla::UniquePtr<uint8_t[]> AllocateBuffer(uint32_t aSize);
    932 
    933  RefPtr<BufferRecycleBin> mRecycleBin;
    934  mozilla::UniquePtr<uint8_t[]> mBuffer;
    935 };
    936 
    937 /**
    938 * NVImage is used to store YUV420SP_NV12 and YUV420SP_NV21 data natively, which
    939 * are not supported by PlanarYCbCrImage. (PlanarYCbCrImage only stores YUV444P,
    940 * YUV422P and YUV420P, it converts YUV420SP_NV12 and YUV420SP_NV21 data into
    941 * YUV420P in its PlanarYCbCrImage::SetData() method.)
    942 *
    943 * PlanarYCbCrData is able to express all the YUV family and so we keep use it
    944 * in NVImage.
    945 */
    946 class NVImage final : public Image {
    947  typedef PlanarYCbCrData Data;
    948 
    949 public:
    950  NVImage();
    951  virtual ~NVImage();
    952 
    953  // Methods inherited from layers::Image.
    954  gfx::IntSize GetSize() const override;
    955  gfx::IntRect GetPictureRect() const override;
    956  already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;
    957  nsresult BuildSurfaceDescriptorBuffer(
    958      SurfaceDescriptorBuffer& aSdBuffer, BuildSdbFlags aFlags,
    959      const std::function<MemoryOrShmem(uint32_t)>& aAllocate) override;
    960  bool IsValid() const override;
    961  NVImage* AsNVImage() override;
    962 
    963  // Methods mimic layers::PlanarYCbCrImage.
    964  nsresult SetData(const Data& aData);
    965  const Data* GetData() const;
    966  uint32_t GetBufferSize() const;
    967 
    968 protected:
    969  /**
    970   * Return a buffer to store image data in.
    971   */
    972  mozilla::UniquePtr<uint8_t[]> AllocateBuffer(uint32_t aSize);
    973 
    974  mozilla::UniquePtr<uint8_t[]> mBuffer;
    975  uint32_t mBufferSize;
    976  gfx::IntSize mSize;
    977  Data mData;
    978  RefPtr<gfx::DataSourceSurface> mSourceSurface;
    979 };
    980 
    981 /**
    982 * Currently, the data in a SourceSurfaceImage surface is treated as being in
    983 * the device output color space. This class is very simple as all backends have
    984 * to know about how to deal with drawing a cairo image.
    985 */
    986 class SourceSurfaceImage final : public Image {
    987 public:
    988  already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override {
    989    RefPtr<gfx::SourceSurface> surface(mSourceSurface);
    990    return surface.forget();
    991  }
    992 
    993  void SetTextureFlags(TextureFlags aTextureFlags) {
    994    mTextureFlags = aTextureFlags;
    995  }
    996  TextureClient* GetTextureClient(KnowsCompositor* aKnowsCompositor) override;
    997 
    998  gfx::IntSize GetSize() const override { return mSize; }
    999 
   1000  SourceSurfaceImage(const gfx::IntSize& aSize,
   1001                     gfx::SourceSurface* aSourceSurface);
   1002  explicit SourceSurfaceImage(gfx::SourceSurface* aSourceSurface);
   1003  virtual ~SourceSurfaceImage();
   1004 
   1005 private:
   1006  gfx::IntSize mSize;
   1007  RefPtr<gfx::SourceSurface> mSourceSurface;
   1008  nsTHashMap<uint32_t, RefPtr<TextureClient>> mTextureClients;
   1009  TextureFlags mTextureFlags;
   1010 };
   1011 
   1012 }  // namespace layers
   1013 }  // namespace mozilla
   1014 
   1015 #endif