Bug 1295921 - PB: Blocking implementation of ImageContainer AutoLockImage. r?mattwoodrow draft
authorDan Glastonbury <dglastonbury@mozilla.com>
Tue, 27 Sep 2016 15:19:21 +1000
changeset 418756 d82b81096c11326c67b4d7ef9b97842e225076fd
parent 418755 b3eac012e23f14ce53904ba7f89227d8b60c8d38
child 418757 65b2e820f82fc322e1827ce3dcb2d1110044306f
push id30774
push userbmo:dglastonbury@mozilla.com
push dateThu, 29 Sep 2016 04:21:40 +0000
reviewersmattwoodrow
bugs1295921
milestone52.0a1
Bug 1295921 - PB: Blocking implementation of ImageContainer AutoLockImage. r?mattwoodrow Adds a version of AutoLockImage and GetCurrentImages that supports blocking the calling thread until there is at least a valid image in the image container. This is used to block drawImage on video elements with suspended decoders. MozReview-Commit-ID: 3pXUQOkc6MN
gfx/layers/ImageContainer.cpp
gfx/layers/ImageContainer.h
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -252,16 +252,17 @@ ImageContainer::SetCurrentImageInternal(
           oldImg.mProducerID == img->mProducerID) {
         img->mComposited = oldImg.mComposited;
         break;
       }
     }
   }
 
   mCurrentImages.SwapElements(newImages);
+  mon.NotifyAll();
 }
 
 void
 ImageContainer::ClearImagesFromImageBridge()
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
   SetCurrentImageInternal(nsTArray<NonOwningImage>());
 }
@@ -352,16 +353,27 @@ ImageContainer::GetCurrentImages(nsTArra
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   *aImages = mCurrentImages;
   if (aGenerationCounter) {
     *aGenerationCounter = mGenerationCounter;
   }
 }
 
+void
+ImageContainer::GetCurrentImagesBlocking(nsTArray<OwningImage>* aImages)
+{
+  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  while (mCurrentImages.IsEmpty()) {
+    mon.Wait();
+  }
+
+  *aImages = mCurrentImages;
+}
+
 gfx::IntSize
 ImageContainer::GetCurrentSize()
 {
   ReentrantMonitorAutoEnter mon(mReentrantMonitor);
 
   if (mCurrentImages.IsEmpty()) {
     return gfx::IntSize(0, 0);
   }
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -173,24 +173,24 @@ class SurfaceTextureImage;
 class MacIOSurfaceImage;
 #elif defined(MOZ_WIDGET_GONK)
 class OverlayImage;
 #endif
 
 /**
  * A class representing a buffer of pixel data. The data can be in one
  * of various formats including YCbCr.
- * 
+ *
  * Create an image using an ImageContainer. Fill the image with data, and
  * then call ImageContainer::SetImage to display it. An image must not be
  * modified after calling SetImage. Image implementations do not need to
  * perform locking; when filling an Image, the Image client is responsible
  * for ensuring only one thread accesses the Image at a time, and after
  * SetImage the image is immutable.
- * 
+ *
  * When resampling an Image, only pixels within the buffer should be
  * sampled. For example, cairo images should be sampled in EXTEND_PAD mode.
  */
 class Image {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Image)
 
 public:
   ImageFormat GetFormat() { return mFormat; }
@@ -262,17 +262,17 @@ protected:
   int32_t mSerial;
   ImageFormat mFormat;
 
   static mozilla::Atomic<int32_t> sSerialCounter;
 };
 
 /**
  * A RecycleBin is owned by an ImageContainer. We store buffers in it that we
- * want to recycle from one image to the next.It's a separate object from 
+ * want to recycle from one image to the next.It's a separate object from
  * ImageContainer because images need to store a strong ref to their RecycleBin
  * and we must avoid creating a reference loop between an ImageContainer and
  * its active image.
  */
 class BufferRecycleBin final {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BufferRecycleBin)
 
   //typedef mozilla::gl::GLContext GLContext;
@@ -327,17 +327,17 @@ protected:
 
   ImageFactory() {}
   virtual ~ImageFactory() {}
 
   virtual RefPtr<PlanarYCbCrImage> CreatePlanarYCbCrImage(
     const gfx::IntSize& aScaleHint,
     BufferRecycleBin *aRecycleBin);
 };
