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
--- 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;
};