- 
+
 /**
  * A class that manages Images for an ImageLayer. The only reason
  * we need a separate class here is that ImageLayers aren't threadsafe
  * (because layers can only be used on the main thread) and we want to
  * be able to set the current Image from any thread, to facilitate
  * video playback without involving the main thread, for example.
  *
  * An ImageContainer can operate in one of these modes:
@@ -411,17 +411,17 @@ public:
    * Every element of aImages must have non-null mImage.
    * mFrameID can be zero, in which case you won't get meaningful
    * painted/dropped frame counts. Otherwise you should use a unique and
    * increasing ID for each decoded and submitted frame (but it's OK to
    * pass the same frame to SetCurrentImages).
    * mProducerID is a unique ID for the stream of images. A change in the
    * mProducerID means changing to a new mFrameID namespace. All frames in
    * aImages must have the same mProducerID.
-   * 
+   *
    * The Image data must not be modified after this method is called!
    * Note that this must not be called if ENABLE_ASYNC has not been set.
    *
    * The implementation calls CurrentImageChanged() while holding
    * mReentrantMonitor.
    *
    * If this ImageContainer has an ImageClient for async video:
    * Schedule a task to send the image to the compositor using the
@@ -447,21 +447,21 @@ public:
    * See Bug 901224.
    */
   void ClearImagesFromImageBridge();
 
   /**
    * Set an Image as the current image to display. The Image must have
    * been created by this ImageContainer.
    * Must be called on the main thread, within a layers transaction.
-   * 
+   *
    * This method takes mReentrantMonitor
    * when accessing thread-shared state.
    * aImage can be null. While it's null, nothing will be painted.
-   * 
+   *
    * The Image data must not be modified after this method is called!
    * Note that this must not be called if ENABLE_ASYNC been set.
    *
    * You won't get meaningful painted/dropped counts when using this method.
    */
   void SetCurrentImageInTransaction(Image* aImage);
   void SetCurrentImagesInTransaction(const nsTArray<NonOwningImage>& aImages);
 
@@ -501,19 +501,23 @@ public:
    * Copy the current Image list to aImages.
    * This has to add references since otherwise there are race conditions
    * where the current image is destroyed before the caller can add
    * a reference.
    * Can be called on any thread.
    * May return an empty list to indicate there is no current image.
    * If aGenerationCounter is non-null, sets *aGenerationCounter to a value
    * that's unique for this ImageContainer state.
+   *
+   * Blocking version will block the calling thread until there are images to
+   * return.
    */
   void GetCurrentImages(nsTArray<OwningImage>* aImages,
                         uint32_t* aGenerationCounter = nullptr);
+  void GetCurrentImagesBlocking(nsTArray<OwningImage>* aImages);
 
   /**
    * Returns the size of the image in pixels.
    * Can be called on any thread. This method takes mReentrantMonitor when accessing
    * thread-shared state.
    */
   gfx::IntSize GetCurrentSize();
 
@@ -645,24 +649,31 @@ private:
 
   // Object must be released on the ImageBridge thread. Field is immutable
   // after creation of the ImageContainer.
   RefPtr<ImageContainerChild> mIPDLChild;
 
   static mozilla::Atomic<uint32_t> sGenerationCounter;
 };
 
+struct BlockingTag { };
+constexpr BlockingTag Blocking = BlockingTag();
+
 class AutoLockImage
 {
 public:
   explicit AutoLockImage(ImageContainer *aContainer)
   {
     aContainer->GetCurrentImages(&mImages);
   }
 
+  AutoLockImage(BlockingTag, ImageContainer *aContainer) {
+    aContainer->GetCurrentImagesBlocking(&mImages);
+  }
+
   bool HasImage() const { return !mImages.IsEmpty(); }
   Image* GetImage() const
   {
     return mImages.IsEmpty() ? nullptr : mImages[0].mImage.get();
   }
 
 private:
   AutoTArray<ImageContainer::OwningImage,4> mImages;
@@ -710,17 +721,17 @@ struct PlanarYCbCrData {
  * The YCbCr format can be:
  *
  * 4:4:4 - CbCr width/height are the same as Y.
  * 4:2:2 - CbCr width is half that of Y. Height is the same.
  * 4:2:0 - CbCr width and height is half that of Y.
  *
  * The color format is detected based on the height/width ratios
  * defined above.
- * 
+ *
  * The Image that is rendered is the picture region defined by
  * mPicX, mPicY and mPicSize. The size of the rendered image is
  * mPicSize, not mYSize or mCbCrSize.
  *
  * mYSkip, mCbSkip, mCrSkip are added to support various output
  * formats from hardware decoder. They are per-pixel skips in the
  * source image.
  *
@@ -905,17 +916,17 @@ private:
   TextureFlags mTextureFlags;
 };
 
 #ifdef MOZ_WIDGET_GONK
 class OverlayImage : public Image {
   /**
    * OverlayImage is a special Image type that does not hold any buffer.
    * It only hold an Id as identifier to the real content of the Image.
-   * Therefore, OverlayImage must be handled by some specialized hardware(e.g. HWC) 
+   * Therefore, OverlayImage must be handled by some specialized hardware(e.g. HWC)
    * to show its content.
    */
 public:
   struct Data {
     int32_t mOverlayId;
     gfx::IntSize mSize;
   };